Сколько человек на сайте?

Наверняка, гуляя по сети в поисках качественной порн..., т.е. качественной информации, вы натыкались на такую фишку, типа:

На сайте: 100 человек

Т.е., когда примерно в таком контексте выводится количество человек, присутствующих в данное время на сайте. Когда я впервые увидел такую фичу, мне она показалось интересной и симпотной. Недавно, по личной надобности, мне захотелось сделать такое для своего сайта и я реализовал все это дело с использованием PHP+MySQL. Итак, в этой статье я хочу вам рассказать, как сделать такую фичу для сайта. Это на самом деле проще жареной капусты ;=) и вскоре вы убедитесь в этом.

Все что нам нужно, это - хостинг с поддержкой PHP и MySQL и пара минут времени. Может быть, некоторые возразят, зачем здесь база данных, когда все можно реализовать на файлах. Скажу вам , что MySQL в данном конкретном случае подходит как нельзя лучше. С использованием файлов же, пришлось бы писать гораздо больше кода и заниматься в большинстве своем рутиной, которая нам ни к чему; в то время как с помощью базы данных все делается парой-другой запросов...

Я надеюсь, что вы умеете хоть как-то обращаться с сервером MySQL и знаете в целом, что такое базы данных и для чего они служат. В противном случае, не могу ничем помочь, кроме как посоветовать обратиться к друзьям, владеющим искусством составлять SQL-запросы... Хотя, в принципе, вы можете просто скопировать мой код и все. Однако, сама база данных все же должна быть настроена...

Итак, постепенно переходим от теории к практической ипостаси. В PHP, к сожалению (да и в других серверных языках веб-программирования), отсутствует такая, на мой взгляд, полезная технология, которая позволяла бы определять момент времени, в который человек покинул сайт. Неважно, каким способом, он это сделал: закрыл окно броузера или перешел по другой ссылке. Да это, в принципе, и невозможно с точки зрения логики. PHP работает на сервере и откуда ему знать, находится ли еще пользователь на сайте или уже давно как ушел.
Раз PHP пасует, сами сделаем кое-какую подобную технологию; естественно, о точности и отсутствии погрешностей здесь не говорю... Однако, все так делают и мы так сделаем. Далее опишу, как мы будем, собственно, определять кол-во юзеров на линии теоретически (не касаясь MySql и PHP конкретно). Если вы уловите мысль, то тотчас же реализуете эту возможность на любом языке веб-программирования и любым доступным для вас методом (файлы, к примеру)...

Для начала, нам нужно установить переменную Точность - время, в течении которого посетитель будет считаться на линии, т.е. бродящем по сайту.

Значит, при заходе на страницу, мы должны определить сперва-наперво IP-адрес зашедшего и его timestamp. Никакой экзотики, TimeStamp - это представление времени, которое равняется "кол-ву секунд, прошедших с полуночи 1 января 1970 года по Гринвичу до настоящего момента". Это весьма универсальное представление времени и, в частности, именно с этим форматом работает большинство PHP-х ф-й для работы с "датой-временем". Весьма удобная метка, поверьте мне на слово. Т.е., чем больше число TimeStamp, чем дольше "мы живем" и чем больше "сейчас времени", извиняюсь за сумбурность.

После, мы открываем какое-либо хранилище (файлы, базы данных, сессионный массив и т.п.) и удаляем из него все записи (каждая запись - информация об одном зашедшем на страничку пользователе), в которых TimeStamp + Точность меньше текущего TimeStamp'а. Т.е., уничтожаем старые записи.

Далее записываем данные о зашедшем пользователе (оставляем запись): IP и timestamp. Однако, если в нашем временном хранилище уже есть запись с IP-м, под которым зашёл человек, то мы ничего, естественно, не записываем. Иначе же, логически скрипт уже будет работать некорректно, записывая всех подряд и тем самым здорово подкручивая счетчик.

Все, подсчитываем количество записей в хранилище - это и есть кол-во человек на сайте в данное время.

Честно говоря, получилось так, что ориентир все равно велся на MySQL, а не на файлы. В самом деле, наше ли это дело, сначала лезть в файл и удалять там что-то; потом опять лезть в него, чтобы записать; а потом только считывать. Куда проще сначала считать файл в массив, удалить из массива старые записи и добавить запись о юзере, если это требуется и уж потом записать массив обратно в файл. При выводе данных же руководствоваться кол-м значений в массиве.

Надеюсь, основную мысль вы все же уловили. Мы просто подсчитываем кол-во юзеров, со времени захода которых не прошло время, которое мы установили (Точность).

Однако, что есть для нашего скрипта пользователь? Отдельный IP-адрес. В этом-то и проявляется первая трабла. Ведь несколько человек могут ходить под одним прокси-сервером, например, а скрипт будет считать их за одного. Что же - ничего тут не поделаешь. Для нас куда проще считать отдельный IP-к отдельным пользователем, чем гонять куки (которые юзер, возможно, отключил) или сессии, грузя сервер. Посмотря правде в глаза, ведь и IP-адрес можно менять быстро (прервать -> позвонить для модемщиков :). Т.е. попросту накручивать счетчик (хотя кому это надо; если счетчик уников за весь день - тогда другое дело). Т.е., всегда возможны специфические ситуации, которые попросту не подстроятся под наши задумки. В данном случае, они не такие уж и страшные. Поэтому продолжим.

Итак, переходим наконец-то к практике. Повторюсь, для хранения информации будет юзаться база MySQL. Для всего этого дела мы создадим отдельную таблицу. Назовем её online.
В таблице создадим 2 поля:

  • ip - уникальное поле символьного типа VARCHAR с максимальным значением 20 cимволов (лично я не видел еще IP-адреса, размером больше 15 символов, но на всякий случай =). В нем хранятся, соответственно, IP'ы людей. Значение по умолчанию - 0.
  • unix - поле символьного типа VARCHAR с максимальным значением 60 символов. Поле, в котором будет храниться timestamp пользователя. Такое странное название выражено скорее моими личными пристрастиями, чем истинным его предназначением. Хотя скажу, что timestamp-формат принят в операционных системах UNIX, как стандарный. Можете поле назвать как угодно (только мой пример с этим именами полей). По дефолту пустое значение.

Замечу, что поле unix будет иметь тип VARCHAR, а не встроенный разработчиками MySQL тип TIMESTAMP. Это связано с тем, что этот тип слишком неудобен для хранения данных даты\времени в базе, как это может показаться на первый взгляд.

Далее привожу запрос, выполнив который, вы создадите соответствующую таблицу с нужными полями. Запрос можно выполнить функцией PHP mysql_query(), либо в какой-нибудь удобной уболочке для работы с MySQL. Например в PHPMyAdmin.


CREATE TABLE `online` (

`ip` varchar(20) NOT NULL default '0',

`unix` varchar(60) NOT NULL default '',

UNIQUE KEY `ip` (`ip`)

) TYPE=ISAM;

Выполнили? Молодцы. Напомню, что команды синтаксиса MySQL лучше всего привыкать писать в верхнем регистре и не для понта, как думают некоторые, а для повышении удобочитаемости кода и просто потому, что так принято.

После выполнения запроса, нам остается только написать код, который будет заниматься, собственно, подсчетом кол-а человек на линии. Этот код я запихнул в отдельную функцию, которая хранится у меня в файле, а сам файл инклюдится ( include(), require() ) на каждой странице моего сайта где-нибудь в самом начале. Я привожу вам пример функции точь-в-точь, какую я написал для своего сайта, разве только немного измененную в целях публичного использования. При наличии необходимых знаний, вы легко сможете отредактировать её под себя.


#------ Файл online.php


// подсчитывает пользователей On-Line, не засоряя при этом таблицу

function on_line() {

$host = "localhost"; // хост, где расположена база данных MySql

$db_name = ""; // имя базы данных;

$db_user = ""; // пользователь, которому разрешен доступ к базе

$db_password = ""; // пароль пользователя
$wine = 300; // точность он-лайн (секунды)

$table_online = "online"; // имя таблицы

global $REMOTE_ADDR; // доступ к переменной текущего IP'a

// соединяемся с сервером MySQL и выбираем нужную базу

mysql_connect($host,$db_user,$db_password) or die("Не удалось соединиться с сервером БД MySQL");

mysql_select_db($db_name) or die("Не удалось выбрать базу данных для работы");
// удаляем всех, кто уже пробыл $wine секунд

$sql_update = "DELETE FROM $table_online WHERE `unix`+$wine < ".time();

$result_update = mysql_query($sql_update);
// вставляем свою запись

$sql_insert = "INSERT INTO $table_online VALUES ('$REMOTE_ADDR','".time()."') ";

$result_insert = mysql_query($sql_insert);
// считаем уников он-лайн

$sql_sel = "SELECT count(ip) FROM $table_online";

$result_sel = mysql_query($sql_sel) or die(mysql_error());

$row_sel = mysql_fetch_row($result_sel); // строка результата

$online_people = $row_sel[0]; // кол-во On-Line пользователей
$rain = strlen($online_people) -1;
// форматирование вывода

if(($online_people[$rain]==2||$online_people[$rain]==3

||$online_people[$rain]==4)

&&(strlen($online_people)==1||(strlen($online_people)>1&&$online_people[$rain-1]!=1)))

$line = "человека"; else $line = "человек";

return "<font color=\"darkblue\">На сайте</font>

<font color=\"red\"><strong>".$online_people."</strong></font>

<font color=\"darkblue\">$line</font>";

mysql_close(); // закрываем соединение с БД

}

Вот такая вот функция. Где-нибудь в начале файла вам надо будет вставлять её как-нибудь по типу:

include 'online.php';

А в том месте, где нужно вывести кол-во пользователей, писать:

echo on_line();

Теперь разъясню немного код функции, так как в ней самой я все подробно откомментировал. Сначала идут переменные, нужные для удачного коннекта к базе, а также переменная $wine - наша точность. Также делается доступной из функции глобальная переменная $REMOTE_ADDR, которая возвращает IP-адрес клиентского компьютера. После происходит соединение с сервером MySQL. И уже после начинается самое интересное.

Первым запросом к базе ( запросы выполняются ф-й mysql_query() ) мы удаляем все записи, в которых timestamp + $wine меньше текущего timestamp. Т.е. мы удаляем из таблицы пользователей, которые пробыли $wine секунд на сайте.

Вторым запросом мы вставляем свою запись со своим IP'м и timestamp'м. Вы спросите, а где же проверка, что текущего IP'a нет в таблице? Оказывается и проверять ничего не нужно, т.к. поле ip унас уникальное, а это значит, что вставка записи в таблицу произойдет только, если IP'a текущего юзера нет в таблице online. Иначе же, произойдет ошибка. Т.к. мы не используем инструкции типа or die(), то волноваться нечего - пользователю никакие сообщения об error'х не полетят.

После всех манипуляций с таблицой, в ней остается истинное кол-во человек на сайте, с момента прихода которых не прошло $wine секунд. Нам остается лишь простым запросом подсчитать кол-во записей в таблице. Это и будет кол-во пользователей в Он-Лайне.

А вот потом идет, собственно, форматирование данных. На мой взгляд, я сделал его очень лаконичным и элегантным. Смотреть приятно, хотя с первого раза и не совсем понятно, как происходит процесс. Возможно, такое форматирование вам не понадобится. Вдруг вы захотите как-либо по-другому выводить информацию о кол-во юзверей. Тогда вам остается или убрать форматирование, или подредактировать его (в том числе и под свой дизайн). Так или иначе, переменная $online_people хранит кол-во пользователей и дальше вы вольны делать с ней все, что хотите. Можете просто возвратить её ( return $online_people; ) и сам формат данных осуществлять при непосредственном выводе, а не в теле функции, либо вообще, как я уже говорил, не осуществлять форматирования:

echo "On-Line: ".on_line()

Возможно, так будет даже красивее.

Важные замечания:

  • Переменная $wine на моем сайте равна 300 секундам, т.е. 5 минутам. Вы можете произвольно выставить её значение.
  • При коннекте и выборе базы данных мы используем конструкцию or die(), которая в случае неудачного действия завершает сценарий, но перед этим выводит в выходной поток (броузер) какую-либо строку. В нашем случае мы применяем ф-ю mysql_error(), которая возвращает в строковом виде ошибку, случившуюся во время манипуляции с базой\таблицой. Если вы не хотите завершать сценарий (в самом деле, зачем это надо: ведь из-за одной ошибки в ф-и сайт перестанет работать!), то просто не используйте эту конструкцию. Тем более что при какой-либо ошибке и наличии этой конструкции, пользователь, возможно (если ошибка при соединении с сервером), сможет узнать некоторые данные вашего сервера MySQL, а именно хост, логин пользователя и имя базы, что чревато взломом сайта (я пессимист по натуре - не верьте мне).
 
« Предыдущая статья   Следующая статья »