diff options
20 files changed, 196 insertions, 94 deletions
diff --git a/.gitignore b/.gitignore index f6e8e993b..269044ea9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,11 @@ application/cache/* !application/cache/index.html -!application/cache/.htaccess application/logs/* !application/logs/index.html -!application/logs/.htaccess + +!application/*/.htaccess composer.lock @@ -28,4 +28,4 @@ user_guide_src/cilexer/pycilexer.egg-info/* *.sublime-workspace *.sublime-project /tests/tests/ -/tests/results/
\ No newline at end of file +/tests/results/ diff --git a/application/cache/.htaccess b/application/cache/.htaccess deleted file mode 100644 index 6c63ed4c4..000000000 --- a/application/cache/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ -<IfModule authz_core_module> - Require all denied -</IfModule> -<IfModule !authz_core_module> - Deny from all -</IfModule>
\ No newline at end of file diff --git a/system/core/Loader.php b/system/core/Loader.php index 6374558ad..580145231 100644 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -1027,6 +1027,26 @@ class CI_Loader { return $this->_ci_load_stock_library($class, $subdir, $params, $object_name); } + // Safety: Was the class already loaded by a previous call? + if (class_exists($class, FALSE)) + { + $property = $object_name; + if (empty($property)) + { + $property = strtolower($class); + isset($this->_ci_varmap[$property]) && $property = $this->_ci_varmap[$property]; + } + + $CI =& get_instance(); + if (isset($CI->$property)) + { + log_message('debug', $class.' class already loaded. Second attempt ignored.'); + return; + } + + return $this->_ci_init_library($class, '', $params, $object_name); + } + // Let's search for the requested library file and load it. foreach ($this->_ci_library_paths as $path) { @@ -1037,27 +1057,8 @@ class CI_Loader { } $filepath = $path.'libraries/'.$subdir.$class.'.php'; - - // Safety: Was the class already loaded by a previous call? - if (class_exists($class, FALSE)) - { - // Before we deem this to be a duplicate request, let's see - // if a custom object name is being supplied. If so, we'll - // return a new instance of the object - if ($object_name !== NULL) - { - $CI =& get_instance(); - if ( ! isset($CI->$object_name)) - { - return $this->_ci_init_library($class, '', $params, $object_name); - } - } - - log_message('debug', $class.' class already loaded. Second attempt ignored.'); - return; - } // Does the file exist? No? Bummer... - elseif ( ! file_exists($filepath)) + if ( ! file_exists($filepath)) { continue; } @@ -1102,16 +1103,17 @@ class CI_Loader { $prefix = config_item('subclass_prefix'); } - // Before we deem this to be a duplicate request, let's see - // if a custom object name is being supplied. If so, we'll - // return a new instance of the object - if ($object_name !== NULL) + $property = $object_name; + if (empty($property)) { - $CI =& get_instance(); - if ( ! isset($CI->$object_name)) - { - return $this->_ci_init_library($library_name, $prefix, $params, $object_name); - } + $property = strtolower($library_name); + isset($this->_ci_varmap[$property]) && $property = $this->_ci_varmap[$property]; + } + + $CI =& get_instance(); + if ( ! isset($CI->$property)) + { + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); } log_message('debug', $library_name.' class already loaded. Second attempt ignored.'); @@ -1133,10 +1135,8 @@ class CI_Loader { { return $this->_ci_init_library($library_name, $prefix, $params, $object_name); } - else - { - log_message('debug', $path.' exists, but does not declare '.$prefix.$library_name); - } + + log_message('debug', $path.' exists, but does not declare '.$prefix.$library_name); } } @@ -1154,10 +1154,8 @@ class CI_Loader { $prefix = config_item('subclass_prefix'); break; } - else - { - log_message('debug', $path.' exists, but does not declare '.$subclass); - } + + log_message('debug', $path.' exists, but does not declare '.$subclass); } } diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php index e04525de3..54740c309 100644 --- a/system/database/DB_driver.php +++ b/system/database/DB_driver.php @@ -854,6 +854,7 @@ abstract class CI_DB_driver { if ($this->_trans_begin()) { + $this->_trans_status = TRUE; $this->_trans_depth++; return TRUE; } diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php index 3ff94be8e..e7b66ac80 100644 --- a/system/database/DB_query_builder.php +++ b/system/database/DB_query_builder.php @@ -1475,11 +1475,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver { // ORDER BY usage is often problematic here (most notably // on Microsoft SQL Server) and ultimately unnecessary // for selecting COUNT(*) ... - if ( ! empty($this->qb_orderby)) - { - $orderby = $this->qb_orderby; - $this->qb_orderby = NULL; - } + $qb_orderby = $this->qb_orderby; + $qb_cache_orderby = $this->qb_cache_orderby; + $this->qb_orderby = $this->qb_cache_orderby = NULL; $result = ($this->qb_distinct === TRUE OR ! empty($this->qb_groupby) OR ! empty($this->qb_cache_groupby) OR $this->qb_limit OR $this->qb_offset) ? $this->query($this->_count_string.$this->protect_identifiers('numrows')."\nFROM (\n".$this->_compile_select()."\n) CI_count_all_results") @@ -1489,10 +1487,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver { { $this->_reset_select(); } - // If we've previously reset the qb_orderby values, get them back - elseif ( ! isset($this->qb_orderby)) + else { - $this->qb_orderby = $orderby; + $this->qb_orderby = $qb_orderby; + $this->qb_cache_orderby = $qb_cache_orderby; } if ($result->num_rows() === 0) diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php index e91a817b6..234be6786 100644 --- a/system/database/drivers/mssql/mssql_driver.php +++ b/system/database/drivers/mssql/mssql_driver.php @@ -441,7 +441,7 @@ class CI_DB_mssql_driver extends CI_DB { $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results - if (count($this->qb_select) === 0) + if (count($this->qb_select) === 0 OR strpos(implode(',', $this->qb_select), '*') !== FALSE) { $select = '*'; // Inevitable } diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php index 929c2b455..0b3d9c2b4 100644 --- a/system/database/drivers/mysqli/mysqli_result.php +++ b/system/database/drivers/mysqli/mysqli_result.php @@ -112,9 +112,9 @@ class CI_DB_mysqli_result extends CI_DB_result { { $retval[$i] = new stdClass(); $retval[$i]->name = $field_data[$i]->name; - $retval[$i]->type = $field_data[$i]->type; + $retval[$i]->type = static::_get_field_type($field_data[$i]->type); $retval[$i]->max_length = $field_data[$i]->max_length; - $retval[$i]->primary_key = (int) ($field_data[$i]->flags & 2); + $retval[$i]->primary_key = (int) ($field_data[$i]->flags & MYSQLI_PRI_KEY_FLAG); $retval[$i]->default = $field_data[$i]->def; } @@ -124,6 +124,60 @@ class CI_DB_mysqli_result extends CI_DB_result { // -------------------------------------------------------------------- /** + * Get field type + * + * Extracts field type info from the bitflags returned by + * mysqli_result::fetch_fields() + * + * @used-by CI_DB_mysqli_result::field_data() + * @param int $flags + * @return string + */ + private static function _get_field_type($flags) + { + static $map; + isset($map) OR $map = array( + MYSQLI_TYPE_DECIMAL => 'decimal', + MYSQLI_TYPE_BIT => 'bit', + MYSQLI_TYPE_TINY => 'tinyint', + MYSQLI_TYPE_SHORT => 'smallint', + MYSQLI_TYPE_INT24 => 'mediumint', + MYSQLI_TYPE_LONG => 'int', + MYSQLI_TYPE_LONGLONG => 'bigint', + MYSQLI_TYPE_FLOAT => 'float', + MYSQLI_TYPE_DOUBLE => 'double', + MYSQLI_TYPE_TIMESTAMP => 'timestamp', + MYSQLI_TYPE_DATE => 'date', + MYSQLI_TYPE_TIME => 'time', + MYSQLI_TYPE_DATETIME => 'datetime', + MYSQLI_TYPE_YEAR => 'year', + MYSQLI_TYPE_NEWDATE => 'date', + MYSQLI_TYPE_INTERVAL => 'interval', + MYSQLI_TYPE_ENUM => 'enum', + MYSQLI_TYPE_SET => 'set', + MYSQLI_TYPE_TINY_BLOB => 'tinyblob', + MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob', + MYSQLI_TYPE_BLOB => 'blob', + MYSQLI_TYPE_LONG_BLOB => 'longblob', + MYSQLI_TYPE_STRING => 'char', + MYSQLI_TYPE_VAR_STRING => 'varchar', + MYSQLI_TYPE_GEOMETRY => 'geometry' + ); + + foreach ($map as $flag => $name) + { + if ($flags & $flag) + { + return $name; + } + } + + return $flags; + } + + // -------------------------------------------------------------------- + + /** * Free the result * * @return void diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php index 4a3dad4d1..1699b611f 100644 --- a/system/database/drivers/mysqli/mysqli_utility.php +++ b/system/database/drivers/mysqli/mysqli_utility.php @@ -155,9 +155,11 @@ class CI_DB_mysqli_utility extends CI_DB_utility { while ($field = $query->result_id->fetch_field()) { // Most versions of MySQL store timestamp as a string - $is_int[$i] = in_array(strtolower($field->type), - array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), - TRUE); + $is_int[$i] = ($field->type & MYSQLI_TYPE_TINY) + OR ($field->type & MYSQLI_TYPE_SHORT) + OR ($field->type & MYSQLI_TYPE_INT24) + OR ($field->type & MYSQLI_TYPE_LONG) + OR ($field->type & MYSQLI_TYPE_LONGLONG); // Create a string of field names $field_str .= $this->db->escape_identifiers($field->name).', '; diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php index fbd279681..b9b86f784 100644 --- a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php +++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php @@ -284,7 +284,7 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver { $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results - if (count($this->qb_select) === 0) + if (count($this->qb_select) === 0 OR strpos(implode(',', $this->qb_select), '*') !== FALSE) { $select = '*'; // Inevitable } diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php index 07c429eec..a9fb4d14a 100644 --- a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php +++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php @@ -316,7 +316,7 @@ class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver { $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results - if (count($this->qb_select) === 0) + if (count($this->qb_select) === 0 OR strpos(implode(',', $this->qb_select), '*') !== FALSE) { $select = '*'; // Inevitable } diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php index a43e2539a..4edcc7fb8 100644 --- a/system/database/drivers/sqlsrv/sqlsrv_driver.php +++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php @@ -478,7 +478,7 @@ class CI_DB_sqlsrv_driver extends CI_DB { $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results - if (count($this->qb_select) === 0) + if (count($this->qb_select) === 0 OR strpos(implode(',', $this->qb_select), '*') !== FALSE) { $select = '*'; // Inevitable } diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php index f2b61adb1..c873eb640 100644 --- a/system/libraries/Cache/drivers/Cache_apc.php +++ b/system/libraries/Cache/drivers/Cache_apc.php @@ -80,14 +80,7 @@ class CI_Cache_apc extends CI_Driver { $success = FALSE; $data = apc_fetch($id, $success); - if ($success === TRUE) - { - return is_array($data) - ? unserialize($data[0]) - : $data; - } - - return FALSE; + return ($success === TRUE) ? $data : FALSE; } // ------------------------------------------------------------------------ @@ -98,18 +91,12 @@ class CI_Cache_apc extends CI_Driver { * @param string $id Cache ID * @param mixed $data Data to store * @param int $ttl Length of time (in seconds) to cache the data - * @param bool $raw Whether to store the raw value + * @param bool $raw Whether to store the raw value (unused) * @return bool TRUE on success, FALSE on failure */ public function save($id, $data, $ttl = 60, $raw = FALSE) { - $ttl = (int) $ttl; - - return apc_store( - $id, - ($raw === TRUE ? $data : array(serialize($data), time(), $ttl)), - $ttl - ); + return apc_store($id, $data, (int) $ttl); } // ------------------------------------------------------------------------ @@ -188,21 +175,30 @@ class CI_Cache_apc extends CI_Driver { */ public function get_metadata($id) { - $success = FALSE; - $stored = apc_fetch($id, $success); - - if ($success === FALSE OR count($stored) !== 3) + $cache_info = apc_cache_info('user', FALSE); + if (empty($cache_info) OR empty($cache_info['cache_list'])) { return FALSE; } - list($data, $time, $ttl) = $stored; + foreach ($cache_info['cache_list'] as &$entry) + { + if ($entry['info'] !== $id) + { + continue; + } + + $success = FALSE; + $metadata = array( + 'expire' => ($entry['ttl'] ? $entry['mtime'] + $entry['ttl'] : 0), + 'mtime' => $entry['ttl'], + 'data' => apc_fetch($id, $success) + ); + + return ($success === TRUE) ? $metadata : FALSE; + } - return array( - 'expire' => $time + $ttl, - 'mtime' => $time, - 'data' => unserialize($data) - ); + return FALSE; } // ------------------------------------------------------------------------ diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php index 8b5a1adb0..60ed05766 100644 --- a/system/libraries/Image_lib.php +++ b/system/libraries/Image_lib.php @@ -972,7 +972,7 @@ class CI_Image_lib { $cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height; } - $cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp'; + $cmd = $this->library_path.$cmd_in.' '.escapeshellarg($this->full_src_path).' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp'; $retval = 1; // exec() might be disabled diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index 3a1731e58..9e8389480 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -1310,7 +1310,7 @@ class CI_Upload { } } - // Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type']) + // Fall back to mime_content_type(), if available (still better than $_FILES[$field]['type']) if (function_exists('mime_content_type')) { $this->file_type = @mime_content_type($file['tmp_name']); diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php index 3b6a7e16c..df698f30c 100644 --- a/tests/codeigniter/core/Loader_test.php +++ b/tests/codeigniter/core/Loader_test.php @@ -99,7 +99,7 @@ class Loader_test extends CI_TestCase { // Test reloading unset($this->ci_obj->$name); $this->assertInstanceOf('CI_Loader', $this->load->library($lib)); - $this->assertObjectNotHasAttribute($name, $this->ci_obj); + $this->assertObjectHasAttribute($name, $this->ci_obj); // Create baseless library $name = 'ext_baseless_lib'; diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst index 4b0a6e56a..a1321fe94 100644 --- a/user_guide_src/source/changelog.rst +++ b/user_guide_src/source/changelog.rst @@ -114,12 +114,41 @@ 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.6 +Version 3.1.7 ============= Release Date: Not Released +Version 3.1.6 +============= + +Release Date: Sep 25, 2017 + +- **Security** + + - Fixed a potential object injection in :doc:`Cache Library <libraries/caching>` 'apc' driver when ``save()`` is used with ``$raw = TRUE`` (thanks to Tomas Bortoli). + +- General Changes + + - Deprecated :doc:`Cache Library Library <libraries/caching>` driver 'apc'. + - Updated the :doc:`Session Library <libraries/sessions>` 'redis', 'memcached' drivers to reduce the potential of a locking race conditions. + + +Bug fixes for 3.1.6 +------------------- + +- Fixed a bug (#5164) - :doc:`Loader Library <libraries/loader>` method ``library()`` ignored requests to load libraries previously assigned to super-object properties named differently than the library name. +- Fixed a bug (#5168) - :doc:`Query Builder <database/query_builder>` method ``count_all_results()`` produced erroneous queries on Microsoft SQL Server when ``ORDER BY`` clauses are cached. +- Fixed a bug (#5128) - :doc:`Profiler <general/profiling>` didn't wrap ``$_SESSION`` and configuration arrays in ``<pre>`` tags. +- Fixed a bug (#5183) - :doc:`Database Library <database/index>` method ``is_write_type()`` didn't return TRUE for ``MERGE`` statements. +- Fixed a bug where :doc:`Image Manipulation Library <libraries/image_lib>` didn't escape image source paths passed to NetPBM as shell arguments. +- Fixed a bug (#5236) - :doc:`Query Builder <database/query_builder>` methods ``limit()``, ``offset()`` break SQL Server 2005, 2008 queries with ``"<tablename>".*`` in the ``SELECT`` clause. +- Fixed a bug (#5243) - :doc:`Database Library <database/index>` method ``version()`` didn't work with the 'pdo/dblib' driver. +- Fixed a bug (#5246) - :doc:`Database transactions <database/transactions>` status wasn't reset unless ``trans_complete()`` was called. +- Fixed a bug (#5260) - :doc:`Database Utilities <database/utilities>` method ``backup()`` generated incorrect ``INSERT`` statements with the 'mysqli' driver. +- Fixed a bug where :doc:`Database Results <database/results>` method ``field_data()`` didn't parse field types with the 'mysqli' driver. + Version 3.1.5 ============= diff --git a/user_guide_src/source/installation/downloads.rst b/user_guide_src/source/installation/downloads.rst index fb9222df9..337ea35d5 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.6-dev <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1-stable>`_ +- `CodeIgniter v3.1.7-dev <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1-stable>`_ +- `CodeIgniter v3.1.6 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.6>`_ - `CodeIgniter v3.1.5 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.5>`_ - `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>`_ diff --git a/user_guide_src/source/installation/upgrade_316.rst b/user_guide_src/source/installation/upgrade_316.rst index e382c20ab..1d86b5720 100644 --- a/user_guide_src/source/installation/upgrade_316.rst +++ b/user_guide_src/source/installation/upgrade_316.rst @@ -12,3 +12,17 @@ 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. + +Step 2: Remove usage of the APC Cache driver (deprecation) +========================================================== + +The :doc:`Cache Library <../libraries/caching>` APC driver is now +deprecated, as the APC extension is effectively dead, as explained in its +`PHP Manual page <https://secure.php.net/manual/en/intro.apc.php>`_. + +If your application happens to be using it, you can switch to another +cache driver, as APC support will be removed in a future CodeIgniter +version. + +.. note:: The driver is still available, but you're strongly encouraged + to remove its usage sooner rather than later. diff --git a/user_guide_src/source/installation/upgrade_317.rst b/user_guide_src/source/installation/upgrade_317.rst new file mode 100644 index 000000000..93c37b687 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_317.rst @@ -0,0 +1,14 @@ +############################# +Upgrading from 3.1.6 to 3.1.7 +############################# + +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 3383796d0..ce1d8a9aa 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.6 to 3.1.7 <upgrade_317> Upgrading from 3.1.5 to 3.1.6 <upgrade_316> Upgrading from 3.1.4 to 3.1.5 <upgrade_315> Upgrading from 3.1.3 to 3.1.4 <upgrade_314> |