Я знаю, что прошло некоторое время, я надеюсь, что вы нашли ответ с тех пор, как он был опубликован, но я добавлю свое решение для потомков.
Вызов 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);
}
}
}
Метод write () работал нормально, если session_regenerate_id()
никогда не вызывался. Однако, если он был вызван, аргумент $ id для write()
отличается от $ id, переданного в read()
, поэтому обновление не найдет никаких записей с новым $ id, потому что они никогда не были вставлены.
Некоторые люди предлагают использовать синтаксис MySQL «REPLACE INTO», но он удаляет и заменяет строку, которая приводит к хаосу, если вы хотите иметь столбец с датой создания. Что я сделал, чтобы исправить проблему, так это удержать идентификатор сеанса, который был передан read
, а затем обновить идентификатор сеанса в базе данных во время записи, используя идентификатор, переданный read
в качестве ключа:
<?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);
}
}
}