CodeIgniter意外的会话轮换 [英] CodeIgniter unexpected session rotation

查看:127
本文介绍了CodeIgniter意外的会话轮换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Codeigniter APP在LAMP上运行。我有一个奇怪的问题,不知何故Codeigniter将销毁会话,并在AJAX调用期间生成一个新的会话ID。事情是我已经设置 $ config ['sess_expiration'] 为0.在session.php中,我更改了session_update中的代码,

I have a Codeigniter APP runs on LAMP. I have a weird problem that somehow Codeigniter will destroy the session and generate a new session id during AJAX calls. The thing is I've already set $config['sess_expiration'] to be 0. In session.php, I changed the code in 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);
}

无论是要更新的会话,会话ID总是相同,因为我只是将旧的会话ID传递给新的。下面是我的配置设置:

No matter it is "session to update" or not, the session ID should always be the same because I just pass the old session ID to new one. Below is my config setting:

$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

在日志中,我登录后可以看到日志:

And in the log, when the server kick me out after I login in, I can see the log:

DEBUG - 2016-03-06 13:48:17 --> A session cookie was not found.

有时候这个问题会发生,有时候它会一整天工作。我在FF,IE,Chrome面临这个问题。任何想法?提前感谢

Sometimes this problem happen, sometimes it works all day. I'm facing this issue in FF, IE, Chrome. Any idea? Thank you in advance

推荐答案

找到问题。

m使用Codeigniter v2。有一个称为sess_read的函数从数据库读取会话信息。默认情况下,会话构造函数将执行sess_gc来清除数据库中的所有会话记录,可能性为5%,这意味着如果有20个请求,其中一个将触发清除会话记录的功能。

I'm using Codeigniter v2. There is a function called "sess_read" reading the session info from the database. And by default, the session constructor will do a sess_gc to clear all session records in the database with a possibility 5%, which means if there are 20 requests, one of them will trigger the function to clear session records.

在它触发sess_gc之后,下一个请求将首先执行sess_read,在这个sess_read中,它将检查数据库中的记录,找到记录caz sess_gc刚刚删除了所有的。然后系统会认为会话被销毁,它会做一个sess_create而不是sess_update,这将弄乱整个事情。

Just after it triggers "sess_gc", next request will do a sess_read first, and in this "sess_read", it will check the records in the database, but it won't find the record caz sess_gc just deleted all of them. Then the system will think the session is destroyed, it will do a sess_create instead of sess_update, which will mess up the whole thing.

这可怕的是,如果触发了sess_gc,系统将删除数据库中的所有会话记录,因此所有用户都被踢出。不能相信Codeigniter默认这样做。

The terrible thing about this is, if a sess_gc is triggered, the system will delete all session records in the database, thus all users are kicked out. Can't believe Codeigniter does this by default.

我做的是在函数中添加一个延迟,代码现在是

What I did is to add a delay in the function, the code now is

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调用期间重新创建会话。然后是一个完全不同的情况。本文解释很好。 http:// www这篇文章建议我们可以在数据库中的会话表中添加另一个colomn来保存。在会话轮换期间的旧会话ID。它大大减少了错误发生时,在会话旋转期间有两个同时的AJAX调用,但它并没有完全解决问题的时间。例如,如果在会话轮换期间有三个同时发生的AJAX调用,则会话仍然会失败。实际上,AJAX调用背后的数据库查询的性能在这里起着重要的作用,如果开放查询/存储过程花费太多时间,则多个AJAX调用将堆栈和挂起的机会更高,机会会话将失败。

Sometimes even if we add a delay in the gc function, we still have the issue that session is recreated during multiple AJAX calls. Then it is a totally different scenario. This article explains it well. http://www.hiretheworld.com/blog/tech-blog/codeigniter-session-race-conditions/comment-page-1#comment-4679 This article suggests that we can add another colomn in the session table in the database to hold the old session ID during session rotation. It hugely reduces the times the bug happens when there are two simultaneous AJAX calls during a session rotation , but it doesn't fully fixed the problem. For example, if there are three simultaneous AJAX calls during the session rotation, the session will still fail. Actually, the performance of the db query behind the AJAX calls play an important role here, if the open query/stored procedure takes too much time, there is a higher chance that multiple AJAX calls will stack and pend, there is a much higher chance that the session will fail.

这篇关于CodeIgniter意外的会话轮换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆