7

私は PHP を試していてsession_set_save_handler、PDO 接続を使用してセッション データを保存したいと考えています。

書き込みアクションのコールバックとしてこの関数があります。

function _write($id, $data) {
    logger('_WRITE ' . $id . ' ' . $data);
    try {
        $access = time();
        $sql = 'REPLACE INTO sessions SET id=:id, access=:access, data=:data';
        logger('This is the last line in this function that appears in the log.');
        $stmt = $GLOBALS['db']->prepare($sql);
        logger('This never gets logged! :(');
        $stmt->bindParam(':id', $id, PDO::PARAM_STR);
        $stmt->bindParam(':access', $access, PDO::PARAM_INT);
        $stmt->bindParam(':data', $data, PDO::PARAM_STR);
        $stmt->execute();
        $stmt->closeCursor();
        return true;
    } catch (PDOException $e) {
        logger('This is never executed.');
        logger($e->getTraceAsString());
    }
}

最初の 2 つのログ メッセージは常に表示されますが、直後の 3 番目のメッセージ$stmt = $GLOBALS['db']->prepare($sql)はログ ファイルに記録されず、例外の痕跡もありません。

セッションデータベース テーブルは空のままです。

コールバックからのログ メッセージ_closeは常に存在します。

データベースに接続する方法は次のとおりです。

$db = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

PHP 5.2.10 を使用しています。

$GLOBALS['db']->exec($sql)「手動で準備した」コンテンツで単純に実行しようとしまし$sqlたが、それでも黙って失敗しました。クエリ自体は問題なく、db コンソールから実行できました。


編集:

VolkerK が問題を特定した後、この奇妙な現象の背後にある理由を説明するこの記事を見つけました。ひょっとしたら、他の方にも参考になるかもしれません。


2回目の編集:

最も簡単な魔法の解決策は、以下の関数呼び出しをフロント コントローラー (メインの index.php) ファイルの最後に追加することです。

session_write_close();
4

3 に答える 3

4

私の賭けは次のとおりです。$GLOBALS['db']が設定されていないか、pdoのインスタンスではない(もう?)ため、PHP Fatal error: Call to a member function prepare() on a non-object発生し、phpが無効になります。

$sql = 'REPLACE INTO sessions SET id=:id, access=:access, data=:data';
logger('This is the last line in this function that appears in the log.');
if ( !isset($GLOBALS['db']) ) {
  logger('there is no globals[db]');
  return;
}
else if ( !is_object($GLOBALS['db']) ) {
  logger('globals[db] is not an object');
  return;
}
else if ( !($GLOBALS['db'] instanceof PDO) ) {
  logger('globals[db] is not a PDO object');
  return;
}
else {
  logger('globals[db] seems ok');
}

$stmt = $GLOBALS['db']->prepare($sql);
logger('This never gets logged! :(');
于 2010-04-07T22:05:56.553 に答える
1

おそらく、PDOはREPLACEINTO構文を認識しません。基盤となるDBアクセスライブラリがプリペアドステートメントを直接サポートしていない場合、PDOはそれらをエミュレートし、可能なステートメントタイプのリストにREPLACEINTOが含まれていない可能性があります。

$stmt->errorCode()準備呼び出しの直後に確認してみますか?

これがmysqlの場合、プリペアドステートメントを次のように書き直してみてください。

INSERT INTO sessions (id, access, data)
VALUES(:id, :access, :data)
ON DUPLICATE KEY UDPATE
    access=VALUES(access), data=VALUES(data);

そしてそれがあなたをさらに遠ざけるかどうか見てください。

于 2010-04-07T22:56:49.700 に答える
0

経由でリソースのデータ型にアクセスできないような気がします$GLOBALS[]。参照の処理方法などについての何か。私の勘をユーモアで表現したい場合は、次の関数宣言を試してください。

function _write($id, $data) {
    global $db;
    logger('_WRITE ' . $id . ' ' . $data);
    try {

そしてこれの代わりに:

$stmt = $GLOBALS['db']->prepare($sql);

試す

$stmt = $db->prepare($sql);

Exceptions の代わりに普通の古い s をキャッチすることもできPDOExceptionます。それに引っかかるかもしれません。

お役に立てれば!

于 2010-04-08T03:27:51.387 に答える