diff options
46 files changed, 605 insertions, 274 deletions
diff --git a/application/config/autoload.php b/application/config/autoload.php index 3f0bd24f2..4bc6bf0ad 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -45,8 +45,9 @@ $autoload['packages'] = array(); | ------------------------------------------------------------------- | Auto-load Libraries | ------------------------------------------------------------------- -| These are the classes located in the system/libraries folder -| or in your application/libraries folder. +| These are the classes located in system/libraries/ or your +| application/libraries/ directory, with the addition of the +| 'database' library, which is somewhat of a special case. | | Prototype: | @@ -63,8 +64,9 @@ $autoload['libraries'] = array(); | ------------------------------------------------------------------- | Auto-load Drivers | ------------------------------------------------------------------- -| These classes are located in the system/libraries folder or in your -| application/libraries folder within their own subdirectory. They +| These classes are located in system/libraries/ or in your +| application/libraries/ directory, but are also placed inside their +| own subdirectory and they extend the CI_Driver_Library class. They | offer multiple interchangeable driver options. | | Prototype: diff --git a/application/config/config.php b/application/config/config.php index 86ca312b7..a4d883fab 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -284,8 +284,15 @@ $config['cache_path'] = ''; | Cache Include Query String |-------------------------------------------------------------------------- | -| Set this to TRUE if you want to use different cache files depending on the -| URL query string. Please be aware this might result in numerous cache files. +| Whether to take the URL query string into consideration when generating +| output cache files. Valid options are: +| +| FALSE = Disabled +| TRUE = Enabled, take all query parameters into account. +| Please be aware that this may result in numerous cache +| files generated for the same page over and over again. +| array('q') = Enabled, but only take into account the specified list +| of query parameters. | */ $config['cache_query_string'] = FALSE; @@ -473,6 +480,8 @@ $config['time_reference'] = 'local'; | can rewrite the tags on-the-fly, enabling you to utilize that syntax | in your view files. Options are TRUE or FALSE (boolean) | +| Note: You need to have eval() enabled for this to work. +| */ $config['rewrite_short_tags'] = FALSE; diff --git a/application/config/database.php b/application/config/database.php index 84aab9169..bf9857fff 100644 --- a/application/config/database.php +++ b/application/config/database.php @@ -40,9 +40,21 @@ defined('BASEPATH') OR exit('No direct script access allowed'); | Sites using Latin-1 or UTF-8 database character set and collation are unaffected. | ['swap_pre'] A default table prefix that should be swapped with the dbprefix | ['encrypt'] Whether or not to use an encrypted connection. +| +| 'mysql' (deprecated), 'sqlsrv' and 'pdo/sqlsrv' drivers accept TRUE/FALSE +| 'mysqli' and 'pdo/mysql' drivers accept an array with the following options: +| +| 'ssl_key' - Path to the private key file +| 'ssl_cert' - Path to the public key certificate file +| 'ssl_ca' - Path to the certificate authority file +| 'ssl_capath' - Path to a directory containing trusted CA certificats in PEM format +| 'ssl_cipher' - List of *allowed* ciphers to be used for the encryption, separated by colons (':') +| 'ssl_verify' - TRUE/FALSE; Whether verify the server certificate or not ('mysqli' only) +| | ['compress'] Whether or not to use client compression (MySQL only) | ['stricton'] TRUE/FALSE - forces 'Strict Mode' connections | - good for ensuring strict SQL while developing +| ['ssl_options'] Used to set various SSL options that can be used when making SSL connections. | ['failover'] array - A array with 0 or more data for connections if the main should fail. | ['save_queries'] TRUE/FALSE - Whether to "save" all executed queries. | NOTE: Disabling this will also effectively disable both diff --git a/application/config/mimes.php b/application/config/mimes.php index d0e1516ff..1f591ba6b 100644 --- a/application/config/mimes.php +++ b/application/config/mimes.php @@ -154,5 +154,5 @@ return array( 'vcf' => 'text/x-vcard', 'srt' => array('text/srt', 'text/plain'), 'vtt' => array('text/vtt', 'text/plain'), - 'ico' => 'image/x-icon' + 'ico' => array('image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon') ); diff --git a/application/views/errors/cli/error_exception.php b/application/views/errors/cli/error_exception.php index 75d7f0fad..efa6a66d1 100644 --- a/application/views/errors/cli/error_exception.php +++ b/application/views/errors/cli/error_exception.php @@ -1,25 +1,21 @@ -<?php -defined('BASEPATH') OR exit('No direct script access allowed'); -?> +<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?> An uncaught Exception was encountered -Type: <?php echo get_class($exception); ?> -Message: <?php echo $message; ?> -Filename: <?php echo $exception->getFile(); ?> +Type: <?php echo get_class($exception), "\n"; ?> +Message: <?php echo $message, "\n"; ?> +Filename: <?php echo $exception->getFile(), "\n"; ?> Line Number: <?php echo $exception->getLine(); ?> <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?> Backtrace: - <?php foreach ($exception->getTrace() as $error): ?> - <?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?> +<?php foreach ($exception->getTrace() as $error): ?> +<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?> + File: <?php echo $error['file'], "\n"; ?> + Line: <?php echo $error['line'], "\n"; ?> + Function: <?php echo $error['function'], "\n\n"; ?> +<?php endif ?> +<?php endforeach ?> - File: <?php echo $error['file']; ?> - Line: <?php echo $error['line']; ?> - Function: <?php echo $error['function']; ?> - - <?php endif ?> - - <?php endforeach ?> -<?php endif ?>
\ No newline at end of file +<?php endif ?> diff --git a/application/views/errors/cli/error_php.php b/application/views/errors/cli/error_php.php index fec91e54f..8a24b6491 100644 --- a/application/views/errors/cli/error_php.php +++ b/application/views/errors/cli/error_php.php @@ -1,25 +1,21 @@ -<?php -defined('BASEPATH') OR exit('No direct script access allowed'); -?> +<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?> A PHP Error was encountered -Severity: <?php echo $severity;?> -Message: <?php echo $message;?> -Filename: <?php echo $filepath;?> -Line Number: <?php echo $line;?> +Severity: <?php echo $severity, "\n"; ?> +Message: <?php echo $message, "\n"; ?> +Filename: <?php echo $filepath, "\n"; ?> +Line Number: <?php echo $line; ?> <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?> Backtrace: - <?php foreach (debug_backtrace() as $error): ?> - <?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?> +<?php foreach (debug_backtrace() as $error): ?> +<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?> + File: <?php echo $error['file'], "\n"; ?> + Line: <?php echo $error['line'], "\n"; ?> + Function: <?php echo $error['function'], "\n\n"; ?> +<?php endif ?> +<?php endforeach ?> - File: <?php echo $error['file'];?> - Line: <?php echo $error['line'];?> - Function: <?php echo $error['function'];?> - - <?php endif ?> - - <?php endforeach ?> -<?php endif ?>
\ No newline at end of file +<?php endif ?> diff --git a/system/core/Common.php b/system/core/Common.php index b850fd39a..ce324a1cc 100644 --- a/system/core/Common.php +++ b/system/core/Common.php @@ -833,19 +833,9 @@ if ( ! function_exists('function_usable')) { if ( ! isset($_suhosin_func_blacklist)) { - if (extension_loaded('suhosin')) - { - $_suhosin_func_blacklist = explode(',', trim(ini_get('suhosin.executor.func.blacklist'))); - - if ( ! in_array('eval', $_suhosin_func_blacklist, TRUE) && ini_get('suhosin.executor.disable_eval')) - { - $_suhosin_func_blacklist[] = 'eval'; - } - } - else - { - $_suhosin_func_blacklist = array(); - } + $_suhosin_func_blacklist = extension_loaded('suhosin') + ? explode(',', trim(ini_get('suhosin.executor.func.blacklist'))) + : array(); } return ! in_array($function_name, $_suhosin_func_blacklist, TRUE); diff --git a/system/core/Loader.php b/system/core/Loader.php index 9205ad1b6..1f48c0782 100644 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -272,7 +272,7 @@ class CI_Loader { $CI =& get_instance(); if (isset($CI->$name)) { - show_error('The model name you are loading is the name of a resource that is already being used: '.$name); + throw new RuntimeException('The model name you are loading is the name of a resource that is already being used: '.$name); } if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE)) @@ -291,23 +291,37 @@ class CI_Loader { } $model = ucfirst(strtolower($model)); - - foreach ($this->_ci_model_paths as $mod_path) + if ( ! class_exists($model)) { - if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) + foreach ($this->_ci_model_paths as $mod_path) { - continue; - } + if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) + { + continue; + } - require_once($mod_path.'models/'.$path.$model.'.php'); + require_once($mod_path.'models/'.$path.$model.'.php'); + if ( ! class_exists($model, FALSE)) + { + throw new RuntimeException($mod_path."models/".$path.$model.".php exists, but doesn't declare class ".$model); + } - $this->_ci_models[] = $name; - $CI->$name = new $model(); - return $this; + break; + } + + if ( ! class_exists($model, FALSE)) + { + throw new RuntimeException('Unable to locate the model you have specified: '.$model); + } + } + elseif ( ! is_subclass_of($model, 'CI_Model')) + { + throw new RuntimeException("Class ".$model." already exists and doesn't extend CI_Model"); } - // couldn't find the model - show_error('Unable to locate the model you have specified: '.$model); + $this->_ci_models[] = $name; + $CI->$name = new $model(); + return $this; } // -------------------------------------------------------------------- @@ -905,7 +919,7 @@ class CI_Loader { // If the PHP installation does not support short tags we'll // do a little string replacement, changing the short tags // to standard PHP echo statements. - if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE && function_usable('eval')) + if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE) { echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path)))); } diff --git a/system/core/Output.php b/system/core/Output.php index e7d559a1d..76c1329d2 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -556,9 +556,16 @@ class CI_Output { .$CI->config->item('index_page') .$CI->uri->uri_string(); - if ($CI->config->item('cache_query_string') && ! empty($_SERVER['QUERY_STRING'])) + if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING'])) { - $uri .= '?'.$_SERVER['QUERY_STRING']; + if (is_array($cache_query_string)) + { + $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string))); + } + else + { + $uri .= '?'.$_SERVER['QUERY_STRING']; + } } $cache_path .= md5($uri); @@ -646,9 +653,16 @@ class CI_Output { // Build the file path. The file name is an MD5 hash of the full URI $uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string; - if ($CFG->item('cache_query_string') && ! empty($_SERVER['QUERY_STRING'])) + if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING'])) { - $uri .= '?'.$_SERVER['QUERY_STRING']; + if (is_array($cache_query_string)) + { + $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string))); + } + else + { + $uri .= '?'.$_SERVER['QUERY_STRING']; + } } $filepath = $cache_path.md5($uri); @@ -729,13 +743,20 @@ class CI_Output { { $uri = $CI->uri->uri_string(); - if ($CI->config->item('cache_query_string') && ! empty($_SERVER['QUERY_STRING'])) + if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING'])) { - $uri .= '?'.$_SERVER['QUERY_STRING']; + if (is_array($cache_query_string)) + { + $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string))); + } + else + { + $uri .= '?'.$_SERVER['QUERY_STRING']; + } } } - $cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').$uri); + $cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/')); if ( ! @unlink($cache_path)) { diff --git a/system/core/Router.php b/system/core/Router.php index 051000533..ab5246a1f 100644 --- a/system/core/Router.php +++ b/system/core/Router.php @@ -83,7 +83,7 @@ class CI_Router { * * @var string */ - public $directory = ''; + public $directory; /** * Default controller (and method if specific) @@ -126,25 +126,16 @@ class CI_Router { $this->uri =& load_class('URI', 'core'); $this->enable_query_strings = ( ! is_cli() && $this->config->item('enable_query_strings') === TRUE); + + // If a directory override is configured, it has to be set before any dynamic routing logic + is_array($routing) && isset($routing['directory']) && $this->set_directory($routing['directory']); $this->_set_routing(); // Set any routing overrides that may exist in the main index file if (is_array($routing)) { - if (isset($routing['directory'])) - { - $this->set_directory($routing['directory']); - } - - if ( ! empty($routing['controller'])) - { - $this->set_class($routing['controller']); - } - - if ( ! empty($routing['function'])) - { - $this->set_method($routing['function']); - } + empty($routing['controller']) OR $this->set_class($routing['controller']); + empty($routing['function']) OR $this->set_method($routing['function']); } log_message('info', 'Router Class Initialized'); @@ -167,12 +158,17 @@ class CI_Router { // If this feature is enabled, we will gather the directory/class/method a little differently if ($this->enable_query_strings) { - $_d = $this->config->item('directory_trigger'); - $_d = isset($_GET[$_d]) ? trim($_GET[$_d], " \t\n\r\0\x0B/") : ''; - if ($_d !== '') + // If the directory is set at this time, it means an override exists, so skip the checks + if ( ! isset($this->directory)) { - $this->uri->filter_uri($_d); - $this->set_directory($_d); + $_d = $this->config->item('directory_trigger'); + $_d = isset($_GET[$_d]) ? trim($_GET[$_d], " \t\n\r\0\x0B/") : ''; + + if ($_d !== '') + { + $this->uri->filter_uri($_d); + $this->set_directory($_d); + } } $_c = trim($this->config->item('controller_trigger')); @@ -333,6 +329,8 @@ class CI_Router { protected function _validate_request($segments) { $c = count($segments); + $directory_override = isset($this->directory); + // Loop through our segments and return as soon as a controller // is found or when such a directory doesn't exist while ($c-- > 0) @@ -340,7 +338,10 @@ class CI_Router { $test = $this->directory .ucfirst($this->translate_uri_dashes === TRUE ? str_replace('-', '_', $segments[0]) : $segments[0]); - if ( ! file_exists(APPPATH.'controllers/'.$test.'.php') && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0])) + if ( ! file_exists(APPPATH.'controllers/'.$test.'.php') + && $directory_override === FALSE + && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]) + ) { $this->set_directory(array_shift($segments), TRUE); continue; @@ -493,7 +494,7 @@ class CI_Router { * Set directory name * * @param string $dir Directory name - * @param bool $appent Whether we're appending rather than setting the full value + * @param bool $append Whether we're appending rather than setting the full value * @return void */ public function set_directory($dir, $append = FALSE) diff --git a/system/core/Security.php b/system/core/Security.php index 9cef42439..7c5199255 100644 --- a/system/core/Security.php +++ b/system/core/Security.php @@ -275,7 +275,7 @@ class CI_Security { $secure_cookie, config_item('cookie_httponly') ); - log_message('info', 'CRSF cookie sent'); + log_message('info', 'CSRF cookie sent'); return $this; } diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php index d99fd0024..dde285598 100644 --- a/system/database/DB_forge.php +++ b/system/database/DB_forge.php @@ -143,7 +143,7 @@ abstract class CI_DB_forge { protected $_unsigned = TRUE; /** - * NULL value representatin in CREATE/ALTER TABLE statements + * NULL value representation in CREATE/ALTER TABLE statements * * @var string */ @@ -239,7 +239,7 @@ abstract class CI_DB_forge { */ public function add_key($key, $primary = FALSE) { - if ($primary === TRUE && is_array($key)) + if (is_array($key)) { foreach ($key as $one) { diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php index a8b5b3579..0bb91bae9 100644 --- a/system/database/DB_query_builder.php +++ b/system/database/DB_query_builder.php @@ -657,10 +657,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { if ($v !== NULL) { - if ($escape === TRUE) - { - $v = ' '.$this->escape($v); - } + $v = ' '.$this->escape($v); if ( ! $this->_has_operator($k)) { @@ -1279,8 +1276,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { foreach ($key as $k => $v) { - $this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = ($escape) - ? $this->escape($v) : $v; + $this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = $this->escape($v); } return $this; @@ -1294,7 +1290,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { * Compiles a SELECT query string and returns the sql. * * @param string the table name to select from (optional) - * @param bool TRUE: resets QB values; FALSE: leave QB vaules alone + * @param bool TRUE: resets QB values; FALSE: leave QB values alone * @return string */ public function get_compiled_select($table = '', $reset = TRUE) @@ -1519,15 +1515,9 @@ abstract class CI_DB_query_builder extends CI_DB_driver { ksort($row); // puts $row in the same order as our keys - if ($escape !== FALSE) + foreach ($row as $k => $v) { - $clean = array(); - foreach ($row as $value) - { - $clean[] = $this->escape($value); - } - - $row = $clean; + $row[$k] = $this->escape($v); } $this->qb_set[] = '('.implode(',', $row).')'; @@ -1736,7 +1726,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { return FALSE; } - $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set); + $sql = $this->_update($this->qb_from[0], $this->qb_set); if ($reset === TRUE) { @@ -1784,7 +1774,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { $this->limit($limit); } - $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set); + $sql = $this->_update($this->qb_from[0], $this->qb_set); $this->_reset_write(); return $this->query($sql); } @@ -1801,7 +1791,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { * @param string the table to update data on * @return bool */ - protected function _validate_update($table = '') + protected function _validate_update($table) { if (count($this->qb_set) === 0) { @@ -1810,7 +1800,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { if ($table !== '') { - $this->qb_from[0] = $table; + $this->qb_from = array($this->protect_identifiers($table, TRUE, NULL, FALSE)); } elseif ( ! isset($this->qb_from[0])) { @@ -1948,7 +1938,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { $index_set = TRUE; } - $clean[$this->protect_identifiers($k2, FALSE, $escape)] = ($escape === FALSE) ? $v2 : $this->escape($v2); + $clean[$this->protect_identifiers($k2, FALSE, $escape)] = $this->escape($v2); } if ($index_set === FALSE) diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php index e953db052..dd3cc77c6 100644 --- a/system/database/drivers/mysqli/mysqli_driver.php +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -102,7 +102,6 @@ class CI_DB_mysqli_driver extends CI_DB { * * @param bool $persistent * @return object - * @todo SSL support */ public function db_connect($persistent = FALSE) { @@ -132,8 +131,52 @@ class CI_DB_mysqli_driver extends CI_DB { $mysqli->options(MYSQLI_INIT_COMMAND, 'SET SESSION sql_mode="STRICT_ALL_TABLES"'); } - return $mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, $socket, $client_flags) - ? $mysqli : FALSE; + if (is_array($this->encrypt)) + { + $ssl = array(); + empty($this->encrypt['ssl_key']) OR $ssl['key'] = $this->encrypt['ssl_key']; + empty($this->encrypt['ssl_cert']) OR $ssl['cert'] = $this->encrypt['ssl_cert']; + empty($this->encrypt['ssl_ca']) OR $ssl['ca'] = $this->encrypt['ssl_ca']; + empty($this->encrypt['ssl_capath']) OR $ssl['capath'] = $this->encrypt['ssl_capath']; + empty($this->encrypt['ssl_cipher']) OR $ssl['cipher'] = $this->encrypt['ssl_cipher']; + + if ( ! empty($ssl)) + { + if ( ! empty($this->encrypt['ssl_verify']) && defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT')) + { + $mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, TRUE); + } + + $client_flags |= MYSQLI_CLIENT_SSL; + $mysqli->ssl_set( + isset($ssl['key']) ? $ssl['key'] : NULL, + isset($ssl['cert']) ? $ssl['cert'] : NULL, + isset($ssl['ca']) ? $ssl['ca'] : NULL, + isset($ssl['capath']) ? $ssl['capath'] : NULL, + isset($ssl['cipher']) ? $ssl['cipher'] : NULL + ); + } + } + + if ($mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, $socket, $client_flags)) + { + // Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails + if ( + ($client_flags & MYSQLI_CLIENT_SSL) + && version_compare($mysqli->client_info, '5.7.3', '<=') + && empty($mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")->fetch_object()->Value) + ) + { + $mysqli->close(); + $message = 'MySQLi was configured for an SSL connection, but got an unencrypted connection instead!'; + log_message('error', $message); + return ($this->db->db_debug) ? $this->db->display_error($message, '', TRUE) : FALSE; + } + + return $mysqli; + } + + return FALSE; } // -------------------------------------------------------------------- diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php index b5cf26536..3c5777751 100644 --- a/system/database/drivers/oci8/oci8_driver.php +++ b/system/database/drivers/oci8/oci8_driver.php @@ -102,6 +102,14 @@ class CI_DB_oci8_driver extends CI_DB { // -------------------------------------------------------------------- /** + * Reset $stmt_id flag + * + * Used by stored_procedure() to prevent _execute() from + * re-setting the statement ID. + */ + protected $_reset_stmt_id = TRUE; + + /** * List of reserved identifiers * * Identifiers that must NOT be escaped. @@ -265,26 +273,13 @@ class CI_DB_oci8_driver extends CI_DB { /* Oracle must parse the query before it is run. All of the actions with * the query are based on the statement id returned by oci_parse(). */ - $this->stmt_id = FALSE; - $this->_set_stmt_id($sql); - oci_set_prefetch($this->stmt_id, 1000); - return oci_execute($this->stmt_id, $this->commit_mode); - } - - // -------------------------------------------------------------------- - - /** - * Generate a statement ID - * - * @param string $sql an SQL query - * @return void - */ - protected function _set_stmt_id($sql) - { - if ( ! is_resource($this->stmt_id)) + if ($this->_reset_stmt_id === TRUE) { $this->stmt_id = oci_parse($this->conn_id, $sql); } + + oci_set_prefetch($this->stmt_id, 1000); + return oci_execute($this->stmt_id, $this->commit_mode); } // -------------------------------------------------------------------- @@ -318,15 +313,15 @@ class CI_DB_oci8_driver extends CI_DB { * type yes the type of the parameter * length yes the max size of the parameter */ - public function stored_procedure($package, $procedure, $params) + public function stored_procedure($package, $procedure, array $params) { - if ($package === '' OR $procedure === '' OR ! is_array($params)) + if ($package === '' OR $procedure === '') { log_message('error', 'Invalid query: '.$package.'.'.$procedure); return ($this->db_debug) ? $this->display_error('db_invalid_query') : FALSE; } - // build the query string + // Build the query string $sql = 'BEGIN '.$package.'.'.$procedure.'('; $have_cursor = FALSE; @@ -341,10 +336,12 @@ class CI_DB_oci8_driver extends CI_DB { } $sql = trim($sql, ',').'); END;'; - $this->stmt_id = FALSE; - $this->_set_stmt_id($sql); + $this->_reset_stmt_id = FALSE; + $this->stmt_id = oci_parse($this->conn_id, $sql); $this->_bind_params($params); - return $this->query($sql, FALSE, $have_cursor); + $result = $this->query($sql, FALSE, $have_cursor); + $this->_reset_stmt_id = TRUE; + return $result; } // -------------------------------------------------------------------- diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php index 206d83595..e9d25cebc 100644 --- a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php +++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php @@ -119,7 +119,6 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver { * * @param bool $persistent * @return object - * @todo SSL support */ public function db_connect($persistent = FALSE) { @@ -151,7 +150,35 @@ class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver { $this->options[PDO::MYSQL_ATTR_COMPRESS] = TRUE; } - return parent::db_connect($persistent); + // SSL support was added to PDO_MYSQL in PHP 5.3.7 + if (is_array($this->encrypt) && is_php('5.3.7')) + { + $ssl = array(); + empty($this->encrypt['ssl_key']) OR $ssl[PDO::MYSQL_ATTR_SSL_KEY] = $this->encrypt['ssl_key']; + empty($this->encrypt['ssl_cert']) OR $ssl[PDO::MYSQL_ATTR_SSL_CERT] = $this->encrypt['ssl_cert']; + empty($this->encrypt['ssl_ca']) OR $ssl[PDO::MYSQL_ATTR_SSL_CA] = $this->encrypt['ssl_ca']; + empty($this->encrypt['ssl_capath']) OR $ssl[PDO::MYSQL_ATTR_SSL_CAPATH] = $this->encrypt['ssl_capath']; + empty($this->encrypt['ssl_cipher']) OR $ssl[PDO::MYSQL_ATTR_SSL_CIPHER] = $this->encrypt['ssl_cipher']; + + // DO NOT use array_merge() here! + // It re-indexes numeric keys and the PDO_MYSQL_ATTR_SSL_* constants are integers. + empty($ssl) OR $this->options += $ssl; + } + + // Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails + if ( + ($pdo = parent::db_connect($persistent)) !== FALSE + && ! empty($ssl) + && version_compare($pdo->getAttribute(PDO::ATTR_CLIENT_VERSION), '5.7.3', '<=') + && empty($pdo->query("SHOW STATUS LIKE 'ssl_cipher'")->fetchObject()->Value) + ) + { + $message = 'PDO_MYSQL was configured for an SSL connection, but got an unencrypted connection instead!'; + log_message('error', $message); + return ($this->db->db_debug) ? $this->db->display_error($message, '', TRUE) : FALSE; + } + + return $pdo; } // -------------------------------------------------------------------- diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php index 95c94a1b8..73f6456c4 100644 --- a/system/helpers/download_helper.php +++ b/system/helpers/download_helper.php @@ -69,16 +69,14 @@ if ( ! function_exists('force_download')) } elseif ($data === NULL) { - if (@is_file($filename) && ($filesize = @filesize($filename)) !== FALSE) - { - $filepath = $filename; - $filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename)); - $filename = end($filename); - } - else + if ( ! @is_file($filename) OR ($filesize = @filesize($filename)) === FALSE) { return; } + + $filepath = $filename; + $filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename)); + $filename = end($filename); } else { @@ -140,14 +138,7 @@ if ( ! function_exists('force_download')) header('Expires: 0'); header('Content-Transfer-Encoding: binary'); header('Content-Length: '.$filesize); - - // Internet Explorer-specific headers - if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) - { - header('Cache-Control: no-cache, no-store, must-revalidate'); - } - - header('Pragma: no-cache'); + header('Cache-Control: private, no-transform, no-store, must-revalidate'); // If we have raw data - just dump it if ($data !== NULL) diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php index 8b15e60a5..cd1c641ec 100644 --- a/system/helpers/file_helper.php +++ b/system/helpers/file_helper.php @@ -54,7 +54,7 @@ if ( ! function_exists('read_file')) /** * Read File * - * Opens the file specfied in the path and returns it as a string. + * Opens the file specified in the path and returns it as a string. * * @todo Remove in version 3.1+. * @deprecated 3.0.0 It is now just an alias for PHP's native file_get_contents(). diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php index 53ee8eb11..fd807769a 100644 --- a/system/helpers/form_helper.php +++ b/system/helpers/form_helper.php @@ -197,7 +197,7 @@ if ( ! function_exists('form_input')) * * @param mixed * @param string - * @param string + * @param mixed * @return string */ function form_input($data = '', $value = '', $extra = '') @@ -208,7 +208,7 @@ if ( ! function_exists('form_input')) 'value' => $value ); - return '<input '._parse_form_attributes($data, $defaults).$extra." />\n"; + return '<input '._parse_form_attributes($data, $defaults)._attributes_to_string($extra)." />\n"; } } @@ -223,7 +223,7 @@ if ( ! function_exists('form_password')) * * @param mixed * @param string - * @param string + * @param mixed * @return string */ function form_password($data = '', $value = '', $extra = '') @@ -245,7 +245,7 @@ if ( ! function_exists('form_upload')) * * @param mixed * @param string - * @param string + * @param mixed * @return string */ function form_upload($data = '', $value = '', $extra = '') @@ -253,7 +253,8 @@ if ( ! function_exists('form_upload')) $defaults = array('type' => 'file', 'name' => ''); is_array($data) OR $data = array('name' => $data); $data['type'] = 'file'; - return '<input '._parse_form_attributes($data, $defaults).$extra." />\n"; + + return '<input '._parse_form_attributes($data, $defaults)._attributes_to_string($extra)." />\n"; } } @@ -266,7 +267,7 @@ if ( ! function_exists('form_textarea')) * * @param mixed $data * @param string $value - * @param string $extra + * @param mixed $extra * @return string */ function form_textarea($data = '', $value = '', $extra = '') @@ -287,7 +288,9 @@ if ( ! function_exists('form_textarea')) unset($data['value']); // textareas don't use the value attribute } - return '<textarea '._parse_form_attributes($data, $defaults).$extra.'>'.html_escape($val)."</textarea>\n"; + return '<textarea '._parse_form_attributes($data, $defaults)._attributes_to_string($extra).'>' + .html_escape($val) + ."</textarea>\n"; } } @@ -301,12 +304,13 @@ if ( ! function_exists('form_multiselect')) * @param string * @param array * @param mixed - * @param string + * @param mixed * @return string */ function form_multiselect($name = '', $options = array(), $selected = array(), $extra = '') { - if ( ! strpos($extra, 'multiple')) + $extra = _attributes_to_string($extra); + if (stripos($extra, 'multiple') === FALSE) { $extra .= ' multiple="multiple"'; } @@ -372,7 +376,7 @@ if ( ! function_exists('form_dropdown')) $extra = _attributes_to_string($extra); - $multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : ''; + $multiple = (count($selected) > 1 && stripos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : ''; $form = '<select '.rtrim(_parse_form_attributes($data, $defaults)).$extra.$multiple.">\n"; @@ -420,7 +424,7 @@ if ( ! function_exists('form_checkbox')) * @param mixed * @param string * @param bool - * @param string + * @param mixed * @return string */ function form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '') @@ -450,7 +454,7 @@ if ( ! function_exists('form_checkbox')) unset($defaults['checked']); } - return '<input '._parse_form_attributes($data, $defaults).$extra." />\n"; + return '<input '._parse_form_attributes($data, $defaults)._attributes_to_string($extra)." />\n"; } } @@ -464,13 +468,14 @@ if ( ! function_exists('form_radio')) * @param mixed * @param string * @param bool - * @param string + * @param mixed * @return string */ function form_radio($data = '', $value = '', $checked = FALSE, $extra = '') { is_array($data) OR $data = array('name' => $data); $data['type'] = 'radio'; + return form_checkbox($data, $value, $checked, $extra); } } @@ -484,7 +489,7 @@ if ( ! function_exists('form_submit')) * * @param mixed * @param string - * @param string + * @param mixed * @return string */ function form_submit($data = '', $value = '', $extra = '') @@ -495,7 +500,7 @@ if ( ! function_exists('form_submit')) 'value' => $value ); - return '<input '._parse_form_attributes($data, $defaults).$extra." />\n"; + return '<input '._parse_form_attributes($data, $defaults)._attributes_to_string($extra)." />\n"; } } @@ -508,7 +513,7 @@ if ( ! function_exists('form_reset')) * * @param mixed * @param string - * @param string + * @param mixed * @return string */ function form_reset($data = '', $value = '', $extra = '') @@ -519,7 +524,7 @@ if ( ! function_exists('form_reset')) 'value' => $value ); - return '<input '._parse_form_attributes($data, $defaults).$extra." />\n"; + return '<input '._parse_form_attributes($data, $defaults)._attributes_to_string($extra)." />\n"; } } @@ -532,7 +537,7 @@ if ( ! function_exists('form_button')) * * @param mixed * @param string - * @param string + * @param mixed * @return string */ function form_button($data = '', $content = '', $extra = '') @@ -548,7 +553,9 @@ if ( ! function_exists('form_button')) unset($data['content']); // content is not an attribute } - return '<button '._parse_form_attributes($data, $defaults).$extra.'>'.$content."</button>\n"; + return '<button '._parse_form_attributes($data, $defaults)._attributes_to_string($extra).'>' + .$content + ."</button>\n"; } } diff --git a/system/helpers/path_helper.php b/system/helpers/path_helper.php index c23ec6435..c96d0b8b3 100644 --- a/system/helpers/path_helper.php +++ b/system/helpers/path_helper.php @@ -61,7 +61,7 @@ if ( ! function_exists('set_realpath')) function set_realpath($path, $check_existance = FALSE) { // Security check to make sure the path is NOT a URL. No remote file inclusion! - if (preg_match('#^(http:\/\/|https:\/\/|www\.|ftp|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})#i', $path)) + if (preg_match('#^(http:\/\/|https:\/\/|www\.|ftp)#i', $path) OR filter_var($path, FILTER_VALIDATE_IP) === $path ) { show_error('The path you submitted must be a local server path, not a URL'); } diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php index f2290c895..fb47036f2 100644 --- a/system/helpers/text_helper.php +++ b/system/helpers/text_helper.php @@ -254,7 +254,7 @@ if ( ! function_exists('word_censor')) * word you've submitted. * * @param string the text string - * @param string the array of censoered words + * @param string the array of censored words * @param string the optional replacement value * @return string */ diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php index 6a033d6ba..d65f92f1b 100644 --- a/system/helpers/url_helper.php +++ b/system/helpers/url_helper.php @@ -492,7 +492,7 @@ if ( ! function_exists('url_title')) $trans = array( '&.+?;' => '', - '[^a-z0-9 _-]' => '', + '[^\w\d _-]' => '', '\s+' => $separator, '('.$q_separator.')+' => $separator ); @@ -500,7 +500,7 @@ if ( ! function_exists('url_title')) $str = strip_tags($str); foreach ($trans as $key => $val) { - $str = preg_replace('#'.$key.'#i', $val, $str); + $str = preg_replace('#'.$key.'#i'.(UTF8_ENABLED ? 'u' : ''), $val, $str); } if ($lowercase === TRUE) diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php index 5faf1f206..a46d4f462 100644 --- a/system/libraries/Encrypt.php +++ b/system/libraries/Encrypt.php @@ -65,7 +65,7 @@ class CI_Encrypt { protected $_hash_type = 'sha1'; /** - * Flag for the existance of mcrypt + * Flag for the existence of mcrypt * * @var bool */ diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php index b53207577..2d345c294 100644 --- a/system/libraries/Ftp.php +++ b/system/libraries/Ftp.php @@ -466,7 +466,7 @@ class CI_FTP { /** * Delete a folder and recursively delete everything (including sub-folders) - * containted within it. + * contained within it. * * @param string $filepath * @return bool diff --git a/system/libraries/Javascript/Jquery.php b/system/libraries/Javascript/Jquery.php index 25acceef7..11f2d2361 100644 --- a/system/libraries/Javascript/Jquery.php +++ b/system/libraries/Javascript/Jquery.php @@ -84,7 +84,7 @@ class CI_Jquery extends CI_Javascript { public $jquery_table_sorter_active = FALSE; /** - * JQuery table sorder pager active + * JQuery table sorter pager active * * @var bool */ diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index d63f61df6..76437f4a5 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -644,7 +644,7 @@ class CI_Pagination { // Kill double slashes. Note: Sometimes we can end up with a double slash // in the penultimate link so we'll kill all double slashes. - $output = preg_replace('#([^:])//+#', '\\1/', $output); + $output = preg_replace('#([^:"])//+#', '\\1/', $output); // Add the wrapper HTML if exists return $this->full_tag_open.$output.$this->full_tag_close; diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 0549fef66..05a470d86 100644 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -795,7 +795,7 @@ class CI_Session { /** * Set flashdata * - * Legacy CI_Session compatibiliy method + * Legacy CI_Session compatibility method * * @param mixed $data Session data key or an associative array * @param mixed $value Value to store diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php index 60b046ba0..3f986f3e8 100644 --- a/system/libraries/Unit_test.php +++ b/system/libraries/Unit_test.php @@ -55,14 +55,14 @@ class CI_Unit_test { * * @var bool */ - public $active = TRUE; + public $active = TRUE; /** * Test results * * @var array */ - public $results = array(); + public $results = array(); /** * Strict comparison flag @@ -71,21 +71,21 @@ class CI_Unit_test { * * @var bool */ - public $strict = FALSE; + public $strict = FALSE; /** * Template * * @var string */ - protected $_template = NULL; + protected $_template = NULL; /** * Template rows * * @var string */ - protected $_template_rows = NULL; + protected $_template_rows = NULL; /** * List of visible test items @@ -93,13 +93,13 @@ class CI_Unit_test { * @var array */ protected $_test_items_visible = array( - 'test_name', - 'test_datatype', - 'res_datatype', - 'result', - 'file', - 'line', - 'notes' + 'test_name', + 'test_datatype', + 'res_datatype', + 'result', + 'file', + 'line', + 'notes' ); // -------------------------------------------------------------------- @@ -167,14 +167,14 @@ class CI_Unit_test { $back = $this->_backtrace(); $report = array ( - 'test_name' => $test_name, - 'test_datatype' => gettype($test), - 'res_datatype' => $extype, - 'result' => ($result === TRUE) ? 'passed' : 'failed', - 'file' => $back['file'], - 'line' => $back['line'], - 'notes' => $notes - ); + 'test_name' => $test_name, + 'test_datatype' => gettype($test), + 'res_datatype' => $extype, + 'result' => ($result === TRUE) ? 'passed' : 'failed', + 'file' => $back['file'], + 'line' => $back['line'], + 'notes' => $notes + ); $this->results[] = $report; @@ -291,10 +291,12 @@ class CI_Unit_test { { continue; } - - if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val), FALSE))) + elseif (in_array($key, array('test_name', 'test_datatype', 'test_res_datatype', 'result'), TRUE)) { - $val = $line; + if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val), FALSE))) + { + $val = $line; + } } $temp[$CI->lang->line('ut_'.$key, FALSE)] = $val; @@ -334,9 +336,9 @@ class CI_Unit_test { { $back = debug_backtrace(); return array( - 'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''), - 'line' => (isset($back[1]['line']) ? $back[1]['line'] : '') - ); + 'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''), + 'line' => (isset($back[1]['line']) ? $back[1]['line'] : '') + ); } // -------------------------------------------------------------------- diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index a1bd14930..20ddfc145 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -533,15 +533,9 @@ class CI_Upload { * If it returns false there was a problem. */ $this->orig_name = $this->file_name; - - if ($this->overwrite === FALSE) + if (FALSE === ($this->file_name = $this->set_filename($this->upload_path, $this->file_name))) { - $this->file_name = $this->set_filename($this->upload_path, $this->file_name); - - if ($this->file_name === FALSE) - { - return FALSE; - } + return FALSE; } /* @@ -656,7 +650,7 @@ class CI_Upload { $filename = md5(uniqid(mt_rand())).$this->file_ext; } - if ( ! file_exists($path.$filename)) + if ($this->overwrite === TRUE OR ! file_exists($path.$filename)) { return $filename; } @@ -701,6 +695,22 @@ class CI_Upload { // -------------------------------------------------------------------- /** + * Set Maximum File Size + * + * An internal alias to set_max_filesize() to help with configuration + * as initialize() will look for a set_<property_name>() method ... + * + * @param int $n + * @return CI_Upload + */ + protected function set_max_size($n) + { + return $this->set_max_filesize($n); + } + + // -------------------------------------------------------------------- + + /** * Set Maximum File Name Length * * @param int $n diff --git a/tests/README.md b/tests/README.md index 47b5241d1..04dfbc3d8 100644 --- a/tests/README.md +++ b/tests/README.md @@ -6,7 +6,7 @@ Status : [![Build Status](https://secure.travis-ci.org/bcit-ci/CodeIgniter.png?b This is the preliminary CodeIgniter testing documentation. It will cover both internal as well as external APIs and the reasoning -behind their implemenation, where appropriate. As with all CodeIgniter +behind their implementation, where appropriate. As with all CodeIgniter documentation, this file should maintain a mostly human readable format to facilitate clean api design. [see http://arrenbrecht.ch/testing/] diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php index cfaf6c74b..889ab92e4 100644 --- a/tests/codeigniter/core/Loader_test.php +++ b/tests/codeigniter/core/Loader_test.php @@ -229,7 +229,7 @@ class Loader_test extends CI_TestCase { $this->ci_obj->$obj = new stdClass(); $this->setExpectedException( 'RuntimeException', - 'CI Error: The model name you are loading is the name of a resource that is already being used: '.$obj + 'The model name you are loading is the name of a resource that is already being used: '.$obj ); $this->load->model('not_real', $obj); } @@ -240,7 +240,7 @@ class Loader_test extends CI_TestCase { { $this->setExpectedException( 'RuntimeException', - 'CI Error: Unable to locate the model you have specified: Ci_test_nonexistent_model.php' + 'Unable to locate the model you have specified: Ci_test_nonexistent_model.php' ); $this->load->model('ci_test_nonexistent_model.php'); diff --git a/user_guide_src/source/_themes/sphinx_rtd_theme/static/css/citheme.css b/user_guide_src/source/_themes/sphinx_rtd_theme/static/css/citheme.css new file mode 100644 index 000000000..10e7d04c6 --- /dev/null +++ b/user_guide_src/source/_themes/sphinx_rtd_theme/static/css/citheme.css @@ -0,0 +1,7 @@ +@import 'theme.css'; + +.highlighted { + padding: 0px !important; + font-weight: inherit !important; + background-color: #f1d40f !important; +}
\ No newline at end of file diff --git a/user_guide_src/source/_themes/sphinx_rtd_theme/theme.conf b/user_guide_src/source/_themes/sphinx_rtd_theme/theme.conf index dcfbf8c22..5814ac963 100644 --- a/user_guide_src/source/_themes/sphinx_rtd_theme/theme.conf +++ b/user_guide_src/source/_themes/sphinx_rtd_theme/theme.conf @@ -1,6 +1,6 @@ [theme] inherit = basic -stylesheet = css/theme.css +stylesheet = css/citheme.css [options] typekit_id = hiw1hhg diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst index 92d8bb164..ee52d2e49 100644 --- a/user_guide_src/source/changelog.rst +++ b/user_guide_src/source/changelog.rst @@ -14,6 +14,7 @@ Release Date: Not Released - Database - Added ``list_fields()`` support for SQLite ('sqlite3' and 'pdo_sqlite' drivers). + - Added SSL connection support for the 'mysqli' and 'pdo_mysql' drivers. - Libraries @@ -25,6 +26,15 @@ Release Date: Not Released - Added 'is_resource' to the available expectations in :doc:`Unit Testing Library <libraries/unit_testing>`. +- Helpers + + - Added Unicode support to :doc:`URL Helper <helpers/url_helper>` function :php:func:`url_title()`. + - Added support for passing the "extra" parameter as an array to all :doc:`Form Helper <helpers/form_helper>` functions that use it. + +- Core + + - Added support for defining a list of specific query parameters in ``$config['cache_query_string']`` for the :doc:`Output Library <libraries/output>`. + - Added class existence and inheritance checks to ``CI_Loader::model()`` in order to ease debugging in case of name collisions. Bug fixes for 3.0.1 ------------------- @@ -50,6 +60,18 @@ Bug fixes for 3.0.1 - Fixed a bug in :doc:`Query Builder <database/query_builder>` where ``delete()`` didn't properly work on multiple tables with a WHERE condition previously set via ``where()``. - Fixed a bug (#3952) - :doc:`Database <database/index>` method ``list_fields()`` didn't work with SQLite3. - Fixed a bug (#3955) - :doc:`Cache Library <libraries/caching>` methods ``increment()`` and ``decrement()`` ignored the 'key_prefix' setting. +- Fixed a bug (#3963) - :doc:`Unit Testing Library <libraries/unit_testing>` wrongly tried to translate filenames, line numbers and notes values in test results. +- Fixed a bug (#3965) - :doc:`File Uploading Library <libraries/file_uploading>` ignored the "encrypt_name" setting when "overwrite" is enabled. +- Fixed a bug (#3968) - :doc:`Database Forge <database/forge>` method ``add_key()`` didn't treat array inputs as composite keys unless it's a PRIMARY KEY. +- Fixed a bug (#3715) - :doc:`Pagination Library <libraries/pagination>` could generate broken link when a protocol-relative base URL is used. +- Fixed a bug (#3828) - :doc:`Output Library <libraries/output>` method ``delete_cache()`` couldn't delete index page caches. +- Fixed a bug (#3704) - :doc:`Database <database/index>` method ``stored_procedure()`` in the 'oci8' driver didn't properly bind parameters. +- Fixed a bug (#3778) - :doc:`Download Helper <helpers/download_helper>` function :php:func:`force_download()` incorrectly sent a *Pragma* response header. +- Fixed a bug (#3752) - ``$routing['directory']`` overrides were not properly handled and always resulted in a 404 "Not Found" error. +- Fixed an internal bug (#3989) - :doc:`Query Builder <database/query_builder>` escaping logic where if field name escaping is force-disabled, would also treat values as fields in methods ``where()``, ``having()``, ``set()``, ``set_insert_batch()``, ``set_update_batch()``. +- Fixed a bug (#3279) - :doc:`Query Builder <database/query_builder>` methods ``update()`` and ``get_compiled_update()`` did double escaping on the table name if it was provided via ``from()``. +- Fixed a bug (#3991) - ``$config['rewrite_short_tags']`` never worked due to ``function_exists('eval')`` always returning FALSE. +- Fixed a bug where the :doc:`File Uploadin Library <libraries/file_uploading>` library will not properly configure its maximum file size unless the input value is of type integer. Version 3.0.0 ============= @@ -823,6 +845,30 @@ Bug fixes for 3.0 - Fixed a bug (#3573) - :doc:`Email Library <libraries/email>` violated `RFC5321 <https://tools.ietf.org/rfc/rfc5321.txt>`_ by sending 'localhost.localdomain' as a hostname. - Fixed a bug (#3572) - ``CI_Security::_remove_evil_attributes()`` failed for large-sized inputs due to *pcre.backtrack_limit* and didn't properly match HTML tags. +Version 2.2.3 +============= + +Release Date: July 14, 2015 + +- Security + + - Removed a fallback to ``mysql_escape_string()`` in the 'mysql' database driver (``escape_str()`` method) when there's no active database connection. + +Version 2.2.2 +============= + +Release Date: April 15, 2015 + +- General Changes + + - Added HTTP "Host" header character validation to prevent cache poisoning attacks when *base_url* auto-detection is used. + - Added *FSCommand* and *seekSegmentTime* to the "evil attributes" list in ``CI_Security::xss_clean()``. + +Bug fixes for 2.2.2 +------------------- + +- Fixed a bug (#3665) - ``CI_Security::entity_decode()`` triggered warnings under some circumstances. + Version 2.2.1 ============= diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index d21c79e44..8026be63a 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -152,9 +152,9 @@ when the database classes are initialized. Explanation of Values: ---------------------- -====================== ================================================================================================== +====================== =========================================================================================================== Name Config Description -====================== ================================================================================================== +====================== =========================================================================================================== **dsn** The DSN connect string (an all-in-one configuration sequence). **hostname** The hostname of your database server. Often this is 'localhost'. **username** The username used to connect to the database. @@ -179,6 +179,17 @@ Explanation of Values: customizable by the end user. **schema** The database schema, defaults to 'public'. Used by PostgreSQL and ODBC drivers. **encrypt** Whether or not to use an encrypted connection. + + - 'mysql' (deprecated), 'sqlsrv' and 'pdo/sqlsrv' drivers accept TRUE/FALSE + - 'mysqli' and 'pdo/mysql' drivers accept an array with the following options: + + - 'ssl_key' - Path to the private key file + - 'ssl_cert' - Path to the public key certificate file + - 'ssl_ca' - Path to the certificate authority file + - 'ssl_capath' - Path to a directory containing trusted CA certificats in PEM format + - 'ssl_cipher' - List of *allowed* ciphers to be used for the encryption, separated by colons (':') + - 'ssl_verify' - TRUE/FALSE; Whether to verify the server certificate or not ('mysqli' only) + **compress** Whether or not to use client compression (MySQL only). **stricton** TRUE/FALSE (boolean) - Whether to force "Strict Mode" connections, good for ensuring strict SQL while developing an application. @@ -186,10 +197,11 @@ Explanation of Values: :: $db['default']['port'] = 5432; -====================== ================================================================================================== + +====================== =========================================================================================================== .. note:: Depending on what database platform you are using (MySQL, PostgreSQL, etc.) not all values will be needed. For example, when using SQLite you will not need to supply a username or password, and the database name will be the path to your database file. The information above assumes - you are using MySQL.
\ No newline at end of file + you are using MySQL. diff --git a/user_guide_src/source/database/forge.rst b/user_guide_src/source/database/forge.rst index a875f7418..646e3a56e 100644 --- a/user_guide_src/source/database/forge.rst +++ b/user_guide_src/source/database/forge.rst @@ -143,6 +143,8 @@ string into the field definitions with add_field() $this->dbforge->add_field("label varchar(100) NOT NULL DEFAULT 'default label'"); +.. note:: Passing raw strings as fields cannot be followed by ``add_key()`` calls on those fields. + .. note:: Multiple calls to add_field() are cumulative. Creating an id field diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst index ac44566d3..e72d9fa77 100644 --- a/user_guide_src/source/database/results.rst +++ b/user_guide_src/source/database/results.rst @@ -19,7 +19,7 @@ This method returns the query result as an array of **objects**, or loop, like this:: $query = $this->db->query("YOUR QUERY"); - + foreach ($query->result() as $row) { echo $row->title; @@ -33,18 +33,15 @@ If you run queries that might **not** produce a result, you are encouraged to test the result first:: $query = $this->db->query("YOUR QUERY"); - - if ($query->num_rows() > 0) + + foreach ($query->result() as $row) { - foreach ($query->result() as $row) - { - echo $row->title; - echo $row->name; - echo $row->body; - } + echo $row->title; + echo $row->name; + echo $row->body; } -You can also pass a string to result() which represents a class to +You can also pass a string to ``result()`` which represents a class to instantiate for each result object (note: this class must be loaded) :: @@ -64,7 +61,7 @@ array when no result is produced. Typically you'll use this in a foreach loop, like this:: $query = $this->db->query("YOUR QUERY"); - + foreach ($query->result_array() as $row) { echo $row['title']; @@ -83,11 +80,11 @@ one row, it returns only the first row. The result is returned as an **object**. Here's a usage example:: $query = $this->db->query("YOUR QUERY"); - - if ($query->num_rows() > 0) + + $row = $query->row(); + + if (isset($row)) { - $row = $query->row(); - echo $row->title; echo $row->name; echo $row->body; @@ -113,11 +110,11 @@ Identical to the above ``row()`` method, except it returns an array. Example:: $query = $this->db->query("YOUR QUERY"); - - if ($query->num_rows() > 0) + + $row = $query->row_array(); + + if (isset($row)) { - $row = $query->row_array(); - echo $row['title']; echo $row['name']; echo $row['body']; @@ -157,7 +154,7 @@ it returns the current row and moves the internal data pointer ahead. :: $query = $this->db->query("YOUR QUERY"); - + while ($row = $query->unbuffered_row()) { echo $row->title; @@ -173,6 +170,94 @@ the returned value's type:: $query->unbuffered_row('array'); // associative array ********************* +Custom Result Objects +********************* + +You can have the results returned as an instance of a custom class instead +of a ``stdClass`` or array, as the ``result()`` and ``result_array()`` +methods allow. This requires that the class is already loaded into memory. +The object will have all values returned from the database set as properties. +If these have been declared and are non-public then you should provide a +``__set()`` method to allow them to be set. + +Example:: + + class User { + + public $id; + public $email; + public $username; + + protected $last_login; + + public function last_login($format) + { + return $this->last_login->format($format); + } + + public function __set($name, $value) + { + if ($name === 'last_login') + { + $this->last_login = DateTime::createFromFormat('U', $value); + } + } + + public function __get($name) + { + if (isset($this->$name)) + { + return $this->$name; + } + } + } + +In addition to the two methods listed below, the following methods also can +take a class name to return the results as: ``first_row()``, ``last_row()``, +``next_row()``, and ``previous_row()``. + +**custom_result_object()** + +Returns the entire result set as an array of instances of the class requested. +The only parameter is the name of the class to instantiate. + +Example:: + + $query = $this->db->query("YOUR QUERY"); + + $rows = $query->custom_result_object('User'); + + foreach ($rows as $row) + { + echo $row->id; + echo $row->email; + echo $row->last_login('Y-m-d'); + } + +**custom_row_object()** + +Returns a single row from your query results. The first parameter is the row +number of the results. The second parameter is the class name to instantiate. + +Example:: + + $query = $this->db->query("YOUR QUERY"); + + $row = $query->custom_row_object(0, 'User'); + + if (isset($row)) + { + echo $row->email; // access attributes + echo $row->last_login('Y-m-d'); // access class methods + } + +You can also use the ``row()`` method in exactly the same way. + +Example:: + + $row = $query->custom_row_object(0, 'User'); + +********************* Result Helper Methods ********************* @@ -182,7 +267,7 @@ The number of rows returned by the query. Note: In this example, $query is the variable that the query result object is assigned to:: $query = $this->db->query('SELECT * FROM my_table'); - + echo $query->num_rows(); .. note:: Not all database drivers have a native way of getting the total @@ -196,7 +281,7 @@ The number of FIELDS (columns) returned by the query. Make sure to call the method using your query result object:: $query = $this->db->query('SELECT * FROM my_table'); - + echo $query->num_fields(); **free_result()** @@ -210,7 +295,7 @@ result has been generated in order to cut down on memory consumption. Example:: $query = $this->db->query('SELECT title FROM my_table'); - + foreach ($query->result() as $row) { echo $row->title; diff --git a/user_guide_src/source/general/environments.rst b/user_guide_src/source/general/environments.rst index 7f030b6ef..ac6f3235e 100644 --- a/user_guide_src/source/general/environments.rst +++ b/user_guide_src/source/general/environments.rst @@ -49,4 +49,4 @@ Optionally, you can have CodeIgniter load environment-specific configuration files. This may be useful for managing things like differing API keys across multiple environments. This is described in more detail in the environment section of the :doc:`Config Class -<../libraries/config>`_ documentation.
\ No newline at end of file +<../libraries/config>` documentation.
\ No newline at end of file diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index 9ddca89bc..6317f08ed 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -191,7 +191,7 @@ The following functions are available: :param array $data: Field attributes data :param string $value: Field value - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML text input field tag :rtype: string @@ -226,11 +226,16 @@ The following functions are available: $js = 'onClick="some_function()"'; echo form_input('username', 'johndoe', $js); + Or you can pass it as an array:: + + $js = array('onClick' => 'some_function();'); + echo form_input('username', 'johndoe', $js); + .. php:function:: form_password([$data = ''[, $value = ''[, $extra = '']]]) :param array $data: Field attributes data :param string $value: Field value - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML password input field tag :rtype: string @@ -242,7 +247,7 @@ The following functions are available: :param array $data: Field attributes data :param string $value: Field value - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML file upload input field tag :rtype: string @@ -255,7 +260,7 @@ The following functions are available: :param array $data: Field attributes data :param string $value: Field value - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML textarea tag :rtype: string @@ -270,7 +275,7 @@ The following functions are available: :param string $name: Field name :param array $options: An associative array of options to be listed :param array $selected: List of fields to mark with the *selected* attribute - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML dropdown select field tag :rtype: string @@ -324,6 +329,14 @@ The following functions are available: $js = 'id="shirts" onChange="some_function();"'; echo form_dropdown('shirts', $options, 'large', $js); + Or you can pass it as an array:: + + $js = array( + 'id' => 'shirts', + 'onChange' => 'some_function();' + ); + echo form_dropdown('shirts', $options, 'large', $js); + If the array passed as ``$options`` is a multidimensional array, then ``form_dropdown()`` will produce an <optgroup> with the array key as the label. @@ -334,7 +347,7 @@ The following functions are available: :param string $name: Field name :param array $options: An associative array of options to be listed :param array $selected: List of fields to mark with the *selected* attribute - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML dropdown multiselect field tag :rtype: string @@ -417,7 +430,7 @@ The following functions are available: :param array $data: Field attributes data :param string $value: Field value :param bool $checked: Whether to mark the checkbox as being *checked* - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML checkbox input tag :rtype: string @@ -450,13 +463,18 @@ The following functions are available: $js = 'onClick="some_function()"'; echo form_checkbox('newsletter', 'accept', TRUE, $js) + Or you can pass it as an array:: + + $js = array('onClick' => 'some_function();'); + echo form_checkbox('newsletter', 'accept', TRUE, $js) + .. php:function:: form_radio([$data = ''[, $value = ''[, $checked = FALSE[, $extra = '']]]]) :param array $data: Field attributes data :param string $value: Field value :param bool $checked: Whether to mark the radio button as being *checked* - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML radio input tag :rtype: string @@ -495,7 +513,7 @@ The following functions are available: :param string $data: Button name :param string $value: Button value - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML input submit tag :rtype: string @@ -513,7 +531,7 @@ The following functions are available: :param string $data: Button name :param string $value: Button value - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML input reset button tag :rtype: string @@ -525,7 +543,7 @@ The following functions are available: :param string $data: Button name :param string $content: Button label - :param string $extra: Extra attributes to be added to the tag *as is* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :returns: An HTML button tag :rtype: string diff --git a/user_guide_src/source/installation/downloads.rst b/user_guide_src/source/installation/downloads.rst index e2b6a9c18..16c8e537a 100644 --- a/user_guide_src/source/installation/downloads.rst +++ b/user_guide_src/source/installation/downloads.rst @@ -2,7 +2,10 @@ Downloading CodeIgniter ####################### -- `CodeIgniter v3.0.0 (Current version) <https://codeload.github.com/bcit-ci/CodeIgniter/zip/develop>`_ +- `CodeIgniter v3.0.1-dev (Current version) <https://codeload.github.com/bcit-ci/CodeIgniter/zip/develop>`_ +- `CodeIgniter v3.0.0 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.0.0>`_ +- `CodeIgniter v2.2.3 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/2.2.3>`_ +- `CodeIgniter v2.2.2 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/2.2.2>`_ - `CodeIgniter v2.2.1 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/2.2.1>`_ - `CodeIgniter v2.2.0 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/2.2.0>`_ - `CodeIgniter v2.1.4 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/2.1.4>`_ diff --git a/user_guide_src/source/installation/upgrade_220.rst b/user_guide_src/source/installation/upgrade_220.rst index b2e943223..91f9e00cd 100644 --- a/user_guide_src/source/installation/upgrade_220.rst +++ b/user_guide_src/source/installation/upgrade_220.rst @@ -1,5 +1,5 @@ ############################# -Upgrading from 2.1.4 to 2.2.0 +Upgrading from 2.1.4 to 2.2.x ############################# .. note:: The :doc:`Encrypt Class </libraries/encrypt>` now requires the diff --git a/user_guide_src/source/installation/upgrade_222.rst b/user_guide_src/source/installation/upgrade_222.rst new file mode 100644 index 000000000..9dcc61d0e --- /dev/null +++ b/user_guide_src/source/installation/upgrade_222.rst @@ -0,0 +1,14 @@ +############################# +Upgrading from 2.2.1 to 2.2.2 +############################# + +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" folder. + +.. note:: If you have any custom developed files in these folders please + make copies of them first.
\ No newline at end of file diff --git a/user_guide_src/source/installation/upgrade_223.rst b/user_guide_src/source/installation/upgrade_223.rst new file mode 100644 index 000000000..252318ae1 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_223.rst @@ -0,0 +1,14 @@ +############################# +Upgrading from 2.2.2 to 2.2.3 +############################# + +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" folder. + +.. note:: If you have any custom developed files in these folders please + make copies of them first.
\ No newline at end of file diff --git a/user_guide_src/source/installation/upgrade_301.rst b/user_guide_src/source/installation/upgrade_301.rst new file mode 100644 index 000000000..f38d34008 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_301.rst @@ -0,0 +1,19 @@ +############################# +Upgrading from 3.0.0 to 3.0.1 +############################# + +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. + +Step 2: Update your CLI error templates +======================================= + +Replace all files under your *application/errors/cli/* directory.
\ No newline at end of file diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 89e90e714..e0f0dd5b7 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -8,9 +8,12 @@ upgrading from. .. toctree:: :titlesonly: - Upgrading from 2.2.x to 3.0.0 <upgrade_300> + Upgrading from 3.0.0 to 3.0.1 <upgrade_301> + Upgrading from 2.2.x to 3.0.x <upgrade_300> + Upgrading from 2.2.2 to 2.2.3 <upgrade_223> + Upgrading from 2.2.1 to 2.2.2 <upgrade_222> Upgrading from 2.2.0 to 2.2.1 <upgrade_221> - Upgrading from 2.1.4 to 2.2.0 <upgrade_220> + Upgrading from 2.1.4 to 2.2.x <upgrade_220> Upgrading from 2.1.3 to 2.1.4 <upgrade_214> Upgrading from 2.1.2 to 2.1.3 <upgrade_213> Upgrading from 2.1.1 to 2.1.2 <upgrade_212> diff --git a/user_guide_src/source/libraries/output.rst b/user_guide_src/source/libraries/output.rst index 4b36d2a03..84529f766 100644 --- a/user_guide_src/source/libraries/output.rst +++ b/user_guide_src/source/libraries/output.rst @@ -160,7 +160,7 @@ Class Reference Permits you to manually set a server status header. Example:: - $this->output->set_status_header('401'); + $this->output->set_status_header(401); // Sets the header as: Unauthorized `See here <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_ for a full list of headers. @@ -230,4 +230,4 @@ Class Reference ->_display(); exit; - .. note:: Calling this method manually without aborting script execution will result in duplicated output.
\ No newline at end of file + .. note:: Calling this method manually without aborting script execution will result in duplicated output. |