【问题标题】:session_regenerate_id and database handlersession_regenerate_id 和数据库处理程序
【发布时间】:2011-05-31 03:11:48
【问题描述】:

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

当用户使用用户名/密码登录时,我会执行 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 尚未在数据库中创建。

谁能帮帮我!

【问题讨论】:

    标签: mysql session


    【解决方案1】:

    我知道这已经有一段时间了,我希望你在发布后找到了答案,但为了后人的利益,我会添加我的解决方案。

    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:

    <?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);
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我想我遇到了和你一样的问题。我不清楚这是 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 编写会话。我希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2011-09-21
        • 1970-01-01
        • 2015-08-04
        • 1970-01-01
        • 1970-01-01
        • 2011-04-25
        • 1970-01-01
        • 2012-07-16
        • 1970-01-01
        相关资源
        最近更新 更多