我将会话存储在数据库中,并且我希望在用户注销时删除所有会话行作为安全预防措施(如果他们已经在多台计算机上登录)。
我的sessions
表格如下:
id | access | data
mj6u4v5rs3hqbo18o5p3ip9h45 2014-08-14 02:47:02 user_id|i:1;fb_123412341234_user_id|s:11:"12341243";.....
如果用户登录多台计算机,则数据库中将有多行。我可以看到将行与用户相关联的唯一方法是user_id
列中的data
变量。
我的问题是,如何删除与特定用户ID关联的所有行?
这是会话类:
namespace app;
class Session {
/** @var \PDO */
private $db;
function __construct(\PDO $db) {
$this->db = $db;
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 test() {
return 'hey';
}
public function _open() {
return true;
}
public function _close() {
return true;
}
public function _read($id) {
$stmt = $this->db->prepare('SELECT data FROM sessions WHERE id = :id');
makeQuery($stmt, array(':id' => $id));
$sRow = $stmt->fetch(\PDO::FETCH_ASSOC);
if (!empty($sRow)) {
return $sRow['data'];
}
else {
return '';
}
}
public function _write($id, $data) {
$stmt = $this->db->prepare('REPLACE INTO sessions VALUES (:id, UTC_TIMESTAMP(), :data)');
makeQuery($stmt, array(':id' => $id, ':data' => $data));
return true;
}
public function _destroy($id) {
$stmt = $this->db->prepare('DELETE FROM sessions WHERE id = :id');
makeQuery($stmt, array(':id' => $id));
return true;
}
public function _gc($maxLifetimeTimestamp) {
$maxLifetime = date('Y-m-d H:i:s', $maxLifetimeTimestamp);
$stmt = $this->db->prepare('DELETE FROM sessions WHERE (UTC_TIMESTAMP() - access) > :maxLifetime'); // @todo test this to ensure math is correct
makeQuery($stmt, array(':maxLifetime' => $maxLifetime));
return true;
}
}
答案 0 :(得分:0)
简而言之,根据您当前的设置,您无法完成您想要完成的任务。
所有课程都设置为在会话表中的id
处理,这与特定浏览器相关。
我认为你能够做到的唯一方法是创建一个辅助脚本(扩展类或创建一个完全不同的脚本),它将查看会话表,选择每一行并反序列化{{1} } 实体。但是,我不建议将其用于生产量大的网站。
我可以问你为什么需要在注销时删除所有用户会话?
答案 1 :(得分:0)
如果user_id
始终是data
中的第一个令牌,那么您可以执行以下操作:
DELETE FROM sessions WHERE SUBSTRING(data, 11, LOCATE(';', data) - 11) = {$user_id}
这里11是“user_id | i:”的长度,因此substring
将返回“user_id | i:”结尾与分号的第一次出现之间的子字符串,如果{ {1}}总是先行,将是用户ID。
如果user_id不一定是第一个令牌,那么该函数会稍微困难一些(特别是因为你的另一个变量fb111_user_id将user_id作为子串),但仍然可行。
答案 2 :(得分:0)
我想我找到了自己的解决方案。我修改了sessions
表格以添加user_id
列,然后像这样修改了我的Session
类:
public function _write($id, $data) {
$stmt = $this->db->prepare('REPLACE INTO sessions VALUES (:id, UTC_TIMESTAMP(), :data, :userId)');
makeQuery($stmt, array(':id' => $id, ':data' => $data, ':userId' => isset($_SESSION['user_id'])?$_SESSION['user_id']:null));
return true;
}
然后,当用户退出时,我使用以下代码:
session_destroy();
unset($_SESSION);
setcookie('PHPSESSID', '', time() - 48*3600, '/', null, null, true);
编辑:然后执行查询以从user_id
等于用户ID的数据库中删除所有会话行。
我还在测试,但到目前为止这似乎有效!