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

Php 如何删除数据库中具有特定变量值(用户ID)的所有会话?,php,mysql,session,Php,Mysql,Session,我将会话存储在数据库中,我希望在用户注销时删除所有会话行,以防他们在多台计算机上登录 我的会话表如下所示: id | access | data mj6u4v5rs3hqbo18o5p3ip9h45 2014-08-14 02:47:02 user_id|i:1;fb_123412341234_user_id|s:11:"12341243";..... public function _write($id, $d

我将会话存储在数据库中,我希望在用户注销时删除所有会话行,以防他们在多台计算机上登录

我的会话表如下所示:

id                         | access              | data
mj6u4v5rs3hqbo18o5p3ip9h45   2014-08-14 02:47:02   user_id|i:1;fb_123412341234_user_id|s:11:"12341243";.....
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;
}
如果用户在多台计算机上登录,则数据库中将有多行。我能看到的将行与用户关联的唯一方法是数据列中的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

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

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

如果用户id始终是数据中的第一个令牌,那么您可以执行以下操作:

id                         | access              | data
mj6u4v5rs3hqbo18o5p3ip9h45   2014-08-14 02:47:02   user_id|i:1;fb_123412341234_user_id|s:11:"12341243";.....
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;
}
从子字符串数据11位于“;”的会话中删除,数据-11={$user_id} 这里11是user|id | i:的长度,因此substring将返回user|id | i:结尾和分号第一次出现之间的子字符串,如果user|id始终位于第一位,则将返回user id


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

我想我找到了自己的解决方案。我修改了sessions表以添加一个user\u id列,然后修改了Session类,如下所示:

id                         | access              | data
mj6u4v5rs3hqbo18o5p3ip9h45   2014-08-14 02:47:02   user_id|i:1;fb_123412341234_user_id|s:11:"12341243";.....
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); 
编辑:然后执行一个查询,从数据库中删除用户id等于用户id的所有会话行


我还在测试,但到目前为止,这似乎是工作

我的问题是,如何删除与特定用户ID关联的所有行你不是在从id=:id的会话中删除吗?@Fred ii-不,删除是数据库中的一个特定行。如果一个用户登录到多台计算机上,那么数据库中将有多行,每一行都具有唯一的ID。所以行ID与用户ID无关,用户ID存储为会话数据。@好的,那么这些记录之间的共同点是什么?找到它,然后用它删除数据。编辑:刚刚看到你的帖子。非结构化数据总是会使这类任务变得棘手。您可能必须使用子字符串0、10==user_id | i:为删除创建自定义条件,然后使用该条件的位置,直到分号与您的用户匹配为止id@scrowler公共分母是数据列中的用户id值。但是,数据列中的数据是序列化的,因此我不能简单地查询user_id=1的会话中的delete-from。我可能可以做全文搜索,但我认为可能有更好的方法。我能问一下为什么你需要在注销时删除所有用户会话吗?假设有人在公共图书馆登录,然后忘记注销。他们是干什么的?唯一有效的解决方案是在用户从一台计算机注销时从所有计算机注销,即删除该用户的所有会话。包括StackOverflow在内的许多网站都采用这种方法。当然,但它们也不会以与您相同的方式存储会话数据。如果你真的担心它,最快和最安全的方法是将会话超时设置为一个低阈值。这是可能的吗?当然,但是他们也不会以与您相同的方式存储会话数据。那他们怎么储存呢?