session_regenerate_id和数据库处理程序

时间:2010-12-27 12:31:14

标签: mysql session

我正在为我的会话使用数据库处理程序,它工作正常,但现在我堆叠成了身份验证问题。

当用户使用用户名/密码登录时,我执行session_regenerate_id,之后我尝试选择当前的session_id。

这是我的代码

session_regenerate_id();
echo $checkQ=" SELECT * FROM my_sessions WHERE id='".session_id()."'  ";
......

但我没有得到任何结果。 session_id是正确的。

完成加载页面并复制粘贴SQL命令到phpMyAdmin后,我得到了结果。

我知道这是它的愚蠢,但我能想到的唯一原因是session_regenerate_id()“太慢”所以当我尝试在下一行读取session_id时,session_id还没有在数据库中创建。

任何人都可以帮助我!

2 个答案:

答案 0 :(得分:2)

我知道已经有一段时间了,我希望你已经找到答案了,但是为了后人的缘故我会添加我的解决方案。

session_generate_id()的调用会导致session_id()的值发生变化:

<?php
$before = session_id();
session_regenerate_id();
$after = session_id();
var_dump($before == $after); // outputs false

这个问题对我来说很明显,因为在会话写入处理程序中我正在这样做(当然没有这样的伪造方法名称):

<?php
class MySQLHandler
{
    function read($id)
    {
        $row = $this->doSelectSql($id);
        if ($row) {
            $this->foundSessionDuringRead = true;
        }
        // snip
    }

     function write($id, $data)
     {
         if ($this->foundSessionDuringRead) {
             $this->doUpdateSql($id, $data);
         }
         else {
             $this->doInsertSql($id, $data);
         }
     }
}

如果从未调用session_regenerate_id(),则write()方法正常工作。但是,如果它被调用,write()的$ id参数与传递给read()的$ id不同,因此更新将找不到具有新$ id的任何记录,因为它们从未插入。

有些人建议使用MySQL的“REPLACE INTO”语法,但删除并替换行,如果你想拥有一个创建日期列,那么就会发生肆虐。我为解决问题所做的是保留传递给read的会话ID,然后在写入期间使用传递给read的id作为密钥更新数据库中的会话ID: / p>

<?php
class MySQLHandler
{
    function read($id)
    {
        $row = $this->doSelectSql($id);
        if ($row) {
            $this->rowSessionId = $id;
        }
        // snip
    }

    function write($id, $data)
    {
        if ($this->rowSessionId) {
            $stmt = $this->pdo->prepare("UPDATE session SET session_id=:id, data=:data WHERE session_id=:rowSessionId AND session_name=:sessionName");
            $stmt->bindValue(':id', $id);
            $stmt->bindValue(':rowSessionId', $this->rowSessionId);
            $stmt->bindValue(':data', $data);
            $stmt->bindValue(':sessionName', $this->sessionName);
            $stmt->execute();
        }
        else {
            $this->doInsertSql($id, $data);
        }
    }
}

答案 1 :(得分:1)

我想我遇到了同样的问题。我不清楚这是PHP(缓存)功能还是错误。

问题在于,当使用自定义SessionHandler并调用session_regenerate_id(true)时,在脚本终止之前不会创建新会话。我已经确认通过做同样的事情:从数据库中选择新的会话ID。新会议不在那里。但是,在脚本完成后,它就是。

这就是我修复它的方法:

$old_id = session_id();
// If you SELECT your DB and search for $old_id, it will be there.

session_regenerate_id(TRUE);

$new_id = session_id();
// If you SELECT your DB for either $old_id or $new_id, none will be there.

session_write_close();
session_start();

// If you SELECT your DB for $new_id, it will be there.

因此,我遇到的解决方案(解决方法)是强制PHP编写会话。我希望这会有所帮助。