我正在为我的会话使用数据库处理程序,它工作正常,但现在我堆叠成了身份验证问题。
当用户使用用户名/密码登录时,我执行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还没有在数据库中创建。
任何人都可以帮助我!
答案 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编写会话。我希望这会有所帮助。