| <?php |
| /** |
| * CodeIgniter |
| * |
| * An open source application development framework for PHP |
| * |
| * This content is released under the MIT License (MIT) |
| * |
| * Copyright (c) 2014 - 2015, British Columbia Institute of Technology |
| * |
| * 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) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/) |
| * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/) |
| * @license http://opensource.org/licenses/MIT MIT License |
| * @link http://codeigniter.com |
| * @since Version 2.0.0 |
| * @filesource |
| */ |
| defined('BASEPATH') OR exit('No direct script access allowed'); |
| |
| /** |
| * CodeIgniter Session Class |
| * |
| * The user interface defined by EllisLab, now with puggable drivers to manage different storage mechanisms. |
| * By default, the cookie session driver will load, but the 'sess_driver' config/param item (see above) can be |
| * used to specify the 'native' driver, or any other you might create. |
| * Once loaded, this driver setup is a drop-in replacement for the former CI_Session library, taking its place as the |
| * 'session' member of the global controller framework (e.g.: $CI->session or $this->session). |
| * In keeping with the CI_Driver methodology, multiple drivers may be loaded, although this might be a bit confusing. |
| * The CI_Session library class keeps track of the most recently loaded driver as "current" to call for driver methods. |
| * Ideally, one driver is loaded and all calls go directly through the main library interface. However, any methods |
| * called through the specific driver will switch the "current" driver to itself before invoking the library method |
| * (which will then call back into the driver for low-level operations). So, alternation between two drivers can be |
| * achieved by specifying which driver to use for each call (e.g.: $this->session->native->set_userdata('foo', 'bar'); |
| * $this->session->cookie->userdata('foo'); $this->session->native->unset_userdata('foo');). Notice in the previous |
| * example that the _native_ userdata value 'foo' would be set to 'bar', which would NOT be returned by the call for |
| * the _cookie_ userdata 'foo', nor would the _cookie_ value be unset by the call to unset the _native_ 'foo' value. |
| * |
| * @package CodeIgniter |
| * @subpackage Libraries |
| * @category Sessions |
| * @author EllisLab Dev Team |
| * @link http://codeigniter.com/user_guide/libraries/sessions.html |
| */ |
| class CI_Session extends CI_Driver_Library { |
| |
| /** |
| * Initialization parameters |
| * |
| * @var array |
| */ |
| public $params = array(); |
| |
| /** |
| * Valid drivers list |
| * |
| * @var array |
| */ |
| public $valid_drivers = array('native', 'cookie'); |
| |
| /** |
| * Current driver in use |
| * |
| * @var string |
| */ |
| public $current = NULL; |
| |
| /** |
| * User data |
| * |
| * @var array |
| */ |
| protected $userdata = array(); |
| |
| // ------------------------------------------------------------------------ |
| |
| const FLASHDATA_KEY = 'flash'; |
| const FLASHDATA_NEW = ':new:'; |
| const FLASHDATA_OLD = ':old:'; |
| const FLASHDATA_EXP = ':exp:'; |
| const EXPIRATION_KEY = '__expirations'; |
| const TEMP_EXP_DEF = 300; |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * CI_Session constructor |
| * |
| * The constructor loads the configured driver ('sess_driver' in config.php or as a parameter), running |
| * routines in its constructor, and manages flashdata aging. |
| * |
| * @param array Configuration parameters |
| * @return void |
| */ |
| public function __construct(array $params = array()) |
| { |
| $_config =& get_instance()->config; |
| |
| // No sessions under CLI |
| if (is_cli()) |
| { |
| return; |
| } |
| |
| log_message('debug', 'CI_Session Class Initialized'); |
| |
| // Add possible extra entries to our valid drivers list |
| $drivers = isset($params['sess_valid_drivers']) ? $params['sess_valid_drivers'] : $_config->item('sess_valid_drivers'); |
| if ( ! empty($drivers)) |
| { |
| $drivers = array_map('strtolower', (array) $drivers); |
| $this->valid_drivers = array_merge($this->valid_drivers, array_diff($drivers, $this->valid_drivers)); |
| } |
| |
| // Get driver to load |
| $driver = isset($params['sess_driver']) ? $params['sess_driver'] : $_config->item('sess_driver'); |
| if ( ! $driver) |
| { |
| log_message('debug', "Session: No driver name is configured, defaulting to 'cookie'."); |
| $driver = 'cookie'; |
| } |
| |
| if ( ! in_array($driver, $this->valid_drivers)) |
| { |
| log_message('error', 'Session: Configured driver name is not valid, aborting.'); |
| return; |
| } |
| |
| // Save a copy of parameters in case drivers need access |
| $this->params = $params; |
| |
| // Load driver and get array reference |
| $this->load_driver($driver); |
| |
| // Delete 'old' flashdata (from last request) |
| $this->_flashdata_sweep(); |
| |
| // Mark all new flashdata as old (data will be deleted before next request) |
| $this->_flashdata_mark(); |
| |
| // Delete expired tempdata |
| $this->_tempdata_sweep(); |
| |
| log_message('debug', 'CI_Session routines successfully run'); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Loads session storage driver |
| * |
| * @param string Driver classname |
| * @return object Loaded driver object |
| */ |
| public function load_driver($driver) |
| { |
| // Save reference to most recently loaded driver as library default and sync userdata |
| $this->current = parent::load_driver($driver); |
| $this->userdata =& $this->current->get_userdata(); |
| return $this->current; |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Select default session storage driver |
| * |
| * @param string Driver name |
| * @return void |
| */ |
| public function select_driver($driver) |
| { |
| // Validate driver name |
| $prefix = (string) get_instance()->config->item('subclass_prefix'); |
| $child = strtolower(str_replace(array('CI_', $prefix, $this->lib_name.'_'), '', $driver)); |
| if (in_array($child, array_map('strtolower', $this->valid_drivers))) |
| { |
| // See if driver is loaded |
| if (isset($this->$child)) |
| { |
| // See if driver is already current |
| if ($this->$child !== $this->current) |
| { |
| // Make driver current and sync userdata |
| $this->current = $this->$child; |
| $this->userdata =& $this->current->get_userdata(); |
| } |
| } |
| else |
| { |
| // Load new driver |
| $this->load_driver($child); |
| } |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Destroy the current session |
| * |
| * @return void |
| */ |
| public function sess_destroy() |
| { |
| // Just call destroy on driver |
| $this->current->sess_destroy(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Regenerate the current session |
| * |
| * @param bool Destroy session data flag (default: false) |
| * @return void |
| */ |
| public function sess_regenerate($destroy = FALSE) |
| { |
| // Call regenerate on driver and resync userdata |
| $this->current->sess_regenerate($destroy); |
| $this->userdata =& $this->current->get_userdata(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Fetch a specific item from the session array |
| * |
| * @param string Item key |
| * @return string Item value or NULL if not found |
| */ |
| public function userdata($item = NULL) |
| { |
| if (isset($item)) |
| { |
| return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL; |
| } |
| |
| return isset($this->userdata) ? $this->userdata : array(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Fetch all session data |
| * |
| * @deprecated 3.0.0 Use userdata() with no parameters instead |
| * @return array User data array |
| */ |
| public function all_userdata() |
| { |
| return isset($this->userdata) ? $this->userdata : array(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Add or change data in the "userdata" array |
| * |
| * @param mixed Item name or array of items |
| * @param string Item value or empty string |
| * @return void |
| */ |
| public function set_userdata($newdata, $newval = '') |
| { |
| // Wrap params as array if singular |
| if (is_string($newdata)) |
| { |
| $newdata = array($newdata => $newval); |
| } |
| |
| // Set each name/value pair |
| if (count($newdata) > 0) |
| { |
| foreach ($newdata as $key => $val) |
| { |
| $this->userdata[$key] = $val; |
| } |
| } |
| |
| // Tell driver data changed |
| $this->current->sess_save(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Delete a session variable from the "userdata" array |
| * |
| * @param mixed Item name or array of item names |
| * @return void |
| */ |
| public function unset_userdata($newdata) |
| { |
| // Wrap single name as array |
| if (is_string($newdata)) |
| { |
| $newdata = array($newdata => ''); |
| } |
| |
| // Unset each item name |
| if (count($newdata) > 0) |
| { |
| foreach (array_keys($newdata) as $key) |
| { |
| unset($this->userdata[$key]); |
| } |
| } |
| |
| // Tell driver data changed |
| $this->current->sess_save(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Determine if an item exists |
| * |
| * @param string Item name |
| * @return bool |
| */ |
| public function has_userdata($item) |
| { |
| return isset($this->userdata[$item]); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Add or change flashdata, only available until the next request |
| * |
| * @param mixed Item name or array of items |
| * @param string Item value or empty string |
| * @return void |
| */ |
| public function set_flashdata($newdata, $newval = '') |
| { |
| // Wrap item as array if singular |
| if (is_string($newdata)) |
| { |
| $newdata = array($newdata => $newval); |
| } |
| |
| // Prepend each key name and set value |
| if (count($newdata) > 0) |
| { |
| foreach ($newdata as $key => $val) |
| { |
| $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key; |
| $this->set_userdata($flashdata_key, $val); |
| } |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Keeps existing flashdata available to next request. |
| * |
| * @param mixed Item key(s) |
| * @return void |
| */ |
| public function keep_flashdata($key) |
| { |
| |
| if (is_array($key)) |
| { |
| foreach ($key as $k) |
| { |
| $this->keep_flashdata($k); |
| } |
| |
| return; |
| } |
| |
| // 'old' flashdata gets removed. Here we mark all flashdata as 'new' to preserve it from _flashdata_sweep() |
| // Note the function will return NULL if the $key provided cannot be found |
| $old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; |
| $value = $this->userdata($old_flashdata_key); |
| |
| $new_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key; |
| $this->set_userdata($new_flashdata_key, $value); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Fetch a specific flashdata item from the session array |
| * |
| * @param string Item key |
| * @return string |
| */ |
| public function flashdata($key = NULL) |
| { |
| if (isset($key)) |
| { |
| return $this->userdata(self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key); |
| } |
| |
| // Get our flashdata items from userdata |
| $out = array(); |
| foreach ($this->userdata() as $key => $val) |
| { |
| if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE) |
| { |
| $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key); |
| $out[$key] = $val; |
| } |
| } |
| |
| return $out; |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Add or change tempdata, only available until expiration |
| * |
| * @param mixed Item name or array of items |
| * @param string Item value or empty string |
| * @param int Item lifetime in seconds or 0 for default |
| * @return void |
| */ |
| public function set_tempdata($newdata, $newval = '', $expire = 0) |
| { |
| // Set expiration time |
| $expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF); |
| |
| // Wrap item as array if singular |
| if (is_string($newdata)) |
| { |
| $newdata = array($newdata => $newval); |
| } |
| |
| // Get or create expiration list |
| $expirations = $this->userdata(self::EXPIRATION_KEY); |
| if ( ! $expirations) |
| { |
| $expirations = array(); |
| } |
| |
| // Prepend each key name and set value |
| if (count($newdata) > 0) |
| { |
| foreach ($newdata as $key => $val) |
| { |
| $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; |
| $expirations[$tempdata_key] = $expire; |
| $this->set_userdata($tempdata_key, $val); |
| } |
| } |
| |
| // Update expiration list |
| $this->set_userdata(self::EXPIRATION_KEY, $expirations); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Delete a temporary session variable from the "userdata" array |
| * |
| * @param mixed Item name or array of item names |
| * @return void |
| */ |
| public function unset_tempdata($newdata) |
| { |
| // Get expirations list |
| $expirations = $this->userdata(self::EXPIRATION_KEY); |
| if (empty($expirations)) |
| { |
| // Nothing to do |
| return; |
| } |
| |
| // Wrap single name as array |
| if (is_string($newdata)) |
| { |
| $newdata = array($newdata => ''); |
| } |
| |
| // Prepend each item name and unset |
| if (count($newdata) > 0) |
| { |
| foreach (array_keys($newdata) as $key) |
| { |
| $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; |
| unset($expirations[$tempdata_key]); |
| $this->unset_userdata($tempdata_key); |
| } |
| } |
| |
| // Update expiration list |
| $this->set_userdata(self::EXPIRATION_KEY, $expirations); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Fetch a specific tempdata item from the session array |
| * |
| * @param string Item key |
| * @return string |
| */ |
| public function tempdata($key = NULL) |
| { |
| if (isset($key)) |
| { |
| return $this->userdata(self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key); |
| } |
| |
| // Get our tempdata items from userdata |
| $out = array(); |
| foreach ($this->userdata() as $key => $val) |
| { |
| if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_EXP) !== FALSE) |
| { |
| $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_EXP, '', $key); |
| $out[$key] = $val; |
| } |
| } |
| |
| return $out; |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Identifies flashdata as 'old' for removal |
| * when _flashdata_sweep() runs. |
| * |
| * @return void |
| */ |
| protected function _flashdata_mark() |
| { |
| foreach ($this->userdata() as $name => $value) |
| { |
| $parts = explode(self::FLASHDATA_NEW, $name); |
| if (count($parts) === 2) |
| { |
| $this->set_userdata(self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1], $value); |
| $this->unset_userdata($name); |
| } |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Removes all flashdata marked as 'old' |
| * |
| * @return void |
| */ |
| protected function _flashdata_sweep() |
| { |
| $userdata = $this->userdata(); |
| foreach (array_keys($userdata) as $key) |
| { |
| if (strpos($key, self::FLASHDATA_OLD)) |
| { |
| $this->unset_userdata($key); |
| } |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Removes all expired tempdata |
| * |
| * @return void |
| */ |
| protected function _tempdata_sweep() |
| { |
| // Get expirations list |
| $expirations = $this->userdata(self::EXPIRATION_KEY); |
| if (empty($expirations)) |
| { |
| // Nothing to do |
| return; |
| } |
| |
| // Unset expired elements |
| $now = time(); |
| $userdata = $this->userdata(); |
| foreach (array_keys($userdata) as $key) |
| { |
| if (strpos($key, self::FLASHDATA_EXP) && $expirations[$key] < $now) |
| { |
| unset($expirations[$key]); |
| $this->unset_userdata($key); |
| } |
| } |
| |
| // Update expiration list |
| $this->set_userdata(self::EXPIRATION_KEY, $expirations); |
| } |
| |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * CI_Session_driver Class |
| * |
| * Extend this class to make a new CI_Session driver. |
| * A CI_Session driver basically manages an array of name/value pairs with some sort of storage mechanism. |
| * To make a new driver, derive from (extend) CI_Session_driver. Overload the initialize method and read or create |
| * session data. Then implement a save handler to write changed data to storage (sess_save), a destroy handler |
| * to remove deleted data (sess_destroy), and an access handler to expose the data (get_userdata). |
| * Put your driver in the libraries/Session/drivers folder anywhere in the loader paths. This includes the |
| * application directory, the system directory, or any path you add with $CI->load->add_package_path(). |
| * Your driver must be named CI_Session_<name>, and your filename must be Session_<name>.php, |
| * preferably also capitalized. (e.g.: CI_Session_foo in libraries/Session/drivers/Session_foo.php) |
| * Then specify the driver by setting 'sess_driver' in your config file or as a parameter when loading the CI_Session |
| * object. (e.g.: $config['sess_driver'] = 'foo'; OR $CI->load->driver('session', array('sess_driver' => 'foo')); ) |
| * Already provided are the Native driver, which manages the native PHP $_SESSION array, and |
| * the Cookie driver, which manages the data in a browser cookie, with optional extra storage in a database table. |
| * |
| * @package CodeIgniter |
| * @subpackage Libraries |
| * @category Sessions |
| * @author EllisLab Dev Team |
| */ |
| abstract class CI_Session_driver extends CI_Driver { |
| |
| /** |
| * CI Singleton |
| * |
| * @see get_instance() |
| * @var object |
| */ |
| protected $CI; |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Constructor |
| * |
| * Gets the CI singleton, so that individual drivers |
| * don't have to do it separately. |
| * |
| * @return void |
| */ |
| public function __construct() |
| { |
| $this->CI =& get_instance(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Decorate |
| * |
| * Decorates the child with the parent driver lib's methods and properties |
| * |
| * @param object Parent library object |
| * @return void |
| */ |
| public function decorate($parent) |
| { |
| // Call base class decorate first |
| parent::decorate($parent); |
| |
| // Call initialize method now that driver has access to $this->_parent |
| $this->initialize(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * __call magic method |
| * |
| * Handles access to the parent driver library's methods |
| * |
| * @param string Library method name |
| * @param array Method arguments (default: none) |
| * @return mixed |
| */ |
| public function __call($method, $args = array()) |
| { |
| // Make sure the parent library uses this driver |
| $this->_parent->select_driver(get_class($this)); |
| return parent::__call($method, $args); |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Initialize driver |
| * |
| * @return void |
| */ |
| protected function initialize() |
| { |
| // Overload this method to implement initialization |
| } |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Save the session data |
| * |
| * Data in the array has changed - perform any storage synchronization |
| * necessary. The child class MUST implement this abstract method! |
| * |
| * @return void |
| */ |
| abstract public function sess_save(); |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Destroy the current session |
| * |
| * Clean up storage for this session - it has been terminated. |
| * The child class MUST implement this abstract method! |
| * |
| * @return void |
| */ |
| abstract public function sess_destroy(); |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Regenerate the current session |
| * |
| * Regenerate the session ID. |
| * The child class MUST implement this abstract method! |
| * |
| * @param bool Destroy session data flag (default: false) |
| * @return void |
| */ |
| abstract public function sess_regenerate($destroy = FALSE); |
| |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Get a reference to user data array |
| * |
| * Give array access to the main CI_Session object. |
| * The child class MUST implement this abstract method! |
| * |
| * @return array Reference to userdata |
| */ |
| abstract public function &get_userdata(); |
| |
| } |
| |
| /* End of file Session.php */ |
| /* Location: ./system/libraries/Session/Session.php */ |