Okay, I’ve tweaked it about a bit to make changing session ID optional…
First of all, I added a new config variable in config.php
$config['sess_retain_session_id'] = TRUE;
Then I copied Session.php to my system/application/libraries folder and made some changes, first adding the new var:
class CI_Session {
var $sess_retain_session_id = FALSE; //New option - keep same session id on update
var $sess_encrypt_cookie = FALSE;
Next, change the constructor to read the new config var:
// 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_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key)
foreach (array('sess_retain_session_id','sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', '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($params[$key])) ? $params[$key] : $this->CI->config->item($key);
}
Now there is a config parameter to switch on/off this behaviour, a quick tweak to sess_update is needed to act on the config var.
// --------------------------------------------------------------------
/**
* 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'];
// Update the session id (default behaviour)
if(!$this->sess_retain_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;
}
else
{
$new_sessid = $old_sessid;
}
// Update the last activity data in the session data array
$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);
}
// --------------------------------------------------------------------
It could probably do with an additional method to manually force a change of session ID for use in non-AJAX files - which would be more secure. However, my AJAX is now working with no transient failures. As the sess_update runs every 5 minutes again, the user doesn’t get logged out due to the cookie expiring regardless of activity.