我有一个在 LAMP 上运行的 Codeigniter 应用程序。我有一个奇怪的问题,Codeigniter 会在 AJAX 调用期间销毁 session 并生成新的 session id。问题是我已经将 $config['sess_expiration']
设置为 0。在 session.php 中,我更改了 session_update 中的代码,
function sess_update()
{
if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
{
return;
}
$old_sessid = $this->userdata['session_id'];
// Pass old session id to new session id directly
$new_sessid = $old_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);
}
无论是否是“要更新的 session ”, session ID 都应该始终相同,因为我只是将旧 session ID 传递给新 session ID。以下是我的配置设置:
$config['sess_cookie_name'] = 'test';
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = TRUE;
$config['sess_encrypt_cookie'] = TRUE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'ci_sessions_dev';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = FALSE;
$config['sess_time_to_update'] = 3; //the problem happens no matter this value is 3 or 30000
并且在日志中,当我登录后服务器将我踢出时,我可以看到日志:
DEBUG - 2016-03-06 13:48:17 --> A session cookie was not found.
有时会出现此问题,有时会整天工作。我在 FF、IE、Chrome 中都遇到这个问题。任何想法?预先感谢您
最佳答案
发现问题了。
我正在使用 Codeigniter v2。有一个名为“sess_read”的函数从数据库读取 session 信息。默认情况下, session 构造函数会执行一次 sess_gc 来清除数据库中的所有 session 记录,可能性为 5%,这意味着如果有 20 个请求,其中一个会触发清除 session 记录的函数。
触发“sess_gc”后,下一个请求会先进行一次sess_read,在这个“sess_read”中,会检查数据库中的记录,但不会找到caz sess_gc刚刚删除的所有记录。然后系统会认为 session 被破坏了,它会执行 sess_create 而不是 sess_update,这会让整个事情变得困惑。
可怕的是,如果触发了sess_gc,系统会删除数据库中的所有 session 记录,从而所有用户都被踢出。不敢相信 Codeigniter 默认会这样做。
我所做的是在函数中添加延迟,现在的代码是
function _sess_gc()
{
if ($this->sess_use_database != TRUE)
{
return;
}
srand(time());
if ((rand() % 100) < $this->gc_probability)
{
$expire = $this->now - $this->sess_expiration;
$expire = $expire - 60*60*12*1; //Never delete session less than 12 hours old
$this->CI->db->where("last_activity < {$expire}");
$this->CI->db->delete($this->sess_table_name);
log_message('debug', 'Session garbage collection performed.');
}
}
有时即使我们在 gc 函数中添加延迟,我们仍然会遇到在多次 AJAX 调用期间重新创建 session 的问题。然后就是完全不同的场景了。这篇文章很好地解释了这一点。 http://www.hiretheworld.com/blog/tech-blog/codeigniter-session-race-conditions/comment-page-1#comment-4679本文建议我们可以在数据库的 session 表中添加另一个列,以在 session 轮转期间保存旧的 session ID。它极大地减少了在 session 轮换期间同时进行两个 AJAX 调用时发生错误的次数,但它并没有完全解决问题。例如,如果在 session 轮换期间同时存在三个 AJAX 调用,则 session 仍然会失败。实际上,AJAX 调用背后的数据库查询的性能在这里起着重要作用,如果打开查询/存储过程花费太多时间,则多个 AJAX 调用堆栈和挂起的机会就更高,有更高的机会 session 将会失败。
关于php - CodeIgniter 意外的 session 轮换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35788313/