2012-09-04 15 views
7

這是事情。我的一位同事正在嘗試覆蓋我們使用的框架的會話處理。該框架默認使用PHP自己的本地會話處理,但他現在正試圖在請求之間實現數據庫層。下面是一個真正的挑戰:爲什麼PHP在會話寫入之前調用關閉函數?

問題在於數據庫對象在再次寫入會話時不可用,但它可用於其他功能,例如從會話讀取數據時。這是一個狂野的行爲。這就是我們所做的:

register_shutdown_function('exithandler'); 

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

每這些功能也寫一行到我們的日誌文件,我們可以用函數的名稱跟蹤。無論何時調用該函數,都會執行此操作。現在這裏有兩個請求的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,最後我做了一個更適合我需求的自定義會話處理程序。但是,儘管需要PHP 5.4才能工作,但您的答案在技術上是「正確答案」。 – kingmaple

+0

register_shutdown_handler()是否可以在Classes中正常工作? –

相關問題