diff options
Diffstat (limited to 'system/libraries/Session/drivers')
5 files changed, 147 insertions, 94 deletions
diff --git a/system/libraries/Session/drivers/Session_database_driver.php b/system/libraries/Session/drivers/Session_database_driver.php index 734fe624f..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 @@ -44,9 +45,9 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @subpackage Libraries * @category Sessions * @author Andrey Andreev - * @link https://codeigniter.com/user_guide/libraries/sessions.html + * @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 @@ -130,7 +131,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan { if (empty($this->_db->conn_id) && ! $this->_db->db_connect()) { - return $this->_fail(); + return $this->_failure; } $this->php5_validate_id(); @@ -150,48 +151,47 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan */ public function read($session_id) { - if ($this->_get_lock($session_id) !== FALSE) + if ($this->_get_lock($session_id) === FALSE) { - // Prevent previous QB calls from messing with our queries - $this->_db->reset_query(); - - // Needed by write() to detect session_regenerate_id() calls - $this->_session_id = $session_id; + return $this->_failure; + } - $this->_db - ->select('data') - ->from($this->_config['save_path']) - ->where('id', $session_id); + // Prevent previous QB calls from messing with our queries + $this->_db->reset_query(); - if ($this->_config['match_ip']) - { - $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']); - } + // Needed by write() to detect session_regenerate_id() calls + $this->_session_id = $session_id; - if ( ! ($result = $this->_db->get()) OR ($result = $result->row()) === NULL) - { - // PHP7 will reuse the same SessionHandler object after - // ID regeneration, so we need to explicitly set this to - // FALSE instead of relying on the default ... - $this->_row_exists = FALSE; - $this->_fingerprint = md5(''); - return ''; - } + $this->_db + ->select('data') + ->from($this->_config['save_path']) + ->where('id', $session_id); - // PostgreSQL's variant of a BLOB datatype is Bytea, which is a - // PITA to work with, so we use base64-encoded data in a TEXT - // field instead. - $result = ($this->_platform === 'postgre') - ? base64_decode(rtrim($result->data)) - : $result->data; + if ($this->_config['match_ip']) + { + $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']); + } - $this->_fingerprint = md5($result); - $this->_row_exists = TRUE; - return $result; + if ( ! ($result = $this->_db->get()) OR ($result = $result->row()) === NULL) + { + // PHP7 will reuse the same SessionHandler object after + // ID regeneration, so we need to explicitly set this to + // FALSE instead of relying on the default ... + $this->_row_exists = FALSE; + $this->_fingerprint = md5(''); + return ''; } - $this->_fingerprint = md5(''); - return ''; + // PostgreSQL's variant of a BLOB datatype is Bytea, which is a + // PITA to work with, so we use base64-encoded data in a TEXT + // field instead. + $result = ($this->_platform === 'postgre') + ? base64_decode(rtrim($result->data)) + : $result->data; + + $this->_fingerprint = md5($result); + $this->_row_exists = TRUE; + return $result; } // ------------------------------------------------------------------------ @@ -215,7 +215,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan { if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id)) { - return $this->_fail(); + return $this->_failure; } $this->_row_exists = FALSE; @@ -223,7 +223,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan } elseif ($this->_lock === FALSE) { - return $this->_fail(); + return $this->_failure; } if ($this->_row_exists === FALSE) @@ -242,7 +242,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan return $this->_success; } - return $this->_fail(); + return $this->_failure; } $this->_db->where('id', $session_id); @@ -265,7 +265,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan return $this->_success; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -280,7 +280,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan public function close() { return ($this->_lock && ! $this->_release_lock()) - ? $this->_fail() + ? $this->_failure : $this->_success; } @@ -309,7 +309,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan if ( ! $this->_db->delete($this->_config['save_path'])) { - return $this->_fail(); + return $this->_failure; } } @@ -319,7 +319,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan return $this->_success; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -339,7 +339,7 @@ class CI_Session_database_driver extends CI_Session_driver implements SessionHan return ($this->_db->delete($this->_config['save_path'], 'timestamp < '.(time() - $maxlifetime))) ? $this->_success - : $this->_fail(); + : $this->_failure; } // -------------------------------------------------------------------- diff --git a/system/libraries/Session/drivers/Session_files_driver.php b/system/libraries/Session/drivers/Session_files_driver.php index 467059434..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 @@ -44,9 +45,9 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @subpackage Libraries * @category Sessions * @author Andrey Andreev - * @link https://codeigniter.com/user_guide/libraries/sessions.html + * @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')); } // ------------------------------------------------------------------------ @@ -135,12 +136,14 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle { if ( ! mkdir($save_path, 0700, TRUE)) { - throw new Exception("Session: Configured save path '".$this->_config['save_path']."' is not a directory, doesn't exist or cannot be created."); + log_message('error', "Session: Configured save path '".$this->_config['save_path']."' is not a directory, doesn't exist or cannot be created."); + return $this->_failure; } } elseif ( ! is_writable($save_path)) { - throw new Exception("Session: Configured save path '".$this->_config['save_path']."' is not writable by the PHP process."); + log_message('error', "Session: Configured save path '".$this->_config['save_path']."' is not writable by the PHP process."); + return $this->_failure; } $this->_config['save_path'] = $save_path; @@ -194,6 +197,10 @@ class CI_Session_files_driver extends CI_Session_driver implements SessionHandle $this->_fingerprint = md5(''); return ''; } + + // Prevent possible data corruption + // See https://github.com/bcit-ci/CodeIgniter/issues/5857 + clearstatcache(TRUE, $this->_file_path.$session_id); } // We shouldn't need this, but apparently we do ... // See https://github.com/bcit-ci/CodeIgniter/issues/4039 diff --git a/system/libraries/Session/drivers/Session_memcached_driver.php b/system/libraries/Session/drivers/Session_memcached_driver.php index ab54f029f..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 @@ -44,9 +45,9 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @subpackage Libraries * @category Sessions * @author Andrey Andreev - * @link https://codeigniter.com/user_guide/libraries/sessions.html + * @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 @@ -117,7 +118,7 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa { $this->_memcached = NULL; log_message('error', 'Session: Invalid Memcached save path format: '.$this->_config['save_path']); - return $this->_fail(); + return $this->_failure; } foreach ($matches as $match) @@ -142,7 +143,7 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa if (empty($server_list)) { log_message('error', 'Session: Memcached server pool is empty.'); - return $this->_fail(); + return $this->_failure; } $this->php5_validate_id(); @@ -172,7 +173,7 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa return $session_data; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -190,14 +191,14 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa { if ( ! isset($this->_memcached, $this->_lock_key)) { - return $this->_fail(); + return $this->_failure; } // Was the ID regenerated? elseif ($session_id !== $this->_session_id) { if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id)) { - return $this->_fail(); + return $this->_failure; } $this->_fingerprint = md5(''); @@ -215,7 +216,7 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa return $this->_success; } - return $this->_fail(); + return $this->_failure; } elseif ( $this->_memcached->touch($key, $this->_config['expiration']) @@ -225,7 +226,7 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa return $this->_success; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -244,14 +245,14 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa $this->_release_lock(); if ( ! $this->_memcached->quit()) { - return $this->_fail(); + return $this->_failure; } $this->_memcached = NULL; return $this->_success; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -273,7 +274,7 @@ class CI_Session_memcached_driver extends CI_Session_driver implements SessionHa return $this->_success; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ diff --git a/system/libraries/Session/drivers/Session_redis_driver.php b/system/libraries/Session/drivers/Session_redis_driver.php index 07511e555..fae024bee 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 @@ -44,9 +45,9 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @subpackage Libraries * @category Sessions * @author Andrey Andreev - * @link https://codeigniter.com/user_guide/libraries/sessions.html + * @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 @@ -76,6 +77,33 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle */ protected $_key_exists = FALSE; + /** + * Name of setTimeout() method in phpRedis + * + * Due to some deprecated methods in phpRedis, we need to call the + * specific methods depending on the version of phpRedis. + * + * @var string + */ + protected $_setTimeout_name; + + /** + * Name of delete() method in phpRedis + * + * Due to some deprecated methods in phpRedis, we need to call the + * specific methods depending on the version of phpRedis. + * + * @var string + */ + protected $_delete_name; + + /** + * Success return value of ping() method in phpRedis + * + * @var mixed + */ + protected $_ping_success; + // ------------------------------------------------------------------------ /** @@ -88,6 +116,20 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle { parent::__construct($params); + // Detect the names of some methods in phpRedis instance + if (version_compare(phpversion('redis'), '5', '>=')) + { + $this->_setTimeout_name = 'expire'; + $this->_delete_name = 'del'; + $this->_ping_success = TRUE; + } + else + { + $this->_setTimeout_name = 'setTimeout'; + $this->_delete_name = 'delete'; + $this->_ping_success = '+PONG'; + } + if (empty($this->_config['save_path'])) { log_message('error', 'Session: No Redis save path configured.'); @@ -96,7 +138,7 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle { $save_path = array('path' => $matches[1]); } - elseif (preg_match('#(?:tcp://)?([^:?]+)(?:\:(\d+))?(?<options>\?.+)?#', $this->_config['save_path'], $matches)) + elseif (preg_match('#(?:(?:tcp|tls)://)?([^:?]+)(?:\:(\d+))?(?<options>\?.+)?#', $this->_config['save_path'], $matches)) { $save_path = array( 'host' => $matches[1], @@ -144,7 +186,7 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle { if (empty($this->_config['save_path'])) { - return $this->_fail(); + return $this->_failure; } $redis = new Redis(); @@ -169,17 +211,18 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle else { $this->_redis = $redis; + $this->php5_validate_id(); return $this->_success; } } else { - log_message('error', 'Session: Unable to connect to Redis with the configured settings.'); + $this->_redis = $redis; + $this->php5_validate_id(); + return $this->_success; } - $this->php5_validate_id(); - - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -209,7 +252,7 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle return $session_data; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -227,21 +270,21 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle { if ( ! isset($this->_redis, $this->_lock_key)) { - return $this->_fail(); + return $this->_failure; } // Was the ID regenerated? elseif ($session_id !== $this->_session_id) { if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id)) { - return $this->_fail(); + return $this->_failure; } $this->_key_exists = FALSE; $this->_session_id = $session_id; } - $this->_redis->setTimeout($this->_lock_key, 300); + $this->_redis->{$this->_setTimeout_name}($this->_lock_key, 300); if ($this->_fingerprint !== ($fingerprint = md5($session_data)) OR $this->_key_exists === FALSE) { if ($this->_redis->set($this->_key_prefix.$session_id, $session_data, $this->_config['expiration'])) @@ -251,12 +294,12 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle return $this->_success; } - return $this->_fail(); + return $this->_failure; } - return ($this->_redis->setTimeout($this->_key_prefix.$session_id, $this->_config['expiration'])) + return ($this->_redis->{$this->_setTimeout_name}($this->_key_prefix.$session_id, $this->_config['expiration'])) ? $this->_success - : $this->_fail(); + : $this->_failure; } // ------------------------------------------------------------------------ @@ -273,12 +316,12 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle if (isset($this->_redis)) { try { - if ($this->_redis->ping() === '+PONG') + if ($this->_redis->ping() === $this->_ping_success) { $this->_release_lock(); if ($this->_redis->close() === FALSE) { - return $this->_fail(); + return $this->_failure; } } } @@ -308,16 +351,16 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle { if (isset($this->_redis, $this->_lock_key)) { - if (($result = $this->_redis->delete($this->_key_prefix.$session_id)) !== 1) + if (($result = $this->_redis->{$this->_delete_name}($this->_key_prefix.$session_id)) !== 1) { - log_message('debug', 'Session: Redis::delete() expected to return 1, got '.var_export($result, TRUE).' instead.'); + log_message('debug', 'Session: Redis::'.$this->_delete_name.'() expected to return 1, got '.var_export($result, TRUE).' instead.'); } $this->_cookie_destroy(); return $this->_success; } - return $this->_fail(); + return $this->_failure; } // ------------------------------------------------------------------------ @@ -369,7 +412,7 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle // correct session ID. if ($this->_lock_key === $this->_key_prefix.$session_id.':lock') { - return $this->_redis->setTimeout($this->_lock_key, 300); + return $this->_redis->{$this->_setTimeout_name}($this->_lock_key, 300); } // 30 attempts to obtain a lock, in case another request already has it @@ -383,11 +426,13 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle continue; } - $result = ($ttl === -2) - ? $this->_redis->set($lock_key, time(), array('nx', 'ex' => 300)) - : $this->_redis->setex($lock_key, 300, time()); - - if ( ! $result) + if ($ttl === -2 && ! $this->_redis->set($lock_key, time(), array('nx', 'ex' => 300))) + { + // Sleep for 1s to wait for lock releases. + sleep(1); + continue; + } + elseif ( ! $this->_redis->setex($lock_key, 300, time())) { log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id); return FALSE; @@ -425,7 +470,7 @@ class CI_Session_redis_driver extends CI_Session_driver implements SessionHandle { if (isset($this->_redis, $this->_lock_key) && $this->_lock) { - if ( ! $this->_redis->delete($this->_lock_key)) + if ( ! $this->_redis->{$this->_delete_name}($this->_lock_key)) { log_message('error', 'Session: Error while trying to free lock for '.$this->_lock_key); return FALSE; diff --git a/system/libraries/Session/drivers/index.html b/system/libraries/Session/drivers/index.html index b702fbc39..bcb7cae34 100644 --- a/system/libraries/Session/drivers/index.html +++ b/system/libraries/Session/drivers/index.html @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html> +<html lang="en"> <head> <title>403 Forbidden</title> </head> |