事情是这样的。我的一位同事正试图覆盖我们使用的框架的会话处理。默认情况下,这个框架使用PHP自己的本地会话处理,但他现在正试图在请求之间实现一个数据库层。
问题是,在编写会话时,数据库对象不再可用,但它可用于其他功能,例如从会话中读取数据时。这是一种疯狂的行为。以下是我们所做的:
register_shutdown_function('exithandler');
session_set_save_handler(
'sess_open',
'sess_close',
'sess_read',
'sess_write',
'sess_destroy',
'sess_gc'
);
这些函数中的每一个还向我们的日志文件写入一行,我们可以使用函数的名称来跟踪它。无论何时调用函数,都会执行此操作。现在这里有两个请求的URL,第一个是实际写入会话的位置(会话的新数据),第二个是刚刚检查会话数据的位置(没有写入任何数据)。以下是谜题:
/login/
sess_open
sess_read
exithandler
sess_write
sess_close
/account/
sess_open
sess_read
sess_write
sess_close
exithandler
为什么这种行为不同?为什么在将数据存储到会话中之前调用出口处理程序?为什么对于常规页面,即使确实调用了相同的方法,情况也不一样?
问题是,在调用exithandler之后,我们的任何类都不再可用,我假设PHP垃圾收集器已经在我们所有的类上调用了__destruct()方法,它们就不见了。这太糟糕了。
有人知道PHP为什么会这样做吗?
正如您的评论所说的PHP5.4,您可能需要查看SessionHandlerInterface()
。您可以在open()
方法中传递register_shutdown_function
来半自动化过程,并真正利用PHP5.4的功能。
<?php
class MySessionHandler implements SessionHandlerInterface
{
private $savePath;
public function open($savePath, $sessionName)
{
register_shutdown_function('session_write_close');
$this->savePath = $savePath;
if (!is_dir($this->savePath)) {
mkdir($this->savePath, 0777);
}
return true;
}
public function close()
{
return true;
}
public function read($id)
{
return (string)@file_get_contents("$this->savePath/sess_$id");
}
public function write($id, $data)
{
return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
}
public function destroy($id)
{
$file = "$this->savePath/sess_$id";
if (file_exists($file)) {
unlink($file);
}
return true;
}
public function gc($maxlifetime)
{
foreach (glob("$this->savePath/sess_*") as $file) {
if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
unlink($file);
}
}
return true;
}
}
$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();