如何在Yii2中获取在线用户列表?需区分在线与已退出用户
Hey there! Let's break down how to get a list of online users in Yii2, plus how to tell apart active users from those who've logged out. I've got two reliable approaches for you:
This method is robust and works well for most applications. Here's how to set it up:
Step 1: Update Your User Table
First, add two fields to your user table (adjust names if needed):
last_active_at: Datetime field to store the user's last activity timestampis_online: Tinyint(1) field (0 for offline, 1 for online)
Step 2: Update Status on Login
When a user logs in successfully, update their online status and last active time:
// In SiteController's actionLogin method if ($model->login()) { Yii::$app->user->identity->updateAttributes([ 'last_active_at' => date('Y-m-d H:i:s'), 'is_online' => 1 ]); return $this->goBack(); }
Step 3: Auto-Update Activity with a Behavior
To keep track of user activity as they navigate your site, create a global behavior that updates last_active_at periodically:
// Create app/components/UserActivityBehavior.php namespace app\components; use yii\base\Behavior; use yii\web\Controller; use Yii; class UserActivityBehavior extends Behavior { public function events() { return [ Controller::EVENT_BEFORE_ACTION => 'updateLastActive', ]; } public function updateLastActive() { if (!Yii::$app->user->isGuest) { $user = Yii::$app->user->identity; // Only update every 5 minutes to avoid excessive DB calls if (strtotime($user->last_active_at) < time() - 300) { $user->updateAttributes([ 'last_active_at' => date('Y-m-d H:i:s'), 'is_online' => 1 ]); } } } }
Register this behavior in your config/web.php so it runs on every controller action:
'components' => [ // ... other component configs 'controller' => [ 'as userActivity' => [ 'class' => 'app\components\UserActivityBehavior', ], ], ],
Step 4: Mark User as Offline on Logout
When a user explicitly logs out, set their is_online status to 0:
// In SiteController's actionLogout method public function actionLogout() { if (!Yii::$app->user->isGuest) { Yii::$app->user->identity->updateAttributes(['is_online' => 0]); } Yii::$app->user->logout(); return $this->goHome(); }
Step 5: Fetch Online/Offline Users
Add static methods to your User model to retrieve the lists:
// In models/User.php public static function getOnlineUsers() { // Consider users online if they've been active in the last 10 minutes $timeout = time() - 600; return self::find() ->where(['>', 'last_active_at', date('Y-m-d H:i:s', $timeout)]) ->andWhere(['is_online' => 1]) ->all(); } public static function getLoggedOutUsers() { // Users marked as offline OR inactive for over 10 minutes $timeout = time() - 600; return self::find() ->where(['is_online' => 0]) ->orWhere(['<', 'last_active_at', date('Y-m-d H:i:s', $timeout)]) ->all(); }
If you don't want to modify your database, you can use Yii2's cache component to track online users. Note: This is better for smaller apps since iterating over cache keys can be inefficient at scale.
Step 1: Store Session on Login
When a user logs in, store their session ID in cache with an expiration:
// After successful login $userId = Yii::$app->user->id; $sessionId = Yii::$app->session->id; // Cache for 1 hour (adjust as needed) Yii::$app->cache->set("online_user_{$userId}", $sessionId, 3600);
Step 2: Remove Cache on Logout
Delete the cache entry when the user logs out:
// In actionLogout $userId = Yii::$app->user->id; Yii::$app->cache->delete("online_user_{$userId}");
Step 3: Fetch Online Users
Retrieve all users with active cache entries:
// In User model public static function getOnlineUsersViaCache() { $keys = Yii::$app->cache->getKeys(); $onlineUserIds = []; foreach ($keys as $key) { if (strpos($key, 'online_user_') === 0) { $userId = str_replace('online_user_', '', $key); $onlineUserIds[] = (int)$userId; } } return self::findAll(['id' => $onlineUserIds]); }
Important Note
For users who close their browser without logging out, the database approach's timeout check will automatically mark them as offline after the set inactivity period. For the cache method, the cache entry will expire after the set time, removing them from the online list.
内容的提问来源于stack exchange,提问作者Angelo De Giacomo

