在经过数小时的调试过程中,我发现在众多Google搜索中找到的参考文章以及大量的Stack
Overflow答案(例如here,here和here)都提供了无效或过时的信息。
在将会话数据保存到数据库中可能导致[严重]问题的事情:
尽管所有在线示例都说明您可以“填充”
session_set_save_handler
,但没有一个示例说明您也必须设置它register_shutdown_function('session_write_close')
(参考)。一些(旧的)导游指的是过时的SQL数据库结构,应该 不会 被使用。将会话数据保存到数据库所需的数据库结构是:
id
/access
/data
。而已。正如我在一些“指南”和示例中看到的那样,不需要各种额外的时间戳列。- 一些较旧的指南也已经过时的MySQL语法,例如
DELETe * FROM ...
- 类[我的问题作出]必须 实现 的
SessionHandlerInterface
。我已经看到了指南(上面已引用),这些指南给出的实现方式sessionHandler
不合适。也许以前版本的PHP的方法稍有不同(可能小于5.4)。
- 一些较旧的指南也已经过时的MySQL语法,例如
会话类方法 必须 返回PHP手册中列出的值。同样,可能是从PHP 5.4之前的版本继承的,但是我阅读的两个指南指出
class->open
返回要读取的行,而PHP手册指出需要返回true
或false
仅返回行 。这是导致我的原始问题的原因 :根据这个非常好的StackOverflow帖子,我使用的是自定义会话名称(实际上,会话名称和会话ID 都是相同的! ),并且生成的会话名称长度为128个字符。由于会话名称是唯一的密钥,需要破解才能破坏会话并接管会话劫持,因此较长的名称/ ID是一件好事。
- 但是,这引起了一个问题,因为 MySQL默默地 将会话 ID切成 32个字符而不是128个字符,因此它永远无法在数据库中找到会话数据。这是一个完全沉默的问题(可能是由于我的数据库连接类未引发此类警告)。但这是要提防的。如果从数据库检索会话有任何问题,请首先检查 完整的 会话ID是否可以存储在提供的字段中。
因此,除了所有这些之外,还需要添加一些额外的细节:
PHP手册页(上面链接)显示了一个类对象不合适的行:
$handler = new MySessionHandler();session_set_save_handler($handler, true);session_start();
如果将其放在类构造函数中,效果也一样:
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(); }...}
这 意味着要在输出页面上开始会话,您需要做的是:
<?phprequire "path/to/sessionhandler.class.php"; new MySessionHandler();//Bang session has been setup and started and works
作为参考,完整的Session通信类如下所示,该类可与PHP 5.6一起使用(可能是7,但尚未在7上进行测试)
<?phpclass MySessionHandler implements SessionHandlerInterface { private $database = null; public function __construct($sessionDBconnectionUrl){ 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(); } 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; } 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 ''; } } 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; } } public function destroy($id) { // Set query if ($this->database->noReturnQuery('DELETE FROM sessions WHERe id = ? LIMIT 1', $id)) { return true; } else { return false; } } public function close(){ // Close the database connection if($this->database->dbilink->close){ // Return True return true; } // Return False return false; } 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(); }}
用法:如类代码文本上方所示。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)