summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Andreev <narf@bofh.bg>2012-10-12 10:56:34 +0200
committerAndrey Andreev <narf@bofh.bg>2012-10-12 10:56:34 +0200
commitbffe3fb935c8a28e1ccacf56f678a491edcff043 (patch)
tree5a39ba6907623d5ad46b7d13ef17e360df1dfe5e
parent55b82c95be57a6727d45d6ae9652ff612f96bc37 (diff)
parent9ae82faaad2f6b07a050d79129652b74483d1da0 (diff)
Merge changes from develop
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml7
-rw-r--r--application/config/autoload.php29
-rw-r--r--application/config/config.php21
-rw-r--r--application/config/constants.php16
-rw-r--r--application/config/database.php2
-rw-r--r--application/config/foreign_chars.php24
-rw-r--r--application/config/mimes.php12
-rw-r--r--application/config/user_agents.php8
-rw-r--r--application/views/errors/error_404.php8
-rw-r--r--application/views/errors/error_db.php8
-rw-r--r--application/views/errors/error_general.php8
-rw-r--r--application/views/welcome_message.php13
-rw-r--r--composer.json5
-rw-r--r--contributing.md92
-rw-r--r--readme.rst160
-rw-r--r--system/core/CodeIgniter.php2
-rw-r--r--system/core/Common.php62
-rw-r--r--system/core/Config.php2
-rw-r--r--system/core/Input.php132
-rw-r--r--system/core/Loader.php51
-rw-r--r--system/core/Output.php6
-rw-r--r--system/core/Utf8.php39
-rw-r--r--system/database/DB_driver.php17
-rw-r--r--system/database/DB_query_builder.php19
-rw-r--r--system/database/drivers/cubrid/cubrid_driver.php26
-rw-r--r--system/database/drivers/ibase/ibase_driver.php20
-rw-r--r--system/database/drivers/mssql/mssql_driver.php20
-rw-r--r--system/database/drivers/mysql/mysql_driver.php42
-rw-r--r--system/database/drivers/mysqli/mysqli_driver.php54
-rw-r--r--system/database/drivers/oci8/oci8_driver.php20
-rw-r--r--system/database/drivers/odbc/odbc_driver.php18
-rw-r--r--system/database/drivers/pdo/pdo_driver.php4
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_4d_driver.php16
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php24
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php18
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php16
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php16
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_informix_driver.php16
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php24
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_oci_driver.php16
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php17
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php16
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php18
-rw-r--r--system/database/drivers/postgre/postgre_driver.php30
-rw-r--r--system/database/drivers/sqlite/sqlite_driver.php4
-rw-r--r--system/database/drivers/sqlite3/sqlite3_driver.php25
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_driver.php22
-rw-r--r--system/helpers/captcha_helper.php3
-rw-r--r--system/helpers/date_helper.php148
-rw-r--r--system/helpers/directory_helper.php2
-rw-r--r--system/helpers/download_helper.php5
-rw-r--r--system/helpers/file_helper.php2
-rw-r--r--system/helpers/html_helper.php30
-rw-r--r--system/helpers/text_helper.php3
-rw-r--r--system/helpers/typography_helper.php4
-rw-r--r--system/helpers/url_helper.php52
-rw-r--r--system/language/english/date_lang.php28
-rw-r--r--system/language/english/form_validation_lang.php5
-rw-r--r--system/libraries/Driver.php20
-rw-r--r--system/libraries/Email.php65
-rw-r--r--system/libraries/Encrypt.php6
-rw-r--r--system/libraries/Form_validation.php20
-rw-r--r--system/libraries/Image_lib.php7
-rw-r--r--system/libraries/Pagination.php19
-rwxr-xr-xsystem/libraries/Session/Session.php714
-rwxr-xr-x[-rw-r--r--]system/libraries/Session/drivers/Session_cookie.php (renamed from system/libraries/Session.php)729
-rwxr-xr-xsystem/libraries/Session/drivers/Session_native.php231
-rw-r--r--system/libraries/Unit_test.php5
-rwxr-xr-x[-rw-r--r--]system/libraries/Xmlrpc.php10
-rw-r--r--tests/Bootstrap.php1
-rw-r--r--tests/codeigniter/core/Common_test.php31
-rw-r--r--tests/codeigniter/database/query_builder/escape_test.php4
-rw-r--r--tests/codeigniter/helpers/date_helper_test.php23
-rw-r--r--tests/codeigniter/helpers/directory_helper_test.php4
-rw-r--r--tests/codeigniter/helpers/html_helper_test.php17
-rw-r--r--tests/codeigniter/libraries/Calendar_test.php204
-rw-r--r--tests/codeigniter/libraries/Session_test.php400
-rw-r--r--tests/codeigniter/libraries/Upload_test.php270
-rw-r--r--tests/mocks/autoloader.php23
-rw-r--r--tests/mocks/core/input.php10
-rw-r--r--tests/mocks/core/lang.php15
-rw-r--r--tests/mocks/libraries/calendar.php25
-rw-r--r--tests/mocks/libraries/session.php43
-rw-r--r--tests/mocks/libraries/upload.php3
-rw-r--r--tests/mocks/uploads/ci_logo.gifbin0 -> 3270 bytes
-rw-r--r--tests/travis/mysql.phpunit.xml2
-rw-r--r--tests/travis/pdo/mysql.phpunit.xml2
-rw-r--r--tests/travis/pdo/pgsql.phpunit.xml2
-rw-r--r--tests/travis/pdo/sqlite.phpunit.xml2
-rw-r--r--tests/travis/pgsql.phpunit.xml2
-rw-r--r--tests/travis/sqlite.phpunit.xml2
-rw-r--r--user_guide_src/source/_themes/eldocs/layout.html16
-rw-r--r--user_guide_src/source/_themes/eldocs/searchbox.html21
-rw-r--r--user_guide_src/source/_themes/eldocs/static/asset/css/common.css6
-rw-r--r--user_guide_src/source/changelog.rst195
-rw-r--r--user_guide_src/source/conf.py1
-rw-r--r--user_guide_src/source/database/configuration.rst7
-rw-r--r--user_guide_src/source/general/autoloader.rst2
-rw-r--r--user_guide_src/source/general/cli.rst2
-rw-r--r--user_guide_src/source/general/reserved_names.rst2
-rw-r--r--user_guide_src/source/helpers/captcha_helper.rst2
-rw-r--r--user_guide_src/source/helpers/date_helper.rst24
-rw-r--r--user_guide_src/source/helpers/url_helper.rst13
-rw-r--r--user_guide_src/source/images/codeigniter_1.7.1_library_reference.pngbin111744 -> 111747 bytes
-rw-r--r--user_guide_src/source/index.rst3
-rw-r--r--user_guide_src/source/installation/upgrade_300.rst39
-rw-r--r--user_guide_src/source/libraries/email.rst17
-rw-r--r--user_guide_src/source/libraries/file_uploading.rst1
-rw-r--r--user_guide_src/source/libraries/form_validation.rst20
-rw-r--r--user_guide_src/source/libraries/image_lib.rst23
-rw-r--r--user_guide_src/source/libraries/loader.rst73
-rw-r--r--user_guide_src/source/libraries/migration.rst134
-rw-r--r--user_guide_src/source/libraries/output.rst3
-rw-r--r--user_guide_src/source/libraries/pagination.rst4
-rw-r--r--user_guide_src/source/libraries/sessions.rst338
-rw-r--r--user_guide_src/source/libraries/trackback.rst2
-rw-r--r--user_guide_src/source/overview/cheatsheets.rst15
118 files changed, 3954 insertions, 1430 deletions
diff --git a/.gitignore b/.gitignore
index 11fb6d67c..a035c2b27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,5 @@ application/logs/*
user_guide_src/build/*
user_guide_src/cilexer/build/*
user_guide_src/cilexer/dist/*
-user_guide_src/cilexer/pycilexer.egg-info/* \ No newline at end of file
+user_guide_src/cilexer/pycilexer.egg-info/*
+/vendor/ \ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 0a76229cd..1c7e87667 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,11 @@ language: php
php:
- 5.3
- 5.4
+
+services:
+ - mysql
+ - postgresql
+ - sqlite
env:
- DB=mysql
@@ -24,4 +29,4 @@ script: phpunit --coverage-text --configuration tests/travis/$DB.phpunit.xml
branches:
only:
- develop
- - /^feature.+/ \ No newline at end of file
+ - /^feature.+/
diff --git a/application/config/autoload.php b/application/config/autoload.php
index b3e63cbf6..ff153fb48 100644
--- a/application/config/autoload.php
+++ b/application/config/autoload.php
@@ -46,10 +46,11 @@
|
| 1. Packages
| 2. Libraries
-| 3. Helper files
-| 4. Custom config files
-| 5. Language files
-| 6. Models
+| 3. Drivers
+| 4. Helper files
+| 5. Custom config files
+| 6. Language files
+| 7. Models
|
*/
@@ -75,7 +76,7 @@ $autoload['packages'] = array();
|
| Prototype:
|
-| $autoload['libraries'] = array('database', 'session', 'xmlrpc');
+| $autoload['libraries'] = array('database', 'email', 'xmlrpc');
*/
$autoload['libraries'] = array();
@@ -83,6 +84,22 @@ $autoload['libraries'] = array();
/*
| -------------------------------------------------------------------
+| Auto-load Drivers
+| -------------------------------------------------------------------
+| These classes are located in the system/libraries folder or in your
+| application/libraries folder within their own subdirectory. They
+| offer multiple interchangeable driver options.
+|
+| Prototype:
+|
+| $autoload['drivers'] = array('session', 'cache');
+*/
+
+$autoload['drivers'] = array();
+
+
+/*
+| -------------------------------------------------------------------
| Auto-load Helper Files
| -------------------------------------------------------------------
| Prototype:
@@ -139,4 +156,4 @@ $autoload['model'] = array();
/* End of file autoload.php */
-/* Location: ./application/config/autoload.php */ \ No newline at end of file
+/* Location: ./application/config/autoload.php */
diff --git a/application/config/config.php b/application/config/config.php
index 28fc406d1..ab1508e7b 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -265,6 +265,9 @@ $config['encryption_key'] = '';
| Session Variables
|--------------------------------------------------------------------------
|
+| 'sess_driver' = the driver to load: cookie (Classic), native (PHP sessions),
+| or your custom driver name
+| 'sess_valid_drivers' = additional valid drivers which may be loaded
| 'sess_cookie_name' = the name you want for the cookie
| 'sess_expiration' = the number of SECONDS you want the session to last.
| by default sessions last 7200 seconds (two hours). Set to zero for no expiration.
@@ -278,6 +281,8 @@ $config['encryption_key'] = '';
| 'sess_time_to_update' = how many seconds between CI refreshing Session Information
|
*/
+$config['sess_driver'] = 'cookie';
+$config['sess_valid_drivers'] = array();
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 7200;
$config['sess_expire_on_close'] = FALSE;
@@ -401,15 +406,19 @@ $config['rewrite_short_tags'] = FALSE;
| Reverse Proxy IPs
|--------------------------------------------------------------------------
|
-| If your server is behind a reverse proxy, you must whitelist the proxy IP
-| addresses from which CodeIgniter should trust the HTTP_X_FORWARDED_FOR
-| header in order to properly identify the visitor's IP address.
-| Comma-delimited, e.g. '10.0.1.200,10.0.1.201'
+| If your server is behind a reverse proxy, you must whitelist the proxy
+| IP addresses from which CodeIgniter should trust headers such as
+| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify
+| the visitor's IP address.
|
+| You can use both an array or a comma-separated list of proxy addresses,
+| as well as specifying whole subnets. Here are a few examples:
+|
+| Comma-separated: '10.0.1.200,192.168.5.0/24'
+| Array: array('10.0.1.200', '192.168.5.0/24')
*/
$config['proxy_ips'] = '';
-
/* End of file config.php */
-/* Location: ./application/config/config.php */
+/* Location: ./application/config/config.php */ \ No newline at end of file
diff --git a/application/config/constants.php b/application/config/constants.php
index d22d2963e..62a18e761 100644
--- a/application/config/constants.php
+++ b/application/config/constants.php
@@ -52,14 +52,14 @@ define('DIR_WRITE_MODE', 0777);
|
*/
-define('FOPEN_READ', 'rb');
-define('FOPEN_READ_WRITE', 'r+b');
-define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); // truncates existing file data, use with care
-define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE', 'w+b'); // truncates existing file data, use with care
-define('FOPEN_WRITE_CREATE', 'ab');
-define('FOPEN_READ_WRITE_CREATE', 'a+b');
-define('FOPEN_WRITE_CREATE_STRICT', 'xb');
-define('FOPEN_READ_WRITE_CREATE_STRICT', 'x+b');
+define('FOPEN_READ', 'rb');
+define('FOPEN_READ_WRITE', 'r+b');
+define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); // truncates existing file data, use with care
+define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE', 'w+b'); // truncates existing file data, use with care
+define('FOPEN_WRITE_CREATE', 'ab');
+define('FOPEN_READ_WRITE_CREATE', 'a+b');
+define('FOPEN_WRITE_CREATE_STRICT', 'xb');
+define('FOPEN_READ_WRITE_CREATE_STRICT', 'x+b');
/*
|--------------------------------------------------------------------------
diff --git a/application/config/database.php b/application/config/database.php
index bb0d87be0..4c5cad03f 100644
--- a/application/config/database.php
+++ b/application/config/database.php
@@ -63,6 +63,7 @@
| Sites using Latin-1 or UTF-8 database character set and collation are unaffected.
| ['swap_pre'] A default table prefix that should be swapped with the dbprefix
| ['autoinit'] Whether or not to automatically initialize the database.
+| ['compress'] Whether or not to use client compression (only MySQL and MySQLi)
| ['stricton'] TRUE/FALSE - forces 'Strict Mode' connections
| - good for ensuring strict SQL while developing
| ['failover'] array - A array with 0 or more data for connections if the main should fail.
@@ -93,6 +94,7 @@ $db['default'] = array(
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'autoinit' => TRUE,
+ 'compress' => TRUE,
'stricton' => FALSE,
'failover' => array()
);
diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php
index 41de123da..6614caa31 100644
--- a/application/config/foreign_chars.php
+++ b/application/config/foreign_chars.php
@@ -40,20 +40,20 @@ $foreign_characters = array(
'/Ä/' => 'Ae',
'/Ü/' => 'Ue',
'/Ö/' => 'Oe',
- '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά/' => 'A',
- '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά/' => 'a',
+ '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά|Ả|Ạ|Ầ|Ẫ|Ẩ|Ậ|Ằ|Ắ|Ẵ|Ẳ|Ặ/' => 'A',
+ '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά|ả|ạ|ầ|ấ|ẫ|ẩ|ậ|ằ|ắ|ẵ|ẳ|ặ/' => 'a',
'/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
'/ç|ć|ĉ|ċ|č/' => 'c',
'/Ð|Ď|Đ|Δ/' => 'Dj',
'/ð|ď|đ|δ/' => 'dj',
- '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ/' => 'E',
- '/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε/' => 'e',
+ '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ/' => 'E',
+ '/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ/' => 'e',
'/Ĝ|Ğ|Ġ|Ģ|Γ/' => 'G',
'/ĝ|ğ|ġ|ģ|γ/' => 'g',
'/Ĥ|Ħ/' => 'H',
'/ĥ|ħ/' => 'h',
- '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ/' => 'I',
- '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ/' => 'i',
+ '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị/' => 'I',
+ '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị/' => 'i',
'/Ĵ/' => 'J',
'/ĵ/' => 'j',
'/Ķ|Κ/' => 'K',
@@ -62,18 +62,18 @@ $foreign_characters = array(
'/ĺ|ļ|ľ|ŀ|ł|λ/' => 'l',
'/Ñ|Ń|Ņ|Ň|Ν/' => 'N',
'/ñ|ń|ņ|ň|ʼn|ν/' => 'n',
- '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ/' => 'O',
- '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ/' => 'o',
+ '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ|Ỏ|Ọ|Ồ|Ố|Ỗ|Ổ|Ộ|Ờ|Ớ|Ỡ|Ở|Ợ/' => 'O',
+ '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ|ỏ|ọ|ồ|ố|ỗ|ổ|ộ|ờ|ớ|ỡ|ở|ợ/' => 'o',
'/Ŕ|Ŗ|Ř|Ρ/' => 'R',
'/ŕ|ŗ|ř|ρ/' => 'r',
'/Ś|Ŝ|Ş|Ș|Š|Σ/' => 'S',
'/ś|ŝ|ş|ș|š|ſ|σ|ς/' => 's',
'/Ț|Ţ|Ť|Ŧ|τ/' => 'T',
'/ț|ţ|ť|ŧ/' => 't',
- '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U',
- '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ/' => 'u',
- '/Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ/' => 'Y',
- '/ý|ÿ|ŷ/' => 'y',
+ '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự/' => 'U',
+ '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự/' => 'u',
+ '/Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ/' => 'Y',
+ '/ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ/' => 'y',
'/Ŵ/' => 'W',
'/ŵ/' => 'w',
'/Ź|Ż|Ž|Ζ/' => 'Z',
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 4b1d6a85d..90ffe61ff 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -37,7 +37,7 @@
return array(
'hqx' => array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'),
'cpt' => 'application/mac-compactpro',
- 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'),
+ 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel', 'text/plain'),
'bin' => array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'),
'dms' => 'application/octet-stream',
'lha' => 'application/octet-stream',
@@ -49,14 +49,14 @@ return array(
'sea' => 'application/octet-stream',
'dll' => 'application/octet-stream',
'oda' => 'application/oda',
- 'pdf' => array('application/pdf', 'application/x-download'),
+ 'pdf' => array('application/pdf', 'application/x-download', 'binary/octet-stream'),
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
'smi' => 'application/smil',
'smil' => 'application/smil',
'mif' => 'application/vnd.mif',
- 'xls' => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),
+ 'xls' => array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'),
'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'),
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'wbxml' => 'application/wbxml',
@@ -123,8 +123,10 @@ return array(
'avi' => array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'),
'movie' => 'video/x-sgi-movie',
'doc' => array('application/msword', 'application/vnd.ms-office'),
- 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'),
- 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'),
+ 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'),
+ 'dot' => array('application/msword', 'application/vnd.ms-office'),
+ 'dotx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'),
+ 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword'),
'word' => array('application/msword', 'application/octet-stream'),
'xl' => 'application/excel',
'eml' => 'message/rfc822',
diff --git a/application/config/user_agents.php b/application/config/user_agents.php
index 416ef5679..78e4c8c7d 100644
--- a/application/config/user_agents.php
+++ b/application/config/user_agents.php
@@ -36,6 +36,7 @@
*/
$platforms = array(
+ 'windows nt 6.2' => 'Windows 8',
'windows nt 6.1' => 'Windows 7',
'windows nt 6.0' => 'Windows Vista',
'windows nt 5.2' => 'Windows 2003',
@@ -146,6 +147,7 @@ $mobiles = array(
'ipaq' => 'HP iPaq',
'mot-' => 'Motorola',
'playstation portable' => 'PlayStation Portable',
+ 'playstation 3' => 'PlayStation 3',
'hiptop' => 'Danger Hiptop',
'nec-' => 'NEC',
'panasonic' => 'Panasonic',
@@ -155,10 +157,10 @@ $mobiles = array(
'spv' => 'SPV',
'zte' => 'ZTE',
'sendo' => 'Sendo',
- 'dsi' => 'Nintendo DSi',
- 'ds' => 'Nintendo DS',
+ 'nintendo dsi' => 'Nintendo DSi',
+ 'nintendo ds' => 'Nintendo DS',
+ 'nintendo 3ds' => 'Nintendo 3DS',
'wii' => 'Nintendo Wii',
- '3ds' => 'Nintendo 3DS',
'open web' => 'Open Web',
'openweb' => 'OpenWeb',
diff --git a/application/views/errors/error_404.php b/application/views/errors/error_404.php
index c19bedfcd..fe48fd524 100644
--- a/application/views/errors/error_404.php
+++ b/application/views/errors/error_404.php
@@ -31,9 +31,9 @@
<title>404 Page Not Found</title>
<style type="text/css">
-::selection{ background-color: #E13300; color: white; }
-::moz-selection{ background-color: #E13300; color: white; }
-::webkit-selection{ background-color: #E13300; color: white; }
+::selection { background-color: #E13300; color: white; }
+::-moz-selection { background-color: #E13300; color: white; }
+::-webkit-selection { background-color: #E13300; color: white; }
body {
background-color: #fff;
@@ -73,6 +73,8 @@ code {
margin: 10px;
border: 1px solid #D0D0D0;
box-shadow: 0 0 8px #D0D0D0;
+ -moz-box-shadow: 0 0 8px #D0D0D0;
+ -webkit-box-shadow: 0 0 8px #D0D0D0;
}
p {
diff --git a/application/views/errors/error_db.php b/application/views/errors/error_db.php
index 3b244e094..76ca6df7a 100644
--- a/application/views/errors/error_db.php
+++ b/application/views/errors/error_db.php
@@ -31,9 +31,9 @@
<title>Database Error</title>
<style type="text/css">
-::selection{ background-color: #E13300; color: white; }
-::moz-selection{ background-color: #E13300; color: white; }
-::webkit-selection{ background-color: #E13300; color: white; }
+::selection { background-color: #E13300; color: white; }
+::-moz-selection { background-color: #E13300; color: white; }
+::-webkit-selection { background-color: #E13300; color: white; }
body {
background-color: #fff;
@@ -73,6 +73,8 @@ code {
margin: 10px;
border: 1px solid #D0D0D0;
box-shadow: 0 0 8px #D0D0D0;
+ -moz-box-shadow: 0 0 8px #D0D0D0;
+ -webkit-box-shadow: 0 0 8px #D0D0D0;
}
p {
diff --git a/application/views/errors/error_general.php b/application/views/errors/error_general.php
index c88afe168..e9baf1665 100644
--- a/application/views/errors/error_general.php
+++ b/application/views/errors/error_general.php
@@ -31,9 +31,9 @@
<title>Error</title>
<style type="text/css">
-::selection{ background-color: #E13300; color: white; }
-::moz-selection{ background-color: #E13300; color: white; }
-::webkit-selection{ background-color: #E13300; color: white; }
+::selection { background-color: #E13300; color: white; }
+::-moz-selection { background-color: #E13300; color: white; }
+::-webkit-selection { background-color: #E13300; color: white; }
body {
background-color: #fff;
@@ -73,6 +73,8 @@ code {
margin: 10px;
border: 1px solid #D0D0D0;
box-shadow: 0 0 8px #D0D0D0;
+ -moz-box-shadow: 0 0 8px #D0D0D0;
+ -webkit-box-shadow: 0 0 8px #D0D0D0;
}
p {
diff --git a/application/views/welcome_message.php b/application/views/welcome_message.php
index 65f62a922..d227f82d1 100644
--- a/application/views/welcome_message.php
+++ b/application/views/welcome_message.php
@@ -32,9 +32,9 @@
<style type="text/css">
- ::selection{ background-color: #E13300; color: white; }
- ::moz-selection{ background-color: #E13300; color: white; }
- ::webkit-selection{ background-color: #E13300; color: white; }
+ ::selection { background-color: #E13300; color: white; }
+ ::-moz-selection { background-color: #E13300; color: white; }
+ ::-webkit-selection { background-color: #E13300; color: white; }
body {
background-color: #fff;
@@ -70,11 +70,11 @@
padding: 12px 10px 12px 10px;
}
- #body{
+ #body {
margin: 0 15px 0 15px;
}
- p.footer{
+ p.footer {
text-align: right;
font-size: 11px;
border-top: 1px solid #D0D0D0;
@@ -83,9 +83,10 @@
margin: 20px 0 0 0;
}
- #container{
+ #container {
margin: 10px;
border: 1px solid #D0D0D0;
+ -moz-box-shadow: 0 0 8px #D0D0D0;
-webkit-box-shadow: 0 0 8px #D0D0D0;
}
</style>
diff --git a/composer.json b/composer.json
index fa6dc02e4..dc098acc3 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,8 @@
{
"require": {
"mikey179/vfsStream": "*"
- }
+ },
+ "require-dev": {
+ "EHER/PHPUnit": "*"
+ }
} \ No newline at end of file
diff --git a/contributing.md b/contributing.md
new file mode 100644
index 000000000..f3f94fbc8
--- /dev/null
+++ b/contributing.md
@@ -0,0 +1,92 @@
+# Contributing to CodeIgniter
+
+
+CodeIgniter is a community driven project and accepts contributions of code and documentation from the community. These contributions are made in the form of Issues or [Pull Requests](http://help.github.com/send-pull-requests/) on the [EllisLab CodeIgniter repository](https://github.com/EllisLab/CodeIgniter>) on GitHub.
+
+Issues are a quick way to point out a bug. If you find a bug or documentation error in CodeIgniter then please check a few things first:
+
+1. There is not already an open Issue
+2. The issue has already been fixed (check the develop branch, or look for closed Issues)
+3. Is it something really obvious that you fix it yourself?
+
+Reporting issues is helpful but an even better approach is to send a Pull Request, which is done by "Forking" the main repository and committing to your own copy. This will require you to use the version control system called Git.
+
+## Guidelines
+
+Before we look into how, here are the guidelines. If your Pull Requests fail
+to pass these guidelines it will be declined and you will need to re-submit
+when you’ve made the changes. This might sound a bit tough, but it is required
+for us to maintain quality of the code-base.
+
+### PHP Style
+
+All code must meet the [Style Guide](http://codeigniter.com/user_guide/general/styleguide.html), which is
+essentially the [Allman indent style](http://en.wikipedia.org/wiki/Indent_style#Allman_style), underscores and readable operators. This makes certain that all code is the same format as the existing code and means it will be as readable as possible.
+
+### Documentation
+
+If you change anything that requires a change to documentation then you will need to add it. New classes, methods, parameters, changing default values, etc are all things that will require a change to documentation. The change-log must also be updated for every change. Also PHPDoc blocks must be maintained.
+
+### Compatibility
+
+CodeIgniter is compatible with PHP 5.2.4 so all code supplied must stick to
+this requirement. If PHP 5.3 or 5.4 functions or features are used then there
+must be a fallback for PHP 5.2.4.
+
+### Branching
+
+CodeIgniter uses the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model which requires all pull requests to be sent to the "develop" branch. This is
+where the next planned version will be developed. The "master" branch will always contain the latest stable version and is kept clean so a "hotfix" (e.g: an emergency security patch) can be applied to master to create a new version, without worrying about other features holding it up. For this reason all commits need to be made to "develop" and any sent to "master" will be closed automatically. If you have multiple changes to submit, please place all changes into their own branch on your fork.
+
+One thing at a time: A pull request should only contain one change. That does not mean only one commit, but one change - however many commits it took. The reason for this is that if you change X and Y but send a pull request for both at the same time, we might really want X but disagree with Y, meaning we cannot merge the request. Using the Git-Flow branching model you can create new branches for both of these features and send two requests.
+
+### Signing
+
+You must sign your work, certifying that you either wrote the work or otherwise have the right to pass it on to an open source project. git makes this trivial as you merely have to use `--signoff` on your commits to your CodeIgniter fork.
+
+`git commit --signoff`
+
+or simply
+
+`git commit -s`
+
+This will sign your commits with the information setup in your git config, e.g.
+
+`Signed-off-by: John Q Public <john.public@example.com>`
+
+If you are using [Tower](http://www.git-tower.com/) there is a "Sign-Off" checkbox in the commit window. You could even alias git commit to use the `-s` flag so you don’t have to think about it.
+
+By signing your work in this manner, you certify to a "Developer's Certificate of Origin". The current version of this certificate is in the `DCO.txt` file in the root of this repository.
+
+
+## How-to Guide
+
+There are two ways to make changes, the easy way and the hard way. Either way you will need to [create a GitHub account](https://github.com/signup/free).
+
+Easy way GitHub allows in-line editing of files for making simple typo changes and quick-fixes. This is not the best way as you are unable to test the code works. If you do this you could be introducing syntax errors, etc, but for a Git-phobic user this is good for a quick-fix.
+
+Hard way The best way to contribute is to "clone" your fork of CodeIgniter to your development area. That sounds like some jargon, but "forking" on GitHub means "making a copy of that repo to your account" and "cloning" means "copying that code to your environment so you can work on it".
+
+1. Set up Git (Windows, Mac & Linux)
+2. Go to the CodeIgniter repo
+3. Fork it
+4. Clone your CodeIgniter repo: git@github.com:<your-name>/CodeIgniter.git
+5. Checkout the "develop" branch At this point you are ready to start making changes.
+6. Fix existing bugs on the Issue tracker after taking a look to see nobody else is working on them.
+7. Commit the files
+8. Push your develop branch to your fork
+9. Send a pull request [http://help.github.com/send-pull-requests/](http://help.github.com/send-pull-requests/)
+
+The Reactor Engineers will now be alerted about the change and at least one of the team will respond. If your change fails to meet the guidelines it will be bounced, or feedback will be provided to help you improve it.
+
+Once the Reactor Engineer handling your pull request is happy with it they will post it to the internal EllisLab discussion area to be double checked by the other Engineers and EllisLab developers. If nobody has a problem with the change then it will be merged into develop and will be part of the next release. Keeping your fork up-to-date
+
+Unlike systems like Subversion, Git can have multiple remotes. A remote is the name for a URL of a Git repository. By default your fork will have a remote named "origin" which points to your fork, but you can add another remote named "codeigniter" which points to `git://github.com/EllisLab/CodeIgniter.git`. This is a read-only remote but you can pull from this develop branch to update your own.
+
+If you are using command-line you can do the following:
+
+1. `git remote add codeigniter git://github.com/EllisLab/CodeIgniter.git`
+2. `git pull codeigniter develop`
+3. `git push origin develop`
+
+Now your fork is up to date. This should be done regularly, or before you send a pull request at least. \ No newline at end of file
diff --git a/readme.rst b/readme.rst
index b211ad7cd..8628645c6 100644
--- a/readme.rst
+++ b/readme.rst
@@ -38,166 +38,6 @@ Installation
Please see the `installation section <http://codeigniter.com/user_guide/installation/index.html>`_
of the CodeIgniter User Guide.
-************
-Contributing
-************
-
-CodeIgniter is a community driven project and accepts contributions of code
-and documentation from the community. These contributions are made in the form
-of Issues or `Pull Requests <http://help.github.com/send-pull-requests/>`_ on
-the `EllisLab CodeIgniter repository
-<https://github.com/EllisLab/CodeIgniter>`_ on GitHub.
-
-Issues are a quick way to point out a bug. If you find a bug or documentation
-error in CodeIgniter then please check a few things first:
-
-- There is not already an open Issue
-- The issue has already been fixed (check the develop branch, or look for
- closed Issues)
-- Is it something really obvious that you fix it yourself?
-
-Reporting issues is helpful but an even better approach is to send a Pull
-Request, which is done by "Forking" the main repository and committing to your
-own copy. This will require you to use the version control system called Git.
-
-**********
-Guidelines
-**********
-
-Before we look into how, here are the guidelines. If your Pull Requests fail
-to pass these guidelines it will be declined and you will need to re-submit
-when you’ve made the changes. This might sound a bit tough, but it is required
-for us to maintain quality of the code-base.
-
-PHP Style
-=========
-
-All code must meet the `Style Guide
-<http://codeigniter.com/user_guide/general/styleguide.html>`_, which is
-essentially the `Allman indent style
-<http://en.wikipedia.org/wiki/Indent_style#Allman_style>`_, underscores and
-readable operators. This makes certain that all code is the same format as the
-existing code and means it will be as readable as possible.
-
-Documentation
-=============
-
-If you change anything that requires a change to documentation then you will
-need to add it. New classes, methods, parameters, changing default values, etc
-are all things that will require a change to documentation. The change-log
-must also be updated for every change. Also PHPDoc blocks must be maintained.
-
-Compatibility
-=============
-
-CodeIgniter is compatible with PHP 5.2.4 so all code supplied must stick to
-this requirement. If PHP 5.3 or 5.4 functions or features are used then there
-must be a fallback for PHP 5.2.4.
-
-Branching
-=========
-
-CodeIgniter uses the `Git-Flow
-<http://nvie.com/posts/a-successful-git-branching-model/>`_ branching model
-which requires all pull requests to be sent to the "develop" branch. This is
-where the next planned version will be developed. The "master" branch will
-always contain the latest stable version and is kept clean so a "hotfix" (e.g:
-an emergency security patch) can be applied to master to create a new version,
-without worrying about other features holding it up. For this reason all
-commits need to be made to "develop" and any sent to "master" will be closed
-automatically. If you have multiple changes to submit, please place all
-changes into their own branch on your fork.
-
-One thing at a time: A pull request should only contain one change. That does
-not mean only one commit, but one change - however many commits it took. The
-reason for this is that if you change X and Y but send a pull request for both
-at the same time, we might really want X but disagree with Y, meaning we
-cannot merge the request. Using the Git-Flow branching model you can create
-new branches for both of these features and send two requests.
-
-Signing
-=======
-You must sign your work, certifying that you either wrote the work or
-otherwise have the right to pass it on to an open source project. git makes
-this trivial as you merely have to use `--signoff` on your commits to your
-CodeIgniter fork.
-
-::
-
- git commit --signoff
-
-or simply::
-
- git commit -s
-
-This will sign your commits with the information setup in your git config, e.g.
-
- Signed-off-by: John Q Public <john.public@example.com>
-
-If you are using Tower there is a "Sign-Off" checkbox in the commit window. You
-could even alias git commit to use the -s flag so you don’t have to think about
-it.
-
-By signing your work in this manner, you certify to a "Developer's Certificate
-or Origin". The current version of this certificate is in the `DCO.txt` file
-in the root of this repository.
-
-
-************
-How-to Guide
-************
-
-There are two ways to make changes, the easy way and the hard way. Either way
-you will need to `create a GitHub account <https://github.com/signup/free>`_.
-
-Easy way GitHub allows in-line editing of files for making simple typo changes
-and quick-fixes. This is not the best way as you are unable to test the code
-works. If you do this you could be introducing syntax errors, etc, but for a
-Git-phobic user this is good for a quick-fix.
-
-Hard way The best way to contribute is to "clone" your fork of CodeIgniter to
-your development area. That sounds like some jargon, but "forking" on GitHub
-means "making a copy of that repo to your account" and "cloning" means
-"copying that code to your environment so you can work on it".
-
-#. Set up Git (Windows, Mac & Linux)
-#. Go to the CodeIgniter repo
-#. Fork it
-#. Clone your CodeIgniter repo: git@github.com:<your-name>/CodeIgniter.git
-#. Checkout the "develop" branch At this point you are ready to start making
- changes.
-#. Fix existing bugs on the Issue tracker after taking a look to see nobody
- else is working on them.
-#. Commit the files
-#. Push your develop branch to your fork
-#. Send a pull request http://help.github.com/send-pull-requests/
-
-The Reactor Engineers will now be alerted about the change and at least one of
-the team will respond. If your change fails to meet the guidelines it will be
-bounced, or feedback will be provided to help you improve it.
-
-Once the Reactor Engineer handling your pull request is happy with it they
-will post it to the internal EllisLab discussion area to be double checked by
-the other Engineers and EllisLab developers. If nobody has a problem with the
-change then it will be merged into develop and will be part of the next
-release. Keeping your fork up-to-date
-
-Unlike systems like Subversion, Git can have multiple remotes. A remote is the
-name for a URL of a Git repository. By default your fork will have a remote
-named "origin" which points to your fork, but you can add another remote named
-"codeigniter" which points to git://github.com/EllisLab/CodeIgniter.git. This
-is a read-only remote but you can pull from this develop branch to update your
-own.
-
-If you are using command-line you can do the following:
-
-#. git remote add codeigniter git://github.com/EllisLab/CodeIgniter.git
-#. git pull codeigniter develop
-#. git push origin develop
-
-Now your fork is up to date. This should be done regularly, or before you send
-a pull request at least.
-
*******
License
*******
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 8159b19f5..f3592eaf9 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -50,7 +50,7 @@
* Load the global functions
* ------------------------------------------------------
*/
- require(BASEPATH.'core/Common.php');
+ require_once(BASEPATH.'core/Common.php');
/*
* ------------------------------------------------------
diff --git a/system/core/Common.php b/system/core/Common.php
index 06b162264..341402c6b 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -150,7 +150,7 @@ if ( ! function_exists('load_class'))
if (class_exists($name) === FALSE)
{
- require($path.$directory.'/'.$class.'.php');
+ require_once($path.$directory.'/'.$class.'.php');
}
break;
@@ -164,7 +164,7 @@ if ( ! function_exists('load_class'))
if (class_exists($name) === FALSE)
{
- require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php');
+ require_once(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php');
}
}
@@ -488,13 +488,9 @@ if ( ! function_exists('set_status_header'))
{
header('Status: '.$code.' '.$text, TRUE);
}
- elseif ($server_protocol === 'HTTP/1.0')
- {
- header('HTTP/1.0 '.$code.' '.$text, TRUE, $code);
- }
else
{
- header('HTTP/1.1 '.$code.' '.$text, TRUE, $code);
+ header(($server_protocol ? $server_protocol : 'HTTP/1.1').' '.$code.' '.$text, TRUE, $code);
}
}
}
@@ -524,18 +520,17 @@ if ( ! function_exists('_exception_handler'))
{
$_error =& load_class('Exceptions', 'core');
- // Should we display the error? We'll get the current error_reporting
+ // Should we ignore the error? We'll get the current error_reporting
// level and add its bits with the severity bits to find out.
- // And respect display_errors
- if (($severity & error_reporting()) === $severity && (bool) ini_get('display_errors') === TRUE)
+ if (($severity & error_reporting()) !== $severity)
{
- $_error->show_php_error($severity, $message, $filepath, $line);
+ return;
}
- // Should we log the error? No? We're done...
- if (config_item('log_threshold') === 0)
+ // Should we display the error?
+ if ((bool) ini_get('display_errors') === TRUE)
{
- return;
+ $_error->show_php_error($severity, $message, $filepath, $line);
}
$_error->log_exception($severity, $message, $filepath, $line);
@@ -598,5 +593,44 @@ if ( ! function_exists('html_escape'))
}
}
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('_stringify_attributes'))
+{
+ /**
+ * Stringify attributes for use in HTML tags.
+ *
+ * Helper function used to convert a string, array, or object
+ * of attributes to a string.
+ *
+ * @param mixed string, array, object
+ * @param bool
+ * @return string
+ */
+ function _stringify_attributes($attributes, $js = FALSE)
+ {
+ $atts = NULL;
+
+ if (empty($attributes))
+ {
+ return $atts;
+ }
+
+ if (is_string($attributes))
+ {
+ return ' '.$attributes;
+ }
+
+ $attributes = (array) $attributes;
+
+ foreach ($attributes as $key => $val)
+ {
+ $atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"';
+ }
+
+ return rtrim($atts, ',');
+ }
+}
+
/* End of file Common.php */
/* Location: ./system/core/Common.php */ \ No newline at end of file
diff --git a/system/core/Config.php b/system/core/Config.php
index 2f6a9e085..8e4f998ef 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -102,7 +102,7 @@ class CI_Config {
{
$file = ($file === '') ? 'config' : str_replace('.php', '', $file);
$found = $loaded = FALSE;
-
+
$check_locations = defined('ENVIRONMENT')
? array(ENVIRONMENT.'/'.$file, $file)
: array($file);
diff --git a/system/core/Input.php b/system/core/Input.php
index 162e40c85..82482f2aa 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -328,39 +328,113 @@ class CI_Input {
return $this->ip_address;
}
- if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR'))
+ $proxy_ips = config_item('proxy_ips');
+ if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
{
- $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY);
- $proxies = is_array($proxies) ? $proxies : array($proxies);
-
- $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
- }
- elseif ( ! $this->server('HTTP_CLIENT_IP') && $this->server('REMOTE_ADDR'))
- {
- $this->ip_address = $_SERVER['REMOTE_ADDR'];
- }
- elseif ($this->server('REMOTE_ADDR') && $this->server('HTTP_CLIENT_IP'))
- {
- $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
- }
- elseif ($this->server('HTTP_CLIENT_IP'))
- {
- $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
- }
- elseif ($this->server('HTTP_X_FORWARDED_FOR'))
- {
- $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
+ $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
}
- if ($this->ip_address === FALSE)
- {
- return $this->ip_address = '0.0.0.0';
- }
+ $this->ip_address = $this->server('REMOTE_ADDR');
- if (strpos($this->ip_address, ',') !== FALSE)
+ if ($proxy_ips)
{
- $x = explode(',', $this->ip_address);
- $this->ip_address = trim(end($x));
+ foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)
+ {
+ if (($spoof = $this->server($header)) !== NULL)
+ {
+ // Some proxies typically list the whole chain of IP
+ // addresses through which the client has reached us.
+ // e.g. client_ip, proxy_ip1, proxy_ip2, etc.
+ if (strpos($spoof, ',') !== FALSE)
+ {
+ $spoof = explode(',', $spoof, 2);
+ $spoof = $spoof[0];
+ }
+
+ if ( ! $this->valid_ip($spoof))
+ {
+ $spoof = NULL;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ if ($spoof)
+ {
+ for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
+ {
+ // Check if we have an IP address or a subnet
+ if (strpos($proxy_ips[$i], '/') === FALSE)
+ {
+ // An IP address (and not a subnet) is specified.
+ // We can compare right away.
+ if ($proxy_ips[$i] === $this->ip_address)
+ {
+ $this->ip_address = $spoof;
+ break;
+ }
+
+ continue;
+ }
+
+ // We have a subnet ... now the heavy lifting begins
+ isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
+
+ // If the proxy entry doesn't match the IP protocol - skip it
+ if (strpos($proxy_ips[$i], $separator) === FALSE)
+ {
+ continue;
+ }
+
+ // Convert the REMOTE_ADDR IP address to binary, if needed
+ if ( ! isset($ip, $convert_func))
+ {
+ if ($separator === ':')
+ {
+ // Make sure we're have the "full" IPv6 format
+ $ip = str_replace('::', str_repeat(':', 9 - substr_count($this->ip_address, ':')), $this->ip_address);
+ $convert_func = is_php('5.3')
+ ? function ($value)
+ {
+ return str_pad(base_convert($value, 16, 2), 16, '0', STR_PAD_LEFT);
+ }
+ : create_function('$value', 'return str_pad(base_convert($value, 16, 2), 16, "0", STR_PAD_LEFT);');
+ }
+ else
+ {
+ $ip = $this->ip_address;
+ $convert_func = is_php('5.3')
+ ? function ($value)
+ {
+ return str_pad(decbin($value), 8, '0', STR_PAD_LEFT);
+ }
+ : create_function('$value', 'return str_pad(decbin($value), 8, "0", STR_PAD_LEFT);');
+ }
+
+ $ip = implode(array_map($convert_func, explode($separator, $ip)));
+ }
+
+ // Split the netmask length off the network address
+ list($netaddr, $masklen) = explode('/', $proxy_ips[$i], 2);
+
+ // Again, an IPv6 address is most likely in a compressed form
+ if ($separator === ':')
+ {
+ $netaddr = str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr);
+ }
+
+ // Convert to a binary form and finally compare
+ $netaddr = implode(array_map($convert_func, explode($separator, $netaddr)));
+ if (strncmp($ip, $netaddr, $masklen) === 0)
+ {
+ $this->ip_address = $spoof;
+ break;
+ }
+ }
+ }
}
if ( ! $this->valid_ip($this->ip_address))
@@ -518,7 +592,7 @@ class CI_Input {
$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
// CSRF Protection check
- if ($this->_enable_csrf === TRUE)
+ if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
{
$this->security->csrf_verify();
}
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 0bc6e844a..75e93608a 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -409,8 +409,8 @@ class CI_Loader {
* 1. The name of the "view" file to be included.
* 2. An associative array of data to be extracted for use in the view.
* 3. TRUE/FALSE - whether to return the data or load it. In
- * some cases it's advantageous to be able to return data so that
- * a developer can process it in some way.
+ * some cases it's advantageous to be able to return data so that
+ * a developer can process it in some way.
*
* @param string
* @param array
@@ -633,13 +633,7 @@ class CI_Loader {
{
$this->driver($driver);
}
- return FALSE;
- }
-
- if ( ! class_exists('CI_Driver_Library'))
- {
- // we aren't instantiating an object here, that'll be done by the Library itself
- require BASEPATH.'libraries/Driver.php';
+ return;
}
if ($library === '')
@@ -785,11 +779,11 @@ class CI_Loader {
$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
$_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view;
- foreach ($this->_ci_view_paths as $view_file => $cascade)
+ foreach ($this->_ci_view_paths as $_ci_view_file => $cascade)
{
- if (file_exists($view_file.$_ci_file))
+ if (file_exists($_ci_view_file.$_ci_file))
{
- $_ci_path = $view_file.$_ci_file;
+ $_ci_path = $_ci_view_file.$_ci_file;
$file_exists = TRUE;
break;
}
@@ -837,10 +831,10 @@ class CI_Loader {
* We buffer the output for two reasons:
* 1. Speed. You get a significant speed boost.
* 2. So that the final rendered template can be post-processed by
- * the output class. Why do we need post processing? For one thing,
- * in order to show the elapsed page load time. Unless we can
- * intercept the content right before it's sent to the browser and
- * then stop the timer it won't be accurate.
+ * the output class. Why do we need post processing? For one thing,
+ * in order to show the elapsed page load time. Unless we can
+ * intercept the content right before it's sent to the browser and
+ * then stop the timer it won't be accurate.
*/
ob_start();
@@ -915,6 +909,13 @@ class CI_Loader {
// Get the filename from the path
$class = substr($class, $last_slash);
+
+ // Check for match and driver base class
+ if (strtolower(trim($subdir, '/')) == strtolower($class) && ! class_exists('CI_Driver_Library'))
+ {
+ // We aren't instantiating an object here, just making the base class available
+ require BASEPATH.'libraries/Driver.php';
+ }
}
// We'll test for both lowercase and capitalized versions of the file name
@@ -996,14 +997,19 @@ class CI_Loader {
$this->_ci_loaded_files[] = $filepath;
return $this->_ci_init_class($class, '', $params, $object_name);
}
-
} // END FOREACH
// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
if ($subdir === '')
{
$path = strtolower($class).'/'.$class;
- return $this->_ci_load_class($path, $params);
+ return $this->_ci_load_class($path, $params, $object_name);
+ }
+ else if (ucfirst($subdir) != $subdir)
+ {
+ // Lowercase subdir failed - retry capitalized
+ $path = ucfirst($subdir).$class;
+ return $this->_ci_load_class($path, $params, $object_name);
}
// If we got this far we were unable to find the requested class.
@@ -1193,6 +1199,15 @@ class CI_Loader {
}
}
+ // Autoload drivers
+ if (isset($autoload['drivers']))
+ {
+ foreach ($autoload['drivers'] as $item)
+ {
+ $this->driver($item);
+ }
+ }
+
// Autoload models
if (isset($autoload['model']))
{
diff --git a/system/core/Output.php b/system/core/Output.php
index 5ec8c4bc0..052367ed6 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -552,13 +552,13 @@ class CI_Output {
fclose($fp);
// Strip out the embedded timestamp
- if ( ! preg_match('/(\d+TS--->)/', $cache, $match))
+ if ( ! preg_match('/^(\d+)TS--->/', $cache, $match))
{
return FALSE;
}
$last_modified = filemtime($cache_path);
- $expire = trim(str_replace('TS--->', '', $match[1]));
+ $expire = $match[1];
// Has the file expired?
if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
@@ -575,7 +575,7 @@ class CI_Output {
}
// Display the cache
- $this->_display(str_replace($match[0], '', $cache));
+ $this->_display(substr($cache, strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
return TRUE;
}
diff --git a/system/core/Utf8.php b/system/core/Utf8.php
index 0a7ec501c..1ff02981b 100644
--- a/system/core/Utf8.php
+++ b/system/core/Utf8.php
@@ -49,30 +49,31 @@ class CI_Utf8 {
{
log_message('debug', 'Utf8 Class Initialized');
- global $CFG;
+ $charset = strtoupper(config_item('charset'));
+
+ // set internal encoding for multibyte string functions if necessary
+ // and set a flag so we don't have to repeatedly use extension_loaded()
+ // or function_exists()
+ if (extension_loaded('mbstring'))
+ {
+ define('MB_ENABLED', TRUE);
+ mb_internal_encoding($charset);
+ }
+ else
+ {
+ define('MB_ENABLED', FALSE);
+ }
+
if (
- @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8
- && function_exists('iconv') // iconv must be installed
- && (bool) @ini_get('mbstring.func_overload') !== TRUE // Multibyte string function overloading cannot be enabled
- && $CFG->item('charset') === 'UTF-8' // Application charset must be UTF-8
+ @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8
+ && function_exists('iconv') // iconv must be installed
+ && MB_ENABLED === TRUE // mbstring must be enabled
+ && $charset === 'UTF-8' // Application charset must be UTF-8
)
{
define('UTF8_ENABLED', TRUE);
log_message('debug', 'UTF-8 Support Enabled');
-
- // set internal encoding for multibyte string functions if necessary
- // and set a flag so we don't have to repeatedly use extension_loaded()
- // or function_exists()
- if (extension_loaded('mbstring'))
- {
- define('MB_ENABLED', TRUE);
- mb_internal_encoding('UTF-8');
- }
- else
- {
- define('MB_ENABLED', FALSE);
- }
}
else
{
@@ -135,7 +136,7 @@ class CI_Utf8 {
{
return @iconv($encoding, 'UTF-8', $str);
}
- elseif (function_exists('mb_convert_encoding'))
+ elseif (MB_ENABLED === TRUE)
{
return @mb_convert_encoding($str, 'UTF-8', $encoding);
}
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index f848cfe4e..ea56d3819 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -51,6 +51,7 @@ abstract class CI_DB_driver {
public $char_set = 'utf8';
public $dbcollat = 'utf8_general_ci';
public $autoinit = TRUE; // Whether to automatically initialize the DB
+ public $compress = TRUE;
public $swap_pre = '';
public $port = '';
public $pconnect = FALSE;
@@ -78,6 +79,10 @@ abstract class CI_DB_driver {
protected $_protect_identifiers = TRUE;
protected $_reserved_identifiers = array('*'); // Identifiers that should NOT be escaped
+ // clause and character used for LIKE escape sequences
+ protected $_like_escape_str = " ESCAPE '%s' ";
+ protected $_like_escape_chr = '!';
+
/**
* The syntax to count rows is slightly different across different
* database engines, so this string appears in each driver and is
@@ -669,7 +674,7 @@ abstract class CI_DB_driver {
*/
public function is_write_type($sql)
{
- return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
+ return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
}
// --------------------------------------------------------------------
@@ -1355,7 +1360,7 @@ abstract class CI_DB_driver {
}
else
{
- $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
+ $message = is_array($error) ? $error : array(str_replace('%s', $swap, $LANG->line($error)));
}
// Find the most likely culprit of the error by going through
@@ -1364,7 +1369,13 @@ abstract class CI_DB_driver {
$trace = debug_backtrace();
foreach ($trace as $call)
{
- if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
+ // We'll need this on Windows, as APPPATH and BASEPATH will always use forward slashes
+ if (DIRECTORY_SEPARATOR !== '/')
+ {
+ $call['file'] = str_replace('\\', '/', $call['file']);
+ }
+
+ if (isset($call['file'], $call['class']) && strpos($call['file'], BASEPATH.'database') === FALSE && strpos($call['class'], 'Loader') !== FALSE)
{
// Found it - use a relative path for safety
$message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']);
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 416132e16..139f467e6 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -1483,19 +1483,18 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// --------------------------------------------------------------------
/**
- * From Tables
+ * FROM tables
*
- * This public function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
*
- * @param array
- * @return string
+ * Note: This is only used (and overriden) by MySQL and CUBRID.
+ *
+ * @return string
*/
- protected function _from_tables($tables)
+ protected function _from_tables()
{
- is_array($tables) OR $tables = array($tables);
-
- return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')';
+ return implode(', ', $this->qb_from);
}
// --------------------------------------------------------------------
@@ -2010,7 +2009,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
// Write the "FROM" portion of the query
if (count($this->qb_from) > 0)
{
- $sql .= "\nFROM ".$this->_from_tables($this->qb_from);
+ $sql .= "\nFROM ".$this->_from_tables();
}
// Write the "JOIN" portion of the query
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index e243aae9f..7f8f297bb 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -45,10 +45,6 @@ class CI_DB_cubrid_driver extends CI_DB {
// The character used for escaping - no need in CUBRID
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in CUBRID
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '';
-
protected $_random_keyword = ' RAND()'; // database specific random keyword
// CUBRID-specific properties
@@ -72,6 +68,8 @@ class CI_DB_cubrid_driver extends CI_DB {
}
}
+ // --------------------------------------------------------------------
+
/**
* Non-persistent database connection
*
@@ -431,6 +429,26 @@ class CI_DB_cubrid_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/ibase/ibase_driver.php b/system/database/drivers/ibase/ibase_driver.php
index 7b37b9999..96d6f6526 100644
--- a/system/database/drivers/ibase/ibase_driver.php
+++ b/system/database/drivers/ibase/ibase_driver.php
@@ -45,10 +45,6 @@ class CI_DB_ibase_driver extends CI_DB {
// The character used to escape with
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' Random()'; // database specific random keyword
// Keeps track of the resource for the current transaction
@@ -309,22 +305,6 @@ class CI_DB_ibase_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This public function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index edc6a8480..4369bbefb 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -45,10 +45,6 @@ class CI_DB_mssql_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' NEWID()';
// MSSQL-specific properties
@@ -366,22 +362,6 @@ class CI_DB_mssql_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index 0a15fe447..60bcf3cfc 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -45,10 +45,6 @@ class CI_DB_mysql_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()'; // database specific random keyword
/**
@@ -83,7 +79,14 @@ class CI_DB_mysql_driver extends CI_DB {
*/
public function db_connect()
{
- return @mysql_connect($this->hostname, $this->username, $this->password, TRUE);
+ if ($this->compress === TRUE)
+ {
+ return @mysql_connect($this->hostname, $this->username, $this->password, TRUE, MYSQL_CLIENT_COMPRESS);
+ }
+ else
+ {
+ return @mysql_connect($this->hostname, $this->username, $this->password, TRUE);
+ }
}
// --------------------------------------------------------------------
@@ -95,7 +98,14 @@ class CI_DB_mysql_driver extends CI_DB {
*/
public function db_pconnect()
{
- return @mysql_pconnect($this->hostname, $this->username, $this->password);
+ if ($this->compress === TRUE)
+ {
+ return @mysql_pconnect($this->hostname, $this->username, $this->password, MYSQL_CLIENT_COMPRESS);
+ }
+ else
+ {
+ return @mysql_pconnect($this->hostname, $this->username, $this->password);
+ }
}
// --------------------------------------------------------------------
@@ -455,6 +465,26 @@ class CI_DB_mysql_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index 5f5a31d34..934694c6c 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -45,10 +45,6 @@ class CI_DB_mysqli_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()'; // database specific random keyword
/**
@@ -65,6 +61,17 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function db_connect()
{
+ // Use MySQL client compression?
+ if ($this->compress === TRUE)
+ {
+ $port = empty($this->port) ? NULL : $this->port;
+
+ $mysqli = new mysqli();
+ @$mysqli->real_connect($this->hostname, $this->username, $this->password, $this->database, $port, NULL, MYSQLI_CLIENT_COMPRESS);
+
+ return $mysqli;
+ }
+
return empty($this->port)
? @new mysqli($this->hostname, $this->username, $this->password, $this->database)
: @new mysqli($this->hostname, $this->username, $this->password, $this->database, $this->port);
@@ -85,6 +92,17 @@ class CI_DB_mysqli_driver extends CI_DB {
return $this->db_connect();
}
+ // Use MySQL client compression?
+ if ($this->compress === TRUE)
+ {
+ $port = empty($this->port) ? NULL : $this->port;
+
+ $mysqli = mysqli_init();
+ $mysqli->real_connect('p:'.$this->hostname, $this->username, $this->password, $this->database, $port, NULL, MYSQLI_CLIENT_COMPRESS);
+
+ return $mysqli;
+ }
+
return empty($this->port)
? @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database)
: @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port);
@@ -400,6 +418,14 @@ class CI_DB_mysqli_driver extends CI_DB {
*/
public function error()
{
+ if ( ! empty($this->conn_id->connect_errno))
+ {
+ return array(
+ 'code' => $this->conn_id->connect_errno,
+ 'message' => is_php('5.2.9') ? $this->conn_id->connect_error : mysqli_connect_error()
+ );
+ }
+
return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error);
}
@@ -447,6 +473,26 @@ class CI_DB_mysqli_driver extends CI_DB {
// --------------------------------------------------------------------
/**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Close DB Connection
*
* @return void
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index dcc46527c..8e4f4ef9d 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -54,10 +54,6 @@ class CI_DB_oci8_driver extends CI_DB {
// The character used for excaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
/**
* The syntax to count rows is slightly different across different
* database engines, so this string appears in each driver and is
@@ -547,22 +543,6 @@ class CI_DB_oci8_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Insert_batch statement
*
* Generates a platform-specific insert string from the supplied data
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index f62400245..741b7419f 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -45,9 +45,7 @@ class CI_DB_odbc_driver extends CI_DB {
// the character used to excape - not necessary for ODBC
protected $_escape_char = '';
- // clause and character used for LIKE escape sequences
protected $_like_escape_str = " {escape '%s'} ";
- protected $_like_escape_chr = '!';
protected $_random_keyword;
@@ -291,22 +289,6 @@ class CI_DB_odbc_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index ee5af783e..f4509b17c 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -45,10 +45,6 @@ class CI_DB_pdo_driver extends CI_DB {
// The character used to escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword;
public $trans_enabled = FALSE;
diff --git a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
index 0e6877c28..438d312a1 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php
@@ -130,22 +130,6 @@ class CI_DB_pdo_4d_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
index 741126310..d2a484d9e 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php
@@ -44,10 +44,6 @@ class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver {
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in CUBRID
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()';
/**
@@ -183,6 +179,26 @@ class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver {
return 'TRUNCATE '.$table;
}
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
}
/* End of file pdo_cubrid_driver.php */
diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
index d6465cda2..782bb53c0 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
@@ -153,22 +153,6 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
@@ -239,4 +223,4 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
}
/* End of file pdo_dblib_driver.php */
-/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php */ \ No newline at end of file
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php */
diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
index 5b36342d2..32d1f219a 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
@@ -139,22 +139,6 @@ class CI_DB_pdo_firebird_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
index 7563a42d6..22a5f928c 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php
@@ -165,22 +165,6 @@ class CI_DB_pdo_ibm_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
index 82480498a..8dd430184 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php
@@ -159,22 +159,6 @@ class CI_DB_pdo_informix_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
index 67da156bf..9ffb93eed 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
@@ -44,10 +44,6 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
protected $_escape_char = '`';
- // clause and character used for LIKE escape sequences - not used in MySQL
- protected $_like_escape_str = '';
- protected $_like_escape_chr = '\\';
-
protected $_random_keyword = ' RAND()';
/**
@@ -211,6 +207,26 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
return 'TRUNCATE '.$table;
}
+ // --------------------------------------------------------------------
+
+ /**
+ * FROM tables
+ *
+ * Groups tables in FROM clauses if needed, so there is no confusion
+ * about operator precedence.
+ *
+ * @return string
+ */
+ protected function _from_tables()
+ {
+ if ( ! empty($this->qb_join) && count($this->qb_from) > 1)
+ {
+ return '('.implode(', ', $this->qb_from).')';
+ }
+
+ return implode(', ', $this->qb_from);
+ }
+
}
/* End of file pdo_mysql_driver.php */
diff --git a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
index cfbb639a8..b03218fad 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php
@@ -146,22 +146,6 @@ class CI_DB_pdo_oci_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Insert_batch statement
*
* @param string the table name
diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
index 0c3467484..5944d55f4 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
@@ -46,7 +46,6 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
protected $_escape_char = '';
// clause and character used for LIKE escape sequences
- protected $_like_escape_chr = '!';
protected $_like_escape_str = " {escape '%s'} ";
protected $_random_keyword = ' RAND()';
@@ -157,22 +156,6 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
index 07cf8f56b..74d56e6b8 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php
@@ -142,22 +142,6 @@ class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
index 4b5747d90..5b1cd9789 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
@@ -182,22 +182,6 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
@@ -273,4 +257,4 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
}
/* End of file pdo_sqlsrv_driver.php */
-/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php */ \ No newline at end of file
+/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php */
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index ddcf3f7c3..19f384ccc 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -44,10 +44,6 @@ class CI_DB_postgre_driver extends CI_DB {
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' RANDOM()'; // database specific random keyword
/**
@@ -132,7 +128,15 @@ class CI_DB_postgre_driver extends CI_DB {
*/
public function db_pconnect()
{
- return @pg_pconnect($this->dsn);
+ $conn = @pg_pconnect($this->dsn);
+ if ($conn && pg_connection_status($conn) === PGSQL_CONNECTION_BAD)
+ {
+ if (pg_ping($conn) === FALSE)
+ {
+ return FALSE;
+ }
+ }
+ return $conn;
}
// --------------------------------------------------------------------
@@ -453,22 +457,6 @@ class CI_DB_postgre_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 19824dbbf..2744a63cf 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -45,10 +45,6 @@ class CI_DB_sqlite_driver extends CI_DB {
// The character used to escape with - not needed for SQLite
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' Random()'; // database specific random keyword
/**
diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
index cc35d319f..d03be15f5 100644
--- a/system/database/drivers/sqlite3/sqlite3_driver.php
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -46,10 +46,6 @@ class CI_DB_sqlite3_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = ' ESCAPE \'%s\' ';
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' RANDOM()';
/**
@@ -288,25 +284,16 @@ class CI_DB_sqlite3_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * The error message string
+ * Error
*
- * @return string
- */
- protected function _error_message()
- {
- return $this->conn_id->lastErrorMsg();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * The error message number
+ * Returns an array containing code and message of the last
+ * database error that has occured.
*
- * @return int
+ * @return array
*/
- protected function _error_number()
+ public function error()
{
- return $this->conn_id->lastErrorCode();
+ return array('code' => $this->conn_id->lastErrorCode(), 'message' => $this->conn_id->lastErrorMsg());
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index badbb8e90..659429256 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -45,10 +45,6 @@ class CI_DB_sqlsrv_driver extends CI_DB {
// The character used for escaping
protected $_escape_char = '"';
- // clause and character used for LIKE escape sequences
- protected $_like_escape_str = " ESCAPE '%s' ";
- protected $_like_escape_chr = '!';
-
protected $_random_keyword = ' NEWID()';
// SQLSRV-specific properties
@@ -225,7 +221,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*/
public function affected_rows()
{
- return sqlrv_rows_affected($this->result_id);
+ return sqlsrv_rows_affected($this->result_id);
}
// --------------------------------------------------------------------
@@ -362,22 +358,6 @@ class CI_DB_sqlsrv_driver extends CI_DB {
// --------------------------------------------------------------------
/**
- * From Tables
- *
- * This function implicitly groups FROM tables so there is no confusion
- * about operator precedence in harmony with SQL standards
- *
- * @param array
- * @return string
- */
- protected function _from_tables($tables)
- {
- return is_array($tables) ? implode(', ', $tables) : $tables;
- }
-
- // --------------------------------------------------------------------
-
- /**
* Update statement
*
* Generates a platform-specific update string from the supplied data
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index a4383c9d3..3aac14db8 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -80,8 +80,7 @@ if ( ! function_exists('create_captcha'))
$current_dir = @opendir($img_path);
while ($filename = @readdir($current_dir))
{
- if ($filename !== '.' && $filename !== '..' && $filename !== 'index.html'
- && (str_replace('.jpg', '', $filename) + $expiration) < $now)
+ if (substr($filename, -4) === '.jpg' && (str_replace('.jpg', '', $filename) + $expiration) < $now)
{
@unlink($img_path.$filename);
}
diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php
index a45b3d7ac..955d74542 100644
--- a/system/helpers/date_helper.php
+++ b/system/helpers/date_helper.php
@@ -575,22 +575,7 @@ if ( ! function_exists('timezone_menu'))
$menu .= ' class="'.$class.'"';
}
- // Generate a string from the attributes submitted, if any
- if (is_array($attributes))
- {
- $atts = '';
- foreach ($attributes as $key => $val)
- {
- $atts .= ' '.$key.'="'.$val.'"';
- }
- $attributes = $atts;
- }
- elseif (is_string($attributes) && strlen($attributes) > 0)
- {
- $attributes = ' '.$attributes;
- }
-
- $menu .= $attributes.">\n";
+ $menu .= _stringify_attributes($attributes).">\n";
foreach (timezones() as $key => $val)
{
@@ -672,5 +657,136 @@ if ( ! function_exists('timezones'))
}
}
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('date_range'))
+{
+ /**
+ * Date range
+ *
+ * Returns a list of dates within a specified period.
+ *
+ * @param int unix_start UNIX timestamp of period start date
+ * @param int unix_end|days UNIX timestamp of period end date
+ * or interval in days.
+ * @param mixed is_unix Specifies wether the second parameter
+ * is a UNIX timestamp or a day interval
+ * - TRUE or 'unix' for a timestamp
+ * - FALSE or 'days' for an interval
+ * @param string date_format Output date format, same as in date()
+ * @return array
+ */
+ function date_range($unix_start = '', $mixed = '', $is_unix = TRUE, $format = 'Y-m-d')
+ {
+ if ($unix_start == '' OR $mixed == '' OR $format == '')
+ {
+ return FALSE;
+ }
+
+ $is_unix = ! ( ! $is_unix OR $is_unix === 'days');
+
+ // Validate input and try strtotime() on invalid timestamps/intervals, just in case
+ if ( ( ! preg_match('/^[0-9]+$/', $unix_start) && ($unix_start = @strtotime($unix_time)) === FALSE)
+ OR ( ! preg_match('/^[0-9]+$/', $mixed) && ($is_unix === FALSE OR ($mixed = @strtotime($mixed)) === FALSE))
+ OR ($is_unix === TRUE && $mixed < $unix_start))
+ {
+ return FALSE;
+ }
+
+ if ($is_unix && ($unix_start == $mixed OR date($format, $unix_start) === date($format, $mixed)))
+ {
+ return array($start_date);
+ }
+
+ $range = array();
+
+ /* NOTE: Even though the DateTime object has many useful features, it appears that
+ * it doesn't always handle properly timezones, when timestamps are passed
+ * directly to its constructor. Neither of the following gave proper results:
+ *
+ * new DateTime('<timestamp>')
+ * new DateTime('<timestamp>', '<timezone>')
+ *
+ * --- available in PHP 5.3:
+ *
+ * DateTime::createFromFormat('<format>', '<timestamp>')
+ * DateTime::createFromFormat('<format>', '<timestamp>', '<timezone')
+ *
+ * ... so we'll have to set the timestamp after the object is instantiated.
+ * Furthermore, in PHP 5.3 we can use DateTime::setTimestamp() to do that and
+ * given that we have UNIX timestamps - we should use it.
+ */
+ $from = new DateTime();
+
+ if (is_php('5.3'))
+ {
+ $from->setTimestamp($unix_start);
+ if ($is_unix)
+ {
+ $arg = new DateTime();
+ $arg->setTimestamp($mixed);
+ }
+ else
+ {
+ $arg = (int) $mixed;
+ }
+
+ $period = new DatePeriod($from, new DateInterval('P1D'), $arg);
+ foreach ($period as $date)
+ {
+ $range[] = $date->format($format);
+ }
+
+ /* If a period end date was passed to the DatePeriod constructor, it might not
+ * be in our results. Not sure if this is a bug or it's just possible because
+ * the end date might actually be less than 24 hours away from the previously
+ * generated DateTime object, but either way - we have to append it manually.
+ */
+ if ( ! is_int($arg) && $range[count($range) - 1] !== $arg->format($format))
+ {
+ $range[] = $arg->format($format);
+ }
+
+ return $range;
+ }
+
+ $from->setDate(date('Y', $unix_start), date('n', $unix_start), date('j', $unix_start));
+ $from->setTime(date('G', $unix_start), date('i', $unix_start), date('s', $unix_start));
+ if ($is_unix)
+ {
+ $arg = new DateTime();
+ $arg->setDate(date('Y', $mixed), date('n', $mixed), date('j', $mixed));
+ $arg->setTime(date('G', $mixed), date('i', $mixed), date('s', $mixed));
+ }
+ else
+ {
+ $arg = (int) $mixed;
+ }
+ $range[] = $from->format($format);
+
+ if (is_int($arg)) // Day intervals
+ {
+ do
+ {
+ $from->modify('+1 day');
+ $range[] = $from->format($format);
+ }
+ while (--$arg > 0);
+ }
+ else // end date UNIX timestamp
+ {
+ for ($from->modify('+1 day'), $end_check = $arg->format('Ymd'); $from->format('Ymd') < $end_check; $from->modify('+1 day'))
+ {
+ $range[] = $from->format($format);
+ }
+
+ // Our loop only appended dates prior to our end date
+ $range[] = $arg->format($format);
+ }
+
+ return $range;
+ }
+}
+
/* End of file date_helper.php */
/* Location: ./system/helpers/date_helper.php */ \ No newline at end of file
diff --git a/system/helpers/directory_helper.php b/system/helpers/directory_helper.php
index e7d3b5e8a..7d6b6770e 100644
--- a/system/helpers/directory_helper.php
+++ b/system/helpers/directory_helper.php
@@ -62,7 +62,7 @@ if ( ! function_exists('directory_map'))
while (FALSE !== ($file = readdir($fp)))
{
// Remove '.', '..', and hidden files [optional]
- if ( ! trim($file, '.') OR ($hidden === FALSE && $file[0] === '.'))
+ if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.'))
{
continue;
}
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index 09c4de578..0232adfe4 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -95,7 +95,10 @@ if ( ! function_exists('force_download'))
}
// Clean output buffer
- ob_clean();
+ if (ob_get_level() !== 0)
+ {
+ ob_clean();
+ }
// Generate the server headers
header('Content-Type: '.$mime);
diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php
index 3834d4895..e68bb7f7a 100644
--- a/system/helpers/file_helper.php
+++ b/system/helpers/file_helper.php
@@ -124,7 +124,7 @@ if ( ! function_exists('delete_files'))
{
delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $level + 1, $htdocs);
}
- elseif ($htdocs === TRUE && ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename))
+ elseif ($htdocs !== TRUE OR ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename))
{
@unlink($path.DIRECTORY_SEPARATOR.$filename);
}
diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php
index 68ce70248..2372e8174 100644
--- a/system/helpers/html_helper.php
+++ b/system/helpers/html_helper.php
@@ -51,7 +51,7 @@ if ( ! function_exists('heading'))
*/
function heading($data = '', $h = '1', $attributes = '')
{
- return '<h'.$h.($attributes !== '' ? ' ' : '').$attributes.'>'.$data.'</h'.$h.'>';
+ return '<h'.$h._stringify_attributes($attributes).'>'.$data.'</h'.$h.'>';
}
}
@@ -119,23 +119,8 @@ if ( ! function_exists('_list'))
// Set the indentation based on the depth
$out = str_repeat(' ', $depth);
- // Were any attributes submitted? If so generate a string
- if (is_array($attributes))
- {
- $atts = '';
- foreach ($attributes as $key => $val)
- {
- $atts .= ' '.$key.'="'.$val.'"';
- }
- $attributes = $atts;
- }
- elseif (is_string($attributes) && strlen($attributes) > 0)
- {
- $attributes = ' '.$attributes;
- }
-
// Write the opening list tag
- $out .= '<'.$type.$attributes.">\n";
+ $out .= '<'.$type._stringify_attributes($attributes).">\n";
// Cycle through the list elements. If an array is
// encountered we will recursively call _list()
@@ -191,9 +176,10 @@ if ( ! function_exists('img'))
*
* @param mixed
* @param bool
+ * @param mixed
* @return string
*/
- function img($src = '', $index_page = FALSE)
+ function img($src = '', $index_page = FALSE, $attributes = '')
{
if ( ! is_array($src) )
{
@@ -229,7 +215,7 @@ if ( ! function_exists('img'))
}
}
- return $img.'/>';
+ return $img._stringify_attributes($attributes).' />';
}
}
@@ -242,9 +228,9 @@ if ( ! function_exists('doctype'))
*
* Generates a page document type declaration
*
- * Valid options are xhtml-11, xhtml-strict, xhtml-trans, xhtml-frame,
- * html4-strict, html4-trans, and html4-frame. Values are saved in the
- * doctypes config file.
+ * Examples of valid options: html5, xhtml-11, xhtml-strict, xhtml-trans,
+ * xhtml-frame, html4-strict, html4-trans, and html4-frame.
+ * All values are saved in the doctypes config file.
*
* @param string type The doctype to be generated
* @return string
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 8a1f01b51..b592f3cc0 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -89,7 +89,8 @@ if ( ! function_exists('character_limiter'))
return $str;
}
- $str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
+ // a bit complicated, but faster than preg_replace with \s+
+ $str = preg_replace('/ {2,}/', ' ', str_replace(array("\r", "\n", "\t", "\x0B", "\x0C"), ' ', $str));
if (strlen($str) <= $n)
{
diff --git a/system/helpers/typography_helper.php b/system/helpers/typography_helper.php
index af9d16a89..9dbba0679 100644
--- a/system/helpers/typography_helper.php
+++ b/system/helpers/typography_helper.php
@@ -65,11 +65,11 @@ if ( ! function_exists('auto_typography'))
* @param bool whether to reduce multiple instances of double newlines to two
* @return string
*/
- function auto_typography($str, $strip_js_event_handlers = TRUE, $reduce_linebreaks = FALSE)
+ function auto_typography($str, $reduce_linebreaks = FALSE)
{
$CI =& get_instance();
$CI->load->library('typography');
- return $CI->typography->auto_typography($str, $strip_js_event_handlers, $reduce_linebreaks);
+ return $CI->typography->auto_typography($str, $reduce_linebreaks);
}
}
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index 39e6343a6..b1f5eccf1 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -165,7 +165,7 @@ if ( ! function_exists('anchor'))
if ($attributes !== '')
{
- $attributes = _parse_attributes($attributes);
+ $attributes = _stringify_attributes($attributes);
}
return '<a href="'.$site_url.'"'.$attributes.'>'.$title.'</a>';
@@ -221,10 +221,10 @@ if ( ! function_exists('anchor_popup'))
unset($attributes[$key]);
}
- $attributes = empty($attributes) ? '' : _parse_attributes($attributes);
+ $attributes = _stringify_attributes($attributes);
return '<a href="'.$site_url
- .'" onclick="window.open(\''.$site_url."', '".$window_name."', '"._parse_attributes($atts, TRUE)."'); return false;\""
+ .'" onclick="window.open(\''.$site_url."', '".$window_name."', '"._stringify_attributes($atts, TRUE)."'); return false;\""
.$attributes.'>'.$title.'</a>';
}
}
@@ -250,7 +250,7 @@ if ( ! function_exists('mailto'))
$title = $email;
}
- return '<a href="mailto:'.$email.'"'._parse_attributes($attributes).'>'.$title.'</a>';
+ return '<a href="mailto:'.$email.'"'._stringify_attributes($attributes).'>'.$title.'</a>';
}
}
@@ -534,7 +534,7 @@ if ( ! function_exists('redirect'))
}
// IIS environment likely? Use 'refresh' for better compatibility
- if (DIRECTORY_SEPARATOR !== '/' && $method === 'auto')
+ if ($method === 'auto' && isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== FALSE)
{
$method = 'refresh';
}
@@ -560,47 +560,5 @@ if ( ! function_exists('redirect'))
}
}
-// ------------------------------------------------------------------------
-
-if ( ! function_exists('_parse_attributes'))
-{
- /**
- * Parse out the attributes
- *
- * Some of the functions use this
- *
- * @param array
- * @param bool
- * @return string
- */
- function _parse_attributes($attributes, $javascript = FALSE)
- {
- if (is_string($attributes))
- {
- return ($attributes !== '') ? ' '.$attributes : '';
- }
-
- $att = '';
- foreach ($attributes as $key => $val)
- {
- if ($javascript === TRUE)
- {
- $att .= $key.'='.$val.',';
- }
- else
- {
- $att .= ' '.$key.'="'.$val.'"';
- }
- }
-
- if ($javascript === TRUE && $att !== '')
- {
- return substr($att, 0, -1);
- }
-
- return $att;
- }
-}
-
/* End of file url_helper.php */
/* Location: ./system/helpers/url_helper.php */ \ No newline at end of file
diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php
index 229d33d2e..6683e4c69 100644
--- a/system/language/english/date_lang.php
+++ b/system/language/english/date_lang.php
@@ -25,20 +25,20 @@
* @filesource
*/
-$lang['date_year'] = "Year";
-$lang['date_years'] = "Years";
-$lang['date_month'] = "Month";
-$lang['date_months'] = "Months";
-$lang['date_week'] = "Week";
-$lang['date_weeks'] = "Weeks";
-$lang['date_day'] = "Day";
-$lang['date_days'] = "Days";
-$lang['date_hour'] = "Hour";
-$lang['date_hours'] = "Hours";
-$lang['date_minute'] = "Minute";
-$lang['date_minutes'] = "Minutes";
-$lang['date_second'] = "Second";
-$lang['date_seconds'] = "Seconds";
+$lang['date_year'] = 'Year';
+$lang['date_years'] = 'Years';
+$lang['date_month'] = 'Month';
+$lang['date_months'] = 'Months';
+$lang['date_week'] = 'Week';
+$lang['date_weeks'] = 'Weeks';
+$lang['date_day'] = 'Day';
+$lang['date_days'] = 'Days';
+$lang['date_hour'] = 'Hour';
+$lang['date_hours'] = 'Hours';
+$lang['date_minute'] = 'Minute';
+$lang['date_minutes'] = 'Minutes';
+$lang['date_second'] = 'Second';
+$lang['date_seconds'] = 'Seconds';
$lang['UM12'] = '(UTC -12:00) Baker/Howland Island';
$lang['UM11'] = '(UTC -11:00) Niue';
diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php
index 021776161..6ff0cc2f4 100644
--- a/system/language/english/form_validation_lang.php
+++ b/system/language/english/form_validation_lang.php
@@ -42,9 +42,10 @@ $lang['is_numeric'] = 'The %s field must contain only numeric characters.';
$lang['integer'] = 'The %s field must contain an integer.';
$lang['regex_match'] = 'The %s field is not in the correct format.';
$lang['matches'] = 'The %s field does not match the %s field.';
+$lang['differs'] = 'The %s field must differ from the %s field.';
$lang['is_unique'] = 'The %s field must contain a unique value.';
-$lang['is_natural'] = 'The %s field must contain only positive numbers.';
-$lang['is_natural_no_zero'] = 'The %s field must contain a number greater than zero.';
+$lang['is_natural'] = 'The %s field must only contain digits.';
+$lang['is_natural_no_zero'] = 'The %s field must only contain digits and must be greater than zero.';
$lang['decimal'] = 'The %s field must contain a decimal number.';
$lang['less_than'] = 'The %s field must contain a number less than %s.';
$lang['less_than_equal_to'] = 'The %s field must contain a number less than or equal to %s.';
diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php
index d67ee2549..769d892dc 100644
--- a/system/libraries/Driver.php
+++ b/system/libraries/Driver.php
@@ -54,14 +54,30 @@ class CI_Driver_Library {
protected $lib_name;
/**
+ * Get magic method
+ *
* The first time a child is used it won't exist, so we instantiate it
* subsequents calls will go straight to the proper child.
*
- * @param mixed $child
- * @return mixed
+ * @param string Child class name
+ * @return object Child class
*/
public function __get($child)
{
+ // Try to load the driver
+ return $this->load_driver($child);
+ }
+
+ /**
+ * Load driver
+ *
+ * Separate load_driver call to support explicit driver load by library or user
+ *
+ * @param string Child class name
+ * @return object Child class
+ */
+ public function load_driver($child)
+ {
if ( ! isset($this->lib_name))
{
$this->lib_name = get_class($this);
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index fdb9be4da..fa1d5e9bf 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -98,6 +98,8 @@ class CI_Email {
*/
public function __construct($config = array())
{
+ $this->charset = strtoupper(config_item('charset'));
+
if (count($config) > 0)
{
$this->initialize($config);
@@ -188,7 +190,7 @@ class CI_Email {
* @param string
* @return object
*/
- public function from($from, $name = '')
+ public function from($from, $name = '', $return_path = '')
{
if (preg_match('/\<(.*)\>/', $from, $match))
{
@@ -198,6 +200,10 @@ class CI_Email {
if ($this->validate)
{
$this->validate_email($this->_str_to_array($from));
+ if ($return_path)
+ {
+ $this->validate_email($this->_str_to_array($return_path));
+ }
}
// prepare the display name
@@ -216,7 +222,12 @@ class CI_Email {
}
$this->set_header('From', $name.' <'.$from.'>');
- $this->set_header('Return-Path', '<'.$from.'>');
+
+ if( ! $return_path)
+ {
+ $return_path = $from;
+ }
+ $this->set_header('Return-Path', '<'.$return_path.'>');
return $this;
}
@@ -971,7 +982,6 @@ class CI_Email {
$this->_finalbody = $body.$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline;
-
if ($this->_get_protocol() === 'mail')
{
$this->_header_str .= $hdr;
@@ -1091,17 +1101,24 @@ class CI_Email {
* Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt
*
* @param string
- * @param int
* @return string
*/
- protected function _prep_quoted_printable($str, $charlim = '')
+ protected function _prep_quoted_printable($str)
{
- // Set the character limit
- // Don't allow over 76, as that will make servers and MUAs barf
- // all over quoted-printable data
- if ($charlim === '' OR $charlim > 76)
+ // RFC 2045 specifies CRLF as "\r\n".
+ // However, many developers choose to override that and violate
+ // the RFC rules due to (apparently) a bug in MS Exchange,
+ // which only works with "\n".
+ if ($this->crlf === "\r\n")
{
- $charlim = 76;
+ if (is_php('5.3'))
+ {
+ return quoted_printable_encode($str);
+ }
+ elseif (function_exists('imap_8bit'))
+ {
+ return imap_8bit($str);
+ }
}
// Reduce multiple spaces & remove nulls
@@ -1146,7 +1163,7 @@ class CI_Email {
// If we're at the character limit, add the line to the output,
// reset our temp variable, and keep on chuggin'
- if ((strlen($temp) + strlen($char)) >= $charlim)
+ if ((strlen($temp) + strlen($char)) >= 76)
{
$output .= $temp.$escape.$this->crlf;
$temp = '';
@@ -1228,7 +1245,7 @@ class CI_Email {
// wrap each line with the shebang, charset, and transfer encoding
// the preceding space on successive lines is required for header "folding"
- return trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $output.$temp));
+ return trim(preg_replace('/^(.*?)(\r*)$/m', ' =?'.$this->charset.'?Q?$1?=$2', $output.$temp));
}
// --------------------------------------------------------------------
@@ -1238,7 +1255,7 @@ class CI_Email {
*
* @return bool
*/
- public function send()
+ public function send($auto_clear = TRUE)
{
if ($this->_replyto_flag === FALSE)
{
@@ -1257,11 +1274,25 @@ class CI_Email {
if ($this->bcc_batch_mode && count($this->_bcc_array) > $this->bcc_batch_size)
{
- return $this->batch_bcc_send();
+ $result = $this->batch_bcc_send();
+
+ if ($result && $auto_clear)
+ {
+ $this->clear();
+ }
+
+ return $result;
}
$this->_build_message();
- return $this->_spool_email();
+ $result = $this->_spool_email();
+
+ if ($result && $auto_clear)
+ {
+ $this->clear();
+ }
+
+ return $result;
}
// --------------------------------------------------------------------
@@ -1385,7 +1416,7 @@ class CI_Email {
{
// most documentation of sendmail using the "-f" flag lacks a space after it, however
// we've encountered servers that seem to require it to be in place.
- return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['From']));
+ return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['Return-Path']));
}
}
@@ -1398,7 +1429,7 @@ class CI_Email {
*/
protected function _send_with_sendmail()
{
- $fp = @popen($this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t', 'w');
+ $fp = @popen($this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t'.' -r '.$this->clean_email($this->_headers['Return-Path']), 'w');
if ($fp === FALSE OR $fp === NULL)
{
diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php
index 8ffd93aea..73ab8ca7d 100644
--- a/system/libraries/Encrypt.php
+++ b/system/libraries/Encrypt.php
@@ -165,7 +165,7 @@ class CI_Encrypt {
*/
public function decode($string, $key = '')
{
- if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
+ if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string) OR base64_encode(base64_decode($string)) !== $string)
{
return FALSE;
}
@@ -484,7 +484,7 @@ class CI_Encrypt {
*/
public function set_hash($type = 'sha1')
{
- $this->_hash_type = ($type !== 'sha1' && $type !== 'md5') ? 'sha1' : $type;
+ $this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1';
}
// --------------------------------------------------------------------
@@ -497,7 +497,7 @@ class CI_Encrypt {
*/
public function hash($str)
{
- return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str);
+ return hash($this->_hash_type, $str);
}
}
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index b490a34ca..91f46b6de 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -134,12 +134,6 @@ class CI_Form_validation {
// Automatically load the form helper
$this->CI->load->helper('form');
- // Set the character encoding in MB.
- if (MB_ENABLED === TRUE)
- {
- mb_internal_encoding($this->CI->config->item('charset'));
- }
-
log_message('debug', 'Form Validation Class Initialized');
}
@@ -977,6 +971,20 @@ class CI_Form_validation {
// --------------------------------------------------------------------
/**
+ * Differs from another field
+ *
+ * @param string
+ * @param string field
+ * @return bool
+ */
+ public function differs($str, $field)
+ {
+ return ! (isset($this->_field_data[$field]) && $this->_field_data[$field]['postdata'] === $str);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Is Unique
*
* Check if the input value doesn't already exist
diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php
index 899b995d4..ef4187847 100644
--- a/system/libraries/Image_lib.php
+++ b/system/libraries/Image_lib.php
@@ -1320,6 +1320,13 @@ class CI_Image_lib {
imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);
imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);
}
+
+ // We can preserve transparency for PNG images
+ if ($this->image_type === 3)
+ {
+ imagealphablending($src_img, FALSE);
+ imagesavealpha($src_img, TRUE);
+ }
}
// Output the final image
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index 5573f6407..e1e729bb0 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -52,20 +52,20 @@ class CI_Pagination {
protected $full_tag_open = '';
protected $full_tag_close = '';
protected $first_tag_open = '';
- protected $first_tag_close = '&nbsp;';
- protected $last_tag_open = '&nbsp;';
+ protected $first_tag_close = '';
+ protected $last_tag_open = '';
protected $last_tag_close = '';
protected $first_url = ''; // Alternative URL for the First Page.
- protected $cur_tag_open = '&nbsp;<strong>';
+ protected $cur_tag_open = '<strong>';
protected $cur_tag_close = '</strong>';
- protected $next_tag_open = '&nbsp;';
- protected $next_tag_close = '&nbsp;';
- protected $prev_tag_open = '&nbsp;';
+ protected $next_tag_open = '';
+ protected $next_tag_close = '';
+ protected $prev_tag_open = '';
protected $prev_tag_close = '';
- protected $num_tag_open = '&nbsp;';
+ protected $num_tag_open = '';
protected $num_tag_close = '';
protected $page_query_string = FALSE;
- protected $query_string_segment = 'per_page';
+ protected $query_string_segment = 'per_page';
protected $display_pages = TRUE;
protected $_attributes = '';
protected $_link_types = array();
@@ -215,7 +215,8 @@ class CI_Pagination {
// string. If post, add a trailing slash to the base URL if needed
if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
{
- $this->base_url = rtrim($this->base_url).'&amp;'.$this->query_string_segment.'=';
+ $segment = (strpos($this->base_url, '?')) ? '&amp;' : '?';
+ $this->base_url = rtrim($this->base_url).$segment.$this->query_string_segment.'=';
}
else
{
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
new file mode 100755
index 000000000..978506062
--- /dev/null
+++ b/system/libraries/Session/Session.php
@@ -0,0 +1,714 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc.
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 2.0
+ * @filesource
+ */
+
+/**
+ * CodeIgniter Session Class
+ *
+ * The user interface defined by EllisLabs, now with puggable drivers to manage different storage mechanisms.
+ * By default, the cookie session driver will load, but the 'sess_driver' config/param item (see above) can be
+ * used to specify the 'native' driver, or any other you might create.
+ * Once loaded, this driver setup is a drop-in replacement for the former CI_Session library, taking its place as the
+ * 'session' member of the global controller framework (e.g.: $CI->session or $this->session).
+ * In keeping with the CI_Driver methodology, multiple drivers may be loaded, although this might be a bit confusing.
+ * The CI_Session library class keeps track of the most recently loaded driver as "current" to call for driver methods.
+ * Ideally, one driver is loaded and all calls go directly through the main library interface. However, any methods
+ * called through the specific driver will switch the "current" driver to itself before invoking the library method
+ * (which will then call back into the driver for low-level operations). So, alternation between two drivers can be
+ * achieved by specifying which driver to use for each call (e.g.: $this->session->native->set_userdata('foo', 'bar');
+ * $this->session->cookie->userdata('foo'); $this->session->native->unset_userdata('foo');). Notice in the previous
+ * example that the _native_ userdata value 'foo' would be set to 'bar', which would NOT be returned by the call for
+ * the _cookie_ userdata 'foo', nor would the _cookie_ value be unset by the call to unset the _native_ 'foo' value.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/libraries/sessions.html
+ */
+class CI_Session extends CI_Driver_Library {
+
+ public $params = array();
+ protected $current = NULL;
+ protected $userdata = array();
+
+ const FLASHDATA_KEY = 'flash';
+ const FLASHDATA_NEW = ':new:';
+ const FLASHDATA_OLD = ':old:';
+ const FLASHDATA_EXP = ':exp:';
+ const EXPIRATION_KEY = '__expirations';
+ const TEMP_EXP_DEF = 300;
+
+ /**
+ * CI_Session constructor
+ *
+ * The constructor loads the configured driver ('sess_driver' in config.php or as a parameter), running
+ * routines in its constructor, and manages flashdata aging.
+ *
+ * @param array Configuration parameters
+ * @return void
+ */
+ public function __construct(array $params = array())
+ {
+ $CI =& get_instance();
+
+ // No sessions under CLI
+ if ($CI->input->is_cli_request())
+ {
+ return;
+ }
+
+ log_message('debug', 'CI_Session Class Initialized');
+
+ // Get valid drivers list
+ $this->valid_drivers = array(
+ 'Session_native',
+ 'Session_cookie'
+ );
+ $key = 'sess_valid_drivers';
+ $drivers = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
+ if ($drivers)
+ {
+ is_array($drivers) OR $drivers = array($drivers);
+
+ // Add driver names to valid list
+ foreach ($drivers as $driver)
+ {
+ if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers)))
+ {
+ $this->valid_drivers[] = $driver;
+ }
+ }
+ }
+
+ // Get driver to load
+ $key = 'sess_driver';
+ $driver = isset($params[$key]) ? $params[$key] : $CI->config->item($key);
+ if ( ! $driver)
+ {
+ $driver = 'cookie';
+ }
+
+ if ( ! in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers)))
+ {
+ $this->valid_drivers[] = 'Session_'.$driver;
+ }
+
+ // Save a copy of parameters in case drivers need access
+ $this->params = $params;
+
+ // Load driver and get array reference
+ $this->load_driver($driver);
+
+ // Delete 'old' flashdata (from last request)
+ $this->_flashdata_sweep();
+
+ // Mark all new flashdata as old (data will be deleted before next request)
+ $this->_flashdata_mark();
+
+ // Delete expired tempdata
+ $this->_tempdata_sweep();
+
+ log_message('debug', 'CI_Session routines successfully run');
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Loads session storage driver
+ *
+ * @param string Driver classname
+ * @return object Loaded driver object
+ */
+ public function load_driver($driver)
+ {
+ // Save reference to most recently loaded driver as library default and sync userdata
+ $this->current = parent::load_driver($driver);
+ $this->userdata =& $this->current->get_userdata();
+ return $this->current;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Select default session storage driver
+ *
+ * @param string Driver classname
+ * @return void
+ */
+ public function select_driver($driver)
+ {
+ // Validate driver name
+ $lowername = strtolower(str_replace('CI_', '', $driver));
+ if (in_array($lowername, array_map('strtolower', $this->valid_drivers)))
+ {
+ // See if driver is loaded
+ $child = str_replace($this->lib_name.'_', '', $driver);
+ if (isset($this->$child))
+ {
+ // See if driver is already current
+ if ($this->$child !== $this->current)
+ {
+ // Make driver current and sync userdata
+ $this->current = $this->$child;
+ $this->userdata =& $this->current->get_userdata();
+ }
+ }
+ else
+ {
+ // Load new driver
+ $this->load_driver($child);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Just call destroy on driver
+ $this->current->sess_destroy();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Call regenerate on driver and resync userdata
+ $this->current->sess_regenerate($destroy);
+ $this->userdata =& $this->current->get_userdata();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific item from the session array
+ *
+ * @param string Item key
+ * @return string Item value or NULL if not found
+ */
+ public function userdata($item)
+ {
+ return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch all session data
+ *
+ * @return array User data array
+ */
+ public function all_userdata()
+ {
+ return isset($this->userdata) ? $this->userdata : NULL;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch all flashdata
+ *
+ * @return array Flash data array
+ */
+ public function all_flashdata()
+ {
+ $out = array();
+
+ // loop through all userdata
+ foreach ($this->all_userdata() as $key => $val)
+ {
+ // if it contains flashdata, add it
+ if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE)
+ {
+ $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key);
+ $out[$key] = $val;
+ }
+ }
+ return $out;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add or change data in the "userdata" array
+ *
+ * @param mixed Item name or array of items
+ * @param string Item value or empty string
+ * @return void
+ */
+ public function set_userdata($newdata = array(), $newval = '')
+ {
+ // Wrap params as array if singular
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => $newval);
+ }
+
+ // Set each name/value pair
+ if (count($newdata) > 0)
+ {
+ foreach ($newdata as $key => $val)
+ {
+ $this->userdata[$key] = $val;
+ }
+ }
+
+ // Tell driver data changed
+ $this->current->sess_save();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Delete a session variable from the "userdata" array
+ *
+ * @param mixed Item name or array of item names
+ * @return void
+ */
+ public function unset_userdata($newdata = array())
+ {
+ // Wrap single name as array
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => '');
+ }
+
+ // Unset each item name
+ if (count($newdata) > 0)
+ {
+ foreach (array_keys($newdata) as $key)
+ {
+ unset($this->userdata[$key]);
+ }
+ }
+
+ // Tell driver data changed
+ $this->current->sess_save();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Determine if an item exists
+ *
+ * @param string Item name
+ * @return bool
+ */
+ public function has_userdata($item)
+ {
+ return isset($this->userdata[$item]);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add or change flashdata, only available until the next request
+ *
+ * @param mixed Item name or array of items
+ * @param string Item value or empty string
+ * @return void
+ */
+ public function set_flashdata($newdata = array(), $newval = '')
+ {
+ // Wrap item as array if singular
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => $newval);
+ }
+
+ // Prepend each key name and set value
+ if (count($newdata) > 0)
+ {
+ foreach ($newdata as $key => $val)
+ {
+ $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key;
+ $this->set_userdata($flashdata_key, $val);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Keeps existing flashdata available to next request.
+ *
+ * @param string Item key
+ * @return void
+ */
+ public function keep_flashdata($key)
+ {
+ // 'old' flashdata gets removed. Here we mark all flashdata as 'new' to preserve it from _flashdata_sweep()
+ // Note the function will return NULL if the $key provided cannot be found
+ $old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key;
+ $value = $this->userdata($old_flashdata_key);
+
+ $new_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key;
+ $this->set_userdata($new_flashdata_key, $value);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific flashdata item from the session array
+ *
+ * @param string Item key
+ * @return string
+ */
+ public function flashdata($key)
+ {
+ // Prepend key and retrieve value
+ $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key;
+ return $this->userdata($flashdata_key);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add or change tempdata, only available until expiration
+ *
+ * @param mixed Item name or array of items
+ * @param string Item value or empty string
+ * @param int Item lifetime in seconds or 0 for default
+ * @return void
+ */
+ public function set_tempdata($newdata = array(), $newval = '', $expire = 0)
+ {
+ // Set expiration time
+ $expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF);
+
+ // Wrap item as array if singular
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => $newval);
+ }
+
+ // Get or create expiration list
+ $expirations = $this->userdata(self::EXPIRATION_KEY);
+ if ( ! $expirations)
+ {
+ $expirations = array();
+ }
+
+ // Prepend each key name and set value
+ if (count($newdata) > 0)
+ {
+ foreach ($newdata as $key => $val)
+ {
+ $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
+ $expirations[$tempdata_key] = $expire;
+ $this->set_userdata($tempdata_key, $val);
+ }
+ }
+
+ // Update expiration list
+ $this->set_userdata(self::EXPIRATION_KEY, $expirations);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Delete a temporary session variable from the "userdata" array
+ *
+ * @param mixed Item name or array of item names
+ * @return void
+ */
+ public function unset_tempdata($newdata = array())
+ {
+ // Get expirations list
+ $expirations = $this->userdata(self::EXPIRATION_KEY);
+ if (empty($expirations))
+ {
+ // Nothing to do
+ return;
+ }
+
+ // Wrap single name as array
+ if (is_string($newdata))
+ {
+ $newdata = array($newdata => '');
+ }
+
+ // Prepend each item name and unset
+ if (count($newdata) > 0)
+ {
+ foreach (array_keys($newdata) as $key)
+ {
+ $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
+ unset($expirations[$tempdata_key]);
+ $this->unset_userdata($tempdata_key);
+ }
+ }
+
+ // Update expiration list
+ $this->set_userdata(self::EXPIRATION_KEY, $expirations);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch a specific tempdata item from the session array
+ *
+ * @param string Item key
+ * @return string
+ */
+ public function tempdata($key)
+ {
+ // Prepend key and return value
+ $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key;
+ return $this->userdata($tempdata_key);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Identifies flashdata as 'old' for removal
+ * when _flashdata_sweep() runs.
+ *
+ * @return void
+ */
+ protected function _flashdata_mark()
+ {
+ foreach ($this->all_userdata() as $name => $value)
+ {
+ $parts = explode(self::FLASHDATA_NEW, $name);
+ if (is_array($parts) && count($parts) === 2)
+ {
+ $new_name = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1];
+ $this->set_userdata($new_name, $value);
+ $this->unset_userdata($name);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Removes all flashdata marked as 'old'
+ *
+ * @return void
+ */
+ protected function _flashdata_sweep()
+ {
+ $userdata = $this->all_userdata();
+ foreach (array_keys($userdata) as $key)
+ {
+ if (strpos($key, self::FLASHDATA_OLD))
+ {
+ $this->unset_userdata($key);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Removes all expired tempdata
+ *
+ * @return void
+ */
+ protected function _tempdata_sweep()
+ {
+ // Get expirations list
+ $expirations = $this->userdata(self::EXPIRATION_KEY);
+ if (empty($expirations))
+ {
+ // Nothing to do
+ return;
+ }
+
+ // Unset expired elements
+ $now = time();
+ $userdata = $this->all_userdata();
+ foreach (array_keys($userdata) as $key)
+ {
+ if (strpos($key, self::FLASHDATA_EXP) && $expirations[$key] < $now)
+ {
+ unset($expirations[$key]);
+ $this->unset_userdata($key);
+ }
+ }
+
+ // Update expiration list
+ $this->set_userdata(self::EXPIRATION_KEY, $expirations);
+ }
+
+}
+
+// ------------------------------------------------------------------------
+
+/**
+ * CI_Session_driver Class
+ *
+ * Extend this class to make a new CI_Session driver.
+ * A CI_Session driver basically manages an array of name/value pairs with some sort of storage mechanism.
+ * To make a new driver, derive from (extend) CI_Session_driver. Overload the initialize method and read or create
+ * session data. Then implement a save handler to write changed data to storage (sess_save), a destroy handler
+ * to remove deleted data (sess_destroy), and an access handler to expose the data (get_userdata).
+ * Put your driver in the libraries/Session/drivers folder anywhere in the loader paths. This includes the
+ * application directory, the system directory, or any path you add with $CI->load->add_package_path().
+ * Your driver must be named CI_Session_<name>, and your filename must be Session_<name>.php,
+ * preferably also capitalized. (e.g.: CI_Session_foo in libraries/Session/drivers/Session_foo.php)
+ * Then specify the driver by setting 'sess_driver' in your config file or as a parameter when loading the CI_Session
+ * object. (e.g.: $config['sess_driver'] = 'foo'; OR $CI->load->driver('session', array('sess_driver' => 'foo')); )
+ * Already provided are the Native driver, which manages the native PHP $_SESSION array, and
+ * the Cookie driver, which manages the data in a browser cookie, with optional extra storage in a database table.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ */
+abstract class CI_Session_driver extends CI_Driver {
+
+ protected $CI;
+
+ /**
+ * Constructor
+ *
+ * Gets the CI singleton, so that individual drivers
+ * don't have to do it separately.
+ *
+ * @return void
+ */
+ public function __construct()
+ {
+ $this->CI =& get_instance();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Decorate
+ *
+ * Decorates the child with the parent driver lib's methods and properties
+ *
+ * @param object Parent library object
+ * @return void
+ */
+ public function decorate($parent)
+ {
+ // Call base class decorate first
+ parent::decorate($parent);
+
+ // Call initialize method now that driver has access to $this->_parent
+ $this->initialize();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * __call magic method
+ *
+ * Handles access to the parent driver library's methods
+ *
+ * @param string Library method name
+ * @param array Method arguments (default: none)
+ * @return mixed
+ */
+ public function __call($method, $args = array())
+ {
+ // Make sure the parent library uses this driver
+ $this->_parent->select_driver(get_class($this));
+ return parent::__call($method, $args);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Initialize driver
+ *
+ * @return void
+ */
+ protected function initialize()
+ {
+ // Overload this method to implement initialization
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Save the session data
+ *
+ * Data in the array has changed - perform any storage synchronization
+ * necessary. The child class MUST implement this abstract method!
+ *
+ * @return void
+ */
+ abstract public function sess_save();
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * Clean up storage for this session - it has been terminated.
+ * The child class MUST implement this abstract method!
+ *
+ * @return void
+ */
+ abstract public function sess_destroy();
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session ID.
+ * The child class MUST implement this abstract method!
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @return void
+ */
+ abstract public function sess_regenerate($destroy = FALSE);
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * Give array access to the main CI_Session object.
+ * The child class MUST implement this abstract method!
+ *
+ * @return array Reference to userdata
+ */
+ abstract public function &get_userdata();
+
+}
+
+/* End of file Session.php */
+/* Location: ./system/libraries/Session/Session.php */ \ No newline at end of file
diff --git a/system/libraries/Session.php b/system/libraries/Session/drivers/Session_cookie.php
index af38dc366..fb62c7ec4 100644..100755
--- a/system/libraries/Session.php
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -9,7 +9,7 @@
* Licensed under the Open Software License version 3.0
*
* This source file is subject to the Open Software License (OSL 3.0) that is
- * bundled with this package in the files license.txt / license.rst. It is
+ * bundled with this package in the files license.txt / license.rst. It is
* also available through the world wide web at this URL:
* http://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to obtain it
@@ -26,7 +26,9 @@
*/
/**
- * Session Class
+ * Cookie-based session management driver
+ *
+ * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver.
*
* @package CodeIgniter
* @subpackage Libraries
@@ -34,7 +36,7 @@
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/libraries/sessions.html
*/
-class CI_Session {
+class CI_Session_cookie extends CI_Session_driver {
/**
* Whether to encrypt the session cookie
@@ -69,7 +71,7 @@ class CI_Session {
*
* @var bool
*/
- public $sess_expire_on_close = FALSE;
+ public $sess_expire_on_close = FALSE;
/**
* Whether to match session on ip address
@@ -83,7 +85,7 @@ class CI_Session {
*
* @var bool
*/
- public $sess_match_useragent = TRUE;
+ public $sess_match_useragent = TRUE;
/**
* Name of session cookie
@@ -104,7 +106,7 @@ class CI_Session {
*
* @var string
*/
- public $cookie_path = '';
+ public $cookie_path = '';
/**
* Session cookie domain
@@ -142,67 +144,83 @@ class CI_Session {
public $encryption_key = '';
/**
- * String to indicate flash data cookies
- *
- * @var string
- */
- public $flashdata_key = 'flash';
-
- /**
* Timezone to use for the current time
*
* @var string
*/
public $time_reference = 'local';
-
/**
* Session data
*
* @var array
*/
- public $userdata = array();
+ public $userdata = array();
/**
- * Reference to CodeIgniter instance
+ * Current time
*
- * @var object
+ * @var int
*/
- public $CI;
+ public $now;
/**
- * Current time
+ * Default userdata keys
*
- * @var int
+ * @var array
*/
- public $now;
+ protected $defaults = array(
+ 'session_id' => NULL,
+ 'ip_address' => NULL,
+ 'user_agent' => NULL,
+ 'last_activity' => NULL
+ );
/**
- * Session Constructor
+ * Data needs DB update flag
*
- * The constructor runs the session routines automatically
- * whenever the class is instantiated.
+ * @var bool
+ */
+ protected $data_dirty = FALSE;
+
+ /**
+ * Initialize session driver object
*
- * @param array
* @return void
*/
- public function __construct($params = array())
+ protected function initialize()
{
- log_message('debug', 'Session Class Initialized');
-
- // Set the super object to a local variable for use throughout the class
- $this->CI =& get_instance();
-
// Set all the session preferences, which can either be set
- // manually via the $params array above or via the config file
- foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
+ // manually via the $params array or via the config file
+ $prefs = array(
+ 'sess_encrypt_cookie',
+ 'sess_use_database',
+ 'sess_table_name',
+ 'sess_expiration',
+ 'sess_expire_on_close',
+ 'sess_match_ip',
+ 'sess_match_useragent',
+ 'sess_cookie_name',
+ 'cookie_path',
+ 'cookie_domain',
+ 'cookie_secure',
+ 'cookie_httponly',
+ 'sess_time_to_update',
+ 'time_reference',
+ 'cookie_prefix',
+ 'encryption_key'
+ );
+
+ foreach ($prefs as $key)
{
- $this->$key = isset($params[$key]) ? $params[$key] : $this->CI->config->item($key);
+ $this->$key = isset($this->_parent->params[$key])
+ ? $this->_parent->params[$key]
+ : $this->CI->config->item($key);
}
if ($this->encryption_key === '')
{
- show_error('In order to use the Session class you are required to set an encryption key in your config file.');
+ show_error('In order to use the Cookie Session driver you are required to set an encryption key in your config file.');
}
// Load the string helper so we can use the strip_slashes() function
@@ -214,14 +232,18 @@ class CI_Session {
$this->CI->load->library('encrypt');
}
- // Are we using a database? If so, load it
+ // Check for database
if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
{
+ // Load database driver
$this->CI->load->database();
+
+ // Register shutdown function
+ register_shutdown_function(array($this, '_update_db'));
}
- // Set the "now" time. Can either be GMT or server time, based on the
- // config prefs. We use this to set the "last activity" time
+ // Set the "now" time. Can either be GMT or server time, based on the config prefs.
+ // We use this to set the "last activity" time
$this->now = $this->_get_time();
// Set the session length. If the session expiration is
@@ -236,59 +258,135 @@ class CI_Session {
// Run the Session routine. If a session doesn't exist we'll
// create a new one. If it does, we'll update it.
- if ( ! $this->sess_read())
+ if ( ! $this->_sess_read())
{
- $this->sess_create();
+ $this->_sess_create();
}
else
{
- $this->sess_update();
+ $this->_sess_update();
}
- // Delete 'old' flashdata (from last request)
- $this->_flashdata_sweep();
-
- // Mark all new flashdata as old (data will be deleted before next request)
- $this->_flashdata_mark();
-
// Delete expired sessions if necessary
$this->_sess_gc();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Write the session data
+ *
+ * @return void
+ */
+ public function sess_save()
+ {
+ // Check for database
+ if ($this->sess_use_database === TRUE)
+ {
+ // Mark custom data as dirty so we know to update the DB
+ $this->data_dirty = TRUE;
+ }
+
+ // Write the cookie
+ $this->_set_cookie();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Kill the session DB row
+ if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
+ {
+ $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id']));
+ $this->data_dirty = FALSE;
+ }
+
+ // Kill the cookie
+ $this->_setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000),
+ $this->cookie_path, $this->cookie_domain, 0);
- log_message('debug', 'Session routines successfully run');
+ // Kill session data
+ $this->userdata = array();
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session id
+ *
+ * @param bool Destroy session data flag (default: false)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Check destroy flag
+ if ($destroy)
+ {
+ // Destroy old session and create new one
+ $this->sess_destroy();
+ $this->_sess_create();
+ }
+ else
+ {
+ // Just force an update to recreate the id
+ $this->_sess_update(TRUE);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * @return array Reference to userdata
+ */
+ public function &get_userdata()
+ {
+ return $this->userdata;
+ }
+
+ // ------------------------------------------------------------------------
/**
* Fetch the current session data if it exists
*
* @return bool
*/
- public function sess_read()
+ protected function _sess_read()
{
// Fetch the cookie
$session = $this->CI->input->cookie($this->sess_cookie_name);
- // No cookie? Goodbye cruel world!...
+ // No cookie? Goodbye cruel world!...
if ($session === NULL)
{
log_message('debug', 'A session cookie was not found.');
return FALSE;
}
- // Decrypt the cookie data
+ // Check for encryption
if ($this->sess_encrypt_cookie === TRUE)
{
+ // Decrypt the cookie data
$session = $this->CI->encrypt->decode($session);
}
else
{
- // encryption was not used, so we need to check the md5 hash
- $hash = substr($session, strlen($session)-32); // get last 32 chars
- $session = substr($session, 0, strlen($session)-32);
+ // Encryption was not used, so we need to check the md5 hash in the last 32 chars
+ $len = strlen($session)-32;
+ $hash = substr($session, $len);
+ $session = substr($session, 0, $len);
// Does the md5 hash match? This is to prevent manipulation of session data in userspace
- if ($hash !== md5($session.$this->encryption_key))
+ if ($hash !== md5($session.$this->encryption_key))
{
log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
$this->sess_destroy();
@@ -321,7 +419,8 @@ class CI_Session {
}
// Does the User Agent Match?
- if ($this->sess_match_useragent === TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
+ if ($this->sess_match_useragent === TRUE &&
+ trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
{
$this->sess_destroy();
return FALSE;
@@ -342,8 +441,19 @@ class CI_Session {
$this->CI->db->where('user_agent', $session['user_agent']);
}
+ // Is caching in effect? Turn it off
+ $db_cache = $this->CI->db->cache_on;
+ $this->CI->db->cache_off();
+
$query = $this->CI->db->limit(1)->get($this->sess_table_name);
+ // Was caching in effect?
+ if ($db_cache)
+ {
+ // Turn it back on
+ $this->CI->db->cache_on();
+ }
+
// No result? Kill it!
if ($query->num_rows() === 0)
{
@@ -351,7 +461,7 @@ class CI_Session {
return FALSE;
}
- // Is there custom data? If so, add it to the main session array
+ // Is there custom data? If so, add it to the main session array
$row = $query->row();
if ( ! empty($row->user_data))
{
@@ -359,424 +469,164 @@ class CI_Session {
if (is_array($custom_data))
{
- foreach ($custom_data as $key => $val)
- {
- $session[$key] = $val;
- }
+ $session = $session + $custom_data;
}
}
}
// Session is valid!
$this->userdata = $session;
- unset($session);
-
return TRUE;
}
- // --------------------------------------------------------------------
-
- /**
- * Write the session data
- *
- * @return void
- */
- public function sess_write()
- {
- // Are we saving custom data to the DB? If not, all we do is update the cookie
- if ($this->sess_use_database === FALSE)
- {
- $this->_set_cookie();
- return;
- }
-
- // set the custom userdata, the session data we will set in a second
- $custom_userdata = $this->userdata;
- $cookie_userdata = array();
-
- // Before continuing, we need to determine if there is any custom data to deal with.
- // Let's determine this by removing the default indexes to see if there's anything left in the array
- // and set the session data while we're at it
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- unset($custom_userdata[$val]);
- $cookie_userdata[$val] = $this->userdata[$val];
- }
-
- // Did we find any custom data? If not, we turn the empty array into a string
- // since there's no reason to serialize and store an empty array in the DB
- if (count($custom_userdata) === 0)
- {
- $custom_userdata = '';
- }
- else
- {
- // Serialize the custom data array so we can store it
- $custom_userdata = $this->_serialize($custom_userdata);
- }
-
- // Run the update query
- $this->CI->db->where('session_id', $this->userdata['session_id']);
- $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
-
- // Write the cookie. Notice that we manually pass the cookie data array to the
- // _set_cookie() function. Normally that function will store $this->userdata, but
- // in this case that array contains custom data, which we do not want in the cookie.
- $this->_set_cookie($cookie_userdata);
- }
-
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Create a new session
*
* @return void
*/
- public function sess_create()
+ protected function _sess_create()
{
- $sessid = '';
- do
- {
- $sessid .= mt_rand(0, mt_getrandmax());
- }
- while (strlen($sessid) < 32);
-
- // To make the session ID even more secure we'll combine it with the user's IP
- $sessid .= $this->CI->input->ip_address();
-
+ // Initialize userdata
$this->userdata = array(
- 'session_id' => md5(uniqid($sessid, TRUE)),
- 'ip_address' => $this->CI->input->ip_address(),
- 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
- 'last_activity' => $this->now,
- 'user_data' => ''
- );
-
- // Save the data to the DB if needed
+ 'session_id' => $this->_make_sess_id(),
+ 'ip_address' => $this->CI->input->ip_address(),
+ 'user_agent' => substr($this->CI->input->user_agent(), 0, 120),
+ 'last_activity' => $this->now,
+ );
+
+ // Check for database
if ($this->sess_use_database === TRUE)
{
- $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
+ // Add empty user_data field and save the data to the DB
+ $this->CI->db->set('user_data', '')->insert($this->sess_table_name, $this->userdata);
}
// Write the cookie
$this->_set_cookie();
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Update an existing session
*
+ * @param bool Force update flag (default: false)
* @return void
*/
- public function sess_update()
+ protected function _sess_update($force = FALSE)
{
- // We only update the session every five minutes by default
- if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
+ // We only update the session every five minutes by default (unless forced)
+ if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
{
return;
}
- // _set_cookie() will handle this for us if we aren't using database sessions
- // by pushing all userdata to the cookie.
- $cookie_data = NULL;
-
- /* Changing the session ID during an AJAX call causes problems,
- * so we'll only update our last_activity
- */
- if ($this->CI->input->is_ajax_request())
- {
- $this->userdata['last_activity'] = $this->now;
-
- // Update the session ID and last_activity field in the DB if needed
- if ($this->sess_use_database === TRUE)
- {
- // set cookie explicitly to only have our session data
- $cookie_data = array();
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- $cookie_data[$val] = $this->userdata[$val];
- }
-
- $this->CI->db->query($this->CI->db->update_string($this->sess_table_name,
- array('last_activity' => $this->userdata['last_activity']),
- array('session_id' => $this->userdata['session_id'])));
- }
-
- return $this->_set_cookie($cookie_data);
- }
+ // Update last activity to now
+ $this->userdata['last_activity'] = $this->now;
- // Save the old session id so we know which record to
- // update in the database if we need it
+ // Save the old session id so we know which DB record to update
$old_sessid = $this->userdata['session_id'];
- $new_sessid = '';
- do
+
+ // Changing the session ID during an AJAX call causes problems
+ if ( ! $this->CI->input->is_ajax_request())
{
- $new_sessid .= mt_rand(0, mt_getrandmax());
+ // Get new id
+ $this->userdata['session_id'] = $this->_make_sess_id();
}
- while (strlen($new_sessid) < 32);
- // To make the session ID even more secure we'll combine it with the user's IP
- $new_sessid .= $this->CI->input->ip_address();
-
- // Turn it into a hash and update the session data array
- $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
- $this->userdata['last_activity'] = $this->now;
-
- // Update the session ID and last_activity field in the DB if needed
+ // Check for database
if ($this->sess_use_database === TRUE)
{
- // set cookie explicitly to only have our session data
- $cookie_data = array();
- foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
- {
- $cookie_data[$val] = $this->userdata[$val];
- }
-
- $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
+ // Update the session ID and last_activity field in the DB
+ $this->CI->db->update($this->sess_table_name, array(
+ 'last_activity' => $this->now,
+ 'session_id' => $this->userdata['session_id']
+ ), array('session_id' => $old_sessid));
}
// Write the cookie
- $this->_set_cookie($cookie_data);
+ $this->_set_cookie();
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
- * Destroy the current session
+ * Update database with current data
+ *
+ * This gets called from the shutdown function and also
+ * registered with PHP to run at the end of the request
+ * so it's guaranteed to update even when a fatal error
+ * occurs. The first call makes the update and clears the
+ * dirty flag so it won't happen twice.
*
* @return void
*/
- public function sess_destroy()
+ public function _update_db()
{
- // Kill the session DB row
- if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
- {
- $this->CI->db->where('session_id', $this->userdata['session_id']);
- $this->CI->db->delete($this->sess_table_name);
- }
-
- // Kill the cookie
- setcookie(
- $this->sess_cookie_name,
- addslashes(serialize(array())),
- ($this->now - 31500000),
- $this->cookie_path,
- $this->cookie_domain,
- 0
+ // Check for database and dirty flag and unsaved
+ if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE)
+ {
+ // Set up activity and data fields to be set
+ // If we don't find custom data, user_data will remain an empty string
+ $set = array(
+ 'last_activity' => $this->userdata['last_activity'],
+ 'user_data' => ''
);
- // Kill session data
- $this->userdata = array();
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Fetch a specific item from the session array
- *
- * @param string
- * @return string
- */
- public function userdata($item)
- {
- return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL;
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Fetch all session data
- *
- * @return array
- */
- public function all_userdata()
- {
- return $this->userdata;
- }
-
- // --------------------------------------------------------------------------
-
- /**
- * Fetch all flashdata
- *
- * @return array
- */
- public function all_flashdata()
- {
- $out = array();
-
- // loop through all userdata
- foreach ($this->all_userdata() as $key => $val)
- {
- // if it contains flashdata, add it
- if (strpos($key, 'flash:old:') !== FALSE)
- {
- $out[$key] = $val;
- }
- }
- return $out;
- }
-
- // --------------------------------------------------------------------
+ // Get the custom userdata, leaving out the defaults
+ // (which get stored in the cookie)
+ $userdata = array_diff_key($this->userdata, $this->defaults);
- /**
- * Add or change data in the "userdata" array
- *
- * @param mixed
- * @param string
- * @return void
- */
- public function set_userdata($newdata = array(), $newval = '')
- {
- if (is_string($newdata))
- {
- $newdata = array($newdata => $newval);
- }
-
- if (count($newdata) > 0)
- {
- foreach ($newdata as $key => $val)
+ // Did we find any custom data?
+ if ( ! empty($userdata))
{
- $this->userdata[$key] = $val;
+ // Serialize the custom data array so we can store it
+ $set['user_data'] = $this->_serialize($userdata);
}
- }
- $this->sess_write();
- }
+ // Run the update query
+ // Any time we change the session id, it gets updated immediately,
+ // so our where clause below is always safe
+ $this->CI->db->update($this->sess_table_name, $set, array('session_id' => $this->userdata['session_id']));
- // --------------------------------------------------------------------
+ // Clear dirty flag to prevent double updates
+ $this->data_dirty = FALSE;
- /**
- * Delete a session variable from the "userdata" array
- *
- * @param array
- * @return void
- */
- public function unset_userdata($newdata = array())
- {
- if (is_string($newdata))
- {
- $newdata = array($newdata => '');
+ log_message('debug', 'CI_Session Data Saved To DB');
}
-
- if (count($newdata) > 0)
- {
- foreach ($newdata as $key => $val)
- {
- unset($this->userdata[$key]);
- }
- }
-
- $this->sess_write();
}
// ------------------------------------------------------------------------
/**
- * Add or change flashdata, only available
- * until the next request
+ * Generate a new session id
*
- * @param mixed
- * @param string
- * @return void
+ * @return string Hashed session id
*/
- public function set_flashdata($newdata = array(), $newval = '')
+ protected function _make_sess_id()
{
- if (is_string($newdata))
- {
- $newdata = array($newdata => $newval);
- }
-
- if (count($newdata) > 0)
+ $new_sessid = '';
+ do
{
- foreach ($newdata as $key => $val)
- {
- $this->set_userdata($this->flashdata_key.':new:'.$key, $val);
- }
+ $new_sessid .= mt_rand(0, mt_getrandmax());
}
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Keeps existing flashdata available to next request.
- *
- * @param string
- * @return void
- */
- public function keep_flashdata($key)
- {
- // 'old' flashdata gets removed. Here we mark all
- // flashdata as 'new' to preserve it from _flashdata_sweep()
- // Note the function will return NULL if the $key
- // provided cannot be found
- $value = $this->userdata($this->flashdata_key.':old:'.$key);
-
- $this->set_userdata($this->flashdata_key.':new:'.$key, $value);
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * Fetch a specific flashdata item from the session array
- *
- * @param string
- * @return string
- */
- public function flashdata($key)
- {
- return $this->userdata($this->flashdata_key.':old:'.$key);
- }
+ while (strlen($new_sessid) < 32);
- // ------------------------------------------------------------------------
+ // To make the session ID even more secure we'll combine it with the user's IP
+ $new_sessid .= $this->CI->input->ip_address();
- /**
- * Identifies flashdata as 'old' for removal
- * when _flashdata_sweep() runs.
- *
- * @return void
- */
- protected function _flashdata_mark()
- {
- $userdata = $this->all_userdata();
- foreach ($userdata as $name => $value)
- {
- $parts = explode(':new:', $name);
- if (is_array($parts) && count($parts) === 2)
- {
- $this->set_userdata($this->flashdata_key.':old:'.$parts[1], $value);
- $this->unset_userdata($name);
- }
- }
+ // Turn it into a hash and return
+ return md5(uniqid($new_sessid, TRUE));
}
// ------------------------------------------------------------------------
/**
- * Removes all flashdata marked as 'old'
- *
- * @return void
- */
- protected function _flashdata_sweep()
- {
- $userdata = $this->all_userdata();
- foreach ($userdata as $key => $value)
- {
- if (strpos($key, ':old:'))
- {
- $this->unset_userdata($key);
- }
- }
-
- }
-
- // --------------------------------------------------------------------
-
- /**
* Get the "now" time
*
- * @return string
+ * @return int Time
*/
protected function _get_time()
{
@@ -791,49 +641,57 @@ class CI_Session {
return mktime($hour, $minute, $second, $month, $day, $year);
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Write the session cookie
*
- * @param mixed
* @return void
*/
- protected function _set_cookie($cookie_data = NULL)
+ protected function _set_cookie()
{
- if (is_null($cookie_data))
- {
- $cookie_data = $this->userdata;
- }
+ // Get userdata (only defaults if database)
+ $cookie_data = ($this->sess_use_database === TRUE)
+ ? array_intersect_key($this->userdata, $this->defaults)
+ : $this->userdata;
// Serialize the userdata for the cookie
$cookie_data = $this->_serialize($cookie_data);
- if ($this->sess_encrypt_cookie === TRUE)
- {
- $cookie_data = $this->CI->encrypt->encode($cookie_data);
- }
- else
- {
+ $cookie_data = ($this->sess_encrypt_cookie === TRUE)
+ ? $this->CI->encrypt->encode($cookie_data)
// if encryption is not used, we provide an md5 hash to prevent userside tampering
- $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
- }
+ : $cookie_data.md5($cookie_data.$this->encryption_key);
$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
// Set the cookie
- setcookie(
- $this->sess_cookie_name,
- $cookie_data,
- $expire,
- $this->cookie_path,
- $this->cookie_domain,
- $this->cookie_secure,
- $this->cookie_httponly
- );
+ $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
+ $this->cookie_secure, $this->cookie_httponly);
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set a cookie with the system
+ *
+ * This abstraction of the setcookie call allows overriding for unit testing
+ *
+ * @param string Cookie name
+ * @param string Cookie value
+ * @param int Expiration time
+ * @param string Cookie path
+ * @param string Cookie domain
+ * @param bool Secure connection flag
+ * @param bool HTTP protocol only flag
+ * @return void
+ */
+ protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE)
+ {
+ setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
+ }
+
+ // ------------------------------------------------------------------------
/**
* Serialize an array
@@ -841,8 +699,8 @@ class CI_Session {
* This function first converts any slashes found in the array to a temporary
* marker, so when it gets unserialized the slashes will be preserved
*
- * @param array
- * @return string
+ * @param mixed Data to serialize
+ * @return string Serialized data
*/
protected function _serialize($data)
{
@@ -854,16 +712,19 @@ class CI_Session {
{
$data = str_replace('\\', '{{slash}}', $data);
}
+
return serialize($data);
}
+ // ------------------------------------------------------------------------
+
/**
* Escape slashes
*
* This function converts any slashes found into a temporary marker
*
- * @param string
- * @param string
+ * @param string Value
+ * @param string Key
* @return void
*/
protected function _escape_slashes(&$val, $key)
@@ -874,7 +735,7 @@ class CI_Session {
}
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Unserialize
@@ -882,8 +743,8 @@ class CI_Session {
* This function unserializes a data string, then converts any
* temporary slash markers back to actual slashes
*
- * @param array
- * @return string
+ * @param mixed Data to unserialize
+ * @return mixed Unserialized data
*/
protected function _unserialize($data)
{
@@ -898,15 +759,15 @@ class CI_Session {
return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Unescape slashes
*
* This function converts any slash markers back into actual slashes
*
- * @param string
- * @param string
+ * @param string Value
+ * @param string Key
* @return void
*/
protected function _unescape_slashes(&$val, $key)
@@ -917,7 +778,7 @@ class CI_Session {
}
}
- // --------------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Garbage collection
@@ -941,9 +802,7 @@ class CI_Session {
if ((mt_rand(0, $divisor) / $divisor) < $probability)
{
$expire = $this->now - $this->sess_expiration;
-
- $this->CI->db->where('last_activity < '.$expire);
- $this->CI->db->delete($this->sess_table_name);
+ $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire);
log_message('debug', 'Session garbage collection performed.');
}
@@ -951,5 +810,5 @@ class CI_Session {
}
-/* End of file Session.php */
-/* Location: ./system/libraries/Session.php */ \ No newline at end of file
+/* End of file Session_cookie.php */
+/* Location: ./system/libraries/Session/drivers/Session_cookie.php */ \ No newline at end of file
diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php
new file mode 100755
index 000000000..8d5e51546
--- /dev/null
+++ b/system/libraries/Session/drivers/Session_native.php
@@ -0,0 +1,231 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 1.0
+ * @filesource
+ */
+
+/**
+ * Native PHP session management driver
+ *
+ * This is the driver that uses the native PHP $_SESSION array through the Session driver library.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Sessions
+ * @author EllisLab Dev Team
+ */
+class CI_Session_native extends CI_Session_driver {
+
+ /**
+ * Initialize session driver object
+ *
+ * @return void
+ */
+ protected function initialize()
+ {
+ // Get config parameters
+ $config = array();
+ $prefs = array(
+ 'sess_cookie_name',
+ 'sess_expire_on_close',
+ 'sess_expiration',
+ 'sess_match_ip',
+ 'sess_match_useragent',
+ 'sess_time_to_update',
+ 'cookie_prefix',
+ 'cookie_path',
+ 'cookie_domain'
+ );
+
+ foreach ($prefs as $key)
+ {
+ $config[$key] = isset($this->_parent->params[$key])
+ ? $this->_parent->params[$key]
+ : $this->CI->config->item($key);
+ }
+
+ // Set session name, if specified
+ if ($config['sess_cookie_name'])
+ {
+ // Differentiate name from cookie driver with '_id' suffix
+ $name = $config['sess_cookie_name'].'_id';
+ if ($config['cookie_prefix'])
+ {
+ // Prepend cookie prefix
+ $name = $config['cookie_prefix'].$name;
+ }
+ session_name($name);
+ }
+
+ // Set expiration, path, and domain
+ $expire = 7200;
+ $path = '/';
+ $domain = '';
+ if ($config['sess_expiration'] !== FALSE)
+ {
+ // Default to 2 years if expiration is "0"
+ $expire = ($config['sess_expiration'] == 0) ? (60*60*24*365*2) : $config['sess_expiration'];
+ }
+
+ if ($config['cookie_path'])
+ {
+ // Use specified path
+ $path = $config['cookie_path'];
+ }
+
+ if ($config['cookie_domain'])
+ {
+ // Use specified domain
+ $domain = $config['cookie_domain'];
+ }
+ session_set_cookie_params($config['sess_expire_on_close'] ? 0 : $expire, $path, $domain);
+
+ // Start session
+ session_start();
+
+ // Check session expiration, ip, and agent
+ $now = time();
+ $destroy = FALSE;
+ if (isset($_SESSION['last_activity']) && ($_SESSION['last_activity'] + $expire) < $now)
+ {
+ // Expired - destroy
+ $destroy = TRUE;
+ }
+ elseif ($config['sess_match_ip'] === TRUE && isset($_SESSION['ip_address'])
+ && $_SESSION['ip_address'] !== $this->CI->input->ip_address())
+ {
+ // IP doesn't match - destroy
+ $destroy = TRUE;
+ }
+ elseif ($config['sess_match_useragent'] === TRUE && isset($_SESSION['user_agent'])
+ && $_SESSION['user_agent'] !== trim(substr($this->CI->input->user_agent(), 0, 50)))
+ {
+ // Agent doesn't match - destroy
+ $destroy = TRUE;
+ }
+
+ // Destroy expired or invalid session
+ if ($destroy)
+ {
+ // Clear old session and start new
+ $this->sess_destroy();
+ session_start();
+ }
+
+ // Check for update time
+ if ($config['sess_time_to_update'] && isset($_SESSION['last_activity'])
+ && ($_SESSION['last_activity'] + $config['sess_time_to_update']) < $now)
+ {
+ // Regenerate ID, but don't destroy session
+ $this->sess_regenerate(FALSE);
+ }
+
+ // Set activity time
+ $_SESSION['last_activity'] = $now;
+
+ // Set matching values as required
+ if ($config['sess_match_ip'] === TRUE && ! isset($_SESSION['ip_address']))
+ {
+ // Store user IP address
+ $_SESSION['ip_address'] = $this->CI->input->ip_address();
+ }
+
+ if ($config['sess_match_useragent'] === TRUE && ! isset($_SESSION['user_agent']))
+ {
+ // Store user agent string
+ $_SESSION['user_agent'] = trim(substr($this->CI->input->user_agent(), 0, 50));
+ }
+
+ // Make session ID available
+ $_SESSION['session_id'] = session_id();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Save the session data
+ *
+ * @return void
+ */
+ public function sess_save()
+ {
+ // Nothing to do - changes to $_SESSION are automatically saved
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Destroy the current session
+ *
+ * @return void
+ */
+ public function sess_destroy()
+ {
+ // Cleanup session
+ $_SESSION = array();
+ $name = session_name();
+ if (isset($_COOKIE[$name]))
+ {
+ // Clear session cookie
+ $params = session_get_cookie_params();
+ setcookie($name, '', time() - 42000, $params['path'], $params['domain']);
+ unset($_COOKIE[$name]);
+ }
+ session_destroy();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Regenerate the current session
+ *
+ * Regenerate the session id
+ *
+ * @param bool Destroy session data flag (default: FALSE)
+ * @return void
+ */
+ public function sess_regenerate($destroy = FALSE)
+ {
+ // Just regenerate id, passing destroy flag
+ session_regenerate_id($destroy);
+ $_SESSION['session_id'] = session_id();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get a reference to user data array
+ *
+ * @return array Reference to userdata
+ */
+ public function &get_userdata()
+ {
+ // Just return reference to $_SESSION
+ return $_SESSION;
+ }
+
+}
+
+/* End of file Session_native.php */
+/* Location: ./system/libraries/Session/drivers/Session_native.php */ \ No newline at end of file
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
index 70ad8dc41..c2c01758e 100644
--- a/system/libraries/Unit_test.php
+++ b/system/libraries/Unit_test.php
@@ -240,6 +240,11 @@ class CI_Unit_test {
{
foreach ($val as $k => $v)
{
+ if ( ! in_array($k, $this->_test_items_visible))
+ {
+ continue;
+ }
+
if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$v))))
{
$v = $line;
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index cbb91c40a..dc5d27f8c 100644..100755
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -1317,15 +1317,15 @@ class XML_RPC_Values extends CI_Xmlrpc
{
$type = $type === '' ? 'string' : $type;
- if ($this->xmlrpcTypes[$type] === 1)
+ if ($this->xmlrpcTypes[$type] == 1)
{
$this->addScalar($val,$type);
}
- elseif ($this->xmlrpcTypes[$type] === 2)
+ elseif ($this->xmlrpcTypes[$type] == 2)
{
$this->addArray($val);
}
- elseif ($this->xmlrpcTypes[$type] === 3)
+ elseif ($this->xmlrpcTypes[$type] == 3)
{
$this->addStruct($val);
}
@@ -1351,7 +1351,7 @@ class XML_RPC_Values extends CI_Xmlrpc
return 0;
}
- if ($typeof !== 1)
+ if ($typeof != 1)
{
echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
return 0;
@@ -1359,7 +1359,7 @@ class XML_RPC_Values extends CI_Xmlrpc
if ($type === $this->xmlrpcBoolean)
{
- $val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
+ $val = (int) (strcasecmp($val, 'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false')));
}
if ($this->mytype === 2)
diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php
index 5216038c6..1c666d503 100644
--- a/tests/Bootstrap.php
+++ b/tests/Bootstrap.php
@@ -11,6 +11,7 @@ defined('PROJECT_BASE') OR define('PROJECT_BASE', realpath($dir.'/../').'/');
defined('BASEPATH') OR define('BASEPATH', PROJECT_BASE.'system/');
defined('APPPATH') OR define('APPPATH', PROJECT_BASE.'application/');
defined('VIEWPATH') OR define('VIEWPATH', PROJECT_BASE.'');
+isset($_SERVER['REMOTE_ADDR']) OR $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
// Get vfsStream either via PEAR or composer
foreach (explode(PATH_SEPARATOR, get_include_path()) as $path)
diff --git a/tests/codeigniter/core/Common_test.php b/tests/codeigniter/core/Common_test.php
index f9bf6c27f..27d48efc2 100644
--- a/tests/codeigniter/core/Common_test.php
+++ b/tests/codeigniter/core/Common_test.php
@@ -10,4 +10,35 @@ class Common_test extends CI_TestCase {
$this->assertEquals(FALSE, is_php('9999.9.9'));
}
+ // ------------------------------------------------------------------------
+
+ public function test_stringify_attributes()
+ {
+ $this->assertEquals(' class="foo" id="bar"', _stringify_attributes(array('class' => 'foo', 'id' => 'bar')));
+
+ $atts = new Stdclass;
+ $atts->class = 'foo';
+ $atts->id = 'bar';
+ $this->assertEquals(' class="foo" id="bar"', _stringify_attributes($atts));
+
+ $atts = new Stdclass;
+ $this->assertEquals('', _stringify_attributes($atts));
+
+ $this->assertEquals(' class="foo" id="bar"', _stringify_attributes('class="foo" id="bar"'));
+
+ $this->assertEquals('', _stringify_attributes(array()));
+ }
+
+ // ------------------------------------------------------------------------
+
+ public function test_stringify_js_attributes()
+ {
+ $this->assertEquals('width=800,height=600', _stringify_attributes(array('width' => '800', 'height' => '600'), TRUE));
+
+ $atts = new Stdclass;
+ $atts->width = 800;
+ $atts->height = 600;
+ $this->assertEquals('width=800,height=600', _stringify_attributes($atts, TRUE));
+ }
+
} \ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/escape_test.php b/tests/codeigniter/database/query_builder/escape_test.php
index c6380ddf1..27e678f22 100644
--- a/tests/codeigniter/database/query_builder/escape_test.php
+++ b/tests/codeigniter/database/query_builder/escape_test.php
@@ -27,7 +27,7 @@ class Escape_test extends CI_TestCase {
if (strpos(DB_DRIVER, 'mysql') !== FALSE)
{
- $sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '';";
+ $sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '!';";
}
else
{
@@ -52,7 +52,7 @@ class Escape_test extends CI_TestCase {
if (strpos(DB_DRIVER, 'mysql') !== FALSE)
{
- $sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '';";
+ $sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '!';";
}
else
{
diff --git a/tests/codeigniter/helpers/date_helper_test.php b/tests/codeigniter/helpers/date_helper_test.php
index 1b79b9480..9feade71c 100644
--- a/tests/codeigniter/helpers/date_helper_test.php
+++ b/tests/codeigniter/helpers/date_helper_test.php
@@ -290,6 +290,29 @@ class Date_helper_test extends CI_TestCase {
$this->assertEquals(0, timezones('non_existant'));
}
+ // ------------------------------------------------------------------------
+
+ public function test_date_range()
+ {
+ $dates = array(
+ '29-01-2012', '30-01-2012', '31-01-2012',
+ '01-02-2012', '02-02-2012', '03-02-2012',
+ '04-02-2012', '05-02-2012', '06-02-2012',
+ '07-02-2012', '08-02-2012', '09-02-2012',
+ '10-02-2012', '11-02-2012', '12-02-2012',
+ '13-02-2012', '14-02-2012', '15-02-2012',
+ '16-02-2012', '17-02-2012', '18-02-2012',
+ '19-02-2012', '20-02-2012', '21-02-2012',
+ '22-02-2012', '23-02-2012', '24-02-2012',
+ '25-02-2012', '26-02-2012', '27-02-2012',
+ '28-02-2012', '29-02-2012', '01-03-2012'
+ );
+
+ $this->assertEquals($dates, date_range(mktime(12, 0, 0, 1, 29, 2012), mktime(12, 0, 0, 3, 1, 2012), TRUE, 'd-m-Y'));
+ array_pop($dates);
+ $this->assertEquals($dates, date_range(mktime(12, 0, 0, 1, 29, 2012), 31, FALSE, 'd-m-Y'));
+ }
+
}
/* End of file date_helper_test.php */ \ No newline at end of file
diff --git a/tests/codeigniter/helpers/directory_helper_test.php b/tests/codeigniter/helpers/directory_helper_test.php
index 176ff1d78..c39ccd8d0 100644
--- a/tests/codeigniter/helpers/directory_helper_test.php
+++ b/tests/codeigniter/helpers/directory_helper_test.php
@@ -19,6 +19,7 @@ class Directory_helper_test extends CI_TestCase {
'benchmark.html' => '',
'database' => array('active_record.html' => '', 'binds.html' => ''),
'email.html' => '',
+ '0' => '',
'.hiddenfile.txt' => ''
)
);
@@ -30,7 +31,8 @@ class Directory_helper_test extends CI_TestCase {
'libraries' => array(
'benchmark.html',
'database' => array('active_record.html', 'binds.html'),
- 'email.html'
+ 'email.html',
+ '0'
)
);
diff --git a/tests/codeigniter/helpers/html_helper_test.php b/tests/codeigniter/helpers/html_helper_test.php
index 9a7bb48bf..4dd717ff7 100644
--- a/tests/codeigniter/helpers/html_helper_test.php
+++ b/tests/codeigniter/helpers/html_helper_test.php
@@ -22,6 +22,22 @@ class Html_helper_test extends CI_TestCase {
$this->assertEquals('<h2 class="bar">foobar</h2>', heading('foobar', 2, 'class="bar"'));
}
+ public function test_heading_array_attributes()
+ {
+ // Test array of attributes
+ $this->assertEquals('<h2 class="bar" id="foo">foobar</h2>', heading('foobar', 2, array('class' => 'bar', 'id' => 'foo')));
+ }
+
+ public function test_heading_object_attributes()
+ {
+ // Test array of attributes
+ $this->assertEquals('<h2 class="bar" id="foo">foobar</h2>', heading('foobar', 2, array('class' => 'bar', 'id' => 'foo')));
+ $test = new stdClass;
+ $test->class = "bar";
+ $test->id = "foo";
+ $this->assertEquals('<h2 class="bar" id="foo">foobar</h2>', heading('foobar', 2, $test));
+ }
+
// ------------------------------------------------------------------------
public function test_Ul()
@@ -72,5 +88,4 @@ EOH;
$this->assertEquals($expect, meta(array('name' => 'foo')));
}
-
} \ No newline at end of file
diff --git a/tests/codeigniter/libraries/Calendar_test.php b/tests/codeigniter/libraries/Calendar_test.php
new file mode 100644
index 000000000..95668d70d
--- /dev/null
+++ b/tests/codeigniter/libraries/Calendar_test.php
@@ -0,0 +1,204 @@
+<?php
+
+class Calendar_test extends CI_TestCase {
+
+ function __construct()
+ {
+ $obj = new stdClass;
+ $obj->calendar = new Mock_Libraries_Calendar();
+
+ $this->calendar = $obj->calendar;
+ }
+
+ function test_initialize()
+ {
+ $this->calendar->initialize(array(
+ 'month_type' => 'short',
+ 'start_day' => 'monday'
+ ));
+ $this->assertEquals('short', $this->calendar->month_type);
+ $this->assertEquals('monday', $this->calendar->start_day);
+ }
+
+ /**
+ * @covers Mock_Libraries_Calendar::parse_template
+ */
+ function test_generate()
+ {
+ $no_events = '<table border="0" cellpadding="4" cellspacing="0">
+
+<tr>
+<th colspan="7">September&nbsp;2011</th>
+
+</tr>
+
+<tr>
+<td>Su</td><td>Mo</td><td>Tu</td><td>We</td><td>Th</td><td>Fr</td><td>Sa</td>
+</tr>
+
+<tr>
+<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>1</td><td>2</td><td>3</td>
+</tr>
+
+<tr>
+<td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td>
+</tr>
+
+<tr>
+<td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td>
+</tr>
+
+<tr>
+<td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td>
+</tr>
+
+<tr>
+<td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td><td>&nbsp;</td>
+</tr>
+
+</table>';
+
+ $this->assertEquals($no_events, $this->calendar->generate(2011, 9));
+
+ $data = array(
+ 3 => 'http://example.com/news/article/2006/03/',
+ 7 => 'http://example.com/news/article/2006/07/',
+ 13 => 'http://example.com/news/article/2006/13/',
+ 26 => 'http://example.com/news/article/2006/26/'
+ );
+
+ $events = '<table border="0" cellpadding="4" cellspacing="0">
+
+<tr>
+<th colspan="7">September&nbsp;2011</th>
+
+</tr>
+
+<tr>
+<td>Su</td><td>Mo</td><td>Tu</td><td>We</td><td>Th</td><td>Fr</td><td>Sa</td>
+</tr>
+
+<tr>
+<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>1</td><td>2</td><td><a href="http://example.com/news/article/2006/03/">3</a></td>
+</tr>
+
+<tr>
+<td>4</td><td>5</td><td>6</td><td><a href="http://example.com/news/article/2006/07/">7</a></td><td>8</td><td>9</td><td>10</td>
+</tr>
+
+<tr>
+<td>11</td><td>12</td><td><a href="http://example.com/news/article/2006/13/">13</a></td><td>14</td><td>15</td><td>16</td><td>17</td>
+</tr>
+
+<tr>
+<td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td>
+</tr>
+
+<tr>
+<td>25</td><td><a href="http://example.com/news/article/2006/26/">26</a></td><td>27</td><td>28</td><td>29</td><td>30</td><td>&nbsp;</td>
+</tr>
+
+</table>';
+
+ $this->assertEquals($events, $this->calendar->generate(2011, 9, $data));
+ }
+
+ function test_get_month_name()
+ {
+ $this->calendar->month_type = NULL;
+ $this->assertEquals('January', $this->calendar->get_month_name('01'));
+
+ $this->calendar->month_type = 'short';
+ $this->assertEquals('Jan', $this->calendar->get_month_name('01'));
+ }
+
+ function test_get_day_names()
+ {
+ $this->assertEquals(array(
+ 'Sunday',
+ 'Monday',
+ 'Tuesday',
+ 'Wednesday',
+ 'Thursday',
+ 'Friday',
+ 'Saturday'
+ ), $this->calendar->get_day_names('long'));
+
+ $this->assertEquals(array(
+ 'Sun',
+ 'Mon',
+ 'Tue',
+ 'Wed',
+ 'Thu',
+ 'Fri',
+ 'Sat'
+ ), $this->calendar->get_day_names('short'));
+
+ $this->calendar->day_type = NULL;
+
+ $this->assertEquals(array(
+ 'Su',
+ 'Mo',
+ 'Tu',
+ 'We',
+ 'Th',
+ 'Fr',
+ 'Sa'
+ ), $this->calendar->get_day_names());
+ }
+
+ function test_adjust_date()
+ {
+ $this->assertEquals(array('month' => 8, 'year' => 2012), $this->calendar->adjust_date(8, 2012));
+ $this->assertEquals(array('month' => 1, 'year' => 2013), $this->calendar->adjust_date(13, 2012));
+ }
+
+ function test_get_total_days()
+ {
+ $this->assertEquals(0, $this->calendar->get_total_days(13, 2012));
+
+ $this->assertEquals(31, $this->calendar->get_total_days(1, 2012));
+ $this->assertEquals(28, $this->calendar->get_total_days(2, 2011));
+ $this->assertEquals(29, $this->calendar->get_total_days(2, 2012));
+ $this->assertEquals(31, $this->calendar->get_total_days(3, 2012));
+ $this->assertEquals(30, $this->calendar->get_total_days(4, 2012));
+ $this->assertEquals(31, $this->calendar->get_total_days(5, 2012));
+ $this->assertEquals(30, $this->calendar->get_total_days(6, 2012));
+ $this->assertEquals(31, $this->calendar->get_total_days(7, 2012));
+ $this->assertEquals(31, $this->calendar->get_total_days(8, 2012));
+ $this->assertEquals(30, $this->calendar->get_total_days(9, 2012));
+ $this->assertEquals(31, $this->calendar->get_total_days(10, 2012));
+ $this->assertEquals(30, $this->calendar->get_total_days(11, 2012));
+ $this->assertEquals(31, $this->calendar->get_total_days(12, 2012));
+ }
+
+ function test_default_template()
+ {
+ $array = array(
+ 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
+ 'heading_row_start' => '<tr>',
+ 'heading_previous_cell' => '<th><a href="{previous_url}">&lt;&lt;</a></th>',
+ 'heading_title_cell' => '<th colspan="{colspan}">{heading}</th>',
+ 'heading_next_cell' => '<th><a href="{next_url}">&gt;&gt;</a></th>',
+ 'heading_row_end' => '</tr>',
+ 'week_row_start' => '<tr>',
+ 'week_day_cell' => '<td>{week_day}</td>',
+ 'week_row_end' => '</tr>',
+ 'cal_row_start' => '<tr>',
+ 'cal_cell_start' => '<td>',
+ 'cal_cell_start_today' => '<td>',
+ 'cal_cell_content' => '<a href="{content}">{day}</a>',
+ 'cal_cell_content_today' => '<a href="{content}"><strong>{day}</strong></a>',
+ 'cal_cell_no_content' => '{day}',
+ 'cal_cell_no_content_today' => '<strong>{day}</strong>',
+ 'cal_cell_blank' => '&nbsp;',
+ 'cal_cell_end' => '</td>',
+ 'cal_cell_end_today' => '</td>',
+ 'cal_row_end' => '</tr>',
+ 'table_close' => '</table>'
+ );
+
+ $this->assertEquals($array, $this->calendar->default_template());
+ }
+
+} \ No newline at end of file
diff --git a/tests/codeigniter/libraries/Session_test.php b/tests/codeigniter/libraries/Session_test.php
new file mode 100644
index 000000000..60d3a5b30
--- /dev/null
+++ b/tests/codeigniter/libraries/Session_test.php
@@ -0,0 +1,400 @@
+<?php
+
+/**
+ * Session driver library unit test
+ */
+class Session_test extends CI_TestCase {
+ protected $settings = array(
+ 'use_cookies' => 0,
+ 'use_only_cookies' => 0,
+ 'cache_limiter' => false
+ );
+ protected $setting_vals = array();
+ protected $cookie_vals;
+ protected $session;
+
+ /**
+ * Set up test framework
+ */
+ public function set_up()
+ {
+ // Override settings
+ foreach ($this->settings as $name => $value) {
+ $this->setting_vals[$name] = ini_get('session.'.$name);
+ ini_set('session.'.$name, $value);
+ }
+
+ // Start with clean environment
+ $this->cookie_vals = $_COOKIE;
+ $_COOKIE = array();
+
+ // Establish necessary support classes
+ $obj = new stdClass;
+ $cfg = $this->ci_core_class('cfg');
+ $obj->config = new $cfg();
+ $ldr = $this->ci_core_class('load');
+ $obj->load = new $ldr();
+ $obj->input = new Mock_Core_Input(NULL, NULL);
+ $this->ci_instance($obj);
+
+ // Attach session instance locally
+ $config = array(
+ 'sess_encrypt_cookie' => FALSE,
+ 'sess_use_database' => FALSE,
+ 'sess_table_name' => '',
+ 'sess_expiration' => 7200,
+ 'sess_expire_on_close' => FALSE,
+ 'sess_match_ip' => FALSE,
+ 'sess_match_useragent' => TRUE,
+ 'sess_cookie_name' => 'ci_session',
+ 'cookie_path' => '',
+ 'cookie_domain' => '',
+ 'cookie_secure' => FALSE,
+ 'cookie_httponly' => FALSE,
+ 'sess_time_to_update' => 300,
+ 'time_reference' => 'local',
+ 'cookie_prefix' => '',
+ 'encryption_key' => 'foobar',
+ 'sess_valid_drivers' => array(
+ 'Mock_Libraries_Session_native',
+ 'Mock_Libraries_Session_cookie'
+ )
+ );
+ $this->session = new Mock_Libraries_Session($config);
+ }
+
+ /**
+ * Tear down test framework
+ */
+ public function tear_down()
+ {
+ // Restore environment
+ if (session_id()) session_destroy();
+ $_SESSION = array();
+ $_COOKIE = $this->cookie_vals;
+
+ // Restore settings
+ foreach ($this->settings as $name => $value) {
+ ini_set('session.'.$name, $this->setting_vals[$name]);
+ }
+ }
+
+ /**
+ * Test set_userdata() function
+ *
+ * @covers CI_Session::set_userdata
+ * @covers CI_Session::userdata
+ */
+ public function test_set_userdata()
+ {
+ // Set userdata values for each driver
+ $key1 = 'test1';
+ $ckey2 = 'test2';
+ $nkey2 = 'test3';
+ $cmsg1 = 'Some test data';
+ $cmsg2 = 42;
+ $nmsg1 = 'Other test data';
+ $nmsg2 = true;
+ $this->session->cookie->set_userdata($key1, $cmsg1);
+ $this->session->set_userdata($ckey2, $cmsg2);
+ $this->session->native->set_userdata($key1, $nmsg1);
+ $this->session->set_userdata($nkey2, $nmsg2);
+
+ // Verify independent messages
+ $this->assertEquals($cmsg1, $this->session->cookie->userdata($key1));
+ $this->assertEquals($nmsg1, $this->session->native->userdata($key1));
+
+ // Verify pre-selected driver sets
+ $this->assertEquals($cmsg2, $this->session->cookie->userdata($ckey2));
+ $this->assertEquals($nmsg2, $this->session->native->userdata($nkey2));
+
+ // Verify no crossover
+ $this->assertNull($this->session->cookie->userdata($nkey2));
+ $this->assertNull($this->session->native->userdata($ckey2));
+ }
+
+ /**
+ * Test the has_userdata() function
+ *
+ * @covers CI_Session::has_userdata
+ */
+ public function test_has_userdata()
+ {
+ // Set a userdata value for each driver
+ $key = 'hastest';
+ $cmsg = 'My test data';
+ $this->session->cookie->set_userdata($key, $cmsg);
+ $nmsg = 'Your test data';
+ $this->session->native->set_userdata($key, $nmsg);
+
+ // Verify values exist
+ $this->assertTrue($this->session->cookie->has_userdata($key));
+ $this->assertTrue($this->session->native->has_userdata($key));
+
+ // Verify non-existent values
+ $nokey = 'hasnot';
+ $this->assertFalse($this->session->cookie->has_userdata($nokey));
+ $this->assertFalse($this->session->native->has_userdata($nokey));
+ }
+
+ /**
+ * Test the all_userdata() function
+ *
+ * @covers CI_Session::all_userdata
+ */
+ public function test_all_userdata()
+ {
+ // Set a specific series of data for each driver
+ $cdata = array(
+ 'one' => 'first',
+ 'two' => 'second',
+ 'three' => 'third',
+ 'foo' => 'bar',
+ 'bar' => 'baz'
+ );
+ $ndata = array(
+ 'one' => 'gold',
+ 'two' => 'silver',
+ 'three' => 'bronze',
+ 'foo' => 'baz',
+ 'bar' => 'foo'
+ );
+ $this->session->cookie->set_userdata($cdata);
+ $this->session->native->set_userdata($ndata);
+
+ // Make sure all values are present
+ $call = $this->session->cookie->all_userdata();
+ foreach ($cdata as $key => $value) {
+ $this->assertEquals($value, $call[$key]);
+ }
+ $nall = $this->session->native->all_userdata();
+ foreach ($ndata as $key => $value) {
+ $this->assertEquals($value, $nall[$key]);
+ }
+ }
+
+ /**
+ * Test the unset_userdata() function
+ *
+ * @covers CI_Session::unset_userdata
+ */
+ public function test_unset_userdata()
+ {
+ // Set a userdata message for each driver
+ $key = 'untest';
+ $cmsg = 'Other test data';
+ $this->session->cookie->set_userdata($key, $cmsg);
+ $nmsg = 'Sundry test data';
+ $this->session->native->set_userdata($key, $nmsg);
+
+ // Verify independent messages
+ $this->assertEquals($this->session->cookie->userdata($key), $cmsg);
+ $this->assertEquals($this->session->native->userdata($key), $nmsg);
+
+ // Unset them and verify absence
+ $this->session->cookie->unset_userdata($key);
+ $this->session->native->unset_userdata($key);
+ $this->assertNull($this->session->cookie->userdata($key));
+ $this->assertNull($this->session->native->userdata($key));
+ }
+
+ /**
+ * Test the flashdata() functions
+ *
+ * @covers CI_Session::set_flashdata
+ * @covers CI_Session::flashdata
+ */
+ public function test_flashdata()
+ {
+ // Set flashdata message for each driver
+ $key = 'fltest';
+ $cmsg = 'Some flash data';
+ $this->session->cookie->set_flashdata($key, $cmsg);
+ $nmsg = 'Other flash data';
+ $this->session->native->set_flashdata($key, $nmsg);
+
+ // Simulate page reload
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+
+ // Verify independent messages
+ $this->assertEquals($cmsg, $this->session->cookie->flashdata($key));
+ $this->assertEquals($nmsg, $this->session->native->flashdata($key));
+
+ // Simulate next page reload
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+
+ // Verify absence of messages
+ $this->assertNull($this->session->cookie->flashdata($key));
+ $this->assertNull($this->session->native->flashdata($key));
+ }
+
+ /**
+ * Test the keep_flashdata() function
+ *
+ * @covers CI_Session::keep_flashdata
+ */
+ public function test_keep_flashdata()
+ {
+ // Set flashdata message for each driver
+ $key = 'kfltest';
+ $cmsg = 'My flash data';
+ $this->session->cookie->set_flashdata($key, $cmsg);
+ $nmsg = 'Your flash data';
+ $this->session->native->set_flashdata($key, $nmsg);
+
+ // Simulate page reload and verify independent messages
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+ $this->assertEquals($cmsg, $this->session->cookie->flashdata($key));
+ $this->assertEquals($nmsg, $this->session->native->flashdata($key));
+
+ // Keep messages
+ $this->session->cookie->keep_flashdata($key);
+ $this->session->native->keep_flashdata($key);
+
+ // Simulate next page reload and verify message persistence
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+ $this->assertEquals($cmsg, $this->session->cookie->flashdata($key));
+ $this->assertEquals($nmsg, $this->session->native->flashdata($key));
+
+ // Simulate next page reload and verify absence of messages
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+ $this->assertNull($this->session->cookie->flashdata($key));
+ $this->assertNull($this->session->native->flashdata($key));
+ }
+
+ /**
+ * Test the all_flashdata() function
+ *
+ * @covers CI_Session::all_flashdata
+ */
+ public function test_all_flashdata()
+ {
+ // Set a specific series of data for each driver
+ $cdata = array(
+ 'one' => 'first',
+ 'two' => 'second',
+ 'three' => 'third',
+ 'foo' => 'bar',
+ 'bar' => 'baz'
+ );
+ $ndata = array(
+ 'one' => 'gold',
+ 'two' => 'silver',
+ 'three' => 'bronze',
+ 'foo' => 'baz',
+ 'bar' => 'foo'
+ );
+ $this->session->cookie->set_flashdata($cdata);
+ $this->session->native->set_flashdata($ndata);
+
+ // Simulate page reload and make sure all values are present
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+ $this->assertEquals($cdata, $this->session->cookie->all_flashdata());
+ $this->assertEquals($ndata, $this->session->native->all_flashdata());
+ }
+
+ /**
+ * Test the tempdata() functions
+ *
+ * @covers CI_Session::set_tempdata
+ * @covers CI_Session::tempdata
+ */
+ public function test_set_tempdata()
+ {
+ // Set tempdata message for each driver - 1 second timeout
+ $key = 'tmptest';
+ $cmsg = 'Some temp data';
+ $this->session->cookie->set_tempdata($key, $cmsg, 1);
+ $nmsg = 'Other temp data';
+ $this->session->native->set_tempdata($key, $nmsg, 1);
+
+ // Simulate page reload and verify independent messages
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+ $this->assertEquals($cmsg, $this->session->cookie->tempdata($key));
+ $this->assertEquals($nmsg, $this->session->native->tempdata($key));
+
+ // Wait 2 seconds, simulate page reload and verify message absence
+ sleep(2);
+ $this->session->cookie->reload();
+ $this->session->native->reload();
+ $this->assertNull($this->session->cookie->tempdata($key));
+ $this->assertNull($this->session->native->tempdata($key));
+ }
+
+ /**
+ * Test the unset_tempdata() function
+ *
+ * @covers CI_Session::unset_tempdata
+ */
+ public function test_unset_tempdata()
+ {
+ // Set tempdata message for each driver - 1 second timeout
+ $key = 'utmptest';
+ $cmsg = 'My temp data';
+ $this->session->cookie->set_tempdata($key, $cmsg, 1);
+ $nmsg = 'Your temp data';
+ $this->session->native->set_tempdata($key, $nmsg, 1);
+
+ // Verify independent messages
+ $this->assertEquals($cmsg, $this->session->cookie->tempdata($key));
+ $this->assertEquals($nmsg, $this->session->native->tempdata($key));
+
+ // Unset data and verify message absence
+ $this->session->cookie->unset_tempdata($key);
+ $this->session->native->unset_tempdata($key);
+ $this->assertNull($this->session->cookie->tempdata($key));
+ $this->assertNull($this->session->native->tempdata($key));
+ }
+
+ /**
+ * Test the sess_regenerate() function
+ *
+ * @covers CI_Session::sess_regenerate
+ */
+ public function test_sess_regenerate()
+ {
+ // Get current session id, regenerate, and compare
+ // Cookie driver
+ $oldid = $this->session->cookie->userdata('session_id');
+ $this->session->cookie->sess_regenerate();
+ $newid = $this->session->cookie->userdata('session_id');
+ $this->assertNotEquals($oldid, $newid);
+
+ // Native driver - bug #55267 (https://bugs.php.net/bug.php?id=55267) prevents testing this
+ // $oldid = session_id();
+ // $this->session->native->sess_regenerate();
+ // $oldid = session_id();
+ // $this->assertNotEquals($oldid, $newid);
+ }
+
+ /**
+ * Test the sess_destroy() function
+ *
+ * @covers CI_Session::sess_destroy
+ */
+ public function test_sess_destroy()
+ {
+ // Set a userdata message, destroy session, and verify absence
+ $key = 'dsttest';
+ $msg = 'More test data';
+
+ // Cookie driver
+ $this->session->cookie->set_userdata($key, $msg);
+ $this->assertEquals($msg, $this->session->cookie->userdata($key));
+ $this->session->cookie->sess_destroy();
+ $this->assertNull($this->session->cookie->userdata($key));
+
+ // Native driver
+ $this->session->native->set_userdata($key, $msg);
+ $this->assertEquals($msg, $this->session->native->userdata($key));
+ $this->session->native->sess_destroy();
+ $this->assertNull($this->session->native->userdata($key));
+ }
+} \ No newline at end of file
diff --git a/tests/codeigniter/libraries/Upload_test.php b/tests/codeigniter/libraries/Upload_test.php
new file mode 100644
index 000000000..d79a3ffc9
--- /dev/null
+++ b/tests/codeigniter/libraries/Upload_test.php
@@ -0,0 +1,270 @@
+<?php
+
+class Upload_test extends CI_TestCase {
+
+ function set_up()
+ {
+ $obj = new stdClass;
+ $obj->upload = new Mock_Libraries_Upload();
+ $obj->security = new Mock_Core_Security();
+ $obj->lang = new Mock_Core_Lang();
+
+ $this->ci_instance($obj);
+ $this->upload = $obj->upload;
+
+ vfsStreamWrapper::register();
+ vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir'));
+
+ $this->_test_dir = vfsStreamWrapper::getRoot();
+ }
+
+ function test_do_upload()
+ {
+ $this->markTestIncomplete('We can\'t really test this at the moment because of the call to `is_uploaded_file` in do_upload which isn\'t supported by vfsStream');
+ }
+
+ function test_data()
+ {
+ $data = array(
+ 'file_name' => 'hello.txt',
+ 'file_type' => 'text/plain',
+ 'file_path' => '/tmp/',
+ 'full_path' => '/tmp/hello.txt',
+ 'raw_name' => 'hello',
+ 'orig_name' => 'hello.txt',
+ 'client_name' => '',
+ 'file_ext' => '.txt',
+ 'file_size' => 100,
+ 'is_image' => FALSE,
+ 'image_width' => '',
+ 'image_height' => '',
+ 'image_type' => '',
+ 'image_size_str' => ''
+ );
+
+ $this->upload->set_upload_path('/tmp/');
+
+ foreach ($data as $k => $v)
+ {
+ $this->upload->{$k} = $v;
+ }
+
+ $this->assertEquals('hello.txt', $this->upload->data('file_name'));
+ $this->assertEquals($data, $this->upload->data());
+ }
+
+ function test_set_upload_path()
+ {
+ $this->upload->set_upload_path('/tmp/');
+ $this->assertEquals('/tmp/', $this->upload->upload_path);
+
+ $this->upload->set_upload_path('/tmp');
+ $this->assertEquals('/tmp/', $this->upload->upload_path);
+ }
+
+ function test_set_filename()
+ {
+ $file1 = vfsStream::newFile('hello-world.txt')->withContent('Hello world.')->at($this->_test_dir);
+ $this->upload->file_ext = '.txt';
+
+ $this->assertEquals('helloworld.txt', $this->upload->set_filename(vfsStream::url('testDir').'/', 'helloworld.txt'));
+ $this->assertEquals('hello-world1.txt', $this->upload->set_filename(vfsStream::url('testDir').'/', 'hello-world.txt'));
+ }
+
+ function test_set_max_filesize()
+ {
+ $this->upload->set_max_filesize(100);
+ $this->assertEquals(100, $this->upload->max_size);
+ }
+
+ function test_set_max_filename()
+ {
+ $this->upload->set_max_filename(100);
+ $this->assertEquals(100, $this->upload->max_filename);
+ }
+
+ function test_set_max_width()
+ {
+ $this->upload->set_max_width(100);
+ $this->assertEquals(100, $this->upload->max_width);
+ }
+
+ function test_set_max_height()
+ {
+ $this->upload->set_max_height(100);
+ $this->assertEquals(100, $this->upload->max_height);
+ }
+
+ function test_set_allowed_types()
+ {
+ $this->upload->set_allowed_types('*');
+ $this->assertEquals('*', $this->upload->allowed_types);
+
+ $this->upload->set_allowed_types('foo|bar');
+ $this->assertEquals(array('foo', 'bar'), $this->upload->allowed_types);
+ }
+
+ function test_set_image_properties()
+ {
+ $this->upload->file_type = 'image/gif';
+ $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+
+ $props = array(
+ 'image_width' => 170,
+ 'image_height' => 73,
+ 'image_type' => 'gif',
+ 'image_size_str' => 'width="170" height="73"'
+ );
+
+ $this->upload->set_image_properties($this->upload->file_temp);
+
+ $this->assertEquals($props['image_width'], $this->upload->image_width);
+ $this->assertEquals($props['image_height'], $this->upload->image_height);
+ $this->assertEquals($props['image_type'], $this->upload->image_type);
+ $this->assertEquals($props['image_size_str'], $this->upload->image_size_str);
+ }
+
+ function test_set_xss_clean()
+ {
+ $this->upload->set_xss_clean(TRUE);
+ $this->assertTrue($this->upload->xss_clean);
+
+ $this->upload->set_xss_clean(FALSE);
+ $this->assertFalse($this->upload->xss_clean);
+ }
+
+ function test_is_image()
+ {
+ $this->upload->file_type = 'image/x-png';
+ $this->assertTrue($this->upload->is_image());
+
+ $this->upload->file_type = 'text/plain';
+ $this->assertFalse($this->upload->is_image());
+ }
+
+ function test_is_allowed_filetype()
+ {
+ $this->upload->allowed_types = array('html', 'gif');
+
+ $this->upload->file_ext = '.txt';
+ $this->upload->file_type = 'text/plain';
+ $this->assertFalse($this->upload->is_allowed_filetype(FALSE));
+ $this->assertFalse($this->upload->is_allowed_filetype(TRUE));
+
+ $this->upload->file_ext = '.html';
+ $this->upload->file_type = 'text/html';
+ $this->assertTrue($this->upload->is_allowed_filetype(FALSE));
+ $this->assertTrue($this->upload->is_allowed_filetype(TRUE));
+
+ $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+ $this->upload->file_ext = '.gif';
+ $this->upload->file_type = 'image/gif';
+ $this->assertTrue($this->upload->is_allowed_filetype());
+ }
+
+ function test_is_allowed_filesize()
+ {
+ $this->upload->max_size = 100;
+ $this->upload->file_size = 99;
+
+ $this->assertTrue($this->upload->is_allowed_filesize());
+
+ $this->upload->file_size = 101;
+ $this->assertFalse($this->upload->is_allowed_filesize());
+ }
+
+ function test_is_allowed_dimensions()
+ {
+ $this->upload->file_type = 'text/plain';
+ $this->assertTrue($this->upload->is_allowed_dimensions());
+
+ $this->upload->file_type = 'image/gif';
+ $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+
+ $this->upload->max_width = 10;
+ $this->assertFalse($this->upload->is_allowed_dimensions());
+
+ $this->upload->max_width = 170;
+ $this->upload->max_height = 10;
+ $this->assertFalse($this->upload->is_allowed_dimensions());
+
+ $this->upload->max_height = 73;
+ $this->assertTrue($this->upload->is_allowed_dimensions());
+ }
+
+ function test_validate_upload_path()
+ {
+ $this->upload->upload_path = '';
+ $this->assertFalse($this->upload->validate_upload_path());
+
+ $this->upload->upload_path = vfsStream::url('testDir');
+ $this->assertTrue($this->upload->validate_upload_path());
+ }
+
+ function test_get_extension()
+ {
+ $this->assertEquals('.txt', $this->upload->get_extension('hello.txt'));
+ $this->assertEquals('.htaccess', $this->upload->get_extension('.htaccess'));
+ $this->assertEquals('', $this->upload->get_extension('hello'));
+ }
+
+ function test_clean_file_name()
+ {
+ $this->assertEquals('hello.txt', $this->upload->clean_file_name('hello.txt'));
+ $this->assertEquals('hello.txt', $this->upload->clean_file_name('%253chell>o.txt'));
+ }
+
+ function test_limit_filename_length()
+ {
+ $this->assertEquals('hello.txt', $this->upload->limit_filename_length('hello.txt', 10));
+ $this->assertEquals('hello.txt', $this->upload->limit_filename_length('hello-world.txt', 9));
+ }
+
+ function test_do_xss_clean()
+ {
+ $file1 = vfsStream::newFile('file1.txt')->withContent('The billy goat was waiting for them.')->at($this->_test_dir);
+ $file2 = vfsStream::newFile('file2.txt')->at($this->_test_dir);
+ $file3 = vfsStream::newFile('file3.txt')->withContent('<script type="text/javascript">alert("Boo! said the billy goat")</script>')->at($this->_test_dir);
+
+ $this->upload->file_temp = vfsStream::url('file1.txt');
+ $this->assertTrue($this->upload->do_xss_clean());
+
+ $this->upload->file_temp = vfsStream::url('file2.txt');
+ $this->assertFalse($this->upload->do_xss_clean());
+
+ $this->upload->file_temp = vfsStream::url('file3.txt');
+ $this->assertFalse($this->upload->do_xss_clean());
+
+ $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+ $this->assertTrue($this->upload->do_xss_clean());
+ }
+
+ function test_set_error()
+ {
+ $errors = array(
+ 'An error!'
+ );
+
+ $another = 'Another error!';
+
+ $this->upload->set_error($errors);
+ $this->assertEquals($errors, $this->upload->error_msg);
+
+ $errors[] = $another;
+ $this->upload->set_error($another);
+ $this->assertEquals($errors, $this->upload->error_msg);
+ }
+
+ function test_display_errors()
+ {
+ $this->upload->error_msg[] = 'Error test';
+ $this->assertEquals('<p>Error test</p>', $this->upload->display_errors());
+ }
+
+ function test_mimes_types()
+ {
+ $this->assertEquals('text/plain', $this->upload->mimes_types('txt'));
+ $this->assertFalse($this->upload->mimes_types('foobar'));
+ }
+
+} \ No newline at end of file
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
index be1c2220c..88d016bba 100644
--- a/tests/mocks/autoloader.php
+++ b/tests/mocks/autoloader.php
@@ -26,10 +26,14 @@ function autoload($class)
'Email', 'Encrypt', 'Form_validation',
'Ftp', 'Image_lib', 'Javascript',
'Log', 'Migration', 'Pagination',
- 'Parser', 'Profiler', 'Session',
- 'Table', 'Trackback', 'Typography',
- 'Unit_test', 'Upload', 'User_agent',
- 'Xmlrpc', 'Zip',
+ 'Parser', 'Profiler', 'Table',
+ 'Trackback', 'Typography', 'Unit_test',
+ 'Upload', 'User_agent', 'Xmlrpc',
+ 'Zip',
+ );
+
+ $ci_drivers = array(
+ 'Session',
);
if (strpos($class, 'Mock_') === 0)
@@ -52,6 +56,15 @@ function autoload($class)
$dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR;
$class = ($subclass === 'Driver_Library') ? 'Driver' : $subclass;
}
+ elseif (in_array($subclass, $ci_drivers))
+ {
+ $dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR.$subclass.DIRECTORY_SEPARATOR;
+ $class = $subclass;
+ }
+ elseif (in_array(($parent = strtok($subclass, '_')), $ci_drivers)) {
+ $dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR.$parent.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
+ $class = $subclass;
+ }
elseif (preg_match('/^CI_DB_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 3)
{
$driver_path = BASEPATH.'database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
@@ -91,4 +104,4 @@ function autoload($class)
}
include_once($file);
-} \ No newline at end of file
+}
diff --git a/tests/mocks/core/input.php b/tests/mocks/core/input.php
index 2a4aa4997..0d1873849 100644
--- a/tests/mocks/core/input.php
+++ b/tests/mocks/core/input.php
@@ -28,4 +28,14 @@ class Mock_Core_Input extends CI_Input {
return parent::_fetch_from_array($array, $index, $xss_clean);
}
+ /**
+ * Lie about being a CLI request
+ *
+ * We take advantage of this in libraries/Session_test
+ */
+ public function is_cli_request()
+ {
+ return FALSE;
+ }
+
} \ No newline at end of file
diff --git a/tests/mocks/core/lang.php b/tests/mocks/core/lang.php
new file mode 100644
index 000000000..1b99aedb3
--- /dev/null
+++ b/tests/mocks/core/lang.php
@@ -0,0 +1,15 @@
+<?php
+
+class Mock_Core_Lang extends CI_Lang {
+
+ function line($line = '')
+ {
+ return FALSE;
+ }
+
+ function load($langfile, $idiom = '', $return = false, $add_suffix = true, $alt_path = '')
+ {
+ return;
+ }
+
+} \ No newline at end of file
diff --git a/tests/mocks/libraries/calendar.php b/tests/mocks/libraries/calendar.php
new file mode 100644
index 000000000..8fee5365e
--- /dev/null
+++ b/tests/mocks/libraries/calendar.php
@@ -0,0 +1,25 @@
+<?php
+
+class Mock_Libraries_Calendar extends CI_Calendar {
+
+ public function __construct($config = array())
+ {
+ $this->CI = new stdClass;
+ $this->CI->lang = new Mock_Core_Lang();
+
+ if ( ! in_array('calendar_lang.php', $this->CI->lang->is_loaded, TRUE))
+ {
+ $this->CI->lang->load('calendar');
+ }
+
+ $this->local_time = time();
+
+ if (count($config) > 0)
+ {
+ $this->initialize($config);
+ }
+
+ log_message('debug', 'Calendar Class Initialized');
+ }
+
+} \ No newline at end of file
diff --git a/tests/mocks/libraries/session.php b/tests/mocks/libraries/session.php
new file mode 100644
index 000000000..9d6feee42
--- /dev/null
+++ b/tests/mocks/libraries/session.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Mock library to add testing features to Session driver library
+ */
+class Mock_Libraries_Session extends CI_Session {
+ /**
+ * Simulate new page load
+ */
+ public function reload()
+ {
+ $this->_flashdata_sweep();
+ $this->_flashdata_mark();
+ $this->_tempdata_sweep();
+ }
+}
+
+/**
+ * Mock cookie driver to overload cookie setting
+ */
+class Mock_Libraries_Session_cookie extends CI_Session_cookie {
+ /**
+ * Overload _setcookie to manage $_COOKIE values, since actual cookies can't be set in unit testing
+ */
+ protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = false,
+ $httponly = false)
+ {
+ if (empty($value) || $expire <= time()) {
+ // Clear cookie
+ unset($_COOKIE[$name]);
+ }
+ else {
+ // Set cookie
+ $_COOKIE[$name] = $value;
+ }
+ }
+}
+
+/**
+ * Mock native driver (just for consistency in loading)
+ */
+class Mock_Libraries_Session_native extends CI_Session_native { }
+
diff --git a/tests/mocks/libraries/upload.php b/tests/mocks/libraries/upload.php
new file mode 100644
index 000000000..988723e45
--- /dev/null
+++ b/tests/mocks/libraries/upload.php
@@ -0,0 +1,3 @@
+<?php
+
+class Mock_Libraries_Upload extends CI_Upload {} \ No newline at end of file
diff --git a/tests/mocks/uploads/ci_logo.gif b/tests/mocks/uploads/ci_logo.gif
new file mode 100644
index 000000000..073ec14b4
--- /dev/null
+++ b/tests/mocks/uploads/ci_logo.gif
Binary files differ
diff --git a/tests/travis/mysql.phpunit.xml b/tests/travis/mysql.phpunit.xml
index 38c8eba48..06d4a011b 100644
--- a/tests/travis/mysql.phpunit.xml
+++ b/tests/travis/mysql.phpunit.xml
@@ -18,7 +18,7 @@
</testsuite>
</testsuites>
<filter>
- <whitelist addUncoveredFilesFromWhitelist="true">
+ <whitelist addUncoveredFilesFromWhitelist="false">
<directory suffix=".php">../../system</directory>
</whitelist>
</filter>
diff --git a/tests/travis/pdo/mysql.phpunit.xml b/tests/travis/pdo/mysql.phpunit.xml
index c3113a66f..7121edc45 100644
--- a/tests/travis/pdo/mysql.phpunit.xml
+++ b/tests/travis/pdo/mysql.phpunit.xml
@@ -18,7 +18,7 @@
</testsuite>
</testsuites>
<filter>
- <whitelist addUncoveredFilesFromWhitelist="true">
+ <whitelist addUncoveredFilesFromWhitelist="false">
<directory suffix=".php">../../../system</directory>
</whitelist>
</filter>
diff --git a/tests/travis/pdo/pgsql.phpunit.xml b/tests/travis/pdo/pgsql.phpunit.xml
index 232025523..df3ff986e 100644
--- a/tests/travis/pdo/pgsql.phpunit.xml
+++ b/tests/travis/pdo/pgsql.phpunit.xml
@@ -18,7 +18,7 @@
</testsuite>
</testsuites>
<filter>
- <whitelist addUncoveredFilesFromWhitelist="true">
+ <whitelist addUncoveredFilesFromWhitelist="false">
<directory suffix=".php">../../../system</directory>
</whitelist>
</filter>
diff --git a/tests/travis/pdo/sqlite.phpunit.xml b/tests/travis/pdo/sqlite.phpunit.xml
index 3d1256721..7d867f6d1 100644
--- a/tests/travis/pdo/sqlite.phpunit.xml
+++ b/tests/travis/pdo/sqlite.phpunit.xml
@@ -18,7 +18,7 @@
</testsuite>
</testsuites>
<filter>
- <whitelist addUncoveredFilesFromWhitelist="true">
+ <whitelist addUncoveredFilesFromWhitelist="false">
<directory suffix=".php">../../../system</directory>
</whitelist>
</filter>
diff --git a/tests/travis/pgsql.phpunit.xml b/tests/travis/pgsql.phpunit.xml
index 51e433d76..bfddbf6b5 100644
--- a/tests/travis/pgsql.phpunit.xml
+++ b/tests/travis/pgsql.phpunit.xml
@@ -18,7 +18,7 @@
</testsuite>
</testsuites>
<filter>
- <whitelist addUncoveredFilesFromWhitelist="true">
+ <whitelist addUncoveredFilesFromWhitelist="false">
<directory suffix=".php">../../system</directory>
</whitelist>
</filter>
diff --git a/tests/travis/sqlite.phpunit.xml b/tests/travis/sqlite.phpunit.xml
index 701165734..75c946aee 100644
--- a/tests/travis/sqlite.phpunit.xml
+++ b/tests/travis/sqlite.phpunit.xml
@@ -18,7 +18,7 @@
</testsuite>
</testsuites>
<filter>
- <whitelist addUncoveredFilesFromWhitelist="true">
+ <whitelist addUncoveredFilesFromWhitelist="false">
<directory suffix=".php">../../system</directory>
</whitelist>
</filter>
diff --git a/user_guide_src/source/_themes/eldocs/layout.html b/user_guide_src/source/_themes/eldocs/layout.html
index 01db07cac..51d61b849 100644
--- a/user_guide_src/source/_themes/eldocs/layout.html
+++ b/user_guide_src/source/_themes/eldocs/layout.html
@@ -91,13 +91,7 @@
</div><!-- /#brand -->
<div id="header">
- <form method="get" action="http://www.google.com/search">
- <fieldset>
- <input type="text" name="q" id="q" value="">
- <input type="hidden" name="as_sitesearch" id="as_sitesearch" value="{{ project_domain }}/user_guide/" />
- <input class="grades" type="submit" value="search">
- </fieldset>
- </form>
+ {%- include "searchbox.html" %}
<ul>
{%- block rootrellink %}
<li><a href="{{ pathto(master_doc) }}">User Guide Home</a>{%- if pagename != 'index' %}&nbsp;&nbsp;{{ reldelim1 }}{%- endif %}</li>
@@ -113,8 +107,10 @@
</ul>
</div><!-- /#header -->
- <div class="section" id="content">
+ <div class="section body" id="content">
+ {%- block body %}
{{ body }}
+ {%- endblock %}
</div>
{%- endblock %}
@@ -125,8 +121,8 @@
{%- block footer %}
<div id="footer">
<p class="top"><a href="#header" title="Return to top">Return to top</a></p>
- <p><a href="{{ project_url }}">{{ project }}</a> &ndash; Copyright &copy; {{ copyright }}</a></p>
+ <p><a href="http://{{ project_domain }}/">{{ project }}</a> &ndash; Copyright &copy; {{ copyright }}</a></p>
</div><!-- /#footer -->
{%- endblock %}
</body>
-</html>
+</html> \ No newline at end of file
diff --git a/user_guide_src/source/_themes/eldocs/searchbox.html b/user_guide_src/source/_themes/eldocs/searchbox.html
new file mode 100644
index 000000000..039590bd9
--- /dev/null
+++ b/user_guide_src/source/_themes/eldocs/searchbox.html
@@ -0,0 +1,21 @@
+<!--
+ --------------------------------
+ Original Google search box block
+ --------------------------------
+
+<form method="get" action="http://www.google.com/search">
+ <fieldset>
+ <input type="text" name="q" id="q" value="">
+ <input type="hidden" name="as_sitesearch" id="as_sitesearch" value="{{ project_domain }}/user_guide/" />
+ <input class="grades" type="submit" value="search">
+ </fieldset>
+</form>
+-->
+
+
+<form class="search" action="{{ pathto('search') }}" method="get">
+ <input type="text" name="q" id="q" value="" />
+ <input type="submit" value="search" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+</form>
diff --git a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
index 6cabda037..0a63871c5 100644
--- a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
+++ b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css
@@ -148,6 +148,8 @@ fieldset{ border: 0; }
.top{ float: right; }
+.highlight{ overflow-x: auto; }
+
.admonition,
.highlight-ee,
.highlight-ci,
@@ -166,6 +168,8 @@ fieldset{ border: 0; }
padding: 10px 10px 8px;
}
+.highlight-ci{ background-color: #FEFEFE; border-color: #E5E5E5; }
+
.admonition p{ margin: 0; }
.codeblock{ margin: 10px 0; }
@@ -181,6 +185,8 @@ fieldset{ border: 0; }
}
.admonition-title:after{ content: ': '; }
+
+.highlighted{ background-color: #FFF09B; }
#table-contents{
bottom: 0;
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 68719efa7..747791cd5 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -22,7 +22,7 @@ Release Date: Not Released
- ``$_SERVER['CI_ENV']`` can now be set to control the ``ENVIRONMENT`` constant.
- Added an optional backtrace to php-error template.
- Added Android to the list of user agents.
- - Added Windows 7, Android, Blackberry and iOS to the list of user platforms.
+ - Added Windows 7, Windows 8, Android, Blackberry, iOS and PlayStation 3 to the list of user platforms.
- Added Fennec (Firefox for mobile) to the list of mobile user agents.
- Ability to log certain error types, not all under a threshold.
- Added support for pem, p10, p12, p7a, p7c, p7m, p7r, p7s, crt, crl, der, kdb, rsa, cer, sst, csr Certs to mimes.php.
@@ -34,10 +34,12 @@ Release Date: Not Released
- Added support for rar archives to mimes.php.
- Updated support for xml ('application/xml') and xsl ('application/xml', 'text/xsl') files in mimes.php.
- Updated support for doc files in mimes.php.
+ - Updated support for docx files in mimes.php.
- Updated support for php files in mimes.php.
- Updated support for zip files in mimes.php.
+ - Updated support for csv files in mimes.php.
- Added some more doctypes.
- - Added Romanian and Greek characters in foreign_characters.php.
+ - Added Romanian, Greek and Vietnamese characters in *foreign_characters.php*.
- Changed logger to only chmod when file is first created.
- Removed previously deprecated SHA1 Library.
- Removed previously deprecated use of ``$autoload['core']`` in application/config/autoload.php.
@@ -49,7 +51,8 @@ Release Date: Not Released
- Changed detection of ``$view_folder`` so that if it's not found in the current path, it will now also be searched for under the application folder.
- Path constants BASEPATH, APPPATH and VIEWPATH are now (internally) defined as absolute paths.
- Updated email validation methods to use ``filter_var()`` instead of PCRE.
- - Changed environment defaults to report all errors in 'development' and only fatal ones in 'testing' and 'production' but only display them in 'development'.
+ - Changed environment defaults to report all errors in *development* and only fatal ones in *testing*, *production* but only display them in *development*.
+ - Updated *ip_address* database field lengths from 16 to 45 for supporting IPv6 address on :doc:`Trackback Library <libraries/trackback>` and :doc:`Captcha Helper <helpers/captcha_helper>`.
- Helpers
@@ -57,13 +60,15 @@ Release Date: Not Released
- ``now()`` now works with all timezone strings supported by PHP.
- Added an optional third parameter to ``timespan()`` that constrains the number of time units displayed.
- Added an optional parameter to ``timezone_menu()`` that allows more attributes to be added to the generated select tag.
- - Deprecated ``standard_date()``, which now just uses the native ``date()`` with `DateTime constants <http://bg2.php.net/manual/en/class.datetime.php#datetime.constants.types>`_.
+ - Deprecated ``standard_date()``, which now just uses the native ``date()`` with `DateTime constants <http://www.php.net/manual/en/class.datetime.php#datetime.constants.types>`_.
+ - Added function ``date_range()`` that generates a list of dates between a specified period.
- ``create_captcha()`` accepts additional colors parameter, allowing for color customization.
- :doc:`URL Helper <helpers/url_helper>` changes include:
- ``url_title()`` will now trim extra dashes from beginning and end.
- ``anchor_popup()`` will now fill the "href" attribute with the URL and its JS code will return false instead.
- Added JS window name support to ``anchor_popup()`` function.
- Added support (auto-detection) for HTTP/1.1 response code 303 in ``redirect()``.
+ - "auto" method in ``redirect()`` now chooses the "refresh" method only on IIS servers, instead of all servers on Windows.
- Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
- Changed ``humanize()`` to include a second param for the separator.
- Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words.
@@ -71,7 +76,7 @@ Release Date: Not Released
- Added a work-around in ``force_download()`` for a bug Android <= 2.1, where the filename extension needs to be in uppercase.
- ``form_dropdown()`` will now also take an array for unity with other form helpers.
- ``do_hash()`` now uses PHP's native ``hash()`` function (supporting more algorithms) and is deprecated.
- - Removed previously deprecated helper function ``js_insert_smiley()`` from smiley helper.
+ - Removed previously deprecated helper function ``js_insert_smiley()`` from :doc:`Smiley Helper <helpers/smiley_helper>`.
- :doc:`File Helper <helpers/file_helper>` changes include:
- ``set_realpath()`` can now also handle file paths as opposed to just directories.
- Added an optional paramater to ``delete_files()`` to enable it to skip deleting files such as .htaccess and index.html.
@@ -101,12 +106,13 @@ Release Date: Not Released
- Replaced the _error_message() and _error_number() methods with error(), that returns an array containing the last database error code and message.
- Improved version() implementation so that drivers that have a native function to get the version number don't have to be defined in the core DB_driver class.
- Improved support of the PostgreSQL driver, including:
- - pg_version() is now used to get the database version number, when possible.
- - Added db_set_charset() support.
- - Added support for optimize_table() in :doc:`Database Utilities <database/utilities>` (rebuilds table indexes).
- - Added boolean data type support in escape().
- - Added update_batch() support.
- - Removed limit() and order_by() support for UPDATE and DELETE queries in as PostgreSQL does not support those features.
+ - ``pg_version()`` is now used to get the database version number, when possible.
+ - Added ``db_set_charset()`` support.
+ - Added support for ``optimize_table()`` in :doc:`Database Utilities <database/utilities>` (rebuilds table indexes).
+ - Added boolean data type support in ``escape()``.
+ - Added ``update_batch()`` support.
+ - Removed ``limit()`` and ``order_by()`` support for UPDATE and DELETE queries as PostgreSQL does not support those features.
+ - Added a work-around for dead persistent connections to be re-created after a database restart.
- Added a constructor to the DB_result class and moved all driver-specific properties and logic out of the base DB_driver class to allow better abstraction.
- Removed protect_identifiers() and renamed internal method _protect_identifiers() to it instead - it was just an alias.
- Renamed internal method _escape_identifiers() to escape_identifiers().
@@ -137,74 +143,106 @@ Release Date: Not Released
- Added PDO support for create_database(), drop_database and drop_table() in :doc:`Database Forge <database/forge>`.
- Added unbuffered_row() method for getting a row without prefetching whole result (consume less memory).
- Added PDO support for ``list_fields()`` in :doc:`Database Results <database/results>`.
- - Added capability for packages to hold database.php config files
+ - Added capability for packages to hold database.php config files
- Added subdrivers support (currently only used by PDO).
+ - Added client compression support for MySQL and MySQLi.
+ - Removed :doc:`Loader Class <libraries/loader>` from Database error tracing to better find the likely culprit.
- Libraries
- - CI_Session now respects php.ini's session.gc_probability and session.gc_divisor
- - Added max_filename_increment config setting for Upload library.
- - CI_Loader::_ci_autoloader() is now a protected method.
- - Added custom filename to Email::attach() as $this->email->attach($filename, $disposition, $newname).
- - Added possibility to send attachment as buffer string in Email::attach() as $this->email->attach($buffer, $disposition, $newname, $mime).
+ - :doc:`Session Library <libraries/sessions>` changes include:
+ - Library changed to :doc:`Driver <general/drivers>` with classic Cookie driver as default.
+ - Added Native PHP Session driver to work with $_SESSION.
+ - Custom session drivers can be added anywhere in package paths and loaded with Session library.
+ - Session drivers interchangeable on the fly.
+ - New tempdata feature allows setting user data items with an expiration time.
+ - Added default $config['sess_driver'] and $config['sess_valid_drivers'] items to config.php file.
+ - Cookie driver now respects php.ini's session.gc_probability and session.gc_divisor
+ - Changed the Cookie driver to select only one row when using database sessions.
+ - Cookie driver now only writes to database at end of request when using database.
+ - Cookie driver now uses PHP functions for faster array manipulation when using database.
+ - Added ``all_flashdata()`` method to session class. Returns an associative array of only flashdata.
+ - Added ``has_userdata()`` method to verify existence of userdata item.
+ - Added ``tempdata()``, ``set_tempdata()``, and ``unset_tempdata()`` methods for manipulating tempdata.
+ - :doc:`File Uploading Library <libraries/file_uploading>` changes include:
+ - Added *max_filename_increment* config setting.
+ - Added an "index" parameter to the ``data()`` method.
- :doc:`Cart library <libraries/cart>` changes include:
- It now auto-increments quantity's instead of just resetting it, this is the default behaviour of large e-commerce sites.
- Product Name strictness can be disabled via the Cart Library by switching "$product_name_safe".
- Added function remove() to remove a cart item, updating with quantity of 0 seemed like a hack but has remained to retain compatibility.
- :doc:`Image Manipulation library <libraries/image_lib>` changes include:
- The initialize() method now only sets existing class properties.
- - Added support for 3-length hex color values for wm_font_color and wm_shadow_color properties, as well as validation for them.
- - Class properties wm_font_color, wm_shadow_color and wm_use_drop_shadow are now protected, to avoid breaking the text_watermark() method if they are set manually after initialization.
- - If property maintain_ratio is set to TRUE, image_reproportion() now doesn't need both width and height to be specified.
- - Property maintain_ratio is now taken into account when resizing images using ImageMagick library
- - Removed SHA1 function in the :doc:`Encryption Library <libraries/encryption>`.
- - Added $config['csrf_regeneration'] to the CSRF protection in the :doc:`Security library <libraries/security>`, which makes token regeneration optional.
- - Added $config['csrf_exclude_uris'] to the CSRF protection in the :doc:`Security library <libraries/security>`, which allows you list URIs which will not have the CSRF validation functions run.
+ - Added support for 3-length hex color values for *wm_font_color* and *wm_shadow_color* properties, as well as validation for them.
+ - Class properties *wm_font_color*, *wm_shadow_color* and *wm_use_drop_shadow* are now protected, to avoid breaking the ``text_watermark()`` method if they are set manually after initialization.
+ - If property *maintain_ratio* is set to TRUE, ``image_reproportion()`` now doesn't need both width and height to be specified.
+ - Property *maintain_ratio* is now taken into account when resizing images using ImageMagick library.
+ - Added support for maintaining transparency for PNG images in method ``text_watermark()``.
- :doc:`Form Validation library <libraries/form_validation>` changes include:
- - Added method error_array() to return all error messages as an array.
- - Added method set_data() to set an alternative data array to be validated instead of the default $_POST.
- - Added method reset_validation(), which resets internal validation variables in case of multiple validation routines.
- - Added support for setting error delimiters in the config file via $config['error_prefix'] and $config['error_suffix'].
- - _execute() now considers input data to be invalid if a specified rule is not found.
- - Removed method is_numeric() as it exists as a native PHP function and _execute() will find and use that (the 'is_numeric' rule itself is deprecated since 1.6.1).
+ - Added method ``error_array()`` to return all error messages as an array.
+ - Added method ``set_data()`` to set an alternative data array to be validated instead of the default ``$_POST``.
+ - Added method ``reset_validation()`` which resets internal validation variables in case of multiple validation routines.
+ - Added support for setting error delimiters in the config file via ``$config['error_prefix']`` and ``$config['error_suffix']``.
+ - ``_execute()`` now considers input data to be invalid if a specified rule is not found.
+ - Removed method ``is_numeric()`` as it exists as a native PHP function and ``_execute()`` will find and use that (the *is_numeric* rule itself is deprecated since 1.6.1).
- Native PHP functions used as rules can now accept an additional parameter, other than the data itself.
- - Updated set_rules() to accept an array of rules as well as a string.
+ - Updated ``set_rules()`` to accept an array of rules as well as a string.
- Fields that have empty rules set no longer run through validation (and therefore are not considered erroneous).
- - Changed the :doc:`Session Library <libraries/sessions>` to select only one row when using database sessions.
- - Added all_flashdata() method to session class. Returns an associative array of only flashdata.
- - Allowed for setting table class defaults in a config file.
+ - Added rule *differs* to check if the value of a field differs from the value of another field.
+ - Added support for setting :doc:`Table <libraries/table>` class defaults in a config file.
- Added a Wincache driver to the :doc:`Caching Library <libraries/caching>`.
- Added a Redis driver to the :doc:`Caching Library <libraries/caching>`.
- - Added dsn (delivery status notification) option to the :doc:`Email Library <libraries/email>`.
- - Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`.
- - Added an "index" parameter to the data() method in the :doc:`Upload Library <libraries/file_uploading>`.
+ - :doc:`Email library <libraries/email>` changes include:
+ - Added custom filename to ``Email::attach()`` as ``$this->email->attach($filename, $disposition, $newname)``.
+ - Added possibility to send attachment as buffer string in ``Email::attach()`` as ``$this->email->attach($buffer, $disposition, $newname, $mime)``.
+ - Added dsn (delivery status notification) option.
+ - Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`.
+ - Successfully sent emails will automatically clear the parameters.
+ - Added a *return_path* parameter to the ``from()`` method.
+ - Removed the second parameter (character limit) from internal method ``_prep_quoted_printable()`` as it is never used.
+ - Internal method ``_prep_quoted_printable()`` will now utilize the native ``quoted_printable_encode()``, ``imap_8bit()`` functions (if available) when CRLF is set to "\r\n".
+ - Default charset now relies on the global ``$config['charset']`` setting.
- :doc:`Pagination Library <libraries/pagination>` changes include:
- Added support for the anchor "rel" attribute.
- Added support for setting custom attributes.
- Deprecated usage of the "anchor_class" setting (use the new "attributes" setting instead).
- Added $config['reuse_query_string'] to allow automatic repopulation of query string arguments, combined with normal URI segments.
+ - Removed the default ``&nbsp;`` from a number of the configuration variables.
- Added the ability to use a proxy with the :doc:`XML-RPC Library <libraries/xmlrpc>`.
+ - :doc:`Encryption Library <libraries/encryption>` changes include:
+ - Added support for hashing algorithms other than SHA1 and MD5.
+ - Removed previously deprecated ``sha1()`` method.
- Core
- Changed private methods in the :doc:`URI Library <libraries/uri>` to protected so MY_URI can override them.
- - Removed CI_CORE boolean constant from CodeIgniter.php (no longer Reactor and Core versions).
- - Added method get_vars() to the :doc:`Loader Library <libraries/loader>` to retrieve all variables loaded with $this->load->vars().
- - is_loaded() function from system/core/Commons.php now returns a reference.
- - $config['rewrite_short_tags'] now has no effect when using PHP 5.4 as *<?=* will always be available.
- - Added method() to the :doc:`Input Library <libraries/input>` to retrieve $_SERVER['REQUEST_METHOD'].
- - Modified valid_ip() to use PHP's filter_var() in the :doc:`Input Library <libraries/input>`.
- - Added support for HTTP-Only cookies with new config option ``cookie_httponly`` (default FALSE).
- - Renamed method _call_hook() to call_hook() in the :doc:`Hooks Library <general/hooks>`.
- - Added get_content_type() method to the :doc:`Output Library <libraries/output>`.
- - Added get_mimes() function to system/core/Commons.php to return the config/mimes.php array.
- - Added a second argument to set_content_type() in the :doc:`Output Library <libraries/output>` that allows setting the document charset as well.
- - $config['time_reference'] now supports all timezone strings supported by PHP.
- - Added support for HTTP code 303 ("See Other") in set_status_header().
- - Changed :doc:`Config Library <libraries/config>` method site_url() to accept an array as well.
- - Added method ``strip_image_tags()`` to the :doc:`Security Library <libraries/security>`.
- - Changed ``_exception_handler()`` to respect php.ini 'display_errors' setting.
-
+ - Removed ``CI_CORE`` boolean constant from *CodeIgniter.php* (no longer Reactor and Core versions).
+ - :doc:`Loader Library <libraries/loader>` changes include:
+ - Added method ``get_vars()`` to the Loader to retrieve all variables loaded with ``$this->load->vars()``.
+ - ``CI_Loader::_ci_autoloader()`` is now a protected method.
+ - Added autoloading of drivers with ``$autoload['drivers']``.
+ - ``CI_Loader::library()`` will now load drivers as well, for backward compatibility of converted libraries (like Session).
+ - ``$config['rewrite_short_tags']`` now has no effect when using PHP 5.4 as *<?=* will always be available.
+ - :doc:`Input Library <libraries/input>` changes include:
+ - Added ``method()`` to retrieve ``$_SERVER['REQUEST_METHOD']``.
+ - Modified ``valid_ip()`` to use PHP's ``filter_var()``.
+ - Added support for arrays and network addresses (e.g. 192.168.1.1/24) for use with the *proxy_ips* setting.
+ - :doc:`Common functions <general/common_functions>` changes include:
+ - Added ``get_mimes()`` function to return the *config/mimes.php* array.
+ - Added support for HTTP code 303 ("See Other") in ``set_status_header()``.
+ - Removed redundant conditional to determine HTTP server protocol in ``set_status_header()``.
+ - Changed ``_exception_handler()`` to respect php.ini *display_errors* setting.
+ - Added support for HTTP-Only cookies with new config option *cookie_httponly* (default FALSE).
+ - Renamed method ``_call_hook()`` to ``call_hook()`` in the :doc:`Hooks Library <general/hooks>`.
+ - :doc:`Output Library <libraries/output>` changes include:
+ - Added method ``get_content_type()``.
+ - Added a second argument to method ``set_content_type()`` that allows setting the document charset as well.
+ - ``$config['time_reference']`` now supports all timezone strings supported by PHP.
+ - Changed :doc:`Config Library <libraries/config>` method ``site_url()`` to accept an array as well.
+ - :doc:`Security Library <libraries/security>` changes include:
+ - Added method ``strip_image_tags()``.
+ - Added ``$config['csrf_regeneration']``, which makes token regeneration optional.
+ - Added ``$config['csrf_exclude_uris']``, which allows you list URIs which will not have the CSRF validation methods run.
Bug fixes for 3.0
------------------
@@ -239,23 +277,20 @@ Bug fixes for 3.0
- Fixed a bug (#129) - ODBC's num_rows() returned -1 in some cases, due to not all subdrivers supporting the odbc_num_rows() function.
- Fixed a bug (#153) - E_NOTICE being generated by getimagesize() in the :doc:`File Uploading Library <libraries/file_uploading>`.
- Fixed a bug (#611) - SQLSRV's error handling methods used to issue warnings when there's no actual error.
-- Fixed a bug (#1036) - is_write_type() method in the :doc:`Database Library <database/index>` didn't return TRUE for RENAME queries.
+- Fixed a bug (#1036) - ``is_write_type()`` method in the :doc:`Database Library <database/index>` didn't return TRUE for RENAME queries.
- Fixed a bug in PDO's _version() method where it used to return the client version as opposed to the server one.
- Fixed a bug in PDO's insert_id() method where it could've failed if it's used with Postgre versions prior to 8.1.
- Fixed a bug in CUBRID's affected_rows() method where a connection resource was passed to cubrid_affected_rows() instead of a result.
- Fixed a bug (#638) - db_set_charset() ignored its arguments and always used the configured charset instead.
- Fixed a bug (#413) - Oracle's error handling methods used to only return connection-related errors.
-- Fixed a bug (#804) - Profiler library was trying to handle objects as strings in some cases, resulting in warnings being issued by htmlspecialchars().
- Fixed a bug (#1101) - MySQL/MySQLi result method field_data() was implemented as if it was handling a DESCRIBE result instead of the actual result set.
- Fixed a bug in Oracle's :doc:`Database Forge Class <database/forge>` method _create_table() where it failed with AUTO_INCREMENT as it's not supported.
- Fixed a bug (#1080) - When using the SMTP protocol, the :doc:`Email Library <libraries/email>` send() method was returning TRUE even if the connection/authentication against the server failed.
-- Fixed a bug (#499) - a CSRF cookie was created even with CSRF protection being disabled.
- Fixed a bug (#306) - ODBC's insert_id() method was calling non-existent function odbc_insert_id(), which resulted in a fatal error.
- Fixed a bug in Oracle's DB_result class where the cursor id passed to it was always NULL.
- Fixed a bug (#64) - Regular expression in DB_query_builder.php failed to handle queries containing SQL bracket delimiters in the join condition.
- Fixed a bug in the :doc:`Session Library <libraries/sessions>` where a PHP E_NOTICE error was triggered by _unserialize() due to results from databases such as MSSQL and Oracle being space-padded on the right.
- Fixed a bug (#501) - set_rules() to check if the request method is not 'POST' before aborting, instead of depending on count($_POST) in the :doc:`Form Validation Library <libraries/form_validation>`.
-- Fixed a bug (#940) - csrf_verify() used to set the CSRF cookie while processing a POST request with no actual POST data, which resulted in validating a request that should be considered invalid.
- Fixed a bug (#136) - PostgreSQL, MySQL and MySQLi's escape_str() method didn't properly escape LIKE wild characters.
- Fixed a bug in the library loader where some PHP versions wouldn't execute the class constructor.
- Fixed a bug (#88) - An unexisting property was used for configuration of the Memcache cache driver.
@@ -274,7 +309,6 @@ Bug fixes for 3.0
- Fixed a bug (#1265) - Database connections were always closed, regardless of the 'pconnect' option value.
- Fixed a bug (#128) - :doc:`Language Library <libraries/language>` did not correctly keep track of loaded language files.
- Fixed a bug (#1242) - Added Windows path compatibility to function read_dir of ZIP library.
-- Fixed a bug (#1314) - sess_destroy() did not destroy userdata.
- Fixed a bug (#1349) - get_extension() in the :doc:`File Uploading Library <libraries/file_uploading>` returned the original filename when it didn't have an actual extension.
- Fixed a bug (#1273) - E_NOTICE being generated by :doc:`Query Builder <database/query_builder>`'s set_update_batch() method.
- Fixed a bug (#44, #110) - :doc:`Upload library <libraries/file_uploading>`'s clean_file_name() method didn't clear '!' and '#' characters.
@@ -288,14 +322,13 @@ Bug fixes for 3.0
- Fixed a bug (#666) - :doc:`Output library <libraries/output>`'s set_content_type() method didn't set the document charset.
- Fixed a bug (#784, #861) - :doc:`Database Forge <database/forge>` method ``create_table()`` used to accept constraints for MSSQL/SQLSRV integer-type columns.
- Fixed a bug (#706) - SQLSRV/MSSSQL didn't escape field names.
-- Fixed a bug (#1452) - protect_identifiers() didn't properly detect identifiers with spaces in their names.
-- Fixed a bug where protect_identifiers() ignored it's extra arguments when the value passed to it is an array.
-- Fixed a bug where _has_operator() didn't detect BETWEEN.
-- Fixed a bug in :doc:`Query Builder <database/query_builder>`'s join() method where it failed with identifiers containing dashes.
+- Fixed a bug (#1452) - ``protect_identifiers()`` didn't properly detect identifiers with spaces in their names.
+- Fixed a bug where ``protect_identifiers()`` ignored it's extra arguments when the value passed to it is an array.
+- Fixed a bug where ``_has_operator()`` didn't detect BETWEEN.
+- Fixed a bug in :doc:`Query Builder <database/query_builder>`'s ``join()`` method where it failed with identifiers containing dashes.
- Fixed a bug (#1264) - :doc:`Database Forge <database/forge>` and :doc:`Database Utilities <database/utilities>` didn't update/reset the databases and tables list cache when a table or a database is created, dropped or renamed.
-- Fixed a bug (#7) - :doc:`Query Builder <database/query_builder>`'s join() method only escaped one set of conditions.
+- Fixed a bug (#7) - :doc:`Query Builder <database/query_builder>`'s ``join()`` method only escaped one set of conditions.
- Fixed a bug (#1321) - Core Exceptions class couldn't find the errors/ folder in some cases.
-- Fixed a bug in the File-based :doc:`Cache Library <libraries/caching>` driver's get_metadata() method where a non-existent array key was accessed for the TTL value.
- Fixed a bug (#1202) - :doc:`Encryption Library <libraries/encryption>` encode_from_legacy() didn't set back the encrypt mode on failure.
- Fixed a bug (#145) - compile_binds() failed when the bind marker was present in a literal string within the query.
- Fixed a bug in protect_identifiers() where if passed along with the field names, operators got escaped as well.
@@ -316,6 +349,38 @@ Bug fixes for 3.0
- Fixed a bug (#135) - PHP Error logging was impossible without the errors being displayed.
- Fixed a bug (#1613) - :doc:`Form Helper <helpers/form_helper>` functions ``form_multiselect()``, ``form_dropdown()`` didn't properly handle empty array option groups.
- Fixed a bug (#1605) - :doc:`Pagination Library <libraries/pagination>` produced incorrect *previous* and *next* link values.
+- Fixed a bug in SQLSRV's ``affected_rows()`` method where an erroneous function name was used.
+- Fixed a bug (#1000) - Change syntax of ``$view_file`` to ``$_ci_view_file`` to prevent being overwritten by application.
+- Fixed a bug (#1757) - :doc:`Directory Helper <helpers/directory_helper>` function ``directory_map()`` was skipping files and directories named *0*.
+- Fixed a bug (#1789) - :doc:`Database Library <database/index>` method ``escape_str()`` escaped quote characters in LIKE conditions twice under MySQL.
+- Fixed a bug (#395) - :doc:`Unit Testing Library <libraries/unit_testing>` method ``result()`` didn't properly check array result columns when called from ``report()``.
+- Fixed a bug (#1692) - :doc:`Database Library <database/index>` method ``display_error()`` didn't properly trace the possible error source on Windows systems.
+- Fixed a bug (#1745) - ``is_write_type()`` method in the :doc:`Database Library <database/index>` didn't return TRUE for LOAD queries.
+- Fixed a bug (#1765) - :doc:`Database Library <database/index>` didn't properly detect connection errors for MySQLi.
+- Fixed a bug (#1257) - :doc:`Query Builder <database/query_builder>` used to (unnecessarily) group FROM clause contents, which breaks certain queries and is invalid for some databases.
+- Fixed a bug (#1709) - :doc:`Email <libraries/email>` headers were broken when using long email subjects and \r\n as CRLF.
+- Fixed a bug where MB_ENABLED was only declared if UTF8_ENABLED was set to TRUE.
+
+Version 2.1.3
+=============
+
+Release Date: October 8, 2012
+
+- Core
+ - :doc:`Common function <general/common_functions>` ``is_loaded()`` now returns a reference.
+
+Bug fixes for 2.1.3
+-------------------
+
+- Fixed a bug (#1543) - File-based :doc:`Caching <libraries/caching>` method ``get_metadata()`` used a non-existent array key to look for the TTL value.
+- Fixed a bug (#1314) - :doc:`Session Library <libraries/session>` method ``sess_destroy()`` didn't destroy the userdata array.
+- Fixed a bug (#804) - Profiler library was trying to handle objects as strings in some cases, resulting in *E_WARNING* messages being issued by ``htmlspecialchars()``.
+- Fixed a bug (#1699) - :doc:`Migration Library <libraries/migration>` ignored the ``$config['migration_path']`` setting.
+- Fixed a bug (#227) - :doc:`Input Library <libraries/input>` allowed unconditional spoofing of HTTP clients' IP addresses through the *HTTP_CLIENT_IP* header.
+- Fixed a bug (#907) - :doc:`Input Library <libraries/input>` ignored *HTTP_X_CLUSTER_CLIENT_IP* and *HTTP_X_CLIENT_IP* headers when checking for proxies.
+- Fixed a bug (#940) - ``csrf_verify()`` used to set the CSRF cookie while processing a POST request with no actual POST data, which resulted in validating a request that should be considered invalid.
+- Fixed a bug (#499) - :doc:`Security Library <libraries/security>` where a CSRF cookie was created even if ``$config['csrf_protection']`` is set tot FALSE.
+- Fixed a bug (#1715) - :doc:`Input Library <libraries/input>` triggered ``csrf_verify()`` on CLI requests.
Version 2.1.2
=============
diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py
index e972a388b..f68405b36 100644
--- a/user_guide_src/source/conf.py
+++ b/user_guide_src/source/conf.py
@@ -167,6 +167,7 @@ html_last_updated_fmt = '%b %d, %Y'
# Output file base name for HTML help builder.
htmlhelp_basename = 'CodeIgniterdoc'
+html_copy_source = False
# -- Options for LaTeX output --------------------------------------------------
diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst
index c17de600a..636b5b5b2 100644
--- a/user_guide_src/source/database/configuration.rst
+++ b/user_guide_src/source/database/configuration.rst
@@ -28,6 +28,7 @@ prototype::
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'autoinit' => TRUE,
+ 'compress' => TRUE,
'stricton' => FALSE,
'failover' => array()
);
@@ -69,6 +70,7 @@ These failovers can be specified by setting the failover for a connection like t
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'autoinit' => TRUE,
+ 'compress' => TRUE,
'stricton' => FALSE
),
array(
@@ -86,6 +88,7 @@ These failovers can be specified by setting the failover for a connection like t
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'autoinit' => TRUE,
+ 'compress' => TRUE,
'stricton' => FALSE
)
);
@@ -115,6 +118,7 @@ example, to set up a "test" environment you would do this::
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'autoinit' => TRUE,
+ 'compress' => TRUE,
'stricton' => FALSE,
'failover' => array()
);
@@ -174,11 +178,12 @@ Explanation of Values:
customizable by the end user.
**autoinit** Whether or not to automatically connect to the database when the library loads. If set to false,
the connection will take place prior to executing the first query.
+**compress** Whether or not to use client compression for MySQL or MySQLi.
**stricton** TRUE/FALSE (boolean) - Whether to force "Strict Mode" connections, good for ensuring strict SQL
while developing an application.
**port** The database port number. To use this value you have to add a line to the database config array.
::
-
+
$db['default']['port'] = 5432;
====================== ==================================================================================================
diff --git a/user_guide_src/source/general/autoloader.rst b/user_guide_src/source/general/autoloader.rst
index 259a4987e..8ecc13cb6 100644
--- a/user_guide_src/source/general/autoloader.rst
+++ b/user_guide_src/source/general/autoloader.rst
@@ -9,7 +9,7 @@ application you should consider auto-loading them for convenience.
The following items can be loaded automatically:
-- Core classes found in the "libraries" folder
+- Classes found in the "libraries" folder
- Helper files found in the "helpers" folder
- Custom config files found in the "config" folder
- Language files found in the "system/language" folder
diff --git a/user_guide_src/source/general/cli.rst b/user_guide_src/source/general/cli.rst
index 7dc1ca319..649d5d548 100644
--- a/user_guide_src/source/general/cli.rst
+++ b/user_guide_src/source/general/cli.rst
@@ -52,7 +52,7 @@ Now normally you would visit the your site using a URL similar to this::
example.com/index.php/tools/message/to
-Instead, we are going to open Terminal in Mac/Lunix or go to Run > "cmd"
+Instead, we are going to open Terminal in Mac/Linux or go to Run > "cmd"
in Windows and navigate to our CodeIgniter project.
.. code-block:: bash
diff --git a/user_guide_src/source/general/reserved_names.rst b/user_guide_src/source/general/reserved_names.rst
index 5ce7fc2ff..3354375c5 100644
--- a/user_guide_src/source/general/reserved_names.rst
+++ b/user_guide_src/source/general/reserved_names.rst
@@ -45,11 +45,11 @@ Constants
---------
- ENVIRONMENT
-- EXT
- FCPATH
- SELF
- BASEPATH
- APPPATH
+- VIEWPATH
- CI_VERSION
- FILE_READ_MODE
- FILE_WRITE_MODE
diff --git a/user_guide_src/source/helpers/captcha_helper.rst b/user_guide_src/source/helpers/captcha_helper.rst
index 48095a11d..90244739b 100644
--- a/user_guide_src/source/helpers/captcha_helper.rst
+++ b/user_guide_src/source/helpers/captcha_helper.rst
@@ -102,7 +102,7 @@ Here is a table prototype
CREATE TABLE captcha (  
captcha_id bigint(13) unsigned NOT NULL auto_increment,  
captcha_time int(10) unsigned NOT NULL,  
- ip_address varchar(16) default '0' NOT NULL,  
+ ip_address varchar(45) NOT NULL,  
word varchar(20) NOT NULL,  
PRIMARY KEY `captcha_id` (`captcha_id`),  
KEY `word` (`word`)
diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst
index e332a913f..9de925ba7 100644
--- a/user_guide_src/source/helpers/date_helper.rst
+++ b/user_guide_src/source/helpers/date_helper.rst
@@ -306,6 +306,30 @@ Example
If the second parameter is empty, the current year will be used.
+date_range()
+============
+
+Returns a list of dates within a specified period.
+
+.. php:method:: date_range($unix_start = '', $mixed = '', $is_unix = TRUE, $format = 'Y-m-d')
+
+ :param integer $unix_start: UNIX timestamp of the range start date
+ :param integer $mixed: UNIX timestamp of the range end date or interval in days
+ :param boolean $is_unix: set to FALSE if $mixed is not a timestamp
+ :param string $format: output date format, same as in date()
+ :returns: array
+
+Example
+
+::
+
+ $range = date_range('2012-01-01', '2012-01-15');
+ echo "First 15 days of 2012:";
+ foreach ($range as $date)
+ {
+ echo $date."\n";
+ }
+
timezones()
===========
diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst
index 82db6a5b3..1987dfb72 100644
--- a/user_guide_src/source/helpers/url_helper.rst
+++ b/user_guide_src/source/helpers/url_helper.rst
@@ -207,7 +207,12 @@ Creates a standard HTML email link. Usage example
echo mailto('me@my-site.com', 'Click Here to Contact Me');
As with the anchor() tab above, you can set attributes using the third
-parameter.
+parameter:
+
+::
+
+ $attributes = array('title' => 'Mail me');
+ echo mailto('me@my-site.com', 'Contact Me', $attributes);
safe_mailto()
=============
@@ -298,7 +303,7 @@ link. The function will build the URL based on your config file values.
The optional second parameter allows you to force a particular redirection
method. The available methods are "location" or "refresh", with location
-being faster but less reliable on Windows servers. The default is "auto",
+being faster but less reliable on IIS servers. The default is "auto",
which will attempt to intelligently choose the method based on the server
environment.
@@ -320,3 +325,7 @@ engine purposes. The default Response Code is 302. The third parameter is
.. note:: For very fine grained control over headers, you should use the
`Output Library </libraries/output>` set_header() function.
+
+.. note:: To IIS users: if you hide the `Server` HTTP header, the "auto"
+ method won't detect IIS, in that case it is advised you explicitly
+ use the "refresh" method.
diff --git a/user_guide_src/source/images/codeigniter_1.7.1_library_reference.png b/user_guide_src/source/images/codeigniter_1.7.1_library_reference.png
index 554ae2eed..7f054f95f 100644
--- a/user_guide_src/source/images/codeigniter_1.7.1_library_reference.png
+++ b/user_guide_src/source/images/codeigniter_1.7.1_library_reference.png
Binary files differ
diff --git a/user_guide_src/source/index.rst b/user_guide_src/source/index.rst
index e42425bab..35089703f 100644
--- a/user_guide_src/source/index.rst
+++ b/user_guide_src/source/index.rst
@@ -80,6 +80,7 @@ Driver Reference
- :doc:`libraries/caching`
- :doc:`database/index`
- :doc:`libraries/javascript`
+- :doc:`libraries/sessions`
****************
Helper Reference
@@ -119,4 +120,4 @@ Contributing to CodeIgniter
documentation/index
tutorial/index
general/quick_reference
- general/credits \ No newline at end of file
+ general/credits
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index f304a716f..31a5c0761 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -31,8 +31,24 @@ Step 3: Remove $autoload['core'] from your config/autoload.php
Use of the ``$autoload['core']`` config array has been deprecated as of CodeIgniter 1.4.1 and is now removed.
Move any entries that you might have listed there to ``$autoload['libraries']`` instead.
+**************************************************************
+Step 4: Add new session driver items to your config/config.php
+**************************************************************
+
+With the change from a single Session Library to the new Session Driver, two new config items have been added:
+
+ - ``$config['sess_driver']`` selects which driver to initially load. Options are:
+ - 'cookie' (the default) for classic CodeIgniter cookie-based sessions
+ - 'native' for native PHP Session support
+ - the name of a custom driver you have provided (see :doc:`Session Driver <../libraries/sessions>` for more info)
+ - ``$config['sess_valid_drivers']`` provides an array of additional custom drivers to make available for loading
+
+As the new Session Driver library loads the classic Cookie driver by default and always makes 'cookie' and 'native'
+available as valid drivers, neither of these configuration items are required. However, it is recommended that you
+add them for clarity and ease of configuration in the future.
+
***************************************
-Step 4: Update your config/database.php
+Step 5: Update your config/database.php
***************************************
Due to 3.0.0's renaming of Active Record to Query Builder, inside your `config/database.php`, you will
@@ -43,20 +59,20 @@ need to rename the `$active_record` variable to `$query_builder`.
$query_builder = TRUE;
*******************************
-Step 5: Move your errors folder
+Step 6: Move your errors folder
*******************************
In version 3.0.0, the errors folder has been moved from _application/errors* to _application/views/errors*.
****************************************************************************
-Step 6: Check the calls to Array Helper's element() and elements() functions
+Step 7: Check the calls to Array Helper's element() and elements() functions
****************************************************************************
The default return value of these functions, when the required elements
don't exist, has been changed from FALSE to NULL.
***************************************************************
-Step 7: Remove usage of (previously) deprecated functionalities
+Step 8: Remove usage of (previously) deprecated functionalities
***************************************************************
In addition to the ``$autoload['core']`` configuration setting, there's a number of other functionalities
@@ -138,4 +154,17 @@ As a result of that, the 'anchor_class' setting is now deprecated and scheduled
CodeIgniter 3.1+.
.. note:: This setting is still available, but you're strongly encouraged to remove its' usage sooner
- rather than later. \ No newline at end of file
+ rather than later.
+
+Email library
+=============
+
+The :doc:`Email library <../libraries/email>` will automatically clear the set parameters after successfully sending
+emails. To override this behaviour, pass FALSE as the first parameter in the ``send()`` function:
+
+::
+
+ if ($this->email->send(FALSE))
+ {
+ // Parameters won't be cleared
+ }
diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst
index c5fa68004..da3bf2616 100644
--- a/user_guide_src/source/libraries/email.rst
+++ b/user_guide_src/source/libraries/email.rst
@@ -97,7 +97,7 @@ Preference Default Value Options Descript
**mailtype** text text or html Type of mail. If you send HTML email you must send it as a complete web
page. Make sure you don't have any relative links or relative image
paths otherwise they will not work.
-**charset** utf-8 Character set (utf-8, iso-8859-1, etc.).
+**charset** ``$config['charset']`` Character set (utf-8, iso-8859-1, etc.).
**validate** FALSE TRUE or FALSE (boolean) Whether to validate the email address.
**priority** 3 1, 2, 3, 4, 5 Email Priority. 1 = highest. 5 = lowest. 3 = normal.
**crlf** \\n "\\r\\n" or "\\n" or "\\r" Newline character. (Use "\\r\\n" to comply with RFC 822).
@@ -117,6 +117,13 @@ Sets the email address and name of the person sending the email::
$this->email->from('you@example.com', 'Your Name');
+You can also set a Return-Path, to help redirect undelivered mail::
+
+ $this->email->from('you@example.com', 'Your Name', 'returned_emails@example.com');
+
+.. note:: Return-Path can't be used if you've configured
+ 'smtp' as your protocol.
+
$this->email->reply_to()
-------------------------
@@ -226,6 +233,14 @@ success or failure, enabling it to be used conditionally::
// Generate error
}
+This function will automatically clear all parameters if the request was
+successful. To stop this behaviour pass FALSE::
+
+ if ($this->email->send(FALSE))
+ {
+ // Parameters won't be cleared
+ }
+
$this->email->attach()
----------------------
diff --git a/user_guide_src/source/libraries/file_uploading.rst b/user_guide_src/source/libraries/file_uploading.rst
index 65cd5c722..1698dcbb9 100644
--- a/user_guide_src/source/libraries/file_uploading.rst
+++ b/user_guide_src/source/libraries/file_uploading.rst
@@ -197,6 +197,7 @@ Preference Default Value Options Descripti
Separate multiple types with a pipe.
**file_name** None Desired file name If set CodeIgniter will rename the uploaded file to this name. The
extension provided in the file name must also be an allowed file type.
+ If no extension is provided in the original file_name will be used.
**overwrite** FALSE TRUE/FALSE (boolean) If set to true, if a file with the same name as the one you are
uploading exists, it will be overwritten. If set to false, a number will
be appended to the filename if another with the same name exists.
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index 3bcad7ba6..6c6743d06 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -399,7 +399,7 @@ The validation system supports callbacks to your own validation
functions. This permits you to extend the validation class to meet your
needs. For example, if you need to run a database query to see if the
user is choosing a unique username, you can create a callback function
-that does that. Let's create a example of this.
+that does that. Let's create an example of this.
In your controller, change the "username" rule to this::
@@ -488,6 +488,17 @@ the name of the function::
$this->form_validation->set_message('username_check')
+If you are using an error message that can accept two $s in your error string,
+such as:
+::
+
+ $this->form_validation->set_message('min_length', 'The $s field must contain at least $s characters.');
+
+Then you can also use %1$s and %2$s:
+::
+
+ $this->form_validation->set_message('min_length', 'This field must contain at least %2$s characters.');
+
You can also override any error message found in the language file. For
example, to change the message for the "required" rule you will do this::
@@ -861,8 +872,10 @@ Rule Parameter Description
========================= ========== ============================================================================================= =======================
**required** No Returns FALSE if the form element is empty.
**matches** Yes Returns FALSE if the form element does not match the one in the parameter. matches[form_item]
-**is_unique** Yes Returns FALSE if the form element is not unique to the is_unique[table.field]
- table and field name in the parameter. is_unique[table.field]
+**differs** Yes Returns FALSE if the form element does not differ from the one in the parameter. differs[form_item]
+**is_unique** Yes Returns FALSE if the form element is not unique to the table and field name in the is_unique[table.field]
+ parameter. Note: This rule requires :doc:`Query Builder <../database/query_builder>` to be
+ enabled in order to work.
**max_length** Yes Returns FALSE if the form element is longer then the parameter value. max_length[12]
**exact_length** Yes Returns FALSE if the form element is not exactly the parameter value. exact_length[8]
**greater_than** Yes Returns FALSE if the form element is less than or equal to the parameter value or not greater_than[8]
@@ -884,7 +897,6 @@ Rule Parameter Description
0, 1, 2, 3, etc.
**is_natural_no_zero** No Returns FALSE if the form element contains anything other than a natural
number, but not zero: 1, 2, 3, etc.
-**is_unique** Yes Returns FALSE if the form element is not unique in a database table. is_unique[table.field]
**valid_email** No Returns FALSE if the form element does not contain a valid email address.
**valid_emails** No Returns FALSE if any value provided in a comma separated list is not a valid email.
**valid_ip** No Returns FALSE if the supplied IP is not valid.
diff --git a/user_guide_src/source/libraries/image_lib.rst b/user_guide_src/source/libraries/image_lib.rst
index ed6575c62..dcdccbd92 100644
--- a/user_guide_src/source/libraries/image_lib.rst
+++ b/user_guide_src/source/libraries/image_lib.rst
@@ -91,9 +91,9 @@ error upon failure, like this::
echo $this->image_lib->display_errors();
}
-Note: You can optionally specify the HTML formatting to be applied to
-the errors, by submitting the opening/closing tags in the function, like
-this::
+.. note:: You can optionally specify the HTML formatting to be applied to
+ the errors, by submitting the opening/closing tags in the function,
+ like this::
$this->image_lib->display_errors('<p>', '</p>');
@@ -225,8 +225,7 @@ pixels) specifying where to crop, like this::
$config['y_axis'] = '40';
All preferences listed in the table above are available for this
-function except these: rotation_angle, width, height, create_thumb,
-new_image.
+function except these: rotation_angle, create_thumb, new_image.
Here's an example showing how you might crop an image::
@@ -243,11 +242,11 @@ Here's an example showing how you might crop an image::
echo $this->image_lib->display_errors();
}
-Note: Without a visual interface it is difficult to crop images, so this
-function is not very useful unless you intend to build such an
-interface. That's exactly what we did using for the photo gallery module
-in ExpressionEngine, the CMS we develop. We added a JavaScript UI that
-lets the cropping area be selected.
+.. note:: Without a visual interface it is difficult to crop images, so this
+ function is not very useful unless you intend to build such an
+ interface. That's exactly what we did using for the photo gallery module
+ in ExpressionEngine, the CMS we develop. We added a JavaScript UI that
+ lets the cropping area be selected.
$this->image_lib->rotate()
===========================
@@ -338,8 +337,8 @@ The above example will use a 16 pixel True Type font to create the text
bottom/center of the image, 20 pixels from the bottom of the image.
.. note:: In order for the image class to be allowed to do any
- processing, the image file must have "write" file permissions. For
- example, 777.
+ processing, the image file must have "write" file permissions
+ For example, 777.
Watermarking Preferences
========================
diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst
index aadf9740a..615aba1c2 100644
--- a/user_guide_src/source/libraries/loader.rst
+++ b/user_guide_src/source/libraries/loader.rst
@@ -4,6 +4,7 @@ Loader Class
Loader, as the name suggests, is used to load elements. These elements
can be libraries (classes) :doc:`View files <../general/views>`,
+:doc:`Drivers <../general/drivers>`,
:doc:`Helpers <../general/helpers>`,
:doc:`Models <../general/models>`, or your own files.
@@ -74,6 +75,70 @@ Assigning a Library to a different object name
If the third (optional) parameter is blank, the library will usually be
assigned to an object with the same name as the library. For example, if
+the library is named Calendar, it will be assigned to a variable named
+$this->calendar.
+
+If you prefer to set your own class names you can pass its value to the
+third parameter::
+
+ $this->load->library('calendar', '', 'my_calendar');
+
+ // Calendar class is now accessed using:
+
+ $this->my_calendar
+
+Please take note, when multiple libraries are supplied in an array for
+the first parameter, this parameter is discarded.
+
+$this->load->driver('parent_name', $config, 'object name')
+===========================================================
+
+This function is used to load driver libraries. Where parent_name is the
+name of the parent class you want to load.
+
+As an example, if you would like to use sessions with CodeIgniter, the first
+step is to load the session driver within your controller::
+
+ $this->load->driver('session');
+
+Once loaded, the library will be ready for use, using
+$this->session->*some_function*().
+
+Driver files must be stored in a subdirectory within the main
+"libraries" folder, or within your personal application/libraries
+folder. The subdirectory must match the parent class name. Read the
+:doc:`Drivers <../general/drivers>` description for details.
+
+Additionally, multiple driver libraries can be loaded at the same time by
+passing an array of drivers to the load function.
+
+::
+
+ $this->load->driver(array('session', 'cache'));
+
+Setting options
+---------------
+
+The second (optional) parameter allows you to optionally pass
+configuration settings. You will typically pass these as an array::
+
+ $config = array (
+ 'sess_driver' => 'cookie',
+ 'sess_encrypt_cookie' => true,
+ 'encryption_key' => 'mysecretkey'
+ );
+
+ $this->load->driver('session', $config);
+
+Config options can usually also be set via a config file. Each library
+is explained in detail in its own page, so please read the information
+regarding each one you would like to use.
+
+Assigning a Driver to a different object name
+----------------------------------------------
+
+If the third (optional) parameter is blank, the library will be assigned
+to an object with the same name as the parent class. For example, if
the library is named Session, it will be assigned to a variable named
$this->session.
@@ -86,8 +151,8 @@ third parameter::
$this->my_session
-Please take note, when multiple libraries are supplied in an array for
-the first parameter, this parameter is discarded.
+.. note:: Driver libraries may also be loaded with the library() method,
+ but it is faster to use driver()
$this->load->view('file_name', $data, true/false)
==================================================
@@ -279,6 +344,6 @@ calling add_package_path().
$this->load->remove_package_path(APPPATH.'my_app');
// Again without the second parameter:
- $this->load->add_package_path(APPPATH.'my_app', TRUE);
+ $this->load->add_package_path(APPPATH.'my_app');
$this->load->view('my_app_index'); // Loads
- $this->load->view('welcome_message'); // Loads \ No newline at end of file
+ $this->load->view('welcome_message'); // Loads
diff --git a/user_guide_src/source/libraries/migration.rst b/user_guide_src/source/libraries/migration.rst
index 5192f1f29..cb7d96a6d 100644
--- a/user_guide_src/source/libraries/migration.rst
+++ b/user_guide_src/source/libraries/migration.rst
@@ -2,4 +2,136 @@
Migrations Class
################
-Coming soon. \ No newline at end of file
+Migrations are a convenient way for you to alter your database in a
+structured and organized manner. You could edit fragments of SQL by hand
+but you would then be responsible for telling other developers that they
+need to go and run them. You would also have to keep track of which changes
+need to be run against the production machines next time you deploy.
+
+The database table **migration** tracks which migrations have already been
+run so all you have to do is update your application files and
+call **$this->migrate->current()** to work out which migrations should be run.
+The current version is found in **config/migration.php**.
+
+******************
+Create a Migration
+******************
+
+.. note:: Each Migration is run in numerical order forward or backwards
+ depending on the method taken. Use a prefix of 3 numbers followed by an
+ underscore for the filename of your migration.
+
+This will be the first migration for a new site which has a blog. All
+migrations go in the folder **application/migrations/** and have names such
+as: **001_add_blog.php**.::
+
+ defined('BASEPATH') OR exit('No direct script access allowed');
+
+ class Migration_Add_blog extends CI_Migration {
+
+ public function up()
+ {
+ $this->dbforge->add_field(array(
+ 'blog_id' => array(
+ 'type' => 'INT',
+ 'constraint' => 5,
+ 'unsigned' => TRUE,
+ 'auto_increment' => TRUE
+ ),
+ 'blog_title' => array(
+ 'type' => 'VARCHAR',
+ 'constraint' => '100',
+ ),
+ 'blog_description' => array(
+ 'type' => 'TEXT',
+ 'null' => TRUE,
+ ),
+ ));
+
+ $this->dbforge->create_table('blog');
+ }
+
+ public function down()
+ {
+ $this->dbforge->drop_table('blog');
+ }
+
+Then in **application/config/migration.php** set **$config['migration_version'] = 1;**.
+
+*************
+Usage Example
+*************
+
+In this example some simple code is placed in **application/controllers/migrate.php**
+to update the schema.::
+
+ $this->load->library('migration');
+
+ if ( ! $this->migration->current())
+ {
+ show_error($this->migration->error_string());
+ }
+
+******************
+Function Reference
+******************
+
+There are five available methods for the Migration class:
+
+- $this->migration->current();
+- $this->migration->error_string();
+- $this->migration->find_migrations();
+- $this->migration->latest();
+- $this->migration->version();
+
+$this->migration->current()
+============================
+
+The current migration is whatever is set for **$config['migration_version']** in
+**application/config/migration.php**.
+
+$this->migration->error_string()
+=================================
+
+This returns a string of errors while performing a migration.
+
+$this->migration->find_migrations()
+====================================
+
+An array of migration filenames are returned that are found in the **migration_path**
+property.
+
+$this->migration->latest()
+===========================
+
+This works much the same way as current() but instead of looking for
+the **$config['migration_version']** the Migration class will use the very
+newest migration found in the filesystem.
+
+$this->migration->version()
+============================
+
+Version can be used to roll back changes or step forwards programmatically to
+specific versions. It works just like current but ignores **$config['migration_version']**.::
+
+ $this->load->library('migration');
+
+ $this->migration->version(5);
+
+*********************
+Migration Preferences
+*********************
+
+The following is a table of all the config options for migrations.
+
+========================== ====================== ============= =============================================
+Preference Default Options Description
+========================== ====================== ============= =============================================
+**migration_enabled** FALSE TRUE / FALSE Enable or disable migrations.
+**migration_path** APPPATH.'migrations/' None The path to your migrations folder.
+**migration_version** 0 None The current version your database should use.
+**migration_table** migrations None The table name for storing the shema
+ version number.
+**migration_auto_latest** FALSE TRUE / FALSE Enable or disable automatically
+ running migrations.
+========================== ====================== ============= =============================================
diff --git a/user_guide_src/source/libraries/output.rst b/user_guide_src/source/libraries/output.rst
index 0472d14cf..3289a241f 100644
--- a/user_guide_src/source/libraries/output.rst
+++ b/user_guide_src/source/libraries/output.rst
@@ -105,6 +105,9 @@ Permits you to manually set a server status header. Example::
`See here <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_ for
a full list of headers.
+.. note:: This method is an alias for :doc:`Common function <../general/common_funtions.rst>`
+ ``set_status_header()``.
+
$this->output->enable_profiler();
==================================
diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst
index 7d750bd23..d9d3f5092 100644
--- a/user_guide_src/source/libraries/pagination.rst
+++ b/user_guide_src/source/libraries/pagination.rst
@@ -80,8 +80,8 @@ The number of "digit" links you would like before and after the selected
page number. For example, the number 2 will place two digits on either
side, as in the example links at the very top of this page.
-$config['use_page_number'] = TRUE;
-==================================
+$config['use_page_numbers'] = TRUE;
+===================================
By default, the URI segment will use the starting index for the items
you are paginating. If you prefer to show the the actual page number,
diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst
index 5400524a9..dd9e8cbb4 100644
--- a/user_guide_src/source/libraries/sessions.rst
+++ b/user_guide_src/source/libraries/sessions.rst
@@ -1,29 +1,19 @@
-#############
-Session Class
-#############
+##############
+Session Driver
+##############
The Session class permits you maintain a user's "state" and track their
-activity while they browse your site. The Session class stores session
-information for each user as serialized (and optionally encrypted) data
-in a cookie. It can also store the session data in a database table for
-added security, as this permits the session ID in the user's cookie to
-be matched against the stored session ID. By default only the cookie is
-saved. If you choose to use the database option you'll need to create
-the session table as indicated below.
-
-.. note:: The Session class does **not** utilize native PHP sessions. It
- generates its own session data, offering more flexibility for
- developers.
-
-.. note:: Even if you are not using encrypted sessions, you must set
- an :doc:`encryption key <./encryption>` in your config file which is used
- to aid in preventing session data manipulation.
+activity while they browse your site. CodeIgniter offers two default
+session drivers: the classic `Cookie Driver`_, and the `Native Driver`_,
+which supports usage of the native PHP Session mechanism. In addition,
+you may create your own `Custom Drivers`_ to store session data however
+you wish, while still taking advantage of the features of the Session class.
Initializing a Session
======================
Sessions will typically run globally with each page load, so the session
-class must either be :doc:`initialized <../general/libraries>` in your
+class must either be :doc:`initialized <../general/drivers>` in your
:doc:`controller <../general/controllers>` constructors, or it can be
:doc:`auto-loaded <../general/autoloader>` by the system. For the most
part the session class will run unattended in the background, so simply
@@ -31,22 +21,25 @@ initializing the class will cause it to read, create, and update
sessions.
To initialize the Session class manually in your controller constructor,
-use the $this->load->library function::
+use the $this->load->driver function::
- $this->load->library('session');
+ $this->load->driver('session');
Once loaded, the Sessions library object will be available using:
$this->session
+.. note:: For backward compatibility, the Session class may stil be loaded
+ using the $this->load->library function, but converting your applications
+ to use $this->load->driver is strongly recommended.
+
How do Sessions work?
=====================
When a page is loaded, the session class will check to see if valid
-session data exists in the user's session cookie. If sessions data does
-**not** exist (or if it has expired) a new session will be created and
-saved in the cookie. If a session does exist, its information will be
-updated and the cookie will be updated. With each update, the
-session_id will be regenerated.
+session data exists in the user's session. If sessions data does **not**
+exist (or if it has expired) a new session will be created and saved.
+If a session does exist, its information will be updated. With each update,
+the session_id will be regenerated.
It's important for you to understand that once initialized, the Session
class runs automatically. There is nothing you need to do to cause the
@@ -79,19 +72,12 @@ prototype::
'last_activity' => timestamp
)
-If you have the encryption option enabled, the serialized array will be
-encrypted before being stored in the cookie, making the data highly
-secure and impervious to being read or altered by someone. More info
-regarding encryption can be :doc:`found here <encryption>`, although
-the Session class will take care of initializing and encrypting the data
-automatically.
-
-Note: Session cookies are only updated every five minutes by default to
-reduce processor load. If you repeatedly reload a page you'll notice
-that the "last activity" time only updates if five minutes or more has
-passed since the last time the cookie was written. This time is
-configurable by changing the $config['sess_time_to_update'] line in
-your system/config/config.php file.
+.. note:: Sessions are only updated every five minutes by default to
+ reduce processor load. If you repeatedly reload a page you'll notice
+ that the "last activity" time only updates if five minutes or more has
+ passed since the last time the cookie was written. This time is
+ configurable by changing the $config['sess_time_to_update'] line in
+ your system/config/config.php file.
Retrieving Session Data
=======================
@@ -106,7 +92,7 @@ fetch. For example, to fetch the session ID you will do this::
$session_id = $this->session->userdata('session_id');
-.. note:: The function returns FALSE (boolean) if the item you are
+.. note:: The function returns NULL if the item you are
trying to access does not exist.
Adding Custom Session Data
@@ -117,7 +103,7 @@ to it and it will be stored in the user's cookie. Why would you want to
do this? Here's one example:
Let's say a particular user logs into your site. Once authenticated, you
-could add their username and email address to the session cookie, making
+could add their username and email address to the session, making
that data globally available to you without having to run a database
query when you need it.
@@ -144,11 +130,11 @@ supports this syntax.
$this->session->set_userdata('some_name', 'some_value');
+If you want to verify that a userdata value exists, call has_userdata().
-.. note:: Cookies can only hold 4KB of data, so be careful not to exceed
- the capacity. The encryption process in particular produces a longer
- data string than the original so keep careful track of how much data you
- are storing.
+::
+
+ $this->session->has_userdata('some_name');
Retrieving All Session Data
===========================
@@ -195,8 +181,8 @@ available for the next server request, and are then automatically
cleared. These can be very useful, and are typically used for
informational or status messages (for example: "record 2 deleted").
-Note: Flash variables are prefaced with "flash\_" so avoid this prefix
-in your own session names.
+.. note:: Flash variables are prefaced with "flash\_" so avoid this prefix
+ in your own session names.
To add flashdata::
@@ -222,9 +208,162 @@ additional request, you can do so using the keep_flashdata() function.
$this->session->keep_flashdata('item');
+Tempdata
+========
+
+CodeIgniter also supports "tempdata", or session data with a specific
+expiration time. After the value expires, or the session expires or is
+deleted, the value is automatically removed.
+
+To add tempdata::
+
+ $expire = 300; // Expire in 5 minutes
+
+ $this->session->set_tempdata('item', 'value', $expire);
+
+You can also pass an array to set_tempdata()::
+
+ $tempdata = array('newuser' => TRUE, 'message' => 'Thanks for joining!');
+
+ $this->session->set_tempdata($tempdata, '', $expire);
+
+.. note:: If the expiration is omitted or set to 0, the default expiration of
+ 5 minutes will be used.
+
+To read a tempdata variable::
+
+ $this->session->tempdata('item');
+
+If you need to remove a tempdata value before it expires,
+use unset_tempdata()::
+
+ $this->session->unset_tempdata('item');
+
+Destroying a Session
+====================
+
+To clear the current session::
+
+ $this->session->sess_destroy();
+
+.. note:: This function should be the last one called, and even flash
+ variables will no longer be available. If you only want some items
+ destroyed and not all, use unset_userdata().
+
+Session Preferences
+===================
+
+You'll find the following Session related preferences in your
+application/config/config.php file:
+
+=========================== =============== =========================== ==========================================================================
+Preference Default Options Description
+=========================== =============== =========================== ==========================================================================
+**sess_driver** cookie cookie/native/*custom* The initial session driver to load.
+**sess_valid_drivers** cookie, native None Additional valid drivers which may be loaded.
+**sess_cookie_name** ci_session None The name you want the session cookie saved as (data for Cookie driver or
+ session ID for Native driver).
+**sess_expiration** 7200 None The number of seconds you would like the session to last. The default
+ value is 2 hours (7200 seconds). If you would like a non-expiring
+ session set the value to zero: 0
+**sess_expire_on_close** FALSE TRUE/FALSE (boolean) Whether to cause the session to expire automatically when the browser
+ window is closed.
+**sess_encrypt_cookie** FALSE TRUE/FALSE (boolean) Whether to encrypt the session data (Cookie driver only).
+**sess_use_database** FALSE TRUE/FALSE (boolean) Whether to save the session data to a database. You must create the
+ table before enabling this option (Cookie driver only).
+**sess_table_name** ci_sessions Any valid SQL table name The name of the session database table (Cookie driver only).
+**sess_time_to_update** 300 Time in seconds This options controls how often the session class will regenerate itself
+ and create a new session id.
+**sess_match_ip** FALSE TRUE/FALSE (boolean) Whether to match the user's IP address when reading the session data.
+ Note that some ISPs dynamically changes the IP, so if you want a
+ non-expiring session you will likely set this to FALSE.
+**sess_match_useragent** TRUE TRUE/FALSE (boolean) Whether to match the User Agent when reading the session data.
+=========================== =============== =========================== ==========================================================================
+
+In addition to the values above, the cookie and native drivers apply the
+following configuration values shared by the :doc:`Input <input>` and
+:doc:`Security <security>` classes:
+
+=========================== =============== ==========================================================================
+Preference Default Description
+=========================== =============== ==========================================================================
+**cookie_prefix** '' Set a cookie name prefix in order to avoid name collisions
+**cookie_domain** '' The domain for which the session is applicable
+**cookie_path** / The path to which the session is applicable
+=========================== =============== ==========================================================================
+
+Session Drivers
+===============
+
+By default, the `Cookie Driver`_ is loaded when a session is initialized.
+However, any valid driver may be selected with the $config['sess_driver']
+line in your config.php file.
+
+The session driver library comes with the cookie and native drivers
+installed, and `Custom Drivers`_ may also be installed by the user.
+
+Typically, only one driver will be used at a time, but CodeIgniter does
+support loading multiple drivers. If a specific valid driver is called, it
+will be automatically loaded. Or, an additional driver may be explicitly
+loaded by calling load_driver()::
+
+ $this->session->load_driver('native');
+
+The Session library keeps track of the most recently selected driver to call
+for driver methods. Normally, session class methods are called directly on
+the parent class, as illustrated above. However, any methods called through
+a specific driver will select that driver before invoking the parent method.
+
+So, alternation between multiple drivers can be achieved by specifying which
+driver to use for each call::
+
+ $this->session->native->set_userdata('foo', 'bar');
+
+ $this->session->cookie->userdata('foo');
+
+ $this->session->native->unset_userdata('foo');
+
+Notice in the previous example that the *native* userdata value 'foo'
+would be set to 'bar', which would NOT be returned by the call for
+the *cookie* userdata 'foo', nor would the *cookie* value be unset by
+the call to unset the *native* 'foo' value. The drivers maintain independent
+sets of values, regardless of key names.
+
+A specific driver may also be explicitly selected for use by pursuant
+methods with the select_driver() call::
+
+ $this->session->select_driver('native');
+
+ $this->session->userdata('item'); // Uses the native driver
+
+Cookie Driver
+-------------
+
+The Cookie driver stores session information for each user as serialized
+(and optionally encrypted) data in a cookie. It can also store the session
+data in a database table for added security, as this permits the session ID
+in the user's cookie to be matched against the stored session ID. By default
+only the cookie is saved. If you choose to use the database option you'll
+need to create the session table as indicated below.
+
+If you have the encryption option enabled, the serialized array will be
+encrypted before being stored in the cookie, making the data highly
+secure and impervious to being read or altered by someone. More info
+regarding encryption can be :doc:`found here <encryption>`, although
+the Session class will take care of initializing and encrypting the data
+automatically.
+
+.. note:: Even if you are not using encrypted sessions, you must set
+ an :doc:`encryption key <./encryption>` in your config file which is used
+ to aid in preventing session data manipulation.
+
+.. note:: Cookies can only hold 4KB of data, so be careful not to exceed
+ the capacity. The encryption process in particular produces a longer
+ data string than the original so keep careful track of how much data you
+ are storing.
Saving Session Data to a Database
-=================================
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
While the session data array stored in the user's cookie contains a
Session ID, unless you store session data in a database there is no way
@@ -267,44 +406,83 @@ session class::
$config['sess_table_name'] = 'ci_sessions';
-.. note:: The Session class has built-in garbage collection which clears
+.. note:: The Cookie driver has built-in garbage collection which clears
out expired sessions so you do not need to write your own routine to do
it.
-Destroying a Session
-====================
+Native Driver
+-------------
-To clear the current session::
+The Native driver relies on native PHP sessions to store data in the
+$_SESSION superglobal array. All stored values continue to be available
+through $_SESSION, but flash- and temp- data items carry special prefixes.
- $this->session->sess_destroy();
+Custom Drivers
+--------------
-.. note:: This function should be the last one called, and even flash
- variables will no longer be available. If you only want some items
- destroyed and not all, use unset_userdata().
+You may also :doc:`create your own <../general/creating_drivers>` custom
+session drivers. A session driver basically manages an array of name/value
+pairs with some sort of storage mechanism.
-Session Preferences
-===================
+To make a new driver, extend CI_Session_driver. Overload the initialize()
+method and read or create session data. Then implement a save handler to
+write changed data to storage (sess_save), a destroy handler to remove
+deleted data (sess_destroy), a regenerate handler to make a new session ID
+(sess_regenerate), and an access handler to expose the data (get_userdata).
+Your initial class might look like::
-You'll find the following Session related preferences in your
-application/config/config.php file:
+ class CI_Session_custom extends CI_Session_driver {
+ protected function initialize()
+ {
+ // Read existing session data or create a new one
+ }
+
+ public function sess_save()
+ {
+ // Save current data to storage
+ }
+
+ public function sess_destroy()
+ {
+ // Destroy the current session and clean up storage
+ }
+
+ public function sess_regenerate()
+ {
+ // Create new session ID
+ }
+
+ public function &get_userdata()
+ {
+ // Return a reference to your userdata array
+ }
+ }
+
+Notice that get_userdata() returns a reference so the parent library is
+accessing the same array the driver object is using. This saves memory
+and avoids synchronization issues during usage.
+
+Put your driver in the libraries/Session/drivers folder anywhere in your
+package paths. This includes the application directory, the system directory,
+or any path you add with $CI->load->add_package_path(). Your driver must be
+named CI_Session_<name>, and your filename must be Session_<name>.php,
+preferably also capitalized, such as::
+
+ CI_Session_foo in libraries/Session/drivers/Session_foo.php
+
+Then specify the driver by setting 'sess_driver' in your config.php file or as a
+parameter when loading the CI_Session object::
+
+ $config['sess_driver'] = 'foo';
+
+OR::
+
+ $CI->load->driver('session', array('sess_driver' => 'foo'));
+
+The driver specified by 'sess_driver' is automatically included as a valid
+driver. However, if you want to make a custom driver available as an option
+without making it the initially loaded driver, set 'sess_valid_drivers' in
+your config.php file to an array including your driver name::
+
+ $config['sess_valid_drivers'] = array('sess_driver');
-=========================== =============== =========================== ==========================================================================
-Preference Default Options Description
-=========================== =============== =========================== ==========================================================================
-**sess_cookie_name** ci_session None The name you want the session cookie saved as.
-**sess_expiration** 7200 None The number of seconds you would like the session to last. The default
- value is 2 hours (7200 seconds). If you would like a non-expiring
- session set the value to zero: 0
-**sess_expire_on_close** FALSE TRUE/FALSE (boolean) Whether to cause the session to expire automatically when the browser
- window is closed.
-**sess_encrypt_cookie** FALSE TRUE/FALSE (boolean) Whether to encrypt the session data.
-**sess_use_database** FALSE TRUE/FALSE (boolean) Whether to save the session data to a database. You must create the
- table before enabling this option.
-**sess_table_name** ci_sessions Any valid SQL table name The name of the session database table.
-**sess_time_to_update** 300 Time in seconds This options controls how often the session class will regenerate itself
- and create a new session id.
-**sess_match_ip** FALSE TRUE/FALSE (boolean) Whether to match the user's IP address when reading the session data.
- Note that some ISPs dynamically changes the IP, so if you want a
- non-expiring session you will likely set this to FALSE.
-**sess_match_useragent** TRUE TRUE/FALSE (boolean) Whether to match the User Agent when reading the session data.
-=========================== =============== =========================== ========================================================================== \ No newline at end of file
diff --git a/user_guide_src/source/libraries/trackback.rst b/user_guide_src/source/libraries/trackback.rst
index 07b2b2177..f9e0df882 100644
--- a/user_guide_src/source/libraries/trackback.rst
+++ b/user_guide_src/source/libraries/trackback.rst
@@ -114,7 +114,7 @@ store them. Here is a basic prototype for such a table::
excerpt text NOT NULL,
blog_name varchar(100) NOT NULL,
tb_date int(10) NOT NULL,
- ip_address varchar(16) NOT NULL,
+ ip_address varchar(45) NOT NULL,
PRIMARY KEY `tb_id` (`tb_id`),
KEY `entry_id` (`entry_id`)
);
diff --git a/user_guide_src/source/overview/cheatsheets.rst b/user_guide_src/source/overview/cheatsheets.rst
index 2e277aa9a..80c3112c4 100644
--- a/user_guide_src/source/overview/cheatsheets.rst
+++ b/user_guide_src/source/overview/cheatsheets.rst
@@ -5,12 +5,19 @@ CodeIgniter Cheatsheets
Library Reference
=================
-`|CodeIgniter Library
-Reference| <../images/codeigniter_1.7.1_library_reference.pdf>`_
+|CodeIgniter Library Reference|
+
+- :download:`Download PDF <../images/codeigniter_1.7.1_library_reference.pdf>`
+
Helpers Reference
=================
-`|image1| <../images/codeigniter_1.7.1_helper_reference.pdf>`_
+|CodeIgniter Helper Reference|
+
+- :download:`Download PDF <../images/codeigniter_1.7.1_helper_reference.pdf>`
+
.. |CodeIgniter Library Reference| image:: ../images/codeigniter_1.7.1_library_reference.png
-.. |image1| image:: ../images/codeigniter_1.7.1_helper_reference.png
+ :target: ../_downloads/codeigniter_1.7.1_library_reference.pdf
+.. |CodeIgniter Helper Reference| image:: ../images/codeigniter_1.7.1_helper_reference.png
+ :target: ../_downloads/codeigniter_1.7.1_helper_reference.pdf