2016-05-14 88 views
0

我已經從PHP 5.6升級到7,並使用自定義會話處理程序腳本來管理數據庫中的會話,以便我可以更好地控制我的用戶。除了一件事之外,一切都很好。PHP 7 session_regenerate_id失敗和PDO調用成員函數prepare()null

session_regenerate_id(true); 

用戶成功登錄後,爲避免會話固定,我們調用session_regenerate_id。使用PHP5.6工作得很好,而不是PHP7:

[14-May-2016 02:04:07 UTC] PHP Warning: Uncaught Error: Call to a member function prepare() on null in /home/xxxx/protected/class.database.php:38 Stack trace:
#0 /home/xxxx/protected/class.session.php(37): Database->query('SELECT data FRO...')
#1 [internal function]: Session->_read('kuq04akaagkjd5n...')
#2 /home/xxxx/protected/user_auth_fns.php(705): session_regenerate_id(true)
#3 /home/xxxx/public_html/passengersdir/login.php(42): login_user('xxxx', 'xxxx', 'xxxx', NULL)
#4 {main}
thrown in /home/xxxx/protected/class.database.php on line 38 [14-May-2016 02:04:07 UTC] Recoverable error: session_regenerate_id(): Failed to create(read) session ID: user (path:) in /home/xxxx/protected/user_auth_fns.php on line 705

顯然session_regenerate返回false,但PHP 5.6讓它滑動。這是PHP的官方迴應:

  • PHP 7.0及更高版本不允許來自用戶保存處理程序的錯誤返回值。 用戶讀處理程序務必返回「字符串」數據總是成功。
  • 本地保存處理程序必須返回SUCCESS以成功處理包括不存在的會話數據的情況。
  • FALSE /失敗的意思是「讀取時出現錯誤」,如權限/網絡/等錯誤。

https://bugs.php.net/bug.php?id=71187

有些人找到了一個解決方法在這裏: https://github.com/magento/magento2/issues/2827

It appears to be an issue with the read function not always returning a string. As a temporary fix I cast the return value for the read() function in the SessionHandler as a string.

我不喜歡的解決方法。我可以簡單地刪除session_generate_id,它的工作原理類似於過去的美好時光,但您可以開始進行會話固定。

理想情況下,我想解決這個問題,或找到一個更好的方式來成功登錄後打擊會話固定。感謝您的期待。

這裏是有問題的代碼:

public function __construct(){ // this is class.database.php 
    // Set DSN 
    $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname; 
    // Set options 
    $options = array(
     PDO::ATTR_PERSISTENT => true, 
     PDO::ATTR_ERRMODE  => PDO::ERRMODE_EXCEPTION 
    ); 
    // Create a new PDO instanace 
    try{ 
     $this->dbh = new PDO($dsn, $this->user, $this->pass, $options); 
    } 
    // Catch any errors 
    catch(PDOException $e){ 
     $this->error = $e->getMessage(); 
    } 
} 

public function query($query){ 
    // this throws Uncaught Error: Call to a member function prepare() on null in /home/opentaxi/protected/class.database.php:38 
    $this->stmt = $this->dbh->prepare($query); 
} 
public function bind($param, $value, $type = null){ 
    if (is_null($type)) { 
     switch (true) { 
      case is_int($value): 
       $type = PDO::PARAM_INT; 
       break; 
      case is_bool($value): 
       $type = PDO::PARAM_BOOL; 
       break; 
      case is_null($value): 
       $type = PDO::PARAM_NULL; 
       break; 
      default: 
       $type = PDO::PARAM_STR; 
     } 
    } 
    $this->stmt->bindValue($param, $value, $type); 
} 
public function execute(){ 
    return $this->stmt->execute(); 
}  

// this is from class.session.php 
public function _read($id){ 
//this is /home/opentaxi/protected/class.session.php(37): Database->query('SELECT data FRO...') 
$this->db->query('SELECT data FROM sessions WHERE id = :id'); 
$this->db->bind(':id', $id); 
if($this->db->execute()){ 
    $row = $this->db->single(); 
    return (string)$row['data']; // I have the workaround that's not working! 
}else{ 
    return ''; 
} 
} 
+0

***「這裏是有問題的代碼:」***我沒有看到它'session_generate_id'。 –

回答

1

您的自定義處理程序必須在PHP7總是返回一個字符串。我在Dev上遇到了同樣的問題測試。我會做什麼(因爲這裏沒有失敗的案例)在以下

if(gettype($row['data']) != 'string') return ''; // It's not a string so return empty for failure 
return $row['data']; 

現在,爲你的錯誤,你的問題似乎是一個不好的參考。沒有看到代碼調用它,這看起來像你的問題

try{ 
    $this->dbh = new PDO($dsn, $this->user, $this->pass, $options); 
} 
// Catch any errors 
catch(PDOException $e){ 
    $this->error = $e->getMessage(); 
} 

因此,catch塊捕捉任何故障並設置一個內部變量。有些東西沒有檢查,以確保你有一個PDO對象。您可能需要回顯$e->getMessage();並查看是否有任何例外情況。因爲您發佈的錯誤表明上述塊失敗。

+0

我在編輯中顯示了上面的完整代碼。我試過如果(gettype($ row ['data'])!='string')return'';這並沒有解決它。奇怪的是我沒有進入捕獲塊......? –

+0

那麼,你需要回應出PDO錯誤。因爲錯誤,'$ this-> dbh''null' – Machavity

+0

終於解決了它,但感覺它很髒...... –

相關問題