5

たくさんのデバッグを行った後、問題は(恥ずかしいことに)私のデータベースセッションコードにあり、典型的なセッションの問題ではなかったようです。あなたはここでそれに関連する私の答えを見ることができます-ありがとう


これは同様の質問(たとえば、1、2、3 )重複である可能性があることを理解していますが、これのベストプラクティスと思われるものに従っているにもかかわらず、まだ問題があります。

session_set_save_handler()を使用してデータベースセッションクラスを使用する場合、session1.phpからリダイレクトされた後、session2.phpでセッションが開始されると、セッションデータがクリアされます。

私の観察の概要:

  • データはsession1.phpでデータベースに正しく保存されます
  • session2.phpのsession_start()でデータが失われます
  • リダイレクト後、session2.phpでsession_start()が呼び出される前に、データはデータベースに残ります。
  • セッションIDは同じままで、リクエストヘッダーでサーバーに正しく返送されるCookieに保存されます
  • PHPのデフォルトのセッション処理を使用すると、問題なく機能します

そして注意:

  • header()の後に使用されるexit()
  • 出力前のすべてのページでsession_start()

私はばかげたタイプミスをしましたか?ダフトエラーを起こしましたか?それともこれは奇妙な癖ですか?

提供された助けを事前に感謝します。

コードは次のとおりです(この問題を修正する際にテストファイルに抽出されます):

session1.php

<?php

require_once('session.php');

session_start();  

$_SESSION['KEY'] = 'VALUE PHPSESSID: ' . session_id();

session_write_close();   
header('Location: session2.php');
exit;

session2.php

<?php

require_once('session.php');

session_start();

// Nothing?
var_dump( $_SESSION );

session.php

<?php

define( "DB_HOST", 'localhost' );
define( "DB_USER", '******' );
define( "DB_PWD", '******' );
define( "DB_NAME", '******' );

require_once('class/DatabaseSessionHandler.php');

// Use the DatabaseSessionHandler class to handle sessions
$session_handler = new DatabaseSessionHandler;
// Set up the handler above as the default session handler
session_set_save_handler(
    array($session_handler, 'open'),
    array($session_handler, 'close'),
    array($session_handler, 'read'),
    array($session_handler, 'write'),
    array($session_handler, 'destroy'),
    array($session_handler, 'gc')
);

DatabaseSessionHandler.php

<?php

class DatabaseSessionHandler
{

    protected $connection;
    protected $session_life_time;

    public function __construct()
    {
        // Ensure that everything is closed correctly as 
        // per warning on http://uk3.php.net/session_set_save_handler
        register_shutdown_function( 'session_write_close' );
    }

    public function open( $save_path, $session_name )
    {
        $this->connection = new mysqli( DB_HOST, DB_USER, DB_PWD, DB_NAME );
        $this->session_life_time = get_cfg_var( "session.gc_maxlifetime" );

        if ( $this->connection->connect_error )
            return false;

        return true;
    }

    public function close()
    {
        $this->connection->close();
        return true;
    }

    public function read( $session_id )
    {
        $data = '';

        $statement = $this->connection->prepare( "SELECT `session_data` 
                                                  FROM `session` 
                                                  WHERE `session_id` = ? " );
        $statement->bind_param( "s", $session_id );
        $statement->execute();
        $statement->bind_result( $data );

        return (string) $data;
    }

    public function write( $session_id, $session_data )
    {
        $expiry_time = time() + $this->session_life_time;
        $statement = $this->connection->prepare( "REPLACE INTO `session` 
                                                (`session_id`, `session_data`, 
                                                `expiry_time`)
                                                 VALUES (?, ?, ?)" );
        $statement->bind_param( "ssi", $session_id, $session_data, $expiry_time );

        if ( !$statement->execute() )
            return false;

        return true;
    }

    public function destroy( $session_id )
    {
        $statement = $this->connection->prepare( "DELETE FROM `session` 
                                                    WHERE `session_id` = ?" );
        $statement->bind_param( "s", $session_id );

        if ( !$statement->execute() )
            return false;

        return true;
    }

    public function gc( $max_lifetime )
    {
        $current_time = time();
        $statement = $this->connection->prepare( "DELETE FROM `session` 
                                                    WHERE `expiry_time` < ?" );
        $statement->bind_param( "i", $current_time );

        if ( !$statement->execute() )
            return false;

        return true;
    }

}
4

2 に答える 2

2

現在の時刻より前のセッション データを消去しています。それは現在の時間でなければなりません - max_lifetime

ここに解決策があります

public function gc( $max_lifetime )
{
    $current_time = time() - $max_lifetime;
    $statement = $this->connection->prepare( "DELETE FROM `session` 
                                                    WHERE `expiry_time` < ?" );
    $statement->bind_param( "i", $current_time );

    if ( !$statement->execute() )
            return false;

    return true;
}
于 2012-08-08T12:02:35.767 に答える
0

大規模なファイルのログ記録と変数の出力後 (一部のセッション関数は、ブラウザーへの出力が送信された後に呼び出されるため、通常の方法でエラーを出力することはできません)、問題は私のデータベース セッション コードにあることが判明しました。 .

MySQLi の出力を変数にバインドした後に '$statement->fetch()' を追加するのを忘れていたため、実際にはデータベースからデータを取得していませんでした。

恥ずかしい間違いですが、ソフトウェアに何か問題がある場合、多くの場合、それはコードの問題であり、使用している言語やライブラリの問題ではないという事実を理解するのに役立ちました.

コメントして回答してくださった方々のおかげで、私はこの数日間で PHP セッションについて多くのことを学びました。

于 2012-08-08T14:00:20.767 に答える