数据库会话处理程序问题
您好,我正在尝试了解会话如何工作以及 session_set_handler()
如何工作,因此我开始构建一个用于会话处理的类,但我遇到了 write( )
函数你能帮我解决这个问题吗?
<?php
class Session extends Model
{
public
$connectionName = 'sessions',
$sessionsId,
$sessionsData;
public function __construct()
{
parent::__construct();
session_set_save_handler(
array($this, 'Open'),
array($this, 'Close'),
array($this, 'Read'),
array($this, 'Write'),
array($this, 'Destroy'),
array($this, 'Gc'));
session_start();
}
public function __destruct()
{
session_write_close();
}
public function Open()
{
return true;
}
public function Close()
{
return true;
}
public function Read($sessionsId)
{
$this->stmt = $this->prepare("SELECT * FROM `sessions` WHERE `id` = :sessionId");
$this->stmt->bindParam(":sessionId", $sessionsId);
$this->stmt->execute();
return $this->stmt->fetchAll();
}
public function Write($sessionsId, $sessionsData)
{
$this->stmt = $this->prepare("REPLACE INTO `sessions`.`sessions`
(`id`, `access`, `data`)
VALUES
(:sessionId, NOW(), :sessionValue)");
$this->stmt->bindParam(":sessionId", $sessionsId);
$this->stmt->bindParam(":sessionValue", $sessionsData);
$this->stmt->execute();
}
public function Destroy($sessionsId)
{
$this->stmt = $this->prepare("DELETE FROM `sessions`.`sessions` WHERE `id` = :sessionId");
$this->stmt->bindParam(":sessionId", $sessionsId);
$this->stmt->execute();
}
public function Gc()
{
$this->stmt = $this->prepare("DELETE FROM `sessions`.`sessions` WHERE `access` < NOW() - INTERVAL 1 HOUR");
$this->stmt->execute();
}
}
现在上面的代码似乎工作得很好,唯一的问题是当我在数据库中写入会话时,我得到以下插入:
dump from mysql
CREATE TABLE IF NOT EXISTS `sessions` (
`id` varchar(32) NOT NULL,
`access` datetime NOT NULL,
`data` text NOT NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `sessions` (`id`, `access`, `data`) VALUES
('lhig71coed8ur81n85iiovje37', '2011-07-25 15:37:57', '');
正如你可以看到会话的值,它没有插入,我只得到会话ID。 对于 var_dump($sessionsData)
我得到:
"name|s:6:"Bogdan";"
对于 var_dump($sessionsId)
我得到:
lhig71coed8ur81n85iiovje37
你能帮忙吗?我没有收到任何错误检查 xampp 日志设置显示错误报告我所知道的所有内容,即使在 php.ini 中仍然没有任何错误,甚至尝试 catch 块也没有使用任何错误。非常感谢您阅读本文并帮助我。
Hello i'm trying to understand how sessions work and how does session_set_handler()
works, so i've started build a class for session handling but i've encountered some problems with the write()
function can you please help me solve the problem?
<?php
class Session extends Model
{
public
$connectionName = 'sessions',
$sessionsId,
$sessionsData;
public function __construct()
{
parent::__construct();
session_set_save_handler(
array($this, 'Open'),
array($this, 'Close'),
array($this, 'Read'),
array($this, 'Write'),
array($this, 'Destroy'),
array($this, 'Gc'));
session_start();
}
public function __destruct()
{
session_write_close();
}
public function Open()
{
return true;
}
public function Close()
{
return true;
}
public function Read($sessionsId)
{
$this->stmt = $this->prepare("SELECT * FROM `sessions` WHERE `id` = :sessionId");
$this->stmt->bindParam(":sessionId", $sessionsId);
$this->stmt->execute();
return $this->stmt->fetchAll();
}
public function Write($sessionsId, $sessionsData)
{
$this->stmt = $this->prepare("REPLACE INTO `sessions`.`sessions`
(`id`, `access`, `data`)
VALUES
(:sessionId, NOW(), :sessionValue)");
$this->stmt->bindParam(":sessionId", $sessionsId);
$this->stmt->bindParam(":sessionValue", $sessionsData);
$this->stmt->execute();
}
public function Destroy($sessionsId)
{
$this->stmt = $this->prepare("DELETE FROM `sessions`.`sessions` WHERE `id` = :sessionId");
$this->stmt->bindParam(":sessionId", $sessionsId);
$this->stmt->execute();
}
public function Gc()
{
$this->stmt = $this->prepare("DELETE FROM `sessions`.`sessions` WHERE `access` < NOW() - INTERVAL 1 HOUR");
$this->stmt->execute();
}
}
now the above code seems to work just fine the only problem is when i write a session in db i get the following insert:
dump from mysql
CREATE TABLE IF NOT EXISTS `sessions` (
`id` varchar(32) NOT NULL,
`access` datetime NOT NULL,
`data` text NOT NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `sessions` (`id`, `access`, `data`) VALUES
('lhig71coed8ur81n85iiovje37', '2011-07-25 15:37:57', '');
As you can see the value of the session it's not inserted i only get the session id.
on var_dump($sessionsData)
i get:
"name|s:6:"Bogdan";"
and for var_dump($sessionsId)
i get:
lhig71coed8ur81n85iiovje37
Can you please help? i don't get any errors checked xampp logs setup display errors on error reporting everything i knew even in php.ini still no error anything used even try catch blocks. thank you very much for reading this and helping me out.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我在您的实现中发现了一个缺陷,该缺陷会导致删除任何会话数据:
该
函数必须返回一个字符串,在您的情况下是来自
data
字段的数据。但是你返回一个数组(因为它看起来像 - 不能具体说,因为实际的数据库是隐藏的,PDO/MySQLi?)。
但是,反序列化会话数据(请参阅
session_decode()
)很可能会失败,因此会话数据将变空,然后再次保存(作为空字符串)。这应该是你的问题的原因。通过从数据库返回字符串数据来修复它。
除此之外,我怀疑存在某种编码问题,但我不完全确定这是导致它的原因。但请考虑以下情况:
会话数据是二进制数据,而不是文本。您可以更改表定义并进行相应的访问。在 MySQL 中,有
BLOB
类型 为此,bindParam()
可以是帮助PDO::PARAM_LOB
数据类型说明符。也许这种类型的改变会解决你的问题。否则,它将确保您存储的数据未更改,这在任何情况下都是您想要的。坚持对会话数据进行二进制安全处理。
I found a flaw in your implementation which results in deleting any session data:
in
That function must return a string, in your case the data from the
data
field.But you're returning an array (as it looks like - can't specifically say because the actual database is hidden, PDO/MySQLi?).
However it's highly likely that unserializing the session data (see
session_decode()
) will fail, hence the session data will become empty and then saved again (as an empty string).This should be the cause of your problem. Fix it by returning the string data from the database.
Next to that I suspect a kind of encoding issue but I'm not entirely sure that this causes it. But just consider the following:
The session data is binary data, not text. You could change your table definition and access accordingly. In MySQL there is the
BLOB
Type for that, andbindParam()
could be helped withPDO::PARAM_LOB
data type specifier.Probably this type of change will cure your issue. Otherwise it will make sure that you store the data un-altered which is what you want in any case. Stick to binary-safe handling for session data.