数時間のデバッグの過程で、多数のGoogle検索で参照された記事と、こちら
、こちら
および
セッションデータをデータベースに保存する際に[重大な]問題を引き起こす可能性のあるもの:
-
オンラインのすべての例では、
session_set_save_handler
を「埋める」ことができると述べています。 、register_shutdown_function('session_write_close')
も設定する必要があるとは記載されていません。 あまりにも(参照 )。 -
いくつかの(古い)ガイドは古いSQLデータベース構造を参照しているため、すべきではありません。 利用される。セッションデータをデータベースに保存するために必要なデータベース構造は次のとおりです。
id
/アクセスコード> /
データコード> 。それでおしまい。いくつかの「ガイド」と例で見たように、さまざまな追加のタイムスタンプ列は必要ありません。
- 古いガイドのいくつかには、
DELETE * FROM ...
などの古いMySQL構文もあります。
- 古いガイドのいくつかには、
-
[私の質問で作成された]クラスは、 実装 する必要があります。
SessionHandlerInterface
。sessionHandler
の実装を提供するガイド(上記参照)を見てきました これは適切なインターフェースではありません。おそらく、以前のバージョンのPHPには、わずかに異なる方法がありました(おそらく<5.4)。 -
セッションクラスのメソッドは必須 PHPマニュアルで設定されている値を返します。繰り返しになりますが、おそらく5.4より前のPHPから継承されていますが、私が読んだ2つのガイドでは、
class-> open
読み取る行を返しますが、PHPマニュアルの状態true
を返す必要があること またはfalse
のみ。 -
これが私の最初の問題の原因です :カスタムセッション名を使用していました(実際には、セッション名としてのIDとセッションIDのは同じものです! )この非常に優れたStackOverflow投稿 による これにより、128文字のセッション名が生成されていました。セッション名は、セッションを危険にさらし、セッションハイジャック その場合、名前/IDを長くすることは非常に良いことです。
- ただし、 MySQLがセッションIDをサイレントにスライスしていたため、これにより問題が発生しました。 128文字ではなく32文字に減少したため、データベースでセッションデータを見つけることができませんでした。これは完全にサイレントな問題でした(おそらく私のデータベース接続クラスがそのようなことの警告をスローしなかったためです)。しかし、これは注意すべきものです。データベースからのセッションの取得で問題が発生した場合は、最初にフルであることを確認してください。 セッションIDは、指定されたフィールドに保存できます。
ですから、これらすべてが邪魔にならないように、追加する追加の詳細もいくつかあります:
PHPのマニュアルページ(上記のリンク)には、クラスオブジェクトに不適切な行の山が示されています:
これをクラスコンストラクターに入れても同様に機能します:
class MySessionHandler implements SessionHandlerInterface {
private $database = null;
public function __construct(){
$this->database = new Database(whatever);
// Set handler to overide SESSION
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
register_shutdown_function('session_write_close');
session_start();
}
...
}
これ つまり、出力ページでセッションを開始するために必要なのは次のとおりです。
<?php
require "path/to/sessionhandler.class.php";
new MySessionHandler();
//Bang session has been setup and started and works
参考までに、完全なセッション通信クラスは次のとおりです。これはPHP 5.6で動作します(おそらく7ですが、7ではまだテストされていません)
<?php
/***
* Created by PhpStorm.
***/
class MySessionHandler implements SessionHandlerInterface {
private $database = null;
public function __construct($sessionDBconnectionUrl){
/***
* Just setting up my own database connection. Use yours as you need.
***/
require_once "class.database.include.php";
$this->database = new DatabaseObject($sessionDBconnectionUrl);
// Set handler to overide SESSION
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
register_shutdown_function('session_write_close');
session_start();
}
/**
* Open
*/
public function open($savepath, $id){
// If successful
$this->database->getSelect("SELECT `data` FROM sessions WHERE id = ? LIMIT 1",$id,TRUE);
if($this->database->selectRowsFoundCounter() == 1){
// Return True
return true;
}
// Return False
return false;
}
/**
* Read
*/
public function read($id)
{
// Set query
$readRow = $this->database->getSelect('SELECT `data` FROM sessions WHERE id = ? LIMIT 1', $id,TRUE);
if ($this->database->selectRowsFoundCounter() > 0) {
return $readRow['data'];
} else {
return '';
}
}
/**
* Write
*/
public function write($id, $data)
{
// Create time stamp
$access = time();
// Set query
$dataReplace[0] = $id;
$dataReplace[1] = $access;
$dataReplace[2] = $data;
if ($this->database->noReturnQuery('REPLACE INTO sessions(id,access,`data`) VALUES (?, ?, ?)', $dataReplace)) {
return true;
} else {
return false;
}
}
/**
* Destroy
*/
public function destroy($id)
{
// Set query
if ($this->database->noReturnQuery('DELETE FROM sessions WHERE id = ? LIMIT 1', $id)) {
return true;
} else {
return false;
}
}
/**
* Close
*/
public function close(){
// Close the database connection
if($this->database->dbiLink->close){
// Return True
return true;
}
// Return False
return false;
}
/**
* Garbage Collection
*/
public function gc($max)
{
// Calculate what is to be deemed old
$old = time() - $max;
if ($this->database->noReturnQuery('DELETE FROM sessions WHERE access < ?', $old)) {
return true;
} else {
return false;
}
}
public function __destruct()
{
$this->close();
}
}
使用法:クラスコードテキストのすぐ上に示されているように。