1

解決済み:答えは2番目の投稿にあります

PDO を使用して DB にセッションを保存しようとしましたが、期待どおりのエラーが発生しません。私のコードを読んでください。

これが私のセッション ハンドラ クラスのコードです。

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
?>

しかし、エラーは発生しません。次に、本のmysqliスクリプトを使用してdbに接続しようとすると、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_real_escape_string()私は最近、mysqliが使用するたびにデータベース接続が必要であることを理解しましたmysqli_queryが、スクリプトが終了したときにpdoにもdb接続が必要だと考えています-> 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 に答える