diff options
Diffstat (limited to 'system')
30 files changed, 497 insertions, 95 deletions
diff --git a/system/core/Common.php b/system/core/Common.php index 9e23a4ea5..a9b8828e3 100644 --- a/system/core/Common.php +++ b/system/core/Common.php @@ -778,11 +778,9 @@ if ( ! function_exists('_stringify_attributes')) */ function _stringify_attributes($attributes, $js = FALSE) { - $atts = NULL; - if (empty($attributes)) { - return $atts; + return NULL; } if (is_string($attributes)) @@ -792,6 +790,7 @@ if ( ! function_exists('_stringify_attributes')) $attributes = (array) $attributes; + $atts = ''; foreach ($attributes as $key => $val) { $atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"'; diff --git a/system/core/Input.php b/system/core/Input.php index 3fb4121eb..47bdbfc5d 100644 --- a/system/core/Input.php +++ b/system/core/Input.php @@ -357,14 +357,15 @@ class CI_Input { * @param string $prefix Cookie name prefix * @param bool $secure Whether to only transfer cookies via SSL * @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript) + * @param string $samesite SameSite attribute * @return void */ - public function set_cookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL) + public function set_cookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL, $samesite = NULL) { if (is_array($name)) { // always leave 'name' in last place, as the loop will break otherwise, due to $$item - foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item) + foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name', 'samesite') as $item) { if (isset($name[$item])) { @@ -405,7 +406,47 @@ class CI_Input { $expire = ($expire > 0) ? time() + $expire : 0; } - setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly); + isset($samesite) OR $samesite = config_item('cookie_samesite'); + if (isset($samesite)) + { + $samesite = ucfirst(strtolower($samesite)); + in_array($samesite, array('Lax', 'Strict', 'None'), TRUE) OR $samesite = 'Lax'; + } + else + { + $samesite = 'Lax'; + } + + if ($samesite === 'None' && ! $secure) + { + log_message('error', $name.' cookie sent with SameSite=None, but without Secure attribute.'); + } + + if ( ! is_php('7.3')) + { + $maxage = $expire - time(); + if ($maxage < 1) + { + $maxage = 0; + } + + $cookie_header = 'Set-Cookie: '.$prefix.$name.'='.rawurlencode($value); + $cookie_header .= ($expire === 0 ? '' : '; Expires='.gmdate('D, d-M-Y H:i:s T', $expire)).'; Max-Age='.$maxage; + $cookie_header .= '; Path='.$path.($domain !== '' ? '; Domain='.$domain : ''); + $cookie_header .= ($secure ? '; Secure' : '').($httponly ? '; HttpOnly' : '').'; SameSite='.$samesite; + header($cookie_header); + return; + } + + $setcookie_options = array( + 'expires' => $expire, + 'path' => $path, + 'domain' => $domain, + 'secure' => $secure, + 'httponly' => $httponly, + 'samesite' => $samesite, + ); + setcookie($prefix.$name, $value, $setcookie_options); } // -------------------------------------------------------------------- @@ -565,7 +606,7 @@ class CI_Input { $which = FILTER_FLAG_IPV6; break; default: - $which = NULL; + $which = 0; break; } diff --git a/system/core/Log.php b/system/core/Log.php index f66f1aa48..683c16bac 100644 --- a/system/core/Log.php +++ b/system/core/Log.php @@ -122,7 +122,7 @@ class CI_Log { { $config =& get_config(); - isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); + isset(self::$func_overload) OR self::$func_overload = ( ! is_php('8.0') && extension_loaded('mbstring') && @ini_get('mbstring.func_overload')); $this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/'; $this->_file_ext = (isset($config['log_file_extension']) && $config['log_file_extension'] !== '') diff --git a/system/core/Output.php b/system/core/Output.php index cef092600..8e3245b79 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -145,7 +145,7 @@ class CI_Output { && extension_loaded('zlib') ); - isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); + isset(self::$func_overload) OR self::$func_overload = ( ! is_php('8.0') && extension_loaded('mbstring') && @ini_get('mbstring.func_overload')); // Get mime types for later $this->mimes =& get_mimes(); @@ -299,10 +299,14 @@ class CI_Output { */ public function get_header($header) { - // Combine headers already sent with our batched headers + // We only need [x][0] from our multi-dimensional array + $header_lines = array_map(function ($headers) + { + return array_shift($headers); + }, $this->headers); + $headers = array_merge( - // We only need [x][0] from our multi-dimensional array - array_map('array_shift', $this->headers), + $header_lines, headers_list() ); diff --git a/system/core/Security.php b/system/core/Security.php index e1dc2a92f..d1d4f8432 100644 --- a/system/core/Security.php +++ b/system/core/Security.php @@ -193,7 +193,7 @@ class CI_Security { $this->_csrf_set_hash(); } - $this->charset = strtoupper(config_item('charset')); + $this->charset = strtoupper((string) config_item('charset')); log_message('info', 'Security Class Initialized'); } @@ -272,15 +272,35 @@ class CI_Security { return FALSE; } - setcookie( - $this->_csrf_cookie_name, - $this->_csrf_hash, - $expire, - config_item('cookie_path'), - config_item('cookie_domain'), - $secure_cookie, - config_item('cookie_httponly') - ); + if (is_php('7.3')) + { + setcookie( + $this->_csrf_cookie_name, + $this->_csrf_hash, + array( + 'expires' => $expire, + 'path' => config_item('cookie_path'), + 'domain' => config_item('cookie_domain'), + 'secure' => $secure_cookie, + 'httponly' => config_item('cookie_httponly'), + 'samesite' => 'Strict' + ) + ); + } + else + { + $domain = trim(config_item('cookie_domain')); + header('Set-Cookie: '.$this->_csrf_cookie_name.'='.$this->_csrf_hash + .'; Expires='.gmdate('D, d-M-Y H:i:s T', $expire) + .'; Max-Age='.$this->_csrf_expire + .'; Path='.rawurlencode(config_item('cookie_path')) + .($domain === '' ? '' : '; Domain='.$domain) + .($secure_cookie ? '; Secure' : '') + .(config_item('cookie_httponly') ? '; HttpOnly' : '') + .'; SameSite=Strict' + ); + } + log_message('info', 'CSRF cookie sent'); return $this; diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php index c7bca96d8..fd7cd5543 100644 --- a/system/database/DB_driver.php +++ b/system/database/DB_driver.php @@ -887,7 +887,7 @@ abstract class CI_DB_driver { { return $this->_trans_status; } - + // -------------------------------------------------------------------- /** @@ -1576,6 +1576,7 @@ abstract class CI_DB_driver { '\s+EXISTS\s*\(.*\)', // EXISTS(sql) '\s+NOT EXISTS\s*\(.*\)', // NOT EXISTS(sql) '\s+BETWEEN\s+', // BETWEEN value AND value + '\s+NOT BETWEEN\s+', // NOT BETWEEN value AND value '\s+IN\s*\(.*\)', // IN(list) '\s+NOT IN\s*\(.*\)', // NOT IN (list) '\s+LIKE\s+\S.*('.$_les.')?', // LIKE 'expr'[ ESCAPE '%s'] diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php index c16897632..3dea1dbc5 100644 --- a/system/database/drivers/mysqli/mysqli_driver.php +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -116,6 +116,13 @@ class CI_DB_mysqli_driver extends CI_DB { */ public function db_connect($persistent = FALSE) { + // PHP 8.1 changes default error handling mode from silent to exceptions - reverse that + if (is_php('8.1')) + { + $mysqli_driver = new mysqli_driver(); + $mysqli_driver->report_mode = MYSQLI_REPORT_OFF; + } + // Do we have a socket path? if ($this->hostname[0] === '/') { diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php index a9d75ebf2..511ef0e64 100644 --- a/system/database/drivers/oci8/oci8_driver.php +++ b/system/database/drivers/oci8/oci8_driver.php @@ -682,6 +682,16 @@ class CI_DB_oci8_driver extends CI_DB { */ protected function _close() { + if (is_resource($this->curs_id)) + { + oci_free_statement($this->curs_id); + } + + if (is_resource($this->stmt_id)) + { + oci_free_statement($this->stmt_id); + } + oci_close($this->conn_id); } diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php index d0a2bf959..b2178b684 100644 --- a/system/database/drivers/pdo/pdo_driver.php +++ b/system/database/drivers/pdo/pdo_driver.php @@ -131,6 +131,14 @@ class CI_DB_pdo_driver extends CI_DB { $this->options[PDO::ATTR_PERSISTENT] = TRUE; } + // From PHP8.0, default PDO::ATTR_ERRMODE is changed + // from PDO::ERRMODE_SILENT to PDO::ERRMODE_EXCEPTION + // as https://wiki.php.net/rfc/pdo_default_errmode + if ( ! isset($this->options[PDO::ATTR_ERRMODE])) + { + $this->options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT; + } + try { return new PDO($this->dsn, $this->username, $this->password, $this->options); diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php index 187cb2d09..4c3a5aaea 100644 --- a/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php +++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php @@ -54,6 +54,13 @@ class CI_DB_pdo_pgsql_forge extends CI_DB_pdo_forge { protected $_drop_table_if = 'DROP TABLE IF EXISTS'; /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS'; + + /** * UNSIGNED support * * @var array diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php index 84717d8b5..eb11a556a 100644 --- a/system/database/drivers/postgre/postgre_driver.php +++ b/system/database/drivers/postgre/postgre_driver.php @@ -135,7 +135,7 @@ class CI_DB_postgre_driver extends CI_DB { * Database connection * * @param bool $persistent - * @return resource + * @return resource|object */ public function db_connect($persistent = FALSE) { @@ -226,7 +226,7 @@ class CI_DB_postgre_driver extends CI_DB { * Execute the query * * @param string $sql an SQL query - * @return resource + * @return resource|object */ protected function _execute($sql) { diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php index a0a628f0a..d977a60e3 100644 --- a/system/database/drivers/postgre/postgre_result.php +++ b/system/database/drivers/postgre/postgre_result.php @@ -126,7 +126,7 @@ class CI_DB_postgre_result extends CI_DB_result { */ public function free_result() { - if (is_resource($this->result_id)) + if ($this->result_id !== FALSE) { pg_free_result($this->result_id); $this->result_id = FALSE; diff --git a/system/libraries/Email.php b/system/libraries/Email.php index dcc4ca0d3..6c453da3f 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -397,7 +397,7 @@ class CI_Email { $this->initialize($config); $this->_safe_mode = ( ! is_php('5.4') && ini_get('safe_mode')); - isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); + isset(self::$func_overload) OR self::$func_overload = ( ! is_php('8.0') && extension_loaded('mbstring') && @ini_get('mbstring.func_overload')); log_message('info', 'Email Class Initialized'); } diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index cb8ad9de9..933f6f232 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -161,7 +161,7 @@ class CI_Encryption { show_error('Encryption: Unable to find an available encryption driver.'); } - isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); + isset(self::$func_overload) OR self::$func_overload = ( ! is_php('8.0') && extension_loaded('mbstring') && @ini_get('mbstring.func_overload')); $this->initialize($params); if ( ! isset($this->_key) && self::strlen($key = config_item('encryption_key')) > 0) @@ -476,7 +476,7 @@ class CI_Encryption { $iv = ($iv_size = openssl_cipher_iv_length($params['handle'])) ? $this->create_key($iv_size) - : NULL; + : ''; $data = openssl_encrypt( $data, @@ -585,7 +585,7 @@ class CI_Encryption { } else { - $iv = NULL; + $iv = ''; } if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0) @@ -632,7 +632,7 @@ class CI_Encryption { } else { - $iv = NULL; + $iv = ''; } return empty($params['handle']) @@ -910,8 +910,8 @@ class CI_Encryption { protected static function strlen($str) { return (self::$func_overload) - ? mb_strlen($str, '8bit') - : strlen($str); + ? mb_strlen((string) $str, '8bit') + : strlen((string) $str); } // -------------------------------------------------------------------- diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 9d976984e..1b7bbb96c 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -1056,7 +1056,7 @@ class CI_Form_validation { { return is_array($str) ? (empty($str) === FALSE) - : (trim($str) !== ''); + : (trim((string) $str) !== ''); } // -------------------------------------------------------------------- diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php index 61fa80c0f..92644153a 100644 --- a/system/libraries/Ftp.php +++ b/system/libraries/Ftp.php @@ -202,7 +202,7 @@ class CI_FTP { */ protected function _is_conn() { - if ( ! is_resource($this->conn_id)) + if ($this->conn_id !== FALSE) { if ($this->debug === TRUE) { diff --git a/system/libraries/Session/CI_Session_driver_interface.php b/system/libraries/Session/CI_Session_driver_interface.php new file mode 100644 index 000000000..a854e92af --- /dev/null +++ b/system/libraries/Session/CI_Session_driver_interface.php @@ -0,0 +1,58 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP + * + * This content is released under the MIT License (MIT) + * + * Copyright (c) 2022, CodeIgniter Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2022, CodeIgniter Foundation (https://codeigniter.com/) + * @license http://opensource.org/licenses/MIT MIT License + * @link https://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * CI_Session_driver_interface + * + * A compatibility typeless SessionHandlerInterface alias + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author Andrey Andreev + * @link https://codeigniter.com/userguide3/libraries/sessions.html + */ +interface CI_Session_driver_interface { + + public function open($save_path, $name); + public function close(); + public function read($session_id); + public function write($session_id, $session_data); + public function destroy($session_id); + public function gc($maxlifetime); +} diff --git a/system/libraries/Session/OldSessionWrapper.php b/system/libraries/Session/OldSessionWrapper.php new file mode 100644 index 000000000..a8bc1d0c0 --- /dev/null +++ b/system/libraries/Session/OldSessionWrapper.php @@ -0,0 +1,88 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP + * + * This content is released under the MIT License (MIT) + * + * Copyright (c) 2022, CodeIgniter Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2022, CodeIgniter Foundation (https://codeigniter.com/) + * @license http://opensource.org/licenses/MIT MIT License + * @link https://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * OldSessionWrapper + * + * PHP 8 Session handler compatibility wrapper, pre-PHP8 version + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author Andrey Andreev + * @link https://codeigniter.com/userguide3/libraries/sessions.html + */ +class CI_SessionWrapper implements SessionHandlerInterface { + + protected $driver; + + public function __construct(CI_Session_driver_interface $driver) + { + $this->driver = $driver; + } + + public function open($save_path, $name) + { + return $this->driver->open($save_path, $name); + } + + public function close() + { + return $this->driver->close(); + } + + public function read($id) + { + return $this->driver->read($id); + } + + public function write($id, $data) + { + return $this->driver->write($id, $data); + } + + public function destroy($id) + { + return $this->driver->destroy($id); + } + + public function gc($maxlifetime) + { + return $this->driver->gc($maxlifetime); + } +} diff --git a/system/libraries/Session/PHP8SessionWrapper.php b/system/libraries/Session/PHP8SessionWrapper.php new file mode 100644 index 000000000..c6dfaf7e0 --- /dev/null +++ b/system/libraries/Session/PHP8SessionWrapper.php @@ -0,0 +1,90 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP + * + * This content is released under the MIT License (MIT) + * + * Copyright (c) 2022, CodeIgniter Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2022, CodeIgniter Foundation (https://codeigniter.com/) + * @license http://opensource.org/licenses/MIT MIT License + * @link https://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PHP8SessionWrapper + * + * PHP 8 Session handler compatibility wrapper + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author Andrey Andreev + * @link https://codeigniter.com/userguide3/libraries/sessions.html + */ +class CI_SessionWrapper implements SessionHandlerInterface { + + protected CI_Session_driver_interface $driver; + + public function __construct(CI_Session_driver_interface $driver) + { + $this->driver = $driver; + } + + public function open(string $save_path, string $name): bool + { + return $this->driver->open($save_path, $name); + } + + public function close(): bool + { + return $this->driver->close(); + } + + #[\ReturnTypeWillChange] + public function read(string $id): mixed + { + return $this->driver->read($id); + } + + public function write(string $id, string $data): bool + { + return $this->driver->write($id, $data); + } + + public function destroy(string $id): bool + { + return $this->driver->destroy($id); + } + + #[\ReturnTypeWillChange] + public function gc(int $maxlifetime): mixed + { + return $this->driver->gc($maxlifetime); + } +} diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 06b953ab2..8d3ba2857 100644 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2019, British Columbia Institute of Technology + * Copyright (c) 2019 - 2022, CodeIgniter Foundation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/) + * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/) * @license https://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 2.0.0 @@ -102,31 +103,24 @@ class CI_Session { $this->_configure($params); $this->_config['_sid_regexp'] = $this->_sid_regexp; - $class = new $class($this->_config); - if ($class instanceof SessionHandlerInterface) + $class = new $class($this->_config); + $wrapper = new CI_SessionWrapper($class); + if (is_php('5.4')) { - if (is_php('5.4')) - { - session_set_save_handler($class, TRUE); - } - else - { - session_set_save_handler( - array($class, 'open'), - array($class, 'close'), - array($class, 'read'), - array($class, 'write'), - array($class, 'destroy'), - array($class, 'gc') - ); - - register_shutdown_function('session_write_close'); - } + session_set_save_handler($wrapper, TRUE); } else { - log_message('error', "Session: Driver '".$this->_driver."' doesn't implement SessionHandlerInterface. Aborting."); - return; + session_set_save_handler( + array($wrapper, 'open'), + array($wrapper, 'close'), + array($wrapper, 'read'), + array($wrapper, 'write'), + array($wrapper, 'destroy'), + array($wrapper, 'gc') + ); + + register_shutdown_function('session_write_close'); } // Sanitize the cookie, because apparently PHP doesn't do that for userspace handlers @@ -160,15 +154,36 @@ class CI_Session { // unless it is being currently created or regenerated elseif (isset($_COOKIE[$this->_config['cookie_name']]) && $_COOKIE[$this->_config['cookie_name']] === session_id()) { - setcookie( - $this->_config['cookie_name'], - session_id(), - (empty($this->_config['cookie_lifetime']) ? 0 : time() + $this->_config['cookie_lifetime']), - $this->_config['cookie_path'], - $this->_config['cookie_domain'], - $this->_config['cookie_secure'], - TRUE - ); + $expires = empty($this->_config['cookie_lifetime']) ? 0 : time() + $this->_config['cookie_lifetime']; + if (is_php('7.3')) + { + setcookie( + $this->_config['cookie_name'], + session_id(), + array( + 'expires' => $expires, + 'path' => $this->_config['cookie_path'], + 'domain' => $this->_config['cookie_domain'], + 'secure' => $this->_config['cookie_secure'], + 'httponly' => TRUE, + 'samesite' => $this->_config['cookie_samesite'] + ) + ); + } + else + { + $header = 'Set-Cookie: '.$this->_config['cookie_name'].'='.session_id(); + $header .= empty($expires) ? '' : '; Expires='.gmdate('D, d-M-Y H:i:s T', $expires).'; Max-Age='.$this->_config['cookie_lifetime']; + $header .= '; Path='.$this->_config['cookie_path']; + $header .= ($this->_config['cookie_domain'] !== '' ? '; Domain='.$this->_config['cookie_domain'] : ''); + $header .= ($this->_config['cookie_secure'] ? '; Secure' : '').'; HttpOnly; SameSite='.$this->_config['cookie_samesite']; + header($header); + } + + if ( ! $this->_config['cookie_secure'] && $this->_config['cookie_samesite'] === 'None') + { + log_message('error', 'Session:', $this->_config['cookie_name'].' cookie sent with SameSite=None, but without Secure attribute.'); + } } $this->_ci_init_vars(); @@ -193,6 +208,10 @@ class CI_Session { // PHP 5.4 compatibility interface_exists('SessionHandlerInterface', FALSE) OR require_once(BASEPATH.'libraries/Session/SessionHandlerInterface.php'); + require_once(BASEPATH.'libraries/Session/CI_Session_driver_interface.php'); + $wrapper = is_php('8.0') ? 'PHP8SessionWrapper' : 'OldSessionWrapper'; + require_once(BASEPATH.'libraries/Session/'.$wrapper.'.php'); + $prefix = config_item('subclass_prefix'); if ( ! class_exists('CI_Session_driver', FALSE)) @@ -286,13 +305,43 @@ class CI_Session { isset($params['cookie_domain']) OR $params['cookie_domain'] = config_item('cookie_domain'); isset($params['cookie_secure']) OR $params['cookie_secure'] = (bool) config_item('cookie_secure'); - session_set_cookie_params( - $params['cookie_lifetime'], - $params['cookie_path'], - $params['cookie_domain'], - $params['cookie_secure'], - TRUE // HttpOnly; Yes, this is intentional and not configurable for security reasons - ); + isset($params['cookie_samesite']) OR $params['cookie_samesite'] = config_item('sess_samesite'); + if ( ! isset($params['cookie_samesite']) && is_php('7.3')) + { + $params['cookie_samesite'] = ini_get('session.cookie_samesite'); + } + + if (isset($params['cookie_samesite'])) + { + $params['cookie_samesite'] = ucfirst(strtolower($params['cookie_samesite'])); + in_array($params['cookie_samesite'], array('Lax', 'Strict', 'None'), TRUE) OR $params['cookie_samesite'] = 'Lax'; + } + else + { + $params['cookie_samesite'] = 'Lax'; + } + + if (is_php('7.3')) + { + session_set_cookie_params(array( + 'lifetime' => $params['cookie_lifetime'], + 'path' => $params['cookie_path'], + 'domain' => $params['cookie_domain'], + 'secure' => $params['cookie_secure'], + 'httponly' => TRUE, + 'samesite' => $params['cookie_samesite'] + )); + } + else + { + session_set_cookie_params( + $params['cookie_lifetime'], + $params['cookie_path'].'; SameSite='.$params['cookie_samesite'], + $params['cookie_domain'], + $params['cookie_secure'], + TRUE // HttpOnly; Yes, this is intentional and not configurable for security reasons + ); + } if (empty($expiration)) { @@ -723,7 +772,7 @@ class CI_Session { * * Legacy CI_Session compatibility method * - * @returns array + * @return array */ public function &get_userdata() { diff --git a/system/libraries/Session/SessionHandlerInterface.php b/system/libraries/Session/SessionHandlerInterface.php index 95d2488b4..914eae03f 100644 --- a/system/libraries/Session/SessionHandlerInterface.php +++ b/system/libraries/Session/SessionHandlerInterface.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2019, British Columbia Institute of Technology + * Copyright (c) 2019 - 2022, CodeIgniter Foundation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (http://bcit.ca/) + * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (http://codeigniter.com/) * @license http://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 3.0.0 diff --git a/system/libraries/Session/Session_driver.php b/system/libraries/Session/Session_driver.php index 734b6e052..b1b1b073e 100644 --- a/system/libraries/Session/Session_driver.php +++ b/system/libraries/Session/Session_driver.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2019, British Columbia Institute of Technology + * Copyright (c) 2019 - 2022, CodeIgniter Foundation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/) + * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/) * @license https://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 3.0.0 @@ -46,7 +47,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @author Andrey Andreev * @link https://codeigniter.com/userguide3/libraries/sessions.html */ -abstract class CI_Session_driver implements SessionHandlerInterface { +abstract class CI_Session_driver { protected $_config; @@ -139,14 +140,28 @@ abstract class CI_Session_driver implements SessionHandlerInterface { */ protected function _cookie_destroy() { + if ( ! is_php('7.3')) + { + $header = 'Set-Cookie: '.$this->_config['cookie_name'].'='; + $header .= '; Expires='.gmdate('D, d-M-Y H:i:s T', 1).'; Max-Age=-1'; + $header .= '; Path='.$this->_config['cookie_path']; + $header .= ($this->_config['cookie_domain'] !== '' ? '; Domain='.$this->_config['cookie_domain'] : ''); + $header .= ($this->_config['cookie_secure'] ? '; Secure' : '').'; HttpOnly; SameSite='.$this->_config['cookie_samesite']; + header($header); + return; + } + return setcookie( $this->_config['cookie_name'], NULL, - 1, - $this->_config['cookie_path'], - $this->_config['cookie_domain'], - $this->_config['cookie_secure'], - TRUE + array( + 'expires' => 1, + 'path' => $this->_config['cookie_path'], + 'domain' => $this->_config['cookie_domain'], + 'secure' => $this->_config['cookie_secure'], + 'httponly' => TRUE, + 'samesite' => $this->_config['cookie_samesite'] + ) ); } diff --git a/system/libraries/Session/drivers/Session_database_driver.php b/system/libraries/Session/drivers/Session_database_driver.php index a3055af5e..2f788a1a1 100644 --- a/system/libraries/Session/drivers/Session_database_driver.php +++ b/system/libraries/Session/drivers/Session_database_driver.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2019, British Columbia Institute of Technology + * Copyright (c) 2019 - 2022, CodeIgniter Foundation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/) + * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/) * @license https://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 3.0.0 @@ -46,7 +47,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @author Andrey Andreev * @link https://codeigniter.com/userguide3/libraries/sessions.html */ -class CI_Session_database_driver extends CI_Session_driver implements SessionHandlerInterface { +class CI_Session_database_driver extends CI_Session_driver implements CI_Session_driver_interface { /** * DB object diff --git a/system/libraries/Session/drivers/Session_files_driver.php b/system/libraries/Session/drivers/Session_files_driver.php index 49bf5b781..4b7b9878b 100644 --- a/system/libraries/Session/drivers/Session_files_driver.php +++ b/system/libraries/Session/drivers/Session_files_driver.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2019, British Columbia Institute of Technology + * Copyright (c) 2019 - 2022, CodeIgniter Foundation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/) + * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/) * @license https://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 3.0.0 @@ -46,7 +47,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @author Andrey Andreev * @link https://codeigniter.com/userguide3/libraries/sessions.html */ -class CI_Session_files_driver extends CI_Session_driver implements SessionHandlerInterface { +class CI_Session_files_driver extends CI_Session_driver implements CI_Session_driver_interface { /** * Save path @@ -115,7 +116,7 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle $this->_sid_regexp = $this->_config['_sid_regexp']; - isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); + isset(self::$func_overload) OR self::$func_overload = ( ! is_php('8.0') && extension_loaded('mbstring') && @ini_get('mbstring.func_overload')); } // ------------------------------------------------------------------------ diff --git a/system/libraries/Session/drivers/Session_memcached_driver.php b/system/libraries/Session/drivers/Session_memcached_driver.php index b4d3eb464..d84a9df1d 100644 --- a/system/libraries/Session/drivers/Session_memcached_driver.php +++ b/system/libraries/Session/drivers/Session_memcached_driver.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2019, British Columbia Institute of Technology + * Copyright (c) 2019 - 2022, CodeIgniter Foundation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/) + * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/) * @license https://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 3.0.0 @@ -46,7 +47,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @author Andrey Andreev * @link https://codeigniter.com/userguide3/libraries/sessions.html */ -class CI_Session_memcached_driver extends CI_Session_driver implements SessionHandlerInterface { +class CI_Session_memcached_driver extends CI_Session_driver implements CI_Session_driver_interface { /** * Memcached instance diff --git a/system/libraries/Session/drivers/Session_redis_driver.php b/system/libraries/Session/drivers/Session_redis_driver.php index d65c6ee14..b112a18c8 100644 --- a/system/libraries/Session/drivers/Session_redis_driver.php +++ b/system/libraries/Session/drivers/Session_redis_driver.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2019, British Columbia Institute of Technology + * Copyright (c) 2019 - 2022, CodeIgniter Foundation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/) + * @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/) * @license https://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 3.0.0 @@ -46,7 +47,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @author Andrey Andreev * @link https://codeigniter.com/userguide3/libraries/sessions.html */ -class CI_Session_redis_driver extends CI_Session_driver implements SessionHandlerInterface { +class CI_Session_redis_driver extends CI_Session_driver implements CI_Session_driver_interface { /** * phpRedis instance diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index ae60f35af..e754205de 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -1227,7 +1227,7 @@ class CI_Upload { if (function_exists('finfo_file')) { $finfo = @finfo_open(FILEINFO_MIME); - if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system + if ($finfo !== FALSE) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system { $mime = @finfo_file($finfo, $file['tmp_name']); finfo_close($finfo); diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php index a42975b35..c144db7a8 100644 --- a/system/libraries/User_agent.php +++ b/system/libraries/User_agent.php @@ -498,7 +498,7 @@ class CI_User_agent { else { $referer_host = @parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); - $own_host = parse_url(config_item('base_url'), PHP_URL_HOST); + $own_host = parse_url((string) config_item('base_url'), PHP_URL_HOST); $this->referer = ($referer_host && $referer_host !== $own_host); } diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index 32b236b43..d500bcf87 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -1914,7 +1914,7 @@ class XML_RPC_Values extends CI_Xmlrpc */ public function iso8601_encode($time, $utc = FALSE) { - return ($utc) ? strftime('%Y%m%dT%H:%i:%s', $time) : gmstrftime('%Y%m%dT%H:%i:%s', $time); + return ($utc) ? date('Ymd\TH:i:s', $time) : gmdate('Ymd\TH:i:s', $time); } } // END XML_RPC_Values Class diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php index e99873ae7..44586697a 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -119,7 +119,7 @@ class CI_Zip { */ public function __construct() { - isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); + isset(self::$func_overload) OR self::$func_overload = ( ! is_php('8.0') && extension_loaded('mbstring') && @ini_get('mbstring.func_overload')); $this->now = time(); log_message('info', 'Zip Compression Class Initialized'); |