2016-05-14 10 views
0

PHP 5.6から7にアップグレードし、カスタムセッションハンドラスクリプトを使用してデータベース内のセッションを管理し、ユーザをより適切に管理できるようにしました。 1つのことを除いて、すべてが以前と同じように機能します。PHP 7 session_regenerate_idメンバ関数への失敗とPDO呼び出しnullの場合prepare()null

session_regenerate_id(true); 

ユーザーが正常にログインした後、セッション固定を回避するために、session_regenerate_idを呼び出します。

[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 7ではないので、PHP 5.6でうまくいきました。これはPHPからの正式な返答です。

  • PHP 7.0以降では、ユーザセーブハンドラからのバグの返り値を許可していません。 ユーザー読み取りハンドラは常に成功のために "文字列"データを返さなければなりません。
  • ネイティブ・セーブ・ハンドラは、存在しないセッション・データを含む成功したケースでは、SUCCESSを戻す必要があります。
  • FALSE/failureは、permission/network/etcエラーなどの「読み込みに誤りがあります」を意味します。

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

編集で上記の完全なコードを示しました。私は試みましたif(gettype($ row ['data'])!= 'string')return '';それはそれを修正していません。奇妙なことは私がキャッチブロックに入っていないことです...? –

+0

さて、PDOエラーをエコーアウトする必要があります。何かが失敗しているので、エラーにより、 '$ this-> dbh'は' null' – Machavity

+0

最後に解決しましたが、汚いと感じました... –

関連する問題