Довольно частый вопрос, который задают мне начинающие веб-программисты — это «как определить — онлайн или оффлайн пользователь сайта в данный момент?»
Самый простой и неточный способ — запоминать в базе момент времени, когда конкретный юзер открыл последнюю страницу. Если это время на N минут меньше чем текущее — значит он уже ушёл. Этот метод годится только если юзер постоянно лазит по страничкам и подтверждает своё присутствие. Если он «зачитался» и долго не кликает ссылок на сайте, то скрипт ошибочно определяет его уход.
Более точный способ — в шапку сайта вшить небольшой js-скрипт, работающий по таймеру и отправляющий каждую минуту, например, небольшой пакет, подтверждающий, что страница всё ещё открыта. Сервер запоминает момент прихода последнего из таких пакетов и тем самым может однозначно определить — находится юзер на сайте или нет. Минусы данного способа очевидны: большая нагрузка на сервер. Если сайт одновременно просматривают 100 пользователей, то сервер будет буквально захлёбываться такими пакетами.
Но просто открытое окно ещё не гарантирует нам, что пользователь находится за компьютером. Поэтому необходимо вводить дополнительные проверки, например в js опрашивать событие onmousemove и проверять активность окна (т.е. открыто оно наверху или свёрнуто, а может быть находится под другими окнами). Этим самым мы уточняем — просматривает ли юзер наш сайт физически или он ушёл чай пить, а окно оставил открытым. И затем по таймеру отправлять статус. Недостаток такой же — загрузка сервера пакетами.
Самый сложный, но оптимальный способ. Каждая страница отправляет пинг-пакет на сервер при открытии, при закрытии, при начале неактивности пользователя и при возобновлении активности (например, если юзер 5 минут не двигает мышь, то отправляем пакет «юзер отошёл», как только он вновь двинул мышь — отправляем пакет «юзер пришёл»). Если окно закрываем — отправляем сообщение «окно закрыто». Важно отслеживать все окна, ведь юзер может открыть их несколько. Статус «оффлайн» ставим только тогда, когда юзер закрыл все окна.
Тут возможны подводные камни, например, юзер отключился от инета и только потом закрыл окна. В этом случае сервер не получит сообщения «юзер ушёл» и будет ошибочно думать, что он ещё с нами. Для этого каждые 10-20 минут все окна всё же должны посылать пинг-пакеты, подтверждая, что они ещё открыты.
На практике реализацию последнего метода я видел только на двух сайтах. Первый применяется достаточно часто, второй — тоже.
Но существует ещё один способ, обычно применяющийся, если на сайте есть чат. Но он может быть реализован и при отсутствии чата. Тут не так всё сложно — организуется Comet-обмен с сервером (обычно это 1 запрос в 1-1,5 минуты, так что сервер сильно не загружается запросами). Про работу протокола Comet (есть его аналог BOSH-XMPP) можете прочитать в интернете. Реализовать его сложнее, чем все вышеперечисленные, но эффективность и качество в этом случае наивысшее.
Для реализации Comet на PHP необходимо использовать фреймворк-демон, например, phpDaemon. А если есть возможность использовать серверный Javascript, то можно применить и nodejs. Я категорически рекомендую именно nodejs, потому что phpDaemon сейчас достаточно сырой и сложный в инсталляции и запуске, а nodejs лаконичен и если вы хорошо знаете Javascript, вам дополнительно ничего не придётся изучать (или почти ничего).
Если у Вас возникли дополнительные вопросы по статье — задайте их мне в комментариях. Я получаю уведомления о новых комментариях и всегда стараюсь на них отвечать.
Про COMET хотелось бы интересную статью…