在线用户计数器Yii2

I want to count all online users in my Yii 2 application, what is your solution?

even I want to count authenticated users. one solution is to over ride authenticate method in login and after login I set a record in db. but here I have a problem. How should I determine when a user is offline? If I change online flag in logout action it has some problem. maybe some users close the browser without login. then database will shows him online. what is best solution for this problem?

Edit

My question is how to over ride session expire method. Not change expiration time. In more details, I want determine if a user is offline even he closes the browser without logout action

You could store sessions in database and the framework will handle expiration for you.

This example is from advanced template and I've takes session from frontend users.

I needed to create and use a custom component to store also the user id.

1) Create a table on db:

    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) Create a model from this table:

<?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) Change configuration in 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) Create the custom component 'CustomDbSession' required in configuration in path \frontend\components:

<?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');


        }
    }


}

There is no immediate method by which to determine a user is offline, if you have ever tested Facebook's own (and other site's) you will realise this very quickly.

The most common way (if you look in Chrome web tools for Facebook they still did this until recently, might still) is to use a hidden iframe of some kind to produce a "heart beat" to the server that says the user is still there.

It is normally better to not rely on sessions (especially if you use multiple device types) for whether a user is logged in but more a request from an authenticated source as them. As such I would store the "online now" field on the user and ping that field every time you do a heart beat.