summaryrefslogtreecommitdiffstats
path: root/system/libraries
diff options
context:
space:
mode:
Diffstat (limited to 'system/libraries')
-rw-r--r--system/libraries/Email.php87
-rw-r--r--system/libraries/Encryption.php2
-rw-r--r--system/libraries/Form_validation.php4
-rw-r--r--system/libraries/Session/Session.php82
-rw-r--r--system/libraries/Session/drivers/Session_files_driver.php45
-rw-r--r--system/libraries/Zip.php74
6 files changed, 251 insertions, 43 deletions
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 6a7e2b3a7..525a1277e 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -374,6 +374,13 @@ class CI_Email {
5 => '5 (Lowest)'
);
+ /**
+ * mbstring.func_override flag
+ *
+ * @var bool
+ */
+ protected static $func_override;
+
// --------------------------------------------------------------------
/**
@@ -390,6 +397,8 @@ class CI_Email {
$this->initialize($config);
$this->_safe_mode = ( ! is_php('5.4') && ini_get('safe_mode'));
+ isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+
log_message('info', 'Email Class Initialized');
}
@@ -1037,7 +1046,7 @@ class CI_Email {
{
if (function_exists('idn_to_ascii') && $atpos = strpos($email, '@'))
{
- $email = substr($email, 0, ++$atpos).idn_to_ascii(substr($email, $atpos));
+ $email = self::substr($email, 0, ++$atpos).idn_to_ascii(self::substr($email, $atpos));
}
return (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
@@ -1154,7 +1163,7 @@ class CI_Email {
{
// Is the line within the allowed character count?
// If so we'll join it to the output and continue
- if (mb_strlen($line) <= $charlim)
+ if (self::strlen($line) <= $charlim)
{
$output .= $line.$this->newline;
continue;
@@ -1170,10 +1179,10 @@ class CI_Email {
}
// Trim the word down
- $temp .= mb_substr($line, 0, $charlim - 1);
- $line = mb_substr($line, $charlim - 1);
+ $temp .= self::substr($line, 0, $charlim - 1);
+ $line = self::substr($line, $charlim - 1);
}
- while (mb_strlen($line) > $charlim);
+ while (self::strlen($line) > $charlim);
// If $temp contains data it means we had to split up an over-length
// word into smaller chunks so we'll add it back to our current line
@@ -1385,7 +1394,7 @@ class CI_Email {
$this->_header_str .= $hdr;
}
- strlen($body) && $body .= $this->newline.$this->newline;
+ self::strlen($body) && $body .= $this->newline.$this->newline;
$body .= $this->_get_mime_message().$this->newline.$this->newline
.'--'.$last_boundary.$this->newline
@@ -1532,7 +1541,7 @@ class CI_Email {
foreach (explode("\n", $str) as $line)
{
- $length = strlen($line);
+ $length = self::strlen($line);
$temp = '';
// Loop through each character in the line to add soft-wrap
@@ -1567,7 +1576,7 @@ class CI_Email {
// If we're at the character limit, add the line to the output,
// reset our temp variable, and keep on chuggin'
- if ((strlen($temp) + strlen($char)) >= 76)
+ if ((self::strlen($temp) + self::strlen($char)) >= 76)
{
$output .= $temp.$escape.$this->crlf;
$temp = '';
@@ -1582,7 +1591,7 @@ class CI_Email {
}
// get rid of extra CRLF tacked onto the end
- return substr($output, 0, strlen($this->crlf) * -1);
+ return self::substr($output, 0, self::strlen($this->crlf) * -1);
}
// --------------------------------------------------------------------
@@ -1624,7 +1633,7 @@ class CI_Email {
// iconv_mime_encode() will always put a header field name.
// We've passed it an empty one, but it still prepends our
// encoded string with ': ', so we need to strip it.
- return substr($output, 2);
+ return self::substr($output, 2);
}
$chars = iconv_strlen($str, 'UTF-8');
@@ -1636,10 +1645,10 @@ class CI_Email {
}
// We might already have this set for UTF-8
- isset($chars) OR $chars = strlen($str);
+ isset($chars) OR $chars = self::strlen($str);
$output = '=?'.$this->charset.'?Q?';
- for ($i = 0, $length = strlen($output); $i < $chars; $i++)
+ for ($i = 0, $length = self::strlen($output); $i < $chars; $i++)
{
$chr = ($this->charset === 'UTF-8' && ICONV_ENABLED === TRUE)
? '='.implode('=', str_split(strtoupper(bin2hex(iconv_substr($str, $i, 1, $this->charset))), 2))
@@ -1647,11 +1656,11 @@ class CI_Email {
// RFC 2045 sets a limit of 76 characters per line.
// We'll append ?= to the end of each line though.
- if ($length + ($l = strlen($chr)) > 74)
+ if ($length + ($l = self::strlen($chr)) > 74)
{
$output .= '?='.$this->crlf // EOL
.' =?'.$this->charset.'?Q?'.$chr; // New line
- $length = 6 + strlen($this->charset) + $l; // Reset the length for the new line
+ $length = 6 + self::strlen($this->charset) + $l; // Reset the length for the new line
}
else
{
@@ -1744,14 +1753,14 @@ class CI_Email {
if ($i === $float)
{
- $chunk[] = substr($set, 1);
+ $chunk[] = self::substr($set, 1);
$float += $this->bcc_batch_size;
$set = '';
}
if ($i === $c-1)
{
- $chunk[] = substr($set, 1);
+ $chunk[] = self::substr($set, 1);
}
}
@@ -2109,7 +2118,7 @@ class CI_Email {
$this->_debug_msg[] = '<pre>'.$cmd.': '.$reply.'</pre>';
- if ((int) substr($reply, 0, 3) !== $resp)
+ if ((int) self::substr($reply, 0, 3) !== $resp)
{
$this->_set_error_message('lang:email_smtp_error', $reply);
return FALSE;
@@ -2196,9 +2205,9 @@ class CI_Email {
protected function _send_data($data)
{
$data .= $this->newline;
- for ($written = $timestamp = 0, $length = strlen($data); $written < $length; $written += $result)
+ for ($written = $timestamp = 0, $length = self::strlen($data); $written < $length; $written += $result)
{
- if (($result = fwrite($this->_smtp_connect, substr($data, $written))) === FALSE)
+ if (($result = fwrite($this->_smtp_connect, self::substr($data, $written))) === FALSE)
{
break;
}
@@ -2382,4 +2391,44 @@ class CI_Email {
{
is_resource($this->_smtp_connect) && $this->_send_command('quit');
}
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Byte-safe strlen()
+ *
+ * @param string $str
+ * @return int
+ */
+ 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);
+ }
}
diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php
index 06284c2ed..545081b3b 100644
--- a/system/libraries/Encryption.php
+++ b/system/libraries/Encryption.php
@@ -907,7 +907,7 @@ class CI_Encryption {
* Byte-safe strlen()
*
* @param string $str
- * @return integer
+ * @return int
*/
protected static function strlen($str)
{
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 4380dd276..384caf000 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -1233,9 +1233,9 @@ class CI_Form_validation {
*/
public function valid_email($str)
{
- if (function_exists('idn_to_ascii') && $atpos = strpos($str, '@'))
+ if (function_exists('idn_to_ascii') && sscanf($str, '%[^@]@%s', $name, $domain) === 2)
{
- $str = substr($str, 0, ++$atpos).idn_to_ascii(substr($str, $atpos));
+ $str = $name.'@'.idn_to_ascii($domain);
}
return (bool) filter_var($str, FILTER_VALIDATE_EMAIL);
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
index 3b391a8ef..01989d2d7 100644
--- a/system/libraries/Session/Session.php
+++ b/system/libraries/Session/Session.php
@@ -57,6 +57,7 @@ class CI_Session {
protected $_driver = 'files';
protected $_config;
+ protected $_sid_regexp;
// ------------------------------------------------------------------------
@@ -99,6 +100,7 @@ class CI_Session {
// Configuration ...
$this->_configure($params);
+ $this->_config['_sid_regexp'] = $this->_sid_regexp;
$class = new $class($this->_config);
if ($class instanceof SessionHandlerInterface)
@@ -131,7 +133,7 @@ class CI_Session {
if (isset($_COOKIE[$this->_config['cookie_name']])
&& (
! is_string($_COOKIE[$this->_config['cookie_name']])
- OR ! preg_match('/^[0-9a-f]{40}$/', $_COOKIE[$this->_config['cookie_name']])
+ OR ! preg_match('#\A'.$this->_sid_regexp.'\z#', $_COOKIE[$this->_config['cookie_name']])
)
)
{
@@ -315,8 +317,82 @@ class CI_Session {
ini_set('session.use_strict_mode', 1);
ini_set('session.use_cookies', 1);
ini_set('session.use_only_cookies', 1);
- ini_set('session.hash_function', 1);
- ini_set('session.hash_bits_per_character', 4);
+
+ $this->_configure_sid_length();
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Configure session ID length
+ *
+ * To make life easier, we used to force SHA-1 and 4 bits per
+ * character on everyone. And of course, someone was unhappy.
+ *
+ * Then PHP 7.1 broke backwards-compatibility because ext/session
+ * is such a mess that nobody wants to touch it with a pole stick,
+ * and the one guy who does, nobody has the energy to argue with.
+ *
+ * So we were forced to make changes, and OF COURSE something was
+ * going to break and now we have this pile of shit. -- Narf
+ *
+ * @return void
+ */
+ protected function _configure_sid_length()
+ {
+ if (PHP_VERSION_ID < 70100)
+ {
+ $hash_function = ini_get('session.hash_function');
+ if (ctype_digit($hash_function))
+ {
+ if ($hash_function !== '1')
+ {
+ ini_set('session.hash_function', 1);
+ }
+
+ $bits = 160;
+ }
+ elseif ( ! in_array($hash_function, hash_algos(), TRUE))
+ {
+ ini_set('session.hash_function', 1);
+ $bits = 160;
+ }
+ elseif (($bits = strlen(hash($hash_function, 'dummy', false)) * 4) < 160)
+ {
+ ini_set('session.hash_function', 1);
+ $bits = 160;
+ }
+
+ $bits_per_character = (int) ini_get('session.hash_bits_per_character');
+ $sid_length = (int) ceil($bits / $bits_per_character);
+ }
+ else
+ {
+ $bits_per_character = (int) ini_get('session.sid_bits_per_character');
+ $sid_length = (int) ini_get('session.sid_length');
+ if (($bits = $sid_length * $bits_per_character) < 160)
+ {
+ // Add as many more characters as necessary to reach at least 160 bits
+ $sid_length += (int) ceil((160 % $bits) / $bits_per_character);
+ ini_set('session.sid_length', $sid_length);
+ }
+ }
+
+ // Yes, 4,5,6 are the only known possible values as of 2016-10-27
+ switch ($bits_per_character)
+ {
+ case 4:
+ $this->_sid_regexp = '[0-9a-f]';
+ break;
+ case 5:
+ $this->_sid_regexp = '[0-9a-v]';
+ break;
+ case 6:
+ $this->_sid_regexp = '[0-9a-zA-Z,-]';
+ break;
+ }
+
+ $this->_sid_regexp .= '{'.$sid_length.'}';
}
// ------------------------------------------------------------------------
diff --git a/system/libraries/Session/drivers/Session_files_driver.php b/system/libraries/Session/drivers/Session_files_driver.php
index bf4df8b20..37315d3cd 100644
--- a/system/libraries/Session/drivers/Session_files_driver.php
+++ b/system/libraries/Session/drivers/Session_files_driver.php
@@ -76,6 +76,20 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
*/
protected $_file_new;
+ /**
+ * Validate SID regular expression
+ *
+ * @var string
+ */
+ protected $_sid_regexp;
+
+ /**
+ * mbstring.func_override flag
+ *
+ * @var bool
+ */
+ protected static $func_override;
+
// ------------------------------------------------------------------------
/**
@@ -98,6 +112,10 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
log_message('debug', 'Session: "sess_save_path" is empty; using "session.save_path" value from php.ini.');
$this->_config['save_path'] = rtrim(ini_get('session.save_path'), '/\\');
}
+
+ $this->_sid_regexp = $this->_config['_sid_regexp'];
+
+ isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
}
// ------------------------------------------------------------------------
@@ -187,7 +205,7 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
}
$session_data = '';
- for ($read = 0, $length = filesize($this->_file_path.$session_id); $read < $length; $read += strlen($buffer))
+ for ($read = 0, $length = filesize($this->_file_path.$session_id); $read < $length; $read += self::strlen($buffer))
{
if (($buffer = fread($this->_file_handle, $length - $read)) === FALSE)
{
@@ -343,10 +361,13 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
$ts = time() - $maxlifetime;
+ $pattern = ($this->_config['match_ip'] === TRUE)
+ ? '[0-9a-f]{32}'
+ : '';
+
$pattern = sprintf(
- '/^%s[0-9a-f]{%d}$/',
- preg_quote($this->_config['cookie_name'], '/'),
- ($this->_config['match_ip'] === TRUE ? 72 : 40)
+ '#\A%s'.$pattern.$this->_sid_regexp.'\z#',
+ preg_quote($this->_config['cookie_name'])
);
while (($file = readdir($directory)) !== FALSE)
@@ -368,4 +389,18 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle
return $this->_success;
}
-} \ No newline at end of file
+ // --------------------------------------------------------------------
+
+ /**
+ * Byte-safe strlen()
+ *
+ * @param string $str
+ * @return int
+ */
+ protected static function strlen($str)
+ {
+ return (self::$func_override)
+ ? mb_strlen($str, '8bit')
+ : strlen($str);
+ }
+}
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index 140ad7212..25315c92e 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -106,12 +106,21 @@ class CI_Zip {
public $compression_level = 2;
/**
+ * mbstring.func_override flag
+ *
+ * @var bool
+ */
+ protected static $func_override;
+
+ /**
* Initialize zip compression class
*
* @return void
*/
public function __construct()
{
+ isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+
$this->now = time();
log_message('info', 'Zip Compression Class Initialized');
}
@@ -182,7 +191,7 @@ class CI_Zip {
.pack('V', 0) // crc32
.pack('V', 0) // compressed filesize
.pack('V', 0) // uncompressed filesize
- .pack('v', strlen($dir)) // length of pathname
+ .pack('v', self::strlen($dir)) // length of pathname
.pack('v', 0) // extra field length
.$dir
// below is "data descriptor" segment
@@ -197,7 +206,7 @@ class CI_Zip {
.pack('V',0) // crc32
.pack('V',0) // compressed filesize
.pack('V',0) // uncompressed filesize
- .pack('v', strlen($dir)) // length of pathname
+ .pack('v', self::strlen($dir)) // length of pathname
.pack('v', 0) // extra field length
.pack('v', 0) // file comment length
.pack('v', 0) // disk number start
@@ -206,7 +215,7 @@ class CI_Zip {
.pack('V', $this->offset) // relative offset of local header
.$dir;
- $this->offset = strlen($this->zipdata);
+ $this->offset = self::strlen($this->zipdata);
$this->entries++;
}
@@ -255,10 +264,10 @@ class CI_Zip {
{
$filepath = str_replace('\\', '/', $filepath);
- $uncompressed_size = strlen($data);
+ $uncompressed_size = self::strlen($data);
$crc32 = crc32($data);
- $gzdata = substr(gzcompress($data, $this->compression_level), 2, -4);
- $compressed_size = strlen($gzdata);
+ $gzdata = self::substr(gzcompress($data, $this->compression_level), 2, -4);
+ $compressed_size = self::strlen($gzdata);
$this->zipdata .=
"\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00"
@@ -267,7 +276,7 @@ class CI_Zip {
.pack('V', $crc32)
.pack('V', $compressed_size)
.pack('V', $uncompressed_size)
- .pack('v', strlen($filepath)) // length of filename
+ .pack('v', self::strlen($filepath)) // length of filename
.pack('v', 0) // extra field length
.$filepath
.$gzdata; // "file data" segment
@@ -279,7 +288,7 @@ class CI_Zip {
.pack('V', $crc32)
.pack('V', $compressed_size)
.pack('V', $uncompressed_size)
- .pack('v', strlen($filepath)) // length of filename
+ .pack('v', self::strlen($filepath)) // length of filename
.pack('v', 0) // extra field length
.pack('v', 0) // file comment length
.pack('v', 0) // disk number start
@@ -288,7 +297,7 @@ class CI_Zip {
.pack('V', $this->offset) // relative offset of local header
.$filepath;
- $this->offset = strlen($this->zipdata);
+ $this->offset = self::strlen($this->zipdata);
$this->entries++;
$this->file_num++;
}
@@ -401,8 +410,8 @@ class CI_Zip {
.$this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00"
.pack('v', $this->entries) // total # of entries "on this disk"
.pack('v', $this->entries) // total # of entries overall
- .pack('V', strlen($this->directory)) // size of central dir
- .pack('V', strlen($this->zipdata)) // offset to start of central dir
+ .pack('V', self::strlen($this->directory)) // size of central dir
+ .pack('V', self::strlen($this->zipdata)) // offset to start of central dir
."\x00\x00"; // .zip file comment length
}
@@ -425,9 +434,9 @@ class CI_Zip {
flock($fp, LOCK_EX);
- for ($result = $written = 0, $data = $this->get_zip(), $length = strlen($data); $written < $length; $written += $result)
+ for ($result = $written = 0, $data = $this->get_zip(), $length = self::strlen($data); $written < $length; $written += $result)
{
- if (($result = fwrite($fp, substr($data, $written))) === FALSE)
+ if (($result = fwrite($fp, self::substr($data, $written))) === FALSE)
{
break;
}
@@ -481,4 +490,43 @@ class CI_Zip {
return $this;
}
+ // --------------------------------------------------------------------
+
+ /**
+ * Byte-safe strlen()
+ *
+ * @param string $str
+ * @return int
+ */
+ 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);
+ }
}