diff --git a/index.php b/index.php index 5cc37108a..d02b6bb38 100755 --- a/index.php +++ b/index.php @@ -91,24 +91,25 @@ switch (ENVIRONMENT) /* *--------------------------------------------------------------- - * SYSTEM FOLDER NAME + * SYSTEM DIRECTORY NAME *--------------------------------------------------------------- * - * This variable must contain the name of your "system" folder. - * Include the path if the folder is not in the same directory - * as this file. + * This variable must contain the name of your "system" directory. + * Set the path if it is not in the same directory as this file. */ $system_path = 'system'; /* *--------------------------------------------------------------- - * APPLICATION FOLDER NAME + * APPLICATION DIRECTORY NAME *--------------------------------------------------------------- * * If you want this front controller to use a different "application" - * folder than the default one you can set its name here. The folder - * can also be renamed or relocated anywhere on your server. If - * you do, use a full server path. For more info please see the user guide: + * directory than the default one you can set its name here. The directory + * can also be renamed or relocated anywhere on your server. If you do, + * use an absolute (full) server path. + * For more info please see the user guide: + * * https://codeigniter.com/user_guide/general/managing_apps.html * * NO TRAILING SLASH! @@ -117,14 +118,14 @@ switch (ENVIRONMENT) /* *--------------------------------------------------------------- - * VIEW FOLDER NAME + * VIEW DIRECTORY NAME *--------------------------------------------------------------- * - * If you want to move the view folder out of the application - * folder set the path to the folder here. The folder can be renamed + * If you want to move the view directory out of the application + * directory, set the path to it here. The directory can be renamed * and relocated anywhere on your server. If blank, it will default - * to the standard location inside your application folder. If you - * do move this, use the full server path to this folder. + * to the standard location inside your application directory. + * If you do move this, use an absolute (full) server path. * * NO TRAILING SLASH! */ @@ -150,8 +151,8 @@ switch (ENVIRONMENT) * * Un-comment the $routing array below to use this feature */ - // The directory name, relative to the "controllers" folder. Leave blank - // if your controller is not in a sub-folder within the "controllers" folder + // The directory name, relative to the "controllers" directory. Leave blank + // if your controller is not in a sub-directory within the "controllers" one // $routing['directory'] = ''; // The controller class file name. Example: mycontroller @@ -197,12 +198,16 @@ switch (ENVIRONMENT) if (($_temp = realpath($system_path)) !== FALSE) { - $system_path = $_temp.'/'; + $system_path = $_temp.DIRECTORY_SEPARATOR; } else { // Ensure there's a trailing slash - $system_path = rtrim($system_path, '/').'/'; + $system_path = strtr( + rtrim($system_path, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ).DIRECTORY_SEPARATOR; } // Is the system path correct? @@ -221,66 +226,84 @@ switch (ENVIRONMENT) // The name of THIS file define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME)); - // Path to the system folder - define('BASEPATH', str_replace('\\', '/', $system_path)); + // Path to the system directory + define('BASEPATH', $system_path); - // Path to the front controller (this file) - define('FCPATH', dirname(__FILE__).'/'); + // Path to the front controller (this file) directory + define('FCPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); - // Name of the "system folder" - define('SYSDIR', trim(strrchr(trim(BASEPATH, '/'), '/'), '/')); + // Name of the "system" directory + define('SYSDIR', basename(BASEPATH)); - // The path to the "application" folder + // The path to the "application" directory if (is_dir($application_folder)) { if (($_temp = realpath($application_folder)) !== FALSE) { $application_folder = $_temp; } - - define('APPPATH', $application_folder.DIRECTORY_SEPARATOR); + else + { + $application_folder = strtr( + rtrim($application_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + } + elseif (is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR)) + { + $application_folder = BASEPATH.strtr( + trim($application_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); } else { - if ( ! is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR)) - { - header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); - echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; - exit(3); // EXIT_CONFIG - } - - define('APPPATH', BASEPATH.$application_folder.DIRECTORY_SEPARATOR); + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; + exit(3); // EXIT_CONFIG } - // The path to the "views" folder - if ( ! is_dir($view_folder)) + define('APPPATH', $application_folder.DIRECTORY_SEPARATOR); + + // The path to the "views" directory + if ( ! isset($view_folder[0]) && is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR)) { - if ( ! empty($view_folder) && is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR)) + $view_folder = APPPATH.'views'; + } + elseif (is_dir($view_folder)) + { + if (($_temp = realpath($view_folder)) !== FALSE) { - $view_folder = APPPATH.$view_folder; - } - elseif ( ! is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR)) - { - header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); - echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; - exit(3); // EXIT_CONFIG + $view_folder = $_temp; } else { - $view_folder = APPPATH.'views'; + $view_folder = strtr( + rtrim($view_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); } } - - if (($_temp = realpath($view_folder)) !== FALSE) + elseif (is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR)) { - $view_folder = $_temp.DIRECTORY_SEPARATOR; + $view_folder = APPPATH.strtr( + trim($view_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); } else { - $view_folder = rtrim($view_folder, '/\\').DIRECTORY_SEPARATOR; + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; + exit(3); // EXIT_CONFIG } - define('VIEWPATH', $view_folder); + define('VIEWPATH', $view_folder.DIRECTORY_SEPARATOR); /* * -------------------------------------------------------------------- diff --git a/license/codeigniter_version.txt b/license/codeigniter_version.txt index 7da3c1687..8ffc1ad64 100644 --- a/license/codeigniter_version.txt +++ b/license/codeigniter_version.txt @@ -1 +1 @@ -3.0.5 \ No newline at end of file +3.0.6 \ No newline at end of file diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php index 94d34c3fd..3eb3e0573 100644 --- a/system/core/CodeIgniter.php +++ b/system/core/CodeIgniter.php @@ -55,7 +55,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @var string * */ - define('CI_VERSION', '3.0.5'); + define('CI_VERSION', '3.0.6'); /* * ------------------------------------------------------ diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php index 7e67fc40f..6dee1e8e4 100644 --- a/system/libraries/Cache/drivers/Cache_memcached.php +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -60,7 +60,7 @@ class CI_Cache_memcached extends CI_Driver { * * @var array */ - protected $_memcache_conf = array( + protected $_config = array( 'default' => array( 'host' => '127.0.0.1', 'port' => 11211, @@ -81,19 +81,11 @@ class CI_Cache_memcached extends CI_Driver { { // Try to load memcached server info from the config file. $CI =& get_instance(); - $defaults = $this->_memcache_conf['default']; + $defaults = $this->_config['default']; if ($CI->config->load('memcached', TRUE, TRUE)) { - if (is_array($CI->config->config['memcached'])) - { - $this->_memcache_conf = array(); - - foreach ($CI->config->config['memcached'] as $name => $conf) - { - $this->_memcache_conf[$name] = $conf; - } - } + $this->_config = $CI->config->config['memcached']; } if (class_exists('Memcached', FALSE)) @@ -110,13 +102,13 @@ class CI_Cache_memcached extends CI_Driver { return; } - foreach ($this->_memcache_conf as $cache_server) + foreach ($this->_config as $cache_server) { isset($cache_server['hostname']) OR $cache_server['hostname'] = $defaults['host']; isset($cache_server['port']) OR $cache_server['port'] = $defaults['port']; isset($cache_server['weight']) OR $cache_server['weight'] = $defaults['weight']; - if (get_class($this->_memcached) === 'Memcache') + if ($this->_memcached instanceof Memcache) { // Third parameter is persistance and defaults to TRUE. $this->_memcached->addServer( @@ -126,7 +118,7 @@ class CI_Cache_memcached extends CI_Driver { $cache_server['weight'] ); } - else + elseif ($this->_memcached instanceof Memcached) { $this->_memcached->addServer( $cache_server['hostname'], @@ -170,11 +162,11 @@ class CI_Cache_memcached extends CI_Driver { $data = array($data, time(), $ttl); } - if (get_class($this->_memcached) === 'Memcached') + if ($this->_memcached instanceof Memcached) { return $this->_memcached->set($id, $data, $ttl); } - elseif (get_class($this->_memcached) === 'Memcache') + elseif ($this->_memcached instanceof Memcache) { return $this->_memcached->set($id, $data, 0, $ttl); } @@ -187,7 +179,7 @@ class CI_Cache_memcached extends CI_Driver { /** * Delete from Cache * - * @param mixed key to be deleted. + * @param mixed $id key to be deleted. * @return bool true on success, false on failure */ public function delete($id) @@ -252,7 +244,7 @@ class CI_Cache_memcached extends CI_Driver { /** * Get Cache Metadata * - * @param mixed key to get cache metadata on + * @param mixed $id key to get cache metadata on * @return mixed FALSE on failure, array on success. */ public function get_metadata($id) @@ -287,4 +279,25 @@ class CI_Cache_memcached extends CI_Driver { { return (extension_loaded('memcached') OR extension_loaded('memcache')); } + + // ------------------------------------------------------------------------ + + /** + * Class destructor + * + * Closes the connection to Memcache(d) if present. + * + * @return void + */ + public function __destruct() + { + if ($this->_memcached instanceof Memcache) + { + $this->_memcached->close(); + } + elseif ($this->_memcached instanceof Memcached) + { + $this->_memcached->quit(); + } + } } diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php index e9194a499..d4d95ebb1 100644 --- a/system/libraries/Cache/drivers/Cache_redis.php +++ b/system/libraries/Cache/drivers/Cache_redis.php @@ -97,15 +97,17 @@ class CI_Cache_redis extends CI_Driver return; } - $config = array(); $CI =& get_instance(); if ($CI->config->load('redis', TRUE, TRUE)) { - $config = $CI->config->item('redis'); + $config = array_merge(self::$_default_config, $CI->config->item('redis')); + } + else + { + $config = self::$_default_config; } - $config = array_merge(self::$_default_config, $config); $this->_redis = new Redis(); try @@ -144,7 +146,7 @@ class CI_Cache_redis extends CI_Driver /** * Get cache * - * @param string Cache ID + * @param string $key Cache ID * @return mixed */ public function get($key) @@ -196,7 +198,7 @@ class CI_Cache_redis extends CI_Driver /** * Delete from cache * - * @param string Cache key + * @param string $key Cache key * @return bool */ public function delete($key) @@ -261,9 +263,9 @@ class CI_Cache_redis extends CI_Driver /** * Get cache driver info * - * @param string Not supported in Redis. - * Only included in order to offer a - * consistent cache API. + * @param string $type Not supported in Redis. + * Only included in order to offer a + * consistent cache API. * @return array * @see Redis::info() */ @@ -277,7 +279,7 @@ class CI_Cache_redis extends CI_Driver /** * Get cache metadata * - * @param string Cache key + * @param string $key Cache key * @return array */ public function get_metadata($key) diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 8b08aacc7..ed6f737a1 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -65,7 +65,7 @@ class CI_Email { public $mailpath = '/usr/sbin/sendmail'; // Sendmail path /** - * Which method to use for sending emails. + * Which method to use for sending e-mails. * * @var string 'mail', 'sendmail' or 'smtp' */ @@ -164,7 +164,7 @@ class CI_Email { public $alt_message = ''; /** - * Whether to validate email addresses. + * Whether to validate e-mail addresses. * * @var bool */ diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 296ddb92a..e4a518957 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -450,7 +450,7 @@ class CI_Form_validation { $this->CI->lang->load('form_validation'); // Cycle through the rules for each field and match the corresponding $validation_data item - foreach ($this->_field_data as $field => $row) + foreach ($this->_field_data as $field => &$row) { // Fetch the data from the validation_data array item and cache it in the _field_data array. // Depending on whether the field name is an array or a string will determine where we get it from. @@ -467,7 +467,7 @@ class CI_Form_validation { // Execute validation rules // Note: A second foreach (for now) is required in order to avoid false-positives // for rules like 'matches', which correlate to other validation fields. - foreach ($this->_field_data as $field => $row) + foreach ($this->_field_data as $field => &$row) { // Don't try to validate if we have no rules set if (empty($row['rules'])) @@ -475,7 +475,7 @@ class CI_Form_validation { continue; } - $this->_execute($row, $row['rules'], $this->_field_data[$field]['postdata']); + $this->_execute($row, $row['rules'], $row['postdata']); } // Did we end up with any errors? @@ -486,7 +486,7 @@ class CI_Form_validation { } // Now we need to re-set the POST data with the new, processed data - $this->_reset_post_array(); + empty($this->validation_data) && $this->_reset_post_array(); return ($total_errors === 0); } @@ -527,10 +527,7 @@ class CI_Form_validation { { if ($row['is_array'] === FALSE) { - if (isset($_POST[$row['field']])) - { - $_POST[$row['field']] = $row['postdata']; - } + isset($_POST[$field]) && $_POST[$field] = $row['postdata']; } else { @@ -550,20 +547,7 @@ class CI_Form_validation { } } - if (is_array($row['postdata'])) - { - $array = array(); - foreach ($row['postdata'] as $k => $v) - { - $array[$k] = $v; - } - - $post_ref = $array; - } - else - { - $post_ref = $row['postdata']; - } + $post_ref = $row['postdata']; } } } @@ -583,7 +567,10 @@ class CI_Form_validation { protected function _execute($row, $rules, $postdata = NULL, $cycles = 0) { // If the $_POST data is an array we will run a recursive call - if (is_array($postdata)) + // + // Note: We MUST check if the array is empty or not! + // Otherwise empty arrays will always pass validation. + if (is_array($postdata) && ! empty($postdata)) { foreach ($postdata as $key => $val) { @@ -1512,10 +1499,11 @@ class CI_Form_validation { * This function allows HTML to be safely shown in a form. * Special characters are converted. * - * @param string - * @return string + * @deprecated 3.0.6 Not used anywhere within the framework and pretty much useless + * @param mixed $data Input data + * @return mixed */ - public function prep_for_form($data = '') + public function prep_for_form($data) { if ($this->_safe_form_data === FALSE OR empty($data)) { diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php index 7aefb6c23..316c94ae3 100644 --- a/system/libraries/Migration.php +++ b/system/libraries/Migration.php @@ -96,9 +96,9 @@ class CI_Migration { /** * Migration basename regex * - * @var bool + * @var string */ - protected $_migration_regex = NULL; + protected $_migration_regex; /** * Error message @@ -217,31 +217,66 @@ class CI_Migration { if ($target_version > $current_version) { - // Moving Up $method = 'up'; } + elseif ($target_version < $current_version) + { + $method = 'down'; + // We need this so that migrations are applied in reverse order + krsort($migrations); + } else { - // Moving Down, apply in reverse order - $method = 'down'; - krsort($migrations); - } - - if (empty($migrations)) - { + // Well, there's nothing to migrate then ... return TRUE; } - $previous = FALSE; - - // Validate all available migrations, and run the ones within our target range + // Validate all available migrations within our target range. + // + // Unfortunately, we'll have to use another loop to run them + // in order to avoid leaving the procedure in a broken state. + // + // See https://github.com/bcit-ci/CodeIgniter/issues/4539 + $pending = array(); foreach ($migrations as $number => $file) { - // Check for sequence gaps - if ($this->_migration_type === 'sequential' && $previous !== FALSE && abs($number - $previous) > 1) + // Ignore versions out of our range. + // + // Because we've previously sorted the $migrations array depending on the direction, + // we can safely break the loop once we reach $target_version ... + if ($method === 'up') { - $this->_error_string = sprintf($this->lang->line('migration_sequence_gap'), $number); - return FALSE; + if ($number <= $current_version) + { + continue; + } + elseif ($number > $target_version) + { + break; + } + } + else + { + if ($number > $current_version) + { + continue; + } + elseif ($number <= $target_version) + { + break; + } + } + + // Check for sequence gaps + if ($this->_migration_type === 'sequential') + { + if (isset($previous) && abs($number - $previous) > 1) + { + $this->_error_string = sprintf($this->lang->line('migration_sequence_gap'), $number); + return FALSE; + } + + $previous = $number; } include_once($file); @@ -253,27 +288,27 @@ class CI_Migration { $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); return FALSE; } - - $previous = $number; - - // Run migrations that are inside the target range - if ( - ($method === 'up' && $number > $current_version && $number <= $target_version) OR - ($method === 'down' && $number <= $current_version && $number > $target_version) - ) + // method_exists() returns true for non-public methods, + // while is_callable() can't be used without instantiating. + // Only get_class_methods() satisfies both conditions. + elseif ( ! in_array($method, array_map('strtolower', get_class_methods($class)))) { - $instance = new $class(); - if ( ! is_callable(array($instance, $method))) - { - $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); - return FALSE; - } - - log_message('debug', 'Migrating '.$method.' from version '.$current_version.' to version '.$number); - call_user_func(array($instance, $method)); - $current_version = $number; - $this->_update_version($current_version); + $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); + return FALSE; } + + $pending[$number] = array($class, $method); + } + + // Now just run the necessary migrations + foreach ($pending as $number => $migration) + { + log_message('debug', 'Migrating '.$method.' from version '.$current_version.' to version '.$number); + + $migration[0] = new $migration[0]; + call_user_func($migration); + $current_version = $number; + $this->_update_version($current_version); } // This is necessary when moving down, since the the last migration applied @@ -285,7 +320,6 @@ class CI_Migration { } log_message('debug', 'Finished migrating to '.$current_version); - return $current_version; } diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 77c56ae70..c9d2e8adc 100644 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -583,6 +583,24 @@ class CI_Session { // ------------------------------------------------------------------------ + /** + * __isset() + * + * @param string $key 'session_id' or a session data key + * @return bool + */ + public function __isset($key) + { + if ($key === 'session_id') + { + return (session_status() === PHP_SESSION_ACTIVE); + } + + return isset($_SESSION[$key]); + } + + // ------------------------------------------------------------------------ + /** * __set() *