summaryrefslogtreecommitdiffstats
path: root/system/libraries/Session
diff options
context:
space:
mode:
authordchill42 <dchill42@gmail.com>2012-07-23 16:53:47 +0200
committerdchill42 <dchill42@gmail.com>2012-07-23 16:53:47 +0200
commitc5079de78e5141330c07e990811ef15e998e95aa (patch)
tree0f39d8c4fc7614246fc185810bfeaa7fad88a33a /system/libraries/Session
parent00fcb545109d4e61bc14e403ec828749c34a54b3 (diff)
parentede49ba66b127535f3430e20aac72ceed2c4611a (diff)
Merge branch develop of github.com:/EllisLab/CodeIgniter into session
Diffstat (limited to 'system/libraries/Session')
-rwxr-xr-xsystem/libraries/Session/Session.php25
-rwxr-xr-xsystem/libraries/Session/drivers/Session_cookie.php413
2 files changed, 316 insertions, 122 deletions
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
index 7c340ccca..94fb4b10a 100755
--- a/system/libraries/Session/Session.php
+++ b/system/libraries/Session/Session.php
@@ -197,6 +197,27 @@ class CI_Session extends CI_Driver_Library {
}
/**
+ * Fetch all flashdata
+ *
+ * @return array Flash data array
+ */
+ public function all_flashdata()
+ {
+ $out = array();
+
+ // loop through all userdata
+ foreach ($this->all_userdata() as $key => $val)
+ {
+ // if it contains flashdata, add it
+ if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE)
+ {
+ $out[$key] = $val;
+ }
+ }
+ return $out;
+ }
+
+ /**
* Add or change data in the "userdata" array
*
* @param mixed Item name or array of items
@@ -297,8 +318,8 @@ class CI_Session extends CI_Driver_Library {
*/
public function keep_flashdata($key)
{
- // 'old' flashdata gets removed. Here we mark all
- // flashdata as 'new' to preserve it from _flashdata_sweep()
+ // 'old' flashdata gets removed. Here we mark all flashdata as 'new' to preserve it from _flashdata_sweep()
+ // Note the function will return NULL if the $key provided cannot be found
$old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key;
$value = $this->userdata($old_flashdata_key);
diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php
index 696105bc6..0dc109bd1 100755
--- a/system/libraries/Session/drivers/Session_cookie.php
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -1,19 +1,30 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* CodeIgniter
*
- * An open source application development framework for PHP 5.1.6 or newer
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
*
* @package CodeIgniter
- * @author ExpressionEngine Dev Team
- * @copyright Copyright (c) 2008 - 2010, EllisLab, Inc.
- * @license http://codeigniter.com/user_guide/license.html
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* @link http://codeigniter.com
- * @since Version 2.0
+ * @since Version 1.0
* @filesource
*/
-
/**
* Cookie-based session management driver
*
@@ -24,29 +35,144 @@
* @package CodeIgniter
* @subpackage Libraries
* @category Sessions
- * @author ExpressionEngine Dev Team
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/libraries/sessions.html
*/
class CI_Session_cookie extends CI_Session_driver {
- 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 $cookie_secure = FALSE;
- 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;
+
+ /**
+ * Whether to encrypt the session cookie
+ *
+ * @var bool
+ */
+ public $sess_encrypt_cookie = FALSE;
+
+ /**
+ * Whether to use to the database for session storage
+ *
+ * @var bool
+ */
+ public $sess_use_database = FALSE;
+
+ /**
+ * Name of the database table in which to store sessions
+ *
+ * @var string
+ */
+ public $sess_table_name = '';
+
+ /**
+ * Length of time (in seconds) for sessions to expire
+ *
+ * @var int
+ */
+ public $sess_expiration = 7200;
+
+ /**
+ * Whether to kill session on close of browser window
+ *
+ * @var bool
+ */
+ public $sess_expire_on_close = FALSE;
+
+ /**
+ * Whether to match session on ip address
+ *
+ * @var bool
+ */
+ public $sess_match_ip = FALSE;
+
+ /**
+ * Whether to match session on user-agent
+ *
+ * @var bool
+ */
+ public $sess_match_useragent = TRUE;
+
+ /**
+ * Name of session cookie
+ *
+ * @var string
+ */
+ public $sess_cookie_name = 'ci_session';
+
+ /**
+ * Session cookie prefix
+ *
+ * @var string
+ */
+ public $cookie_prefix = '';
+
+ /**
+ * Session cookie path
+ *
+ * @var string
+ */
+ public $cookie_path = '';
+
+ /**
+ * Session cookie domain
+ *
+ * @var string
+ */
+ public $cookie_domain = '';
+
+ /**
+ * Whether to set the cookie only on HTTPS connections
+ *
+ * @var bool
+ */
+ public $cookie_secure = FALSE;
+
+ /**
+ * Whether cookie should be allowed only to be sent by the server
+ *
+ * @var bool
+ */
+ public $cookie_httponly = FALSE;
+
+ /**
+ * Interval at which to update session
+ *
+ * @var int
+ */
+ public $sess_time_to_update = 300;
+
+ /**
+ * Key with which to encrypt the session cookie
+ *
+ * @var string
+ */
+ public $encryption_key = '';
+
+ /**
+ * Timezone to use for the current time
+ *
+ * @var string
+ */
+ public $time_reference = 'local';
+
+
+ /**
+ * Session data
+ *
+ * @var array
+ */
+ public $userdata = array();
+
+ /**
+ * Reference to CodeIgniter instance
+ *
+ * @var object
+ */
+ public $CI;
+
+ /**
+ * Current time
+ *
+ * @var int
+ */
+ public $now;
/**
* Initialize session driver object
@@ -63,15 +189,16 @@ class CI_Session_cookie extends CI_Session_driver {
// 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)
+ '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->CI->config->item($key);
+ $this->$key = isset($this->parent->params[$key]) ? $this->parent->params[$key] :
+ $this->CI->config->item($key);
}
- if ($this->encryption_key == '')
+ if ($this->encryption_key === '')
{
- show_error('In order to use the Cookie Session driver you are required to set an encryption key '.
+ show_error('In order to use the Session Cookie driver you are required to set an encryption key '.
'in your config file.');
}
@@ -79,13 +206,13 @@ class CI_Session_cookie extends CI_Session_driver {
$this->CI->load->helper('string');
// Do we need encryption? If so, load the encryption class
- if ($this->sess_encrypt_cookie == TRUE)
+ 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 != '')
+ if ($this->sess_use_database === TRUE && $this->sess_table_name !== '')
{
$this->CI->load->database();
}
@@ -96,7 +223,7 @@ class CI_Session_cookie extends CI_Session_driver {
// 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)
+ if ($this->sess_expiration === 0)
{
$this->sess_expiration = (60*60*24*365*2);
}
@@ -143,7 +270,7 @@ class CI_Session_cookie extends CI_Session_driver {
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
{
unset($custom_userdata[$val]);
- $cookie_userdata[$val] = $this->userdata($val);
+ $cookie_userdata[$val] = $this->userdata[$val];
}
// Did we find any custom data? If not, we turn the empty array into a string
@@ -159,9 +286,9 @@ 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->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));
+ 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
@@ -186,6 +313,9 @@ class CI_Session_cookie extends CI_Session_driver {
// Kill the cookie
setcookie($this->sess_cookie_name, addslashes(serialize(array())), ($this->now - 31500000),
$this->cookie_path, $this->cookie_domain, 0);
+
+ // Kill session data
+ $this->userdata = array();
}
/**
@@ -235,21 +365,21 @@ class CI_Session_cookie extends CI_Session_driver {
$session = $this->CI->input->cookie($this->sess_cookie_name);
// No cookie? Goodbye cruel world!...
- if ($session === FALSE)
+ if ($session === NULL)
{
log_message('debug', 'A session cookie was not found.');
return FALSE;
}
// Decrypt the cookie data
- if ($this->sess_encrypt_cookie == TRUE)
+ 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
+ $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
@@ -266,30 +396,30 @@ class CI_Session_cookie extends CI_Session_driver {
$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']))
+ if ( ! is_array($session) || ! isset($session['session_id'], $session['ip_address'], $session['user_agent'],
+ $session['last_activity']))
{
$this->sess_destroy();
return FALSE;
}
// Is the session current?
- if (($session['last_activity'] + $this->sess_expiration) < $this->now())
+ 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())
+ // 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)))
+ if ($this->sess_match_useragent === TRUE &&
+ trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
{
$this->sess_destroy();
return FALSE;
@@ -300,20 +430,20 @@ class CI_Session_cookie extends CI_Session_driver {
{
$this->CI->db->where('session_id', $session['session_id']);
- if ($this->sess_match_ip == TRUE)
+ if ($this->sess_match_ip === TRUE)
{
$this->CI->db->where('ip_address', $session['ip_address']);
}
- if ($this->sess_match_useragent == TRUE)
+ if ($this->sess_match_useragent === TRUE)
{
$this->CI->db->where('user_agent', $session['user_agent']);
}
- $query = $this->CI->db->get($this->sess_table_name);
+ $query = $this->CI->db->limit(1)->get($this->sess_table_name);
// No result? Kill it!
- if ($query->num_rows() == 0)
+ if ($query->num_rows() === 0)
{
$this->sess_destroy();
return FALSE;
@@ -321,7 +451,7 @@ class CI_Session_cookie extends CI_Session_driver {
// Is there custom data? If so, add it to the main session array
$row = $query->row();
- if (isset($row->user_data) && $row->user_data != '')
+ if ( ! empty($row->user_data))
{
$custom_data = $this->_unserialize($row->user_data);
@@ -351,24 +481,27 @@ class CI_Session_cookie extends CI_Session_driver {
protected function _sess_create()
{
$sessid = '';
- while (strlen($sessid) < 32)
+ 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();
- $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());
-
+ $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,
+ 'user_data' => ''
+ );
// 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()));
+ $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
}
// Write the cookie
@@ -382,36 +515,59 @@ class CI_Session_cookie extends CI_Session_driver {
* @param boolean Force update flag (default: false)
* @return void
*/
- protected 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())
+ if (!$force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
{
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;
+
+ /* 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;
+
+ // 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->userdata['last_activity']),
+ array('session_id' => $this->userdata['session_id'])));
+ }
+
+ return $this->_set_cookie($cookie_data);
+ }
+
// 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)
+ do
{
$new_sessid .= mt_rand(0, mt_getrandmax());
}
+ while (strlen($new_sessid) < 32);
// 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;
+ // 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)
@@ -424,8 +580,7 @@ class CI_Session_cookie extends CI_Session_driver {
}
$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)));
+ array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
}
// Write the cookie
@@ -436,22 +591,19 @@ class CI_Session_cookie extends CI_Session_driver {
* Get the "now" time
*
* @access protected
- * @return int
+ * @return int Time
*/
protected function _get_time()
{
- if (strtolower($this->time_reference) == 'gmt')
+ if ($this->time_reference === 'local' || $this->time_reference === date_default_timezone_get())
{
- $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();
}
- return $time;
+ $datetime = new DateTime('now', new DateTimeZone($this->time_reference));
+ sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
+
+ return mktime($hour, $minute, $second, $month, $day, $year);
}
/**
@@ -465,13 +617,13 @@ class CI_Session_cookie extends CI_Session_driver {
{
if (is_null($cookie_data))
{
- $cookie_data = $this->all_userdata();
+ $cookie_data = $this->userdata;
}
// Serialize the userdata for the cookie
$cookie_data = $this->_serialize($cookie_data);
- if ($this->sess_encrypt_cookie == TRUE)
+ if ($this->sess_encrypt_cookie === TRUE)
{
$cookie_data = $this->CI->encrypt->encode($cookie_data);
}
@@ -485,7 +637,7 @@ class CI_Session_cookie extends CI_Session_driver {
// Set the cookie
setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain,
- $this->cookie_secure);
+ $this->cookie_secure, $this->cookie_httponly);
}
/**
@@ -496,59 +648,78 @@ class CI_Session_cookie extends CI_Session_driver {
*
* @access protected
* @param mixed Data to serialize
- * @return string
+ * @return string Serialized data
*/
protected function _serialize($data)
{
if (is_array($data))
{
- foreach ($data as $key => $val)
- {
- if (is_string($val))
- {
- $data[$key] = str_replace('\\', '{{slash}}', $val);
- }
- }
+ array_walk_recursive($data, array(&$this, '_escape_slashes'));
}
- else
+ elseif (is_string($data))
{
- if (is_string($data))
- {
- $data = str_replace('\\', '{{slash}}', $data);
- }
+ $data = str_replace('\\', '{{slash}}', $data);
}
-
return serialize($data);
}
/**
+ * Escape slashes
+ *
+ * This function converts any slashes found into a temporary marker
+ *
+ * @access protected
+ * @param string Value
+ * @param string Key
+ * @return void
+ */
+ protected function _escape_slashes(&$val, $key)
+ {
+ if (is_string($val))
+ {
+ $val = str_replace('\\', '{{slash}}', $val);
+ }
+ }
+
+ /**
* Unserialize
*
* This function unserializes a data string, then converts any
* temporary slash markers back to actual slashes
*
* @access protected
- * @param string Data to unserialize
- * @return mixed
+ * @param mixed Data to unserialize
+ * @return mixed Unserialized data
*/
protected function _unserialize($data)
{
- $data = @unserialize(strip_slashes($data));
+ $data = @unserialize(strip_slashes(trim($data)));
if (is_array($data))
{
- foreach ($data as $key => $val)
- {
- if (is_string($val))
- {
- $data[$key] = str_replace('{{slash}}', '\\', $val);
- }
- }
-
+ array_walk_recursive($data, array(&$this, '_unescape_slashes'));
return $data;
}
- return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
+ return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data;
+ }
+
+ /**
+ * Unescape slashes
+ *
+ * This function converts any slash markers back into actual slashes
+ *
+ * @access protected
+ * @param string Value
+ * @param string Key
+ * @return void
+ */
+ protected function _unescape_slashes(&$val, $key)
+ {
+ if (is_string($val))
+ {
+ $val= str_replace('{{slash}}', '\\', $val);
+ }
}
/**
@@ -562,15 +733,18 @@ class CI_Session_cookie extends CI_Session_driver {
*/
protected function _sess_gc()
{
- if ($this->sess_use_database != TRUE)
+ if ($this->sess_use_database !== TRUE)
{
return;
}
+ $probability = ini_get('session.gc_probability');
+ $divisor = ini_get('session.gc_divisor');
+
srand(time());
- if ((rand() % 100) < self::gc_probability)
+ if ((mt_rand(0, $divisor) / $divisor) < $probability)
{
- $expire = $this->now() - $this->sess_expiration;
+ $expire = $this->now - $this->sess_expiration;
$this->CI->db->where('last_activity < '.$expire);
$this->CI->db->delete($this->sess_table_name);
@@ -578,9 +752,8 @@ class CI_Session_cookie extends CI_Session_driver {
log_message('debug', 'Session garbage collection performed.');
}
}
+
}
-// END CI_Session_cookie Class
/* End of file Session_cookie.php */
/* Location: ./system/libraries/Session/drivers/Session_cookie.php */
-?>