如何使用特定变量值(用户ID)删除数据库中的所有会话?

时间:2014-08-14 03:07:31

标签: php mysql session

我将会话存储在数据库中,并且我希望在用户注销时删除所有会话行作为安全预防措施(如果他们已经在多台计算机上登录)。

我的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;
    }
} 

3 个答案:

答案 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的数据库中删除所有会话行。

我还在测试,但到目前为止这似乎有效!