1

已解决:答案在第二篇文章中

我尝试使用 PDO 将会话存储在数据库中,但它不会产生我预期的错误,请阅读我的代码。

这是我的会话处理程序类的代码:

class MySessionHandler implements SessionHandlerInterface
{
    protected $conn = NULL;

    public function open($savePath, $sessionName)
    {
        if(is_null($this->conn))
        {
            $dsn = 'mysql:host=localhost;dbname=php_advanced';
            $username = 'root';
            $password = 'password';
            try
            {
                 $this->conn = new PDO($dsn, $username, $password);
                 $this->conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
            }
            catch(PDOException $e)
            {
                 $this->conn = NULL;
                 die('error in open function ' . $e->getMessage());
            }
        }
        return TRUE;
    }

    public function close()
    {

        echo '<p>close</p>';
        $this->conn = NULL;

        return TRUE;
    }

    public function read($id)
    {

        echo '<p>read</p>';
        $query = 'SELECT data FROM session_table WHERE session_id = :id';
        try
        {
            $pdo = $this->conn->prepare($query);
            $pdo->bindValue(':id', $id);
            $pdo->execute();

            //    Kalo query berhasil nemuin id..
            if($pdo->rowCount() == 1)
            {
                list($sessionData) = $pdo->fetch();

                return $sessionData;
            }

            return FALSE;
        }
        catch(PDOException $e)
        {
            $this->conn = NULL;
            die('error in read function => ' . $e->getMessage());
        }

    }

    public function write($id, $data)
    {

        echo '<p>write</p>';
        $query = 'REPLACE INTO session_table(session_id, data) VALUES(:id, :data)';

        try
        {
            $pdo = $this->conn->prepare($query);
            $pdo->bindValue(':id', $id);
            $pdo->bindValue(':data', $data);
            $pdo->execute();

            // return the value whether its success or not
            return (bool)$pdo->rowCount();
        }
        catch(PDOException $e)
        {
            $this->conn = NULL;
            die('error in write function => ' . $e->getMessage());
        }
    }

    public function destroy($id)
    {

        echo '<p>destroy</p>';
        $query = 'DELETE FROM session_table WHERE session_id = :id LIMIT 1';

        try
        {
            $pdo = $this->conn->prepare($query);
            $pdo->bindValue(':id', $id);
            $pdo->execute();
            $_SESSION = array();
            return (bool)$pdo->rowCount();
        }
        catch(PDOException $e)
        {
            $this->conn = NULL;
            die('error in destroy function => ' . $e->getMessage());
        }
    }

    public function gc($maxLifeTime)
    {

        echo '<p>garbage collection</p>';
        $query = 'DELETE FROM session_table WHERE DATE_ADD(last_accessed INTERVAL :time SECOND) < NOW()';

        try
        {
            $pdo = $this->conn->prepare($query);
            $pdo->bindValue(':time', $maxLifeTime);
            $pdo->execute();

            return TRUE;
        }
        catch(PDOException $e)
        {
            $this->conn = NULL;
            die('error in gc function => ' . $e->getMessage());
        }
    }
}

$SessionHandler = new MySessionHandler();
session_set_save_handler($SessionHandler);
session_name('my_session');

session_start();

我故意删除了 session_write_close。这可能听起来很愚蠢,但我想获得会话错误以了解更多信息..

这是会话脚本(使用本书的代码):

require('session_class.php');
?><!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>DB Session Test</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
<?php
// Store some dummy data in the session, if no data is present:
if (empty($_SESSION)) {

    $_SESSION['blah'] = 'umlaut';
    $_SESSION['this'] = 3615684.45;
    $_SESSION['that'] = 'blue';

    // Print a message indicating what's going on:
    echo '<p>Session data stored.</p>';

} else { // Print the already-stored data:
    echo '<p>Session Data Exists:<pre>' . print_r($_SESSION, 1) . '</pre></p>';
}

// Log the user out, if applicable:
if (isset($_GET['logout'])) {

    session_destroy();
    echo '<p>Session destroyed.</p>';
} else { // Otherwise, print the "Log Out" link:
    echo '<a href="session_link.php?logout=true">Log Out</a>';
}

// Reprint the session data:
echo '<p>Session Data:<pre>' . print_r($_SESSION, 1) . '</pre></p>';

// Complete the page:
echo '</body>
</html>';

// Write and close the session:
// session_write_close() <<<<<--- I REMOVE THIS ON PURPOSE TO GET ERROR
?>

但我没有收到任何错误,然后我尝试使用 book 的 mysqli 脚本连接数据库,它产生了我预期的错误,因为我删除了session_write_close()..

谁能解释为什么如果我使用 PDO 它不会产生错误?我什至不使用

register_shutdown_function('session_write_close');

在我的会话类析构函数中(故意)

注意:我是故意这样做的,因为我想了解更多。

我期望的错误就像我使用 mysqli 连接时一样(连接在脚本末尾由 php 关闭,然后会话尝试写入并关闭但没有可用的连接):

Warning: mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 66



Warning: mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 66



Warning: mysqli_query() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 67



Warning: mysqli_close() expects parameter 1 to be mysqli, null given in /var/www/ullman_advance/ch3/ullman_db.php on line 33

更新 1

我最近发现 mysqli 每次使用时都需要数据库连接mysqli_real_escape_string()mysqli_query并且因为但我认为我的 pdo 在脚本结束时也需要数据库连接-> db 连接关闭->MySessionHandler将尝试写入并关闭,但没有 db连接,因为 pdo 已被 php 关闭,但没有产生错误..

更新 2

我只是试图传递session_set_save_handler函数回调,它会产生错误

<?php

$conn = NULL;

function open_session()
{
    echo '<p>open session</p>';
    global $conn;
    $_dsn = 'mysql:host=localhost;dbname=php_advanced';
    $_username = 'root';
    $_password = 'password';
    $conn = new PDO($_dsn, $_username, $_password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    return TRUE;
}

function close_session()
{
    echo '<p>close session</p>';
    global $conn;

    $conn = NULL;
    return TRUE;
}

function read_session($sid)
{
    echo '<p>read session</p>';
    global $conn;

    $query = 'SELECT data FROM session_table WHERE session_id = :sid';
    $pdo = $conn->prepare($query);
    $pdo->bindValue(':sid', $sid, PDO::PARAM_STR);
    $pdo->execute();

    if($pdo->rowCount() == 1)
    {
        list($session_data) = $pdo->fetch();
        echo '<pre>';
        print_r($session_data);
        echo '</pre>';

        return $session_data;
    }
    else
    {
        return '';
    }
}


function write_session($sid, $data)
{
    echo '<p>write session</p>';
    global $conn;

    $query = 'REPLACE INTO session_table(session_id, data) VALUES(:sid, :data)';
    $pdo = $conn->prepare($query);
    $pdo->bindValue(':sid', $sid, PDO::PARAM_STR);
    $pdo->bindValue(':data', $data, PDO::PARAM_STR);
    $pdo->execute();

    return $pdo->rowCount();
}

function destroy_session($sid)
{
    echo '<p>destroy session </p>';
    global $conn;

    $query = 'DELETE FROM session_table WHERE session_id = :sid';
    $pdo = $conn->prepare($query);
    $pdo->bindValue(':sid', $sid, PDO::PARAM_STR);
    $pdo->execute();

    // clean the session array;
    $_SESSION = array();

    return (bool)$pdo->rowCount();
}


function clean_session($expire)
{
    echo '<p>clean session</p>';
    global $conn;

    $query = 'DELETE FROM session_table WHERE DATE_ADD(last_accessed, INTERVAL :expire SECOND) < NOW()';

    $pdo = $conn->prepare($query);
    $pdo->bindValue(':expire', $expire, PDO::PARAM_INT);
    $pdo->execute();

    return $pdo->rowCount();
}

session_set_save_handler('open_session', 'close_session', 'read_session', 'write_session', 'destroy_session', 'clean_session');
session_name('my_session');
session_start();

但是当我通过MySessionHandler课程时,它不会因为没有连接而产生错误。

4

1 回答 1

1

解决方案

对不起,伙计们,我的错误实际上是一个非常简单的答案,为什么类不会在脚本末尾MySessionHandler产生错误,session_write_close()

session_set_save_handler()默认情况下将注册session_write_close()register_shutdown_function()

因此,如果您想为会话创建自己的关闭功能,请使用: session_set_save_handler($SessionClass, FALSE),如果您这样做,那么您必须session_write_close()在您的类析构函数中提供

来源: http: //php.net/manual/en/function.session-set-save-handler.php

感谢您的提示和关注

于 2013-03-14T16:07:32.903 回答