diff --git a/composer.json b/composer.json index b0a10c6e..5cac0114 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,6 @@ "roave/security-advisories": "dev-master", "gregwar/captcha": "^1.1", "phpmailer/phpmailer": "^5.2", - "codeigniter/framework": "3.1.5" + "codeigniter/framework": "3.1.6" } } diff --git a/composer.lock b/composer.lock index 846a62eb..47d5f10a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "9291221da0af4f9eeb4fb70314d354f2", + "content-hash": "8c888cb85f0aee3ee5b357c38a3182e4", "packages": [ { "name": "codeigniter/framework", - "version": "3.1.5", + "version": "3.1.6", "source": { "type": "git", "url": "https://github.com/bcit-ci/CodeIgniter.git", - "reference": "6c7a4266410070d30f8f6bcdf9c9e67f3d6478e3" + "reference": "7e4f63cd4b792e7dc2dc4b8b0183a6072a3f9462" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bcit-ci/CodeIgniter/zipball/6c7a4266410070d30f8f6bcdf9c9e67f3d6478e3", - "reference": "6c7a4266410070d30f8f6bcdf9c9e67f3d6478e3", + "url": "https://api.github.com/repos/bcit-ci/CodeIgniter/zipball/7e4f63cd4b792e7dc2dc4b8b0183a6072a3f9462", + "reference": "7e4f63cd4b792e7dc2dc4b8b0183a6072a3f9462", "shasum": "" }, "require": { @@ -37,7 +37,7 @@ ], "description": "The CodeIgniter framework", "homepage": "https://codeigniter.com", - "time": "2017-06-19T08:33:58+00:00" + "time": "2017-09-25T16:43:58+00:00" }, { "name": "gregwar/captcha", diff --git a/src/system/core/CodeIgniter.php b/src/system/core/CodeIgniter.php index 823e034d..0d03293f 100644 --- a/src/system/core/CodeIgniter.php +++ b/src/system/core/CodeIgniter.php @@ -55,7 +55,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @var string * */ - const CI_VERSION = '3.1.5'; + const CI_VERSION = '3.1.6'; /* * ------------------------------------------------------ diff --git a/src/system/core/Loader.php b/src/system/core/Loader.php index 5ed6adb4..085c5b51 100644 --- a/src/system/core/Loader.php +++ b/src/system/core/Loader.php @@ -182,7 +182,7 @@ class CI_Loader { * Loads and instantiates libraries. * Designed to be called from application controllers. * - * @param string $library Library name + * @param mixed $library Library name * @param array $params Optional parameters to pass to the library class constructor * @param string $object_name An optional object name to assign to * @return object @@ -1037,6 +1037,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) { @@ -1047,27 +1067,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; } @@ -1112,16 +1113,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.'); @@ -1143,10 +1145,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); } } @@ -1164,10 +1164,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/src/system/database/DB_driver.php b/src/system/database/DB_driver.php index 3eb51f73..0b13a2f8 100644 --- a/src/system/database/DB_driver.php +++ b/src/system/database/DB_driver.php @@ -916,6 +916,7 @@ abstract class CI_DB_driver { if ($this->_trans_begin()) { + $this->_trans_status = TRUE; $this->_trans_depth++; return TRUE; } @@ -1044,7 +1045,7 @@ abstract class CI_DB_driver { */ public function is_write_type($sql) { - return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s/i', $sql); + return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX|MERGE)\s/i', $sql); } // -------------------------------------------------------------------- diff --git a/src/system/database/DB_query_builder.php b/src/system/database/DB_query_builder.php index 9216651a..81603bf3 100644 --- a/src/system/database/DB_query_builder.php +++ b/src/system/database/DB_query_builder.php @@ -1403,11 +1403,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") @@ -1417,10 +1415,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/src/system/database/drivers/mssql/mssql_driver.php b/src/system/database/drivers/mssql/mssql_driver.php index a2ccd1c8..cb89f3b3 100644 --- a/src/system/database/drivers/mssql/mssql_driver.php +++ b/src/system/database/drivers/mssql/mssql_driver.php @@ -453,7 +453,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/src/system/database/drivers/mysqli/mysqli_result.php b/src/system/database/drivers/mysqli/mysqli_result.php index 929c2b45..0b3d9c2b 100644 --- a/src/system/database/drivers/mysqli/mysqli_result.php +++ b/src/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; } @@ -123,6 +123,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 * diff --git a/src/system/database/drivers/mysqli/mysqli_utility.php b/src/system/database/drivers/mysqli/mysqli_utility.php index 4a3dad4d..1699b611 100644 --- a/src/system/database/drivers/mysqli/mysqli_utility.php +++ b/src/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/src/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/src/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php index 08243232..b9b86f78 100644 --- a/src/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php +++ b/src/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 } @@ -334,4 +334,20 @@ class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver { return ($this->db_debug) ? $this->display_error('db_unsupported_feature') : FALSE; } + // -------------------------------------------------------------------- + + /** + * Database version number + * + * @return string + */ + public function version() + { + if (isset($this->data_cache['version'])) + { + return $this->data_cache['version']; + } + + return $this->data_cache['version'] = $this->conn_id->query("SELECT SERVERPROPERTY('ProductVersion') AS ver")->fetchColumn(0); + } } diff --git a/src/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/src/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php index 07c429ee..a9fb4d14 100644 --- a/src/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php +++ b/src/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/src/system/database/drivers/sqlsrv/sqlsrv_driver.php b/src/system/database/drivers/sqlsrv/sqlsrv_driver.php index a43e2539..4edcc7fb 100644 --- a/src/system/database/drivers/sqlsrv/sqlsrv_driver.php +++ b/src/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/src/system/libraries/Cache/drivers/Cache_apc.php b/src/system/libraries/Cache/drivers/Cache_apc.php index f2b61adb..c873eb64 100644 --- a/src/system/libraries/Cache/drivers/Cache_apc.php +++ b/src/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; + } - return array( - 'expire' => $time + $ttl, - 'mtime' => $time, - 'data' => unserialize($data) - ); + $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 FALSE; } // ------------------------------------------------------------------------ diff --git a/src/system/libraries/Image_lib.php b/src/system/libraries/Image_lib.php index 88c9e7ed..8786d9d0 100644 --- a/src/system/libraries/Image_lib.php +++ b/src/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/src/system/libraries/Profiler.php b/src/system/libraries/Profiler.php index 9ea09a52..cb3eaed7 100644 --- a/src/system/libraries/Profiler.php +++ b/src/system/libraries/Profiler.php @@ -484,13 +484,19 @@ class CI_Profiler { foreach ($this->CI->config->config as $config => $val) { + $pre = ''; + $pre_close = ''; + if (is_array($val) OR is_object($val)) { $val = print_r($val, TRUE); + + $pre = '
' ;
+ 				$pre_close = '
'; } $output .= '' - .$config.'  '.htmlspecialchars($val, ENT_QUOTES, config_item('charset'))."\n"; + .$config.'  '.$pre.htmlspecialchars($val, ENT_QUOTES, config_item('charset')).$pre_close."\n"; } return $output."\n"; @@ -516,13 +522,19 @@ class CI_Profiler { foreach ($this->CI->session->userdata() as $key => $val) { + $pre = ''; + $pre_close = ''; + if (is_array($val) OR is_object($val)) { $val = print_r($val, TRUE); + + $pre = '
' ;
+ 				$pre_close = '
'; } $output .= '' - .$key.'  '.htmlspecialchars($val, ENT_QUOTES, config_item('charset'))."\n"; + .$key.'  '.$pre.htmlspecialchars($val, ENT_QUOTES, config_item('charset')).$pre_close."\n"; } return $output."\n"; diff --git a/src/system/libraries/Session/drivers/Session_memcached_driver.php b/src/system/libraries/Session/drivers/Session_memcached_driver.php index 2556bf0f..5e90539d 100644 --- a/src/system/libraries/Session/drivers/Session_memcached_driver.php +++ b/src/system/libraries/Session/drivers/Session_memcached_driver.php @@ -310,7 +310,7 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa if ( ! $this->_memcached->replace($this->_lock_key, time(), 300)) { return ($this->_memcached->getResultCode() === Memcached::RES_NOTFOUND) - ? $this->_memcached->set($this->_lock_key, time(), 300) + ? $this->_memcached->add($this->_lock_key, time(), 300) : FALSE; } } @@ -326,7 +326,8 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa continue; } - if ( ! $this->_memcached->set($lock_key, time(), 300)) + $method = ($this->_memcached->getResultCode() === Memcached::RES_NOTFOUND) ? 'add' : 'set'; + if ( ! $this->_memcached->$method($lock_key, time(), 300)) { log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id); return FALSE; diff --git a/src/system/libraries/Session/drivers/Session_redis_driver.php b/src/system/libraries/Session/drivers/Session_redis_driver.php index e220a295..a9e655a8 100644 --- a/src/system/libraries/Session/drivers/Session_redis_driver.php +++ b/src/system/libraries/Session/drivers/Session_redis_driver.php @@ -341,7 +341,11 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle continue; } - if ( ! $this->_redis->setex($lock_key, 300, time())) + $result = ($ttl === -2) + ? $this->_redis->set($lock_key, time(), array('nx', 'ex' => 300)) + : $this->_redis->setex($lock_key, 300, time()); + + if ( ! $result) { log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id); return FALSE; diff --git a/src/system/libraries/Upload.php b/src/system/libraries/Upload.php index b37cc2f5..0ad8dd37 100644 --- a/src/system/libraries/Upload.php +++ b/src/system/libraries/Upload.php @@ -1312,7 +1312,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']);