PHP:存储在数据库中的会话并不总是更新

时间:2011-11-17 08:12:22

标签: php database session

在数据库中存储会话时,我注意到更新会话不一定会调用session_set_save_handler()中设置的write函数。当您在脚本末尾调用session_write_close()时,似乎可以解决此问题。

我是否遗漏了某些东西,或者这确实是在使用session_set_save_handler()在数据库中存储会话时需要做什么?

我目前使用的代码。

// EXECUTE AT START OF SCRIPT
$session = new Session();
session_start();

会话班

public function __construct() {
    $database       = Database::instance();
    $this->dbh      = $database->dbh();
    $this->lifetime = get_cfg_var('session.gc_maxlifetime');

    session_set_save_handler(
        array(&$this, 'open'),
        array(&$this, 'close'),
        array(&$this, 'read'),
        array(&$this, 'write'),
        array(&$this, 'destroy'),
        array(&$this, 'clean')
    );
}

// SESSION HANDLER METHODS
function open($savePath, $sessionName) {
    return true;
}

function close() {
    return true;
}

function read($sessionUuid) {
    logMessage('READ SESSION DATA > ' . $sessionUuid);
    $data = array();
    $time = time();

    $sth = $this->dbh->prepare("SELECT sessionData FROM phpSession WHERE sessionUuid = :sessionUuid AND expires > " . $time);
    $sth->setFetchMode(PDO::FETCH_ASSOC);

    try {
        $sth->execute(array('sessionUuid' => $sessionUuid));

        if ($sth->rowCount() == 1) {
            $row = $sth->fetch();
            $data = $row['sessionData'];
        }

    } catch (PDOException $exception) {
        // HANDLE EXCEPTION
    }

    return $data;
}

function write($sessionUuid, $sessionData) {
    logMessage('WRITE SESSION DATA > ' . $sessionUuid);
    $time = time() + $this->lifetime;

    $sth1 = $this->dbh->prepare("SELECT sessionUuid FROM phpSession WHERE sessionUuid = :sessionUuid");

    try {
        $sth1->execute(array('sessionUuid' => $sessionUuid));

        $query  = '';
        $data   = array(
            'sessionUuid'   => $sessionUuid,
            'sessionData'   => $sessionData,
            'expires'       => $time
        );

        if ($sth1->rowCount() == 1) {
            // UPDATE
            $query = "UPDATE phpSession SET sessionUuid = :sessionUuid, sessionData = :sessionData, expires = :expires";

        } else {
            // INSERT
            $query = "INSERT INTO phpSession (sessionUuid, sessionData, expires) VALUES (:sessionUuid, :sessionData, :expires)";
        }

        $sth2 = $this->dbh->prepare($query);

        try {
            $sth2->execute($data);

        } catch (PDOException $exception) {
            // HANDLE EXCEPTION
        }

    } catch (PDOException $exception) {
        // HANDLE EXCEPTION
    }

    return true;
}

function destroy($sessionUuid) {
    $sth = $this->dbh->prepare("DELETE FROM phpSession WHERE 'sessionUuid' = :sessionUuid");

    try {
        $sth->execute(array('sessionUuid' => $sessionUuid));

    } catch (PDOException $exception) {
        // HANDLE EXCEPTION
    }

    return true;
}

function clean() {
    $sth = $this->dbh->prepare("DELETE FROM phpSession WHERE 'expires' < UNIX_TIMESTAMP()");

    try {
        $sth->execute();

    } catch (PDOException $exception) {
        // HANDLE EXCEPTION
    }

    return true;
}

2 个答案:

答案 0 :(得分:3)

根据http://php.net/manual/en/function.session-write-close.php

会话数据通常在脚本终止后存储,无需调用session_write_close(),但由于会话数据被锁定以防止并发写入,因此任何时候只有一个脚本可以对会话进行操作。

锁定通常是没有编写会话的原因。这可能发生在框架页面(如文档所述)或冗长的ajax请求中,其中多个请求同时发生。

答案 1 :(得分:2)

对于PHP&lt; 5.4您需要将session_write_close()注册为关闭函数,以便在脚本执行周期结束之前进行数据库写入。

register_shutdown_function('session_write_close');