diff options
Diffstat (limited to 'system')
37 files changed, 661 insertions, 310 deletions
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php index 1c6e76b4f..5ff788ae3 100644 --- a/system/core/CodeIgniter.php +++ b/system/core/CodeIgniter.php @@ -249,7 +249,7 @@ if ( ! is_php('5.4')) require_once(BASEPATH.'core/compat/mbstring.php'); require_once(BASEPATH.'core/compat/hash.php'); require_once(BASEPATH.'core/compat/password.php'); - require_once(BASEPATH.'core/compat/array.php'); + require_once(BASEPATH.'core/compat/standard.php'); /* * ------------------------------------------------------ @@ -449,6 +449,23 @@ if ( ! is_php('5.4')) /* * ------------------------------------------------------ + * Should we use a Composer autoloader? + * ------------------------------------------------------ + */ + if (($composer_autoload = config_item('composer_autoload')) !== FALSE) + { + if ($composer_autoload === TRUE && file_exists(APPPATH.'vendor/autoload.php')) + { + require_once(APPPATH.'vendor/autoload.php'); + } + elseif (file_exists($composer_autoload)) + { + require_once($composer_autoload); + } + } + +/* + * ------------------------------------------------------ * Is there a "pre_controller" hook? * ------------------------------------------------------ */ diff --git a/system/core/Common.php b/system/core/Common.php index 752a2e7f1..504e22571 100644 --- a/system/core/Common.php +++ b/system/core/Common.php @@ -289,7 +289,7 @@ if ( ! function_exists('config_item')) $_config[0] =& get_config(); } - return isset($_config[0][$item]) ? $_config[0][$item] : FALSE; + return isset($_config[0][$item]) ? $_config[0][$item] : NULL; } } @@ -690,16 +690,20 @@ if ( ! function_exists('remove_invisible_characters')) if ( ! function_exists('html_escape')) { /** - * Returns HTML escaped variable + * Returns HTML escaped variable. * - * @param mixed - * @return mixed + * @param mixed $var The input string or array of strings to be escaped. + * @param bool $double_encode $double_encode set to FALSE prevents escaping twice. + * @return mixed The escaped string or array of strings as a result. */ - function html_escape($var) + function html_escape($var, $double_encode = TRUE) { - return is_array($var) - ? array_map('html_escape', $var) - : htmlspecialchars($var, ENT_QUOTES, config_item('charset')); + if (is_array($var)) + { + return array_map('html_escape', $var, array_fill(0, count($var), $double_encode)); + } + + return htmlspecialchars($var, ENT_QUOTES, config_item('charset'), $double_encode); } } diff --git a/system/core/Config.php b/system/core/Config.php index ad0e5f981..db406dfde 100644 --- a/system/core/Config.php +++ b/system/core/Config.php @@ -104,10 +104,11 @@ class CI_Config { public function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) { $file = ($file === '') ? 'config' : str_replace('.php', '', $file); - $found = $loaded = FALSE; + $loaded = FALSE; foreach ($this->_config_paths as $path) { + $found = FALSE; foreach (array(ENVIRONMENT.'/'.$file, $file) as $location) { $file_path = $path.'config/'.$location.'.php'; diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php index cb4bc3cd6..49c2217c9 100644 --- a/system/core/Exceptions.php +++ b/system/core/Exceptions.php @@ -145,9 +145,11 @@ class CI_Exceptions { */ public function show_error($heading, $message, $template = 'error_general', $status_code = 500) { - $templates_path = config_item('error_views_path') - ? config_item('error_views_path') - : VIEWPATH.'errors'.DIRECTORY_SEPARATOR; + $templates_path = config_item('error_views_path'); + if (empty($templates_path)) + { + $templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR; + } if (is_cli()) { @@ -185,9 +187,11 @@ class CI_Exceptions { */ public function show_php_error($severity, $message, $filepath, $line) { - $templates_path = config_item('error_views_path') - ? config_item('error_views_path') - : VIEWPATH.'errors'.DIRECTORY_SEPARATOR; + $templates_path = config_item('error_views_path'); + if (empty($templates_path)) + { + $templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR; + } $severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity; diff --git a/system/core/Hooks.php b/system/core/Hooks.php index fd1a2ba11..26ced0894 100644 --- a/system/core/Hooks.php +++ b/system/core/Hooks.php @@ -127,7 +127,7 @@ class CI_Hooks { return FALSE; } - if (is_array($this->hooks[$which])) + if (is_array($this->hooks[$which]) && ! isset($this->hooks[$which]['function'])) { foreach ($this->hooks[$which] as $val) { diff --git a/system/core/Input.php b/system/core/Input.php index 544b7c08b..9ae2f6d6f 100644 --- a/system/core/Input.php +++ b/system/core/Input.php @@ -353,7 +353,7 @@ class CI_Input { $path = config_item('cookie_path'); } - if ($secure === FALSE && config_item('cookie_secure') !== FALSE) + if ($secure === FALSE && config_item('cookie_secure') === TRUE) { $secure = config_item('cookie_secure'); } @@ -766,7 +766,7 @@ class CI_Input { * * @param string $index Header name * @param bool $xss_clean Whether to apply XSS filtering - * @return string|bool The requested header on success or FALSE on failure + * @return string|null The requested header on success or NULL on failure */ public function get_request_header($index, $xss_clean = FALSE) { diff --git a/system/core/Log.php b/system/core/Log.php index a949c3f39..1dca1bf3b 100644 --- a/system/core/Log.php +++ b/system/core/Log.php @@ -45,32 +45,39 @@ class CI_Log { protected $_log_path; /** + * File permissions + * + * @var int + */ + protected $_file_permissions = 0644; + + /** * Level of logging * * @var int */ - protected $_threshold = 1; + protected $_threshold = 1; /** * Highest level of logging * * @var int */ - protected $_threshold_max = 0; + protected $_threshold_max = 0; /** * Array of threshold levels to log * * @var array */ - protected $_threshold_array = array(); + protected $_threshold_array = array(); /** * Format of timestamp for log files * * @var string */ - protected $_date_fmt = 'Y-m-d H:i:s'; + protected $_date_fmt = 'Y-m-d H:i:s'; /** * Filename extension @@ -84,14 +91,14 @@ class CI_Log { * * @var bool */ - protected $_enabled = TRUE; + protected $_enabled = TRUE; /** * Predefined logging levels * * @var array */ - protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4); + protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4); // -------------------------------------------------------------------- @@ -108,7 +115,7 @@ class CI_Log { $this->_file_ext = (isset($config['log_file_extension']) && $config['log_file_extension'] !== '') ? ltrim($config['log_file_extension'], '.') : 'php'; - file_exists($this->_log_path) OR mkdir($this->_log_path, 0777, TRUE); + file_exists($this->_log_path) OR mkdir($this->_log_path, 0755, TRUE); if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path)) { @@ -125,10 +132,15 @@ class CI_Log { $this->_threshold_array = array_flip($config['log_threshold']); } - if ($config['log_date_format'] !== '') + if ( ! empty($config['log_date_format'])) { $this->_date_fmt = $config['log_date_format']; } + + if ( ! empty($config['log_file_permissions']) && is_int($config['log_file_permissions'])) + { + $this->_file_permissions = $config['log_file_permissions']; + } } // -------------------------------------------------------------------- @@ -192,7 +204,7 @@ class CI_Log { if (isset($newfile) && $newfile === TRUE) { - @chmod($filepath, 0666); + chmod($filepath, $this->_file_permissions); } return is_int($result); diff --git a/system/core/Output.php b/system/core/Output.php index 238d223e2..de07125ad 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -606,7 +606,7 @@ class CI_Output { if (is_int($result)) { - @chmod($cache_path, 0666); + chmod($cache_path, 0640); log_message('debug', 'Cache file written: '.$cache_path); // Send HTTP cache-control headers to browser to match file cache settings. diff --git a/system/core/Security.php b/system/core/Security.php index 2cf214b18..cffdb9ad9 100755 --- a/system/core/Security.php +++ b/system/core/Security.php @@ -77,7 +77,7 @@ class CI_Security { * * @var string */ - protected $_xss_hash = ''; + protected $_xss_hash; /** * CSRF Hash @@ -86,7 +86,7 @@ class CI_Security { * * @var string */ - protected $_csrf_hash = ''; + protected $_csrf_hash; /** * CSRF Expire time @@ -158,7 +158,7 @@ class CI_Security { public function __construct() { // Is CSRF protection enabled? - if (config_item('csrf_protection') === TRUE) + if (config_item('csrf_protection')) { // CSRF config foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key) @@ -170,9 +170,9 @@ class CI_Security { } // Append application specific cookie prefix - if (config_item('cookie_prefix')) + if ($cookie_prefix = config_item('cookie_prefix')) { - $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name; + $this->_csrf_cookie_name = $cookie_prefix.$this->_csrf_cookie_name; } // Set the CSRF hash @@ -203,9 +203,12 @@ class CI_Security { if ($exclude_uris = config_item('csrf_exclude_uris')) { $uri = load_class('URI', 'core'); - if (in_array($uri->uri_string(), $exclude_uris)) + foreach ($exclude_uris as $excluded) { - return $this; + if (preg_match('#^'.$excluded.'$#i'.(UTF8_ENABLED ? 'u' : ''), $uri->uri_string())) + { + return $this; + } } } @@ -224,7 +227,7 @@ class CI_Security { { // Nothing should last forever unset($_COOKIE[$this->_csrf_cookie_name]); - $this->_csrf_hash = ''; + $this->_csrf_hash = NULL; } $this->_csrf_set_hash(); @@ -275,7 +278,7 @@ class CI_Security { */ public function csrf_show_error() { - show_error('The action you have requested is not allowed.'); + show_error('The action you have requested is not allowed.', 403); } // -------------------------------------------------------------------- @@ -370,7 +373,7 @@ class CI_Security { * We only convert entities that are within tags since * these are the ones that will pose security problems. */ - $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); + $str = preg_replace_callback("/[^a-z0-9>]+[a-z0-9]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); $str = preg_replace_callback('/<\w+.*/si', array($this, '_decode_entity'), $str); // Remove Invisible Characters Again! @@ -436,7 +439,7 @@ class CI_Security { /* * Remove disallowed Javascript in links or img tags - * We used to do some version comparisons and use of stripos for PHP5, + * We used to do some version comparisons and use of stripos(), * but it is dog slow compared to these simplified non-capturing * preg_match(), especially if the pattern exists in the string * @@ -535,9 +538,12 @@ class CI_Security { */ public function xss_hash() { - if ($this->_xss_hash === '') + if ($this->_xss_hash === NULL) { - $this->_xss_hash = md5(uniqid(mt_rand())); + $rand = $this->get_random_bytes(16); + $this->_xss_hash = ($rand === FALSE) + ? md5(uniqid(mt_rand(), TRUE)) + : bin2hex($rand); } return $this->_xss_hash; @@ -546,6 +552,48 @@ class CI_Security { // -------------------------------------------------------------------- /** + * Get random bytes + * + * @param int $length Output length + * @return string + */ + public function get_random_bytes($length) + { + if (empty($length) OR ! ctype_digit((string) $length)) + { + return FALSE; + } + + // Unfortunately, none of the following PRNGs is guaranteed to exist ... + if (defined('MCRYPT_DEV_URANDOM') && ($output = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)) !== FALSE) + { + return $output; + } + + + if (is_readable('/dev/urandom') && ($fp = fopen('/dev/urandom', 'rb')) !== FALSE) + { + // Try not to waste entropy ... + is_php('5.4') && stream_set_chunk_size($fp, $length); + $output = fread($fp, $length); + fclose($fp); + if ($output !== FALSE) + { + return $output; + } + } + + if (function_exists('openssl_random_pseudo_bytes')) + { + return openssl_random_pseudo_bytes($length); + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** * HTML Entities Decode * * A replacement for html_entity_decode() @@ -605,7 +653,7 @@ class CI_Security { { if (($char = array_search($matches[$i].';', $_entities, TRUE)) !== FALSE) { - $replace[$matches[$i]] = $character; + $replace[$matches[$i]] = $char; } } @@ -912,7 +960,7 @@ class CI_Security { */ protected function _csrf_set_hash() { - if ($this->_csrf_hash === '') + if ($this->_csrf_hash === NULL) { // If the cookie exists we will use its value. // We don't necessarily want to regenerate it with @@ -924,8 +972,10 @@ class CI_Security { return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name]; } - $this->_csrf_hash = md5(uniqid(mt_rand(), TRUE)); - $this->csrf_set_cookie(); + $rand = $this->get_random_bytes(16); + $this->_csrf_hash = ($rand === FALSE) + ? md5(uniqid(mt_rand(), TRUE)) + : bin2hex($rand); } return $this->_csrf_hash; diff --git a/system/core/compat/password.php b/system/core/compat/password.php index a9355d5d0..1f67a5269 100644 --- a/system/core/compat/password.php +++ b/system/core/compat/password.php @@ -83,6 +83,9 @@ if ( ! function_exists('password_hash')) */ function password_hash($password, $algo, array $options = array()) { + static $func_override; + isset($func_override) OR $func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override')); + if ($algo !== 1) { trigger_error('password_hash(): Unknown hashing algorithm: '.(int) $algo, E_USER_WARNING); @@ -95,9 +98,9 @@ if ( ! function_exists('password_hash')) return NULL; } - if (isset($options['salt']) && strlen($options['salt']) < 22) + if (isset($options['salt']) && ($saltlen = ($func_override ? mb_strlen($options['salt'], '8bit') : strlen($options['salt']))) < 22) { - trigger_error('password_hash(): Provided salt is too short: '.strlen($options['salt']).' expecting 22', E_USER_WARNING); + trigger_error('password_hash(): Provided salt is too short: '.$saltlen.' expecting 22', E_USER_WARNING); return NULL; } elseif ( ! isset($options['salt'])) @@ -118,8 +121,11 @@ if ( ! function_exists('password_hash')) return FALSE; } + // Try not to waste entropy ... + is_php('5.4') && stream_set_chunk_size($fp, 16); + $options['salt'] = ''; - for ($read = 0; $read < 16; $read = strlen($options['salt'])) + for ($read = 0; $read < 16; $read = ($func_override) ? mb_strlen($options['salt'], '8bit') : strlen($options['salt'])) { if (($read = fread($fp, 16 - $read)) === FALSE) { @@ -145,7 +151,10 @@ if ( ! function_exists('password_hash')) } isset($options['cost']) OR $options['cost'] = 10; - return crypt($password, sprintf('$2y$%02d$%s', $options['cost'], $options['salt'])); + + return (strlen($password = crypt($password, sprintf('$2y$%02d$%s', $options['cost'], $options['salt']))) === 60) + ? $password + : FALSE; } } diff --git a/system/core/compat/array.php b/system/core/compat/standard.php index 07dae21c2..afe9e9852 100644 --- a/system/core/compat/array.php +++ b/system/core/compat/standard.php @@ -27,14 +27,13 @@ defined('BASEPATH') OR exit('No direct script access allowed'); /** - * PHP ext/standard/array compatibility package + * PHP ext/standard compatibility package * * @package CodeIgniter * @subpackage CodeIgniter * @category Compatibility * @author Andrey Andreev * @link http://codeigniter.com/user_guide/ - * @link http://php.net/book.array */ // ------------------------------------------------------------------------ @@ -125,6 +124,54 @@ if ( ! function_exists('array_column')) // ------------------------------------------------------------------------ +if (is_php('5.4')) +{ + return; +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('hex2bin')) +{ + /** + * hex2bin() + * + * @link http://php.net/hex2bin + * @param string $data + * @return string + */ + function hex2bin($data) + { + if (in_array($type = gettype($data), array('array', 'double', 'object'), TRUE)) + { + if ($type === 'object' && method_exists($data, '__toString')) + { + $data = (string) $data; + } + else + { + trigger_error('hex2bin() expects parameter 1 to be string, '.$type.' given', E_USER_WARNING); + return NULL; + } + } + + if (strlen($data) % 2 !== 0) + { + trigger_error('Hexadecimal input string must have an even length', E_USER_WARNING); + return FALSE; + } + elseif ( ! preg_match('/^[0-9a-f]*$/i', $data)) + { + trigger_error('Input string must be hexadecimal string', E_USER_WARNING); + return FALSE; + } + + return pack('H*', $data); + } +} + +// ------------------------------------------------------------------------ + if (is_php('5.3')) { return; @@ -242,5 +289,93 @@ if ( ! function_exists('array_replace_recursive')) } } -/* End of file array.php */ -/* Location: ./system/core/compat/array.php */
\ No newline at end of file +// ------------------------------------------------------------------------ + +if ( ! function_exists('quoted_printable_encode')) +{ + /** + * quoted_printable_encode() + * + * @link http://php.net/quoted_printable_encode + * @param string $str + * @return string + */ + function quoted_printable_encode($str) + { + if (strlen($str) === 0) + { + return ''; + } + elseif (in_array($type = gettype($str), array('array', 'object'), TRUE)) + { + if ($type === 'object' && method_exists($str, '__toString')) + { + $str = (string) $str; + } + else + { + trigger_error('quoted_printable_encode() expects parameter 1 to be string, '.$type.' given', E_USER_WARNING); + return NULL; + } + } + + if (function_exists('imap_8bit')) + { + return imap_8bit($str); + } + + $i = $lp = 0; + $output = ''; + $hex = '0123456789ABCDEF'; + $length = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')) + ? mb_strlen($str, '8bit') + : strlen($str); + + while ($length--) + { + if ((($c = $str[$i++]) === "\015") && isset($str[$i]) && ($str[$i] === "\012") && $length > 0) + { + $output .= "\015".$str[$i++]; + $length--; + $lp = 0; + continue; + } + + if ( + ctype_cntrl($c) + OR (ord($c) === 0x7f) + OR (ord($c) & 0x80) + OR ($c === '=') + OR ($c === ' ' && isset($str[$i]) && $str[$i] === "\015") + ) + { + if ( + (($lp += 3) > 75 && ord($c) <= 0x7f) + OR (ord($c) > 0x7f && ord($c) <= 0xdf && ($lp + 3) > 75) + OR (ord($c) > 0xdf && ord($c) <= 0xef && ($lp + 6) > 75) + OR (ord($c) > 0xef && ord($c) <= 0xf4 && ($lp + 9) > 75) + ) + { + $output .= "=\015\012"; + $lp = 3; + } + + $output .= '='.$hex[ord($c) >> 4].$hex[ord($c) & 0xf]; + continue; + } + + if ((++$lp) > 75) + { + $output .= "=\015\012"; + $lp = 1; + } + + $output .= $c; + } + + return $output; + } +} + +/* End of file standard.php */ +/* Location: ./system/core/compat/standard.php */
\ No newline at end of file diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php index b855ff24e..2efb42c5c 100644 --- a/system/database/DB_cache.php +++ b/system/database/DB_cache.php @@ -156,14 +156,9 @@ class CI_DB_Cache { $dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'; $filename = md5($sql); - if ( ! is_dir($dir_path)) + if ( ! is_dir($dir_path) && ! @mkdir($dir_path, 0750)) { - if ( ! @mkdir($dir_path, 0777)) - { - return FALSE; - } - - @chmod($dir_path, 0777); + return FALSE; } if (write_file($dir_path.$filename, serialize($object)) === FALSE) @@ -171,7 +166,7 @@ class CI_DB_Cache { return FALSE; } - @chmod($dir_path.$filename, 0666); + chmod($dir_path.$filename, 0640); return TRUE; } diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php index 12ab5bb2a..62cea758e 100644 --- a/system/database/DB_driver.php +++ b/system/database/DB_driver.php @@ -1440,7 +1440,7 @@ abstract class CI_DB_driver { */ protected function _has_operator($str) { - return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str)); + return (bool) preg_match('/(<|>|!|=|\sIS\s|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str)); } // -------------------------------------------------------------------- @@ -1464,8 +1464,7 @@ abstract class CI_DB_driver { '\s*(?:<|>|!)?=\s*', // =, <=, >=, != '\s*<>?\s*', // <, <> '\s*>\s*', // > - '\s+IS NULL', // IS NULL - '\s+IS NOT NULL', // IS NOT NULL + '\s+IS(?:\sNOT)?(?:\sNULL)?', // IS[ NOT] NULL '\s+EXISTS\s*\([^\)]+\)', // EXISTS(sql) '\s+NOT EXISTS\s*\([^\)]+\)', // NOT EXISTS(sql) '\s+BETWEEN\s+\S+\s+AND\s+\S+', // BETWEEN value AND value diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php index 111546ecc..2dd243cae 100644 --- a/system/database/DB_forge.php +++ b/system/database/DB_forge.php @@ -929,7 +929,7 @@ abstract class CI_DB_forge { $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null; // Override the NULL attribute if that's our default - $attributes['NULL'] = NULL; + $attributes['NULL'] = TRUE; $field['null'] = empty($this->_null) ? '' : ' '.$this->_null; } else diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php index 085c615e5..2096ffd60 100644 --- a/system/database/DB_query_builder.php +++ b/system/database/DB_query_builder.php @@ -635,7 +635,7 @@ abstract class CI_DB_query_builder extends CI_DB_driver { $key = array($key => $value); } - // If the escape value was not set will will base it on the global setting + // If the escape value was not set will base it on the global setting is_bool($escape) OR $escape = $this->_protect_identifiers; foreach ($key as $k => $v) @@ -661,6 +661,10 @@ abstract class CI_DB_query_builder extends CI_DB_driver { // value appears not to have been set, assign the test to IS NULL $k .= ' IS NULL'; } + elseif (preg_match('/\s*(!?=|<>)\s*$/i', $k, $match, PREG_OFFSET_CAPTURE)) + { + $k = substr($k, 0, $match[0][1]).($match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL'); + } $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); if ($this->qb_caching === TRUE) diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php index 138b0ed45..c5cb79683 100644 --- a/system/database/drivers/cubrid/cubrid_driver.php +++ b/system/database/drivers/cubrid/cubrid_driver.php @@ -264,14 +264,7 @@ class CI_DB_cubrid_driver extends CI_DB { */ protected function _escape_str($str) { - if (function_exists('cubrid_real_escape_string') && - (is_resource($this->conn_id) - OR (get_resource_type($this->conn_id) === 'Unknown' && preg_match('/Resource id #/', strval($this->conn_id))))) - { - return cubrid_real_escape_string($str, $this->conn_id); - } - - return addslashes($str); + return cubrid_real_escape_string($str, $this->conn_id); } // -------------------------------------------------------------------- diff --git a/system/database/drivers/ibase/ibase_driver.php b/system/database/drivers/ibase/ibase_driver.php index b19985c37..f4e5aef7c 100644 --- a/system/database/drivers/ibase/ibase_driver.php +++ b/system/database/drivers/ibase/ibase_driver.php @@ -219,11 +219,11 @@ class CI_DB_ibase_driver extends CI_DB { */ protected function _list_tables($prefix_limit = FALSE) { - $sql = 'SELECT "RDB$RELATION_NAME" FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\''; + $sql = 'SELECT TRIM("RDB$RELATION_NAME") AS TABLE_NAME FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\''; if ($prefix_limit !== FALSE && $this->dbprefix !== '') { - return $sql.' AND "RDB$RELATION_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " + return $sql.' AND TRIM("RDB$RELATION_NAME") AS TABLE_NAME LIKE \''.$this->escape_like_str($this->dbprefix)."%' " .sprintf($this->_like_escape_str, $this->_like_escape_chr); } @@ -242,7 +242,7 @@ class CI_DB_ibase_driver extends CI_DB { */ protected function _list_columns($table = '') { - return 'SELECT "RDB$FIELD_NAME" FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table); + return 'SELECT TRIM("RDB$FIELD_NAME") AS COLUMN_NAME FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table); } // -------------------------------------------------------------------- diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php index f4a166180..8d830fb51 100644 --- a/system/database/drivers/mssql/mssql_driver.php +++ b/system/database/drivers/mssql/mssql_driver.php @@ -143,8 +143,8 @@ class CI_DB_mssql_driver extends CI_DB { } // Note: Escaping is required in the event that the DB name - // contains reserved characters - if (mssql_select_db($this->escape_identifiers($database), $this->conn_id)) + // contains reserved characters. + if (mssql_select_db('['.$database.']', $this->conn_id)) { $this->database = $database; return TRUE; diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php index 7cbcf1028..a827a6ed4 100644 --- a/system/database/drivers/mysql/mysql_driver.php +++ b/system/database/drivers/mysql/mysql_driver.php @@ -336,9 +336,7 @@ class CI_DB_mysql_driver extends CI_DB { */ protected function _escape_str($str) { - return is_resource($this->conn_id) - ? mysql_real_escape_string($str, $this->conn_id) - : addslashes($str); + return mysql_real_escape_string($str, $this->conn_id); } // -------------------------------------------------------------------- diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php index 09277fc39..aa4c6b559 100644 --- a/system/database/drivers/mysqli/mysqli_driver.php +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -307,9 +307,7 @@ class CI_DB_mysqli_driver extends CI_DB { */ protected function _escape_str($str) { - return is_object($this->conn_id) - ? $this->conn_id->real_escape_string($str) - : addslashes($str); + return $this->conn_id->real_escape_string($str); } // -------------------------------------------------------------------- diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php index 1b8fbc9d4..3f3af2e19 100644 --- a/system/database/drivers/pdo/pdo_result.php +++ b/system/database/drivers/pdo/pdo_result.php @@ -93,7 +93,7 @@ class CI_DB_pdo_result extends CI_DB_result { { // Might trigger an E_WARNING due to not all subdrivers // supporting getColumnMeta() - $field_names[$i] = @$this->result_id->getColumnMeta(); + $field_names[$i] = @$this->result_id->getColumnMeta($i); $field_names[$i] = $field_names[$i]['name']; } diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php index a7d0d087d..2b447a1b3 100644 --- a/system/database/drivers/sqlite3/sqlite3_driver.php +++ b/system/database/drivers/sqlite3/sqlite3_driver.php @@ -189,7 +189,7 @@ class CI_DB_sqlite3_driver extends CI_DB { */ protected function _escape_str($str) { - return $this->conn_id->escapeString(remove_invisible_characters($str)); + return $this->conn_id->escapeString($str); } // -------------------------------------------------------------------- diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php index 74ab24ffb..f4ed6168f 100644 --- a/system/helpers/captcha_helper.php +++ b/system/helpers/captcha_helper.php @@ -216,8 +216,22 @@ if ( ! function_exists('create_captcha')) // Generate the image // ----------------------------------- $img_url = rtrim($img_url, '/').'/'; - $img_filename = $now.'.jpg'; - ImageJPEG($im, $img_path.$img_filename); + + if (function_exists('imagejpeg')) + { + $img_filename = $now.'.jpg'; + imagejpeg($im, $img_path.$img_filename); + } + elseif (function_exists('imagepng')) + { + $img_filename = $now.'.png'; + imagepng($im, $img_path.$img_filename); + } + else + { + return FALSE; + } + $img = '<img src="'.$img_url.$img_filename.'" style="width: '.$img_width.'; height: '.$img_height .'; border: 0;" alt=" " />'; ImageDestroy($im); diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php index 8cfe0f1c1..7d2253ef0 100644 --- a/system/helpers/file_helper.php +++ b/system/helpers/file_helper.php @@ -80,7 +80,7 @@ if ( ! function_exists('write_file')) flock($fp, LOCK_EX); - for ($written = 0, $length = strlen($data); $written < $length; $written += $result) + for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) { if (($result = fwrite($fp, substr($data, $written))) === FALSE) { @@ -225,7 +225,7 @@ if ( ! function_exists('get_dir_file_info')) $source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } - // foreach (scandir($source_dir, 1) as $file) // In addition to being PHP5+, scandir() is simply not as fast + // Used to be foreach (scandir($source_dir, 1) as $file), but scandir() is simply not as fast while (FALSE !== ($file = readdir($fp))) { if (is_dir($source_dir.$file) && $file[0] !== '.' && $top_level_only === FALSE) diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php index dff1a86d2..0846472e7 100644 --- a/system/helpers/url_helper.php +++ b/system/helpers/url_helper.php @@ -208,8 +208,12 @@ if ( ! function_exists('anchor_popup')) $window_name = $attributes['window_name']; unset($attributes['window_name']); } + else + { + $window_name = '_blank'; + } - foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0') as $key => $val) + foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'menubar' => 'no', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0') as $key => $val) { $atts[$key] = isset($attributes[$key]) ? $attributes[$key] : $val; unset($attributes[$key]); diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php index c6aa848fe..29898040a 100644 --- a/system/libraries/Cache/drivers/Cache_file.php +++ b/system/libraries/Cache/drivers/Cache_file.php @@ -92,7 +92,7 @@ class CI_Cache_file extends CI_Driver { if (write_file($this->_cache_path.$id, serialize($contents))) { - @chmod($this->_cache_path.$id, 0660); + chmod($this->_cache_path.$id, 0640); return TRUE; } @@ -125,7 +125,11 @@ class CI_Cache_file extends CI_Driver { { $data = $this->_get($id); - if ($data === FALSE OR ! is_int($data['data'])) + if ($data === FALSE) + { + $data = array('data' => 0, 'ttl' => 60); + } + elseif ( ! is_int($data['data'])) { return FALSE; } @@ -149,7 +153,11 @@ class CI_Cache_file extends CI_Driver { { $data = $this->_get($id); - if ($data === FALSE OR ! is_int($data['data'])) + if ($data === FALSE) + { + $data = array('data' => 0, 'ttl' => 60); + } + elseif ( ! is_int($data['data'])) { return FALSE; } diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php index bed606afb..55b769424 100644 --- a/system/libraries/Cache/drivers/Cache_memcached.php +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -49,7 +49,7 @@ class CI_Cache_memcached extends CI_Driver { * * @var array */ - protected $_memcache_conf = array( + protected $_memcache_conf = array( 'default' => array( 'host' => '127.0.0.1', 'port' => 11211, @@ -202,12 +202,12 @@ 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']; if ($CI->config->load('memcached', TRUE, TRUE)) { if (is_array($CI->config->config['memcached'])) { - $defaults = $this->_memcache_conf['default']; $this->_memcache_conf = array(); foreach ($CI->config->config['memcached'] as $name => $conf) diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php index 1c76426c5..7c9da3d2e 100644 --- a/system/libraries/Cache/drivers/Cache_redis.php +++ b/system/libraries/Cache/drivers/Cache_redis.php @@ -58,6 +58,13 @@ class CI_Cache_redis extends CI_Driver */ protected $_redis; + /** + * An internal cache for storing keys of serialized values. + * + * @var array + */ + protected $_serialized = array(); + // ------------------------------------------------------------------------ /** @@ -68,7 +75,14 @@ class CI_Cache_redis extends CI_Driver */ public function get($key) { - return $this->_redis->get($key); + $value = $this->_redis->get($key); + + if ($value !== FALSE && isset($this->_serialized[$key])) + { + return unserialize($value); + } + + return $value; } // ------------------------------------------------------------------------ @@ -84,6 +98,22 @@ class CI_Cache_redis extends CI_Driver */ public function save($id, $data, $ttl = 60, $raw = FALSE) { + if (is_array($data) OR is_object($data)) + { + if ( ! $this->_redis->sAdd('_ci_redis_serialized', $id)) + { + return FALSE; + } + + isset($this->_serialized[$id]) OR $this->_serialized[$id] = TRUE; + $data = serialize($data); + } + elseif (isset($this->_serialized[$id])) + { + $this->_serialized[$id] = NULL; + $this->_redis->sRemove('_ci_redis_serialized', $id); + } + return ($ttl) ? $this->_redis->setex($id, $ttl, $data) : $this->_redis->set($id, $data); @@ -99,7 +129,18 @@ class CI_Cache_redis extends CI_Driver */ public function delete($key) { - return ($this->_redis->delete($key) === 1); + if ($this->_redis->delete($key) !== 1) + { + return FALSE; + } + + if (isset($this->_serialized[$key])) + { + $this->_serialized[$key] = NULL; + $this->_redis->sRemove('_ci_redis_serialized', $key); + } + + return TRUE; } // ------------------------------------------------------------------------ @@ -113,9 +154,7 @@ class CI_Cache_redis extends CI_Driver */ public function increment($id, $offset = 1) { - return $this->_redis->exists($id) - ? $this->_redis->incr($id, $offset) - : FALSE; + return $this->_redis->incr($id, $offset); } // ------------------------------------------------------------------------ @@ -129,9 +168,7 @@ class CI_Cache_redis extends CI_Driver */ public function decrement($id, $offset = 1) { - return $this->_redis->exists($id) - ? $this->_redis->decr($id, $offset) - : FALSE; + return $this->_redis->decr($id, $offset); } // ------------------------------------------------------------------------ @@ -259,13 +296,19 @@ class CI_Cache_redis extends CI_Driver $this->_redis->auth($config['password']); } + // Initialize the index of serialized values. + $serialized = $this->_redis->sMembers('_ci_redis_serialized'); + if ( ! empty($serialized)) + { + $this->_serialized = array_flip($serialized); + } + return TRUE; } // ------------------------------------------------------------------------ /** - * Class destructor * * Closes the connection to Redis if present. diff --git a/system/libraries/Email.php b/system/libraries/Email.php index c39a26a15..88398d316 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1079,6 +1079,11 @@ class CI_Email { */ public function valid_email($email) { + if (function_exists('idn_to_ascii') && $atpos = strpos($email, '@')) + { + $email = substr($email, 0, ++$atpos).idn_to_ascii(substr($email, $atpos)); + } + return (bool) filter_var($email, FILTER_VALIDATE_EMAIL); } diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php index 2541a4467..1af42ed1f 100644 --- a/system/libraries/Encrypt.php +++ b/system/libraries/Encrypt.php @@ -29,7 +29,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Encryption Class * - * Provides two-way keyed encoding using XOR Hashing and Mcrypt + * Provides two-way keyed encoding using Mcrypt * * @package CodeIgniter * @subpackage Libraries @@ -111,7 +111,7 @@ class CI_Encrypt { $key = config_item('encryption_key'); - if ($key === FALSE) + if ( ! strlen($key)) { show_error('In order to use the encryption class requires that you set an encryption key in your config file.'); } diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 810b7bf4a..1a61967a7 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -105,7 +105,6 @@ class CI_Encryption { 'cfb8' => 'cfb8', 'ctr' => 'ctr', 'stream' => '', - 'gcm' => 'gcm', 'xts' => 'xts' ) ); @@ -124,6 +123,13 @@ class CI_Encryption { 'sha512' => 64 ); + /** + * mbstring.func_override flag + * + * @var bool + */ + protected static $func_override; + // -------------------------------------------------------------------- /** @@ -146,8 +152,10 @@ class CI_Encryption { return show_error('Encryption: Unable to find an available encryption driver.'); } + isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override')); $this->initialize($params); - if ( ! isset($this->_key) && strlen($key = config_item('encryption_key')) > 0) + + if ( ! isset($this->_key) && self::strlen($key = config_item('encryption_key')) > 0) { $this->_key = $key; } @@ -310,6 +318,21 @@ class CI_Encryption { // -------------------------------------------------------------------- /** + * Create a random key + * + * @param int $length Output length + * @return string + */ + public function create_key($length) + { + return ($this->_driver === 'mcrypt') + ? mcrypt_create_iv($length, MCRYPT_DEV_URANDOM) + : openssl_random_pseudo_bytes($length); + } + + // -------------------------------------------------------------------- + + /** * Encrypt * * @param string $data Input data @@ -323,7 +346,7 @@ class CI_Encryption { return FALSE; } - isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); + isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption'); if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE) { @@ -356,16 +379,14 @@ class CI_Encryption { { return FALSE; } - elseif ( ! isset($params['iv'])) - { - // The greater-than-1 comparison is mostly a work-around for a bug, - // where 1 is returned for ARCFour instead of 0. - $params['iv'] = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) - ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM) - : NULL; - } - if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + // The greater-than-1 comparison is mostly a work-around for a bug, + // where 1 is returned for ARCFour instead of 0. + $iv = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) + ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM) + : NULL; + + if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0) { if ($params['handle'] !== $this->_handle) { @@ -380,7 +401,7 @@ class CI_Encryption { if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE)) { $block_size = mcrypt_enc_get_block_size($params['handle']); - $pad = $block_size - (strlen($data) % $block_size); + $pad = $block_size - (self::strlen($data) % $block_size); $data .= str_repeat(chr($pad), $pad); } @@ -396,7 +417,7 @@ class CI_Encryption { // but OpenSSL isn't that dumb and we need to make the process // portable, so ... $data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') - ? $params['iv'].mcrypt_generic($params['handle'], $data) + ? $iv.mcrypt_generic($params['handle'], $data) : mcrypt_generic($params['handle'], $data); mcrypt_generic_deinit($params['handle']); @@ -423,19 +444,17 @@ class CI_Encryption { { return FALSE; } - elseif ( ! isset($params['iv'])) - { - $params['iv'] = ($iv_size = openssl_cipher_iv_length($params['handle'])) - ? openssl_random_pseudo_bytes($iv_size) - : NULL; - } + + $iv = ($iv_size = openssl_cipher_iv_length($params['handle'])) + ? openssl_random_pseudo_bytes($iv_size) + : NULL; $data = openssl_encrypt( $data, $params['handle'], $params['key'], 1, // DO NOT TOUCH! - $params['iv'] + $iv ); if ($data === FALSE) @@ -443,7 +462,7 @@ class CI_Encryption { return FALSE; } - return $params['iv'].$data; + return $iv.$data; } // -------------------------------------------------------------------- @@ -470,13 +489,13 @@ class CI_Encryption { ? $this->_digests[$params['hmac_digest']] * 2 : $this->_digests[$params['hmac_digest']]; - if (strlen($data) <= $digest_size) + if (self::strlen($data) <= $digest_size) { return FALSE; } - $hmac_input = substr($data, 0, $digest_size); - $data = substr($data, $digest_size); + $hmac_input = self::substr($data, 0, $digest_size); + $data = self::substr($data, $digest_size); isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication'); $hmac_check = hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']); @@ -499,12 +518,7 @@ class CI_Encryption { $data = base64_decode($data); } - if (isset($params['iv']) && strncmp($params['iv'], $data, $iv_size = strlen($params['iv'])) === 0) - { - $data = substr($data, $iv_size); - } - - isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); + isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption'); return $this->{'_'.$this->_driver.'_decrypt'}($data, $params); } @@ -524,30 +538,28 @@ class CI_Encryption { { return FALSE; } - elseif ( ! isset($params['iv'])) + + // The greater-than-1 comparison is mostly a work-around for a bug, + // where 1 is returned for ARCFour instead of 0. + if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) { - // The greater-than-1 comparison is mostly a work-around for a bug, - // where 1 is returned for ARCFour instead of 0. - if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) + if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') { - if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') - { - $params['iv'] = substr($data, 0, $iv_size); - $data = substr($data, $iv_size); - } - else - { - // MCrypt is dumb and this is ignored, only size matters - $params['iv'] = str_repeat("\x0", $iv_size); - } + $iv = self::substr($data, 0, $iv_size); + $data = self::substr($data, $iv_size); } else { - $params['iv'] = NULL; + // MCrypt is dumb and this is ignored, only size matters + $iv = str_repeat("\x0", $iv_size); } } + else + { + $iv = NULL; + } - if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0) { if ($params['handle'] !== $this->_handle) { @@ -561,7 +573,7 @@ class CI_Encryption { // Remove PKCS#7 padding, if necessary if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE)) { - $data = substr($data, 0, -ord($data[strlen($data)-1])); + $data = self::substr($data, 0, -ord($data[self::strlen($data)-1])); } mcrypt_generic_deinit($params['handle']); @@ -584,17 +596,14 @@ class CI_Encryption { */ protected function _openssl_decrypt($data, $params) { - if ( ! isset($params['iv'])) + if ($iv_size = openssl_cipher_iv_length($params['handle'])) { - if ($iv_size = openssl_cipher_iv_length($params['handle'])) - { - $params['iv'] = substr($data, 0, $iv_size); - $data = substr($data, $iv_size); - } - else - { - $params['iv'] = NULL; - } + $iv = self::substr($data, 0, $iv_size); + $data = self::substr($data, $iv_size); + } + else + { + $iv = NULL; } return empty($params['handle']) @@ -604,7 +613,7 @@ class CI_Encryption { $params['handle'], $params['key'], 1, // DO NOT TOUCH! - $params['iv'] + $iv ); } @@ -627,7 +636,7 @@ class CI_Encryption { 'mode' => $this->_mode, 'key' => NULL, 'base64' => TRUE, - 'hmac_digest' => ($this->_mode !== 'gcm' ? 'sha512' : NULL), + 'hmac_digest' => 'sha512', 'hmac_key' => NULL ) : FALSE; @@ -650,7 +659,7 @@ class CI_Encryption { } } - if ($params['mode'] === 'gcm' OR (isset($params['hmac']) && $params['hmac'] === FALSE)) + if (isset($params['hmac']) && $params['hmac'] === FALSE) { $params['hmac_digest'] = $params['hmac_key'] = NULL; } @@ -679,7 +688,6 @@ class CI_Encryption { 'cipher' => $params['cipher'], 'mode' => $params['mode'], 'key' => $params['key'], - 'iv' => isset($params['iv']) ? $params['iv'] : NULL, 'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE, 'hmac_digest' => $params['hmac_digest'], 'hmac_key' => $params['hmac_key'] @@ -828,17 +836,17 @@ class CI_Encryption { return FALSE; } - strlen($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]); + self::strlen($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]); $prk = hash_hmac($digest, $key, $salt, TRUE); $key = ''; - for ($key_block = '', $block_index = 1; strlen($key) < $length; $block_index++) + for ($key_block = '', $block_index = 1; self::strlen($key) < $length; $block_index++) { $key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE); $key .= $key_block; } - return substr($key, 0, $length); + return self::substr($key, 0, $length); } // -------------------------------------------------------------------- @@ -864,6 +872,45 @@ class CI_Encryption { return NULL; } + // -------------------------------------------------------------------- + + /** + * Byte-safe strlen() + * + * @param string $str + * @return integer + */ + protected static function strlen($str) + { + return (self::$func_override) + ? mb_strlen($str, '8bit') + : strlen($str); + } + + // -------------------------------------------------------------------- + + /** + * Byte-safe substr() + * + * @param string $str + * @param int $start + * @param int $length + * @return string + */ + protected static function substr($str, $start, $length = NULL) + { + if (self::$func_override) + { + // mb_substr($str, $start, null, '8bit') returns an empty + // string on PHP 5.3 + isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start); + return mb_substr($str, $start, $length, '8bit'); + } + + return isset($length) + ? substr($str, $start, $length) + : substr($str, $start); + } } /* End of file Encryption.php */ diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index dc5d17fb3..b640f1ec1 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -701,6 +701,12 @@ class CI_Form_validation { { $callable = TRUE; } + elseif (is_array($rule) && isset($rule[0], $rule[1]) && is_callable($rule[1])) + { + // We have a "named" callable, so save the name + $callable = $rule[0]; + $rule = $rule[1]; + } // Strip the parameter (if exists) from the rule // Rules can contain a parameter: max_length[5] @@ -712,7 +718,7 @@ class CI_Form_validation { } // Call the function that corresponds to the rule - if ($callback OR $callable) + if ($callback OR $callable !== FALSE) { if ($callback) { @@ -730,8 +736,14 @@ class CI_Form_validation { else { $result = is_array($rule) - ? $rule[0]->{$rule[1]}($postdata, $param) - : $rule($postdata, $param); + ? $rule[0]->{$rule[1]}($postdata) + : $rule($postdata); + + // Is $callable set to a rule name? + if ($callable !== FALSE) + { + $rule = $callable; + } } // Re-assign the result to the master data array @@ -791,28 +803,30 @@ class CI_Form_validation { // Did the rule test negatively? If so, grab the error. if ($result === FALSE) { - // Callable rules don't have named error messages - if ( ! is_callable($rule)) + // Callable rules might not have named error messages + if ( ! is_string($rule)) { - // Check if a custom message is defined - if (isset($this->_field_data[$row['field']]['errors'][$rule])) - { - $line = $this->_field_data[$row['field']]['errors'][$rule]; - } - elseif ( ! isset($this->_error_messages[$rule])) - { - if (FALSE === ($line = $this->CI->lang->line('form_validation_'.$rule)) - // DEPRECATED support for non-prefixed keys - && FALSE === ($line = $this->CI->lang->line($rule, FALSE))) - { - $line = 'Unable to access an error message corresponding to your field name.'; - } - } - else + return; + } + + // Check if a custom message is defined + if (isset($this->_field_data[$row['field']]['errors'][$rule])) + { + $line = $this->_field_data[$row['field']]['errors'][$rule]; + } + elseif ( ! isset($this->_error_messages[$rule])) + { + if (FALSE === ($line = $this->CI->lang->line('form_validation_'.$rule)) + // DEPRECATED support for non-prefixed keys + && FALSE === ($line = $this->CI->lang->line($rule, FALSE))) { - $line = $this->_error_messages[$rule]; + $line = 'Unable to access an error message corresponding to your field name.'; } } + else + { + $line = $this->_error_messages[$rule]; + } // Is the parameter we are inserting into the error message the name // of another field? If so we need to grab its "field label" @@ -1225,6 +1239,11 @@ class CI_Form_validation { */ public function valid_email($str) { + if (function_exists('idn_to_ascii') && $atpos = strpos($str, '@')) + { + $str = substr($str, 0, ++$atpos).idn_to_ascii(substr($str, $atpos)); + } + return (bool) filter_var($str, FILTER_VALIDATE_EMAIL); } diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php index f1339b57a..39753705b 100644 --- a/system/libraries/Image_lib.php +++ b/system/libraries/Image_lib.php @@ -327,6 +327,13 @@ class CI_Image_lib { public $full_dst_path = ''; /** + * File permissions + * + * @var int + */ + public $file_permissions = 0644; + + /** * Name of function to create image * * @var string @@ -734,7 +741,7 @@ class CI_Image_lib { { if ($this->source_image !== $this->new_image && @copy($this->full_src_path, $this->full_dst_path)) { - @chmod($this->full_dst_path, 0666); + chmod($this->full_dst_path, $this->file_permissions); } return TRUE; @@ -810,8 +817,7 @@ class CI_Image_lib { imagedestroy($dst_img); imagedestroy($src_img); - // Set the file to 666 - @chmod($this->full_dst_path, 0666); + chmod($this->full_dst_path, $this->file_permissions); return TRUE; } @@ -880,8 +886,7 @@ class CI_Image_lib { return FALSE; } - // Set the file to 666 - @chmod($this->full_dst_path, 0666); + chmod($this->full_dst_path, $this->file_permissions); return TRUE; } @@ -969,7 +974,7 @@ class CI_Image_lib { // we have to rename the temp file. copy($this->dest_folder.'netpbm.tmp', $this->full_dst_path); unlink($this->dest_folder.'netpbm.tmp'); - @chmod($this->full_dst_path, 0666); + chmod($this->full_dst_path, $this->file_permissions); return TRUE; } @@ -1013,8 +1018,7 @@ class CI_Image_lib { imagedestroy($dst_img); imagedestroy($src_img); - // Set the file to 666 - @chmod($this->full_dst_path, 0666); + chmod($this->full_dst_path, $this->file_permissions); return TRUE; } @@ -1086,8 +1090,7 @@ class CI_Image_lib { // Kill the file handles imagedestroy($src_img); - // Set the file to 666 - @chmod($this->full_dst_path, 0666); + chmod($this->full_dst_path, $this->file_permissions); return TRUE; } diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index 5b9bfcb5d..b7df06292 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -51,45 +51,45 @@ class CI_Pagination { * * @var string */ - protected $prefix = ''; + protected $prefix = ''; /** * Suffix * * @var string */ - protected $suffix = ''; + protected $suffix = ''; /** * Total number of items * * @var int */ - protected $total_rows = 0; + protected $total_rows = 0; /** - * Items per page + * Number of links to show + * + * Relates to "digit" type links shown before/after + * the currently viewed page. * * @var int */ - protected $per_page = 10; + protected $num_links = 2; /** - * Number of links to show - * - * Relates to "digit" type links shown before/after - * the currently viewed page. + * Items per page * * @var int */ - protected $num_links = 2; + public $per_page = 10; /** * Current page * * @var int */ - protected $cur_page = 0; + public $cur_page = 0; /** * Use page numbers flag @@ -98,84 +98,84 @@ class CI_Pagination { * * @var bool */ - protected $use_page_numbers = FALSE; + protected $use_page_numbers = FALSE; /** * First link * * @var string */ - protected $first_link = '‹ First'; + protected $first_link = '‹ First'; /** * Next link * * @var string */ - protected $next_link = '>'; + protected $next_link = '>'; /** * Previous link * * @var string */ - protected $prev_link = '<'; + protected $prev_link = '<'; /** * Last link * * @var string */ - protected $last_link = 'Last ›'; + protected $last_link = 'Last ›'; /** * URI Segment * * @var int */ - protected $uri_segment = 0; + protected $uri_segment = 0; /** * Full tag open * * @var string */ - protected $full_tag_open = ''; + protected $full_tag_open = ''; /** * Full tag close * * @var string */ - protected $full_tag_close = ''; + protected $full_tag_close = ''; /** * First tag open * * @var string */ - protected $first_tag_open = ''; + protected $first_tag_open = ''; /** * First tag close * * @var string */ - protected $first_tag_close = ''; + protected $first_tag_close = ''; /** * Last tag open * * @var string */ - protected $last_tag_open = ''; + protected $last_tag_open = ''; /** * Last tag close * * @var string */ - protected $last_tag_close = ''; + protected $last_tag_close = ''; /** * First URL @@ -184,70 +184,70 @@ class CI_Pagination { * * @var string */ - protected $first_url = ''; + protected $first_url = ''; /** * Current tag open * * @var string */ - protected $cur_tag_open = '<strong>'; + protected $cur_tag_open = '<strong>'; /** * Current tag close * * @var string */ - protected $cur_tag_close = '</strong>'; + protected $cur_tag_close = '</strong>'; /** * Next tag open * * @var string */ - protected $next_tag_open = ''; + protected $next_tag_open = ''; /** * Next tag close * * @var string */ - protected $next_tag_close = ''; + protected $next_tag_close = ''; /** * Previous tag open * * @var string */ - protected $prev_tag_open = ''; + protected $prev_tag_open = ''; /** * Previous tag close * * @var string */ - protected $prev_tag_close = ''; + protected $prev_tag_close = ''; /** * Number tag open * * @var string */ - protected $num_tag_open = ''; + protected $num_tag_open = ''; /** * Number tag close * * @var string */ - protected $num_tag_close = ''; + protected $num_tag_close = ''; /** * Page query string flag * * @var bool */ - protected $page_query_string = FALSE; + protected $page_query_string = FALSE; /** * Query string segment @@ -261,14 +261,14 @@ class CI_Pagination { * * @var bool */ - protected $display_pages = TRUE; + protected $display_pages = TRUE; /** * Attributes * * @var string */ - protected $_attributes = ''; + protected $_attributes = ''; /** * Link types @@ -278,21 +278,21 @@ class CI_Pagination { * @see CI_Pagination::_attr_rel() * @var array */ - protected $_link_types = array(); + protected $_link_types = array(); /** * Reuse query string flag * * @var bool */ - protected $reuse_query_string = FALSE; + protected $reuse_query_string = FALSE; /** * Data page attribute * * @var string */ - protected $data_page_attr = 'data-ci-pagination-page'; + protected $data_page_attr = 'data-ci-pagination-page'; /** * CI Singleton @@ -393,9 +393,9 @@ class CI_Pagination { // Check the user defined number of links. $this->num_links = (int) $this->num_links; - if ($this->num_links < 1) + if ($this->num_links < 0) { - show_error('Your number of links must be a positive number.'); + show_error('Your number of links must be a non-negative number.'); } // Keep any existing query string items. @@ -533,7 +533,7 @@ class CI_Pagination { $output = ''; // Render the "First" link. - if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1)) + if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1 + ! $this->num_links)) { // Take the general parameters, and squeeze this pagination-page attr in for JS frameworks. $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, 1); @@ -609,7 +609,7 @@ class CI_Pagination { } // Render the "Last" link - if ($this->last_link !== FALSE && ($this->cur_page + $this->num_links) < $num_pages) + if ($this->last_link !== FALSE && ($this->cur_page + $this->num_links + ! $this->num_links) < $num_pages) { $i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page; diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php index d23a53423..2c2fc73b6 100644 --- a/system/libraries/Parser.php +++ b/system/libraries/Parser.php @@ -128,13 +128,20 @@ class CI_Parser { return FALSE; } + $replace = array(); foreach ($data as $key => $val) { - $template = is_array($val) + $replace = array_merge( + $replace, + is_array($val) ? $this->_parse_pair($key, $val, $template) - : $template = $this->_parse_single($key, (string) $val, $template); + : $this->_parse_single($key, (string) $val, $template) + ); } + unset($data); + $template = strtr($template, $replace); + if ($return === FALSE) { $this->CI->output->append_output($template); @@ -170,7 +177,7 @@ class CI_Parser { */ protected function _parse_single($key, $val, $string) { - return str_replace($this->l_delim.$key.$this->r_delim, (string) $val, $string); + return array($this->l_delim.$key.$this->r_delim => (string) $val); } // -------------------------------------------------------------------- @@ -187,50 +194,43 @@ class CI_Parser { */ protected function _parse_pair($variable, $data, $string) { - if (FALSE === ($matches = $this->_match_pair($string, $variable))) - { - return $string; - } + $replace = array(); + preg_match_all( + '#'.preg_quote($this->l_delim.$variable.$this->r_delim).'(.+?)'.preg_quote($this->l_delim.'/'.$variable.$this->r_delim).'#s', + $string, + $matches, + PREG_SET_ORDER + ); - $str = ''; - $search = $replace = array(); foreach ($matches as $match) { $str = ''; foreach ($data as $row) { - $temp = $match[1]; + $temp = array(); foreach ($row as $key => $val) { - $temp = is_array($val) - ? $this->_parse_pair($key, $val, $temp) - : $this->_parse_single($key, $val, $temp); + if (is_array($val)) + { + $pair = $this->_parse_pair($key, $val, $match[1]); + if ( ! empty($pair)) + { + $temp = array_merge($temp, $pair); + } + + continue; + } + + $temp[$this->l_delim.$key.$this->r_delim] = $val; } - $str .= $temp; + $str .= strtr($match[1], $temp); } - $search[] = $match[0]; - $replace[] = $str; + $replace[$match[0]] = $str; } - return str_replace($search, $replace, $string); - } - - // -------------------------------------------------------------------- - - /** - * Matches a variable pair - * - * @param string $string - * @param string $variable - * @return mixed - */ - protected function _match_pair($string, $variable) - { - return preg_match_all('|'.preg_quote($this->l_delim).$variable.preg_quote($this->r_delim).'(.+?)'.preg_quote($this->l_delim).'/'.$variable.preg_quote($this->r_delim).'|s', - $string, $match, PREG_SET_ORDER) - ? $match : FALSE; + return $replace; } } diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index 75fc0624f..49c69a32c 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -327,23 +327,26 @@ class CI_Upload { $this->$key = $defaults[$key]; } } - - return $this; + } - - foreach ($config as $key => &$value) + else { - if ($key[0] !== '_' && $reflection->hasProperty($key)) + + foreach ($config as $key => &$value) { - if ($reflection->hasMethod('set_'.$key)) - { - $this->{'set_'.$key}($value); - } - else + if ($key[0] !== '_' && $reflection->hasProperty($key)) { - $this->$key = $value; + if ($reflection->hasMethod('set_'.$key)) + { + $this->{'set_'.$key}($value); + } + else + { + $this->$key = $value; + } } } + } // if a file_name was provided in the config, use it instead of the user input @@ -1155,28 +1158,14 @@ class CI_Upload { */ protected function _prep_filename($filename) { - if ($this->mod_mime_fix === FALSE OR $this->allowed_types === '*' OR strpos($filename, '.') === FALSE) + if ($this->mod_mime_fix === FALSE OR $this->allowed_types === '*' OR ($ext_pos = strrpos($filename, '.')) === FALSE) { return $filename; } - $parts = explode('.', $filename); - $ext = array_pop($parts); - $filename = array_shift($parts); - - foreach ($parts as $part) - { - if ( ! in_array(strtolower($part), $this->allowed_types) OR ! isset($this->_mimes[strtolower($part)])) - { - $filename .= '.'.$part.'_'; - } - else - { - $filename .= '.'.$part; - } - } - - return $filename.'.'.$ext; + $ext = substr($filename, $ext_pos); + $filename = substr($filename, 0, $ext_pos); + return str_replace('.', '_', $filename).$ext; } // -------------------------------------------------------------------- diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php index ab30a9019..62a84ae75 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -405,7 +405,7 @@ class CI_Zip { flock($fp, LOCK_EX); - for ($written = 0, $data = $this->get_zip(), $length = strlen($data); $written < $length; $written += $result) + for ($result = $written = 0, $data = $this->get_zip(), $length = strlen($data); $written < $length; $written += $result) { if (($result = fwrite($fp, substr($data, $written))) === FALSE) { |