2012-09-04 3 views
7

ここに事があります。私の同僚は、私たちが使用しているフレームワークのセッション処理を上書きしようとしています。このフレームワークはデフォルトでPHP独自のネイティブセッション処理を使用していますが、現在はリクエスト間にデータベースレイヤーを実装しようとしています。ここには真の挑戦があります:セッションが書かれる前にPHPがシャットダウン機能を呼び出すのはなぜですか?

問題は、セッションがもう書き込まれるまでにデータベースオブジェクトが利用できないということですが、セッションからデータを読み込むときなど、他の機能にも使用できます。これは野生の行動です。

register_shutdown_function('exithandler'); 

session_set_save_handler(
    'sess_open', 
    'sess_close', 
    'sess_read', 
    'sess_write', 
    'sess_destroy', 
    'sess_gc' 
); 

これらの機能のそれぞれは、ログファイルに1行を書き込んで、機能の名前で追跡することもできます。これは、関数が呼び出されるたびに実行されます。ここで2つのURLが要求されます。最初はセッションが実際に書き込まれる場所(セッションに新しいデータ)とセッションのデータがちょうどチェックされた場所(書き込まれない場所)です。ここにパズルがあります:

/login/ 
sess_open 
sess_read 
exithandler 
sess_write 
sess_close 

/account/ 
sess_open 
sess_read 
sess_write 
sess_close 
exithandler 

なぜこの動作が異なるのですか?同じメソッドが実際に呼び出されたにもかかわらず、データがセッションに格納される前に出口ハンドラが呼び出されて、なぜ通常のページで同じでないのはなぜですか?

exithandlerが呼び出された後に私たちのクラスがもう使用できないという問題があります。私は、PHPのガベージコレクタがすべてのクラスで__destruct()メソッドを呼び出したと仮定しています。これはちょうど悪いことです。

PHPがこのように動作する理由は誰でも知っていますか?

+1

使用しているPHPのバージョンは? –

+0

私はこれをPHP 5.4でテストしましたが、セッションデータの読み込みと書き込みの両方のタイプの要求に対して、最初の操作順序しか再現できません。 – nickb

+1

PHPのいくつかのバージョンでは、 'session_set_save_handler()'を呼び出す前に行を追加する必要があるという共通の問題があります。最初に 'register_shutdown_function( 'session_write_close')'を使って不安定な動作を修正するかどうかを確認してください。 –

答えて

2

あなたのコメントはPHP5.4と言いますので、SessionHandlerInterface()をご覧ください。 open()メソッドのregister_shutdown_functionを渡すと、プロセスを半自動化して、実際にPHP5.4の機能を利用できます。

<?php 
class MySessionHandler implements SessionHandlerInterface 
{ 
    private $savePath; 

    public function open($savePath, $sessionName) 
    { 
     register_shutdown_function('session_write_close'); 
     $this->savePath = $savePath; 
     if (!is_dir($this->savePath)) { 
      mkdir($this->savePath, 0777); 
     } 

     return true; 
    } 

    public function close() 
    { 
     return true; 
    } 

    public function read($id) 
    { 
     return (string)@file_get_contents("$this->savePath/sess_$id"); 
    } 

    public function write($id, $data) 
    { 
     return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true; 
    } 

    public function destroy($id) 
    { 
     $file = "$this->savePath/sess_$id"; 
     if (file_exists($file)) { 
      unlink($file); 
     } 

     return true; 
    } 

    public function gc($maxlifetime) 
    { 
     foreach (glob("$this->savePath/sess_*") as $file) { 
      if (filemtime($file) + $maxlifetime < time() && file_exists($file)) { 
       unlink($file); 
      } 
     } 

     return true; 
    } 
} 

$handler = new MySessionHandler(); 
session_set_save_handler($handler, true); 
session_start(); 
+0

悲しいことに、私のフレームワークにはPHP 5.3が必要です。私のニーズに適したカスタムセッションハンドラを終わらせました。しかし、あなたの答えは技術的には「正解」です。 – kingmaple

+0

register_shutdown_handler()はクラス内でうまく動作しますか? –

関連する問題