当我使用以下配置时,我在 codeigniter 版本 2.1.3 中也遇到了这个问题:
$config['sess_use_database'] = TRUE;
$config['sess_time_to_update'] = 300;
我认为这与 ajax 请求无关,而是与 codeigniter 中的错误有关。
似乎当您将会话存储在数据库中时,会在 300 秒后强制注销。经过3个小时的搜索和分析,我发现代码中有一个明显的bug和一个不清楚的bug,我已经解决了这个bug:
在应用程序/库文件夹中创建一个新文件:MY_Session.php
添加以下代码:
<?php
// fixed by sirderno 2013
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Session extends CI_Session
{
public function __construct()
{
parent::__construct();
}
/**
* Update an existing session
*
* @access public
* @return void
*/
public 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];
}
$cookie_data['session_id'] = $new_sessid; // added to solve bug
//added to solve bug
if (!empty($this->userdata['user_data']))
$cookie_data['user_data'] = $this->userdata['user_data'];
$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);
}
/**
* Write the session cookie
*
* @access public
* @return void
*/
public 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);
}
$_COOKIE[ $this->sess_cookie_name ] = $cookie_data; // added to solve bug
$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
);
}
}
?>
明显的错误是它没有将“user_data”存储在更新的 cookie 中。不清楚的错误是它在更新新的会话 id 后执行文件 Session.php 中的函数 sess_read(),我不知道为什么会发生这种情况,因为我希望它在更新之前执行,而不是在构造函数中写入之后执行Session.php。所以 sess_read() 函数开始用旧的 session id 读取旧的 cookie 信息,并想将它与数据库中的 session id 进行比较,但是在 session_id 更新后它不再存在于数据库中,所以这会导致注销。
Session.php文件的函数sess_read中的这行代码负责读取旧的cookie信息:
$session = $this->CI->input->cookie($this->sess_cookie_name);
所以在 MY_Session.php 的 _set_cookie 函数中,我添加了这行代码来用新的更新服务器的旧 cookie 信息:
$_COOKIE[ $this->sess_cookie_name ] = $cookie_data; // added to solve bug
通过此修复,“sess_time_to_update”与“sess_use_database”结合使用应该可以正常工作。这是一个简单明了的错误修复。