summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Andreev <narf@devilix.net>2014-10-05 23:04:19 +0200
committerAndrey Andreev <narf@devilix.net>2014-10-05 23:04:19 +0200
commit4a485a73d64a8bebc7625aabc5fdc361d5e7dc56 (patch)
treecb18690c4de1c6ca008227260f9dd0cd2b9279d2
parent39ec29585b7cdca7edc1a0757c913a13a2ee4f85 (diff)
parentd444d445ed0458a352ecb9ff79ffd158677ee805 (diff)
Merge branch 'develop' into feature/session
-rw-r--r--application/config/config.php34
-rw-r--r--application/config/constants.php2
-rw-r--r--application/config/mimes.php6
-rw-r--r--system/core/CodeIgniter.php19
-rw-r--r--system/core/Common.php20
-rw-r--r--system/core/Config.php3
-rw-r--r--system/core/Exceptions.php16
-rw-r--r--system/core/Hooks.php2
-rw-r--r--system/core/Input.php4
-rw-r--r--system/core/Log.php30
-rw-r--r--system/core/Output.php2
-rwxr-xr-xsystem/core/Security.php84
-rw-r--r--system/core/compat/password.php17
-rw-r--r--system/core/compat/standard.php (renamed from system/core/compat/array.php)143
-rw-r--r--system/database/DB_cache.php11
-rw-r--r--system/database/DB_driver.php5
-rw-r--r--system/database/DB_forge.php2
-rw-r--r--system/database/DB_query_builder.php6
-rw-r--r--system/database/drivers/cubrid/cubrid_driver.php9
-rw-r--r--system/database/drivers/ibase/ibase_driver.php6
-rw-r--r--system/database/drivers/mssql/mssql_driver.php4
-rw-r--r--system/database/drivers/mysql/mysql_driver.php4
-rw-r--r--system/database/drivers/mysqli/mysqli_driver.php4
-rw-r--r--system/database/drivers/pdo/pdo_result.php2
-rw-r--r--system/database/drivers/sqlite3/sqlite3_driver.php2
-rw-r--r--system/helpers/captcha_helper.php18
-rw-r--r--system/helpers/file_helper.php4
-rw-r--r--system/helpers/url_helper.php6
-rw-r--r--system/libraries/Cache/drivers/Cache_file.php14
-rw-r--r--system/libraries/Cache/drivers/Cache_memcached.php4
-rw-r--r--system/libraries/Cache/drivers/Cache_redis.php61
-rw-r--r--system/libraries/Email.php5
-rw-r--r--system/libraries/Encrypt.php4
-rw-r--r--system/libraries/Encryption.php177
-rw-r--r--system/libraries/Form_validation.php61
-rw-r--r--system/libraries/Image_lib.php23
-rw-r--r--system/libraries/Pagination.php84
-rw-r--r--system/libraries/Parser.php66
-rw-r--r--system/libraries/Upload.php47
-rw-r--r--system/libraries/Zip.php2
-rw-r--r--tests/Bootstrap.php2
-rw-r--r--tests/codeigniter/core/compat/array_test.php429
-rw-r--r--tests/codeigniter/core/compat/standard_test.php576
-rw-r--r--tests/codeigniter/libraries/Encrypt_test.php34
-rw-r--r--tests/codeigniter/libraries/Encryption_test.php9
-rw-r--r--tests/mocks/core/common.php2
-rw-r--r--user_guide_src/source/changelog.rst29
-rw-r--r--user_guide_src/source/general/ancillary_classes.rst2
-rw-r--r--user_guide_src/source/general/autoloader.rst6
-rw-r--r--user_guide_src/source/general/common_functions.rst2
-rw-r--r--user_guide_src/source/general/compatibility_functions.rst47
-rw-r--r--user_guide_src/source/general/creating_drivers.rst6
-rw-r--r--user_guide_src/source/general/creating_libraries.rst2
-rw-r--r--user_guide_src/source/general/routing.rst4
-rw-r--r--user_guide_src/source/helpers/captcha_helper.rst2
-rw-r--r--user_guide_src/source/helpers/file_helper.rst4
-rw-r--r--user_guide_src/source/installation/upgrade_300.rst4
-rw-r--r--user_guide_src/source/libraries/encryption.rst39
-rw-r--r--user_guide_src/source/libraries/form_validation.rst31
-rw-r--r--user_guide_src/source/libraries/ftp.rst6
-rw-r--r--user_guide_src/source/libraries/image_lib.rst2
-rw-r--r--user_guide_src/source/libraries/output.rst26
-rw-r--r--user_guide_src/source/libraries/security.rst24
-rw-r--r--user_guide_src/source/libraries/table.rst36
-rw-r--r--user_guide_src/source/libraries/zip.rst2
65 files changed, 1486 insertions, 853 deletions
diff --git a/application/config/config.php b/application/config/config.php
index d269b6e5d..e8d30b625 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -121,7 +121,6 @@ $config['charset'] = 'UTF-8';
*/
$config['enable_hooks'] = FALSE;
-
/*
|--------------------------------------------------------------------------
| Class Extension Prefix
@@ -136,6 +135,27 @@ $config['enable_hooks'] = FALSE;
*/
$config['subclass_prefix'] = 'MY_';
+/*
+|--------------------------------------------------------------------------
+| Composer auto-loading
+|--------------------------------------------------------------------------
+|
+| Enabling this setting will tell CodeIgniter to look for a Composer
+| package auto-loader script in application/vendor/autoload.php.
+|
+| $config['composer_autoload'] = TRUE;
+|
+| Or if you have your vendor/ directory located somewhere else, you
+| can opt to set a specific path as well:
+|
+| $config['composer_autoload'] = '/path/to/vendor/autoload.php';
+|
+| For more information about Composer, please visit http://getcomposer.org/
+|
+| Note: This will NOT disable or override the CodeIgniter-specific
+| autoloading (application/config/autoload.php)
+*/
+$config['composer_autoload'] = FALSE;
/*
|--------------------------------------------------------------------------
@@ -244,6 +264,18 @@ $config['log_file_extension'] = '';
/*
|--------------------------------------------------------------------------
+| Log File Permissions
+|--------------------------------------------------------------------------
+|
+| The file system permissions to be applied on newly created log files.
+|
+| IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal
+| integer notation (i.e. 0700, 0644, etc.)
+*/
+$config['log_file_permissions'] = 0644;
+
+/*
+|--------------------------------------------------------------------------
| Date Format for Logs
|--------------------------------------------------------------------------
|
diff --git a/application/config/constants.php b/application/config/constants.php
index 239fd46fb..c19f044ab 100644
--- a/application/config/constants.php
+++ b/application/config/constants.php
@@ -42,7 +42,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
define('FILE_READ_MODE', 0644);
define('FILE_WRITE_MODE', 0666);
define('DIR_READ_MODE', 0755);
-define('DIR_WRITE_MODE', 0777);
+define('DIR_WRITE_MODE', 0755);
/*
|--------------------------------------------------------------------------
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 8123557f4..bab431f77 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -58,7 +58,7 @@ return array(
'smil' => 'application/smil',
'mif' => 'application/vnd.mif',
'xls' => array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'),
- 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'),
+ 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint', 'application/vnd.ms-office', 'application/msword'),
'pptx' => array('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-zip', 'application/zip'),
'wbxml' => 'application/wbxml',
'wmlc' => 'application/wmlc',
@@ -174,7 +174,9 @@ return array(
'7zip' => array('application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'),
'cdr' => array('application/cdr', 'application/coreldraw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'),
'wma' => array('audio/x-ms-wma', 'video/x-ms-asf'),
- 'jar' => array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed')
+ 'jar' => array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed'),
+ 'svg' => array('image/svg+xml', 'application/xml', 'text/xml'),
+ 'vcf' => 'text/x-vcard'
);
/* End of file mimes.php */
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 = '&lsaquo; First';
+ protected $first_link = '&lsaquo; First';
/**
* Next link
*
* @var string
*/
- protected $next_link = '&gt;';
+ protected $next_link = '&gt;';
/**
* Previous link
*
* @var string
*/
- protected $prev_link = '&lt;';
+ protected $prev_link = '&lt;';
/**
* Last link
*
* @var string
*/
- protected $last_link = 'Last &rsaquo;';
+ protected $last_link = 'Last &rsaquo;';
/**
* 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)
{
diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php
index cc84abf28..713c0fdb3 100644
--- a/tests/Bootstrap.php
+++ b/tests/Bootstrap.php
@@ -69,7 +69,7 @@ is_php('5.6') && ini_set('php.internal_encoding', 'UTF-8');
include_once SYSTEM_PATH.'core/compat/mbstring.php';
include_once SYSTEM_PATH.'core/compat/hash.php';
include_once SYSTEM_PATH.'core/compat/password.php';
-include_once SYSTEM_PATH.'core/compat/array.php';
+include_once SYSTEM_PATH.'core/compat/standard.php';
include_once $dir.'/mocks/autoloader.php';
spl_autoload_register('autoload');
diff --git a/tests/codeigniter/core/compat/array_test.php b/tests/codeigniter/core/compat/array_test.php
deleted file mode 100644
index 9d2deaba6..000000000
--- a/tests/codeigniter/core/compat/array_test.php
+++ /dev/null
@@ -1,429 +0,0 @@
-<?php
-
-class array_test extends CI_TestCase {
-
- public function test_bootstrap()
- {
- if (is_php('5.5'))
- {
- return $this->markTestSkipped('All array functions are already available on PHP 5.5');
- }
- elseif ( ! is_php('5.3'))
- {
- $this->assertTrue(function_exists('array_replace'));
- $this->assertTrue(function_exists('array_replace_recursive'));
- }
-
- $this->assertTrue(function_exists('array_column'));
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * array_column() test
- *
- * Borrowed from PHP's own tests
- *
- * @depends test_bootstrap
- */
- public function test_array_column()
- {
- // Basic tests
-
- $input = array(
- array(
- 'id' => 1,
- 'first_name' => 'John',
- 'last_name' => 'Doe'
- ),
- array(
- 'id' => 2,
- 'first_name' => 'Sally',
- 'last_name' => 'Smith'
- ),
- array(
- 'id' => 3,
- 'first_name' => 'Jane',
- 'last_name' => 'Jones'
- )
- );
-
- // Ensure internal array position doesn't break it
- next($input);
-
- $this->assertEquals(
- array('John', 'Sally', 'Jane'),
- array_column($input, 'first_name')
- );
-
- $this->assertEquals(
- array(1, 2, 3),
- array_column($input, 'id')
- );
-
- $this->assertEquals(
- array(
- 1 => 'Doe',
- 2 => 'Smith',
- 3 => 'Jones'
- ),
- array_column($input, 'last_name', 'id')
- );
-
- $this->assertEquals(
- array(
- 'John' => 'Doe',
- 'Sally' => 'Smith',
- 'Jane' => 'Jones'
- ),
- array_column($input, 'last_name', 'first_name')
- );
-
- // Object key search
-
- $f = new Foo();
- $b = new Bar();
-
- $this->assertEquals(
- array('Doe', 'Smith', 'Jones'),
- array_column($input, $f)
- );
-
- $this->assertEquals(
- array(
- 'John' => 'Doe',
- 'Sally' => 'Smith',
- 'Jane' => 'Jones'
- ),
- array_column($input, $f, $b)
- );
-
- // NULL parameters
-
- $input = array(
- 456 => array(
- 'id' => '3',
- 'title' => 'Foo',
- 'date' => '2013-03-25'
- ),
- 457 => array(
- 'id' => '5',
- 'title' => 'Bar',
- 'date' => '2012-05-20'
- )
- );
-
- $this->assertEquals(
- array(
- 3 => array(
- 'id' => '3',
- 'title' => 'Foo',
- 'date' => '2013-03-25'
- ),
- 5 => array(
- 'id' => '5',
- 'title' => 'Bar',
- 'date' => '2012-05-20'
- )
- ),
- array_column($input, NULL, 'id')
- );
-
- $this->assertEquals(
- array(
- array(
- 'id' => '3',
- 'title' => 'Foo',
- 'date' => '2013-03-25'
- ),
- array(
- 'id' => '5',
- 'title' => 'Bar',
- 'date' => '2012-05-20'
- )
- ),
- array_column($input, NULL, 'foo')
- );
-
- $this->assertEquals(
- array(
- array(
- 'id' => '3',
- 'title' => 'Foo',
- 'date' => '2013-03-25'
- ),
- array(
- 'id' => '5',
- 'title' => 'Bar',
- 'date' => '2012-05-20'
- )
- ),
- array_column($input, NULL)
- );
-
- // Data types
-
- $fh = fopen(__FILE__, 'r', TRUE);
- $stdClass = new stdClass();
- $input = array(
- array(
- 'id' => 1,
- 'value' => $stdClass
- ),
- array(
- 'id' => 2,
- 'value' => 34.2345
- ),
- array(
- 'id' => 3,
- 'value' => TRUE
- ),
- array(
- 'id' => 4,
- 'value' => FALSE
- ),
- array(
- 'id' => 5,
- 'value' => NULL
- ),
- array(
- 'id' => 6,
- 'value' => 1234
- ),
- array(
- 'id' => 7,
- 'value' => 'Foo'
- ),
- array(
- 'id' => 8,
- 'value' => $fh
- )
- );
-
- $this->assertEquals(
- array(
- $stdClass,
- 34.2345,
- TRUE,
- FALSE,
- NULL,
- 1234,
- 'Foo',
- $fh
- ),
- array_column($input, 'value')
- );
-
- $this->assertEquals(
- array(
- 1 => $stdClass,
- 2 => 34.2345,
- 3 => TRUE,
- 4 => FALSE,
- 5 => NULL,
- 6 => 1234,
- 7 => 'Foo',
- 8 => $fh
- ),
- array_column($input, 'value', 'id')
- );
-
- // Numeric column keys
-
- $input = array(
- array('aaa', '111'),
- array('bbb', '222'),
- array('ccc', '333', -1 => 'ddd')
- );
-
- $this->assertEquals(
- array('111', '222', '333'),
- array_column($input, 1)
- );
-
- $this->assertEquals(
- array(
- 'aaa' => '111',
- 'bbb' => '222',
- 'ccc' => '333'
- ),
- array_column($input, 1, 0)
- );
-
- $this->assertEquals(
- array(
- 'aaa' => '111',
- 'bbb' => '222',
- 'ccc' => '333'
- ),
- array_column($input, 1, 0.123)
- );
-
- $this->assertEquals(
- array(
- 0 => '111',
- 1 => '222',
- 'ddd' => '333'
- ),
- array_column($input, 1, -1)
- );
-
- // Non-existing columns
-
- $this->assertEquals(array(), array_column($input, 2));
- $this->assertEquals(array(), array_column($input, 'foo'));
- $this->assertEquals(
- array('aaa', 'bbb', 'ccc'),
- array_column($input, 0, 'foo')
- );
- $this->assertEquals(array(), array_column($input, 3.14));
-
- // One-dimensional array
- $this->assertEquals(array(), array_column(array('foo', 'bar', 'baz'), 1));
-
- // Columns not present in all rows
-
- $input = array(
- array('a' => 'foo', 'b' => 'bar', 'e' => 'bbb'),
- array('a' => 'baz', 'c' => 'qux', 'd' => 'aaa'),
- array('a' => 'eee', 'b' => 'fff', 'e' => 'ggg')
- );
-
- $this->assertEquals(
- array('qux'),
- array_column($input, 'c')
- );
-
- $this->assertEquals(
- array('baz' => 'qux'),
- array_column($input, 'c', 'a')
- );
-
- $this->assertEquals(
- array(
- 0 => 'foo',
- 'aaa' => 'baz',
- 1 => 'eee'
- ),
- array_column($input, 'a', 'd')
- );
-
- $this->assertEquals(
- array(
- 'bbb' => 'foo',
- 0 => 'baz',
- 'ggg' => 'eee'
- ),
- array_column($input, 'a', 'e')
- );
-
- $this->assertEquals(
- array('bar', 'fff'),
- array_column($input, 'b')
- );
-
- $this->assertEquals(
- array(
- 'foo' => 'bar',
- 'eee' => 'fff'
- ),
- array_column($input, 'b', 'a')
- );
- }
-
- // ------------------------------------------------------------------------
-
- /**
- * array_replace(), array_replace_recursive() tests
- *
- * Borrowed from PHP's own tests
- *
- * @depends test_bootstrap
- */
- public function test_array_replace_recursive()
- {
- if (is_php('5.3'))
- {
- return $this->markTestSkipped('array_replace() and array_replace_recursive() are already available on PHP 5.3');
- }
-
- $array1 = array(
- 0 => 'dontclobber',
- '1' => 'unclobbered',
- 'test2' => 0.0,
- 'test3' => array(
- 'testarray2' => TRUE,
- 1 => array(
- 'testsubarray1' => 'dontclobber2',
- 'testsubarray2' => 'dontclobber3'
- )
- )
- );
-
- $array2 = array(
- 1 => 'clobbered',
- 'test3' => array(
- 'testarray2' => FALSE
- ),
- 'test4' => array(
- 'clobbered3' => array(0, 1, 2)
- )
- );
-
- // array_replace()
- $this->assertEquals(
- array(
- 0 => 'dontclobber',
- 1 => 'clobbered',
- 'test2' => 0.0,
- 'test3' => array(
- 'testarray2' => FALSE
- ),
- 'test4' => array(
- 'clobbered3' => array(0, 1, 2)
- )
- ),
- array_replace($array1, $array2)
- );
-
- // array_replace_recursive()
- $this->assertEquals(
- array(
- 0 => 'dontclobber',
- 1 => 'clobbered',
- 'test2' => 0.0,
- 'test3' => array(
- 'testarray2' => FALSE,
- 1 => array(
- 'testsubarray1' => 'dontclobber2',
- 'testsubarray2' => 'dontclobber3'
- )
- ),
- 'test4' => array(
- 'clobbered3' => array(0, 1, 2)
- )
- ),
- array_replace_recursive($array1, $array2)
- );
- }
-}
-
-// ------------------------------------------------------------------------
-
-// These are necessary for the array_column() tests
-
-class Foo {
-
- public function __toString()
- {
- return 'last_name';
- }
-}
-
-class Bar {
-
- public function __toString()
- {
- return 'first_name';
- }
-} \ No newline at end of file
diff --git a/tests/codeigniter/core/compat/standard_test.php b/tests/codeigniter/core/compat/standard_test.php
new file mode 100644
index 000000000..a3a6d9552
--- /dev/null
+++ b/tests/codeigniter/core/compat/standard_test.php
@@ -0,0 +1,576 @@
+<?php
+
+class standard_test extends CI_TestCase {
+
+ public function test_bootstrap()
+ {
+ if (is_php('5.5'))
+ {
+ return $this->markTestSkipped('All array functions are already available on PHP 5.5');
+ }
+
+ $this->assertTrue(function_exists('array_column'));
+
+ if ( ! is_php('5.4'))
+ {
+ $this->assertTrue(function_exists('hex2bin'));
+ }
+
+ if ( ! is_php('5.3'))
+ {
+ $this->assertTrue(function_exists('array_replace'));
+ $this->assertTrue(function_exists('array_replace_recursive'));
+ $this->assertTrue(function_exists('quoted_printable_encode'));
+ }
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * array_column() test
+ *
+ * Borrowed from PHP's own tests
+ *
+ * @depends test_bootstrap
+ */
+ public function test_array_column()
+ {
+ // Basic tests
+
+ $input = array(
+ array(
+ 'id' => 1,
+ 'first_name' => 'John',
+ 'last_name' => 'Doe'
+ ),
+ array(
+ 'id' => 2,
+ 'first_name' => 'Sally',
+ 'last_name' => 'Smith'
+ ),
+ array(
+ 'id' => 3,
+ 'first_name' => 'Jane',
+ 'last_name' => 'Jones'
+ )
+ );
+
+ // Ensure internal array position doesn't break it
+ next($input);
+
+ $this->assertEquals(
+ array('John', 'Sally', 'Jane'),
+ array_column($input, 'first_name')
+ );
+
+ $this->assertEquals(
+ array(1, 2, 3),
+ array_column($input, 'id')
+ );
+
+ $this->assertEquals(
+ array(
+ 1 => 'Doe',
+ 2 => 'Smith',
+ 3 => 'Jones'
+ ),
+ array_column($input, 'last_name', 'id')
+ );
+
+ $this->assertEquals(
+ array(
+ 'John' => 'Doe',
+ 'Sally' => 'Smith',
+ 'Jane' => 'Jones'
+ ),
+ array_column($input, 'last_name', 'first_name')
+ );
+
+ // Object key search
+
+ $f = new Foo();
+ $b = new Bar();
+
+ $this->assertEquals(
+ array('Doe', 'Smith', 'Jones'),
+ array_column($input, $f)
+ );
+
+ $this->assertEquals(
+ array(
+ 'John' => 'Doe',
+ 'Sally' => 'Smith',
+ 'Jane' => 'Jones'
+ ),
+ array_column($input, $f, $b)
+ );
+
+ // NULL parameters
+
+ $input = array(
+ 456 => array(
+ 'id' => '3',
+ 'title' => 'Foo',
+ 'date' => '2013-03-25'
+ ),
+ 457 => array(
+ 'id' => '5',
+ 'title' => 'Bar',
+ 'date' => '2012-05-20'
+ )
+ );
+
+ $this->assertEquals(
+ array(
+ 3 => array(
+ 'id' => '3',
+ 'title' => 'Foo',
+ 'date' => '2013-03-25'
+ ),
+ 5 => array(
+ 'id' => '5',
+ 'title' => 'Bar',
+ 'date' => '2012-05-20'
+ )
+ ),
+ array_column($input, NULL, 'id')
+ );
+
+ $this->assertEquals(
+ array(
+ array(
+ 'id' => '3',
+ 'title' => 'Foo',
+ 'date' => '2013-03-25'
+ ),
+ array(
+ 'id' => '5',
+ 'title' => 'Bar',
+ 'date' => '2012-05-20'
+ )
+ ),
+ array_column($input, NULL, 'foo')
+ );
+
+ $this->assertEquals(
+ array(
+ array(
+ 'id' => '3',
+ 'title' => 'Foo',
+ 'date' => '2013-03-25'
+ ),
+ array(
+ 'id' => '5',
+ 'title' => 'Bar',
+ 'date' => '2012-05-20'
+ )
+ ),
+ array_column($input, NULL)
+ );
+
+ // Data types
+
+ $fh = fopen(__FILE__, 'r', TRUE);
+ $stdClass = new stdClass();
+ $input = array(
+ array(
+ 'id' => 1,
+ 'value' => $stdClass
+ ),
+ array(
+ 'id' => 2,
+ 'value' => 34.2345
+ ),
+ array(
+ 'id' => 3,
+ 'value' => TRUE
+ ),
+ array(
+ 'id' => 4,
+ 'value' => FALSE
+ ),
+ array(
+ 'id' => 5,
+ 'value' => NULL
+ ),
+ array(
+ 'id' => 6,
+ 'value' => 1234
+ ),
+ array(
+ 'id' => 7,
+ 'value' => 'Foo'
+ ),
+ array(
+ 'id' => 8,
+ 'value' => $fh
+ )
+ );
+
+ $this->assertEquals(
+ array(
+ $stdClass,
+ 34.2345,
+ TRUE,
+ FALSE,
+ NULL,
+ 1234,
+ 'Foo',
+ $fh
+ ),
+ array_column($input, 'value')
+ );
+
+ $this->assertEquals(
+ array(
+ 1 => $stdClass,
+ 2 => 34.2345,
+ 3 => TRUE,
+ 4 => FALSE,
+ 5 => NULL,
+ 6 => 1234,
+ 7 => 'Foo',
+ 8 => $fh
+ ),
+ array_column($input, 'value', 'id')
+ );
+
+ // Numeric column keys
+
+ $input = array(
+ array('aaa', '111'),
+ array('bbb', '222'),
+ array('ccc', '333', -1 => 'ddd')
+ );
+
+ $this->assertEquals(
+ array('111', '222', '333'),
+ array_column($input, 1)
+ );
+
+ $this->assertEquals(
+ array(
+ 'aaa' => '111',
+ 'bbb' => '222',
+ 'ccc' => '333'
+ ),
+ array_column($input, 1, 0)
+ );
+
+ $this->assertEquals(
+ array(
+ 'aaa' => '111',
+ 'bbb' => '222',
+ 'ccc' => '333'
+ ),
+ array_column($input, 1, 0.123)
+ );
+
+ $this->assertEquals(
+ array(
+ 0 => '111',
+ 1 => '222',
+ 'ddd' => '333'
+ ),
+ array_column($input, 1, -1)
+ );
+
+ // Non-existing columns
+
+ $this->assertEquals(array(), array_column($input, 2));
+ $this->assertEquals(array(), array_column($input, 'foo'));
+ $this->assertEquals(
+ array('aaa', 'bbb', 'ccc'),
+ array_column($input, 0, 'foo')
+ );
+ $this->assertEquals(array(), array_column($input, 3.14));
+
+ // One-dimensional array
+ $this->assertEquals(array(), array_column(array('foo', 'bar', 'baz'), 1));
+
+ // Columns not present in all rows
+
+ $input = array(
+ array('a' => 'foo', 'b' => 'bar', 'e' => 'bbb'),
+ array('a' => 'baz', 'c' => 'qux', 'd' => 'aaa'),
+ array('a' => 'eee', 'b' => 'fff', 'e' => 'ggg')
+ );
+
+ $this->assertEquals(
+ array('qux'),
+ array_column($input, 'c')
+ );
+
+ $this->assertEquals(
+ array('baz' => 'qux'),
+ array_column($input, 'c', 'a')
+ );
+
+ $this->assertEquals(
+ array(
+ 0 => 'foo',
+ 'aaa' => 'baz',
+ 1 => 'eee'
+ ),
+ array_column($input, 'a', 'd')
+ );
+
+ $this->assertEquals(
+ array(
+ 'bbb' => 'foo',
+ 0 => 'baz',
+ 'ggg' => 'eee'
+ ),
+ array_column($input, 'a', 'e')
+ );
+
+ $this->assertEquals(
+ array('bar', 'fff'),
+ array_column($input, 'b')
+ );
+
+ $this->assertEquals(
+ array(
+ 'foo' => 'bar',
+ 'eee' => 'fff'
+ ),
+ array_column($input, 'b', 'a')
+ );
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * hex2bin() tests
+ *
+ * @depends test_bootstrap
+ */
+ public function test_hex2bin()
+ {
+ if (is_php('5.4'))
+ {
+ return $this->markTestSkipped('hex2bin() is already available on PHP 5.4');
+ }
+
+ $this->assertEquals("\x03\x04", hex2bin("0304"));
+ $this->assertEquals('', hex2bin(''));
+ $this->assertEquals("\x01\x02\x03", hex2bin(new FooHex()));
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * array_replace(), array_replace_recursive() tests
+ *
+ * Borrowed from PHP's own tests
+ *
+ * @depends test_bootstrap
+ */
+ public function test_array_replace_recursive()
+ {
+ if (is_php('5.3'))
+ {
+ return $this->markTestSkipped('array_replace() and array_replace_recursive() are already available on PHP 5.3');
+ }
+
+ $array1 = array(
+ 0 => 'dontclobber',
+ '1' => 'unclobbered',
+ 'test2' => 0.0,
+ 'test3' => array(
+ 'testarray2' => TRUE,
+ 1 => array(
+ 'testsubarray1' => 'dontclobber2',
+ 'testsubarray2' => 'dontclobber3'
+ )
+ )
+ );
+
+ $array2 = array(
+ 1 => 'clobbered',
+ 'test3' => array(
+ 'testarray2' => FALSE
+ ),
+ 'test4' => array(
+ 'clobbered3' => array(0, 1, 2)
+ )
+ );
+
+ // array_replace()
+ $this->assertEquals(
+ array(
+ 0 => 'dontclobber',
+ 1 => 'clobbered',
+ 'test2' => 0.0,
+ 'test3' => array(
+ 'testarray2' => FALSE
+ ),
+ 'test4' => array(
+ 'clobbered3' => array(0, 1, 2)
+ )
+ ),
+ array_replace($array1, $array2)
+ );
+
+ // array_replace_recursive()
+ $this->assertEquals(
+ array(
+ 0 => 'dontclobber',
+ 1 => 'clobbered',
+ 'test2' => 0.0,
+ 'test3' => array(
+ 'testarray2' => FALSE,
+ 1 => array(
+ 'testsubarray1' => 'dontclobber2',
+ 'testsubarray2' => 'dontclobber3'
+ )
+ ),
+ 'test4' => array(
+ 'clobbered3' => array(0, 1, 2)
+ )
+ ),
+ array_replace_recursive($array1, $array2)
+ );
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * quoted_printable_encode() tests
+ *
+ * Borrowed from PHP's own tests
+ *
+ * @depends test_bootstrap
+ */
+ public function test_quoted_printable_encode()
+ {
+ if (is_php('5.3'))
+ {
+ return $this->markTestSkipped('quoted_printable_encode() is already available on PHP 5.3');
+ }
+
+
+ // These are actually imap_8bit() tests:
+ $this->assertEquals("String with CRLF at end=20\r\n", quoted_printable_encode("String with CRLF at end \r\n"));
+ // ext/imap/tests/imap_8bit_basic.phpt says for this line:
+ // NB this appears to be a bug in cclient; a space at end of string should be encoded as =20
+ $this->assertEquals("String with space at end ", quoted_printable_encode("String with space at end "));
+ $this->assertEquals("String with tabs =09=09 in middle", quoted_printable_encode("String with tabs \t\t in middle"));
+ $this->assertEquals("String with tab at end =09", quoted_printable_encode("String with tab at end \t"));
+ $this->assertEquals("=00=01=02=03=04=FE=FF=0A=0D", quoted_printable_encode("\x00\x01\x02\x03\x04\xfe\xff\x0a\x0d"));
+
+ // And these are from ext/standard/tests/strings/quoted_printable_encode_002.phpt:
+ $this->assertEquals(
+ "=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=\r\n"
+ ."=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=\r\n"
+ ."=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=\r\n"
+ ."=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=\r\n"
+ ."=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=\r\n"
+ ."=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=\r\n"
+ ."=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=\r\n"
+ ."=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00=00",
+ $d = quoted_printable_encode(str_repeat("\0", 200))
+ );
+ $this->assertEquals(str_repeat("\x0", 200), quoted_printable_decode($d));
+ $this->assertEquals(
+ "=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=\r\n"
+ ."=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=\r\n"
+ ."=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=\r\n"
+ ."=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=\r\n"
+ ."=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=\r\n"
+ ."=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=\r\n"
+ ."=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=\r\n"
+ ."=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=\r\n"
+ ."=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =\r\n"
+ ."=D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=\r\n"
+ ."=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=\r\n"
+ ."=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=\r\n"
+ ."=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=\r\n"
+ ."=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=\r\n"
+ ."=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=\r\n"
+ ."=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=\r\n"
+ ."=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=\r\n"
+ ."=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=\r\n"
+ ."=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=\r\n"
+ ."=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =\r\n"
+ ."=D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=\r\n"
+ ."=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=\r\n"
+ ."=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=\r\n"
+ ."=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=\r\n"
+ ."=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=\r\n"
+ ."=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=\r\n"
+ ."=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=\r\n"
+ ."=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=\r\n"
+ ."=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=\r\n"
+ ."=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=\r\n"
+ ."=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=\r\n"
+ ."=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =\r\n"
+ ."=D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=\r\n"
+ ."=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=\r\n"
+ ."=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=\r\n"
+ ."=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=\r\n"
+ ."=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=\r\n"
+ ."=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=\r\n"
+ ."=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=\r\n"
+ ."=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=\r\n"
+ ."=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=\r\n"
+ ."=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=\r\n"
+ ."=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =\r\n"
+ ."=D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=\r\n"
+ ."=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=\r\n"
+ ."=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=\r\n"
+ ."=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=\r\n"
+ ."=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=\r\n"
+ ."=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=\r\n"
+ ."=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=\r\n"
+ ."=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=\r\n"
+ ."=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=\r\n"
+ ."=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=\r\n"
+ ."=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=\r\n"
+ ."=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =\r\n"
+ ."=D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=\r\n"
+ ."=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=\r\n"
+ ."=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=\r\n"
+ ."=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=8E=D0=BD=D0=B8=\r\n"
+ ."=D0=BA=D0=BE=D0=B4=D0=B5=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0 =D0=B2 =D1=\r\n"
+ ."=8E=D0=BD=D0=B8=D0=BA=D0=BE=D0=B4=D0=B5",
+ $d = quoted_printable_encode(str_repeat('строка в юникоде', 50))
+ );
+ $this->assertEquals(str_repeat('строка в юникоде', 50), quoted_printable_decode($d));
+ $this->assertEquals('this is a foo', quoted_printable_encode(new FooObject()));
+ }
+}
+
+// ------------------------------------------------------------------------
+
+class Foo {
+
+ public function __toString()
+ {
+ return 'last_name';
+ }
+}
+
+class Bar {
+
+ public function __toString()
+ {
+ return 'first_name';
+ }
+}
+
+class FooHex {
+
+ public function __toString()
+ {
+ return '010203';
+ }
+}
+
+class FooObject
+{
+ public function __toString()
+ {
+ return 'this is a foo';
+ }
+} \ No newline at end of file
diff --git a/tests/codeigniter/libraries/Encrypt_test.php b/tests/codeigniter/libraries/Encrypt_test.php
index a08db8ed0..ced763301 100644
--- a/tests/codeigniter/libraries/Encrypt_test.php
+++ b/tests/codeigniter/libraries/Encrypt_test.php
@@ -1,15 +1,21 @@
<?php
-
+/**
+ * @requires extension mcrypt
+ */
class Encrypt_test extends CI_TestCase {
public function set_up()
{
+ if ( ! extension_loaded('mcrypt'))
+ {
+ return;
+ }
+
$this->encrypt = new Mock_Libraries_Encrypt();
$this->ci_instance_var('encrypt', $this->encrypt);
$this->ci_set_config('encryption_key', "Encryptin'glike@boss!");
$this->msg = 'My secret message';
- $this->mcrypt = extension_loaded('mcrypt');
}
// --------------------------------------------------------------------
@@ -40,12 +46,6 @@ class Encrypt_test extends CI_TestCase {
public function test_default_cipher()
{
- if ( ! $this->mcrypt)
- {
- $this->markTestSkipped('MCrypt not available');
- return;
- }
-
$this->assertEquals('rijndael-256', $this->encrypt->get_cipher());
}
@@ -53,12 +53,6 @@ class Encrypt_test extends CI_TestCase {
public function test_set_cipher()
{
- if ( ! $this->mcrypt)
- {
- $this->markTestSkipped('MCrypt not available');
- return;
- }
-
$this->encrypt->set_cipher(MCRYPT_BLOWFISH);
$this->assertEquals('blowfish', $this->encrypt->get_cipher());
}
@@ -67,12 +61,6 @@ class Encrypt_test extends CI_TestCase {
public function test_default_mode()
{
- if ( ! $this->mcrypt)
- {
- $this->markTestSkipped('MCrypt not available');
- return;
- }
-
$this->assertEquals('cbc', $this->encrypt->get_mode());
}
@@ -80,12 +68,6 @@ class Encrypt_test extends CI_TestCase {
public function test_set_mode()
{
- if ( ! $this->mcrypt)
- {
- $this->markTestSkipped('MCrypt not available');
- return;
- }
-
$this->encrypt->set_mode(MCRYPT_MODE_CFB);
$this->assertEquals('cfb', $this->encrypt->get_mode());
}
diff --git a/tests/codeigniter/libraries/Encryption_test.php b/tests/codeigniter/libraries/Encryption_test.php
index 759d7cdac..f457fe325 100644
--- a/tests/codeigniter/libraries/Encryption_test.php
+++ b/tests/codeigniter/libraries/Encryption_test.php
@@ -141,7 +141,6 @@ class Encryption_test extends CI_TestCase {
$this->assertTrue(is_array($this->encryption->__get_params($params)));
- $params['iv'] = NULL;
$params['base64'] = TRUE;
$params['hmac_digest'] = 'sha512';
@@ -150,7 +149,6 @@ class Encryption_test extends CI_TestCase {
'cipher' => 'aes-128',
'mode' => 'cbc',
'key' => str_repeat("\x0", 16),
- 'iv' => str_repeat("\x0", 16),
'raw_data' => TRUE,
'hmac_key' => str_repeat("\x0", 16),
'hmac_digest' => 'sha256'
@@ -216,22 +214,17 @@ class Encryption_test extends CI_TestCase {
$this->assertFalse($this->encryption->encrypt($message, array('foo')));
$this->assertFalse($this->encryption->decrypt($message, array('foo')));
- // Custom IV (we'll check it), no HMAC, binary output
+ // No HMAC, binary output
$params = array(
'cipher' => 'tripledes',
'mode' => 'cfb',
'key' => str_repeat("\x1", 16),
- 'iv' => str_repeat("\x2", 8),
'base64' => FALSE,
'hmac' => FALSE
);
$ciphertext = $this->encryption->encrypt($message, $params);
- $this->assertEquals(0, strncmp($params['iv'], $ciphertext, 8));
- // IV should be found in the cipher-text, no matter if it was supplied or not
- $this->assertEquals($message, $this->encryption->decrypt($ciphertext, $params));
- unset($params['iv']);
$this->assertEquals($message, $this->encryption->decrypt($ciphertext, $params));
}
diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php
index 5c32ca5c2..2e8265b15 100644
--- a/tests/mocks/core/common.php
+++ b/tests/mocks/core/common.php
@@ -32,7 +32,7 @@ if ( ! function_exists('config_item'))
if ( ! isset($config[$item]))
{
- return FALSE;
+ return NULL;
}
return $config[$item];
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 8492be289..0e4930289 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -61,6 +61,7 @@ Release Date: Not Released
- Added availability checks where usage of dangerous functions like ``eval()`` and ``exec()`` is required.
- Added support for changing the file extension of log files using ``$config['log_file_extension']``.
- Added support for turning newline standardization on/off via ``$config['standardize_newlines']`` and set it to FALSE by default.
+ - Added configuration setting ``$config['composer_autoload']`` to enable loading of a `Composer <https://getcomposer.org/>`_ auto-loader.
- Helpers
@@ -79,6 +80,7 @@ Release Date: Not Released
- :func:`url_title()` will now trim extra dashes from beginning and end.
- :func:`anchor_popup()` will now fill the *href* attribute with the URL and its JS code will return FALSE instead.
- Added JS window name support to the :func:`anchor_popup()` function.
+ - Added support for menubar attribute to the :func:`anchor_popup()`.
- Added support (auto-detection) for HTTP/1.1 response codes 303, 307 in :func:`redirect()`.
- Changed :func:`redirect()` to choose the **refresh** method only on IIS servers, instead of all servers on Windows (when **auto** is used).
- Changed :func:`anchor()`, :func:`anchor_popup()`, and :func:`redirect()` to support protocol-relative URLs (e.g. *//ellislab.com/codeigniter*).
@@ -135,6 +137,7 @@ Release Date: Not Released
- Added *word_length* and *pool* options to allow customization of the generated word.
- Added *colors* configuration to allow customization for the *background*, *border*, *text* and *grid* colors.
- Added *filename* to the returned array elements.
+ - Updated to use `imagepng()` in case that `imagejpeg()` isn't available.
- :doc:`Text Helper <helpers/text_helper>` changes include:
@@ -184,6 +187,7 @@ Release Date: Not Released
- Changed ``limit()`` to ignore NULL values instead of always casting to integer.
- Changed ``offset()`` to ignore empty values instead of always casting to integer.
- Methods ``insert_batch()`` and ``update_batch()`` now return an integer representing the number of rows affected by them.
+ - Methods ``where()``, ``or_where()``, ``having()`` and ``or_having()`` now convert trailing ``=`` and ``<>``, ``!=`` SQL operators to ``IS NULL`` and ``IS NOT NULL`` respectively when the supplied comparison value is ``NULL``.
- :doc:`Database Results <database/results>` changes include:
@@ -302,6 +306,7 @@ Release Date: Not Released
- Added a ``$reset`` parameter to method ``initialize()``.
- Removed method ``clean_file_name()`` and its usage in favor of :doc:`Security Library <libraries/security>`'s ``sanitize_filename()``.
- Removed method ``mimes_types()``.
+ - Changed ``CI_Upload::_prep_filename()`` to simply replace all (but the last) dots in the filename with underscores, instead of suffixing them.
- :doc:`Calendar Library <libraries/calendar>` changes include:
@@ -328,6 +333,7 @@ Release Date: Not Released
- If property *maintain_ratio* is set to TRUE, ``image_reproportion()`` now doesn't need both width and height to be specified.
- Property *maintain_ratio* is now taken into account when resizing images using ImageMagick library.
- Added support for maintaining transparency for PNG images in method ``text_watermark()``.
+ - Added a **file_permissions** setting.
- :doc:`Form Validation Library <libraries/form_validation>` changes include:
@@ -347,6 +353,7 @@ Release Date: Not Released
- Added rule **alpha_numeric_spaces**.
- Added support for custom error messages per field rule.
- Added support for callable rules when they are passed as an array.
+ - Added support for non-ASCII domains in **valid_email** rule, depending on the Intl extension.
- :doc:`Caching Library <libraries/caching>` changes include:
@@ -375,6 +382,7 @@ Release Date: Not Released
- Added an optional parameter to ``print_debugger()`` to allow specifying which parts of the message should be printed ('headers', 'subject', 'body').
- Added SMTP keepalive option to avoid opening the connection for each ``send()`` call. Accessible as ``$smtp_keepalive``.
- Public method ``set_header()`` now filters the input by removing all "\\r" and "\\n" characters.
+ - Added support for non-ASCII domains in ``valid_email()``, depending on the Intl extension.
- :doc:`Pagination Library <libraries/pagination>` changes include:
@@ -385,6 +393,7 @@ Release Date: Not Released
- Added support for language translations of the *first_link*, *next_link*, *prev_link* and *last_link* values.
- Added ``$config['reuse_query_string']`` to allow automatic repopulation of query string arguments, combined with normal URI segments.
- Removed the default ``&nbsp;`` from a number of the configuration variables.
+ - Added support for ``$config['num_links'] = 0`` configuration.
- :doc:`Profiler Library <general/profiling>` changes include:
@@ -482,6 +491,8 @@ Release Date: Not Released
- Removed the third (`$php_error`) argument from function :func:`log_message()`.
- Changed internal function ``load_class()`` to accept a constructor parameter instead of (previously unused) class name prefix.
- Removed default parameter value of :func:`is_php()`.
+ - Added a second argument ``$double_encode`` to :func:`html_escape()`.
+ - Changed function ``config_item()`` to return NULL instead of FALSE when no value is found.
- :doc:`Output Library <libraries/output>` changes include:
@@ -499,10 +510,12 @@ Release Date: Not Released
- :doc:`Security Library <libraries/security>` changes include:
+ - Added ``$config['csrf_regeneration']``, which makes CSRF token regeneration optional.
+ - Added ``$config['csrf_exclude_uris']``, allowing for exclusion of URIs from the CSRF protection (regular expressions are supported).
- Added method ``strip_image_tags()``.
- - Added ``$config['csrf_regeneration']``, which makes token regeneration optional.
- - Added ``$config['csrf_exclude_uris']``, which allows you list URIs which will not have the CSRF validation methods run.
+ - Added method ``get_random_bytes()`` and switched CSRF & XSS token generation to use it.
- Modified method ``sanitize_filename()`` to read a public ``$filename_bad_chars`` property for getting the invalid characters list.
+ - Return status code of 403 instead of a 500 if CSRF protection is enabled but a token is missing from a request.
- :doc:`Language Library <libraries/language>` changes include:
@@ -522,15 +535,19 @@ Release Date: Not Released
- Changed method ``clean_string()`` to utilize ``mb_convert_encoding()`` if it is available.
- Renamed method ``_is_ascii()`` to ``is_ascii()`` and made it public.
+ - Log Library changes include:
+
+ - Added a ``$config['log_file_permissions']`` setting.
+ - Changed the library constructor to try to create the **log_path** directory if it doesn't exist.
+
- Added `compatibility layers <general/compatibility_functions>` for:
- `Multibyte String <http://php.net/mbstring>`_ (limited support).
- `Hash <http://php.net/hash>`_ (``hash_equals()``, ``hash_pbkdf2()``).
- `Password Hashing <http://php.net/password>`_.
- - `Array Functions <http://php.net/book.array>`_ (``array_column()``, ``array_replace()``, ``array_replace_recursive()``).
+ - `Standard Functions ``array_column()``, ``array_replace()``, ``array_replace_recursive()``, ``hex2bin()``, ``quoted_printable_encode()``.
- Removed ``CI_CORE`` boolean constant from *CodeIgniter.php* (no longer Reactor and Core versions).
- - Log Library will now try to create the **log_path** directory if it doesn't exist.
- Added support for HTTP-Only cookies with new config option *cookie_httponly* (default FALSE).
- ``$config['time_reference']`` now supports all timezone strings supported by PHP.
- Fatal PHP errors are now also passed to ``_exception_handler()``, so they can be logged.
@@ -733,6 +750,8 @@ Bug fixes for 3.0
- Partially fixed a bug (#261) - UTF-8 class method ``clean_string()`` generating log messages and/or not producing the desired result due to an upstream bug in iconv.
- Fixed a bug where ``CI_Xmlrpcs::parseRequest()`` could fail if ``$HTTP_RAW_POST_DATA`` is not populated.
- Fixed a bug in :doc:`Zip Library <libraries/zip>` internal method ``_get_mod_time()`` where it was not parsing result returned by ``filemtime()``.
+- Fixed a bug (#3161) - :doc:`Cache Library <libraries/cache>` methods `increment()`, `decrement()` didn't auto-create non-existent items when using redis and/or file storage.
+- Fixed a bug (#3189) - :doc:`Parser Library <libraries/parser>` used double replacement on ``key->value`` pairs, exposing a potential template injection vulnerability.
Version 2.2.0
=============
@@ -789,7 +808,7 @@ Bug fixes for 2.1.3
- Fixed a bug (#227) - :doc:`Input Library <libraries/input>` allowed unconditional spoofing of HTTP clients' IP addresses through the *HTTP_CLIENT_IP* header.
- Fixed a bug (#907) - :doc:`Input Library <libraries/input>` ignored *HTTP_X_CLUSTER_CLIENT_IP* and *HTTP_X_CLIENT_IP* headers when checking for proxies.
- Fixed a bug (#940) - ``csrf_verify()`` used to set the CSRF cookie while processing a POST request with no actual POST data, which resulted in validating a request that should be considered invalid.
-- Fixed a bug (#499) - :doc:`Security Library <libraries/security>` where a CSRF cookie was created even if ``$config['csrf_protection']`` is set tot FALSE.
+- Fixed a bug (#499) - :doc:`Security Library <libraries/security>` where a CSRF cookie was created even if ``$config['csrf_protection']`` is set to FALSE.
- Fixed a bug (#1715) - :doc:`Input Library <libraries/input>` triggered ``csrf_verify()`` on CLI requests.
- Fixed a bug (#751) - :doc:`Query Builder <database/query_builder>` didn't properly handle cached field escaping overrides.
- Fixed a bug (#2004) - :doc:`Query Builder <database/query_builder>` didn't properly merge cached calls with non-cache ones.
diff --git a/user_guide_src/source/general/ancillary_classes.rst b/user_guide_src/source/general/ancillary_classes.rst
index edb3a14fb..f9b6ba231 100644
--- a/user_guide_src/source/general/ancillary_classes.rst
+++ b/user_guide_src/source/general/ancillary_classes.rst
@@ -78,7 +78,7 @@ Example::
public function bar()
{
- $this->CI->config_item('base_url');
+ $this->CI->config->item('base_url');
}
}
diff --git a/user_guide_src/source/general/autoloader.rst b/user_guide_src/source/general/autoloader.rst
index bf2e3935a..2f1223e28 100644
--- a/user_guide_src/source/general/autoloader.rst
+++ b/user_guide_src/source/general/autoloader.rst
@@ -20,4 +20,8 @@ file and add the item you want loaded to the autoload array. You'll
find instructions in that file corresponding to each type of item.
.. note:: Do not include the file extension (.php) when adding items to
- the autoload array. \ No newline at end of file
+ the autoload array.
+
+Additionally, if you want CodeIgniter to use a `Composer <https://getcomposer.org/>`_
+auto-loader, just set ``$config['composer_autoload']`` to ``TRUE`` or
+a custom path in **application/config/config.php**. \ No newline at end of file
diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst
index 9c0a7cbe1..399a323cc 100644
--- a/user_guide_src/source/general/common_functions.rst
+++ b/user_guide_src/source/general/common_functions.rst
@@ -63,7 +63,7 @@ loading any libraries or helpers.
.. function:: config_item($key)
:param string $key: Config item key
- :returns: Configuration key value or FALSE if not found
+ :returns: Configuration key value or NULL if not found
:rtype: mixed
The :doc:`Config Library <../libraries/config>` is the preferred way of
diff --git a/user_guide_src/source/general/compatibility_functions.rst b/user_guide_src/source/general/compatibility_functions.rst
index e685073a1..aee9b1ef0 100644
--- a/user_guide_src/source/general/compatibility_functions.rst
+++ b/user_guide_src/source/general/compatibility_functions.rst
@@ -7,12 +7,12 @@ you to use functions what are otherwise natively available in PHP,
but only in higher versions or depending on a certain extension.
Being custom implementations, these functions will also have some
-set of dependancies on their own, but are still useful if your
+set of dependencies on their own, but are still useful if your
PHP setup doesn't offer them natively.
.. note:: Much like the `common functions <common_functions>`, the
compatibility functions are always available, as long as
- their dependancies are met.
+ their dependencies are met.
.. contents::
:local:
@@ -29,7 +29,7 @@ This set of compatibility functions offers a "backport" of PHP's
standard `Password Hashing extension <http://php.net/password>`_
that is otherwise available only since PHP 5.5.
-Dependancies
+Dependencies
============
- PHP 5.3.7
@@ -65,7 +65,7 @@ Function reference
password_hash() <http://php.net/password_hash>`_.
.. note:: Unless you provide your own (and valid) salt, this function
- has a further dependancy on an available CSPRNG source. Each
+ has a further dependency on an available CSPRNG source. Each
of the following would satisfy that:
- ``mcrypt_create_iv()`` with ``MCRYPT_DEV_URANDOM``
- ``openssl_random_pseudo_bytes()``
@@ -101,7 +101,7 @@ This compatibility layer contains backports for the ``hash_equals()``
and ``hash_pbkdf2()`` functions, which otherwise require PHP 5.6 and/or
PHP 5.5 respectively.
-Dependancies
+Dependencies
============
- None
@@ -144,19 +144,19 @@ the limited alternative solutions, only a few functions are available.
.. note:: When a character set parameter is ommited,
``$config['charset']`` will be used.
-Dependancies
+Dependencies
============
- `iconv <http://php.net/iconv>`_ extension
-.. important:: This dependancy is optional and these functions will
+.. important:: This dependency is optional and these functions will
always be declared. If iconv is not available, they WILL
fall-back to their non-mbstring versions.
.. important:: Where a character set is supplied, it must be
supported by iconv and in a format that it recognizes.
-.. note:: For you own dependancy check on the actual mbstring
+.. note:: For you own dependency check on the actual mbstring
extension, use the ``MB_ENABLED`` constant.
Function reference
@@ -196,15 +196,14 @@ Function reference
For more information, please refer to the `PHP manual for
mb_substr() <http://php.net/mb_substr>`_.
-***************
-Array Functions
-***************
+******************
+Standard Functions
+******************
This set of compatibility functions offers support for a few
-standard `Array Functions <http://php.net/book.array>`_ in PHP
-that otherwise require a newer PHP version.
+standard functions in PHP that otherwise require a newer PHP version.
-Dependancies
+Dependencies
============
- None
@@ -244,4 +243,22 @@ Function reference
array_replace_recursive() <http://php.net/array_replace_recursive>`_.
.. important:: Only PHP's native function can detect endless recursion.
- Unless you are running PHP 5.3+, be careful with references! \ No newline at end of file
+ Unless you are running PHP 5.3+, be careful with references!
+
+.. function:: hex2bin($data)
+
+ :param array $data: Hexadecimal representation of data
+ :returns: Binary representation of the given data
+ :rtype: string
+
+ For more information, please refer to the `PHP manual for hex2bin()
+ <http://php.net/hex2bin>`_.
+
+.. function:: quoted_printable_encode($str)
+
+ :param string $str: Input string
+ :returns: 8bit-encoded string
+ :rtype: string
+
+ For more information, please refer to the `PHP manual for
+ quoted_printable_encode() <http://php.net/quoted_printable_encode>`_. \ No newline at end of file
diff --git a/user_guide_src/source/general/creating_drivers.rst b/user_guide_src/source/general/creating_drivers.rst
index cf4ea5d7f..63ac83902 100644
--- a/user_guide_src/source/general/creating_drivers.rst
+++ b/user_guide_src/source/general/creating_drivers.rst
@@ -18,4 +18,8 @@ Sample driver directory and file structure layout:
.. note:: In order to maintain compatibility on case-sensitive
file systems, the Driver_name directory must be
- named in the format returned by ``ucfirst()``. \ No newline at end of file
+ named in the format returned by ``ucfirst()``.
+
+.. note:: The Driver library's architecture is such that
+ the subclasses don't extend and therefore don't inherit
+ properties or methods of the main driver. \ No newline at end of file
diff --git a/user_guide_src/source/general/creating_libraries.rst b/user_guide_src/source/general/creating_libraries.rst
index a1e1b3e78..0e3ae4c85 100644
--- a/user_guide_src/source/general/creating_libraries.rst
+++ b/user_guide_src/source/general/creating_libraries.rst
@@ -170,7 +170,7 @@ methods, you're encouraged to assign it to a property instead::
public function bar()
{
- echo $this->CI->config_item('base_url');
+ echo $this->CI->config->item('base_url');
}
}
diff --git a/user_guide_src/source/general/routing.rst b/user_guide_src/source/general/routing.rst
index 0b91d3fa9..766e0b2ab 100644
--- a/user_guide_src/source/general/routing.rst
+++ b/user_guide_src/source/general/routing.rst
@@ -116,15 +116,13 @@ call the "shirts" controller class and the "id_123" method.
With regular expressions, you can also catch a segment containing a
forward slash ('/'), which would usually represent the delimiter between
multiple segments.
+
For example, if a user accesses a password protected area of your web
application and you wish to be able to redirect them back to the same
page after they log in, you may find this example useful::
$route['login/(.+)'] = 'auth/login/$1';
-That will call the "auth" controller class and its ``login()`` method,
-passing everything contained in the URI after *login/* as a parameter.
-
For those of you who don't know regular expressions and want to learn
more about them, `regular-expressions.info <http://www.regular-expressions.info/>`
might be a good starting point.
diff --git a/user_guide_src/source/helpers/captcha_helper.rst b/user_guide_src/source/helpers/captcha_helper.rst
index d83490b8e..1b74d08ad 100644
--- a/user_guide_src/source/helpers/captcha_helper.rst
+++ b/user_guide_src/source/helpers/captcha_helper.rst
@@ -54,7 +54,7 @@ Once loaded you can generate a CAPTCHA like this::
can draw randomly from.
- If you do not specify a path to a TRUE TYPE font, the native ugly GD
font will be used.
-- The "captcha" folder must be writable (666, or 777)
+- The "captcha" directory must be writable
- The **expiration** (in seconds) signifies how long an image will remain
in the captcha folder before it will be deleted. The default is two
hours.
diff --git a/user_guide_src/source/helpers/file_helper.rst b/user_guide_src/source/helpers/file_helper.rst
index 59cabcce2..013b583a0 100644
--- a/user_guide_src/source/helpers/file_helper.rst
+++ b/user_guide_src/source/helpers/file_helper.rst
@@ -80,8 +80,8 @@ The following functions are available:
for mode options.
.. note: In order for this function to write data to a file, its permissions must
- be set such that it is writable (666, 777, etc.). If the file does not
- already exist, the directory containing it must be writable.
+ be set such that it is writable. If the file does not already exist,
+ then the directory containing it must be writable.
.. note:: The path is relative to your main site index.php file, NOT your
controller or view files. CodeIgniter uses a front controller so paths
diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst
index 6915fafe2..81340e6ad 100644
--- a/user_guide_src/source/installation/upgrade_300.rst
+++ b/user_guide_src/source/installation/upgrade_300.rst
@@ -158,6 +158,10 @@ Step 10: Many functions now return NULL instead of FALSE on missing items
Many methods and functions now return NULL instead of FALSE when the required items don't exist:
+ - :doc:`Common functions <../general/common_functions>`
+
+ - config_item()
+
- :doc:`Config Class <../libraries/config>`
- config->item()
diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst
index a4415f510..f29ebf4ed 100644
--- a/user_guide_src/source/libraries/encryption.rst
+++ b/user_guide_src/source/libraries/encryption.rst
@@ -5,13 +5,13 @@ Encryption Library
The Encryption Library provides two-way data encryption. To do so in
a cryptographically secure way, it utilizes PHP extensions that are
unfortunately not always available on all systems.
-You must meet one of the following dependancies in order to use this
+You must meet one of the following dependencies in order to use this
library:
- `OpenSSL <http://php.net/openssl>`_ (and PHP 5.3.3)
- `MCrypt <http://php.net/mcrypt>`_ (and `MCRYPT_DEV_URANDOM` availability)
-If neither of the above dependancies is met, we simply cannot offer
+If neither of the above dependencies is met, we simply cannot offer
you a good enough implementation to meet the high standards required
for proper cryptography.
@@ -84,14 +84,19 @@ your server is not totally under your control it's impossible to ensure
key security so you may want to think carefully before using it for
anything that requires high security, like storing credit card numbers.
-Your encryption key should be as long as the encyption algorithm in use
-allows. For AES-128, that's 128 bits or 16 bytes (charcters) long. The
-key should be as random as possible and it should **not** be a simple
-text string.
-
+Your encryption key **must** be as long as the encyption algorithm in use
+allows. For AES-128, that's 128 bits or 16 bytes (charcters) long.
You will find a table below that shows the supported key lengths of
different ciphers.
+The key should be as random as possible and it **must not** be a regular
+text string, nor the output of a hashing function, etc. In order to create
+a proper key, you must use the Encryption library's ``create_key()`` method
+::
+
+ // $key will be assigned a 16-byte (128-bit) random key
+ $key = $this->encryption->create_key(16);
+
The key can be either stored in your *application/config/config.php*, or
you can design your own storage mechanism and pass the key dynamically
when encrypting/decrypting.
@@ -168,9 +173,9 @@ but regardless, here's a list of most of them:
============== ========= ============================== =========================================
Cipher name Driver Key lengths (bits / bytes) Supported modes
============== ========= ============================== =========================================
-AES-128 OpenSSL 128 / 16 CBC, CTR, CFB, CFB8, OFB, ECB, GCM, XTS
-AES-192 OpenSSL 192 / 24 CBC, CTR, CFB, CFB8, OFB, ECB, GCM, XTS
-AES-256 OpenSSL 256 / 32 CBC, CTR, CFB, CFB8, OFB, ECB, GCM, XTS
+AES-128 OpenSSL 128 / 16 CBC, CTR, CFB, CFB8, OFB, ECB, XTS
+AES-192 OpenSSL 192 / 24 CBC, CTR, CFB, CFB8, OFB, ECB, XTS
+AES-256 OpenSSL 256 / 32 CBC, CTR, CFB, CFB8, OFB, ECB, XTS
Rijndael-128 MCrypt 128 / 16, 192 / 24, 256 / 32 CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
Rijndael-192 MCrypt 128 / 16, 192 / 24, 256 / 32 CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
Rijndael-256 MCrypt 128 / 16, 192 / 24, 256 / 32 CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
@@ -234,7 +239,6 @@ CFB8 cfb8 MCrypt, OpenSSL Same as CFB, but operates in 8-
OFB ofb MCrypt, OpenSSL N/A
OFB8 ofb8 MCrypt Same as OFB, but operates in 8-bit mode (not recommended).
ECB ecb MCrypt, OpenSSL Ignores IV (not recommended).
-GCM gcm OpenSSL Provides authentication and therefore doesn't need a HMAC.
XTS xts OpenSSL Usually used for encrypting random access data such as RAM or hard-disk storage.
Stream stream MCrypt, OpenSSL This is not actually a mode, it just says that a stream cipher is being used. Required because of the general cipher+mode initialization process.
=========== ================== ================= ===================================================================================================================================================
@@ -246,10 +250,9 @@ It's probably important for you to know that an encrypted string is usually
longer than the original, plain-text string (depending on the cipher).
This is influenced by the cipher algorithm itself, the IV prepended to the
-cipher-text and (unless you are using GCM mode) the HMAC authentication
-message that is also prepended. Furthermore, the encrypted message is also
-Base64-encoded so that it is safe for storage and transmission, regardless
-of a possible character set in use.
+cipher-text and the HMAC authentication message that is also prepended.
+Furthermore, the encrypted message is also Base64-encoded so that it is safe
+for storage and transmission, regardless of a possible character set in use.
Keep this information in mind when selecting your data storage mechanism.
Cookies, for example, can only hold 4K of information.
@@ -425,9 +428,6 @@ Option Default value Mandatory / Optional Description
cipher N/A Yes Encryption algorithm (see :ref:`ciphers-and-modes`).
mode N/A Yes Encryption mode (see :ref:`encryption-modes`).
key N/A Yes Encryption key.
-iv N/A No Initialization vector (IV).
- If not provided it will be automatically generated
- during encryption and looked for during decryption.
hmac TRUE No Whether to use a HMAC.
Boolean. If set to FALSE, then *hmac_digest* and
*hmac_key* will be ignored.
@@ -444,9 +444,6 @@ raw_data FALSE No Whether the cipher-t
value is incorrect. This includes *hmac_key*, unless *hmac*
is set to FALSE.
-.. note:: If GCM mode is used, *hmac* will always be FALSE. This is
- because GCM mode itself provides authentication.
-
.. _digests:
Supported HMAC authentication algorithms
diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst
index 2ae56d29a..aae9e3b89 100644
--- a/user_guide_src/source/libraries/form_validation.rst
+++ b/user_guide_src/source/libraries/form_validation.rst
@@ -505,11 +505,40 @@ function::
'required',
function($value)
{
- // Check $value and return TRUE/FALSE
+ // Check $value
}
)
);
+Of course, since a Callable rule by itself is not a string, it isn't
+a rule name either. That is a problem when you want to set error messages
+for them. In order to get around that problem, you can put such rules as
+the second element of an array, with the first one being the rule name::
+
+ $this->form_validation->set_rules(
+ 'username', 'Username',
+ array(
+ 'required',
+ array('username_callable', array($this->users_model, 'valid_username'))
+ )
+ );
+
+Anonymous function (PHP 5.3+) version::
+
+ $this->form_validation->set_rules(
+ 'username', 'Username',
+ array(
+ 'required',
+ array(
+ 'username_callable',
+ function($str)
+ {
+ // Check validity of $str and return TRUE or FALSE
+ }
+ )
+ )
+ );
+
.. _setting-error-messages:
Setting Error Messages
diff --git a/user_guide_src/source/libraries/ftp.rst b/user_guide_src/source/libraries/ftp.rst
index dd9440443..4be1a6ea4 100644
--- a/user_guide_src/source/libraries/ftp.rst
+++ b/user_guide_src/source/libraries/ftp.rst
@@ -270,7 +270,7 @@ Class Reference
::
// Creates a folder named "bar"
- $this->ftp->mkdir('/public_html/foo/bar/', DIR_WRITE_MODE);
+ $this->ftp->mkdir('/public_html/foo/bar/', 0755);
.. method:: chmod($path, $perm)
@@ -282,8 +282,8 @@ Class Reference
Permits you to set file permissions. Supply the path to the file or
directory you wish to alter permissions on::
- // Chmod "bar" to 777
- $this->ftp->chmod('/public_html/foo/bar/', DIR_WRITE_MODE);
+ // Chmod "bar" to 755
+ $this->ftp->chmod('/public_html/foo/bar/', 0755);
.. method:: changedir($path[, $suppress_debug = FALSE])
diff --git a/user_guide_src/source/libraries/image_lib.rst b/user_guide_src/source/libraries/image_lib.rst
index 16acf090b..a52cf3e02 100644
--- a/user_guide_src/source/libraries/image_lib.rst
+++ b/user_guide_src/source/libraries/image_lib.rst
@@ -137,6 +137,8 @@ Preference Default Value Options
image can be shown at a time, and it can't be positioned on the page. It
simply outputs the raw image dynamically to your browser, along with
image headers.
+**file_permissions** 0644 (integer) File system permissions to apply on the resulting image file, R, C, X, W
+ writing it to the disk. WARNING: Use octal integer notation!
**quality** 90% 1 - 100% Sets the quality of the image. The higher the quality the larger the R, C, X, W
file size.
**new_image** None None Sets the destination image name/path. You'll use this preference when R, C, X, W
diff --git a/user_guide_src/source/libraries/output.rst b/user_guide_src/source/libraries/output.rst
index e49ea5366..218ec5896 100644
--- a/user_guide_src/source/libraries/output.rst
+++ b/user_guide_src/source/libraries/output.rst
@@ -205,4 +205,28 @@ Class Reference
Caches the current page for the specified amount of seconds.
- For more information, please see the :doc:`caching documentation <../general/caching>`. \ No newline at end of file
+ For more information, please see the :doc:`caching documentation <../general/caching>`.
+
+ .. method:: _display([$output = ''])
+
+ :param string $output: Output data override
+ :returns: void
+ :rtype: void
+
+ Sends finalized output data to the browser along with any server headers. It also stops benchmark
+ timers.
+
+ .. note:: This method is called automatically at the end of script execution, you won't need to
+ call it manually unless you are aborting script execution using ``exit()`` or ``die()`` in your code.
+
+ Example::
+ $response = array('status' => 'OK');
+
+ $this->output
+ ->set_status_header(200)
+ ->set_content_type('application/json', 'utf-8')
+ ->set_output(json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))
+ ->_display();
+ exit;
+
+ .. note:: Calling this method manually without aborting script execution will result in duplicated output. \ No newline at end of file
diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst
index fb875a0d9..0c51e342b 100644
--- a/user_guide_src/source/libraries/security.rst
+++ b/user_guide_src/source/libraries/security.rst
@@ -97,6 +97,13 @@ by editing the 'csrf_exclude_uris' config parameter::
$config['csrf_exclude_uris'] = array('api/person/add');
+Regular expressions are also supported (case-insensitive)::
+
+ $config['csrf_exclude_uris'] = array(
+ 'api/record/[0-9]+',
+ 'api/title/[a-z]+'
+ );
+
***************
Class Reference
***************
@@ -156,4 +163,19 @@ Class Reference
This method acts a lot like PHP's own native ``html_entity_decode()`` function in ENT_COMPAT mode, only
it tries to detect HTML entities that don't end in a semicolon because some browsers allow that.
- If the ``$charset`` parameter is left empty, then your configured ``$config['charset']`` value will be used. \ No newline at end of file
+ If the ``$charset`` parameter is left empty, then your configured ``$config['charset']`` value will be used.
+
+ .. method:: get_random_bytes($length)
+
+ :param int $length: Output length
+ :returns: A binary stream of random bytes or FALSE on failure
+ :rtype: string
+
+ A convenience method for getting proper random bytes via ``mcrypt_create_iv()``,
+ ``/dev/urandom`` or ``openssl_random_pseudo_bytes()`` (in that order), if one
+ of them is available.
+
+ Used for generating CSRF and XSS tokens.
+
+ .. note:: The output is NOT guaranteed to be cryptographically secure,
+ just the best attempt at that. \ No newline at end of file
diff --git a/user_guide_src/source/libraries/table.rst b/user_guide_src/source/libraries/table.rst
index 9d95eddfc..bb001e84c 100644
--- a/user_guide_src/source/libraries/table.rst
+++ b/user_guide_src/source/libraries/table.rst
@@ -95,24 +95,30 @@ The Table Class permits you to set a table template with which you can
specify the design of your layout. Here is the template prototype::
$template = array(
- 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
+ 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
- 'heading_row_start' => '<tr>',
- 'heading_row_end' => '</tr>',
- 'heading_cell_start' => '<th>',
- 'heading_cell_end' => '</th>',
+ 'thead_open' => '<thead>',
+ 'thead_close' => '</thead>',
- 'row_start' => '<tr>',
- 'row_end' => '</tr>',
- 'cell_start' => '<td>',
- 'cell_end' => '</td>',
+ 'heading_row_start' => '<tr>',
+ 'heading_row_end' => '</tr>',
+ 'heading_cell_start' => '<th>',
+ 'heading_cell_end' => '</th>',
- 'row_alt_start' => '<tr>',
- 'row_alt_end' => '</tr>',
- 'cell_alt_start' => '<td>',
- 'cell_alt_end' => '</td>',
+ 'tbody_open' => '<tbody>',
+ 'tbody_close' => '</tbody>',
- 'table_close' => '</table>'
+ 'row_start' => '<tr>',
+ 'row_end' => '</tr>',
+ 'cell_start' => '<td>',
+ 'cell_end' => '</td>',
+
+ 'row_alt_start' => '<tr>',
+ 'row_alt_end' => '</tr>',
+ 'cell_alt_start' => '<td>',
+ 'cell_alt_end' => '</td>',
+
+ 'table_close' => '</table>'
);
$this->table->set_template($template);
@@ -288,4 +294,4 @@ Class Reference
$this->table->add_row('Mary', 'Monday', 'Air');
$this->table->add_row('John', 'Saturday', 'Overnight');
- echo $this->table->generate(); \ No newline at end of file
+ echo $this->table->generate();
diff --git a/user_guide_src/source/libraries/zip.rst b/user_guide_src/source/libraries/zip.rst
index 5ff7d07d6..4ca14086a 100644
--- a/user_guide_src/source/libraries/zip.rst
+++ b/user_guide_src/source/libraries/zip.rst
@@ -173,7 +173,7 @@ Class Reference
:rtype: bool
Writes the Zip-encoded file to a directory on your server. Submit a valid server path ending in the file name.
- Make sure the directory is writable (660 or 666 is usually OK). Example::
+ Make sure the directory is writable (755 is usually OK). Example::
$this->zip->archive('/path/to/folder/myarchive.zip'); // Creates a file named myarchive.zip