Мониторинг онлайн пользователей в PHP приложении
Основной метод: хранение времени последней активности в базе данных
В качестве наиболее эффективного решения для отслеживания онлайн-пользователей используется запись в реляционной базе данных времени последнего запроса каждого пользователя. При каждом визите страницы обновляется поле last_activity. Пользователь считаётся онлайн, если его последняя активность была не более заданного таймаута (например, 5 минут).
Пример структуры таблицы users с дополнительным полем:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
last_activity DATETIME NULL
);
Php скрипт пользователи (php скрипт управления пользователями)
Код PHP для обновления времени при каждом запросе:
<?php
session_start();
$userId = $_SESSION['user_id'];
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('UPDATE users SET last_activity = NOW() WHERE id = ?');
$stmt->execute([$userId]);
?>
Users view login php (просмотр пользователей php)
Получение списка онлайн пользователей:
$timeout = 300; // 5 минут
$deadline = date('Y-m-d H:i:s', time() - $timeout);
$query = $pdo->query("SELECT username FROM users WHERE last_activity >= '$deadline'");
$onlineUsers = $query->fetchAll(PDO::FETCH_COLUMN);
Action profile profile php (действие профиля в php)
Типичные проблемы и решения:
- Нагрузка на БД: при большом количестве пользователей каждое обновление может быть затратным. Решение - использовать кэширование (Redis) или агрегировать обновления через очередь.
- Гонка состояний: два одновременных запроса могут обновить время с разницей в секунду - некритично. Для строгой точности применяется блокировка строки (FOR UPDATE).
- Очистка устаревших записей: сами по себе они не мешают, но для экономии места можно запускать CRON-задачу:
DELETE FROM users WHERE last_activity < NOW() - INTERVAL 1 DAY
Как определить онлайн пользователей через файловую систему?
Метод основан на хранении временных файлов для каждой сессии. При входе создаётся файл в каталоге /tmp/online/ с именем, соответствующим ID сессии, и временем последней активности внутри. Файлы со старым временем удаляются.
$onlineDir = '/tmp/online';
$sessionId = session_id();
file_put_contents("$onlineDir/$sessionId", time());
// очистка старых
foreach (glob("$onlineDir/*") as $file) {
$content = file_get_contents($file);
if (time() - $content > 300) {
unlink($file);
}
}
Online online user php (онлайн пользователь в php)
Проблемы: низкая производительность при большом количестве файлов, проблемы с монтированием tmpfs, отсутствие атомарности в некоторых операциях.
Как реализовать онлайн статус с помощью Redis?
Redis предоставляет структуру данных SORTED SET (отсортированное множество) с временем последней активности в качестве score.
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$userId = 42;
$redis->zAdd('online_users', time(), $userId);
// получить онлайн (активны последние 5 минут)
$deadline = time() - 300;
$redis->zRemRangeByScore('online_users', '-inf', $deadline); // очистка устаревших
$onlineIds = $redis->zRevRangeByScore('online_users', '+inf', $deadline);
$onlineIds = array_map('intval', $onlineIds);
User new php (новый пользователь в php)
Проблемы: необходимость установки Redis, потеря данных при перезапуске (если не сохранять на диск). Решение - настройка персистентности RDB/AOF.
Как использовать сессии и таблицу session в MySQL?
При встроенном хранении сессий в БД (создана таблица sessions) можно проверять время последней активности сессии.
CREATE TABLE sessions (
session_id VARCHAR(128) PRIMARY KEY,
last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
Обновление при каждом запросе через пользовательский обработчик сессий. Получение онлайн: SELECT COUNT(*) FROM sessions WHERE last_activity > NOW() - INTERVAL 5 MINUTE.
Проблемы: сложность реализации собственного обработчика сессий, блокировки на уровне таблицы при частых записях.
Расширенные примеры реализации отслеживания онлайн пользователей
Пример 1. AJAX-пинг для обновления статуса
Клиент отправляет запрос каждые 60 секунд, сервер обновляет время последней активности.
// ajax_ping.php
<?php
session_start();
$userId = $_SESSION['user_id'] ?? null;
if ($userId) {
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $db->prepare('UPDATE users SET last_activity = NOW() WHERE id = ?');
$stmt->execute([$userId]);
echo 'ok';
} else {
http_response_code(401);
}
?>
// JavaScript (jQuery)
setInterval(function() {
$.get('ajax_ping.php');
}, 60000);
Пример 2. Отображение списка онлайн с именем и временем
<?php
$pdo = new PDO(...);
$timeout = 300;
$deadline = date('Y-m-d H:i:s', time() - $timeout);
$stmt = $pdo->prepare('
SELECT username, last_activity
FROM users
WHERE last_activity >= ?
ORDER BY last_activity DESC
');
$stmt->execute([$deadline]);
$online = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<ul>
<?php foreach ($online as $user): ?>
<li><?= htmlspecialchars($user['username']) ?> - <?= $user['last_activity'] ?></li>
<?php endforeach; ?>
</ul>
Результат (пример):
- admin - 2025-02-18 14:35:12
- user1 - 2025-02-18 14:33:40
- user2 - 2025-02-18 14:30:15
Пример 3. Комбинирование Redis и MySQL для асинхронной записи
PHP обновляет время в Redis, а отдельный демон (или CRON) переносит данные в MySQL раз в минуту. Это снижает нагрузку на БД.
// обновление в PHP
$redis = new Redis();
$redis->connect('127.0.0.1');
$redis->zAdd('online:latest', time(), $userId);
// CRON-скрипт (запуск раз в 60 сек)
$allNew = $redis->zRangeByScore('online:latest', (time()-60), '+inf');
$pdo = new PDO(...);
$stmt = $pdo->prepare('INSERT INTO users (id, last_activity) VALUES (?, NOW()) ON DUPLICATE KEY UPDATE last_activity = NOW()');
foreach ($allNew as $uid) {
$stmt->execute([$uid]);
}
$redis->del('online:latest');
Пример 4. Безопасное удаление устаревших записей через транзакцию
$pdo->beginTransaction();
try {
$pdo->exec("DELETE FROM users WHERE last_activity < NOW() - INTERVAL 5 MINUTE");
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
// логирование ошибки
}
// Сообщение об удалении (количество удалённых строк) echo 'Очищено: ' . $stmt->rowCount() . ' записей';
Пример 5. Использование cookies для отслеживания гостей
Для неавторизованных пользователей можно создать временный идентификатор, хранящийся в cookie, и записывать его в таблицу online_guests.
if (!isset($_COOKIE['guest_id'])) {
$guestId = bin2hex(random_bytes(16));
setcookie('guest_id', $guestId, time()+3600, '/');
} else {
$guestId = $_COOKIE['guest_id'];
}
$pdo->prepare('INSERT INTO online_guests (guest_id, last_activity) VALUES (?, NOW()) ON DUPLICATE KEY UPDATE last_activity = NOW()')
->execute([$guestId]);