【问题标题】:How to delete all sessions in database with a certain variable value (user ID)?如何删除数据库中具有特定变量值(用户 ID)的所有会话?
【发布时间】:2014-10-07 14:15:43
【问题描述】:

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

我的sessions 表如下所示:

id                         | access              | data
mj6u4v5rs3hqbo18o5p3ip9h45   2014-08-14 02:47:02   user_id|i:1;fb_123412341234_user_id|s:11:"12341243";.....

如果用户在多台计算机上登录,那么数据库中将有多行。我可以看到将行与用户关联的唯一方法是 data 列中的 user_id 变量。

我的问题是,如何删除与特定用户 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;
    }
} 

【问题讨论】:

  • “我的问题是,如何删除与特定用户 ID 关联的所有行?” - 你不是用 DELETE FROM sessions WHERE id = :id 做的吗?
  • @Fred-ii- 不,删除是数据库中的特定行。如果用户在多台计算机上登录,那么数据库中将有多行供他们使用(每行都有唯一的 ID)。所以行 ID 和用户 ID 没有任何关系,用户 ID 是作为会话数据存储的。
  • @Nate 好的,那么这些记录之间的共同点是什么?找到它,然后用它来删除您的数据。 编辑: 刚刚看到你的帖子。非结构化数据总是会让这类任务变得棘手。您可能必须使用例如为您的删除创建自定义条件子字符串 0, 10 == user_id|i: 然后是它的位置,直到分号与您的用户 ID 匹配
  • @scrowler 共同点是data 列中的user_id 值。但是data列中的数据是序列化的,所以我不能简单地查询delete from sessions where user_id = 1。我也许可以进行全文搜索,但我认为可能有更好的方法。

标签: php mysql session


【解决方案1】:

简而言之,以您当前的设置,您无法完成您想要完成的工作。

您的所有课程都设置为使用会话表中的id,这与特定浏览器相关。

我认为您能够做到这一点的唯一方法是创建一个辅助脚本(扩展类或创建一个完全不同的脚本),该脚本将查看会话表,选择每一行并取消序列化 data 实体.但是,我不建议将其用于生产量大的网站。

我能问一下为什么需要在注销时删除所有用户会话吗?

【讨论】:

  • Can I ask why you need to delete all user sessions on logout? 假设有人在公共图书馆登录,然后忘记退出。他们在做什么?唯一有效的解决方案是在用户从一台计算机上注销时从所有计算机上注销(即删除该用户的所有会话)。包括 StackOverflow 在内的许多网站都采用这种方法。
  • 当然,但他们也不会以与您相同的方式存储会话数据。如果您真的担心它,最快和最安全的方法是将会话超时设置为低阈值。这可能吗?
  • Sure, but they also don't store their session data in the same manner as you. 那他们怎么存储呢?
【解决方案2】:

如果user_id 始终是data 中的第一个标记,那么您可以执行以下操作:

DELETE FROM sessions WHERE SUBSTRING(data, 11, LOCATE(';', data) - 11) = {$user_id}

这里 11 是 "user_id|i:" 的长度,所以substring 将返回介于 "user_id|i:" 结尾和第一次出现的分号之间的子字符串,如果 user_id总是先行,将是用户 ID。

如果 user_id 不一定是第一个标记,那么函数会稍微困难一些(特别是因为您的另一个变量 fb111_user_id 具有 user_id 作为子字符串),但仍然可行。

【讨论】:

    【解决方案3】:

    我想我找到了自己的解决方案。我修改了我的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。

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

    【讨论】:

      猜你喜欢
      • 2013-11-11
      • 1970-01-01
      • 2013-08-19
      • 1970-01-01
      • 2020-09-25
      • 1970-01-01
      • 1970-01-01
      • 2016-11-15
      • 1970-01-01
      相关资源
      最近更新 更多