在线用户计数器Yii2

3

我想在我的Yii 2应用程序中统计所有在线用户,你有什么解决方案?

即使我想要统计经过身份验证的用户。一种解决方案是在登录时覆盖authenticate方法,并在登录后在数据库中设置一个记录。但是这里我有一个问题。如何确定用户何时离线?如果我在注销操作中更改在线标志,就会出现一些问题。也许有些用户关闭浏览器而没有登录。然后数据库将显示他在线。这个问题的最佳解决方案是什么?

编辑

我的问题是如何覆盖会话过期方法。不更改到期时间。更详细地说,我想确定用户何时离线,即使他关闭浏览器而没有注销操作。


你的会话过期时间是多久?它能用来使已关闭浏览器的其他用户失效吗? - saurabh kamble
是的,这是一个明智的解决方案。但是如何重写会话过期方法? - Behzad Hassani
尝试这个 @behzad https://dev59.com/_Wcs5IYBdhLWcg3wcDaZ - saurabh kamble
2个回答

6

您可以将会话存储在数据库中,框架将为您处理过期问题。

这个例子来自高级模板,我已经从前端用户那里获取了会话。

我需要创建和使用一个自定义组件来存储用户ID。

1)在数据库中创建一个表:

    CREATE TABLE `session_frontend_user` (
    `id` char(80) CHARACTER SET utf8 NOT NULL,
    `user_id` int(11) DEFAULT NULL,
    `ip` varchar(15) CHARACTER SET utf8 NOT NULL,
    `expire` int(11) DEFAULT NULL,
    `data` longblob,
    PRIMARY KEY (`id`),
    KEY `expire` (`expire`)
    ) ENGINE=InnoDB

2)从这个表格中创建一个模型:

<?php

namespace common\models;

use Yii;

/**
 * This is the model class for table "session_frontend_user".
 *
 * @property string $id
 * @property integer $user_id
 * @property string $ip
 * @property integer $expire
 * @property resource $data
 */
class SessionFrontendUser extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'session_frontend_user';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id', 'ip'], 'required'],
            [['user_id', 'expire'], 'integer'],
            [['data'], 'string'],
            [['id'], 'string', 'max' => 80],
            [['ip'], 'string', 'max' => 15]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'user_id' => 'User ID',
            'ip' => 'Ip',
            'expire' => 'Expire',
            'data' => 'Data',
        ];
    }
}

3) 在config/main.php中更改配置

'components' => [

    'session' => [
        'class' => '\frontend\components\CustomDbSession',
        // 'db' => 'mydb',  // the application component ID of the DB connection. Defaults to 'db'.
        'sessionTable' => 'session_frontend_user', // session table name. Defaults to 'session'.
    ], 

4) 在路径 \frontend\components 中创建所需的自定义组件 'CustomDbSession',该组件在配置中使用:

<?php

namespace frontend\components;


use Yii;
use yii\db\Connection;
use yii\db\Query;
use yii\base\InvalidConfigException;
use yii\di\Instance;

class CustomDbSession extends \yii\web\DbSession {

    public $writeCallback = ['\frontend\components\CustomDbSession', 'writeCustomFields'];

    public function writeCustomFields($session) {

        try
        {
            $uid = (\Yii::$app->user->getIdentity(false) == null)?null:\Yii::$app->user->getIdentity(false)->id;
            return [ 'user_id' => $uid, 'ip' => $_SERVER['REMOTE_ADDR'] ];
        }
        catch(Exception $excp)
        {
            \Yii::info(print_r($excp), 'informazioni');


        }
    }


}

完美解决方案,对于自动清理,我们可以在一定时间间隔内使用ajax ;) - Behzad Hassani
当用户注销时,会话将被销毁,并且会话在1440秒内过期(或在php.ini中设置的“session.gc_maxlifetime”值)。 - Fabrizio Caldarelli
不,它清除了user_id字段。我在你的解释后进行了测试。 - Behzad Hassani

2

目前没有立即确定用户是否离线的方法,如果你曾经测试过Facebook(和其他网站),你会很快意识到这一点。

最常见的方法(如果你在Chrome Web工具中查看Facebook,他们直到最近仍在使用此方法,可能仍在使用)是使用某种隐藏的iframe来向服务器发送“心跳”,以表示用户仍然在线。

通常最好不要依赖于会话(特别是如果您使用多个设备类型),而是更多地从已认证的来源请求用户是否登录。因此,我会将“在线”字段存储在用户上,并在每次进行“心跳”时检查该字段。


感谢您的回复。 - Behzad Hassani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接