2016-01-10 85 views
0

我寫了一個類來將我的會話數據存儲到我的數據庫中(請參見下文)。所有在登錄後第一次加載頁面都可以正常工作,我可以看到數據庫中的數據。然後,print_r($ _ SESSION)返回一個空數組,並更新數據庫條目以將數據列設置爲空,但相應地更新了訪問列。在第二頁上丟失數據庫會話數據

編輯:確認,具有現有會話ID的行正在更新,因爲訪問列具有新的時間值,但數據字段不爲空。

任何幫助非常感謝。謝謝。

<?php 
namespace MyCompany\MyProject; 

use \PDO; 


class Session 
{ 
    private $dblayer; 
    private $user_agent; 

    public function __construct(PDO $dblayer) 
    { 
     $this->dblayer = $dblayer; 
     $this->user_agent = $_SERVER['HTTP_USER_AGENT']; 

     session_set_save_handler(
      array($this, 'open'), 
      array($this, 'close'), 
      array($this, 'read'), 
      array($this, 'write'), 
      array($this, 'destroy'), 
      array($this, 'gc') 
     ); 

     if ('LIVE' == DEVELOPMENT_MODE) { 
      session_set_cookie_params(0, '/', '', true, true); 
     } else { 
      session_set_cookie_params(0, '/', '', false, true); 
     } 

     session_start(); 

    } 

    public function checkUserAgent() 
    { 
     if ($_SERVER['HTTP_USER_AGENT'] === $this->user_agent) { 
      session_regenerate_id(true); 
      return true; 
     } 

     return false; 
    } 

    public function open() 
    { 
     if ($this->dblayer) { 
      return true; 
     } 

     return false; 
    } 

    public function close() 
    { 
     $this->dblayer = null; 
     if (!$this->dblayer) { 
      return true; 
     } 

     return false; 
    } 

    public function read($id) 
    { 
     try { 
      $this->dblayer->beginTransaction(); 
      $stmt = $this->dblayer->prepare("SELECT data FROM sessions WHERE id = :id LIMIT 1"); 
      $stmt->execute(); 

      $this->dblayer->commit(); 

      if ($data = $stmt->fetch()) { 
       return $data['data']; 
      } 

      return ''; 

     } catch (\Exception $e) { 
      $this->dblayer->rollBack(); 
      // will use file_put_contents to save error message, file etc to error log 
      return false; 
     } 
    } 

    public function write($id, $data) 
    { 

      $this->dblayer->beginTransaction(); 
      $stmt = $this->dblayer->prepare("REPLACE INTO sessions VALUES(:id, :data, NOW())"); 
      $stmt->bindParam(':data', $data); 
      $stmt->bindParam(':id', $id); 
      $stmt->execute(); 

      $this->dblayer->commit(); 

      if ($stmt) { 
       return true; 
      } 

      $this->dblayer->rollBack(); 
      // can i save to error log here? 
      return false; 

    } 

    public function destroy($id) 
    { 
     try { 
      $this->dblayer->beginTransaction(); 
      $stmt = $this->dblayer->prepare("DELETE FROM sessions WHERE id = :id"); 
      $stmt->bindParam(':id', $id); 
      $stmt->execute(); 

      $this->dblayer->commit(); 

     } catch (\PDOException $e) { 
      $this->dblayer->rollBack(); 
      // again, will save error data to log 
      echo $e->getMessage(); 
      return false; 
     } 
    } 

    public function gc($max) 
    { 
     $to_delete = UNIX_TIMESTAMP(time() - $max); 

     try { 
      $this->dblayer->beginTransaction(); 
      $stmt = $this->dblayer->prepare("DELETE FROM sessions WHERE access < :to_delete"); 
      $stmt->bindParam(':to_delete', $to_delete); 

      $this->dblayer->commit(); 

      return true; 

     } catch (\PDOException $e) { 
      $this->dblayer->rollBack(); 
      // save error data to log; 
      return false; 
     } 
    } 


} 
+0

在你的代碼中,你正在使用'rollBack',這可能會導致問題嗎?有東西失敗了,所以它回滾了? – Script47

+0

這是一個很好的觀點,儘管第一次寫得非常好。 – DJC

+0

你的'id'字段是如何確定的,這意味着它在每次擊中都是唯一的? – Script47

回答

0

檢查會話是否在調用第二頁時存在,如果不是,則調用session_start。

+0

我在下一頁實例化Session類,因此在__construct方法中調用session_start() – DJC

0

在第二頁上,請確保將session_start(); ,請仔細檢查,你可能會忽略。

+0

我在下一頁實例化Session類,因此session_start( )在__construct方法中被調用 – DJC

0

雖然大多數類似的情況不可能有我的確切原因,但問題確實強調需要了解何時以及如何調用每個會話方法。問題實際上是在read()方法中,我沒有綁定id參數。

缺失行:

$stmt->bindParam(':id', $id); 

所以有同樣的問題任何人,檢查所有的方法!