本文目录导读:

我来详细介绍PHP用户在线状态维护的几种方案:
基于Session的方案(最简单)
实现方式
<?php
// 使用session最后活动时间
session_start();
$_SESSION['last_activity'] = time();
// 判断用户是否在线(5分钟内活跃)
function isUserOnline($lastActivity) {
return (time() - $lastActivity) < 300;
}
// 更新在线状态
function updateOnlineStatus($userId) {
$_SESSION['user_id'] = $userId;
$_SESSION['last_activity'] = time();
}
?>
优点: 简单易实现
缺点: 无法跨设备、无法持久化、Session过期即失效
数据库方案(推荐)
数据库表结构
CREATE TABLE user_online (
user_id INT PRIMARY KEY,
last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR(45),
session_id VARCHAR(100),
user_agent VARCHAR(255),
INDEX idx_last_activity (last_activity)
);
核心实现代码
<?php
class UserOnlineManager {
private $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
// 记录用户活动
public function trackActivity($userId) {
$sessionId = session_id();
$ip = $_SERVER['REMOTE_ADDR'];
$userAgent = $_SERVER['HTTP_USER_AGENT'];
$sql = "INSERT INTO user_online (user_id, last_activity, ip_address, session_id, user_agent)
VALUES (?, NOW(), ?, ?, ?)
ON DUPLICATE KEY UPDATE
last_activity = NOW(),
ip_address = VALUES(ip_address),
session_id = VALUES(session_id)";
$stmt = $this->pdo->prepare($sql);
return $stmt->execute([$userId, $ip, $sessionId, $userAgent]);
}
// 检查用户是否在线
public function isOnline($userId, $timeout = 300) {
$sql = "SELECT COUNT(*) FROM user_online
WHERE user_id = ?
AND last_activity > DATE_SUB(NOW(), INTERVAL ? SECOND)";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([$userId, $timeout]);
return $stmt->fetchColumn() > 0;
}
// 获取在线用户列表
public function getOnlineUsers($timeout = 300) {
$sql = "SELECT user_id, last_activity FROM user_online
WHERE last_activity > DATE_SUB(NOW(), INTERVAL ? SECOND)";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([$timeout]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 清理过期记录(定期执行)
public function cleanupExpired($timeout = 300) {
$sql = "DELETE FROM user_online
WHERE last_activity < DATE_SUB(NOW(), INTERVAL ? SECOND)";
$stmt = $this->pdo->prepare($sql);
return $stmt->execute([$timeout]);
}
// 用户登出时主动删除
public function userLogout($userId) {
$sql = "DELETE FROM user_online WHERE user_id = ?";
$stmt = $this->pdo->prepare($sql);
return $stmt->execute([$userId]);
}
}
?>
在应用中集成
<?php
// 在页面加载时调用
require_once 'UserOnlineManager.php';
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$onlineManager = new UserOnlineManager($pdo);
// 已登录用户每次请求都更新状态
if ($_SESSION['user_id']) {
$onlineManager->trackActivity($_SESSION['user_id']);
}
// 在需要的地方检查在线状态
if ($onlineManager->isOnline(123)) {
echo "用户在线";
} else {
echo "用户离线";
}
?>
Redis方案(高性能)
使用Redis实现
<?php
class RedisUserOnline {
private $redis;
private $prefix = 'user:online:';
public function __construct($redis) {
$this->redis = $redis;
}
// 记录用户在线
public function markOnline($userId) {
$key = $this->prefix . $userId;
return $this->redis->setex($key, 300, time());
}
// 检查用户是否在线
public function isOnline($userId) {
$key = $this->prefix . $userId;
return $this->redis->exists($key);
}
// 批量获取在线状态
public function getBulkOnline($userIds) {
$keys = array_map(function($id) {
return $this->prefix . $id;
}, $userIds);
return $this->redis->mget($keys);
}
// 获取所有在线用户(需要维护一个集合)
public function markOnlineWithTracking($userId) {
$key = $this->prefix . $userId;
$this->redis->setex($key, 300, time());
// 记录在线集合
$this->redis->sAdd('online:users', $userId);
}
// 获取在线用户数
public function getOnlineCount() {
return $this->redis->scard('online:users');
}
}
?>
实时推送方案(WebSocket)
结合Node.js + Socket.io
// client端JavaScript
const socket = io('wss://your-server.com');
// 记录用户活动
setInterval(() => {
socket.emit('heartbeat', { userId: userId });
}, 60000); // 每分钟发送一次心跳
// 实时获取在线用户
socket.on('onlineUsers', (users) => {
console.log('在线用户:', users);
});
PHP服务端处理心跳
<?php
// 通过API接口接收心跳
public function handleHeartbeat($userId) {
// 更新数据库或Redis状态
$this->trackActivity($userId);
// 广播在线状态变化(通过消息队列或WebSocket)
$broadcastData = [
'user_id' => $userId,
'status' => 'online'
];
}
?>
性能优化建议
批量更新
<?php
// 使用延迟批量更新
class BatchOnlineManager {
private $pendingUpdates = [];
public function queueActivity($userId) {
$this->pendingUpdates[$userId] = time();
}
public function flushUpdates() {
if (empty($this->pendingUpdates)) return;
$sql = "INSERT INTO user_online (user_id, last_activity) VALUES ";
$values = [];
$params = [];
foreach ($this->pendingUpdates as $userId => $time) {
$values[] = "(?, ?)";
$params[] = $userId;
$params[] = date('Y-m-d H:i:s', $time);
}
$sql .= implode(',', $values);
$sql .= " ON DUPLICATE KEY UPDATE last_activity = VALUES(last_activity)";
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$this->pendingUpdates = [];
}
public function __destruct() {
$this->flushUpdates();
}
}
?>
完整示例:综合方案
<?php
class OnlineUserService {
private $db;
private $redis;
private $timeout = 300; // 5分钟超时
public function __construct($db, $redis = null) {
$this->db = $db;
$this->redis = $redis;
}
// 核心方法:更新在线状态
public function updateStatus($userId) {
// 方案1:更新数据库
$this->updateDatabase($userId);
// 方案2:更新Redis(如果可用)
if ($this->redis) {
$this->updateRedis($userId);
}
}
private function updateDatabase($userId) {
$sql = "UPDATE users SET last_active = NOW(), is_online = 1
WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
}
private function updateRedis($userId) {
$key = "user:online:{$userId}";
$this->redis->setex($key, $this->timeout, 1);
}
// 检查在线状态
public function checkOnline($userId) {
// 优先从Redis读取
if ($this->redis) {
$result = $this->redis->get("user:online:{$userId}");
if ($result !== null) {
return $result == 1;
}
}
// 回退到数据库查询
$sql = "SELECT is_online, last_active FROM users WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
$user = $stmt->fetch();
if ($user && $user['is_online']) {
return (time() - strtotime($user['last_active'])) <= $this->timeout;
}
return false;
}
// 获取在线用户数量
public function getOnlineCount() {
if ($this->redis) {
// Redis方式
$keys = $this->redis->keys('user:online:*');
return count($keys);
} else {
// 数据库方式
$sql = "SELECT COUNT(*) FROM users
WHERE is_online = 1
AND last_active > DATE_SUB(NOW(), INTERVAL 5 MINUTE)";
return $this->db->query($sql)->fetchColumn();
}
}
}
?>
最佳实践建议
- 超时设置:根据业务需求设置合理的超时时间(通常3-5分钟)
- 清理机制:定期清理过期记录,防止数据膨胀
- 性能考虑:高并发场景使用Redis,低并发使用数据库
- 用户感知:在页面加载时更新状态,离开时发送离线信号
- 安全考虑:防止恶意刷在线状态,验证用户身份后再更新
- 扩展性:考虑支持多设备登录,每个设备独立维护状态
根据实际需求选择合适方案,小型应用用Session或数据库即可,大型应用建议使用Redis或WebSocket方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播