Skip to content

Commit

Permalink
Merge pull request #942 from narfbg/develop-issue-154
Browse files Browse the repository at this point in the history
Fix issue #154
  • Loading branch information
Phil Sturgeon committed Feb 2, 2012
2 parents 27c80af + 7ff563d commit b211ade
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 56 deletions.
133 changes: 77 additions & 56 deletions system/libraries/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
* @filesource
*/

// ------------------------------------------------------------------------

/**
* Session Class
*
Expand Down Expand Up @@ -67,7 +65,7 @@ class CI_Session {
*/
public function __construct($params = array())
{
log_message('debug', "Session Class Initialized");
log_message('debug', 'Session Class Initialized');

// Set the super object to a local variable for use throughout the class
$this->CI =& get_instance();
Expand All @@ -93,14 +91,14 @@ public function __construct($params = array())
$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 != '')
// 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
// 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
Expand All @@ -114,7 +112,7 @@ public function __construct($params = array())
$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.
// create a new one. If it does, we'll update it.
if ( ! $this->sess_read())
{
$this->sess_create();
Expand All @@ -133,7 +131,7 @@ public function __construct($params = array())
// Delete expired sessions if necessary
$this->_sess_gc();

log_message('debug', "Session routines successfully run");
log_message('debug', 'Session routines successfully run');
}

// --------------------------------------------------------------------
Expand Down Expand Up @@ -166,7 +164,7 @@ public function sess_read()
$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
// 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.');
Expand All @@ -179,7 +177,7 @@ public function sess_read()
$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']))
if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity']))
{
$this->sess_destroy();
return FALSE;
Expand All @@ -192,15 +190,15 @@ public function sess_read()
return FALSE;
}

// Does the IP Match?
if ($this->sess_match_ip == TRUE AND $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 AND trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
if ($this->sess_match_useragent == TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120)))
{
$this->sess_destroy();
return FALSE;
Expand All @@ -223,7 +221,7 @@ public function sess_read()

$query = $this->CI->db->get($this->sess_table_name);

// No result? Kill it!
// No result? Kill it!
if ($query->num_rows() === 0)
{
$this->sess_destroy();
Expand All @@ -232,7 +230,7 @@ public function sess_read()

// 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 != '')
if (isset($row->user_data) && $row->user_data != '')
{
$custom_data = $this->_unserialize($row->user_data);

Expand Down Expand Up @@ -282,7 +280,7 @@ public function sess_write()
$cookie_userdata[$val] = $this->userdata[$val];
}

// Did we find any custom data? If not, we turn the empty array into a string
// 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)
{
Expand All @@ -298,7 +296,7 @@ public function sess_write()
$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
// 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);
Expand All @@ -324,13 +322,12 @@ public function sess_create()
$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,
'user_data' => ''
);

'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)
Expand All @@ -357,6 +354,35 @@ public function sess_update()
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'];
Expand All @@ -374,10 +400,6 @@ public function sess_update()
$this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE));
$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)
{
Expand Down Expand Up @@ -405,21 +427,21 @@ public function sess_update()
public function sess_destroy()
{
// Kill the session DB row
if ($this->sess_use_database === TRUE AND isset($this->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);
}

// Kill the cookie
setcookie(
$this->sess_cookie_name,
addslashes(serialize(array())),
($this->now - 31500000),
$this->cookie_path,
$this->cookie_domain,
0
);
$this->sess_cookie_name,
addslashes(serialize(array())),
($this->now - 31500000),
$this->cookie_path,
$this->cookie_domain,
0
);
}

// --------------------------------------------------------------------
Expand Down Expand Up @@ -535,7 +557,7 @@ public function set_flashdata($newdata = array(), $newval = '')
*/
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()
// Note the function will return FALSE if the $key
// provided cannot be found
Expand Down Expand Up @@ -586,7 +608,6 @@ protected function _flashdata_mark()
*
* @return void
*/

protected function _flashdata_sweep()
{
$userdata = $this->all_userdata();
Expand All @@ -609,13 +630,9 @@ protected function _flashdata_sweep()
*/
protected function _get_time()
{
if (strtolower($this->time_reference) === 'gmt')
{
$now = time();
return mktime(gmdate('H', $now), gmdate('i', $now), gmdate('s', $now), gmdate('m', $now), gmdate('d', $now), gmdate('Y', $now));
}

return time();
return (strtolower($this->time_reference) === 'gmt')
? mktime(gmdate('H'), gmdate('i'), gmdate('s'), gmdate('m'), gmdate('d'), gmdate('Y'))
: time();
}

// --------------------------------------------------------------------
Expand Down Expand Up @@ -649,13 +666,13 @@ protected function _set_cookie($cookie_data = NULL)

// Set the cookie
setcookie(
$this->sess_cookie_name,
$cookie_data,
$expire,
$this->cookie_path,
$this->cookie_domain,
$this->cookie_secure
);
$this->sess_cookie_name,
$cookie_data,
$expire,
$this->cookie_path,
$this->cookie_domain,
$this->cookie_secure
);
}

// --------------------------------------------------------------------
Expand Down Expand Up @@ -687,8 +704,11 @@ protected function _serialize($data)
*
* This function converts any slashes found into a temporary marker
*
* @param string
* @param string
* @return void
*/
function _escape_slashes(&$val, $key)
protected function _escape_slashes(&$val, $key)
{
if (is_string($val))
{
Expand Down Expand Up @@ -725,6 +745,9 @@ protected function _unserialize($data)
*
* This function converts any slash markers back into actual slashes
*
* @param string
* @param string
* @return void
*/
protected function _unescape_slashes(&$val, $key)
{
Expand Down Expand Up @@ -763,9 +786,7 @@ protected function _sess_gc()
}
}


}
// END Session Class

/* End of file Session.php */
/* Location: ./system/libraries/Session.php */
1 change: 1 addition & 0 deletions user_guide_src/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Bug fixes for 3.0
- Fixed a bug (#561) - Errors in :doc:`XML-RPC Library <libraries/xmlrpc>` were not properly escaped.
- Fixed a bug (#904) - ``CI_Loader::initialize()`` caused a PHP Fatal error to be triggered if error level E_STRICT is used.
- Fixed a hosting edge case where an empty $_SERVER['HTTPS'] variable would evaluate to 'on'
- Fixed a bug (#154) - ``CI_Session::sess_update()`` caused the session to be destroyed on pages where multiple AJAX requests were executed at once.

Version 2.1.0
=============
Expand Down

0 comments on commit b211ade

Please sign in to comment.