Php 在第2页上丢失数据库会话数据

Php 在第2页上丢失数据库会话数据,php,mysql,session,Php,Mysql,Session,我编写了一个类来将会话数据存储到数据库中(见下文)。登录后的第一个页面加载一切正常,我在数据库中看到了数据 但是,转到下一页,print_r($_SESSION)返回一个空数组,数据库条目已更新为将数据列设置为nothing,但相应地更新了access列 编辑:要确认,将更新具有现有会话ID的行,因为access列具有新的时间值,但数据字段不为空 非常感谢您的帮助。谢谢 <?php namespace MyCompany\MyProject; use \PDO; class Sess

我编写了一个类来将会话数据存储到数据库中(见下文)。登录后的第一个页面加载一切正常,我在数据库中看到了数据

但是,转到下一页,print_r($_SESSION)返回一个空数组,数据库条目已更新为将数据列设置为nothing,但相应地更新了access列

编辑:要确认,将更新具有现有会话ID的行,因为access列具有新的时间值,但数据字段不为空

非常感谢您的帮助。谢谢

<?php
namespace MyCompany\MyProject;

use \PDO;


class Session
{
    private $dblayer;
    private $user_agent;

    public function __construct(PDO $dblayer)
    {
        $this->dblayer = $dblayer;
        $this->user_agent = $_SERVER['HTTP_USER_AGENT'];

        session_set_save_handler(
            array($this, 'open'),
            array($this, 'close'),
            array($this, 'read'),
            array($this, 'write'),
            array($this, 'destroy'),
            array($this, 'gc')
        );

        if ('LIVE' == DEVELOPMENT_MODE) {
            session_set_cookie_params(0, '/', '', true, true);
        } else {
            session_set_cookie_params(0, '/', '', false, true);
        }

        session_start();

    }

    public function checkUserAgent()
    {
        if ($_SERVER['HTTP_USER_AGENT'] === $this->user_agent) {
            session_regenerate_id(true);
            return true;
        }

        return false;
    }

    public function open()
    {
        if ($this->dblayer) {
            return true;
        }

        return false;
    }

    public function close()
    {
        $this->dblayer = null;
        if (!$this->dblayer) {
            return true;
        }

        return false;
    }

    public function read($id)
    {
        try {
            $this->dblayer->beginTransaction();
            $stmt = $this->dblayer->prepare("SELECT data FROM sessions WHERE id = :id LIMIT 1");
            $stmt->execute();

            $this->dblayer->commit();

            if ($data = $stmt->fetch()) {
                return $data['data'];
            }

            return '';

        } catch (\Exception $e) {
            $this->dblayer->rollBack();
            // will use file_put_contents to save error message, file etc to error log
            return false;
        }
    }

    public function write($id, $data)
    {

            $this->dblayer->beginTransaction();
            $stmt = $this->dblayer->prepare("REPLACE INTO sessions VALUES(:id, :data, NOW())");
            $stmt->bindParam(':data', $data);
            $stmt->bindParam(':id', $id);
            $stmt->execute();

            $this->dblayer->commit();

            if ($stmt) {
                return true;
            }

            $this->dblayer->rollBack();
            // can i save to error log here?
            return false;

    }

    public function destroy($id)
    {
        try {
            $this->dblayer->beginTransaction();
            $stmt = $this->dblayer->prepare("DELETE FROM sessions WHERE id = :id");
            $stmt->bindParam(':id', $id);
            $stmt->execute();

            $this->dblayer->commit();

        } catch (\PDOException $e) {
            $this->dblayer->rollBack();
            // again, will save error data to log
            echo $e->getMessage();
            return false;
        }
    }

    public function gc($max)
    {
        $to_delete = UNIX_TIMESTAMP(time() - $max);

        try {
            $this->dblayer->beginTransaction();
            $stmt = $this->dblayer->prepare("DELETE FROM sessions WHERE access < :to_delete");
            $stmt->bindParam(':to_delete', $to_delete);

            $this->dblayer->commit();

            return true;

        } catch (\PDOException $e) {
            $this->dblayer->rollBack();
            // save error data to log;
            return false;
        }
    }


}

在调用第二页时检查会话是否存在,如果不存在,则调用会话\u启动

在第二页上,确保将会话_start(),只需仔细检查,您可能会忽略。

虽然大多数类似的情况不太可能有我的确切原因,但该问题确实强调需要了解何时以及如何调用每个会话方法。实际上,问题出在read()方法中,我没有绑定id参数

缺行:

$stmt->bindParam(':id', $id);

因此,任何人有相同的问题,检查所有的方法

在您的代码中,您正在使用
回滚
,这可能是导致问题的原因吗?有些东西失败了,所以它正在回滚?这是一个很好的观点,尽管它第一次写得非常好?您的
id
字段是如何确定的,这意味着它在每次命中时都是唯一的?查询使用replace_into,id字段是我的主键,因此它插入,除非主键匹配,在这种情况下,它会在插入之前删除该行。access列正在更新。我这样问,可能是因为刷新时找不到ID,因为ID发生了更改,或者是因为
数据
字段发生了更改,导致查询失败并回滚,这是可能的吗?另外,这是我第一次遇到
REPLACE
子句,所以我不完全确定它是如何工作的。我在下一页实例化了会话类,因此在u构造方法中调用了Session_start()。我在下一页实例化了会话类,因此Session_start()也被调用了在_构造方法中调用