summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Andreev <narf@devilix.net>2017-03-24 10:04:53 +0100
committerAndrey Andreev <narf@devilix.net>2017-03-24 10:04:53 +0100
commitc7c0bdf4f7af7c4e71b073ee87ddb792087bdfac (patch)
tree5cfb825e1e0d67f30d4c8a91428cd52eb580695a
parent1d9aaee34ea77fdb68d79d7add37f26dd2649c00 (diff)
parent0eb38af2eaf1127b9b82261b7ec3bf4d4b847318 (diff)
Merge branch '3.1-stable' into develop
Conflicts resolved: system/core/CodeIgniter.php system/core/Common.php system/core/Input.php system/helpers/cookie_helper.php tests/codeigniter/helpers/html_helper_test.php user_guide_src/source/changelog.rst user_guide_src/source/conf.py user_guide_src/source/installation/downloads.rst user_guide_src/source/installation/upgrading.rst user_guide_src/source/libraries/input.rst
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml2
-rw-r--r--composer.json5
-rw-r--r--system/core/Common.php19
-rw-r--r--system/core/Input.php16
-rw-r--r--system/core/Log.php10
-rw-r--r--system/core/Output.php10
-rw-r--r--system/core/Security.php4
-rw-r--r--system/core/compat/hash.php17
-rw-r--r--system/core/compat/password.php8
-rw-r--r--system/database/DB_query_builder.php27
-rw-r--r--system/database/drivers/ibase/ibase_driver.php2
-rw-r--r--system/database/drivers/mssql/mssql_driver.php2
-rw-r--r--system/database/drivers/mysqli/mysqli_driver.php2
-rw-r--r--system/database/drivers/odbc/odbc_driver.php4
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php2
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php2
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php2
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php2
-rw-r--r--system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php2
-rw-r--r--system/database/drivers/postgre/postgre_driver.php4
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_driver.php2
-rw-r--r--system/helpers/cookie_helper.php2
-rw-r--r--system/helpers/html_helper.php2
-rw-r--r--system/helpers/string_helper.php4
-rw-r--r--system/helpers/text_helper.php7
-rw-r--r--system/libraries/Email.php10
-rw-r--r--system/libraries/Encrypt.php59
-rw-r--r--system/libraries/Encryption.php10
-rw-r--r--system/libraries/Session/drivers/Session_database_driver.php10
-rw-r--r--system/libraries/Session/drivers/Session_files_driver.php8
-rw-r--r--system/libraries/Xmlrpc.php36
-rw-r--r--system/libraries/Xmlrpcs.php4
-rw-r--r--system/libraries/Zip.php10
-rw-r--r--tests/codeigniter/helpers/html_helper_test.php14
-rw-r--r--tests/codeigniter/libraries/Encryption_test.php16
-rw-r--r--tests/mocks/ci_testconfig.php8
-rw-r--r--tests/phpunit.xml10
-rw-r--r--user_guide_src/source/changelog.rst35
-rw-r--r--user_guide_src/source/general/routing.rst3
-rw-r--r--user_guide_src/source/helpers/cookie_helper.rst2
-rw-r--r--user_guide_src/source/installation/downloads.rst3
-rw-r--r--user_guide_src/source/installation/upgrade_315.rst14
-rw-r--r--user_guide_src/source/installation/upgrading.rst1
-rw-r--r--user_guide_src/source/libraries/input.rst6
-rw-r--r--user_guide_src/source/libraries/security.rst11
-rw-r--r--user_guide_src/source/libraries/typography.rst4
47 files changed, 278 insertions, 157 deletions
diff --git a/.gitignore b/.gitignore
index 97f1d3159..916cbe589 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,8 @@ application/logs/*
!application/logs/index.html
!application/logs/.htaccess
+composer.lock
+
user_guide_src/build/*
user_guide_src/cilexer/build/*
user_guide_src/cilexer/dist/*
diff --git a/.travis.yml b/.travis.yml
index 3d0691e50..100b145b2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,7 +25,7 @@ before_script:
- sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'create database ci_test;' -U postgres; fi"
- sh -c "if [ '$DB' = 'mysql' ] || [ '$DB' = 'mysqli' ] || [ '$DB' = 'pdo/mysql' ]; then mysql -e 'create database IF NOT EXISTS ci_test;'; fi"
-script: phpunit -d zend.enable_gc=0 -d date.timezone=UTC --coverage-text --configuration tests/travis/$DB.phpunit.xml
+script: php -d zend.enable_gc=0 -d date.timezone=UTC -d mbstring.func_overload=7 -d mbstring.internal_encoding=UTF-8 vendor/bin/phpunit --coverage-text --configuration tests/travis/$DB.phpunit.xml
matrix:
allow_failures:
diff --git a/composer.json b/composer.json
index 64d1be155..0a898d2c1 100644
--- a/composer.json
+++ b/composer.json
@@ -17,6 +17,7 @@
"paragonie/random_compat": "Provides better randomness in PHP 5.x"
},
"require-dev": {
- "mikey179/vfsStream": "1.1.*"
+ "mikey179/vfsStream": "1.1.*",
+ "phpunit/phpunit": "4.* || 5.*"
}
-} \ No newline at end of file
+}
diff --git a/system/core/Common.php b/system/core/Common.php
index cef9f47e0..c4f6dd30b 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -318,12 +318,9 @@ if ( ! function_exists('get_mimes'))
if (empty($_mimes))
{
- $_mimes = array();
-
- if (file_exists(APPPATH.'config/mimes.php'))
- {
- $_mimes = array_merge($_mimes, include(APPPATH.'config/mimes.php'));
- }
+ $_mimes = file_exists(APPPATH.'config/mimes.php')
+ ? include(APPPATH.'config/mimes.php')
+ : array();
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
{
@@ -564,12 +561,12 @@ if ( ! function_exists('set_status_header'))
if (strpos(PHP_SAPI, 'cgi') === 0)
{
header('Status: '.$code.' '.$text, TRUE);
+ return;
}
- else
- {
- $server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
- header($server_protocol.' '.$code.' '.$text, TRUE, $code);
- }
+
+ $server_protocol = (isset($_SERVER['SERVER_PROTOCOL']) && in_array($_SERVER['SERVER_PROTOCOL'], array('HTTP/1.0', 'HTTP/1.1', 'HTTP/2'), TRUE))
+ ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
+ header($server_protocol.' '.$code.' '.$text, TRUE, $code);
}
}
diff --git a/system/core/Input.php b/system/core/Input.php
index 70a3c61ee..dcaae60eb 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -304,7 +304,7 @@ class CI_Input {
* @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript)
* @return void
*/
- public function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
+ public function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL)
{
if (is_array($name))
{
@@ -333,15 +333,13 @@ class CI_Input {
$path = config_item('cookie_path');
}
- if ($secure === FALSE && config_item('cookie_secure') === TRUE)
- {
- $secure = config_item('cookie_secure');
- }
+ $secure = ($secure === NULL && config_item('cookie_secure') !== NULL)
+ ? (bool) config_item('cookie_secure')
+ : (bool) $secure;
- if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE)
- {
- $httponly = config_item('cookie_httponly');
- }
+ $httponly = ($httponly === NULL && config_item('cookie_httponly') !== NULL)
+ ? (bool) config_item('cookie_httponly')
+ : (bool) $httponly;
if ( ! is_numeric($expire) OR $expire < 0)
{
diff --git a/system/core/Log.php b/system/core/Log.php
index 67b315b6b..dd6ab8b90 100644
--- a/system/core/Log.php
+++ b/system/core/Log.php
@@ -105,11 +105,11 @@ class CI_Log {
protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4);
/**
- * mbstring.func_override flag
+ * mbstring.func_overload flag
*
* @var bool
*/
- protected static $func_override;
+ protected static $func_overload;
// --------------------------------------------------------------------
@@ -122,7 +122,7 @@ class CI_Log {
{
$config =& get_config();
- isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
$this->_log_path = ($config['log_path'] !== '')
? rtrim($config['log_path'], '/\\').DIRECTORY_SEPARATOR : APPPATH.'logs'.DIRECTORY_SEPARATOR;
@@ -266,7 +266,7 @@ class CI_Log {
*/
protected static function strlen($str)
{
- return (self::$func_override)
+ return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
@@ -283,7 +283,7 @@ class CI_Log {
*/
protected static function substr($str, $start, $length = NULL)
{
- if (self::$func_override)
+ if (self::$func_overload)
{
return mb_substr($str, $start, $length, '8bit');
}
diff --git a/system/core/Output.php b/system/core/Output.php
index 2cdb9808c..c684c94c9 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -123,11 +123,11 @@ class CI_Output {
public $parse_exec_vars = TRUE;
/**
- * mbstring.func_override flag
+ * mbstring.func_overload flag
*
* @var bool
*/
- protected static $func_override;
+ protected static $func_overload;
/**
* Class constructor
@@ -145,7 +145,7 @@ class CI_Output {
&& extension_loaded('zlib')
);
- isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
// Get mime types for later
$this->mimes =& get_mimes();
@@ -817,7 +817,7 @@ class CI_Output {
*/
protected static function strlen($str)
{
- return (self::$func_override)
+ return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
@@ -834,7 +834,7 @@ class CI_Output {
*/
protected static function substr($str, $start, $length = NULL)
{
- if (self::$func_override)
+ if (self::$func_overload)
{
return mb_substr($str, $start, $length, '8bit');
}
diff --git a/system/core/Security.php b/system/core/Security.php
index 4ad550fff..4b6df01a3 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -355,9 +355,9 @@ class CI_Security {
// Is the string an array?
if (is_array($str))
{
- while (list($key) = each($str))
+ foreach ($str as $key => &$value)
{
- $str[$key] = $this->xss_clean($str[$key]);
+ $str[$key] = $this->xss_clean($value);
}
return $str;
diff --git a/system/core/compat/hash.php b/system/core/compat/hash.php
index c0eab4909..fc319028d 100644
--- a/system/core/compat/hash.php
+++ b/system/core/compat/hash.php
@@ -173,7 +173,9 @@ if ( ! function_exists('hash_pbkdf2'))
return FALSE;
}
- $hash_length = strlen(hash($algo, NULL, TRUE));
+ $hash_length = defined('MB_OVERLOAD_STRING')
+ ? mb_strlen(hash($algo, NULL, TRUE), '8bit')
+ : strlen(hash($algo, NULL, TRUE));
empty($length) && $length = $hash_length;
// Pre-hash password inputs longer than the algorithm's block size
@@ -219,14 +221,14 @@ if ( ! function_exists('hash_pbkdf2'))
'whirlpool' => 64
);
- if (isset($block_sizes[$algo]) && strlen($password) > $block_sizes[$algo])
+ if (isset($block_sizes[$algo], $password[$block_sizes[$algo]]))
{
$password = hash($algo, $password, TRUE);
}
$hash = '';
// Note: Blocks are NOT 0-indexed
- for ($bc = ceil($length / $hash_length), $bi = 1; $bi <= $bc; $bi++)
+ for ($bc = (int) ceil($length / $hash_length), $bi = 1; $bi <= $bc; $bi++)
{
$key = $derived_key = hash_hmac($algo, $salt.pack('N', $bi), $password, TRUE);
for ($i = 1; $i < $iterations; $i++)
@@ -238,6 +240,13 @@ if ( ! function_exists('hash_pbkdf2'))
}
// This is not RFC-compatible, but we're aiming for natural PHP compatibility
- return substr($raw_output ? $hash : bin2hex($hash), 0, $length);
+ if ( ! $raw_output)
+ {
+ $hash = bin2hex($hash);
+ }
+
+ return defined('MB_OVERLOAD_STRING')
+ ? mb_substr($hash, 0, $length, '8bit')
+ : substr($hash, 0, $length);
}
}
diff --git a/system/core/compat/password.php b/system/core/compat/password.php
index 84be66738..fa28f5492 100644
--- a/system/core/compat/password.php
+++ b/system/core/compat/password.php
@@ -94,8 +94,8 @@ if ( ! function_exists('password_hash'))
*/
function password_hash($password, $algo, array $options = array())
{
- static $func_override;
- isset($func_override) OR $func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ static $func_overload;
+ isset($func_overload) OR $func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
if ($algo !== 1)
{
@@ -109,7 +109,7 @@ if ( ! function_exists('password_hash'))
return NULL;
}
- if (isset($options['salt']) && ($saltlen = ($func_override ? mb_strlen($options['salt'], '8bit') : strlen($options['salt']))) < 22)
+ if (isset($options['salt']) && ($saltlen = ($func_overload ? mb_strlen($options['salt'], '8bit') : strlen($options['salt']))) < 22)
{
trigger_error('password_hash(): Provided salt is too short: '.$saltlen.' expecting 22', E_USER_WARNING);
return NULL;
@@ -144,7 +144,7 @@ if ( ! function_exists('password_hash'))
stream_set_chunk_size($fp, 16);
$options['salt'] = '';
- for ($read = 0; $read < 16; $read = ($func_override) ? mb_strlen($options['salt'], '8bit') : strlen($options['salt']))
+ for ($read = 0; $read < 16; $read = ($func_overload) ? mb_strlen($options['salt'], '8bit') : strlen($options['salt']))
{
if (($read = fread($fp, 16 - $read)) === FALSE)
{
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 1daee99a8..ef375227c 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -2576,26 +2576,27 @@ abstract class CI_DB_query_builder extends CI_DB_driver {
*/
protected function _compile_order_by()
{
- if (is_array($this->qb_orderby) && count($this->qb_orderby) > 0)
+ if (empty($this->qb_orderby))
{
- for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++)
+ return '';
+ }
+
+ for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++)
+ {
+ if (is_string($this->qb_orderby[$i]))
{
- if ($this->qb_orderby[$i]['escape'] !== FALSE && ! $this->_is_literal($this->qb_orderby[$i]['field']))
- {
- $this->qb_orderby[$i]['field'] = $this->protect_identifiers($this->qb_orderby[$i]['field']);
- }
+ continue;
+ }
- $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction'];
+ if ($this->qb_orderby[$i]['escape'] !== FALSE && ! $this->_is_literal($this->qb_orderby[$i]['field']))
+ {
+ $this->qb_orderby[$i]['field'] = $this->protect_identifiers($this->qb_orderby[$i]['field']);
}
- return $this->qb_orderby = "\nORDER BY ".implode(', ', $this->qb_orderby);
- }
- elseif (is_string($this->qb_orderby))
- {
- return $this->qb_orderby;
+ $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction'];
}
- return '';
+ return "\nORDER BY ".implode(', ', $this->qb_orderby);
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/ibase/ibase_driver.php b/system/database/drivers/ibase/ibase_driver.php
index fea3bfe52..3069d6699 100644
--- a/system/database/drivers/ibase/ibase_driver.php
+++ b/system/database/drivers/ibase/ibase_driver.php
@@ -395,7 +395,7 @@ class CI_DB_ibase_driver extends CI_DB {
*/
protected function _insert_batch($table, $keys, $values)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index a490d206c..e91a817b6 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -488,7 +488,7 @@ class CI_DB_mssql_driver extends CI_DB {
return parent::_insert_batch($table, $keys, $values);
}
- return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index 290101153..a7ef648d7 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -210,7 +210,7 @@ class CI_DB_mysqli_driver extends CI_DB {
$this->_mysqli->close();
$message = 'MySQLi was configured for an SSL connection, but got an unencrypted connection instead!';
log_message('error', $message);
- return ($this->db->db_debug) ? $this->db->display_error($message, '', TRUE) : FALSE;
+ return ($this->db_debug) ? $this->display_error($message, '', TRUE) : FALSE;
}
if ( ! $this->_mysqli->set_charset($this->char_set))
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index ed44412c1..ef982fc63 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -316,7 +316,7 @@ class CI_DB_odbc_driver extends CI_DB_driver {
*/
protected function _escape_str($str)
{
- $this->db->display_error('db_unsupported_feature');
+ $this->display_error('db_unsupported_feature');
}
// --------------------------------------------------------------------
@@ -340,7 +340,7 @@ class CI_DB_odbc_driver extends CI_DB_driver {
*/
public function insert_id()
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
index 3249a1d7f..08243232e 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php
@@ -331,7 +331,7 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver {
return parent::_insert_batch($table, $keys, $values);
}
- return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
index aa5e7d6e7..cb93f19b7 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php
@@ -274,6 +274,6 @@ class CI_DB_pdo_firebird_driver extends CI_DB_pdo_driver {
*/
protected function _insert_batch($table, $keys, $values)
{
- return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
}
diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
index 66c15dac6..64b13d827 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php
@@ -182,7 +182,7 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver {
{
$message = 'PDO_MYSQL was configured for an SSL connection, but got an unencrypted connection instead!';
log_message('error', $message);
- return ($this->db->db_debug) ? $this->db->display_error($message, '', TRUE) : FALSE;
+ return ($this->db_debug) ? $this->display_error($message, '', TRUE) : FALSE;
}
return $pdo;
diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
index 5a492d881..066dd9614 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php
@@ -168,7 +168,7 @@ class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver {
*/
protected function _escape_str($str)
{
- $this->db->display_error('db_unsupported_feature');
+ $this->display_error('db_unsupported_feature');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
index 1cf6c614d..07c429eec 100644
--- a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
+++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php
@@ -363,7 +363,7 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver {
return parent::_insert_batch($table, $keys, $values);
}
- return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
}
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 75b1d4c37..505d609b8 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -130,9 +130,9 @@ class CI_DB_postgre_driver extends CI_DB {
*/
foreach (array('connect_timeout', 'options', 'sslmode', 'service') as $key)
{
- if (isset($this->$key) && is_string($this->key) && $this->key !== '')
+ if (isset($this->$key) && is_string($this->$key) && $this->$key !== '')
{
- $this->dsn .= $key."='".$this->key."' ";
+ $this->dsn .= $key."='".$this->$key."' ";
}
}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index e4f403180..a43e2539a 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -525,7 +525,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
return parent::_insert_batch($table, $keys, $values);
}
- return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
+ return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/helpers/cookie_helper.php b/system/helpers/cookie_helper.php
index d069cdb15..a1a9324ff 100644
--- a/system/helpers/cookie_helper.php
+++ b/system/helpers/cookie_helper.php
@@ -67,7 +67,7 @@ if ( ! function_exists('set_cookie'))
* @param bool true makes the cookie accessible via http(s) only (no javascript)
* @return void
*/
- function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
+ function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL)
{
// Set the config file options
get_instance()->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly);
diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php
index b5e8ed783..93ba2dd7d 100644
--- a/system/helpers/html_helper.php
+++ b/system/helpers/html_helper.php
@@ -192,7 +192,7 @@ if ( ! function_exists('img'))
foreach ($src as $k => $v)
{
- if ($k === 'src' && ! preg_match('#^([a-z]+:)?//#i', $v))
+ if ($k === 'src' && ! preg_match('#^(data:[a-z,;])|(([a-z]+:)?(?<!data:)//)#i', $v))
{
if ($index_page === TRUE)
{
diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php
index 311f7a420..896973704 100644
--- a/system/helpers/string_helper.php
+++ b/system/helpers/string_helper.php
@@ -168,9 +168,7 @@ if ( ! function_exists('reduce_multiples'))
if ( ! function_exists('random_string'))
{
/**
- * Create a Random String
- *
- * Useful for generating passwords or hashes.
+ * Create a "Random" String
*
* @param string type of random string. basic, alpha, alnum, numeric, nozero, unique, md5, encrypt and sha1
* @param int number of characters
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 07c01c3af..217729b70 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -138,7 +138,10 @@ if ( ! function_exists('ascii_to_entities'))
function ascii_to_entities($str)
{
$out = '';
- for ($i = 0, $s = strlen($str) - 1, $count = 1, $temp = array(); $i <= $s; $i++)
+ $length = defined('MB_OVERLOAD_STRING')
+ ? mb_strlen($str, '8bit') - 1
+ : strlen($str) - 1;
+ for ($i = 0, $count = 1, $temp = array(); $i <= $length; $i++)
{
$ordinal = ord($str[$i]);
@@ -176,7 +179,7 @@ if ( ! function_exists('ascii_to_entities'))
$temp = array();
}
// If this is the last iteration, just output whatever we have
- elseif ($i === $s)
+ elseif ($i === $length)
{
$out .= '&#'.implode(';', $temp).';';
}
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 1483f2203..d7178f321 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -368,11 +368,11 @@ class CI_Email {
);
/**
- * mbstring.func_override flag
+ * mbstring.func_overload flag
*
* @var bool
*/
- protected static $func_override;
+ protected static $func_overload;
// --------------------------------------------------------------------
@@ -389,7 +389,7 @@ class CI_Email {
$this->charset = config_item('charset');
$this->initialize($config);
- isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
log_message('info', 'Email Class Initialized');
}
@@ -2420,7 +2420,7 @@ class CI_Email {
*/
protected static function strlen($str)
{
- return (self::$func_override)
+ return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
@@ -2437,7 +2437,7 @@ class CI_Email {
*/
protected static function substr($str, $start, $length = NULL)
{
- if (self::$func_override)
+ if (self::$func_overload)
{
return mb_substr($str, $start, $length, '8bit');
}
diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php
index 46f374726..ebcc6e8c6 100644
--- a/system/libraries/Encrypt.php
+++ b/system/libraries/Encrypt.php
@@ -122,7 +122,7 @@ class CI_Encrypt {
$key = config_item('encryption_key');
- if ( ! strlen($key))
+ if ( ! self::strlen($key))
{
show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
}
@@ -252,7 +252,7 @@ class CI_Encrypt {
$string = $this->_xor_merge($string, $key);
$dec = '';
- for ($i = 0, $l = strlen($string); $i < $l; $i++)
+ for ($i = 0, $l = self::strlen($string); $i < $l; $i++)
{
$dec .= ($string[$i++] ^ $string[$i]);
}
@@ -275,7 +275,8 @@ class CI_Encrypt {
{
$hash = $this->hash($key);
$str = '';
- for ($i = 0, $ls = strlen($string), $lh = strlen($hash); $i < $ls; $i++)
+
+ for ($i = 0, $ls = self::strlen($string), $lh = self::strlen($hash); $i < $ls; $i++)
{
$str .= $string[$i] ^ $hash[($i % $lh)];
}
@@ -295,7 +296,7 @@ class CI_Encrypt {
public function mcrypt_encode($data, $key)
{
$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
- $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
+ $init_vect = mcrypt_create_iv($init_size, MCRYPT_DEV_URANDOM);
return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
}
@@ -313,13 +314,14 @@ class CI_Encrypt {
$data = $this->_remove_cipher_noise($data, $key);
$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
- if ($init_size > strlen($data))
+ if ($init_size > self::strlen($data))
{
return FALSE;
}
- $init_vect = substr($data, 0, $init_size);
- $data = substr($data, $init_size);
+ $init_vect = self::substr($data, 0, $init_size);
+ $data = self::substr($data, $init_size);
+
return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
}
@@ -339,7 +341,7 @@ class CI_Encrypt {
$key = $this->hash($key);
$str = '';
- for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
+ for ($i = 0, $j = 0, $ld = self::strlen($data), $lk = self::strlen($key); $i < $ld; ++$i, ++$j)
{
if ($j >= $lk)
{
@@ -369,7 +371,7 @@ class CI_Encrypt {
$key = $this->hash($key);
$str = '';
- for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
+ for ($i = 0, $j = 0, $ld = self::strlen($data), $lk = self::strlen($key); $i < $ld; ++$i, ++$j)
{
if ($j >= $lk)
{
@@ -477,4 +479,43 @@ class CI_Encrypt {
return hash($this->_hash_type, $str);
}
+ // --------------------------------------------------------------------
+
+ /**
+ * Byte-safe strlen()
+ *
+ * @param string $str
+ * @return int
+ */
+ protected static function strlen($str)
+ {
+ return defined('MB_OVERLOAD_STRING')
+ ? mb_strlen($str, '8bit')
+ : strlen($str);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Byte-safe substr()
+ *
+ * @param string $str
+ * @param int $start
+ * @param int $length
+ * @return string
+ */
+ protected static function substr($str, $start, $length = NULL)
+ {
+ if (defined('MB_OVERLOAD_STRING'))
+ {
+ // mb_substr($str, $start, null, '8bit') returns an empty
+ // string on PHP 5.3
+ isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
+ return mb_substr($str, $start, $length, '8bit');
+ }
+
+ return isset($length)
+ ? substr($str, $start, $length)
+ : substr($str, $start);
+ }
}
diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php
index 6799d0fef..c3ddf60ed 100644
--- a/system/libraries/Encryption.php
+++ b/system/libraries/Encryption.php
@@ -135,11 +135,11 @@ class CI_Encryption {
);
/**
- * mbstring.func_override flag
+ * mbstring.func_overload flag
*
* @var bool
*/
- protected static $func_override;
+ protected static $func_overload;
// --------------------------------------------------------------------
@@ -161,7 +161,7 @@ class CI_Encryption {
show_error('Encryption: Unable to find an available encryption driver.');
}
- isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
$this->initialize($params);
if ( ! isset($this->_key) && self::strlen($key = config_item('encryption_key')) > 0)
@@ -911,7 +911,7 @@ class CI_Encryption {
*/
protected static function strlen($str)
{
- return (self::$func_override)
+ return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
@@ -928,7 +928,7 @@ class CI_Encryption {
*/
protected static function substr($str, $start, $length = NULL)
{
- if (self::$func_override)
+ if (self::$func_overload)
{
return mb_substr($str, $start, $length, '8bit');
}
diff --git a/system/libraries/Session/drivers/Session_database_driver.php b/system/libraries/Session/drivers/Session_database_driver.php
index 31f5a4663..b519b782f 100644
--- a/system/libraries/Session/drivers/Session_database_driver.php
+++ b/system/libraries/Session/drivers/Session_database_driver.php
@@ -208,12 +208,8 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan
// Prevent previous QB calls from messing with our queries
$this->_db->reset_query();
- if ($this->_lock === FALSE)
- {
- return $this->_fail();
- }
// Was the ID regenerated?
- elseif ($session_id !== $this->_session_id)
+ if (isset($this->_session_id) && $session_id !== $this->_session_id)
{
if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id))
{
@@ -223,6 +219,10 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan
$this->_row_exists = FALSE;
$this->_session_id = $session_id;
}
+ elseif ($this->_lock === FALSE)
+ {
+ return $this->_fail();
+ }
if ($this->_row_exists === FALSE)
{
diff --git a/system/libraries/Session/drivers/Session_files_driver.php b/system/libraries/Session/drivers/Session_files_driver.php
index 6016e094e..8860ef667 100644
--- a/system/libraries/Session/drivers/Session_files_driver.php
+++ b/system/libraries/Session/drivers/Session_files_driver.php
@@ -84,11 +84,11 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
protected $_sid_regexp;
/**
- * mbstring.func_override flag
+ * mbstring.func_overload flag
*
* @var bool
*/
- protected static $func_override;
+ protected static $func_overload;
// ------------------------------------------------------------------------
@@ -115,7 +115,7 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
$this->_sid_regexp = $this->_config['_sid_regexp'];
- isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
}
// ------------------------------------------------------------------------
@@ -399,7 +399,7 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
*/
protected static function strlen($str)
{
- return (self::$func_override)
+ return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php
index e025c4508..ca35e85c0 100644
--- a/system/libraries/Xmlrpc.php
+++ b/system/libraries/Xmlrpc.php
@@ -460,7 +460,7 @@ class CI_Xmlrpc {
{
if (is_array($value[0]) && ($value[1] === 'struct' OR $value[1] === 'array'))
{
- while (list($k) = each($value[0]))
+ foreach (array_keys($value[0]) as $k)
{
$value[0][$k] = $this->values_parsing($value[0][$k]);
}
@@ -929,15 +929,15 @@ class XML_RPC_Response
if (is_array($array))
{
- while (list($key) = each($array))
+ foreach ($array as $key => &$value)
{
- if (is_array($array[$key]))
+ if (is_array($value))
{
- $array[$key] = $this->decode($array[$key]);
+ $array[$key] = $this->decode($value);
}
elseif ($this->xss_clean)
{
- $array[$key] = $CI->security->xss_clean($array[$key]);
+ $array[$key] = $CI->security->xss_clean($value);
}
}
@@ -991,10 +991,11 @@ class XML_RPC_Response
reset($xmlrpc_val->me['struct']);
$arr = array();
- while (list($key,$value) = each($xmlrpc_val->me['struct']))
+ foreach ($xmlrpc_val->me['struct'] as $key => &$value)
{
$arr[$key] = $this->xmlrpc_decoder($value);
}
+
return $arr;
}
}
@@ -1560,17 +1561,17 @@ class XML_RPC_Message extends CI_Xmlrpc
if ( ! empty($array))
{
- while (list($key) = each($array))
+ foreach ($array as $key => &$value)
{
- if (is_array($array[$key]))
+ if (is_array($value))
{
- $array[$key] = $this->output_parameters($array[$key]);
+ $array[$key] = $this->output_parameters($value);
}
elseif ($key !== 'bits' && $this->xss_clean)
{
// 'bits' is for the MetaWeblog API image bits
// @todo - this needs to be made more general purpose
- $array[$key] = $CI->security->xss_clean($array[$key]);
+ $array[$key] = $CI->security->xss_clean($value);
}
}
@@ -1630,7 +1631,7 @@ class XML_RPC_Message extends CI_Xmlrpc
reset($param->me['struct']);
$arr = array();
- while (list($key,$value) = each($param->me['struct']))
+ foreach ($param->me['struct'] as $key => &$value)
{
$arr[$key] = $this->decode_message($value);
}
@@ -1821,7 +1822,7 @@ class XML_RPC_Values extends CI_Xmlrpc
// struct
$rs .= "<struct>\n";
reset($val);
- while (list($key2, $val2) = each($val))
+ foreach ($val as $key2 => &$val2)
{
$rs .= "<member>\n<name>{$key2}</name>\n".$this->serializeval($val2)."</member>\n";
}
@@ -1882,11 +1883,9 @@ class XML_RPC_Values extends CI_Xmlrpc
*/
public function serializeval($o)
{
- $ar = $o->me;
- reset($ar);
-
- list($typ, $val) = each($ar);
- return "<value>\n".$this->serializedata($typ, $val)."</value>\n";
+ $array = $o->me;
+ list($value, $type) = array(reset($ar), key($array));
+ return "<value>\n".$this->serializedata($type, $value)."</value>\n";
}
// --------------------------------------------------------------------
@@ -1898,8 +1897,7 @@ class XML_RPC_Values extends CI_Xmlrpc
*/
public function scalarval()
{
- reset($this->me);
- return current($this->me);
+ return reset($this->me);
}
// --------------------------------------------------------------------
diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php
index 21de937c8..0274f13b6 100644
--- a/system/libraries/Xmlrpcs.php
+++ b/system/libraries/Xmlrpcs.php
@@ -584,7 +584,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc {
return $this->multicall_error('nomethod');
}
- list($scalar_type, $scalar_value) = each($methName->me);
+ list($scalar_value, $scalar_type) = array(reset($methName->me), key($methName->me));
$scalar_type = $scalar_type === $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type;
if ($methName->kindOf() !== 'scalar' OR $scalar_type !== 'string')
@@ -604,7 +604,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc {
return $this->multicall_error('notarray');
}
- list($a, $b) = each($params->me);
+ list($b, $a) = array(reset($params->me), key($params->me));
$msg = new XML_RPC_Message($scalar_value);
for ($i = 0, $numParams = count($b); $i < $numParams; $i++)
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index d6974b13a..c14de00c4 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -106,11 +106,11 @@ class CI_Zip {
public $compression_level = 2;
/**
- * mbstring.func_override flag
+ * mbstring.func_overload flag
*
* @var bool
*/
- protected static $func_override;
+ protected static $func_overload;
/**
* Initialize zip compression class
@@ -119,7 +119,7 @@ class CI_Zip {
*/
public function __construct()
{
- isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
$this->now = time();
log_message('info', 'Zip Compression Class Initialized');
@@ -500,7 +500,7 @@ class CI_Zip {
*/
protected static function strlen($str)
{
- return (self::$func_override)
+ return (self::$func_overload)
? mb_strlen($str, '8bit')
: strlen($str);
}
@@ -517,7 +517,7 @@ class CI_Zip {
*/
protected static function substr($str, $start, $length = NULL)
{
- if (self::$func_override)
+ if (self::$func_overload)
{
return mb_substr($str, $start, $length, '8bit');
}
diff --git a/tests/codeigniter/helpers/html_helper_test.php b/tests/codeigniter/helpers/html_helper_test.php
index 5565e011b..3ca23e015 100644
--- a/tests/codeigniter/helpers/html_helper_test.php
+++ b/tests/codeigniter/helpers/html_helper_test.php
@@ -33,6 +33,20 @@ class Html_helper_test extends CI_TestCase {
// ------------------------------------------------------------------------
+ public function test_img()
+ {
+ $this->ci_set_config('base_url', 'http://localhost/');
+ $this->assertEquals('<img src="http://localhost/test" alt="" />', img("test"));
+ $this->assertEquals('<img src="data:foo/bar,baz" alt="" />', img("data:foo/bar,baz"));
+ $this->assertEquals('<img src="http://localhost/data://foo" alt="" />', img("data://foo"));
+ $this->assertEquals('<img src="//foo.bar/baz" alt="" />', img("//foo.bar/baz"));
+ $this->assertEquals('<img src="http://foo.bar/baz" alt="" />', img("http://foo.bar/baz"));
+ $this->assertEquals('<img src="https://foo.bar/baz" alt="" />', img("https://foo.bar/baz"));
+ $this->assertEquals('<img src="ftp://foo.bar/baz" alt="" />', img("ftp://foo.bar/baz"));
+ }
+
+ // ------------------------------------------------------------------------
+
public function test_Ul()
{
$expect = <<<EOH
diff --git a/tests/codeigniter/libraries/Encryption_test.php b/tests/codeigniter/libraries/Encryption_test.php
index 96e52ada8..99c5d4b9d 100644
--- a/tests/codeigniter/libraries/Encryption_test.php
+++ b/tests/codeigniter/libraries/Encryption_test.php
@@ -94,10 +94,22 @@ class Encryption_test extends CI_TestCase {
}
// Test default length, it must match the digest size
- $this->assertEquals(64, strlen($this->encryption->hkdf('foobar', 'sha512')));
+ $hkdf_result = $this->encryption->hkdf('foobar', 'sha512');
+ $this->assertEquals(
+ 64,
+ defined('MB_OVERLOAD_STRING')
+ ? mb_strlen($hkdf_result, '8bit')
+ : strlen($hkdf_result)
+ );
// Test maximum length (RFC5869 says that it must be up to 255 times the digest size)
- $this->assertEquals(12240, strlen($this->encryption->hkdf('foobar', 'sha384', NULL, 48 * 255)));
+ $hkdf_result = $this->encryption->hkdf('foobar', 'sha384', NULL, 48 * 255);
+ $this->assertEquals(
+ 12240,
+ defined('MB_OVERLOAD_STRING')
+ ? mb_strlen($hkdf_result, '8bit')
+ : strlen($hkdf_result)
+ );
$this->assertFalse($this->encryption->hkdf('foobar', 'sha224', NULL, 28 * 255 + 1));
// CI-specific test for an invalid digest
diff --git a/tests/mocks/ci_testconfig.php b/tests/mocks/ci_testconfig.php
index f80adc5d4..afdb71001 100644
--- a/tests/mocks/ci_testconfig.php
+++ b/tests/mocks/ci_testconfig.php
@@ -1,20 +1,20 @@
<?php
-class CI_TestConfig {
+class CI_TestConfig extends CI_Config {
public $config = array();
public $_config_paths = array(APPPATH);
public $loaded = array();
- public function item($key)
+ public function item($key, $index = '')
{
return isset($this->config[$key]) ? $this->config[$key] : FALSE;
}
- public function load($file, $arg2 = FALSE, $arg3 = FALSE)
+ public function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
{
$this->loaded[] = $file;
return TRUE;
}
-} \ No newline at end of file
+}
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 96c3af9bb..875198c4e 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -17,10 +17,8 @@
</testsuite>
</testsuites>
<filter>
- <blacklist>
- <directory suffix=".php">PEAR_INSTALL_DIR</directory>
- <directory suffix=".php">PHP_LIBDIR</directory>
- <directory suffix=".php">../vendor</directory>
- </blacklist>
+ <whitelist>
+ <directory suffix=".php">../system/</directory>
+ </whitelist>
</filter>
-</phpunit> \ No newline at end of file
+</phpunit>
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index f1f0b6834..2b8d65f4c 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -106,11 +106,25 @@ Release Date: Not Released
- Removed the second (out of three) parameter from the :php:func:`form_upload()` function (it was never used).
-Version 3.1.4
+Version 3.1.5
=============
Release Date: Not Released
+
+Version 3.1.4
+=============
+
+Release Date: March 20, 2017
+
+- **Security**
+
+ - Fixed a header injection vulnerability in :doc:`common function <general/common_functions>` :php:func:`set_status_header()` under Apache (thanks to Guillermo Caminer from `Flowgate <https://flowgate.net/>`_).
+ - Fixed byte-safety issues in :doc:`Encrypt Library <libraries/encrypt>` (DEPRECATED) when ``mbstring.func_overload`` is enabled.
+ - Fixed byte-safety issues in :doc:`Encryption Library <libraries/encryption>` when ``mbstring.func_overload`` is enabled.
+ - Fixed byte-safety issues in :doc:`compatibility functions <general/compatibility_functions>` ``password_hash()``, ``hash_pbkdf2()`` when ``mbstring.func_overload`` is enabled.
+ - Updated :doc:`Encrypt Library <libraries/encrypt>` (DEPRECATED) to call ``mcrypt_create_iv()`` with ``MCRYPT_DEV_URANDOM``.
+
- General Changes
- Updated the :doc:`Image Manipulation Library <libraries/image_lib>` to work-around an issue with some JPEGs when using GD.
@@ -119,6 +133,21 @@ Bug fixes for 3.1.4
-------------------
- Fixed a regression (#4975) - :doc:`Loader Library <libraries/loader>` couldn't handle objects passed as view variables.
+- Fixed a bug (#4977) - :doc:`Loader Library <libraries/loader>` method ``helper()`` could accept any character as a filename extension separator.
+- Fixed a regression where the :doc:`Session Library <libraries/sessions>` would fail on a ``session_regenerate_id(TRUE)`` call with the 'database' driver.
+- Fixed a bug (#4987) - :doc:`Query Builder <database/query_builder>` caching didn't keep track of table aliases.
+- Fixed a bug where :doc:`Text Helper <helpers/text_helper>` function ``ascii_to_entities()`` wasn't byte-safe when ``mbstring.func_overload`` is enabled.
+- Fixed a bug where ``CI_Log``, ``CI_Output``, ``CI_Email`` and ``CI_Zip`` didn't handle strings in a byte-safe manner when ``mbstring.func_overload`` is enabled.
+- Fixed a bug where :doc:`Session Library <libraries/sessions>` didn't read session data in a byte-safe manner when ``mbstring.func_overload`` is enabled.
+- Fixed a bug (#4990) - :doc:`Profiler <general/profiling>` didn't close ``<pre>`` tags it generated.
+- Fixed a bug (#4990) - :doc:`Profiler <general/profiling>` didn't HTML-escape quotes for ``$_SESSION`` variables.
+- Fixed a bug where :doc:`Input Library <libraries/input>` method ``set_cookie()`` didn't allow its *httponly* and *secure* parameters to be overriden to ``FALSE``.
+- Fixed a bug (#5006) - :doc:`common function <general/common_functions>` :php:func:`get_mimes()` didn't load *application/config/mimes.php* if an environment specific config exists.
+- Fixed a bug (#5006) - :doc:`common function <general/common_functions>` :php:func:`remove_invisible_characters()` didn't remove URL-encoded ``0x7F``.
+- Fixed a bug (#4815) - :doc:`Database Library <database/index>` stripped URL-encoded sequences while escaping strings with the 'mssql' driver.
+- Fixed a bug (#5044) - :doc:`HTML Helper <helpers/html_helper>` function :php:func:`img()` didn't accept ``data:`` URI schemes for the image source.
+- Fixed a bug (#5050) - :doc:`Database Library <database/index>` tried to access an undefined property in a number of error handling cases.
+- Fixed a bug (#5057) - :doc:`Database <database/index>` driver 'postgre' didn't actually apply extra options (such as 'connect_timeout') to its DSN.
Version 3.1.3
=============
@@ -183,7 +212,7 @@ Bug fixes for 3.1.2
- Fixed a regression (#4874) - :doc:`Session Library <libraries/sessions>` didn't take into account ``session.hash_bits_per_character`` when validating session IDs.
- Fixed a bug (#4871) - :doc:`Query Builder <database/query_builder>` method ``update_batch()`` didn't properly handle identifier escaping.
- Fixed a bug (#4884) - :doc:`Query Builder <database/query_builder>` didn't properly parse field names ending in 'is' when used inside WHERE and HAVING statements.
-- Fixed a bug where ``CI_Log``, ``CI_Output``, ``CI_Email`` and ``CI_Zip`` didn't handle strings in a byte-safe manner when ``mbstring.func_override`` is enabled.
+- Fixed a bug where ``CI_Log``, ``CI_Output``, ``CI_Email`` and ``CI_Zip`` didn't handle strings in a byte-safe manner when ``mbstring.func_overload`` is enabled.
Version 3.1.1
=============
@@ -220,7 +249,7 @@ Bug fixes for 3.1.1
- Fixed a bug where :doc:`Query Builder <database/query_builder>` method ``insert_batch()`` tried to execute an unsupported SQL query with the 'ibase' and 'pdo/firebird' drivers.
- Fixed a bug (#4809) - :doc:`Database <database/index>` driver 'pdo/mysql' didn't turn off ``AUTOCOMMIT`` when starting a transaction.
- Fixed a bug (#4822) - :doc:`CAPTCHA Helper <helpers/captcha_helper>` didn't clear expired PNG images.
-- Fixed a bug (#4823) - :doc:`Session Library <libraries/sessions>` 'files' driver could enter an infinite loop if ``mbstring.func_override`` is enabled.
+- Fixed a bug (#4823) - :doc:`Session Library <libraries/sessions>` 'files' driver could enter an infinite loop if ``mbstring.func_overload`` is enabled.
- Fixed a bug (#4851) - :doc:`Database Forge <database/forge>` didn't quote schema names passed to its ``create_database()`` method.
- Fixed a bug (#4863) - :doc:`HTML Table Library <libraries/table>` method ``set_caption()`` was missing method chaining support.
- Fixed a bug (#4843) - :doc:`XML-RPC Library <libraries/xmlrpc>` client class didn't set a read/write socket timeout.
diff --git a/user_guide_src/source/general/routing.rst b/user_guide_src/source/general/routing.rst
index b53a85d31..909289d8d 100644
--- a/user_guide_src/source/general/routing.rst
+++ b/user_guide_src/source/general/routing.rst
@@ -205,6 +205,3 @@ underscores in the controller and method URI segments, thus saving you
additional route entries if you need to do that.
This is required, because the dash isn't a valid class or method name
character and would cause a fatal error if you try to use it.
-
-.. important:: The reserved routes must come before any wildcard or
- regular expression routes. \ No newline at end of file
diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst
index 71e40a33c..25c4c3a0b 100644
--- a/user_guide_src/source/helpers/cookie_helper.rst
+++ b/user_guide_src/source/helpers/cookie_helper.rst
@@ -25,7 +25,7 @@ Available Functions
The following functions are available:
-.. php:function:: set_cookie($name[, $value = ''[, $expire = ''[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = FALSE[, $httponly = FALSE]]]]]]])
+.. php:function:: set_cookie($name[, $value = ''[, $expire = 0[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = NULL[, $httponly = NULL]]]]]]])
:param mixed $name: Cookie name *or* associative array of all of the parameters available to this function
:param string $value: Cookie value
diff --git a/user_guide_src/source/installation/downloads.rst b/user_guide_src/source/installation/downloads.rst
index d36296e35..f36857e57 100644
--- a/user_guide_src/source/installation/downloads.rst
+++ b/user_guide_src/source/installation/downloads.rst
@@ -3,7 +3,8 @@ Downloading CodeIgniter
#######################
- `CodeIgniter v3.2.0-dev (Current version) <https://codeload.github.com/bcit-ci/CodeIgniter/zip/develop>`_
-- `CodeIgniter v3.1.4-dev <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1-stable>`_
+- `CodeIgniter v3.1.5-dev <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1-stable>`_
+- `CodeIgniter v3.1.4 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.4>`_
- `CodeIgniter v3.1.3 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.3>`_
- `CodeIgniter v3.1.2 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.2>`_
- `CodeIgniter v3.1.1 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.1>`_
diff --git a/user_guide_src/source/installation/upgrade_315.rst b/user_guide_src/source/installation/upgrade_315.rst
new file mode 100644
index 000000000..cf673abbb
--- /dev/null
+++ b/user_guide_src/source/installation/upgrade_315.rst
@@ -0,0 +1,14 @@
+#############################
+Upgrading from 3.1.4 to 3.1.5
+#############################
+
+Before performing an update you should take your site offline by
+replacing the index.php file with a static one.
+
+Step 1: Update your CodeIgniter files
+=====================================
+
+Replace all files and directories in your *system/* directory.
+
+.. note:: If you have any custom developed files in these directories,
+ please make copies of them first.
diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst
index ca7677ba9..b76392d05 100644
--- a/user_guide_src/source/installation/upgrading.rst
+++ b/user_guide_src/source/installation/upgrading.rst
@@ -9,6 +9,7 @@ upgrading from.
:titlesonly:
Upgrading from 3.1.3+ to 3.2.x <upgrade_320>
+ Upgrading from 3.1.4 to 3.1.5 <upgrade_315>
Upgrading from 3.1.3 to 3.1.4 <upgrade_314>
Upgrading from 3.1.2 to 3.1.3 <upgrade_313>
Upgrading from 3.1.1 to 3.1.2 <upgrade_312>
diff --git a/user_guide_src/source/libraries/input.rst b/user_guide_src/source/libraries/input.rst
index 8a0b5f286..7f762e9f0 100644
--- a/user_guide_src/source/libraries/input.rst
+++ b/user_guide_src/source/libraries/input.rst
@@ -242,7 +242,7 @@ Class Reference
This method is identical to ``get()``, ``post()`` and ``cookie()``,
only it fetches the *php://input* stream data.
- .. php:method:: set_cookie($name = ''[, $value = ''[, $expire = 0[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = FALSE[, $httponly = FALSE]]]]]]])
+ .. php:method:: set_cookie($name = ''[, $value = ''[, $expire = 0[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = NULL[, $httponly = NULL]]]]]]])
:param mixed $name: Cookie name or an array of parameters
:param string $value: Cookie value
@@ -295,8 +295,8 @@ Class Reference
The prefix is only needed if you need to avoid name collisions with
other identically named cookies for your server.
- The secure boolean is only needed if you want to make it a secure cookie
- by setting it to TRUE.
+ The *httponly* and *secure* flags, when omitted, will default to your
+ ``$config['cookie_httponly']`` and ``$config['cookie_secure']`` settings.
**Discrete Parameters**
diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst
index f7604ef00..fc5cba19d 100644
--- a/user_guide_src/source/libraries/security.rst
+++ b/user_guide_src/source/libraries/security.rst
@@ -40,6 +40,9 @@ browser may attempt to execute.
// file failed the XSS test
}
+.. important:: If you want to filter HTML attribute values, use
+ :php:func:`html_escape()` instead!
+
*********************************
Cross-site request forgery (CSRF)
*********************************
@@ -101,7 +104,11 @@ Class Reference
:rtype: mixed
Tries to remove XSS exploits from the input data and returns the cleaned string.
- If the optional second parameter is set to true, it will return boolean TRUE if the image is safe to use and FALSE if malicious data was detected in it.
+ If the optional second parameter is set to true, it will return boolean TRUE if
+ the image is safe to use and FALSE if malicious data was detected in it.
+
+ .. important:: This method is not suitable for filtering HTML attribute vales!
+ Use :php:func:`html_escape()` for that instead.
.. php:method:: sanitize_filename($str[, $relative_path = FALSE])
@@ -162,4 +169,4 @@ Class Reference
Used for generating CSRF and XSS tokens.
.. note:: The output is NOT guaranteed to be cryptographically secure,
- just the best attempt at that. \ No newline at end of file
+ just the best attempt at that.
diff --git a/user_guide_src/source/libraries/typography.rst b/user_guide_src/source/libraries/typography.rst
index 1d1e4f3c4..9e1386835 100644
--- a/user_guide_src/source/libraries/typography.rst
+++ b/user_guide_src/source/libraries/typography.rst
@@ -44,7 +44,7 @@ Class Reference
$this->load->library('typography');
$this->typography->protect_braced_quotes = TRUE;
- .. method auto_typography($str[, $reduce_linebreaks = FALSE])
+ .. php:method:: auto_typography($str[, $reduce_linebreaks = FALSE])
:param string $str: Input string
:param bool $reduce_linebreaks: Whether to reduce consequitive linebreaks
@@ -104,4 +104,4 @@ Class Reference
Usage example::
- $string = $this->typography->nl2br_except_pre($string); \ No newline at end of file
+ $string = $this->typography->nl2br_except_pre($string);