2011-12-23 21 views
2

EDIT xdebugとnetbeansでこれをデバッグしようとしました。私がいくつかのブレークポイントを置くと、デバッグセッション中にエクスポートが機能するのは不思議です。しかし、ブレークポイントがなく、より現実的な環境であれば、輸出は機能しません。PHP Redisセッションが保存されない

コードの一部にスリープ状態を追加しようとしました。

Redisのコミットが完了する前にPHPが終了している可能性があります。多分、Redis接続は非同期的に行われていますが、私はPRedisをチェックして、デフォルトは同期接続です。


私は報告ツールを開発中です。

ここに基本的な問題があります。

レポートをセッションオブジェクトに格納しますが、セッションオブジェクト内のレポートにアクセスしようとすると、後で要求があったときにその要求が破棄されます。

これは、より詳細なバージョンです。

私はそう

$_SESSION['report_name_unixtimestamp'] = gzcompress(serialize($reportObject)); 

ユーザーは、いくつかの表形式でレポートを見て、彼らが望むならば、彼らはそれをエクスポートすることができますのようなセッションに「報告書」オブジェクトを格納します。レポートが変更される可能性があるので、セッションに保存するという考え方は、ユーザーがPDF、Excelなどにエクスポートすると、表示されているレポートと同じレポートが表示されます。

ユーザはエクスポートボタンをクリックし、PHP側ではセッションに入り、取得パラメータとして提供されたキーを使用してレポートを取得し(圧縮解除およびシリアル化解除)、エクスポートを作成してユーザに送信しますダウンロードのために。

これは、レディスキャッシングサーバーをセッション管理のためのツールとして導入しようとするまで、うまく機能しています。今、何が起こる

は以下の通りです:

我々はレポートを最初に実行したときには、それがキャッシュに保存されますと、輸出が正常に動作します。

同じセッションで同じユーザーアカウントを使用してレポートを再度実行します。 unixtimestampが変更されるため、$_SESSIONに2つのエントリが必要です。 ($_SESSION['report_name_oldertimetamp']および$_SESSION['report_name_newertimestamp'])。エクスポートボタンを再度クリックすると、ファイルが存在しないというエラーが表示されます(サーバーから送信されていないため)。

新しいバージョンのレポートについてredisサーバーをチェックすると、そこには存在しませんが、古いタイムスタンプはそのまま残ります。

これは、ファイルセッション管理では機能しましたが、Redisでは機能しませんでした。私たちは、純粋なPHPクライアントPredisと同様、PHP用のredisモジュールを試しました。

誰にもアイデアはありますか?ここで

は、いくつかの詳細は以下のとおりです。

  1. Redisのは、メモリが不足していません。これを何度も確認しました。
  2. セッションでレポートオブジェクトをシリアル化解除するには、レポートクラスを既にインクルードしておく必要があることは既にわかっています。
  3. レポートが実行されているリクエスト中にPHPセッションオブジェクトをチェックすると、新しいレポートが含まれますが、Redisには決して反映されません。

以下は、Predisで使用されているセーブハンドラです。 redis_session_initは、session_start()の直前に呼び出されて登録される関数です。私はどのようにredis_session_write関数が動作するかわからないので、多分誰かが私を助けることができます。

<?php 
    namespace RedisSession 
    { 

     $redisTargetPrefix = "PHPREDIS_SESSION:"; 
     $unpackItems = array(); 
     $redisServer = "tcp://cache.emcweb.com"; 

     function redis_session_init($unpack = null, $server = null, $prefix = null) 
     { 
      global $unpackItems, $redisServer, $redisTargetPrefix; 

      if($unpack !== null) 
      { 
       $unpackItems = $unpack; 
      } 

      if($server !== null) 
      { 
       $redisServer = $server; 
      } 

      if($prefix !== null) 
      { 
       $redisTargetPrefix = $prefix; 
      } 

      session_set_save_handler('RedisSession\redis_session_open', 'RedisSession\redis_session_close', 'RedisSession\redis_session_read', 'RedisSession\redis_session_write', 'RedisSession\redis_session_destroy', 'RedisSession\redis_session_gc'); 
     } 

     function redis_session_read($id) 
     { 
      global $redisServer, $redisTargetPrefix; 

      $redisConnection = new \Predis\Client($redisServer); 
      return base64_decode($redisConnection->get($redisTargetPrefix . $id)); 
     } 

     function redis_session_write($id, $data) 
     { 
      global $unpackItems, $redisServer, $redisTargetPrefix; 

      $redisConnection = new \Predis\Client($redisServer); 
      $ttl = ini_get("session.gc_maxlifetime"); 

      $redisConnection->pipeline(function ($r) use (&$id, &$data, &$redisTargetPrefix, &$ttl, &$unpackItems) 
     { 
      $r->setex($redisTargetPrefix . $id, $ttl, base64_encode($data)); 

      foreach($unpackItems as $item) 
      { 
       $keyname = $redisTargetPrefix . $id . ":" . $item; 

       if(isset($_SESSION[ $item ])) 
       { 
        $r->setex($keyname, $ttl, $_SESSION[ $item ]); 
       } 
       else 
       { 
        $r->del($keyname); 
       } 
      } 
     }); 
     } 

     function redis_session_destroy($id) 
     { 
      global $redisServer, $redisTargetPrefix; 

      $redisConnection = new \Predis\Client($redisServer); 
      $redisConnection->del($redisTargetPrefix . $id); 

      $unpacked = $redisConnection->keys($redisTargetPrefix . $id . ":*"); 

      foreach($unpacked as $unp) 
      { 
       $redisConnection->del($unp); 
      } 
     } 

     // These functions are all noops for various reasons... opening has no practical meaning in 
     // terms of non-shared Redis connections, the same for closing. Garbage collection is handled by 
     // Redis anyway. 
     function redis_session_open($path, $name) 
     { 

     } 

     function redis_session_close() 
     { 

     } 

     function redis_session_gc($age) 
     { 



     } 
    } 
+0

セッション変数に別のキーを使用してください(診断用)。 md5( 'report_name_unixtimestamp')や 'timestamp-reportname'など? 背景:私は鍵が切り捨てられていると思われます。 –

+0

@EugenRieck、この$ _SESSION [md5( 'report_name_1234')]のような意味ですか?たぶん、最初のレポートのエクスポートが機能する理由は説明されません。キーの長さは、異なるタイムスタンプと同じ名前なので、レポートでは同じです。私はそれを試してみます、ありがとう。 –

+0

@EugenRieck、それは仕事をしなかった。私はあなたが示唆したようにmd5ハッシュを試みたが、どちらも動作していない。 –

答えて

2

問題は解決され、私が思っていたよりもはるかにおさまりました。

セーブハンドラは、どのような方法でもロックを実装しません。レポートページには、ajaxなどを介してサーバーに複数のリクエストが行われます。 ajaxリクエストの1つは、レポートがセッションスペースに保存される前に開始されます。したがって、セッションを読み取り、最後にセッションを書き込みます。

レポートは毎回高速に実行されるため、レポートはRedisのセッションにキャッシュされますが、古いバージョンのセッシェンを持つ別のスクリプトによって上書きされます。

私は私の同僚の助けを借りていました。うん!これは頭​​がおかしくなってしまいました。

+0

そう...どうやってそれを解決しましたか? –

+0

私たちは、セッション管理のためにredisを使用せず、今のところphpセッションに固執してしまいました。しかし、解決策は、セーブハンドラのロック機構を記述して、セッションへの変更がさまざまな要求によってキャッチされるようにすることです。 –

+0

私は実際にそれを少し考えました。厳密にはロックではなく、むしろ各セッションでチェックサムを維持します。チェックサムが変更されている場合は、両方の配列をマージする必要があります。 CPPではなくPHPで簡単に行う –

関連する問題