summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Stollfuß <j0inty@users.noreply.github.com>2015-11-08 20:05:31 +0100
committerSteffen Stollfuß <j0inty@users.noreply.github.com>2015-11-08 20:05:31 +0100
commit49c78f694eded442d95a25feb5bbc69e6bffb205 (patch)
treeae36e42478e17f3d016bb3bd3b86aba0e9f16ca3
parent81a6f81d88a0cded9fa5617c4bc578311c5bb652 (diff)
parent6c4daef7ace73e1e9bacb511f646ade778763ff9 (diff)
Merge pull request #1 from bcit-ci/develop
Pull current develop branch to submit a bug report later
-rw-r--r--application/config/config.php14
-rw-r--r--application/config/mimes.php8
-rw-r--r--readme.rst3
-rw-r--r--system/core/Common.php7
-rw-r--r--system/core/Config.php6
-rw-r--r--system/core/Security.php66
-rw-r--r--system/database/DB_driver.php115
-rw-r--r--system/database/DB_forge.php8
-rw-r--r--system/database/drivers/cubrid/cubrid_driver.php38
-rw-r--r--system/database/drivers/ibase/ibase_driver.php32
-rw-r--r--system/database/drivers/mssql/mssql_driver.php30
-rw-r--r--system/database/drivers/mysql/mysql_driver.php37
-rw-r--r--system/database/drivers/mysqli/mysqli_driver.php30
-rw-r--r--system/database/drivers/oci8/oci8_driver.php41
-rw-r--r--system/database/drivers/odbc/odbc_driver.php34
-rw-r--r--system/database/drivers/pdo/pdo_driver.php30
-rw-r--r--system/database/drivers/postgre/postgre_driver.php30
-rw-r--r--system/database/drivers/sqlite/sqlite_driver.php39
-rw-r--r--system/database/drivers/sqlite3/sqlite3_driver.php30
-rw-r--r--system/database/drivers/sqlsrv/sqlsrv_driver.php34
-rw-r--r--system/helpers/captcha_helper.php89
-rw-r--r--system/libraries/Email.php13
-rw-r--r--system/libraries/Session/drivers/Session_database_driver.php4
-rw-r--r--tests/codeigniter/core/Common_test.php5
-rw-r--r--tests/codeigniter/core/Config_test.php47
-rw-r--r--tests/codeigniter/core/Security_test.php35
-rw-r--r--user_guide_src/source/changelog.rst18
-rw-r--r--user_guide_src/source/database/db_driver_reference.rst6
-rw-r--r--user_guide_src/source/database/query_builder.rst2
-rw-r--r--user_guide_src/source/installation/downloads.rst4
-rw-r--r--user_guide_src/source/installation/upgrade_300.rst45
-rw-r--r--user_guide_src/source/installation/upgrade_303.rst43
-rw-r--r--user_guide_src/source/installation/upgrade_304.rst14
-rw-r--r--user_guide_src/source/installation/upgrading.rst1
34 files changed, 504 insertions, 454 deletions
diff --git a/application/config/config.php b/application/config/config.php
index 479d591a4..4f8f81406 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -11,10 +11,16 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
| http://example.com/
|
-| If this is not set then CodeIgniter will try guess the protocol, domain
-| and path to your installation. However, you should always configure this
-| explicitly and never rely on auto-guessing, especially in production
-| environments.
+| WARNING: You MUST set this value!
+|
+| If it is not set, then CodeIgniter will try guess the protocol and path
+| your installation, but due to security concerns the hostname will be set
+| to $_SERVER['SERVER_ADDR'] if available, or localhost otherwise.
+| The auto-detection mechanism exists only for convenience during
+| development and MUST NOT be used in production!
+|
+| If you need to allow multiple domains, remember that this file is still
+| a PHP script and you can easily do that on your own.
|
*/
$config['base_url'] = '';
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 1f591ba6b..aa3b1836a 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -77,6 +77,14 @@ return array(
'jpeg' => array('image/jpeg', 'image/pjpeg'),
'jpg' => array('image/jpeg', 'image/pjpeg'),
'jpe' => array('image/jpeg', 'image/pjpeg'),
+ 'jp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
+ 'j2k' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
+ 'jpf' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
+ 'jpg2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
+ 'jpx' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
+ 'jpm' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
+ 'mj2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
+ 'mjp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'),
'png' => array('image/png', 'image/x-png'),
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
diff --git a/readme.rst b/readme.rst
index 640dd241b..2e35d7223 100644
--- a/readme.rst
+++ b/readme.rst
@@ -59,7 +59,8 @@ Resources
- `Community Wiki <https://github.com/bcit-ci/CodeIgniter/wiki>`_
- `Community IRC <http://www.codeigniter.com/irc>`_
-Report security issues to our `Security Panel <mailto:security@codeigniter.com>`_, thank you.
+Report security issues to our `Security Panel <mailto:security@codeigniter.com>`_
+or via our `page on HackerOne <https://hackerone.com/codeigniter>`_, thank you.
***************
Acknowledgement
diff --git a/system/core/Common.php b/system/core/Common.php
index ad3ca9f93..3ab98cf6d 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -752,7 +752,12 @@ if ( ! function_exists('html_escape'))
if (is_array($var))
{
- return array_map('html_escape', $var, array_fill(0, count($var), $double_encode));
+ foreach (array_keys($var) as $key)
+ {
+ $var[$key] = html_escape($var[$key], $double_encode);
+ }
+
+ return $var;
}
return htmlspecialchars($var, ENT_QUOTES, config_item('charset'), $double_encode);
diff --git a/system/core/Config.php b/system/core/Config.php
index feea7c85a..0264776f9 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -88,11 +88,9 @@ class CI_Config {
// Set the base_url automatically if none was provided
if (empty($this->config['base_url']))
{
- // The regular expression is only a basic validation for a valid "Host" header.
- // It's not exhaustive, only checks for valid characters.
- if (isset($_SERVER['HTTP_HOST']) && preg_match('/^((\[[0-9a-f:]+\])|(\d{1,3}(\.\d{1,3}){3})|[a-z0-9\-\.]+)(:\d+)?$/i', $_SERVER['HTTP_HOST']))
+ if (isset($_SERVER['SERVER_ADDR']))
{
- $base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST']
+ $base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['SERVER_ADDR']
.substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
}
else
diff --git a/system/core/Security.php b/system/core/Security.php
index ab85e2239..36dea4cf2 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -803,43 +803,55 @@ class CI_Security {
// For other tags, see if their attributes are "evil" and strip those
elseif (isset($matches['attributes']))
{
- // We'll need to catch all attributes separately first
- $pattern = '#'
- .'([\s\042\047/=]*)' // non-attribute characters, excluding > (tag close) for obvious reasons
+ // We'll store the already fitlered attributes here
+ $attributes = array();
+
+ // Attribute-catching pattern
+ $attributes_pattern = '#'
.'(?<name>[^\s\042\047>/=]+)' // attribute characters
// optional attribute-value
.'(?:\s*=(?<value>[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*)))' // attribute-value separator
.'#i';
- if ($count = preg_match_all($pattern, $matches['attributes'], $attributes, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
+ // Blacklist pattern for evil attribute names
+ $is_evil_pattern = '#^('.implode('|', $evil_attributes).')$#i';
+
+ // Each iteration filters a single attribute
+ do
{
- // Since we'll be using substr_replace() below, we
- // need to handle the attributes in reverse order,
- // so we don't damage the string.
- for ($i = $count - 1; $i > -1; $i--)
+ // Strip any non-alpha characters that may preceed an attribute.
+ // Browsers often parse these incorrectly and that has been a
+ // of numerous XSS issues we've had.
+ $matches['attributes'] = preg_replace('#^[^a-z]+#i', '', $matches['attributes']);
+
+ if ( ! preg_match($attributes_pattern, $matches['attributes'], $attribute, PREG_OFFSET_CAPTURE))
{
- if (
- // Is it indeed an "evil" attribute?
- preg_match('#^('.implode('|', $evil_attributes).')$#i', $attributes[$i]['name'][0])
- // Or an attribute not starting with a letter? Some parsers get confused by that
- OR ! ctype_alpha($attributes[$i]['name'][0][0])
- // Does it have an equals sign, but no value and not quoted? Strip that too!
- OR (trim($attributes[$i]['value'][0]) === '')
- )
- {
- $matches['attributes'] = substr_replace(
- $matches['attributes'],
- ' [removed]',
- $attributes[$i][0][1],
- strlen($attributes[$i][0][0])
- );
- }
+ // No (valid) attribute found? Discard everything else inside the tag
+ break;
}
- // Note: This will strip some non-space characters and/or
- // reduce multiple spaces between attributes.
- return '<'.$matches['slash'].$matches['tagName'].' '.trim($matches['attributes']).'>';
+ if (
+ // Is it indeed an "evil" attribute?
+ preg_match($is_evil_pattern, $attribute['name'][0])
+ // Or does it have an equals sign, but no value and not quoted? Strip that too!
+ OR (trim($attribute['value'][0]) === '')
+ )
+ {
+ $attributes[] = 'xss=removed';
+ }
+ else
+ {
+ $attributes[] = $attribute[0][0];
+ }
+
+ $matches['attributes'] = substr($matches['attributes'], $attribute[0][1] + strlen($attribute[0][0]));
}
+ while ($matches['attributes'] !== '');
+
+ $attributes = empty($attributes)
+ ? ''
+ : ' '.implode(' ', $attributes);
+ return '<'.$matches['slash'].$matches['tagName'].$attributes.'>';
}
return $matches[0];
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index cc94edc16..0ea679432 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -668,7 +668,13 @@ abstract class CI_DB_driver {
{
do
{
+ $trans_depth = $this->_trans_depth;
$this->trans_complete();
+ if ($trans_depth === $this->_trans_depth)
+ {
+ log_message('error', 'Database: Failure during an automated transaction commit/rollback!');
+ break;
+ }
}
while ($this->_trans_depth !== 0);
}
@@ -813,24 +819,16 @@ abstract class CI_DB_driver {
* Start Transaction
*
* @param bool $test_mode = FALSE
- * @return void
+ * @return bool
*/
public function trans_start($test_mode = FALSE)
{
if ( ! $this->trans_enabled)
{
- return;
- }
-
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ($this->_trans_depth > 0)
- {
- $this->_trans_depth += 1;
- return;
+ return FALSE;
}
- $this->trans_begin($test_mode);
- $this->_trans_depth += 1;
+ return $this->trans_begin($test_mode);
}
// --------------------------------------------------------------------
@@ -847,17 +845,6 @@ abstract class CI_DB_driver {
return FALSE;
}
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ($this->_trans_depth > 1)
- {
- $this->_trans_depth -= 1;
- return TRUE;
- }
- else
- {
- $this->_trans_depth = 0;
- }
-
// The query() function will set this flag to FALSE in the event that a query failed
if ($this->_trans_status === FALSE OR $this->_trans_failure === TRUE)
{
@@ -875,8 +862,7 @@ abstract class CI_DB_driver {
return FALSE;
}
- $this->trans_commit();
- return TRUE;
+ return $this->trans_commit();
}
// --------------------------------------------------------------------
@@ -894,6 +880,87 @@ abstract class CI_DB_driver {
// --------------------------------------------------------------------
/**
+ * Begin Transaction
+ *
+ * @param bool $test_mode
+ * @return bool
+ */
+ public function trans_begin($test_mode = FALSE)
+ {
+ if ( ! $this->trans_enabled)
+ {
+ return FALSE;
+ }
+ // When transactions are nested we only begin/commit/rollback the outermost ones
+ elseif ($this->_trans_depth > 0)
+ {
+ $this->_trans_depth++;
+ return TRUE;
+ }
+
+ // Reset the transaction failure flag.
+ // If the $test_mode flag is set to TRUE transactions will be rolled back
+ // even if the queries produce a successful result.
+ $this->_trans_failure = ($test_mode === TRUE);
+
+ if ($this->_trans_begin())
+ {
+ $this->_trans_depth++;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Commit Transaction
+ *
+ * @return bool
+ */
+ public function trans_commit()
+ {
+ if ( ! $this->trans_enabled OR $this->_trans_depth === 0)
+ {
+ return FALSE;
+ }
+ // When transactions are nested we only begin/commit/rollback the outermost ones
+ elseif ($this->_trans_depth > 1 OR $this->_trans_commit())
+ {
+ $this->_trans_depth--;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Rollback Transaction
+ *
+ * @return bool
+ */
+ public function trans_rollback()
+ {
+ if ( ! $this->trans_enabled OR $this->_trans_depth === 0)
+ {
+ return FALSE;
+ }
+ // When transactions are nested we only begin/commit/rollback the outermost ones
+ elseif ($this->_trans_depth > 1 OR $this->_trans_rollback())
+ {
+ $this->_trans_depth--;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Compile Bindings
*
* @param string the sql statement
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index dde285598..f9cf76a14 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -239,7 +239,13 @@ abstract class CI_DB_forge {
*/
public function add_key($key, $primary = FALSE)
{
- if (is_array($key))
+ // DO NOT change this! This condition is only applicable
+ // for PRIMARY keys because you can only have one such,
+ // and therefore all fields you add to it will be included
+ // in the same, composite PRIMARY KEY.
+ //
+ // It's not the same for regular indexes.
+ if ($primary === TRUE && is_array($key))
{
foreach ($key as $one)
{
diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php
index f80b4db54..65f4adb3f 100644
--- a/system/database/drivers/cubrid/cubrid_driver.php
+++ b/system/database/drivers/cubrid/cubrid_driver.php
@@ -187,25 +187,17 @@ class CI_DB_cubrid_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if (($autocommit = cubrid_get_autocommit($this->conn_id)) === NULL)
{
- return TRUE;
+ return FALSE;
}
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
- if (cubrid_get_autocommit($this->conn_id))
+ elseif ($autocommit === TRUE)
{
- cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_FALSE);
+ return cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_FALSE);
}
return TRUE;
@@ -218,19 +210,16 @@ class CI_DB_cubrid_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if ( ! cubrid_commit($this->conn_id))
{
- return TRUE;
+ return FALSE;
}
- cubrid_commit($this->conn_id);
-
if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id))
{
- cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE);
+ return cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE);
}
return TRUE;
@@ -243,16 +232,13 @@ class CI_DB_cubrid_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if ( ! cubrid_rollback($this->conn_id))
{
- return TRUE;
+ return FALSE;
}
- cubrid_rollback($this->conn_id);
-
if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id))
{
cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE);
diff --git a/system/database/drivers/ibase/ibase_driver.php b/system/database/drivers/ibase/ibase_driver.php
index 529c320cd..82550d51b 100644
--- a/system/database/drivers/ibase/ibase_driver.php
+++ b/system/database/drivers/ibase/ibase_driver.php
@@ -134,24 +134,16 @@ class CI_DB_ibase_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if (($trans_handle = ibase_trans($this->conn_id)) === FALSE)
{
- return TRUE;
+ return FALSE;
}
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
- $this->_ibase_trans = ibase_trans($this->conn_id);
-
+ $this->_ibase_trans = $trans_handle;
return TRUE;
}
@@ -162,15 +154,15 @@ class CI_DB_ibase_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans->depth > 0)
+ if (ibase_commit($this->_ibase_trans))
{
+ $this->_ibase_trans = NULL;
return TRUE;
}
- return ibase_commit($this->_ibase_trans);
+ return FALSE;
}
// --------------------------------------------------------------------
@@ -180,15 +172,15 @@ class CI_DB_ibase_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if (ibase_rollback($this->_ibase_trans))
{
+ $this->_ibase_trans = NULL;
return TRUE;
}
- return ibase_rollback($this->_ibase_trans);
+ return FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 05e5418c3..883973ae1 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -182,22 +182,10 @@ class CI_DB_mssql_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
return $this->simple_query('BEGIN TRAN');
}
@@ -208,14 +196,8 @@ class CI_DB_mssql_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return $this->simple_query('COMMIT TRAN');
}
@@ -226,14 +208,8 @@ class CI_DB_mssql_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return $this->simple_query('ROLLBACK TRAN');
}
diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php
index df0f24920..9c630d0d6 100644
--- a/system/database/drivers/mysql/mysql_driver.php
+++ b/system/database/drivers/mysql/mysql_driver.php
@@ -272,25 +272,12 @@ class CI_DB_mysql_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
$this->simple_query('SET AUTOCOMMIT=0');
- $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
- return TRUE;
+ return $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
}
// --------------------------------------------------------------------
@@ -300,17 +287,15 @@ class CI_DB_mysql_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if ($this->simple_query('COMMIT'))
{
+ $this->simple_query('SET AUTOCOMMIT=1');
return TRUE;
}
- $this->simple_query('COMMIT');
- $this->simple_query('SET AUTOCOMMIT=1');
- return TRUE;
+ return FALSE;
}
// --------------------------------------------------------------------
@@ -320,17 +305,15 @@ class CI_DB_mysql_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if ($this->simple_query('ROLLBACK'))
{
+ $this->simple_query('SET AUTOCOMMIT=1');
return TRUE;
}
- $this->simple_query('ROLLBACK');
- $this->simple_query('SET AUTOCOMMIT=1');
- return TRUE;
+ return FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index dd3cc77c6..827470078 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -291,22 +291,10 @@ class CI_DB_mysqli_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
$this->conn_id->autocommit(FALSE);
return is_php('5.5')
? $this->conn_id->begin_transaction()
@@ -320,14 +308,8 @@ class CI_DB_mysqli_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
if ($this->conn_id->commit())
{
$this->conn_id->autocommit(TRUE);
@@ -344,14 +326,8 @@ class CI_DB_mysqli_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
if ($this->conn_id->rollback())
{
$this->conn_id->autocommit(TRUE);
diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php
index f2e40da9b..916ddeb90 100644
--- a/system/database/drivers/oci8/oci8_driver.php
+++ b/system/database/drivers/oci8/oci8_driver.php
@@ -378,27 +378,10 @@ class CI_DB_oci8_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- if ( ! $this->trans_enabled)
- {
- return TRUE;
- }
-
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ($this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
$this->commit_mode = is_php('5.3.2') ? OCI_NO_AUTO_COMMIT : OCI_DEFAULT;
return TRUE;
}
@@ -410,20 +393,10 @@ class CI_DB_oci8_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- if ( ! $this->trans_enabled)
- {
- return TRUE;
- }
-
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ($this->_trans_depth > 0)
- {
- return TRUE;
- }
-
$this->commit_mode = OCI_COMMIT_ON_SUCCESS;
+
return oci_commit($this->conn_id);
}
@@ -434,14 +407,8 @@ class CI_DB_oci8_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
$this->commit_mode = OCI_COMMIT_ON_SUCCESS;
return oci_rollback($this->conn_id);
}
diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php
index f5d77a147..409284b44 100644
--- a/system/database/drivers/odbc/odbc_driver.php
+++ b/system/database/drivers/odbc/odbc_driver.php
@@ -143,22 +143,10 @@ class CI_DB_odbc_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
return odbc_autocommit($this->conn_id, FALSE);
}
@@ -169,17 +157,15 @@ class CI_DB_odbc_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if (odbc_commit($this->conn_id))
{
+ odbc_autocommit($this->conn_id, TRUE);
return TRUE;
}
- $ret = odbc_commit($this->conn_id);
- odbc_autocommit($this->conn_id, TRUE);
- return $ret;
+ return FALSE;
}
// --------------------------------------------------------------------
@@ -189,17 +175,15 @@ class CI_DB_odbc_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
+ if (odbc_rollback($this->conn_id))
{
+ odbc_autocommit($this->conn_id, TRUE);
return TRUE;
}
- $ret = odbc_rollback($this->conn_id);
- odbc_autocommit($this->conn_id, TRUE);
- return $ret;
+ return FALSE;
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index cc77e9568..8c5a5e7e3 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -186,22 +186,10 @@ class CI_DB_pdo_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
return $this->conn_id->beginTransaction();
}
@@ -212,14 +200,8 @@ class CI_DB_pdo_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return $this->conn_id->commit();
}
@@ -230,14 +212,8 @@ class CI_DB_pdo_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return $this->conn_id->rollBack();
}
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 7be07c3bf..b1df326f7 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -247,22 +247,10 @@ class CI_DB_postgre_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
return (bool) pg_query($this->conn_id, 'BEGIN');
}
@@ -273,14 +261,8 @@ class CI_DB_postgre_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return (bool) pg_query($this->conn_id, 'COMMIT');
}
@@ -291,14 +273,8 @@ class CI_DB_postgre_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return (bool) pg_query($this->conn_id, 'ROLLBACK');
}
diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php
index 9d9caa0b4..e000a8e50 100644
--- a/system/database/drivers/sqlite/sqlite_driver.php
+++ b/system/database/drivers/sqlite/sqlite_driver.php
@@ -122,24 +122,11 @@ class CI_DB_sqlite_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
- $this->simple_query('BEGIN TRANSACTION');
- return TRUE;
+ return $this->simple_query('BEGIN TRANSACTION');
}
// --------------------------------------------------------------------
@@ -149,16 +136,9 @@ class CI_DB_sqlite_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- $this->simple_query('COMMIT');
- return TRUE;
+ return $this->simple_query('COMMIT');
}
// --------------------------------------------------------------------
@@ -168,16 +148,9 @@ class CI_DB_sqlite_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- $this->simple_query('ROLLBACK');
- return TRUE;
+ return $this->simple_query('ROLLBACK');
}
// --------------------------------------------------------------------
diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php
index 31e37de91..73e453785 100644
--- a/system/database/drivers/sqlite3/sqlite3_driver.php
+++ b/system/database/drivers/sqlite3/sqlite3_driver.php
@@ -134,22 +134,10 @@ class CI_DB_sqlite3_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
return $this->conn_id->exec('BEGIN TRANSACTION');
}
@@ -160,14 +148,8 @@ class CI_DB_sqlite3_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return $this->conn_id->exec('END TRANSACTION');
}
@@ -178,14 +160,8 @@ class CI_DB_sqlite3_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return $this->conn_id->exec('ROLLBACK');
}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php
index 8d383b274..414669a4b 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_driver.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php
@@ -197,22 +197,10 @@ class CI_DB_sqlsrv_driver extends CI_DB {
/**
* Begin Transaction
*
- * @param bool $test_mode
* @return bool
*/
- public function trans_begin($test_mode = FALSE)
+ protected function _trans_begin()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
- // Reset the transaction failure flag.
- // If the $test_mode flag is set to TRUE transactions will be rolled back
- // even if the queries produce a successful result.
- $this->_trans_failure = ($test_mode === TRUE);
-
return sqlsrv_begin_transaction($this->conn_id);
}
@@ -223,14 +211,8 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*
* @return bool
*/
- public function trans_commit()
+ protected function _trans_commit()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return sqlsrv_commit($this->conn_id);
}
@@ -241,14 +223,8 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*
* @return bool
*/
- public function trans_rollback()
+ protected function _trans_rollback()
{
- // When transactions are nested we only begin/commit/rollback the outermost ones
- if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
- {
- return TRUE;
- }
-
return sqlsrv_rollback($this->conn_id);
}
@@ -275,9 +251,7 @@ class CI_DB_sqlsrv_driver extends CI_DB {
*/
public function insert_id()
{
- $query = $this->query('SELECT @@IDENTITY AS insert_id');
- $query = $query->row();
- return $query->insert_id;
+ return $this->query('SELECT SCOPE_IDENTITY() AS insert_id')->row()->insert_id;
}
// --------------------------------------------------------------------
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index 201987ac8..85bcfb5a0 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -125,9 +125,94 @@ if ( ! function_exists('create_captcha'))
if (empty($word))
{
$word = '';
- for ($i = 0, $mt_rand_max = strlen($pool) - 1; $i < $word_length; $i++)
+ $pool_length = strlen($pool);
+ $rand_max = $pool_length - 1;
+
+ // PHP7 or a suitable polyfill
+ if (function_exists('random_int'))
+ {
+ try
+ {
+ for ($i = 0; $i < $word_length; $i++)
+ {
+ $word .= $pool[random_int(0, $rand_max)];
+ }
+ }
+ catch (Exception $e)
+ {
+ // This means fallback to the next possible
+ // alternative to random_int()
+ $word = '';
+ }
+ }
+ }
+
+ if (empty($word))
+ {
+ // Nobody will have a larger character pool than
+ // 256 characters, but let's handle it just in case ...
+ //
+ // No, I do not care that the fallback to mt_rand() can
+ // handle it; if you trigger this, you're very obviously
+ // trying to break it. -- Narf
+ if ($pool_length > 256)
+ {
+ return FALSE;
+ }
+
+ // We'll try using the operating system's PRNG first,
+ // which we can access through CI_Security::get_random_bytes()
+ $security = get_instance()->security;
+
+ // To avoid numerous get_random_bytes() calls, we'll
+ // just try fetching as much bytes as we need at once.
+ if (($bytes = $security->get_random_bytes($pool_length)) !== FALSE)
+ {
+ $byte_index = $word_index = 0;
+ while ($word_index < $word_length)
+ {
+ if (($rand_index = unpack('C', $bytes[$byte_index++])) > $rand_max)
+ {
+ // Was this the last byte we have?
+ // If so, try to fetch more.
+ if ($byte_index === $pool_length)
+ {
+ // No failures should be possible if
+ // the first get_random_bytes() call
+ // didn't return FALSE, but still ...
+ for ($i = 0; $i < 5; $i++)
+ {
+ if (($bytes = $security->get_random_bytes($pool_length)) === FALSE)
+ {
+ continue;
+ }
+
+ $byte_index = 0;
+ break;
+ }
+
+ if ($bytes === FALSE)
+ {
+ // Sadly, this means fallback to mt_rand()
+ $word = '';
+ break;
+ }
+ }
+
+ continue;
+ }
+
+ $word .= $pool[$rand_index];
+ $word_index++;
+ }
+ }
+ }
+
+ if (empty($word))
+ {
+ for ($i = 0; $i < $word_length; $i++)
{
- $word .= $pool[mt_rand(0, $mt_rand_max)];
+ $word .= $pool[mt_rand(0, $rand_max)];
}
}
elseif ( ! is_string($word))
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index acf3629c3..ebff7567a 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -1563,11 +1563,10 @@ class CI_Email {
if ($this->charset === 'UTF-8')
{
- if (MB_ENABLED === TRUE)
- {
- return mb_encode_mimeheader($str, $this->charset, 'Q', $this->crlf);
- }
- elseif (ICONV_ENABLED === TRUE)
+ // Note: We used to have mb_encode_mimeheader() as the first choice
+ // here, but it turned out to be buggy and unreliable. DO NOT
+ // re-add it! -- Narf
+ if (ICONV_ENABLED === TRUE)
{
$output = @iconv_mime_encode('', $str,
array(
@@ -1590,6 +1589,10 @@ class CI_Email {
$chars = iconv_strlen($str, 'UTF-8');
}
+ elseif (MB_ENABLED === TRUE)
+ {
+ $chars = mb_strlen($str, 'UTF-8');
+ }
}
// We might already have this set for UTF-8
diff --git a/system/libraries/Session/drivers/Session_database_driver.php b/system/libraries/Session/drivers/Session_database_driver.php
index 1d01c2923..72b39d12d 100644
--- a/system/libraries/Session/drivers/Session_database_driver.php
+++ b/system/libraries/Session/drivers/Session_database_driver.php
@@ -159,6 +159,10 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan
if (($result = $this->_db->get()->row()) === NULL)
{
+ // PHP7 will reuse the same SessionHandler object after
+ // ID regeneration, so we need to explicitly set this to
+ // FALSE instead of relying on the default ...
+ $this->_row_exists = FALSE;
$this->_fingerprint = md5('');
return '';
}
diff --git a/tests/codeigniter/core/Common_test.php b/tests/codeigniter/core/Common_test.php
index 999b49cb3..81a185eaf 100644
--- a/tests/codeigniter/core/Common_test.php
+++ b/tests/codeigniter/core/Common_test.php
@@ -47,6 +47,11 @@ class Common_test extends CI_TestCase {
html_escape('Here is a string containing "quoted" text.'),
'Here is a string containing &quot;quoted&quot; text.'
);
+
+ $this->assertEquals(
+ html_escape(array('associative' => 'and', array('multi' => 'dimentional'))),
+ array('associative' => 'and', array('multi' => 'dimentional'))
+ );
}
} \ No newline at end of file
diff --git a/tests/codeigniter/core/Config_test.php b/tests/codeigniter/core/Config_test.php
index f125fc6e9..26a5f32f5 100644
--- a/tests/codeigniter/core/Config_test.php
+++ b/tests/codeigniter/core/Config_test.php
@@ -79,46 +79,33 @@ class Config_test extends CI_TestCase {
$old_script_name = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL;
$old_script_filename = $_SERVER['SCRIPT_FILENAME'];
$old_https = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : NULL;
+ $old_server_addr = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : NULL;
- // Setup server vars for detection
- $host = 'test.com';
- $path = '/';
- $script = 'base_test.php';
- $_SERVER['HTTP_HOST'] = $host;
- $_SERVER['SCRIPT_NAME'] = $path.$script;
- $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/'.$script;
-
- // Rerun constructor
+ // The 'Host' header is user input and must not be trusted
+ $_SERVER['HTTP_HOST'] = 'test.com';
$this->config = new $cls;
+ $this->assertEquals('http://localhost/', $this->config->base_url());
- // Test plain detected (root)
- $this->assertEquals('http://'.$host.$path, $this->config->base_url());
-
- // Rerun constructor
- $path = '/path/';
- $_SERVER['SCRIPT_NAME'] = $path.$script;
- $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/'.$path.$script;
+ // However, we may fallback to the server's IP address
+ $_SERVER['SERVER_ADDR'] = '127.0.0.1';
+ $_SERVER['SCRIPT_NAME'] = '/base_test.php';
+ $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/base_test.php';
$this->config = new $cls;
+ $this->assertEquals('http://127.0.0.1/', $this->config->base_url());
- // Test plain detected (subfolder)
- $this->assertEquals('http://'.$host.$path, $this->config->base_url());
-
- // Rerun constructor
+ // Making sure that HTTPS and URI path are also detected
$_SERVER['HTTPS'] = 'on';
+ $_SERVER['SCRIPT_NAME'] = '/path/base_test.php';
+ $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/path/base_test.php';
$this->config = new $cls;
-
- // Test secure detected
- $this->assertEquals('https://'.$host.$path, $this->config->base_url());
+ $this->assertEquals('https://127.0.0.1/path/', $this->config->base_url());
// Restore server vars
- if ($old_host === NULL) unset($_SERVER['HTTP_HOST']);
- else $_SERVER['HTTP_HOST'] = $old_host;
- if ($old_script_name === NULL) unset($_SERVER['SCRIPT_NAME']);
- else $_SERVER['SCRIPT_NAME'] = $old_script_name;
- if ($old_https === NULL) unset($_SERVER['HTTPS']);
- else $_SERVER['HTTPS'] = $old_https;
-
+ $_SERVER['HTTP_HOST'] = $old_host;
+ $_SERVER['SCRIPT_NAME'] = $old_script_name;
$_SERVER['SCRIPT_FILENAME'] = $old_script_filename;
+ $_SERVER['HTTPS'] = $old_https;
+ $_SERVER['SERVER_ADDR'] = $old_server_addr;
}
// --------------------------------------------------------------------
diff --git a/tests/codeigniter/core/Security_test.php b/tests/codeigniter/core/Security_test.php
index 52967dc2f..2ef822863 100644
--- a/tests/codeigniter/core/Security_test.php
+++ b/tests/codeigniter/core/Security_test.php
@@ -115,7 +115,7 @@ class Security_test extends CI_TestCase {
public function test_xss_clean_entity_double_encoded()
{
$input = '<a href="&#38&#35&#49&#48&#54&#38&#35&#57&#55&#38&#35&#49&#49&#56&#38&#35&#57&#55&#38&#35&#49&#49&#53&#38&#35&#57&#57&#38&#35&#49&#49&#52&#38&#35&#49&#48&#53&#38&#35&#49&#49&#50&#38&#35&#49&#49&#54&#38&#35&#53&#56&#38&#35&#57&#57&#38&#35&#49&#49&#49&#38&#35&#49&#49&#48&#38&#35&#49&#48&#50&#38&#35&#49&#48&#53&#38&#35&#49&#49&#52&#38&#35&#49&#48&#57&#38&#35&#52&#48&#38&#35&#52&#57&#38&#35&#52&#49">Clickhere</a>';
- $this->assertEquals('<a >Clickhere</a>', $this->security->xss_clean($input));
+ $this->assertEquals('<a>Clickhere</a>', $this->security->xss_clean($input));
}
// --------------------------------------------------------------------
@@ -134,7 +134,7 @@ class Security_test extends CI_TestCase {
public function test_xss_clean_js_img_removal()
{
$input = '<img src="&#38&#35&#49&#48&#54&#38&#35&#57&#55&#38&#35&#49&#49&#56&#38&#35&#57&#55&#38&#35&#49&#49&#53&#38&#35&#57&#57&#38&#35&#49&#49&#52&#38&#35&#49&#48&#53&#38&#35&#49&#49&#50&#38&#35&#49&#49&#54&#38&#35&#53&#56&#38&#35&#57&#57&#38&#35&#49&#49&#49&#38&#35&#49&#49&#48&#38&#35&#49&#48&#50&#38&#35&#49&#48&#53&#38&#35&#49&#49&#52&#38&#35&#49&#48&#57&#38&#35&#52&#48&#38&#35&#52&#57&#38&#35&#52&#49">Clickhere';
- $this->assertEquals('<img >', $this->security->xss_clean($input));
+ $this->assertEquals('<img>', $this->security->xss_clean($input));
}
// --------------------------------------------------------------------
@@ -146,7 +146,7 @@ class Security_test extends CI_TestCase {
$this->assertEquals('<fubar>', $this->security->xss_clean('<fubar>'));
$this->assertEquals(
- '<img [removed]> src="x">',
+ '<img svg=""> src="x">',
$this->security->xss_clean('<img <svg=""> src="x">')
);
@@ -160,21 +160,21 @@ class Security_test extends CI_TestCase {
public function test_xss_clean_sanitize_naughty_html_attributes()
{
- $this->assertEquals('<foo [removed]>', $this->security->xss_clean('<foo onAttribute="bar">'));
- $this->assertEquals('<foo [removed]>', $this->security->xss_clean('<foo onAttributeNoQuotes=bar>'));
- $this->assertEquals('<foo [removed]bar>', $this->security->xss_clean('<foo onAttributeWithSpaces = bar>'));
+ $this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo onAttribute="bar">'));
+ $this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo onAttributeNoQuotes=bar>'));
+ $this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo onAttributeWithSpaces = bar>'));
$this->assertEquals('<foo prefixOnAttribute="bar">', $this->security->xss_clean('<foo prefixOnAttribute="bar">'));
$this->assertEquals('<foo>onOutsideOfTag=test</foo>', $this->security->xss_clean('<foo>onOutsideOfTag=test</foo>'));
$this->assertEquals('onNoTagAtAll = true', $this->security->xss_clean('onNoTagAtAll = true'));
- $this->assertEquals('<foo [removed]>', $this->security->xss_clean('<foo fscommand=case-insensitive>'));
- $this->assertEquals('<foo [removed]>', $this->security->xss_clean('<foo seekSegmentTime=whatever>'));
+ $this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo fscommand=case-insensitive>'));
+ $this->assertEquals('<foo xss=removed>', $this->security->xss_clean('<foo seekSegmentTime=whatever>'));
$this->assertEquals(
- '<foo bar=">" baz=\'>\' [removed]>',
+ '<foo bar=">" baz=\'>\' xss=removed>',
$this->security->xss_clean('<foo bar=">" baz=\'>\' onAfterGreaterThan="quotes">')
);
$this->assertEquals(
- '<foo bar=">" baz=\'>\' [removed]>',
+ '<foo bar=">" baz=\'>\' xss=removed>',
$this->security->xss_clean('<foo bar=">" baz=\'>\' onAfterGreaterThan=noQuotes>')
);
@@ -194,7 +194,7 @@ class Security_test extends CI_TestCase {
);
$this->assertEquals(
- '<a [removed]>',
+ '<a xss=removed>',
$this->security->xss_clean('<a< onmouseover="alert(1)">')
);
@@ -204,19 +204,24 @@ class Security_test extends CI_TestCase {
);
$this->assertEquals(
- '<image src="<>" [removed]>',
+ '<image src="<>" xss=removed>',
$this->security->xss_clean('<image src="<>" onerror=\'alert(1)\'>')
);
$this->assertEquals(
- '<b [removed] [removed]>',
+ '<b xss=removed>',
$this->security->xss_clean('<b "=<= onmouseover=alert(1)>')
);
$this->assertEquals(
- '<b [removed] [removed]alert&#40;1&#41;,1>1">',
+ '<b xss=removed xss=removed>1">',
$this->security->xss_clean('<b a=<=" onmouseover="alert(1),1>1">')
);
+
+ $this->assertEquals(
+ '<b x=" onmouseover=alert&#40;1&#41;//">',
+ $this->security->xss_clean('<b "="< x=" onmouseover=alert(1)//">')
+ );
}
// --------------------------------------------------------------------
@@ -228,7 +233,7 @@ class Security_test extends CI_TestCase {
public function test_naughty_html_plus_evil_attributes()
{
$this->assertEquals(
- '&lt;svg<img &gt; src="x" [removed]>',
+ '&lt;svg<img src="x" xss=removed>',
$this->security->xss_clean('<svg<img > src="x" onerror="location=/javascript/.source+/:alert/.source+/(1)/.source">')
);
}
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 03cbeb673..f28fd8930 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -11,15 +11,31 @@ Release Date: Not Released
Version 3.0.3
=============
-Release Date: Not Released
+Release Date: October 31, 2015
+
+- **Security**
+
+ - Fixed an XSS attack vector in :doc:`Security Library <libraries/security>` method ``xss_clean()``.
+ - Changed :doc:`Config Library <libraries/config>` method ``base_url()`` to fallback to ``$_SERVER['SERVER_ADDR']`` when ``$config['base_url']`` is empty in order to avoid *Host* header injections.
+ - Changed :doc:`CAPTCHA Helper <helpers/captcha_helper>` to use the operating system's PRNG when possible.
- Database
- Optimized :doc:`Database Utility <database/utilities>` method ``csv_from_result()`` for speed with larger result sets.
+ - Added proper return values to :doc:`Database Transactions <database/transactions>` method ``trans_start()``.
Bug fixes for 3.0.3
-------------------
+- Fixed a bug (#4170) - :doc:`Database <database/index>` method ``insert_id()`` could return an identity from the wrong scope with the 'sqlsrv' driver.
+- Fixed a bug (#4179) - :doc:`Session Library <libraries/sessions>` doesn't properly maintain its state after ID regeneration with the 'database' driver on PHP7.
+- Fixed a bug (#4173) - :doc:`Database Forge <database/forge>` method ``add_key()`` didn't allow creation of non-PRIMARY composite keys after the "bugfix" for #3968.
+- Fixed a bug (#4171) - :doc:`Database Transactions <database/transactions>` didn't work with nesting in methods ``trans_begin()``, ``trans_commit()``, ``trans_rollback()``.
+- Fixed a bug where :doc:`Database Transaction <database/transactions>` methods ``trans_begin()``, ``trans_commit()``, ``trans_rollback()`` ignored failures.
+- Fixed a bug where all :doc:`Database Transaction <database/transactions>` methods returned TRUE while transactions are actually disabled.
+- Fixed a bug where :doc:`common function <general/common_functions>` :php:func:`html_escape()` modified keys of its array inputs.
+- Fixed a bug (#4192) - :doc:`Email Library <libraries/email>` wouldn't always have proper Quoted-printable encoding due to a bug in PHP's own ``mb_mime_encodeheader()`` function.
+
Version 3.0.2
=============
diff --git a/user_guide_src/source/database/db_driver_reference.rst b/user_guide_src/source/database/db_driver_reference.rst
index ea692515c..8fc26c01b 100644
--- a/user_guide_src/source/database/db_driver_reference.rst
+++ b/user_guide_src/source/database/db_driver_reference.rst
@@ -140,13 +140,15 @@ This article is intended to be a reference for them.
.. php:method:: trans_start([$test_mode = FALSE])
:param bool $test_mode: Test mode flag
- :rtype: void
+ :returns: TRUE on success, FALSE on failure
+ :rtype: bool
Start a transaction.
.. php:method:: trans_complete()
- :rtype: void
+ :returns: TRUE on success, FALSE on failure
+ :rtype: bool
Complete Transaction.
diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst
index 9c3ff306f..5d9ae4592 100644
--- a/user_guide_src/source/database/query_builder.rst
+++ b/user_guide_src/source/database/query_builder.rst
@@ -1018,7 +1018,7 @@ Here's a usage example::
.. note:: The following statements can be cached: select, from, join,
- where, like, group_by, having, order_by, set
+ where, like, group_by, having, order_by
***********************
diff --git a/user_guide_src/source/installation/downloads.rst b/user_guide_src/source/installation/downloads.rst
index d3081719f..c5ce2e836 100644
--- a/user_guide_src/source/installation/downloads.rst
+++ b/user_guide_src/source/installation/downloads.rst
@@ -2,8 +2,10 @@
Downloading CodeIgniter
#######################
+<<<<<<< HEAD
- `CodeIgniter v3.1.0-dev (Current version) <https://codeload.github.com/bcit-ci/CodeIgniter/zip/develop>`_
-- `CodeIgniter v3.0.3-dev <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0-stable>`_
+- `CodeIgniter v3.0.4-dev <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0-stable>`_
+- `CodeIgniter v3.0.3 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0.3>`_
- `CodeIgniter v3.0.2 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0.2>`_
- `CodeIgniter v3.0.1 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0.1>`_
- `CodeIgniter v3.0.0 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0.0>`_
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index 4b3b408a7..a29f400f8 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -464,8 +464,51 @@ files and error messages format:
Therefore you're encouraged to update its usage sooner rather than
later.
+************************************************************
+Step 19: Make sure your 'base_url' config value is not empty
+************************************************************
+
+When ``$config['base_url']`` is not set, CodeIgniter tries to automatically
+detect what your website's base URL is. This is done purely for convenience
+when you are starting development of a new application.
+
+Auto-detection is never reliable and also has security implications, which
+is why you should **always** have it manually configured!
+
+One of the changes in CodeIgniter 3.0.3 is how this auto-detection works,
+and more specifically it now falls back to the server's IP address instead
+of the hostname requested by the client. Therefore, if you've ever relied
+on auto-detection, it will change how your website works now.
+
+In case you need to allow e.g. multiple domains, or both http:// and
+https:// prefixes to be dynamically used depending on the request,
+remember that *application/config/config.php* is still a PHP script, in
+which you can create this logic with a few lines of code. For example::
+
+ $allowed_domains = array('domain1.tld', 'domain2.tld');
+ $default_domain = 'domain1.tld';
+
+ if (in_array($_SERVER['HTTP_HOST'], $allowed_domains, TRUE))
+ {
+ $domain = $_SERVER['HTTP_HOST'];
+ }
+ else
+ {
+ $domain = $default_domain;
+ }
+
+ if ( ! empty($_SERVER['HTTPS']))
+ {
+ $config['base_url'] = 'https://'.$domain;
+ }
+ else
+ {
+ $config['base_url'] = 'http://'.$domain;
+ }
+
+
****************************************************************
-Step 19: Remove usage of (previously) deprecated functionalities
+Step 20: Remove usage of (previously) deprecated functionalities
****************************************************************
In addition to the ``$autoload['core']`` configuration setting, there's a
diff --git a/user_guide_src/source/installation/upgrade_303.rst b/user_guide_src/source/installation/upgrade_303.rst
index a98eed0d4..d13a0fe46 100644
--- a/user_guide_src/source/installation/upgrade_303.rst
+++ b/user_guide_src/source/installation/upgrade_303.rst
@@ -11,4 +11,45 @@ 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. \ No newline at end of file
+ please make copies of them first.
+
+Step 2: Make sure your 'base_url' config value is not empty
+===========================================================
+
+When ``$config['base_url']`` is not set, CodeIgniter tries to automatically
+detect what your website's base URL is. This is done purely for convenience
+when you are starting development of a new application.
+
+Auto-detection is never reliable and also has security implications, which
+is why you should **always** have it manually configured!
+
+One of the changes in CodeIgniter 3.0.3 is how this auto-detection works,
+and more specifically it now falls back to the server's IP address instead
+of the hostname requested by the client. Therefore, if you've ever relied
+on auto-detection, it will change how your website works now.
+
+In case you need to allow e.g. multiple domains, or both http:// and
+https:// prefixes to be dynamically used depending on the request,
+remember that *application/config/config.php* is still a PHP script, in
+which you can create this logic with a few lines of code. For example::
+
+ $allowed_domains = array('domain1.tld', 'domain2.tld');
+ $default_domain = 'domain1.tld';
+
+ if (in_array($_SERVER['HTTP_HOST'], $allowed_domains, TRUE))
+ {
+ $domain = $_SERVER['HTTP_HOST'];
+ }
+ else
+ {
+ $domain = $default_domain;
+ }
+
+ if ( ! empty($_SERVER['HTTPS']))
+ {
+ $config['base_url'] = 'https://'.$domain;
+ }
+ else
+ {
+ $config['base_url'] = 'http://'.$domain;
+ }
diff --git a/user_guide_src/source/installation/upgrade_304.rst b/user_guide_src/source/installation/upgrade_304.rst
new file mode 100644
index 000000000..4d5bd2bb0
--- /dev/null
+++ b/user_guide_src/source/installation/upgrade_304.rst
@@ -0,0 +1,14 @@
+#############################
+Upgrading from 3.0.3 to 3.0.4
+#############################
+
+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 de2877165..2a3b0b047 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.0.x to 3.1.x <upgrade_310>
+ Upgrading from 3.0.3 to 3.0.4 <upgrade_304>
Upgrading from 3.0.2 to 3.0.3 <upgrade_303>
Upgrading from 3.0.1 to 3.0.2 <upgrade_302>
Upgrading from 3.0.0 to 3.0.1 <upgrade_301>