From c4e266b87f39d521ff1002fefa9df809c6b9bd61 Mon Sep 17 00:00:00 2001 From: Darren Hill Date: Tue, 30 Aug 2011 15:40:27 -0400 Subject: Added Session driver with native PHP sessions and original-flavor CI cookie sessions --- system/core/Loader.php | 11 +- system/libraries/Driver.php | 42 +- system/libraries/Session.php | 776 --------------------- system/libraries/Session/Session.php | 601 ++++++++++++++++ .../libraries/Session/drivers/Session_cookie.php | 583 ++++++++++++++++ .../libraries/Session/drivers/Session_native.php | 190 +++++ 6 files changed, 1414 insertions(+), 789 deletions(-) delete mode 100644 system/libraries/Session.php create mode 100755 system/libraries/Session/Session.php create mode 100755 system/libraries/Session/drivers/Session_cookie.php create mode 100755 system/libraries/Session/drivers/Session_native.php diff --git a/system/core/Loader.php b/system/core/Loader.php index de0fc06d2..51e6b82ca 100755 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -1174,6 +1174,15 @@ class CI_Loader { } } + // Autoload drivers + if (isset($autoload['drivers'])) + { + foreach ($autoload['drivers'] as $item) + { + $this->driver($item); + } + } + // Autoload models if (isset($autoload['model'])) { @@ -1240,4 +1249,4 @@ class CI_Loader { } /* End of file Loader.php */ -/* Location: ./system/core/Loader.php */ \ No newline at end of file +/* Location: ./system/core/Loader.php */ diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index 9881c1eec..e958fc67f 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -30,11 +30,32 @@ class CI_Driver_Library { protected $valid_drivers = array(); - protected static $lib_name; - - // The first time a child is used it won't exist, so we instantiate it - // subsequents calls will go straight to the proper child. - function __get($child) + protected $lib_name; + + /** + * Get magic method + * + * The first time a child is used it won't exist, so we instantiate it + * subsequents calls will go straight to the proper child. + * + * @param string Child class name + * @return object Child class + */ + public function __get($child) + { + // Try to load the driver + return load_driver($child); + } + + /** + * Load driver + * + * Separate load_driver call to support explicit driver load by library or user + * + * @param string Child class name + * @return object Child class + */ + public function load_driver($child) { if ( ! isset($this->lib_name)) { @@ -64,7 +85,7 @@ class CI_Driver_Library { if (file_exists($filepath)) { include_once $filepath; - break; + break 2; } } } @@ -84,12 +105,9 @@ class CI_Driver_Library { } // The requested driver isn't valid! - log_message('error', "Invalid driver requested: ".$child_class); - show_error("Invalid driver requested: ".$child_class); + log_message('error', 'Invalid driver requested: '.$child_class); + show_error('Invalid driver requested: '.$child_class); } - - // -------------------------------------------------------------------- - } // END CI_Driver_Library CLASS @@ -226,4 +244,4 @@ class CI_Driver { // END CI_Driver CLASS /* End of file Driver.php */ -/* Location: ./system/libraries/Driver.php */ \ No newline at end of file +/* Location: ./system/libraries/Driver.php */ diff --git a/system/libraries/Session.php b/system/libraries/Session.php deleted file mode 100644 index 2c8a80163..000000000 --- a/system/libraries/Session.php +++ /dev/null @@ -1,776 +0,0 @@ -CI =& get_instance(); - - // Set all the session preferences, which can either be set - // manually via the $params array above or via the config file - foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) - { - $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key); - } - - if ($this->encryption_key == '') - { - show_error('In order to use the Session class you are required to set an encryption key in your config file.'); - } - - // Load the string helper so we can use the strip_slashes() function - $this->CI->load->helper('string'); - - // Do we need encryption? If so, load the encryption class - if ($this->sess_encrypt_cookie == TRUE) - { - $this->CI->load->library('encrypt'); - } - - // Are we using a database? If so, load it - if ($this->sess_use_database === TRUE AND $this->sess_table_name != '') - { - $this->CI->load->database(); - } - - // Set the "now" time. Can either be GMT or server time, based on the - // config prefs. We use this to set the "last activity" time - $this->now = $this->_get_time(); - - // Set the session length. If the session expiration is - // set to zero we'll set the expiration two years from now. - if ($this->sess_expiration == 0) - { - $this->sess_expiration = (60*60*24*365*2); - } - - // Set the cookie name - $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; - - // Run the Session routine. If a session doesn't exist we'll - // create a new one. If it does, we'll update it. - if ( ! $this->sess_read()) - { - $this->sess_create(); - } - else - { - $this->sess_update(); - } - - // 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 sessions if necessary - $this->_sess_gc(); - - log_message('debug', "Session routines successfully run"); - } - - // -------------------------------------------------------------------- - - /** - * Fetch the current session data if it exists - * - * @access public - * @return bool - */ - function sess_read() - { - // Fetch the cookie - $session = $this->CI->input->cookie($this->sess_cookie_name); - - // No cookie? Goodbye cruel world!... - if ($session === FALSE) - { - log_message('debug', 'A session cookie was not found.'); - return FALSE; - } - - // Decrypt the cookie data - if ($this->sess_encrypt_cookie == TRUE) - { - $session = $this->CI->encrypt->decode($session); - } - else - { - // encryption was not used, so we need to check the md5 hash - $hash = substr($session, strlen($session)-32); // get last 32 chars - $session = substr($session, 0, strlen($session)-32); - - // Does the md5 hash match? This is to prevent manipulation of session data in userspace - if ($hash !== md5($session.$this->encryption_key)) - { - log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.'); - $this->sess_destroy(); - return FALSE; - } - } - - // Unserialize the session array - $session = $this->_unserialize($session); - - // Is the session data we unserialized an array with the correct format? - if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity'])) - { - $this->sess_destroy(); - return FALSE; - } - - // Is the session current? - if (($session['last_activity'] + $this->sess_expiration) < $this->now) - { - $this->sess_destroy(); - return FALSE; - } - - // Does the IP Match? - if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address()) - { - $this->sess_destroy(); - return FALSE; - } - - // Does the User Agent Match? - if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120))) - { - $this->sess_destroy(); - return FALSE; - } - - // Is there a corresponding session in the DB? - if ($this->sess_use_database === TRUE) - { - $this->CI->db->where('session_id', $session['session_id']); - - if ($this->sess_match_ip == TRUE) - { - $this->CI->db->where('ip_address', $session['ip_address']); - } - - if ($this->sess_match_useragent == TRUE) - { - $this->CI->db->where('user_agent', $session['user_agent']); - } - - $query = $this->CI->db->get($this->sess_table_name); - - // No result? Kill it! - if ($query->num_rows() == 0) - { - $this->sess_destroy(); - return FALSE; - } - - // Is there custom data? If so, add it to the main session array - $row = $query->row(); - if (isset($row->user_data) AND $row->user_data != '') - { - $custom_data = $this->_unserialize($row->user_data); - - if (is_array($custom_data)) - { - foreach ($custom_data as $key => $val) - { - $session[$key] = $val; - } - } - } - } - - // Session is valid! - $this->userdata = $session; - unset($session); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Write the session data - * - * @access public - * @return void - */ - function sess_write() - { - // Are we saving custom data to the DB? If not, all we do is update the cookie - if ($this->sess_use_database === FALSE) - { - $this->_set_cookie(); - return; - } - - // set the custom userdata, the session data we will set in a second - $custom_userdata = $this->userdata; - $cookie_userdata = array(); - - // Before continuing, we need to determine if there is any custom data to deal with. - // Let's determine this by removing the default indexes to see if there's anything left in the array - // and set the session data while we're at it - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - unset($custom_userdata[$val]); - $cookie_userdata[$val] = $this->userdata[$val]; - } - - // Did we find any custom data? If not, we turn the empty array into a string - // since there's no reason to serialize and store an empty array in the DB - if (count($custom_userdata) === 0) - { - $custom_userdata = ''; - } - else - { - // Serialize the custom data array so we can store it - $custom_userdata = $this->_serialize($custom_userdata); - } - - // Run the update query - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata)); - - // Write the cookie. Notice that we manually pass the cookie data array to the - // _set_cookie() function. Normally that function will store $this->userdata, but - // in this case that array contains custom data, which we do not want in the cookie. - $this->_set_cookie($cookie_userdata); - } - - // -------------------------------------------------------------------- - - /** - * Create a new session - * - * @access public - * @return void - */ - function sess_create() - { - $sessid = ''; - while (strlen($sessid) < 32) - { - $sessid .= mt_rand(0, mt_getrandmax()); - } - - // To make the session ID even more secure we'll combine it with the user's IP - $sessid .= $this->CI->input->ip_address(); - - $this->userdata = array( - 'session_id' => md5(uniqid($sessid, TRUE)), - 'ip_address' => $this->CI->input->ip_address(), - 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), - 'last_activity' => $this->now - ); - - - // Save the data to the DB if needed - if ($this->sess_use_database === TRUE) - { - $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata)); - } - - // Write the cookie - $this->_set_cookie(); - } - - // -------------------------------------------------------------------- - - /** - * Update an existing session - * - * @access public - * @return void - */ - function sess_update() - { - // We only update the session every five minutes by default - if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) - { - return; - } - - // Save the old session id so we know which record to - // update in the database if we need it - $old_sessid = $this->userdata['session_id']; - $new_sessid = ''; - while (strlen($new_sessid) < 32) - { - $new_sessid .= mt_rand(0, mt_getrandmax()); - } - - // To make the session ID even more secure we'll combine it with the user's IP - $new_sessid .= $this->CI->input->ip_address(); - - // Turn it into a hash - $new_sessid = md5(uniqid($new_sessid, TRUE)); - - // Update the session data in the session data array - $this->userdata['session_id'] = $new_sessid; - $this->userdata['last_activity'] = $this->now; - - // _set_cookie() will handle this for us if we aren't using database sessions - // by pushing all userdata to the cookie. - $cookie_data = NULL; - - // Update the session ID and last_activity field in the DB if needed - if ($this->sess_use_database === TRUE) - { - // set cookie explicitly to only have our session data - $cookie_data = array(); - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - $cookie_data[$val] = $this->userdata[$val]; - } - - $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); - } - - // Write the cookie - $this->_set_cookie($cookie_data); - } - - // -------------------------------------------------------------------- - - /** - * Destroy the current session - * - * @access public - * @return void - */ - function sess_destroy() - { - // Kill the session DB row - if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id'])) - { - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->delete($this->sess_table_name); - } - - // Kill the cookie - setcookie( - $this->sess_cookie_name, - addslashes(serialize(array())), - ($this->now - 31500000), - $this->cookie_path, - $this->cookie_domain, - 0 - ); - } - - // -------------------------------------------------------------------- - - /** - * Fetch a specific item from the session array - * - * @access public - * @param string - * @return string - */ - function userdata($item) - { - return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item]; - } - - // -------------------------------------------------------------------- - - /** - * Fetch all session data - * - * @access public - * @return array - */ - function all_userdata() - { - return $this->userdata; - } - - // -------------------------------------------------------------------- - - /** - * Add or change data in the "userdata" array - * - * @access public - * @param mixed - * @param string - * @return void - */ - function set_userdata($newdata = array(), $newval = '') - { - if (is_string($newdata)) - { - $newdata = array($newdata => $newval); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - $this->userdata[$key] = $val; - } - } - - $this->sess_write(); - } - - // -------------------------------------------------------------------- - - /** - * Delete a session variable from the "userdata" array - * - * @access array - * @return void - */ - function unset_userdata($newdata = array()) - { - if (is_string($newdata)) - { - $newdata = array($newdata => ''); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - unset($this->userdata[$key]); - } - } - - $this->sess_write(); - } - - // ------------------------------------------------------------------------ - - /** - * Add or change flashdata, only available - * until the next request - * - * @access public - * @param mixed - * @param string - * @return void - */ - function set_flashdata($newdata = array(), $newval = '') - { - if (is_string($newdata)) - { - $newdata = array($newdata => $newval); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - $flashdata_key = $this->flashdata_key.':new:'.$key; - $this->set_userdata($flashdata_key, $val); - } - } - } - - // ------------------------------------------------------------------------ - - /** - * Keeps existing flashdata available to next request. - * - * @access public - * @param string - * @return void - */ - function keep_flashdata($key) - { - // 'old' flashdata gets removed. Here we mark all - // flashdata as 'new' to preserve it from _flashdata_sweep() - // Note the function will return FALSE if the $key - // provided cannot be found - $old_flashdata_key = $this->flashdata_key.':old:'.$key; - $value = $this->userdata($old_flashdata_key); - - $new_flashdata_key = $this->flashdata_key.':new:'.$key; - $this->set_userdata($new_flashdata_key, $value); - } - - // ------------------------------------------------------------------------ - - /** - * Fetch a specific flashdata item from the session array - * - * @access public - * @param string - * @return string - */ - function flashdata($key) - { - $flashdata_key = $this->flashdata_key.':old:'.$key; - return $this->userdata($flashdata_key); - } - - // ------------------------------------------------------------------------ - - /** - * Identifies flashdata as 'old' for removal - * when _flashdata_sweep() runs. - * - * @access private - * @return void - */ - function _flashdata_mark() - { - $userdata = $this->all_userdata(); - foreach ($userdata as $name => $value) - { - $parts = explode(':new:', $name); - if (is_array($parts) && count($parts) === 2) - { - $new_name = $this->flashdata_key.':old:'.$parts[1]; - $this->set_userdata($new_name, $value); - $this->unset_userdata($name); - } - } - } - - // ------------------------------------------------------------------------ - - /** - * Removes all flashdata marked as 'old' - * - * @access private - * @return void - */ - - function _flashdata_sweep() - { - $userdata = $this->all_userdata(); - foreach ($userdata as $key => $value) - { - if (strpos($key, ':old:')) - { - $this->unset_userdata($key); - } - } - - } - - // -------------------------------------------------------------------- - - /** - * Get the "now" time - * - * @access private - * @return string - */ - function _get_time() - { - if (strtolower($this->time_reference) == 'gmt') - { - $now = time(); - $time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now)); - } - else - { - $time = time(); - } - - return $time; - } - - // -------------------------------------------------------------------- - - /** - * Write the session cookie - * - * @access public - * @return void - */ - function _set_cookie($cookie_data = NULL) - { - if (is_null($cookie_data)) - { - $cookie_data = $this->userdata; - } - - // Serialize the userdata for the cookie - $cookie_data = $this->_serialize($cookie_data); - - if ($this->sess_encrypt_cookie == TRUE) - { - $cookie_data = $this->CI->encrypt->encode($cookie_data); - } - else - { - // if encryption is not used, we provide an md5 hash to prevent userside tampering - $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); - } - - $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); - - // Set the cookie - setcookie( - $this->sess_cookie_name, - $cookie_data, - $expire, - $this->cookie_path, - $this->cookie_domain, - $this->cookie_secure - ); - } - - // -------------------------------------------------------------------- - - /** - * Serialize an array - * - * This function first converts any slashes found in the array to a temporary - * marker, so when it gets unserialized the slashes will be preserved - * - * @access private - * @param array - * @return string - */ - function _serialize($data) - { - if (is_array($data)) - { - foreach ($data as $key => $val) - { - if (is_string($val)) - { - $data[$key] = str_replace('\\', '{{slash}}', $val); - } - } - } - else - { - if (is_string($data)) - { - $data = str_replace('\\', '{{slash}}', $data); - } - } - - return serialize($data); - } - - // -------------------------------------------------------------------- - - /** - * Unserialize - * - * This function unserializes a data string, then converts any - * temporary slash markers back to actual slashes - * - * @access private - * @param array - * @return string - */ - function _unserialize($data) - { - $data = @unserialize(strip_slashes($data)); - - if (is_array($data)) - { - foreach ($data as $key => $val) - { - if (is_string($val)) - { - $data[$key] = str_replace('{{slash}}', '\\', $val); - } - } - - return $data; - } - - return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data; - } - - // -------------------------------------------------------------------- - - /** - * Garbage collection - * - * This deletes expired session rows from database - * if the probability percentage is met - * - * @access public - * @return void - */ - function _sess_gc() - { - if ($this->sess_use_database != TRUE) - { - return; - } - - srand(time()); - if ((rand() % 100) < $this->gc_probability) - { - $expire = $this->now - $this->sess_expiration; - - $this->CI->db->where("last_activity < {$expire}"); - $this->CI->db->delete($this->sess_table_name); - - log_message('debug', 'Session garbage collection performed.'); - } - } - - -} -// END Session Class - -/* End of file Session.php */ -/* Location: ./system/libraries/Session.php */ \ No newline at end of file diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php new file mode 100755 index 000000000..7aaf706a1 --- /dev/null +++ b/system/libraries/Session/Session.php @@ -0,0 +1,601 @@ +session or $this->session). + * In keeping with the CI_Driver methodology, multiple drivers may be loaded, although this might be a bit confusing. + * The 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 Darren Hill (DChill) + * @link http://codeigniter.com/user_guide/libraries/sessions.html + */ +final class Session extends CI_Driver_Library { + public $params = array(); + private $current = null; + private $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; + + /** + * 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 + */ + public function __construct(array $params = array()) + { + log_message('debug', 'Session Class Initialized'); + + // Get valid drivers list + $CI =& get_instance(); + $this->valid_drivers = array('Session_Native', 'Session_Cookie'); + $key = 'sess_valid_drivers'; + $drivers = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); + if ($drivers) + { + if (!is_array($drivers)) $drivers = array($drivers); + + // Add driver names to valid list + foreach ($drivers as $driver) + { + if (!in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers))) + { + $this->valid_drivers[] = $driver; + } + } + } + + // Get driver to load + $key = 'sess_driver'; + $driver = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); + if (!$driver) $driver = 'Native'; + if (!in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers))) + { + $this->valid_drivers[] = 'Session_'.$driver; + } + + // Save a copy of parameters in case drivers need access + $this->params = $params; + + // Load driver and get array reference + $this->load_driver($driver); + $this->userdata =& $this->current->get_userdata(); + + // 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', '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 + $this->current = parent::load_driver($driver); + return $this->current; + } + + /** + * Select default session storage driver + * + * @param string Driver classname + * @return void + */ + public function select_driver($driver) + { + // Validate driver name + $lowername = strtolower($driver); + if (in_array($lowername, array_map('strtolower', $this->valid_drivers))) + { + // See if regular or lowercase variant is loaded + if (class_exists($driver)) + { + $this->current = $this->$driver; + } + else if (class_exists($lowername)) + { + $this->current = $this->$lowername; + } + else + { + $this->load_driver($driver); + } + } + } + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Just call destroy on driver + $this->current->sess_destroy(); + } + + /** + * Regenerate the current session + * + * @param boolean Destroy session data flag (default: false) + * @return void + */ + public function sess_regenerate($destroy = false) + { + // Just call regenerate on driver + $this->current->sess_regenerate($destroy); + } + + /** + * Fetch a specific item from the session array + * + * @param string Item key + * @return string Item value + */ + public function userdata($item) + { + // Return value or FALSE if not found + return (!isset($this->userdata[$item])) ? FALSE : $this->userdata[$item]; + } + + /** + * Fetch all session data + * + * @return array User data array + */ + public function all_userdata() + { + // Return entire array + return (!isset($this->userdata)) ? FALSE : $this->userdata; + } + + /** + * 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 = array(), $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 = array()) + { + // Wrap single name as array + if (is_string($newdata)) + { + $newdata = array($newdata => ''); + } + + // Unset each item name + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + unset($this->userdata[$key]); + } + } + + // Tell driver data changed + $this->current->sess_save(); + } + + /** + * Determine if an item exists + * + * @param string Item name + * @return boolean + */ + public function has_userdata($item) + { + // Check for item name + 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 = array(), $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 string Item key + * @return void + */ + public function keep_flashdata($key) + { + // 'old' flashdata gets removed. Here we mark all + // flashdata as 'new' to preserve it from _flashdata_sweep() + $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) + { + // Prepend key and retrieve value + $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; + return $this->userdata($flashdata_key); + } + + /** + * 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 = array(), $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 = array()) + { + // Get expirations list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if (!$expirations || !count($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 ($newdata as $key => $val) + { + $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) + { + // Prepend key and return value + $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; + return $this->userdata($tempdata_key); + } + + /** + * Identifies flashdata as 'old' for removal + * when _flashdata_sweep() runs. + * + * @access private + * @return void + */ + private function _flashdata_mark() + { + $userdata = $this->all_userdata(); + foreach ($userdata as $name => $value) + { + $parts = explode(self::FLASHDATA_NEW, $name); + if (is_array($parts) && count($parts) === 2) + { + $new_name = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1]; + $this->set_userdata($new_name, $value); + $this->unset_userdata($name); + } + } + } + + /** + * Removes all flashdata marked as 'old' + * + * @access private + * @return void + */ + private function _flashdata_sweep() + { + $userdata = $this->all_userdata(); + foreach ($userdata as $key => $value) + { + if (strpos($key, self::FLASHDATA_OLD)) + { + $this->unset_userdata($key); + } + } + } + + /** + * Removes all expired tempdata + * + * @access private + * @return void + */ + private function _tempdata_sweep() + { + // Get expirations list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if (!$expirations || !count($expirations)) + { + // Nothing to do + return; + } + + // Unset expired elements + $now = time(); + $userdata = $this->all_userdata(); + foreach ($userdata as $key => $value) + { + 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); + } +} +// END Session Class + + +/** + * SessionDriver Class + * + * Extend this class to make a new Session driver. + * A Session driver basically manages an array of name/value pairs with some sort of storage mechanism. + * To make a new driver, derive from (extend) SessionDriver. 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 Session_, where is capitalized, and your filename must be Session_.EXT, + * preferably also capitalized. (e.g.: 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 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 Darren Hill (DChill) + */ +abstract class SessionDriver extends CI_Driver { + /** + * 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 boolean 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 Session object + * The child class MUST implement this abstract method! + * + * @return array Reference to userdata + */ + abstract public function &get_userdata(); +} +// END SessionDriver Class + + +/* End of file Session.php */ +/* Location: ./system/libraries/Session/Session.php */ +?> diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php new file mode 100755 index 000000000..0982b1e01 --- /dev/null +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -0,0 +1,583 @@ +CI =& get_instance(); + + // Set all the session preferences, which can either be set + // manually via the $params array above or via the config file + foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', + 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', + 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) + { + $this->$key = (isset($this->parent->params[$key])) ? $this->parent->params[$key] : $this->CI->config->item($key); + } + + if ($this->encryption_key == '') + { + show_error('In order to use the Cookie Session driver you are required to set an encryption key '. + 'in your config file.'); + } + + // Load the string helper so we can use the strip_slashes() function + $this->CI->load->helper('string'); + + // Do we need encryption? If so, load the encryption class + if ($this->sess_encrypt_cookie == TRUE) + { + $this->CI->load->library('encrypt'); + } + + // Are we using a database? If so, load it + if ($this->sess_use_database === TRUE && $this->sess_table_name != '') + { + $this->CI->load->database(); + } + + // Set the "now" time. Can either be GMT or server time, based on the config prefs. + // We use this to set the "last activity" time + $this->now = $this->_get_time(); + + // Set the session length. If the session expiration is + // set to zero we'll set the expiration two years from now. + if ($this->sess_expiration == 0) + { + $this->sess_expiration = (60*60*24*365*2); + } + + // Set the cookie name + $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; + + // Run the Session routine. If a session doesn't exist we'll + // create a new one. If it does, we'll update it. + if ( ! $this->_sess_read()) + { + $this->_sess_create(); + } + else + { + $this->_sess_update(); + } + + // Delete expired sessions if necessary + $this->_sess_gc(); + } + + /** + * Write the session data + * + * @return void + */ + public function sess_save() + { + // Are we saving custom data to the DB? If not, all we do is update the cookie + if ($this->sess_use_database === FALSE) + { + $this->_set_cookie(); + return; + } + + // set the custom userdata, the session data we will set in a second + $custom_userdata = $this->all_userdata(); + $cookie_userdata = array(); + + // Before continuing, we need to determine if there is any custom data to deal with. + // Let's determine this by removing the default indexes to see if there's anything left in the array + // and set the session data while we're at it + foreach (array('session_id','ip_address','user_agent','last_activity') as $val) + { + unset($custom_userdata[$val]); + $cookie_userdata[$val] = $this->userdata($val); + } + + // Did we find any custom data? If not, we turn the empty array into a string + // since there's no reason to serialize and store an empty array in the DB + if (count($custom_userdata) === 0) + { + $custom_userdata = ''; + } + else + { + // Serialize the custom data array so we can store it + $custom_userdata = $this->_serialize($custom_userdata); + } + + // Run the update query + $this->CI->db->where('session_id', $this->userdata('session_id')); + $this->CI->db->update($this->sess_table_name, + array('last_activity' => $this->userdata('last_activity'), 'user_data' => $custom_userdata)); + + // Write the cookie. Notice that we manually pass the cookie data array to the + // _set_cookie() function. Normally that function will store $this->userdata, but + // in this case that array contains custom data, which we do not want in the cookie. + $this->_set_cookie($cookie_userdata); + } + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Kill the session DB row + if ($this->sess_use_database === TRUE && $this->has_userdata('session_id')) + { + $this->CI->db->where('session_id', $this->userdata['session_id']); + $this->CI->db->delete($this->sess_table_name); + } + + // Kill the cookie + setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000), + $this->cookie_path, $this->cookie_domain, 0); + } + + /** + * Regenerate the current session + * + * Regenerate the session id + * + * @param boolean Destroy session data flag (default: false) + * @return void + */ + public function sess_regenerate($destroy = false) + { + // Check destroy flag + if ($destroy) + { + // Destroy old session and create new one + $this->sess_destroy(); + $this->_sess_create(); + } + else + { + // Just force an update to recreate the id + $this->_sess_update(true); + } + } + + /** + * Get a reference to user data array + * + * @return array - Reference to userdata + */ + public function &get_userdata() + { + // Return reference to array + return $this->userdata; + } + + /** + * Fetch the current session data if it exists + * + * @access private + * @return bool + */ + private function _sess_read() + { + // Fetch the cookie + $session = $this->CI->input->cookie($this->sess_cookie_name); + + // No cookie? Goodbye cruel world!... + if ($session === FALSE) + { + log_message('debug', 'A session cookie was not found.'); + return FALSE; + } + + // Decrypt the cookie data + if ($this->sess_encrypt_cookie == TRUE) + { + $session = $this->CI->encrypt->decode($session); + } + else + { + // encryption was not used, so we need to check the md5 hash + $hash = substr($session, strlen($session)-32); // get last 32 chars + $session = substr($session, 0, strlen($session)-32); + + // Does the md5 hash match? This is to prevent manipulation of session data in userspace + if ($hash !== md5($session.$this->encryption_key)) + { + log_message('error', 'The session cookie data did not match what was expected. '. + 'This could be a possible hacking attempt.'); + $this->sess_destroy(); + return FALSE; + } + } + + // Unserialize the session array + $session = $this->_unserialize($session); + + // Is the session data we unserialized an array with the correct format? + if ( ! is_array($session) || ! isset($session['session_id']) || ! isset($session['ip_address']) || + ! isset($session['user_agent']) || ! isset($session['last_activity'])) + { + $this->sess_destroy(); + return FALSE; + } + + // Is the session current? + if (($session['last_activity'] + $this->sess_expiration) < $this->now()) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the IP Match? + if ($this->sess_match_ip == TRUE && $session['ip_address'] != $this->CI->input->ip_address()) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the User Agent Match? + if ($this->sess_match_useragent == TRUE && + trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50))) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there a corresponding session in the DB? + if ($this->sess_use_database === TRUE) + { + $this->CI->db->where('session_id', $session['session_id']); + + if ($this->sess_match_ip == TRUE) + { + $this->CI->db->where('ip_address', $session['ip_address']); + } + + if ($this->sess_match_useragent == TRUE) + { + $this->CI->db->where('user_agent', $session['user_agent']); + } + + $query = $this->CI->db->get($this->sess_table_name); + + // No result? Kill it! + if ($query->num_rows() == 0) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there custom data? If so, add it to the main session array + $row = $query->row(); + if (isset($row->user_data) && $row->user_data != '') + { + $custom_data = $this->_unserialize($row->user_data); + + if (is_array($custom_data)) + { + foreach ($custom_data as $key => $val) + { + $session[$key] = $val; + } + } + } + } + + // Session is valid! + $this->userdata = $session; + unset($session); + + return TRUE; + } + + /** + * Create a new session + * + * @access private + * @return void + */ + private function _sess_create() + { + $sessid = ''; + while (strlen($sessid) < 32) + { + $sessid .= mt_rand(0, mt_getrandmax()); + } + + // To make the session ID even more secure we'll combine it with the user's IP + $sessid .= $this->CI->input->ip_address(); + + $this->set_userdata('session_id', md5(uniqid($sessid, TRUE))); + $this->set_userdata('ip_address', $this->CI->input->ip_address()); + $this->set_userdata('user_agent', substr($this->CI->input->user_agent(), 0, 50)); + $this->set_userdata('last_activity',$this->now()); + + + // Save the data to the DB if needed + if ($this->sess_use_database === TRUE) + { + $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->all_userdata())); + } + + // Write the cookie + $this->_set_cookie(); + } + + /** + * Update an existing session + * + * @access private + * @param boolean Force update flag (default: false) + * @return void + */ + private function _sess_update($force = false) + { + // We only update the session every five minutes by default (unless forced) + if (!$force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now()) + { + return; + } + + // Save the old session id so we know which record to + // update in the database if we need it + $old_sessid = $this->userdata['session_id']; + $new_sessid = ''; + while (strlen($new_sessid) < 32) + { + $new_sessid .= mt_rand(0, mt_getrandmax()); + } + + // To make the session ID even more secure we'll combine it with the user's IP + $new_sessid .= $this->CI->input->ip_address(); + + // Turn it into a hash + $new_sessid = md5(uniqid($new_sessid, TRUE)); + + // Update the session data in the session data array + $this->set_userdata('session_id', $new_sessid); + $this->set_userdata('last_activity', $this->now()); + + // _set_cookie() will handle this for us if we aren't using database sessions + // by pushing all userdata to the cookie. + $cookie_data = NULL; + + // Update the session ID and last_activity field in the DB if needed + if ($this->sess_use_database === TRUE) + { + // set cookie explicitly to only have our session data + $cookie_data = array(); + foreach (array('session_id','ip_address','user_agent','last_activity') as $val) + { + $cookie_data[$val] = $this->userdata[$val]; + } + + $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, + array('last_activity' => $this->now(), 'session_id' => $new_sessid), + array('session_id' => $old_sessid))); + } + + // Write the cookie + $this->_set_cookie($cookie_data); + } + + /** + * Get the "now" time + * + * @access private + * @return int + */ + private function _get_time() + { + if (strtolower($this->time_reference) == 'gmt') + { + $now = time(); + $time = mktime(gmdate('H', $now), gmdate('i', $now), gmdate('s', $now), gmdate('m', $now), + gmdate('d', $now), gmdate('Y', $now)); + } + else + { + $time = time(); + } + + return $time; + } + + /** + * Write the session cookie + * + * @access private + * @param array Cookie name/value pairs + * @return void + */ + private function _set_cookie(array $cookie_data = NULL) + { + if (is_null($cookie_data)) + { + $cookie_data = $this->all_userdata(); + } + + // Serialize the userdata for the cookie + $cookie_data = $this->_serialize($cookie_data); + + if ($this->sess_encrypt_cookie == TRUE) + { + $cookie_data = $this->CI->encrypt->encode($cookie_data); + } + else + { + // if encryption is not used, we provide an md5 hash to prevent userside tampering + $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); + } + + $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); + + // Set the cookie + setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain, 0); + } + + /** + * Serialize an array + * + * This function first converts any slashes found in the array to a temporary + * marker, so when it gets unserialized the slashes will be preserved + * + * @access private + * @param mixed Data to serialize + * @return string + */ + private function _serialize($data) + { + if (is_array($data)) + { + foreach ($data as $key => $val) + { + if (is_string($val)) + { + $data[$key] = str_replace('\\', '{{slash}}', $val); + } + } + } + else + { + if (is_string($data)) + { + $data = str_replace('\\', '{{slash}}', $data); + } + } + + return serialize($data); + } + + /** + * Unserialize + * + * This function unserializes a data string, then converts any + * temporary slash markers back to actual slashes + * + * @access private + * @param string Data to unserialize + * @return mixed + */ + private function _unserialize($data) + { + $data = @unserialize(strip_slashes($data)); + + if (is_array($data)) + { + foreach ($data as $key => $val) + { + if (is_string($val)) + { + $data[$key] = str_replace('{{slash}}', '\\', $val); + } + } + + return $data; + } + + return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data; + } + + /** + * Garbage collection + * + * This deletes expired session rows from database + * if the probability percentage is met + * + * @access private + * @return void + */ + private function _sess_gc() + { + if ($this->sess_use_database != TRUE) + { + return; + } + + srand(time()); + if ((rand() % 100) < self::gc_probability) + { + $expire = $this->now() - $this->sess_expiration; + + $this->CI->db->where('last_activity < '.$expire); + $this->CI->db->delete($this->sess_table_name); + + log_message('debug', 'Session garbage collection performed.'); + } + } +} +// END Session_Cookie Class + +/* End of file Session_cookie.php */ +/* Location: ./system/libraries/Session/Session.php */ +?> diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php new file mode 100755 index 000000000..df588175f --- /dev/null +++ b/system/libraries/Session/drivers/Session_native.php @@ -0,0 +1,190 @@ +parent->params[$key]) ? $this->parent->params[$key] : $CI->config->item($key); + } + + // Set session name, if specified + if ($config['sess_cookie_name']) + { + $name = $config['sess_cookie_name']; + if ($config['cookie_prefix']) + { + // Prepend cookie prefix + $name = $config['cookie_prefix'].$name; + } + session_name($name); + } + + // Set expiration, path, and domain + $expire = 7200; + $path = '/'; + $domain = ''; + if ($config['sess_expiration'] !== FALSE) + { + // Default to 2 years if expiration is "0" + $expire = ($config['sess_expiration'] == 0) ? (60*60*24*365*2) : $config['sess_expiration']; + } + if ($config['cookie_path']) + { + // Use specified path + $path = $config['cookie_path']; + } + if ($config['cookie_domain']) + { + // Use specified domain + $domain = $config['cookie_domain']; + } + session_set_cookie_params($config['sess_expire_on_close'] ? 0 : $expire, $path, $domain); + + // Start session + session_start(); + + // Check session expiration, ip, and agent + $now = time(); + $destroy = FALSE; + if (isset($_SESSION['last_activity']) && ($_SESSION['last_activity'] + $expire) < $now) + { + // Expired - destroy + $destroy = TRUE; + } + else if ($config['sess_match_ip'] == TRUE && isset($_SESSION['ip_address']) && + $_SESSION['ip_address'] != $CI->input->ip_address()) + { + // IP doesn't match - destroy + $destroy = TRUE; + } + else if ($config['sess_match_useragent'] == TRUE && isset($_SESSION['user_agent']) && + $_SESSION['user_agent'] != trim(substr($CI->input->user_agent(), 0, 50))) + { + // Agent doesn't match - destroy + $destroy = TRUE; + } + + // Destroy expired or invalid session + if ($destroy) + { + // Clear old session and start new + $this->sess_destroy(); + session_start(); + } + + // Set activity time + $_SESSION['last_activity'] = $now; + + // Set matching values as required + if ($config['sess_match_ip'] == TRUE && !isset($_SESSION['ip_address'])) + { + // Store user IP address + $_SESSION['ip_address'] = $CI->input->ip_address(); + } + if ($config['sess_match_useragent'] == TRUE && !isset($_SESSION['user_agent'])) + { + // Store user agent string + $_SESSION['user_agent'] = trim(substr($CI->input->user_agent(), 0, 50)); + } + } + + /** + * Save the session data + * + * @access public + * @return void + */ + public function sess_save() + { + // Nothing to do - changes to $_SESSION are automatically saved + } + + /** + * Destroy the current session + * + * @access public + * @return void + */ + public function sess_destroy() + { + // Cleanup session + $_SESSION = array(); + $name = session_name(); + if (isset($_COOKIE[$name])) + { + // Clear session cookie + $params = session_get_cookie_params(); + setcookie($name, '', time() - 42000, $params['path'], $params['domain']); + unset($_COOKIE[$name]); + } + session_destroy(); + } + + /** + * Regenerate the current session + * + * Regenerate the session id + * + * @access public + * @param boolean Destroy session data flag (default: false) + * @return void + */ + public function sess_regenerate($destroy = false) + { + // Just regenerate id, passing destroy flag + session_regenerate_id($destroy); + } + + /** + * Get a reference to user data array + * + * @access public + * @return array Reference to userdata + */ + public function &get_userdata() + { + // Just return reference to $_SESSION + return $_SESSION; + } +} +// END Session_Native Class + + +/* End of file Session_native.php */ +/* Location: ./system/libraries/Session/Session.php */ +?> -- cgit v1.2.3-24-g4f1b From 3bd8d1ad9273f12c47d1ce1f59d4140718a02e4f Mon Sep 17 00:00:00 2001 From: Darren Hill Date: Wed, 31 Aug 2011 08:28:16 -0400 Subject: Removed ucfirst on Driver library name --- system/libraries/Driver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index e958fc67f..c3bcc252e 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -66,8 +66,8 @@ class CI_Driver_Library { $child_class = $this->lib_name.'_'.$child; // Remove the CI_ prefix and lowercase - $lib_name = ucfirst(strtolower(str_replace('CI_', '', $this->lib_name))); - $driver_name = strtolower(str_replace('CI_', '', $child_class)); + $lib_name = strtolower(preg_replace('/^CI_/', '', $this->lib_name)); + $driver_name = strtolower(preg_replace('/^CI_/', '', $child_class)); if (in_array($driver_name, array_map('strtolower', $this->valid_drivers))) { -- cgit v1.2.3-24-g4f1b From ca3be1d515a68293b64704a9a8346802702dedaa Mon Sep 17 00:00:00 2001 From: Darren Hill Date: Wed, 31 Aug 2011 08:31:18 -0400 Subject: Whitespace cleanup --- system/core/Loader.php | 8 ++++---- system/libraries/Driver.php | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/system/core/Loader.php b/system/core/Loader.php index 51e6b82ca..edf5853f0 100755 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -1177,10 +1177,10 @@ class CI_Loader { // Autoload drivers if (isset($autoload['drivers'])) { - foreach ($autoload['drivers'] as $item) - { - $this->driver($item); - } + foreach ($autoload['drivers'] as $item) + { + $this->driver($item); + } } // Autoload models diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index c3bcc252e..80c0e2812 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -32,29 +32,29 @@ class CI_Driver_Library { protected $valid_drivers = array(); protected $lib_name; - /** - * Get magic method - * + /** + * Get magic method + * * The first time a child is used it won't exist, so we instantiate it * subsequents calls will go straight to the proper child. - * - * @param string Child class name - * @return object Child class - */ + * + * @param string Child class name + * @return object Child class + */ public function __get($child) { - // Try to load the driver + // Try to load the driver return load_driver($child); - } + } - /** - * Load driver - * + /** + * Load driver + * * Separate load_driver call to support explicit driver load by library or user - * - * @param string Child class name - * @return object Child class - */ + * + * @param string Child class name + * @return object Child class + */ public function load_driver($child) { if ( ! isset($this->lib_name)) -- cgit v1.2.3-24-g4f1b From 5073a375951f09b654f6b991df7ca04e1f88d93c Mon Sep 17 00:00:00 2001 From: Darren Hill Date: Wed, 31 Aug 2011 13:54:19 -0400 Subject: Better style guide compliance --- system/libraries/Session/Session.php | 136 ++++++++++----------- .../libraries/Session/drivers/Session_cookie.php | 8 +- .../libraries/Session/drivers/Session_native.php | 8 +- 3 files changed, 76 insertions(+), 76 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 7aaf706a1..dacc249c5 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -15,15 +15,15 @@ /** - * Session Class + * CI_Session Class * * The user interface defined by EllisLabs, now with puggable drivers to manage different storage mechanisms. - * By default, the Native PHP session driver will load, but the 'sess_driver' config/param item (see above) can be - * used to specify the 'Cookie' driver, or any other you might create. + * By default, the native PHP session driver will load, but the 'sess_driver' config/param item (see above) can be + * used to specify the 'cookie' 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 Session library class keeps track of the most recently loaded driver as "current" to call for driver methods. + * 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 @@ -35,10 +35,10 @@ * @package CodeIgniter * @subpackage Libraries * @category Sessions - * @author Darren Hill (DChill) + * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/libraries/sessions.html */ -final class Session extends CI_Driver_Library { +final class CI_Session extends CI_Driver_Library { public $params = array(); private $current = null; private $userdata = array(); @@ -51,20 +51,20 @@ final class Session extends CI_Driver_Library { const TEMP_EXP_DEF = 300; /** - * Session constructor + * 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 + * @param array Configuration parameters */ public function __construct(array $params = array()) { - log_message('debug', 'Session Class Initialized'); + log_message('debug', 'CI_Session Class Initialized'); // Get valid drivers list $CI =& get_instance(); - $this->valid_drivers = array('Session_Native', 'Session_Cookie'); + $this->valid_drivers = array('CI_Session_native', 'CI_Session_cookie'); $key = 'sess_valid_drivers'; $drivers = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); if ($drivers) @@ -84,7 +84,7 @@ final class Session extends CI_Driver_Library { // Get driver to load $key = 'sess_driver'; $driver = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); - if (!$driver) $driver = 'Native'; + if (!$driver) $driver = 'native'; if (!in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers))) { $this->valid_drivers[] = 'Session_'.$driver; @@ -106,14 +106,14 @@ final class Session extends CI_Driver_Library { // Delete expired tempdata $this->_tempdata_sweep(); - log_message('debug', 'Session routines successfully run'); + log_message('debug', 'CI_Session routines successfully run'); } /** * Loads session storage driver * - * @param string Driver classname - * @return object Loaded driver object + * @param string Driver classname + * @return object Loaded driver object */ public function load_driver($driver) { @@ -125,8 +125,8 @@ final class Session extends CI_Driver_Library { /** * Select default session storage driver * - * @param string Driver classname - * @return void + * @param string Driver classname + * @return void */ public function select_driver($driver) { @@ -153,7 +153,7 @@ final class Session extends CI_Driver_Library { /** * Destroy the current session * - * @return void + * @return void */ public function sess_destroy() { @@ -164,8 +164,8 @@ final class Session extends CI_Driver_Library { /** * Regenerate the current session * - * @param boolean Destroy session data flag (default: false) - * @return void + * @param boolean Destroy session data flag (default: false) + * @return void */ public function sess_regenerate($destroy = false) { @@ -176,8 +176,8 @@ final class Session extends CI_Driver_Library { /** * Fetch a specific item from the session array * - * @param string Item key - * @return string Item value + * @param string Item key + * @return string Item value */ public function userdata($item) { @@ -199,9 +199,9 @@ final class Session extends CI_Driver_Library { /** * 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 + * @param mixed Item name or array of items + * @param string Item value or empty string + * @return void */ public function set_userdata($newdata = array(), $newval = '') { @@ -227,8 +227,8 @@ final class Session extends CI_Driver_Library { /** * Delete a session variable from the "userdata" array * - * @param mixed Item name or array of item names - * @return void + * @param mixed Item name or array of item names + * @return void */ public function unset_userdata($newdata = array()) { @@ -254,8 +254,8 @@ final class Session extends CI_Driver_Library { /** * Determine if an item exists * - * @param string Item name - * @return boolean + * @param string Item name + * @return boolean */ public function has_userdata($item) { @@ -266,9 +266,9 @@ final class Session extends CI_Driver_Library { /** * 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 + * @param mixed Item name or array of items + * @param string Item value or empty string + * @return void */ public function set_flashdata($newdata = array(), $newval = '') { @@ -292,12 +292,12 @@ final class Session extends CI_Driver_Library { /** * Keeps existing flashdata available to next request. * - * @param string Item key - * @return void + * @param string Item key + * @return void */ public function keep_flashdata($key) { - // 'old' flashdata gets removed. Here we mark all + // 'old' flashdata gets removed. Here we mark all // flashdata as 'new' to preserve it from _flashdata_sweep() $old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; $value = $this->userdata($old_flashdata_key); @@ -309,8 +309,8 @@ final class Session extends CI_Driver_Library { /** * Fetch a specific flashdata item from the session array * - * @param string Item key - * @return string + * @param string Item key + * @return string */ public function flashdata($key) { @@ -323,10 +323,10 @@ final class Session extends CI_Driver_Library { * 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 + * @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 = array(), $newval = '', $expire = 0) { @@ -364,8 +364,8 @@ final class Session extends CI_Driver_Library { /** * Delete a temporary session variable from the "userdata" array * - * @param mixed Item name or array of item names - * @return void + * @param mixed Item name or array of item names + * @return void */ public function unset_tempdata($newdata = array()) { @@ -401,8 +401,8 @@ final class Session extends CI_Driver_Library { /** * Fetch a specific tempdata item from the session array * - * @param string Item key - * @return string + * @param string Item key + * @return string */ public function tempdata($key) { @@ -483,32 +483,32 @@ final class Session extends CI_Driver_Library { $this->set_userdata(self::EXPIRATION_KEY, $expirations); } } -// END Session Class +// END CI_Session Class /** - * SessionDriver Class + * CI_Session_driver Class * - * Extend this class to make a new Session driver. - * A Session driver basically manages an array of name/value pairs with some sort of storage mechanism. - * To make a new driver, derive from (extend) SessionDriver. Overload the initialize method and read or create + * 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 Session_, where is capitalized, and your filename must be Session_.EXT, - * preferably also capitalized. (e.g.: 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 Session + * 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_, and your filename must be Session_.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 + * @package CodeIgniter + * @subpackage Libraries * @category Sessions - * @author Darren Hill (DChill) + * @author ExpressionEngine Dev Team */ -abstract class SessionDriver extends CI_Driver { +abstract class CI_Session_driver extends CI_Driver { /** * Decorate * @@ -531,8 +531,8 @@ abstract class SessionDriver extends CI_Driver { * * Handles access to the parent driver library's methods * - * @param string Library method name - * @param array Method arguments (default: none) + * @param string Library method name + * @param array Method arguments (default: none) * @return mixed */ public function __call($method, $args = array()) @@ -545,7 +545,7 @@ abstract class SessionDriver extends CI_Driver { /** * Initialize driver * - * @return void + * @return void */ protected function initialize() { @@ -558,7 +558,7 @@ abstract class SessionDriver extends CI_Driver { * Data in the array has changed - perform any storage synchronization necessary * The child class MUST implement this abstract method! * - * @return void + * @return void */ abstract public function sess_save(); @@ -568,7 +568,7 @@ abstract class SessionDriver extends CI_Driver { * Clean up storage for this session - it has been terminated * The child class MUST implement this abstract method! * - * @return void + * @return void */ abstract public function sess_destroy(); @@ -578,22 +578,22 @@ abstract class SessionDriver extends CI_Driver { * Regenerate the session id * The child class MUST implement this abstract method! * - * @param boolean Destroy session data flag (default: false) - * @return void + * @param boolean 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 Session object + * Give array access to the main CI_Session object * The child class MUST implement this abstract method! * - * @return array Reference to userdata + * @return array Reference to userdata */ abstract public function &get_userdata(); } -// END SessionDriver Class +// END CI_Session_driver Class /* End of file Session.php */ diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index 0982b1e01..d26ab0432 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -24,9 +24,9 @@ * @package CodeIgniter * @subpackage Libraries * @category Sessions - * @author ExpressionEngine Dev Team and Darren Hill (DChill42) + * @author ExpressionEngine Dev Team */ -class Session_Cookie extends SessionDriver { +class CI_Session_cookie extends CI_Session_driver { private $sess_encrypt_cookie = FALSE; private $sess_use_database = FALSE; private $sess_table_name = ''; @@ -576,8 +576,8 @@ class Session_Cookie extends SessionDriver { } } } -// END Session_Cookie Class +// END CI_Session_cookie Class /* End of file Session_cookie.php */ -/* Location: ./system/libraries/Session/Session.php */ +/* Location: ./system/libraries/Session/drivers/Session_cookie.php */ ?> diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index df588175f..37da3445a 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -22,9 +22,9 @@ * @package CodeIgniter * @subpackage Libraries * @category Sessions - * @author Darren Hill (DChill) + * @author ExpressionEngine Dev Team */ -class Session_Native extends SessionDriver { +class CI_Session_native extends CI_Session_driver { /** * Initialize session driver object * @@ -182,9 +182,9 @@ class Session_Native extends SessionDriver { return $_SESSION; } } -// END Session_Native Class +// END CI_Session_native Class /* End of file Session_native.php */ -/* Location: ./system/libraries/Session/Session.php */ +/* Location: ./system/libraries/Session/drivers/Session_native.php */ ?> -- cgit v1.2.3-24-g4f1b From 4d1cd4c56697bc53b5a9899089ab4c978c66e1da Mon Sep 17 00:00:00 2001 From: Darren Hill Date: Wed, 31 Aug 2011 13:59:09 -0400 Subject: Restored errantly removed ucfirst --- system/libraries/Driver.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index 80c0e2812..e958fc67f 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -32,29 +32,29 @@ class CI_Driver_Library { protected $valid_drivers = array(); protected $lib_name; - /** - * Get magic method - * + /** + * Get magic method + * * The first time a child is used it won't exist, so we instantiate it * subsequents calls will go straight to the proper child. - * - * @param string Child class name - * @return object Child class - */ + * + * @param string Child class name + * @return object Child class + */ public function __get($child) { - // Try to load the driver + // Try to load the driver return load_driver($child); - } + } - /** - * Load driver - * + /** + * Load driver + * * Separate load_driver call to support explicit driver load by library or user - * - * @param string Child class name - * @return object Child class - */ + * + * @param string Child class name + * @return object Child class + */ public function load_driver($child) { if ( ! isset($this->lib_name)) @@ -66,8 +66,8 @@ class CI_Driver_Library { $child_class = $this->lib_name.'_'.$child; // Remove the CI_ prefix and lowercase - $lib_name = strtolower(preg_replace('/^CI_/', '', $this->lib_name)); - $driver_name = strtolower(preg_replace('/^CI_/', '', $child_class)); + $lib_name = ucfirst(strtolower(str_replace('CI_', '', $this->lib_name))); + $driver_name = strtolower(str_replace('CI_', '', $child_class)); if (in_array($driver_name, array_map('strtolower', $this->valid_drivers))) { -- cgit v1.2.3-24-g4f1b From 6fbf6bd1dfa2ef373fc8072c52f63446cdd00327 Mon Sep 17 00:00:00 2001 From: Darren Hill Date: Wed, 31 Aug 2011 14:15:35 -0400 Subject: Missed whitespace on Driver --- system/libraries/Driver.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index e958fc67f..77476e139 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -32,29 +32,29 @@ class CI_Driver_Library { protected $valid_drivers = array(); protected $lib_name; - /** - * Get magic method - * + /** + * Get magic method + * * The first time a child is used it won't exist, so we instantiate it * subsequents calls will go straight to the proper child. - * - * @param string Child class name - * @return object Child class - */ + * + * @param string Child class name + * @return object Child class + */ public function __get($child) { - // Try to load the driver + // Try to load the driver return load_driver($child); - } + } - /** - * Load driver - * + /** + * Load driver + * * Separate load_driver call to support explicit driver load by library or user - * - * @param string Child class name - * @return object Child class - */ + * + * @param string Child class name + * @return object Child class + */ public function load_driver($child) { if ( ! isset($this->lib_name)) -- cgit v1.2.3-24-g4f1b From a2ae6571e55d5a3d23645e96929eea996e9f0499 Mon Sep 17 00:00:00 2001 From: Darren Hill Date: Thu, 1 Sep 2011 07:36:26 -0400 Subject: Made private members protected for inheritance --- system/libraries/Session/Session.php | 18 +++--- .../libraries/Session/drivers/Session_cookie.php | 66 +++++++++++----------- .../libraries/Session/drivers/Session_native.php | 28 ++++----- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index dacc249c5..7c340ccca 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -38,10 +38,10 @@ * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/libraries/sessions.html */ -final class CI_Session extends CI_Driver_Library { +class CI_Session extends CI_Driver_Library { public $params = array(); - private $current = null; - private $userdata = array(); + protected $current = null; + protected $userdata = array(); const FLASHDATA_KEY = 'flash'; const FLASHDATA_NEW = ':new:'; @@ -415,10 +415,10 @@ final class CI_Session extends CI_Driver_Library { * Identifies flashdata as 'old' for removal * when _flashdata_sweep() runs. * - * @access private + * @access protected * @return void */ - private function _flashdata_mark() + protected function _flashdata_mark() { $userdata = $this->all_userdata(); foreach ($userdata as $name => $value) @@ -436,10 +436,10 @@ final class CI_Session extends CI_Driver_Library { /** * Removes all flashdata marked as 'old' * - * @access private + * @access protected * @return void */ - private function _flashdata_sweep() + protected function _flashdata_sweep() { $userdata = $this->all_userdata(); foreach ($userdata as $key => $value) @@ -454,10 +454,10 @@ final class CI_Session extends CI_Driver_Library { /** * Removes all expired tempdata * - * @access private + * @access protected * @return void */ - private function _tempdata_sweep() + protected function _tempdata_sweep() { // Get expirations list $expirations = $this->userdata(self::EXPIRATION_KEY); diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index d26ab0432..334218ec2 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -27,23 +27,23 @@ * @author ExpressionEngine Dev Team */ class CI_Session_cookie extends CI_Session_driver { - private $sess_encrypt_cookie = FALSE; - private $sess_use_database = FALSE; - private $sess_table_name = ''; - private $sess_expiration = 7200; - private $sess_expire_on_close = FALSE; - private $sess_match_ip = FALSE; - private $sess_match_useragent = TRUE; - private $sess_cookie_name = 'ci_session'; - private $cookie_prefix = ''; - private $cookie_path = ''; - private $cookie_domain = ''; - private $sess_time_to_update = 300; - private $encryption_key = ''; - private $time_reference = 'time'; - private $userdata = array(); - private $CI = null; - private $now = 0; + protected $sess_encrypt_cookie = FALSE; + protected $sess_use_database = FALSE; + protected $sess_table_name = ''; + protected $sess_expiration = 7200; + protected $sess_expire_on_close = FALSE; + protected $sess_match_ip = FALSE; + protected $sess_match_useragent = TRUE; + protected $sess_cookie_name = 'ci_session'; + protected $cookie_prefix = ''; + protected $cookie_path = ''; + protected $cookie_domain = ''; + protected $sess_time_to_update = 300; + protected $encryption_key = ''; + protected $time_reference = 'time'; + protected $userdata = array(); + protected $CI = null; + protected $now = 0; const gc_probability = 5; @@ -224,10 +224,10 @@ class CI_Session_cookie extends CI_Session_driver { /** * Fetch the current session data if it exists * - * @access private + * @access protected * @return bool */ - private function _sess_read() + protected function _sess_read() { // Fetch the cookie $session = $this->CI->input->cookie($this->sess_cookie_name); @@ -343,10 +343,10 @@ class CI_Session_cookie extends CI_Session_driver { /** * Create a new session * - * @access private + * @access protected * @return void */ - private function _sess_create() + protected function _sess_create() { $sessid = ''; while (strlen($sessid) < 32) @@ -376,11 +376,11 @@ class CI_Session_cookie extends CI_Session_driver { /** * Update an existing session * - * @access private + * @access protected * @param boolean Force update flag (default: false) * @return void */ - private function _sess_update($force = false) + protected function _sess_update($force = false) { // We only update the session every five minutes by default (unless forced) if (!$force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now()) @@ -433,10 +433,10 @@ class CI_Session_cookie extends CI_Session_driver { /** * Get the "now" time * - * @access private + * @access protected * @return int */ - private function _get_time() + protected function _get_time() { if (strtolower($this->time_reference) == 'gmt') { @@ -455,11 +455,11 @@ class CI_Session_cookie extends CI_Session_driver { /** * Write the session cookie * - * @access private + * @access protected * @param array Cookie name/value pairs * @return void */ - private function _set_cookie(array $cookie_data = NULL) + protected function _set_cookie(array $cookie_data = NULL) { if (is_null($cookie_data)) { @@ -491,11 +491,11 @@ class CI_Session_cookie extends CI_Session_driver { * This function first converts any slashes found in the array to a temporary * marker, so when it gets unserialized the slashes will be preserved * - * @access private + * @access protected * @param mixed Data to serialize * @return string */ - private function _serialize($data) + protected function _serialize($data) { if (is_array($data)) { @@ -524,11 +524,11 @@ class CI_Session_cookie extends CI_Session_driver { * This function unserializes a data string, then converts any * temporary slash markers back to actual slashes * - * @access private + * @access protected * @param string Data to unserialize * @return mixed */ - private function _unserialize($data) + protected function _unserialize($data) { $data = @unserialize(strip_slashes($data)); @@ -554,10 +554,10 @@ class CI_Session_cookie extends CI_Session_driver { * This deletes expired session rows from database * if the probability percentage is met * - * @access private + * @access protected * @return void */ - private function _sess_gc() + protected function _sess_gc() { if ($this->sess_use_database != TRUE) { diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index 37da3445a..c7130b688 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -5,11 +5,11 @@ * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter - * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2010, EllisLab, Inc. + * @author ExpressionEngine Dev Team + * @copyright Copyright (c) 2008 - 2010, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com - * @since Version 2.0 + * @since Version 2.0 * @filesource */ @@ -22,13 +22,13 @@ * @package CodeIgniter * @subpackage Libraries * @category Sessions - * @author ExpressionEngine Dev Team + * @author ExpressionEngine Dev Team */ class CI_Session_native extends CI_Session_driver { /** * Initialize session driver object * - * @access protected + * @access protected * @return void */ protected function initialize() @@ -126,8 +126,8 @@ class CI_Session_native extends CI_Session_driver { /** * Save the session data * - * @access public - * @return void + * @access public + * @return void */ public function sess_save() { @@ -137,8 +137,8 @@ class CI_Session_native extends CI_Session_driver { /** * Destroy the current session * - * @access public - * @return void + * @access public + * @return void */ public function sess_destroy() { @@ -160,9 +160,9 @@ class CI_Session_native extends CI_Session_driver { * * Regenerate the session id * - * @access public - * @param boolean Destroy session data flag (default: false) - * @return void + * @access public + * @param boolean Destroy session data flag (default: false) + * @return void */ public function sess_regenerate($destroy = false) { @@ -173,8 +173,8 @@ class CI_Session_native extends CI_Session_driver { /** * Get a reference to user data array * - * @access public - * @return array Reference to userdata + * @access public + * @return array Reference to userdata */ public function &get_userdata() { -- cgit v1.2.3-24-g4f1b From 42b77a9a1a5d4ec7ceb94b421b12af9c442769ba Mon Sep 17 00:00:00 2001 From: dchill42 Date: Mon, 23 Jul 2012 11:28:42 -0400 Subject: Made cookie driver default and did miniscule code cleanup on drivers --- system/libraries/Session/Session.php | 2 +- system/libraries/Session/drivers/Session_cookie.php | 9 ++------- system/libraries/Session/drivers/Session_native.php | 3 --- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 94fb4b10a..474ca9c7a 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -84,7 +84,7 @@ class CI_Session extends CI_Driver_Library { // Get driver to load $key = 'sess_driver'; $driver = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); - if (!$driver) $driver = 'native'; + if (!$driver) $driver = 'cookie'; if (!in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers))) { $this->valid_drivers[] = 'Session_'.$driver; diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index 0dc109bd1..255a1ae3e 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -39,7 +39,6 @@ * @link http://codeigniter.com/user_guide/libraries/sessions.html */ class CI_Session_cookie extends CI_Session_driver { - /** * Whether to encrypt the session cookie * @@ -152,7 +151,6 @@ class CI_Session_cookie extends CI_Session_driver { */ public $time_reference = 'local'; - /** * Session data * @@ -186,7 +184,7 @@ class CI_Session_cookie extends CI_Session_driver { $this->CI =& get_instance(); // Set all the session preferences, which can either be set - // manually via the $params array above or via the config file + // manually via the $params array or via the config file foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', @@ -527,9 +525,7 @@ class CI_Session_cookie extends CI_Session_driver { // by pushing all userdata to the cookie. $cookie_data = NULL; - /* Changing the session ID during an AJAX call causes problems, - * so we'll only update our last_activity - */ + // Changing the session ID during an AJAX call causes problems, so we'll only update our last_activity if ($this->CI->input->is_ajax_request()) { $this->userdata['last_activity'] = $this->now; @@ -752,7 +748,6 @@ class CI_Session_cookie extends CI_Session_driver { log_message('debug', 'Session garbage collection performed.'); } } - } /* End of file Session_cookie.php */ diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index 09fb7f999..7fbe9f89e 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -182,9 +182,6 @@ class CI_Session_native extends CI_Session_driver { return $_SESSION; } } -// END CI_Session_native Class - /* End of file Session_native.php */ /* Location: ./system/libraries/Session/drivers/Session_native.php */ -?> -- cgit v1.2.3-24-g4f1b From 77ee3fdac34d317b600a269e0b845588c88fa4c5 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Tue, 24 Jul 2012 11:50:01 -0400 Subject: Cleaned up bangs and lowercase booleans, and fixed userdata return on not found to NULL --- system/libraries/Session/Session.php | 18 +++++++++--------- system/libraries/Session/drivers/Session_cookie.php | 2 +- system/libraries/Session/drivers/Session_native.php | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 474ca9c7a..9c887d88e 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -69,12 +69,12 @@ class CI_Session extends CI_Driver_Library { $drivers = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); if ($drivers) { - if (!is_array($drivers)) $drivers = array($drivers); + if ( ! is_array($drivers)) $drivers = array($drivers); // Add driver names to valid list foreach ($drivers as $driver) { - if (!in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers))) + if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers))) { $this->valid_drivers[] = $driver; } @@ -84,8 +84,8 @@ class CI_Session extends CI_Driver_Library { // Get driver to load $key = 'sess_driver'; $driver = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); - if (!$driver) $driver = 'cookie'; - if (!in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers))) + if ( ! $driver) $driver = 'cookie'; + if ( ! in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers))) { $this->valid_drivers[] = 'Session_'.$driver; } @@ -182,7 +182,7 @@ class CI_Session extends CI_Driver_Library { public function userdata($item) { // Return value or FALSE if not found - return (!isset($this->userdata[$item])) ? FALSE : $this->userdata[$item]; + return ( ! isset($this->userdata[$item])) ? NULL : $this->userdata[$item]; } /** @@ -193,7 +193,7 @@ class CI_Session extends CI_Driver_Library { public function all_userdata() { // Return entire array - return (!isset($this->userdata)) ? FALSE : $this->userdata; + return ( ! isset($this->userdata)) ? NULL : $this->userdata; } /** @@ -362,7 +362,7 @@ class CI_Session extends CI_Driver_Library { // Get or create expiration list $expirations = $this->userdata(self::EXPIRATION_KEY); - if (!$expirations) + if ( ! $expirations) { $expirations = array(); } @@ -392,7 +392,7 @@ class CI_Session extends CI_Driver_Library { { // Get expirations list $expirations = $this->userdata(self::EXPIRATION_KEY); - if (!$expirations || !count($expirations)) + if ( ! $expirations || ! count($expirations)) { // Nothing to do return; @@ -482,7 +482,7 @@ class CI_Session extends CI_Driver_Library { { // Get expirations list $expirations = $this->userdata(self::EXPIRATION_KEY); - if (!$expirations || !count($expirations)) + if ( ! $expirations || ! count($expirations)) { // Nothing to do return; diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index 255a1ae3e..e39ada052 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -516,7 +516,7 @@ class CI_Session_cookie extends CI_Session_driver { protected function _sess_update($force = FALSE) { // We only update the session every five minutes by default (unless forced) - if (!$force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) + if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) { return; } diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index 7fbe9f89e..8388e06b5 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -161,10 +161,10 @@ class CI_Session_native extends CI_Session_driver { * Regenerate the session id * * @access public - * @param boolean Destroy session data flag (default: false) + * @param boolean Destroy session data flag (default: FALSE) * @return void */ - public function sess_regenerate($destroy = false) + public function sess_regenerate($destroy = FALSE) { // Just regenerate id, passing destroy flag session_regenerate_id($destroy); -- cgit v1.2.3-24-g4f1b From c58722535e0358367f351c168480ef98a033264c Mon Sep 17 00:00:00 2001 From: dchill42 Date: Mon, 30 Jul 2012 14:53:11 -0400 Subject: Fixed _parent references and several minor bugs --- system/libraries/Driver.php | 2 +- system/libraries/Session/Session.php | 14 +++++----- .../libraries/Session/drivers/Session_cookie.php | 30 +++++++++++++++++++--- .../libraries/Session/drivers/Session_native.php | 2 +- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index 86b233a15..1d084c8e4 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -65,7 +65,7 @@ class CI_Driver_Library { public function __get($child) { // Try to load the driver - return load_driver($child); + return $this->load_driver($child); } /** diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 9c887d88e..734334249 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -64,7 +64,7 @@ class CI_Session extends CI_Driver_Library { // Get valid drivers list $CI =& get_instance(); - $this->valid_drivers = array('CI_Session_native', 'CI_Session_cookie'); + $this->valid_drivers = array('Session_native', 'Session_cookie'); $key = 'sess_valid_drivers'; $drivers = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); if ($drivers) @@ -131,7 +131,7 @@ class CI_Session extends CI_Driver_Library { public function select_driver($driver) { // Validate driver name - $lowername = strtolower($driver); + $lowername = strtolower(str_replace('CI_', '', $driver)); if (in_array($lowername, array_map('strtolower', $this->valid_drivers))) { // See if regular or lowercase variant is loaded @@ -177,11 +177,11 @@ class CI_Session extends CI_Driver_Library { * Fetch a specific item from the session array * * @param string Item key - * @return string Item value + * @return string Item value or NULL if not found */ public function userdata($item) { - // Return value or FALSE if not found + // Return value or NULL if not found return ( ! isset($this->userdata[$item])) ? NULL : $this->userdata[$item]; } @@ -208,7 +208,7 @@ class CI_Session extends CI_Driver_Library { // loop through all userdata foreach ($this->all_userdata() as $key => $val) { - // if it contains flashdata, add it + // if it contains flashdata, add it if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE) { $out[$key] = $val; @@ -543,7 +543,7 @@ abstract class CI_Session_driver extends CI_Driver { // Call base class decorate first parent::decorate($parent); - // Call initialize method now that driver has access to $this->parent + // Call initialize method now that driver has access to $this->_parent $this->initialize(); } @@ -559,7 +559,7 @@ abstract class CI_Session_driver extends CI_Driver { public function __call($method, $args = array()) { // Make sure the parent library uses this driver - $this->parent->select_driver(get_class($this)); + $this->_parent->select_driver(get_class($this)); return parent::__call($method, $args); } diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index e39ada052..19ccd417d 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -190,13 +190,13 @@ class CI_Session_cookie extends CI_Session_driver { 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) { - $this->$key = isset($this->parent->params[$key]) ? $this->parent->params[$key] : + $this->$key = isset($this->_parent->params[$key]) ? $this->_parent->params[$key] : $this->CI->config->item($key); } if ($this->encryption_key === '') { - show_error('In order to use the Session Cookie driver you are required to set an encryption key '. + show_error('In order to use the Cookie Session driver you are required to set an encryption key '. 'in your config file.'); } @@ -309,7 +309,7 @@ class CI_Session_cookie extends CI_Session_driver { } // Kill the cookie - setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000), + $this->_setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000), $this->cookie_path, $this->cookie_domain, 0); // Kill session data @@ -632,10 +632,32 @@ class CI_Session_cookie extends CI_Session_driver { $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); // Set the cookie - setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain, + $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain, $this->cookie_secure, $this->cookie_httponly); } + /** + * Set a cookie with the system + * + * This abstraction of the setcookie call allows overriding for unit testing + * + * @access protected + * @param string Cookie name + * @param string Cookie value + * @param int Expiration time + * @param string Cookie path + * @param string Cookie domain + * @param bool Secure connection flag + * @param bool HTTP protocol only flag + * @return void + */ + protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = false, + $httponly = false) + { + // Set the cookie + setcookie($name, $value, $expire, $path, $domain, $secure, $httponly); + } + /** * Serialize an array * diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index 8388e06b5..27db942eb 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -39,7 +39,7 @@ class CI_Session_native extends CI_Session_driver { foreach (array('sess_cookie_name', 'sess_expire_on_close', 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', 'cookie_prefix', 'cookie_path', 'cookie_domain') as $key) { - $config[$key] = isset($this->parent->params[$key]) ? $this->parent->params[$key] : $CI->config->item($key); + $config[$key] = isset($this->_parent->params[$key]) ? $this->_parent->params[$key] : $CI->config->item($key); } // Set session name, if specified -- cgit v1.2.3-24-g4f1b From b185537938061bf9b8f132f9f3c3992e12902be8 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Tue, 31 Jul 2012 09:32:23 -0400 Subject: Fixed userdata synchronization, loaded driver check, and all_flashdata keys --- system/libraries/Session/Session.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 734334249..68819a665 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -95,7 +95,6 @@ class CI_Session extends CI_Driver_Library { // Load driver and get array reference $this->load_driver($driver); - $this->userdata =& $this->current->get_userdata(); // Delete 'old' flashdata (from last request) $this->_flashdata_sweep(); @@ -119,6 +118,7 @@ class CI_Session extends CI_Driver_Library { { // Save reference to most recently loaded driver as library default $this->current = parent::load_driver($driver); + $this->userdata =& $this->current->get_userdata(); return $this->current; } @@ -134,14 +134,12 @@ class CI_Session extends CI_Driver_Library { $lowername = strtolower(str_replace('CI_', '', $driver)); if (in_array($lowername, array_map('strtolower', $this->valid_drivers))) { - // See if regular or lowercase variant is loaded - if (class_exists($driver)) - { - $this->current = $this->$driver; - } - else if (class_exists($lowername)) + // See if driver is loaded + $child = str_replace($this->lib_name.'_', '', $driver); + if (isset($this->$child)) { - $this->current = $this->$lowername; + $this->current = $this->$child; + $this->userdata =& $this->current->get_userdata(); } else { @@ -211,6 +209,7 @@ class CI_Session extends CI_Driver_Library { // if it contains flashdata, add it if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE) { + $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key); $out[$key] = $val; } } -- cgit v1.2.3-24-g4f1b From 57486009573a86d9e286a49c92216ba17aae0d5a Mon Sep 17 00:00:00 2001 From: dchill42 Date: Tue, 31 Jul 2012 09:39:53 -0400 Subject: Added Session driver library unit tests and added driver library autoloading to test framework --- tests/codeigniter/libraries/Session_test.php | 304 +++++++++++++++++++++++++++ tests/mocks/autoloader.php | 23 +- tests/mocks/libraries/session.php | 43 ++++ 3 files changed, 365 insertions(+), 5 deletions(-) create mode 100644 tests/codeigniter/libraries/Session_test.php create mode 100644 tests/mocks/libraries/session.php diff --git a/tests/codeigniter/libraries/Session_test.php b/tests/codeigniter/libraries/Session_test.php new file mode 100644 index 000000000..db7efb6b7 --- /dev/null +++ b/tests/codeigniter/libraries/Session_test.php @@ -0,0 +1,304 @@ + 0, 'use_only_cookies' => 0, 'cache_limiter' => false); + protected $setting_vals = array(); + protected $cookie_vals; + protected $session; + + /** + * Set up test framework + */ + public function set_up() + { + // Override settings + foreach ($this->settings as $name => $value) { + $this->setting_vals[$name] = ini_get('session.'.$name); + ini_set('session.'.$name, $value); + } + + // Start with clean environment + $this->cookie_vals = $_COOKIE; + $_COOKIE = array(); + + // Establish necessary support classes + $obj = new stdClass; + foreach (array('config' => 'cfg', 'load' => 'load', 'input' => 'in') as $name => $abbr) { + $class = $this->ci_core_class($abbr); + $obj->$name = new $class; + } + $this->ci_instance($obj); + + // Attach session instance locally + $config = array('sess_encrypt_cookie' => FALSE, 'sess_use_database' => FALSE, 'sess_table_name' => '', + 'sess_expiration' => 7200, 'sess_expire_on_close' => FALSE, 'sess_match_ip' => FALSE, + 'sess_match_useragent' => TRUE, 'sess_cookie_name' => 'ci_session', 'cookie_path' => '', + 'cookie_domain' => '', 'cookie_secure' => FALSE, 'cookie_httponly' => FALSE, 'sess_time_to_update' => 300, + 'time_reference' => 'local', 'cookie_prefix' => '', 'encryption_key' => 'foobar', + 'sess_valid_drivers' => array('Mock_Libraries_Session_native', 'Mock_Libraries_Session_cookie')); + $this->session = new Mock_Libraries_Session($config); + } + + /** + * Tear down test framework + */ + public function tear_down() + { + // Restore environment + if (session_id()) session_destroy(); + $_SESSION = array(); + $_COOKIE = $this->cookie_vals; + + // Restore settings + foreach ($this->settings as $name => $value) { + ini_set('session.'.$name, $this->setting_vals[$name]); + } + } + + /** + * Test set_userdata() function + */ + public function test_set_userdata() + { + // Set a userdata message for each driver + $cmsg = 'Some test data'; + $this->session->cookie->set_userdata('test1', $cmsg); + $nmsg = 'Other test data'; + $this->session->native->set_userdata('test1', $nmsg); + + // Verify independent messages + $this->assertEquals($this->session->cookie->userdata('test1'), $cmsg); + $this->assertEquals($this->session->native->userdata('test1'), $nmsg); + } + + /** + * Test the has_userdata() function + */ + public function test_has_userdata() + { + // Set a userdata message for each driver + $cmsg = 'My test data'; + $this->session->cookie->set_userdata('test2', $cmsg); + $nmsg = 'Your test data'; + $this->session->native->set_userdata('test2', $nmsg); + + // Verify independent messages + $this->assertTrue($this->session->cookie->has_userdata('test2')); + $this->assertTrue($this->session->native->has_userdata('test2')); + } + + /** + * Test the all_userdata() function + */ + public function test_all_userdata() + { + // Set a specific series of data for each driver + $cdata = array('one' => 'first', 'two' => 'second', 'three' => 'third', 'foo' => 'bar', 'bar' => 'baz'); + $this->session->cookie->set_userdata($cdata); + $ndata = array('one' => 'gold', 'two' => 'silver', 'three' => 'bronze', 'foo' => 'baz', 'bar' => 'foo'); + $this->session->native->set_userdata($ndata); + + // Make sure all values are present + $call = $this->session->cookie->all_userdata(); + foreach ($cdata as $key => $value) { + $this->assertEquals($value, $call[$key]); + } + $nall = $this->session->native->all_userdata(); + foreach ($ndata as $key => $value) { + $this->assertEquals($value, $nall[$key]); + } + } + + /** + * Test the unset_userdata() function + */ + public function test_unset_userdata() + { + // Set a userdata message for each driver + $cmsg = 'Other test data'; + $this->session->cookie->set_userdata('test3', $cmsg); + $nmsg = 'Sundry test data'; + $this->session->native->set_userdata('test3', $nmsg); + + // Verify independent messages + $this->assertEquals($this->session->cookie->userdata('test3'), $cmsg); + $this->assertEquals($this->session->native->userdata('test3'), $nmsg); + + // Unset them and verify absence + $this->session->cookie->unset_userdata('test3'); + $this->session->native->unset_userdata('test3'); + $this->assertEquals($this->session->cookie->userdata('test3'), NULL); + $this->assertEquals($this->session->native->userdata('test3'), NULL); + } + + /** + * Test the set_flashdata() function + */ + public function test_set_flashdata() + { + // Set flashdata message for each driver + $cmsg = 'Some flash data'; + $this->session->cookie->set_flashdata('test4', $cmsg); + $nmsg = 'Other flash data'; + $this->session->native->set_flashdata('test4', $nmsg); + + // Simulate page reload + $this->session->cookie->reload(); + $this->session->native->reload(); + + // Verify independent messages + $this->assertEquals($this->session->cookie->flashdata('test4'), $cmsg); + $this->assertEquals($this->session->native->flashdata('test4'), $nmsg); + + // Simulate next page reload + $this->session->cookie->reload(); + $this->session->native->reload(); + + // Verify absence of messages + $this->assertEquals($this->session->cookie->flashdata('test4'), NULL); + $this->assertEquals($this->session->native->flashdata('test4'), NULL); + } + + /** + * Test the keep_flashdata() function + */ + public function test_keep_flashdata() + { + // Set flashdata message for each driver + $cmsg = 'My flash data'; + $this->session->cookie->set_flashdata('test5', $cmsg); + $nmsg = 'Your flash data'; + $this->session->native->set_flashdata('test5', $nmsg); + + // Simulate page reload and verify independent messages + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($this->session->cookie->flashdata('test5'), $cmsg); + $this->assertEquals($this->session->native->flashdata('test5'), $nmsg); + + // Keep messages + $this->session->cookie->keep_flashdata('test5'); + $this->session->native->keep_flashdata('test5'); + + // Simulate next page reload and verify message persistence + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($this->session->cookie->flashdata('test5'), $cmsg); + $this->assertEquals($this->session->native->flashdata('test5'), $nmsg); + + // Simulate next page reload and verify absence of messages + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($this->session->cookie->flashdata('test5'), NULL); + $this->assertEquals($this->session->native->flashdata('test5'), NULL); + } + + /** + * Test the all_flashdata() function + */ + public function test_all_flashdata() + { + // Set a specific series of data for each driver + $cdata = array('one' => 'first', 'two' => 'second', 'three' => 'third', 'foo' => 'bar', 'bar' => 'baz'); + $this->session->cookie->set_flashdata($cdata); + $ndata = array('one' => 'gold', 'two' => 'silver', 'three' => 'bronze', 'foo' => 'baz', 'bar' => 'foo'); + $this->session->native->set_flashdata($ndata); + + // Simulate page reload and make sure all values are present + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($cdata, $this->session->cookie->all_flashdata()); + $this->assertEquals($ndata, $this->session->native->all_flashdata()); + } + + /** + * Test the set_tempdata() function + */ + public function test_set_tempdata() + { + // Set tempdata message for each driver - 1 second timeout + $cmsg = 'Some temp data'; + $this->session->cookie->set_tempdata('test6', $cmsg, 1); + $nmsg = 'Other temp data'; + $this->session->native->set_tempdata('test6', $nmsg, 1); + + // Simulate page reload and verify independent messages + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($this->session->cookie->tempdata('test6'), $cmsg); + $this->assertEquals($this->session->native->tempdata('test6'), $nmsg); + + // Wait 2 seconds, simulate page reload and verify message absence + sleep(2); + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($this->session->cookie->tempdata('test6'), NULL); + $this->assertEquals($this->session->native->tempdata('test6'), NULL); + } + + /** + * Test the unset_tempdata() function + */ + public function test_unset_tempdata() + { + // Set tempdata message for each driver - 1 second timeout + $cmsg = 'My temp data'; + $this->session->cookie->set_tempdata('test7', $cmsg, 1); + $nmsg = 'Your temp data'; + $this->session->native->set_tempdata('test7', $nmsg, 1); + + // Verify independent messages + $this->assertEquals($this->session->cookie->tempdata('test7'), $cmsg); + $this->assertEquals($this->session->native->tempdata('test7'), $nmsg); + + // Unset data and verify message absence + $this->session->cookie->unset_tempdata('test7'); + $this->session->native->unset_tempdata('test7'); + $this->assertEquals($this->session->cookie->tempdata('test7'), NULL); + $this->assertEquals($this->session->native->tempdata('test7'), NULL); + } + + /** + * Test the sess_regenerate() function + */ + public function test_sess_regenerate() + { + // Get current session id, regenerate, and compare + // Cookie driver + $oldid = $this->session->cookie->userdata('session_id'); + $this->session->cookie->sess_regenerate(); + $newid = $this->session->cookie->userdata('session_id'); + $this->assertFalse($oldid === $newid); + + // Native driver - bug #55267 (https://bugs.php.net/bug.php?id=55267) prevents testing this + /*$oldid = session_id(); + $this->session->native->sess_regenerate(); + $oldid = session_id(); + $this->assertFalse($oldid === $newid);*/ + } + + /** + * Test the sess_destroy() function + */ + public function test_sess_destroy() + { + // Set a userdata message, destroy session, and verify absence + $msg = 'More test data'; + + // Cookie driver + $this->session->cookie->set_userdata('test8', $msg); + $this->assertEquals($this->session->cookie->userdata('test8'), $msg); + $this->session->cookie->sess_destroy(); + $this->assertEquals($this->session->cookie->userdata('test8'), NULL); + + // Native driver + $this->session->native->set_userdata('test8', $msg); + $this->assertEquals($this->session->native->userdata('test8'), $msg); + $this->session->native->sess_destroy(); + $this->assertEquals($this->session->native->userdata('test8'), NULL); + } +} + diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php index be1c2220c..88d016bba 100644 --- a/tests/mocks/autoloader.php +++ b/tests/mocks/autoloader.php @@ -26,10 +26,14 @@ function autoload($class) 'Email', 'Encrypt', 'Form_validation', 'Ftp', 'Image_lib', 'Javascript', 'Log', 'Migration', 'Pagination', - 'Parser', 'Profiler', 'Session', - 'Table', 'Trackback', 'Typography', - 'Unit_test', 'Upload', 'User_agent', - 'Xmlrpc', 'Zip', + 'Parser', 'Profiler', 'Table', + 'Trackback', 'Typography', 'Unit_test', + 'Upload', 'User_agent', 'Xmlrpc', + 'Zip', + ); + + $ci_drivers = array( + 'Session', ); if (strpos($class, 'Mock_') === 0) @@ -52,6 +56,15 @@ function autoload($class) $dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR; $class = ($subclass === 'Driver_Library') ? 'Driver' : $subclass; } + elseif (in_array($subclass, $ci_drivers)) + { + $dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR.$subclass.DIRECTORY_SEPARATOR; + $class = $subclass; + } + elseif (in_array(($parent = strtok($subclass, '_')), $ci_drivers)) { + $dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR.$parent.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR; + $class = $subclass; + } elseif (preg_match('/^CI_DB_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 3) { $driver_path = BASEPATH.'database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR; @@ -91,4 +104,4 @@ function autoload($class) } include_once($file); -} \ No newline at end of file +} diff --git a/tests/mocks/libraries/session.php b/tests/mocks/libraries/session.php new file mode 100644 index 000000000..9d6feee42 --- /dev/null +++ b/tests/mocks/libraries/session.php @@ -0,0 +1,43 @@ +_flashdata_sweep(); + $this->_flashdata_mark(); + $this->_tempdata_sweep(); + } +} + +/** + * Mock cookie driver to overload cookie setting + */ +class Mock_Libraries_Session_cookie extends CI_Session_cookie { + /** + * Overload _setcookie to manage $_COOKIE values, since actual cookies can't be set in unit testing + */ + protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = false, + $httponly = false) + { + if (empty($value) || $expire <= time()) { + // Clear cookie + unset($_COOKIE[$name]); + } + else { + // Set cookie + $_COOKIE[$name] = $value; + } + } +} + +/** + * Mock native driver (just for consistency in loading) + */ +class Mock_Libraries_Session_native extends CI_Session_native { } + -- cgit v1.2.3-24-g4f1b From 4153c928229ff174743b78472ae27138cd715efe Mon Sep 17 00:00:00 2001 From: dchill42 Date: Tue, 31 Jul 2012 10:38:21 -0400 Subject: Coding standard cleanup and added userdata resync on sess_regenerate() --- tests/codeigniter/libraries/Session_test.php | 73 +++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/tests/codeigniter/libraries/Session_test.php b/tests/codeigniter/libraries/Session_test.php index db7efb6b7..5d58a9e69 100644 --- a/tests/codeigniter/libraries/Session_test.php +++ b/tests/codeigniter/libraries/Session_test.php @@ -4,7 +4,11 @@ * Session driver library unit test */ class Session_test extends CI_TestCase { - protected $settings = array('use_cookies' => 0, 'use_only_cookies' => 0, 'cache_limiter' => false); + protected $settings = array( + 'use_cookies' => 0, + 'use_only_cookies' => 0, + 'cache_limiter' => false + ); protected $setting_vals = array(); protected $cookie_vals; protected $session; @@ -26,19 +30,40 @@ class Session_test extends CI_TestCase { // Establish necessary support classes $obj = new stdClass; - foreach (array('config' => 'cfg', 'load' => 'load', 'input' => 'in') as $name => $abbr) { + $classes = array( + 'config' => 'cfg', + 'load' => 'load', + 'input' => 'in' + ); + foreach ($classes as $name => $abbr) { $class = $this->ci_core_class($abbr); $obj->$name = new $class; } $this->ci_instance($obj); // Attach session instance locally - $config = array('sess_encrypt_cookie' => FALSE, 'sess_use_database' => FALSE, 'sess_table_name' => '', - 'sess_expiration' => 7200, 'sess_expire_on_close' => FALSE, 'sess_match_ip' => FALSE, - 'sess_match_useragent' => TRUE, 'sess_cookie_name' => 'ci_session', 'cookie_path' => '', - 'cookie_domain' => '', 'cookie_secure' => FALSE, 'cookie_httponly' => FALSE, 'sess_time_to_update' => 300, - 'time_reference' => 'local', 'cookie_prefix' => '', 'encryption_key' => 'foobar', - 'sess_valid_drivers' => array('Mock_Libraries_Session_native', 'Mock_Libraries_Session_cookie')); + $config = array( + 'sess_encrypt_cookie' => FALSE, + 'sess_use_database' => FALSE, + 'sess_table_name' => '', + 'sess_expiration' => 7200, + 'sess_expire_on_close' => FALSE, + 'sess_match_ip' => FALSE, + 'sess_match_useragent' => TRUE, + 'sess_cookie_name' => 'ci_session', + 'cookie_path' => '', + 'cookie_domain' => '', + 'cookie_secure' => FALSE, + 'cookie_httponly' => FALSE, + 'sess_time_to_update' => 300, + 'time_reference' => 'local', + 'cookie_prefix' => '', + 'encryption_key' => 'foobar', + 'sess_valid_drivers' => array( + 'Mock_Libraries_Session_native', + 'Mock_Libraries_Session_cookie' + ) + ); $this->session = new Mock_Libraries_Session($config); } @@ -96,9 +121,21 @@ class Session_test extends CI_TestCase { public function test_all_userdata() { // Set a specific series of data for each driver - $cdata = array('one' => 'first', 'two' => 'second', 'three' => 'third', 'foo' => 'bar', 'bar' => 'baz'); + $cdata = array( + 'one' => 'first', + 'two' => 'second', + 'three' => 'third', + 'foo' => 'bar', + 'bar' => 'baz' + ); + $ndata = array( + 'one' => 'gold', + 'two' => 'silver', + 'three' => 'bronze', + 'foo' => 'baz', + 'bar' => 'foo' + ); $this->session->cookie->set_userdata($cdata); - $ndata = array('one' => 'gold', 'two' => 'silver', 'three' => 'bronze', 'foo' => 'baz', 'bar' => 'foo'); $this->session->native->set_userdata($ndata); // Make sure all values are present @@ -202,9 +239,21 @@ class Session_test extends CI_TestCase { public function test_all_flashdata() { // Set a specific series of data for each driver - $cdata = array('one' => 'first', 'two' => 'second', 'three' => 'third', 'foo' => 'bar', 'bar' => 'baz'); + $cdata = array( + 'one' => 'first', + 'two' => 'second', + 'three' => 'third', + 'foo' => 'bar', + 'bar' => 'baz' + ); + $ndata = array( + 'one' => 'gold', + 'two' => 'silver', + 'three' => 'bronze', + 'foo' => 'baz', + 'bar' => 'foo' + ); $this->session->cookie->set_flashdata($cdata); - $ndata = array('one' => 'gold', 'two' => 'silver', 'three' => 'bronze', 'foo' => 'baz', 'bar' => 'foo'); $this->session->native->set_flashdata($ndata); // Simulate page reload and make sure all values are present -- cgit v1.2.3-24-g4f1b From 2642920e4781db091309ab97d0ff43c22e7c7e44 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Tue, 31 Jul 2012 10:55:07 -0400 Subject: Damn, missed files on last commit --- system/libraries/Session/Session.php | 16 ++++-- .../libraries/Session/drivers/Session_cookie.php | 61 +++++++++++++++++----- .../libraries/Session/drivers/Session_native.php | 16 ++++-- 3 files changed, 72 insertions(+), 21 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 68819a665..41539a598 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -64,7 +64,10 @@ class CI_Session extends CI_Driver_Library { // Get valid drivers list $CI =& get_instance(); - $this->valid_drivers = array('Session_native', 'Session_cookie'); + $this->valid_drivers = array( + 'Session_native', + 'Session_cookie' + ); $key = 'sess_valid_drivers'; $drivers = (isset($params[$key])) ? $params[$key] : $CI->config->item($key); if ($drivers) @@ -116,7 +119,7 @@ class CI_Session extends CI_Driver_Library { */ public function load_driver($driver) { - // Save reference to most recently loaded driver as library default + // 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; @@ -138,11 +141,13 @@ class CI_Session extends CI_Driver_Library { $child = str_replace($this->lib_name.'_', '', $driver); if (isset($this->$child)) { + // Make driver current and sync userdata $this->current = $this->$child; - $this->userdata =& $this->current->get_userdata(); + $this->userdata =& $this->current->get_userdata(); } else { + // Load new driver $this->load_driver($driver); } } @@ -167,8 +172,9 @@ class CI_Session extends CI_Driver_Library { */ public function sess_regenerate($destroy = false) { - // Just call regenerate on driver + // Call regenerate on driver and resync userdata $this->current->sess_regenerate($destroy); + $this->userdata =& $this->current->get_userdata(); } /** @@ -209,7 +215,7 @@ class CI_Session extends CI_Driver_Library { // if it contains flashdata, add it if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE) { - $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key); + $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key); $out[$key] = $val; } } diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index 19ccd417d..8ac92e432 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -72,7 +72,7 @@ class CI_Session_cookie extends CI_Session_driver { * * @var bool */ - public $sess_expire_on_close = FALSE; + public $sess_expire_on_close = FALSE; /** * Whether to match session on ip address @@ -86,7 +86,7 @@ class CI_Session_cookie extends CI_Session_driver { * * @var bool */ - public $sess_match_useragent = TRUE; + public $sess_match_useragent = TRUE; /** * Name of session cookie @@ -107,7 +107,7 @@ class CI_Session_cookie extends CI_Session_driver { * * @var string */ - public $cookie_path = ''; + public $cookie_path = ''; /** * Session cookie domain @@ -156,7 +156,7 @@ class CI_Session_cookie extends CI_Session_driver { * * @var array */ - public $userdata = array(); + public $userdata = array(); /** * Reference to CodeIgniter instance @@ -185,10 +185,25 @@ class CI_Session_cookie extends CI_Session_driver { // Set all the session preferences, which can either be set // manually via the $params array or via the config file - foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', - 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', - 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', - 'encryption_key') as $key) + $prefs = array( + 'sess_encrypt_cookie', + 'sess_use_database', + 'sess_table_name', + 'sess_expiration', + 'sess_expire_on_close', + 'sess_match_ip', + 'sess_match_useragent', + 'sess_cookie_name', + 'cookie_path', + 'cookie_domain', + 'cookie_secure', + 'cookie_httponly', + 'sess_time_to_update', + 'time_reference', + 'cookie_prefix', + 'encryption_key' + ); + foreach ($prefs as $key) { $this->$key = isset($this->_parent->params[$key]) ? $this->_parent->params[$key] : $this->CI->config->item($key); @@ -265,7 +280,13 @@ class CI_Session_cookie extends CI_Session_driver { // Before continuing, we need to determine if there is any custom data to deal with. // Let's determine this by removing the default indexes to see if there's anything left in the array // and set the session data while we're at it - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) + $defaults = array( + 'session_id', + 'ip_address', + 'user_agent', + 'last_activity' + ); + foreach ($defaults as $val) { unset($custom_userdata[$val]); $cookie_userdata[$val] = $this->userdata[$val]; @@ -285,8 +306,10 @@ class CI_Session_cookie extends CI_Session_driver { // Run the update query $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->update($this->sess_table_name, - array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata)); + $this->CI->db->update($this->sess_table_name, array( + 'last_activity' => $this->userdata['last_activity'], + 'user_data' => $custom_userdata + )); // Write the cookie. Notice that we manually pass the cookie data array to the // _set_cookie() function. Normally that function will store $this->userdata, but @@ -535,7 +558,13 @@ class CI_Session_cookie extends CI_Session_driver { { // set cookie explicitly to only have our session data $cookie_data = array(); - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) + $defaults = array( + 'session_id', + 'ip_address', + 'user_agent', + 'last_activity' + ); + foreach ($defaults as $val) { $cookie_data[$val] = $this->userdata[$val]; } @@ -570,7 +599,13 @@ class CI_Session_cookie extends CI_Session_driver { { // set cookie explicitly to only have our session data $cookie_data = array(); - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) + $defaults = array( + 'session_id', + 'ip_address', + 'user_agent', + 'last_activity' + ); + foreach ($defaults as $val) { $cookie_data[$val] = $this->userdata[$val]; } diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index 27db942eb..356deb4dc 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -36,10 +36,20 @@ class CI_Session_native extends CI_Session_driver { // Get config parameters $config = array(); $CI =& get_instance(); - foreach (array('sess_cookie_name', 'sess_expire_on_close', 'sess_expiration', 'sess_match_ip', - 'sess_match_useragent', 'cookie_prefix', 'cookie_path', 'cookie_domain') as $key) + $prefs = array( + 'sess_cookie_name', + 'sess_expire_on_close', + 'sess_expiration', + 'sess_match_ip', + 'sess_match_useragent', + 'cookie_prefix', + 'cookie_path', + 'cookie_domain' + ); + foreach ($prefs as $key) { - $config[$key] = isset($this->_parent->params[$key]) ? $this->_parent->params[$key] : $CI->config->item($key); + $config[$key] = isset($this->_parent->params[$key]) ? $this->_parent->params[$key] : + $CI->config->item($key); } // Set session name, if specified -- cgit v1.2.3-24-g4f1b From f79afb57b7f7bac62a79638f195560739e4a80ef Mon Sep 17 00:00:00 2001 From: dchill42 Date: Wed, 8 Aug 2012 12:03:46 -0400 Subject: Added session_id to userdata and applied sess_time_to_update --- system/libraries/Session/drivers/Session_native.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index 356deb4dc..04c985574 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -42,6 +42,7 @@ class CI_Session_native extends CI_Session_driver { 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', + 'sess_time_to_update', 'cookie_prefix', 'cookie_path', 'cookie_domain' @@ -117,6 +118,14 @@ class CI_Session_native extends CI_Session_driver { session_start(); } + // Check for update time + if ($config['sess_time_to_update'] && isset($_SESSION['last_activity']) && + ($_SESSION['last_activity'] + $config['sess_time_to_update']) < $now) + { + // Regenerate ID, but don't destroy session + $this->sess_regenerate(FALSE); + } + // Set activity time $_SESSION['last_activity'] = $now; @@ -131,6 +140,9 @@ class CI_Session_native extends CI_Session_driver { // Store user agent string $_SESSION['user_agent'] = trim(substr($CI->input->user_agent(), 0, 50)); } + + // Make session ID available + $_SESSION['session_id'] = session_id(); } /** @@ -178,6 +190,7 @@ class CI_Session_native extends CI_Session_driver { { // Just regenerate id, passing destroy flag session_regenerate_id($destroy); + $_SESSION['session_id'] = session_id(); } /** -- cgit v1.2.3-24-g4f1b From 5628ba0efca7a631012fef91e259b92d7d807af1 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Wed, 8 Aug 2012 12:05:45 -0400 Subject: Relocated driver base class inclusion so drivers can be loaded with library() --- system/core/Loader.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/system/core/Loader.php b/system/core/Loader.php index ea81c6f26..a62cf06f5 100644 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -409,8 +409,8 @@ class CI_Loader { * 1. The name of the "view" file to be included. * 2. An associative array of data to be extracted for use in the view. * 3. TRUE/FALSE - whether to return the data or load it. In - * some cases it's advantageous to be able to return data so that - * a developer can process it in some way. + * some cases it's advantageous to be able to return data so that + * a developer can process it in some way. * * @param string * @param array @@ -636,12 +636,6 @@ class CI_Loader { return FALSE; } - if ( ! class_exists('CI_Driver_Library')) - { - // we aren't instantiating an object here, that'll be done by the Library itself - require BASEPATH.'libraries/Driver.php'; - } - if ($library === '') { return FALSE; @@ -837,10 +831,10 @@ class CI_Loader { * We buffer the output for two reasons: * 1. Speed. You get a significant speed boost. * 2. So that the final rendered template can be post-processed by - * the output class. Why do we need post processing? For one thing, - * in order to show the elapsed page load time. Unless we can - * intercept the content right before it's sent to the browser and - * then stop the timer it won't be accurate. + * the output class. Why do we need post processing? For one thing, + * in order to show the elapsed page load time. Unless we can + * intercept the content right before it's sent to the browser and + * then stop the timer it won't be accurate. */ ob_start(); @@ -915,6 +909,13 @@ class CI_Loader { // Get the filename from the path $class = substr($class, $last_slash); + + // Check for match and driver base class + if (strtolower($subdir) == strtolower($class) && ! class_exists('CI_Driver_Library')) + { + // We aren't instantiating an object here, just making the base class available + require BASEPATH.'libraries/Driver.php'; + } } // We'll test for both lowercase and capitalized versions of the file name @@ -996,7 +997,6 @@ class CI_Loader { $this->_ci_loaded_files[] = $filepath; return $this->_ci_init_class($class, '', $params, $object_name); } - } // END FOREACH // One last attempt. Maybe the library is in a subdirectory, but it wasn't specified? -- cgit v1.2.3-24-g4f1b From 0e88408d0965ee539d9af3ff7eca5415d3276c74 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Sat, 11 Aug 2012 20:10:17 -0400 Subject: Updated comments about default driver --- system/libraries/Session/Session.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 41539a598..97eab803f 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -18,8 +18,8 @@ * CI_Session Class * * The user interface defined by EllisLabs, now with puggable drivers to manage different storage mechanisms. - * By default, the native PHP session driver will load, but the 'sess_driver' config/param item (see above) can be - * used to specify the 'cookie' driver, or any other you might create. + * 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. -- cgit v1.2.3-24-g4f1b From 3169f26fe6b5e23d5ab5d791143d1dd51d78f80d Mon Sep 17 00:00:00 2001 From: dchill42 Date: Sat, 11 Aug 2012 20:12:05 -0400 Subject: Updated Loader and Session documentation --- user_guide_src/source/index.rst | 3 +- user_guide_src/source/libraries/loader.rst | 71 +++++- user_guide_src/source/libraries/sessions.rst | 338 ++++++++++++++++++++------- 3 files changed, 328 insertions(+), 84 deletions(-) diff --git a/user_guide_src/source/index.rst b/user_guide_src/source/index.rst index e42425bab..35089703f 100644 --- a/user_guide_src/source/index.rst +++ b/user_guide_src/source/index.rst @@ -80,6 +80,7 @@ Driver Reference - :doc:`libraries/caching` - :doc:`database/index` - :doc:`libraries/javascript` +- :doc:`libraries/sessions` **************** Helper Reference @@ -119,4 +120,4 @@ Contributing to CodeIgniter documentation/index tutorial/index general/quick_reference - general/credits \ No newline at end of file + general/credits diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst index aadf9740a..5a17629d2 100644 --- a/user_guide_src/source/libraries/loader.rst +++ b/user_guide_src/source/libraries/loader.rst @@ -4,6 +4,7 @@ Loader Class Loader, as the name suggests, is used to load elements. These elements can be libraries (classes) :doc:`View files <../general/views>`, +:doc:`Drivers <../general/drivers>`, :doc:`Helpers <../general/helpers>`, :doc:`Models <../general/models>`, or your own files. @@ -74,6 +75,70 @@ Assigning a Library to a different object name If the third (optional) parameter is blank, the library will usually be assigned to an object with the same name as the library. For example, if +the library is named Calendar, it will be assigned to a variable named +$this->calendar. + +If you prefer to set your own class names you can pass its value to the +third parameter:: + + $this->load->library('calendar', '', 'my_calendar'); + + // Session class is now accessed using: + + $this->my_calendar + +Please take note, when multiple libraries are supplied in an array for +the first parameter, this parameter is discarded. + +$this->load->driver('parent_name', $config, 'object name') +=========================================================== + +This function is used to load driver libraries. Where parent_name is the +name of the parent class you want to load. + +As an example, if you would like to use sessions with CodeIgniter, the first +step is to load the session driver within your controller:: + + $this->load->driver('session'); + +Once loaded, the library will be ready for use, using +$this->session->*some_function*(). + +Driver files must be stored in a subdirectory within the main +"libraries" folder, or within your personal application/libraries +folder. The subdirectory must match the parent class name. Read the +:doc:`Drivers <../general/drivers>` description for details. + +Additionally, multiple driver libraries can be loaded at the same time by +passing an array of drivers to the load function. + +:: + + $this->load->driver(array('session', 'cache')); + +Setting options +--------------- + +The second (optional) parameter allows you to optionally pass +configuration settings. You will typically pass these as an array:: + + $config = array ( + 'sess_driver' => 'cookie', + 'sess_encrypt_cookie' => true, + 'encryption_key' => 'mysecretkey' + ); + + $this->load->driver('session', $config); + +Config options can usually also be set via a config file. Each library +is explained in detail in its own page, so please read the information +regarding each one you would like to use. + +Assigning a Driver to a different object name +---------------------------------------------- + +If the third (optional) parameter is blank, the library will be assigned +to an object with the same name as the parent class. For example, if the library is named Session, it will be assigned to a variable named $this->session. @@ -86,8 +151,8 @@ third parameter:: $this->my_session -Please take note, when multiple libraries are supplied in an array for -the first parameter, this parameter is discarded. +.. note:: Driver libraries may also be loaded with the library() method, + but it is faster to use driver() $this->load->view('file_name', $data, true/false) ================================================== @@ -281,4 +346,4 @@ calling add_package_path(). // Again without the second parameter: $this->load->add_package_path(APPPATH.'my_app', TRUE); $this->load->view('my_app_index'); // Loads - $this->load->view('welcome_message'); // Loads \ No newline at end of file + $this->load->view('welcome_message'); // Loads diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 5400524a9..7a27a8f34 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -1,29 +1,19 @@ -############# -Session Class -############# +############## +Session Driver +############## The Session class permits you maintain a user's "state" and track their -activity while they browse your site. The Session class stores session -information for each user as serialized (and optionally encrypted) data -in a cookie. It can also store the session data in a database table for -added security, as this permits the session ID in the user's cookie to -be matched against the stored session ID. By default only the cookie is -saved. If you choose to use the database option you'll need to create -the session table as indicated below. - -.. note:: The Session class does **not** utilize native PHP sessions. It - generates its own session data, offering more flexibility for - developers. - -.. note:: Even if you are not using encrypted sessions, you must set - an :doc:`encryption key <./encryption>` in your config file which is used - to aid in preventing session data manipulation. +activity while they browse your site. CodeIgniter offers two default +session drivers: the classic `Cookie Driver`_, and the `Native Driver`_, +which supports usage of the native PHP Session mechanism. In addition, +you may create your own `Custom Drivers`_ to store session data however +you wish, while still taking advantage of the features of the Session class. Initializing a Session ====================== Sessions will typically run globally with each page load, so the session -class must either be :doc:`initialized <../general/libraries>` in your +class must either be :doc:`initialized <../general/drivers>` in your :doc:`controller <../general/controllers>` constructors, or it can be :doc:`auto-loaded <../general/autoloader>` by the system. For the most part the session class will run unattended in the background, so simply @@ -31,22 +21,25 @@ initializing the class will cause it to read, create, and update sessions. To initialize the Session class manually in your controller constructor, -use the $this->load->library function:: +use the $this->load->driver function:: - $this->load->library('session'); + $this->load->driver('session'); Once loaded, the Sessions library object will be available using: $this->session +.. note:: For backward compatibility, the Session class may stil be loaded + using the $this->load->library function, but converting your applications + to use $this->load->driver is strongly recommended. + How do Sessions work? ===================== When a page is loaded, the session class will check to see if valid -session data exists in the user's session cookie. If sessions data does -**not** exist (or if it has expired) a new session will be created and -saved in the cookie. If a session does exist, its information will be -updated and the cookie will be updated. With each update, the -session_id will be regenerated. +session data exists in the user's session. If sessions data does **not** +exist (or if it has expired) a new session will be created and saved. +If a session does exist, its information will be updated. With each update, +the session_id will be regenerated. It's important for you to understand that once initialized, the Session class runs automatically. There is nothing you need to do to cause the @@ -79,19 +72,12 @@ prototype:: 'last_activity' => timestamp ) -If you have the encryption option enabled, the serialized array will be -encrypted before being stored in the cookie, making the data highly -secure and impervious to being read or altered by someone. More info -regarding encryption can be :doc:`found here `, although -the Session class will take care of initializing and encrypting the data -automatically. - -Note: Session cookies are only updated every five minutes by default to -reduce processor load. If you repeatedly reload a page you'll notice -that the "last activity" time only updates if five minutes or more has -passed since the last time the cookie was written. This time is -configurable by changing the $config['sess_time_to_update'] line in -your system/config/config.php file. +.. note:: Sessions are only updated every five minutes by default to + reduce processor load. If you repeatedly reload a page you'll notice + that the "last activity" time only updates if five minutes or more has + passed since the last time the cookie was written. This time is + configurable by changing the $config['sess_time_to_update'] line in + your system/config/config.php file. Retrieving Session Data ======================= @@ -106,7 +92,7 @@ fetch. For example, to fetch the session ID you will do this:: $session_id = $this->session->userdata('session_id'); -.. note:: The function returns FALSE (boolean) if the item you are +.. note:: The function returns NULL if the item you are trying to access does not exist. Adding Custom Session Data @@ -117,7 +103,7 @@ to it and it will be stored in the user's cookie. Why would you want to do this? Here's one example: Let's say a particular user logs into your site. Once authenticated, you -could add their username and email address to the session cookie, making +could add their username and email address to the session, making that data globally available to you without having to run a database query when you need it. @@ -144,11 +130,11 @@ supports this syntax. $this->session->set_userdata('some_name', 'some_value'); +If you want to verify that a userdata value exists, call has_userdata(). -.. note:: Cookies can only hold 4KB of data, so be careful not to exceed - the capacity. The encryption process in particular produces a longer - data string than the original so keep careful track of how much data you - are storing. +:: + + $this->session->has_userdata('some_name'); Retrieving All Session Data =========================== @@ -195,8 +181,8 @@ available for the next server request, and are then automatically cleared. These can be very useful, and are typically used for informational or status messages (for example: "record 2 deleted"). -Note: Flash variables are prefaced with "flash\_" so avoid this prefix -in your own session names. +.. note:: Flash variables are prefaced with "flash\_" so avoid this prefix + in your own session names. To add flashdata:: @@ -222,9 +208,162 @@ additional request, you can do so using the keep_flashdata() function. $this->session->keep_flashdata('item'); +Tempdata +======== + +CodeIgniter also supports "tempdata", or session data with a specific +expiration time. After the value expires, or the session expires or is +deleted, the value is automatically removed. + +To add tempdata:: + + $expire = 300; // Expire in 5 minutes + + $this->session->set_tempdata('item', 'value', $expire); + +You can also pass an array to set_tempdata():: + + $tempdata = array('newuser' => TRUE, 'message' => 'Thanks for joining!'); + + $this->session->set_tempdata($tempdata, '', $expire); + +.. note:: If the expiration is omitted or set to 0, the default expiration of + 5 minutes will be used. + +To read a tempdata variable:: + + $this->session->tempdata('item'); + +If you need to remove a tempdata value before it expires, +use unset_tempdata():: + + $this->session->unset_tempdata('item'); + +Destroying a Session +==================== + +To clear the current session:: + + $this->session->sess_destroy(); + +.. note:: This function should be the last one called, and even flash + variables will no longer be available. If you only want some items + destroyed and not all, use unset_userdata(). + +Session Preferences +=================== + +You'll find the following Session related preferences in your +application/config/config.php file: + +=========================== =============== =========================== ========================================================================== +Preference Default Options Description +=========================== =============== =========================== ========================================================================== +**sess_driver** cookie cookie/native/*custom* The initial session driver to load. +**sess_valid_drivers** cookie, native None Additional valid drivers which may be loaded. +**sess_cookie_name** ci_session None The name you want the session cookie saved as (data for Cookie driver or + session ID for Native driver). +**sess_expiration** 7200 None The number of seconds you would like the session to last. The default + value is 2 hours (7200 seconds). If you would like a non-expiring + session set the value to zero: 0 +**sess_expire_on_close** FALSE TRUE/FALSE (boolean) Whether to cause the session to expire automatically when the browser + window is closed. +**sess_encrypt_cookie** FALSE TRUE/FALSE (boolean) Whether to encrypt the session data (Cookie driver only). +**sess_use_database** FALSE TRUE/FALSE (boolean) Whether to save the session data to a database. You must create the + table before enabling this option (Cookie driver only). +**sess_table_name** ci_sessions Any valid SQL table name The name of the session database table (Cookie driver only). +**sess_time_to_update** 300 Time in seconds This options controls how often the session class will regenerate itself + and create a new session id. +**sess_match_ip** FALSE TRUE/FALSE (boolean) Whether to match the user's IP address when reading the session data. + Note that some ISPs dynamically changes the IP, so if you want a + non-expiring session you will likely set this to FALSE. +**sess_match_useragent** TRUE TRUE/FALSE (boolean) Whether to match the User Agent when reading the session data. +=========================== =============== =========================== ========================================================================== + +In addition to the values above, the cookie and native drivers apply the +following configuration values shared by the :doc:`Input ` and +:doc:`Security ` classes: + +=========================== =============== ========================================================================== +Preference Default Description +=========================== =============== ========================================================================== +**cookie_prefix** '' Set a cookie name prefix in order to avoid name collisions +**cookie_domain** '' The domain for which the session is applicable +**cookie_path** / The path to which the session is applicable +=========================== =============== ========================================================================== + +Session Drivers +=============== + +By default, the `Cookie Driver`_ is loaded when a session is initialized. +However, any valid driver may be selected with the $config['sess_driver'] +line in your config.php file. + +The session driver library comes with the cookie and native drivers +installed, and `Custom Drivers`_ may also be installed by the user. + +Typically, only one driver will be used at a time, but CodeIgniter does +support loading multiple drivers. If a specific valid driver is called, it +will be automatically loaded. Or, an additional driver may be explicitly +loaded by calling load_driver():: + + $this->session->load_driver('native'); + +The Session library keeps track of the most recently selected driver to call +for driver methods. Normally, session class methods are called directly on +the parent class, as illustrated above. However, any methods called through +a specific driver will select that driver before invoking the parent method. + +So, alternation between multiple drivers can be achieved by specifying which +driver to use for each call:: + + $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. The drivers maintain independent +sets of values, regardless of key names. + +A specific driver may also be explicitly selected for use by pursuant +methods with the select_driver() call:: + + $this->session->select_driver('native'); + + $this->session->userdata('item'); // Uses the native driver + +Cookie Driver +------------- + +The Cookie driver stores session information for each user as serialized +(and optionally encrypted) data in a cookie. It can also store the session +data in a database table for added security, as this permits the session ID +in the user's cookie to be matched against the stored session ID. By default +only the cookie is saved. If you choose to use the database option you'll +need to create the session table as indicated below. + +If you have the encryption option enabled, the serialized array will be +encrypted before being stored in the cookie, making the data highly +secure and impervious to being read or altered by someone. More info +regarding encryption can be :doc:`found here `, although +the Session class will take care of initializing and encrypting the data +automatically. + +.. note:: Even if you are not using encrypted sessions, you must set + an :doc:`encryption key <./encryption>` in your config file which is used + to aid in preventing session data manipulation. + +.. note:: Cookies can only hold 4KB of data, so be careful not to exceed + the capacity. The encryption process in particular produces a longer + data string than the original so keep careful track of how much data you + are storing. Saving Session Data to a Database -================================= +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ While the session data array stored in the user's cookie contains a Session ID, unless you store session data in a database there is no way @@ -267,44 +406,83 @@ session class:: $config['sess_table_name'] = 'ci_sessions'; -.. note:: The Session class has built-in garbage collection which clears +.. note:: The Cookie driver has built-in garbage collection which clears out expired sessions so you do not need to write your own routine to do it. -Destroying a Session -==================== +Native Driver +------------- -To clear the current session:: +The Native driver relies on native PHP sessions to store data in the +$_SESSION superglobal array. All stored values continue to be available +through $_SESSION, but flash- and temp- data items carry special prefixes. - $this->session->sess_destroy(); +Custom Drivers +-------------- -.. note:: This function should be the last one called, and even flash - variables will no longer be available. If you only want some items - destroyed and not all, use unset_userdata(). +You may also :doc:`create your own <../general/creating_drivers>` custom +session drivers. A session driver basically manages an array of name/value +pairs with some sort of storage mechanism. -Session Preferences -=================== +To make a new driver, 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), a regenerate handler to make a new session ID, +and an access handler to expose the data (get_userdata). Your initial class +might look like:: -You'll find the following Session related preferences in your -application/config/config.php file: + class CI_Session_custom extends CI_Session_driver { + protected function initialize() + { + // Read existing session data or create a new one + } + + public function sess_save() + { + // Save current data to storage + } + + public function sess_destroy() + { + // Destroy the current session and clean up storage + } + + public function sess_regenerate() + { + // Create new session ID + } + + public function &get_userdata() + { + // Return a reference to your userdata array + } + } + +Notice that get_userdata() returns a reference so the parent library is +accessing the same array the driver object is using. This saves memory +and avoids synchronization issues during usage. + +Put your driver in the libraries/Session/drivers folder anywhere in your +package 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_, and your filename must be Session_.php, +preferably also capitalized, such as:: + + CI_Session_foo in libraries/Session/drivers/Session_foo.php + +Then specify the driver by setting 'sess_driver' in your config.php file or as a +parameter when loading the CI_Session object:: + + $config['sess_driver'] = 'foo'; + +OR:: + + $CI->load->driver('session', array('sess_driver' => 'foo')); + +The driver specified by 'sess_driver' is automatically included as a valid +driver. However, if you want to make a custom driver available as an option +without making it the initially loaded driver, set 'sess_valid_drivers' in +your config.php file to an array including your driver name:: + + $config['sess_valid_drivers'] = array('sess_driver'); -=========================== =============== =========================== ========================================================================== -Preference Default Options Description -=========================== =============== =========================== ========================================================================== -**sess_cookie_name** ci_session None The name you want the session cookie saved as. -**sess_expiration** 7200 None The number of seconds you would like the session to last. The default - value is 2 hours (7200 seconds). If you would like a non-expiring - session set the value to zero: 0 -**sess_expire_on_close** FALSE TRUE/FALSE (boolean) Whether to cause the session to expire automatically when the browser - window is closed. -**sess_encrypt_cookie** FALSE TRUE/FALSE (boolean) Whether to encrypt the session data. -**sess_use_database** FALSE TRUE/FALSE (boolean) Whether to save the session data to a database. You must create the - table before enabling this option. -**sess_table_name** ci_sessions Any valid SQL table name The name of the session database table. -**sess_time_to_update** 300 Time in seconds This options controls how often the session class will regenerate itself - and create a new session id. -**sess_match_ip** FALSE TRUE/FALSE (boolean) Whether to match the user's IP address when reading the session data. - Note that some ISPs dynamically changes the IP, so if you want a - non-expiring session you will likely set this to FALSE. -**sess_match_useragent** TRUE TRUE/FALSE (boolean) Whether to match the User Agent when reading the session data. -=========================== =============== =========================== ========================================================================== \ No newline at end of file -- cgit v1.2.3-24-g4f1b From b3816b794592873a4e98187e66745544b463e933 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Mon, 13 Aug 2012 09:47:58 -0400 Subject: Minor doc fixes --- user_guide_src/source/libraries/loader.rst | 2 +- user_guide_src/source/libraries/sessions.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst index 5a17629d2..33c1bafec 100644 --- a/user_guide_src/source/libraries/loader.rst +++ b/user_guide_src/source/libraries/loader.rst @@ -83,7 +83,7 @@ third parameter:: $this->load->library('calendar', '', 'my_calendar'); - // Session class is now accessed using: + // Calendar class is now accessed using: $this->my_calendar diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 7a27a8f34..dd9e8cbb4 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -424,12 +424,12 @@ You may also :doc:`create your own <../general/creating_drivers>` custom session drivers. A session driver basically manages an array of name/value pairs with some sort of storage mechanism. -To make a new driver, extend CI_Session_driver. Overload the initialize +To make a new driver, 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), a regenerate handler to make a new session ID, -and an access handler to expose the data (get_userdata). Your initial class -might look like:: +deleted data (sess_destroy), a regenerate handler to make a new session ID +(sess_regenerate), and an access handler to expose the data (get_userdata). +Your initial class might look like:: class CI_Session_custom extends CI_Session_driver { protected function initialize() -- cgit v1.2.3-24-g4f1b From aee9265602c3bb30a1f7f3dfd562b9b36cc612a4 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Sun, 26 Aug 2012 21:45:35 -0400 Subject: Fixed select_driver(), cookie sess_destroy(), and native cookie name conflict --- system/core/Loader.php | 8 +++++++- system/libraries/Session/Session.php | 11 +++++++---- system/libraries/Session/drivers/Session_cookie.php | 2 +- system/libraries/Session/drivers/Session_native.php | 3 ++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/system/core/Loader.php b/system/core/Loader.php index a62cf06f5..01d99dd37 100644 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -911,7 +911,7 @@ class CI_Loader { $class = substr($class, $last_slash); // Check for match and driver base class - if (strtolower($subdir) == strtolower($class) && ! class_exists('CI_Driver_Library')) + if (strtolower(trim($subdir, '/')) == strtolower($class) && ! class_exists('CI_Driver_Library')) { // We aren't instantiating an object here, just making the base class available require BASEPATH.'libraries/Driver.php'; @@ -1005,6 +1005,12 @@ class CI_Loader { $path = strtolower($class).'/'.$class; return $this->_ci_load_class($path, $params); } + else if (ucfirst($subdir) != $subdir) + { + // Lowercase subdir failed - retry capitalized + $path = ucfirst($subdir).$class; + return $this->_ci_load_class($path, $params); + } // If we got this far we were unable to find the requested class. // We do not issue errors if the load call failed due to a duplicate request diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 97eab803f..1f24456a4 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -141,14 +141,17 @@ class CI_Session extends CI_Driver_Library { $child = str_replace($this->lib_name.'_', '', $driver); if (isset($this->$child)) { - // Make driver current and sync userdata - $this->current = $this->$child; - $this->userdata =& $this->current->get_userdata(); + // 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($driver); + $this->load_driver($child); } } } diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index 8ac92e432..89e81386f 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -325,7 +325,7 @@ class CI_Session_cookie extends CI_Session_driver { public function sess_destroy() { // Kill the session DB row - if ($this->sess_use_database === TRUE && $this->has_userdata('session_id')) + if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) { $this->CI->db->where('session_id', $this->userdata['session_id']); $this->CI->db->delete($this->sess_table_name); diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index 04c985574..8ba8e749a 100755 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -56,7 +56,8 @@ class CI_Session_native extends CI_Session_driver { // Set session name, if specified if ($config['sess_cookie_name']) { - $name = $config['sess_cookie_name']; + // Differentiate name from cookie driver with '_id' suffix + $name = $config['sess_cookie_name'].'_id'; if ($config['cookie_prefix']) { // Prepend cookie prefix -- cgit v1.2.3-24-g4f1b From 0fc3be559d23fda6ab112c01b0cd9156f201af85 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Mon, 27 Aug 2012 20:54:23 -0400 Subject: Fixed multi-driver load return and last-ditch library subdirectory retry object names --- system/core/Loader.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/core/Loader.php b/system/core/Loader.php index 01d99dd37..0d05649ca 100644 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -633,7 +633,7 @@ class CI_Loader { { $this->driver($driver); } - return FALSE; + return; } if ($library === '') @@ -1003,13 +1003,13 @@ class CI_Loader { if ($subdir === '') { $path = strtolower($class).'/'.$class; - return $this->_ci_load_class($path, $params); + return $this->_ci_load_class($path, $params, $object_name); } else if (ucfirst($subdir) != $subdir) { // Lowercase subdir failed - retry capitalized $path = ucfirst($subdir).$class; - return $this->_ci_load_class($path, $params); + return $this->_ci_load_class($path, $params, $object_name); } // If we got this far we were unable to find the requested class. -- cgit v1.2.3-24-g4f1b From 08c8304778e573d725b5565f350e44c34fb0d830 Mon Sep 17 00:00:00 2001 From: dchill42 Date: Tue, 28 Aug 2012 17:35:56 -0400 Subject: Minor session test improvements Signed-off-by: dchill42 --- tests/codeigniter/libraries/Session_test.php | 182 +++++++++++++++++---------- 1 file changed, 117 insertions(+), 65 deletions(-) diff --git a/tests/codeigniter/libraries/Session_test.php b/tests/codeigniter/libraries/Session_test.php index 5d58a9e69..135f71806 100644 --- a/tests/codeigniter/libraries/Session_test.php +++ b/tests/codeigniter/libraries/Session_test.php @@ -85,38 +85,66 @@ class Session_test extends CI_TestCase { /** * Test set_userdata() function + * + * @covers CI_Session::set_userdata + * @covers CI_Session::userdata */ public function test_set_userdata() { - // Set a userdata message for each driver - $cmsg = 'Some test data'; - $this->session->cookie->set_userdata('test1', $cmsg); - $nmsg = 'Other test data'; - $this->session->native->set_userdata('test1', $nmsg); + // Set userdata values for each driver + $key1 = 'test1'; + $ckey2 = 'test2'; + $nkey2 = 'test3'; + $cmsg1 = 'Some test data'; + $cmsg2 = 42; + $nmsg1 = 'Other test data'; + $nmsg2 = true; + $this->session->cookie->set_userdata($key1, $cmsg1); + $this->session->set_userdata($ckey2, $cmsg2); + $this->session->native->set_userdata($key1, $nmsg1); + $this->session->set_userdata($nkey2, $nmsg2); // Verify independent messages - $this->assertEquals($this->session->cookie->userdata('test1'), $cmsg); - $this->assertEquals($this->session->native->userdata('test1'), $nmsg); + $this->assertEquals($cmsg1, $this->session->cookie->userdata($key1)); + $this->assertEquals($nmsg1, $this->session->native->userdata($key1)); + + // Verify pre-selected driver sets + $this->assertEquals($cmsg2, $this->session->cookie->userdata($ckey2)); + $this->assertEquals($nmsg2, $this->session->native->userdata($nkey2)); + + // Verify no crossover + $this->assertNull($this->session->cookie->userdata($nkey2)); + $this->assertNull($this->session->native->userdata($ckey2)); } /** * Test the has_userdata() function + * + * @covers CI_Session::has_userdata */ public function test_has_userdata() { - // Set a userdata message for each driver + // Set a userdata value for each driver + $key = 'hastest'; $cmsg = 'My test data'; - $this->session->cookie->set_userdata('test2', $cmsg); + $this->session->cookie->set_userdata($key, $cmsg); $nmsg = 'Your test data'; - $this->session->native->set_userdata('test2', $nmsg); + $this->session->native->set_userdata($key, $nmsg); - // Verify independent messages - $this->assertTrue($this->session->cookie->has_userdata('test2')); - $this->assertTrue($this->session->native->has_userdata('test2')); + // Verify values exist + $this->assertTrue($this->session->cookie->has_userdata($key)); + $this->assertTrue($this->session->native->has_userdata($key)); + + // Verify non-existent values + $nokey = 'hasnot'; + $this->assertFalse($this->session->cookie->has_userdata($nokey)); + $this->assertFalse($this->session->native->has_userdata($nokey)); } /** * Test the all_userdata() function + * + * @covers CI_Session::all_userdata */ public function test_all_userdata() { @@ -151,90 +179,102 @@ class Session_test extends CI_TestCase { /** * Test the unset_userdata() function + * + * @covers CI_Session::unset_userdata */ public function test_unset_userdata() { // Set a userdata message for each driver + $key = 'untest'; $cmsg = 'Other test data'; - $this->session->cookie->set_userdata('test3', $cmsg); + $this->session->cookie->set_userdata($key, $cmsg); $nmsg = 'Sundry test data'; - $this->session->native->set_userdata('test3', $nmsg); + $this->session->native->set_userdata($key, $nmsg); // Verify independent messages - $this->assertEquals($this->session->cookie->userdata('test3'), $cmsg); - $this->assertEquals($this->session->native->userdata('test3'), $nmsg); + $this->assertEquals($this->session->cookie->userdata($key), $cmsg); + $this->assertEquals($this->session->native->userdata($key), $nmsg); // Unset them and verify absence - $this->session->cookie->unset_userdata('test3'); - $this->session->native->unset_userdata('test3'); - $this->assertEquals($this->session->cookie->userdata('test3'), NULL); - $this->assertEquals($this->session->native->userdata('test3'), NULL); + $this->session->cookie->unset_userdata($key); + $this->session->native->unset_userdata($key); + $this->assertNull($this->session->cookie->userdata($key)); + $this->assertNull($this->session->native->userdata($key)); } /** - * Test the set_flashdata() function + * Test the flashdata() functions + * + * @covers CI_Session::set_flashdata + * @covers CI_Session::flashdata */ - public function test_set_flashdata() + public function test_flashdata() { // Set flashdata message for each driver + $key = 'fltest'; $cmsg = 'Some flash data'; - $this->session->cookie->set_flashdata('test4', $cmsg); + $this->session->cookie->set_flashdata($key, $cmsg); $nmsg = 'Other flash data'; - $this->session->native->set_flashdata('test4', $nmsg); + $this->session->native->set_flashdata($key, $nmsg); // Simulate page reload $this->session->cookie->reload(); $this->session->native->reload(); // Verify independent messages - $this->assertEquals($this->session->cookie->flashdata('test4'), $cmsg); - $this->assertEquals($this->session->native->flashdata('test4'), $nmsg); + $this->assertEquals($cmsg, $this->session->cookie->flashdata($key)); + $this->assertEquals($nmsg, $this->session->native->flashdata($key)); // Simulate next page reload $this->session->cookie->reload(); $this->session->native->reload(); // Verify absence of messages - $this->assertEquals($this->session->cookie->flashdata('test4'), NULL); - $this->assertEquals($this->session->native->flashdata('test4'), NULL); + $this->assertNull($this->session->cookie->flashdata($key)); + $this->assertNull($this->session->native->flashdata($key)); } /** * Test the keep_flashdata() function + * + * @covers CI_Session::keep_flashdata */ public function test_keep_flashdata() { // Set flashdata message for each driver + $key = 'kfltest'; $cmsg = 'My flash data'; - $this->session->cookie->set_flashdata('test5', $cmsg); + $this->session->cookie->set_flashdata($key, $cmsg); $nmsg = 'Your flash data'; - $this->session->native->set_flashdata('test5', $nmsg); + $this->session->native->set_flashdata($key, $nmsg); // Simulate page reload and verify independent messages $this->session->cookie->reload(); $this->session->native->reload(); - $this->assertEquals($this->session->cookie->flashdata('test5'), $cmsg); - $this->assertEquals($this->session->native->flashdata('test5'), $nmsg); + $this->assertEquals($cmsg, $this->session->cookie->flashdata($key)); + $this->assertEquals($nmsg, $this->session->native->flashdata($key)); // Keep messages - $this->session->cookie->keep_flashdata('test5'); - $this->session->native->keep_flashdata('test5'); + $this->session->cookie->keep_flashdata($key); + $this->session->native->keep_flashdata($key); // Simulate next page reload and verify message persistence $this->session->cookie->reload(); $this->session->native->reload(); - $this->assertEquals($this->session->cookie->flashdata('test5'), $cmsg); - $this->assertEquals($this->session->native->flashdata('test5'), $nmsg); + $this->assertEquals($cmsg, $this->session->cookie->flashdata($key)); + $this->assertEquals($nmsg, $this->session->native->flashdata($key)); // Simulate next page reload and verify absence of messages $this->session->cookie->reload(); $this->session->native->reload(); - $this->assertEquals($this->session->cookie->flashdata('test5'), NULL); - $this->assertEquals($this->session->native->flashdata('test5'), NULL); + $this->assertNull($this->session->cookie->flashdata($key)); + $this->assertNull($this->session->native->flashdata($key)); } /** * Test the all_flashdata() function + * + * @covers CI_Session::all_flashdata */ public function test_all_flashdata() { @@ -264,54 +304,63 @@ class Session_test extends CI_TestCase { } /** - * Test the set_tempdata() function + * Test the tempdata() functions + * + * @covers CI_Session::set_tempdata + * @covers CI_Session::tempdata */ public function test_set_tempdata() { // Set tempdata message for each driver - 1 second timeout + $key = 'tmptest'; $cmsg = 'Some temp data'; - $this->session->cookie->set_tempdata('test6', $cmsg, 1); + $this->session->cookie->set_tempdata($key, $cmsg, 1); $nmsg = 'Other temp data'; - $this->session->native->set_tempdata('test6', $nmsg, 1); + $this->session->native->set_tempdata($key, $nmsg, 1); // Simulate page reload and verify independent messages $this->session->cookie->reload(); $this->session->native->reload(); - $this->assertEquals($this->session->cookie->tempdata('test6'), $cmsg); - $this->assertEquals($this->session->native->tempdata('test6'), $nmsg); + $this->assertEquals($cmsg, $this->session->cookie->tempdata($key)); + $this->assertEquals($nmsg, $this->session->native->tempdata($key)); // Wait 2 seconds, simulate page reload and verify message absence sleep(2); $this->session->cookie->reload(); $this->session->native->reload(); - $this->assertEquals($this->session->cookie->tempdata('test6'), NULL); - $this->assertEquals($this->session->native->tempdata('test6'), NULL); + $this->assertNull($this->session->cookie->tempdata($key)); + $this->assertNull($this->session->native->tempdata($key)); } /** * Test the unset_tempdata() function + * + * @covers CI_Session::unset_tempdata */ public function test_unset_tempdata() { // Set tempdata message for each driver - 1 second timeout + $key = 'utmptest'; $cmsg = 'My temp data'; - $this->session->cookie->set_tempdata('test7', $cmsg, 1); + $this->session->cookie->set_tempdata($key, $cmsg, 1); $nmsg = 'Your temp data'; - $this->session->native->set_tempdata('test7', $nmsg, 1); + $this->session->native->set_tempdata($key, $nmsg, 1); // Verify independent messages - $this->assertEquals($this->session->cookie->tempdata('test7'), $cmsg); - $this->assertEquals($this->session->native->tempdata('test7'), $nmsg); + $this->assertEquals($cmsg, $this->session->cookie->tempdata($key)); + $this->assertEquals($nmsg, $this->session->native->tempdata($key)); // Unset data and verify message absence - $this->session->cookie->unset_tempdata('test7'); - $this->session->native->unset_tempdata('test7'); - $this->assertEquals($this->session->cookie->tempdata('test7'), NULL); - $this->assertEquals($this->session->native->tempdata('test7'), NULL); + $this->session->cookie->unset_tempdata($key); + $this->session->native->unset_tempdata($key); + $this->assertNull($this->session->cookie->tempdata($key)); + $this->assertNull($this->session->native->tempdata($key)); } /** * Test the sess_regenerate() function + * + * @covers CI_Session::sess_regenerate */ public function test_sess_regenerate() { @@ -320,34 +369,37 @@ class Session_test extends CI_TestCase { $oldid = $this->session->cookie->userdata('session_id'); $this->session->cookie->sess_regenerate(); $newid = $this->session->cookie->userdata('session_id'); - $this->assertFalse($oldid === $newid); + $this->assertNotEquals($oldid, $newid); // Native driver - bug #55267 (https://bugs.php.net/bug.php?id=55267) prevents testing this - /*$oldid = session_id(); - $this->session->native->sess_regenerate(); - $oldid = session_id(); - $this->assertFalse($oldid === $newid);*/ + // $oldid = session_id(); + // $this->session->native->sess_regenerate(); + // $oldid = session_id(); + // $this->assertNotEquals($oldid, $newid); } /** * Test the sess_destroy() function + * + * @covers CI_Session::sess_destroy */ public function test_sess_destroy() { // Set a userdata message, destroy session, and verify absence + $key = 'dsttest'; $msg = 'More test data'; // Cookie driver - $this->session->cookie->set_userdata('test8', $msg); - $this->assertEquals($this->session->cookie->userdata('test8'), $msg); + $this->session->cookie->set_userdata($key, $msg); + $this->assertEquals($msg, $this->session->cookie->userdata($key)); $this->session->cookie->sess_destroy(); - $this->assertEquals($this->session->cookie->userdata('test8'), NULL); + $this->assertNull($this->session->cookie->userdata($key)); // Native driver - $this->session->native->set_userdata('test8', $msg); - $this->assertEquals($this->session->native->userdata('test8'), $msg); + $this->session->native->set_userdata($key, $msg); + $this->assertEquals($msg, $this->session->native->userdata($key)); $this->session->native->sess_destroy(); - $this->assertEquals($this->session->native->userdata('test8'), NULL); + $this->assertNull($this->session->native->userdata($key)); } } -- cgit v1.2.3-24-g4f1b From 3cecd8234d3bb9045e9cc41e15f603a6e87c5fac Mon Sep 17 00:00:00 2001 From: dchill42 Date: Tue, 28 Aug 2012 21:37:27 -0400 Subject: Extracted cookie database saves to shutdown and cleaned up code Signed-off-by: dchill42 --- system/libraries/Session/Session.php | 35 +++ .../libraries/Session/drivers/Session_cookie.php | 269 ++++++++++----------- 2 files changed, 169 insertions(+), 135 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 1f24456a4..1195ed955 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -42,6 +42,7 @@ class CI_Session extends CI_Driver_Library { public $params = array(); protected $current = null; protected $userdata = array(); + protected $loaded = array(); const FLASHDATA_KEY = 'flash'; const FLASHDATA_NEW = ':new:'; @@ -111,6 +112,22 @@ class CI_Session extends CI_Driver_Library { log_message('debug', 'CI_Session routines successfully run'); } + /** + * CI_Session destructor + * + * The destructor calls shutdown() on each loaded driver + */ + public function __destruct() + { + // Call shutdown for each loaded driver + foreach ($this->loaded as $driver) + { + $this->$driver->shutdown(); + } + + log_message('debug', 'CI_Session Class Shutdown'); + } + /** * Loads session storage driver * @@ -122,6 +139,14 @@ class CI_Session extends CI_Driver_Library { // 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(); + + // Mark driver as loaded + if (!in_array($driver, $this->loaded)) + { + $this->loaded[] = $driver; + } + + // Return driver object return $this->current; } @@ -581,6 +606,16 @@ abstract class CI_Session_driver extends CI_Driver { // Overload this method to implement initialization } + /** + * Shut down driver + * + * @return void + */ + public function shutdown() + { + // Overload this method to implement shutdown + } + /** * Save the session data * diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index 89e81386f..df3282cee 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -28,9 +28,7 @@ /** * Cookie-based session management driver * - * This is the CI_Session functionality, as written by EllisLab, abstracted out to a driver. - * I have done a little updating for PHP5, and made minor changes to extract this functionality from - * the public interface (now in the Session Library), but effectively this code is unchanged. + * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver. * * @package CodeIgniter * @subpackage Libraries @@ -172,6 +170,25 @@ class CI_Session_cookie extends CI_Session_driver { */ public $now; + /** + * Default userdata keys + * + * @var array + */ + protected $defaults = array( + 'session_id', + 'ip_address', + 'user_agent', + 'last_activity' + ); + + /** + * Data needs DB update flag + * + * @var bool + */ + protected $data_dirty = FALSE; + /** * Initialize session driver object * @@ -224,10 +241,14 @@ class CI_Session_cookie extends CI_Session_driver { $this->CI->load->library('encrypt'); } - // Are we using a database? If so, load it + // Check for database if ($this->sess_use_database === TRUE && $this->sess_table_name !== '') { + // Load database driver $this->CI->load->database(); + + // Register shutdown function + register_shutdown_function(array($this, '_update_db')); } // Set the "now" time. Can either be GMT or server time, based on the config prefs. @@ -259,6 +280,17 @@ class CI_Session_cookie extends CI_Session_driver { $this->_sess_gc(); } + /** + * Shutdown session driver object + * + * @return void + */ + public function shutdown() + { + // Just update the DB + $this->_update_db(); + } + /** * Write the session data * @@ -266,55 +298,15 @@ class CI_Session_cookie extends CI_Session_driver { */ public function sess_save() { - // Are we saving custom data to the DB? If not, all we do is update the cookie + // Check for database if ($this->sess_use_database === FALSE) { - $this->_set_cookie(); - return; - } - - // set the custom userdata, the session data we will set in a second - $custom_userdata = $this->all_userdata(); - $cookie_userdata = array(); - - // Before continuing, we need to determine if there is any custom data to deal with. - // Let's determine this by removing the default indexes to see if there's anything left in the array - // and set the session data while we're at it - $defaults = array( - 'session_id', - 'ip_address', - 'user_agent', - 'last_activity' - ); - foreach ($defaults as $val) - { - unset($custom_userdata[$val]); - $cookie_userdata[$val] = $this->userdata[$val]; + // Mark custom data as dirty so we know to update the DB + $this->data_dirty = TRUE; } - // Did we find any custom data? If not, we turn the empty array into a string - // since there's no reason to serialize and store an empty array in the DB - if (count($custom_userdata) === 0) - { - $custom_userdata = ''; - } - else - { - // Serialize the custom data array so we can store it - $custom_userdata = $this->_serialize($custom_userdata); - } - - // Run the update query - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->update($this->sess_table_name, array( - 'last_activity' => $this->userdata['last_activity'], - 'user_data' => $custom_userdata - )); - - // Write the cookie. Notice that we manually pass the cookie data array to the - // _set_cookie() function. Normally that function will store $this->userdata, but - // in this case that array contains custom data, which we do not want in the cookie. - $this->_set_cookie($cookie_userdata); + // Write the cookie + $this->_set_cookie(); } /** @@ -327,8 +319,7 @@ class CI_Session_cookie extends CI_Session_driver { // Kill the session DB row if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) { - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->delete($this->sess_table_name); + $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id'])); } // Kill the cookie @@ -392,16 +383,18 @@ class CI_Session_cookie extends CI_Session_driver { return FALSE; } - // Decrypt the cookie data + // Check for encryption if ($this->sess_encrypt_cookie === TRUE) { + // Decrypt the cookie data $session = $this->CI->encrypt->decode($session); } else { - // encryption was not used, so we need to check the md5 hash - $hash = substr($session, strlen($session)-32); // get last 32 chars - $session = substr($session, 0, strlen($session)-32); + // Encryption was not used, so we need to check the md5 hash in the last 32 chars + $len = strlen($session)-32; + $hash = substr($session, $len); + $session = substr($session, 0, $len); // Does the md5 hash match? This is to prevent manipulation of session data in userspace if ($hash !== md5($session.$this->encryption_key)) @@ -478,18 +471,13 @@ class CI_Session_cookie extends CI_Session_driver { if (is_array($custom_data)) { - foreach ($custom_data as $key => $val) - { - $session[$key] = $val; - } + $session = $session + $custom_data; } } } // Session is valid! $this->userdata = $session; - unset($session); - return TRUE; } @@ -501,28 +489,19 @@ class CI_Session_cookie extends CI_Session_driver { */ protected function _sess_create() { - $sessid = ''; - do - { - $sessid .= mt_rand(0, mt_getrandmax()); - } - while (strlen($sessid) < 32); - - // To make the session ID even more secure we'll combine it with the user's IP - $sessid .= $this->CI->input->ip_address(); - + // Initialize userdata $this->userdata = array( - 'session_id' => md5(uniqid($sessid, TRUE)), + 'session_id' => $this->_make_sess_id(), 'ip_address' => $this->CI->input->ip_address(), 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), 'last_activity' => $this->now, - 'user_data' => '' ); - // Save the data to the DB if needed + // Check for database if ($this->sess_use_database === TRUE) { - $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata)); + // Add empty user_data field and save the data to the DB + $this->CI->db->set('user_data', '')->insert($this->sess_table_name, $this->userdata); } // Write the cookie @@ -544,42 +523,84 @@ class CI_Session_cookie extends CI_Session_driver { return; } - // _set_cookie() will handle this for us if we aren't using database sessions - // by pushing all userdata to the cookie. - $cookie_data = NULL; + // Update last activity to now + $this->userdata['last_activity'] = $this->now; + + // Save the old session id so we know which DB record to update + $old_sessid = $this->userdata['session_id']; + + // Changing the session ID during an AJAX call causes problems + if ( ! $this->CI->input->is_ajax_request()) + { + // Get new id + $this->userdata['session_id'] = $this->_make_sess_id(); + } - // Changing the session ID during an AJAX call causes problems, so we'll only update our last_activity - if ($this->CI->input->is_ajax_request()) + // Check for database + if ($this->sess_use_database === TRUE) { - $this->userdata['last_activity'] = $this->now; + // Update the session ID and last_activity field in the DB + $this->CI->db->update($this->sess_table_name, array( + 'last_activity' => $this->now, + 'session_id' => $this->userdata['session_id'] + ), array('session_id' => $old_sessid)); + } - // Update the session ID and last_activity field in the DB if needed - if ($this->sess_use_database === TRUE) - { - // set cookie explicitly to only have our session data - $cookie_data = array(); - $defaults = array( - 'session_id', - 'ip_address', - 'user_agent', - 'last_activity' - ); - foreach ($defaults as $val) - { - $cookie_data[$val] = $this->userdata[$val]; - } + // Write the cookie + $this->_set_cookie(); + } - $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, - array('last_activity' => $this->userdata['last_activity']), - array('session_id' => $this->userdata['session_id']))); + /** + * Update database with current data + * + * This gets called from the shutdown function and also + * registered with PHP to run at the end of the request + * so it's guaranteed to update even when a fatal error + * occurs. The first call makes the update and clears the + * dirty flag so it won't happen twice. + */ + public function _update_db() + { + // Check for database and dirty flag and unsaved + if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE) + { + // Set up activity and data fields to be set + // If we don't find custom data, user_data will remain an empty string + $set = array( + 'last_activity' => $this->userdata['last_activity'], + 'user_data' => '' + ); + + // Get the custom userdata, leaving out the defaults + // (which get stored in the cookie) + $userdata = array_diff_key($this->userdata, $this->defaults); + + // Did we find any custom data? + if ( ! empty($userdata)) + { + // Serialize the custom data array so we can store it + $set['user_data'] = $this->_serialize($userdata); } - return $this->_set_cookie($cookie_data); + // Run the update query + // Any time we change the session id, it gets updated immediately, + // so our where clause below is always safe + $this->CI->db->update($this->sess_table_name, $set, array('session_id' => $this->userdata['session_id'])); + + // Clear dirty flag to prevent double updates + $this->data_dirty = FALSE; + + log_message('debug', 'CI_Session Data Saved To DB'); } + } - // Save the old session id so we know which record to - // update in the database if we need it - $old_sessid = $this->userdata['session_id']; + /** + * Generate a new session id + * + * @return string Hashed session id + */ + protected function _make_sess_id() + { $new_sessid = ''; do { @@ -590,32 +611,8 @@ class CI_Session_cookie extends CI_Session_driver { // To make the session ID even more secure we'll combine it with the user's IP $new_sessid .= $this->CI->input->ip_address(); - // Turn it into a hash and update the session data array - $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE)); - $this->userdata['last_activity'] = $this->now; - - // Update the session ID and last_activity field in the DB if needed - if ($this->sess_use_database === TRUE) - { - // set cookie explicitly to only have our session data - $cookie_data = array(); - $defaults = array( - 'session_id', - 'ip_address', - 'user_agent', - 'last_activity' - ); - foreach ($defaults as $val) - { - $cookie_data[$val] = $this->userdata[$val]; - } - - $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, - array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); - } - - // Write the cookie - $this->_set_cookie($cookie_data); + // Turn it into a hash and return + return md5(uniqid($new_sessid, TRUE)); } /** @@ -641,12 +638,16 @@ class CI_Session_cookie extends CI_Session_driver { * Write the session cookie * * @access protected - * @param array Cookie name/value pairs * @return void */ - protected function _set_cookie(array $cookie_data = NULL) + protected function _set_cookie() { - if (is_null($cookie_data)) + // Get userdata (only defaults if database) + if ($this->sess_use_database === TRUE) + { + $cookie_data = array_intersect_key($this->userdata, $this->defaults); + } + else { $cookie_data = $this->userdata; } @@ -798,9 +799,7 @@ class CI_Session_cookie extends CI_Session_driver { if ((mt_rand(0, $divisor) / $divisor) < $probability) { $expire = $this->now - $this->sess_expiration; - - $this->CI->db->where('last_activity < '.$expire); - $this->CI->db->delete($this->sess_table_name); + $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire); log_message('debug', 'Session garbage collection performed.'); } -- cgit v1.2.3-24-g4f1b From 88b636b06dd91807706e2d442d910fe8b6a3b50c Mon Sep 17 00:00:00 2001 From: dchill42 Date: Wed, 29 Aug 2012 08:47:05 -0400 Subject: Fixed defaults and database check, reverted redundant shutdown feature Signed-off-by: dchill42 --- system/libraries/Session/Session.php | 35 ---------------------- .../libraries/Session/drivers/Session_cookie.php | 21 ++++--------- 2 files changed, 5 insertions(+), 51 deletions(-) diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 1195ed955..1f24456a4 100755 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -42,7 +42,6 @@ class CI_Session extends CI_Driver_Library { public $params = array(); protected $current = null; protected $userdata = array(); - protected $loaded = array(); const FLASHDATA_KEY = 'flash'; const FLASHDATA_NEW = ':new:'; @@ -112,22 +111,6 @@ class CI_Session extends CI_Driver_Library { log_message('debug', 'CI_Session routines successfully run'); } - /** - * CI_Session destructor - * - * The destructor calls shutdown() on each loaded driver - */ - public function __destruct() - { - // Call shutdown for each loaded driver - foreach ($this->loaded as $driver) - { - $this->$driver->shutdown(); - } - - log_message('debug', 'CI_Session Class Shutdown'); - } - /** * Loads session storage driver * @@ -139,14 +122,6 @@ class CI_Session extends CI_Driver_Library { // 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(); - - // Mark driver as loaded - if (!in_array($driver, $this->loaded)) - { - $this->loaded[] = $driver; - } - - // Return driver object return $this->current; } @@ -606,16 +581,6 @@ abstract class CI_Session_driver extends CI_Driver { // Overload this method to implement initialization } - /** - * Shut down driver - * - * @return void - */ - public function shutdown() - { - // Overload this method to implement shutdown - } - /** * Save the session data * diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index df3282cee..69e5fde14 100755 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -176,10 +176,10 @@ class CI_Session_cookie extends CI_Session_driver { * @var array */ protected $defaults = array( - 'session_id', - 'ip_address', - 'user_agent', - 'last_activity' + 'session_id' => NULL, + 'ip_address' => NULL, + 'user_agent' => NULL, + 'last_activity' => NULL ); /** @@ -280,17 +280,6 @@ class CI_Session_cookie extends CI_Session_driver { $this->_sess_gc(); } - /** - * Shutdown session driver object - * - * @return void - */ - public function shutdown() - { - // Just update the DB - $this->_update_db(); - } - /** * Write the session data * @@ -299,7 +288,7 @@ class CI_Session_cookie extends CI_Session_driver { public function sess_save() { // Check for database - if ($this->sess_use_database === FALSE) + if ($this->sess_use_database === TRUE) { // Mark custom data as dirty so we know to update the DB $this->data_dirty = TRUE; -- cgit v1.2.3-24-g4f1b