2012-08-08 40 views
5

經過大量調試後,似乎問題出現在我的數據庫會話代碼中(令人尷尬),而不是典型的會話問題。你可以看到我的回答與它here - 感謝會話數據在頁面重定向後在session_start()上被刪除


我理解這可能是類似的問題重複(如onetwothree),但儘管下面似乎是爲了這個,我的最佳實踐」米仍然有問題。

當使用session_set_save_handler()來使用我的數據庫會話類時,會話數據在會話從session1.php重定向到session2.php後開始時被清除。

我的觀察概述:

  • 數據保存到數據庫中正確session1.php
  • 數據在session2.php失去了在session_start()
  • 的數據仍在數據庫之後在session2.php中調用session_start()之前的session_start()被調用
  • 會話ID保持不變並存儲在正在被正確發送回服務器的cookie中
  • 使用PHP的默認會話處理它的作品沒關係

及注意事項:

  • 退出()輸出

以前在每一頁上標頭()

  • 在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; 
        } 
    
    } 
    
  • +2

    記錄一些東西在銷燬和gc中的其他東西,這樣你就知道哪一個是負責刪除的。或者使用調試器。 – greg0ire 2012-08-08 11:35:02

    +0

    如果你不用'session_write_close();'來試試它會怎麼樣?另外,你在運行什麼服務器?看看這個問題(請參閱評論中的答案)http://stackoverflow.com/questions/10028643/php-session-data-not-being-stored-simply – 2012-08-08 11:37:23

    +0

    @GeraldVersluis的數據仍然在數據庫中後重定向等它不是session_write_close()函數(嘗試刪除它,但仍然沒有運氣) – Skyrail 2012-08-08 12:12:57

    回答

    0

    那麼經過廣泛的文件記錄,並打印出變量(輸出到瀏覽器發送,因此經過一番的會話函數調用你不能以正常的方式輸出錯誤),事實證明問題出在我的數據庫會話代碼上。

    我忘了在將MySQLi輸出綁定到變量之後添加'$ statement-> fetch()',因此我從來沒有真正從數據庫中獲取數據。

    一個令人尷尬的錯誤,但它有助於驅動回家的事實,如果您的軟件有問題,往往不是你的代碼中的問題,而是你使用的語言或庫中的問題。

    感謝那些評論和回答的人,在過去的幾天裏,我學到了很多關於PHP會話的原因。

    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; 
    } 
    
    +0

    啊,這是一個問題我忽略了,但似乎並不是問題。即使垃圾收集器未被調用,也會發生該問題。我很感激你糾正錯誤,因爲它很可能會被錯過。 – Skyrail 2012-08-08 12:22:29