И сколько человек на сайте ?
Всем доброго времени суток!
Наверняка, гуляя по сети в поисках порн..., т.е. в поисках
какой-либо информации, вы натыкались на такую фишку, типа:
На сайте: 100 человек
Т.е., когда примерно в таком контексте выводится количество
человек, присутствующих в данное время на сайте. Когда я
впервые увидел такую фичу, мне она показалось интересной и
симпотной.
Недавно, по личной надобности, мне захотелось сделать такое
для своего сайта и я реализовал все это дело с использованием
PHP+MySQL.
Итак, в этой статье я хочу вам рассказать, как сделать
такую фичу для сайта. Это на самом деле проще жареной капусты
;=) и вскоре вы убедитесь в этом.
Все что нам нужно, это - хостинг с поддержкой PHP и MySQL и
пара минут времени. Может быть, некоторые возразят, зачем
здесь база данных, когда все можно реализовать на файлах.
Скажу вам , что MySQL в данном конкретном случае подходит как
нельзя лучше. С использованием файлов же, пришлось бы писать
гораздо больше кода и заниматься в большинстве своем рутиной,
которая нам ни к чему; в то время как с помощью базы данных
все делается парой-другой запросов...
Я надеюсь, что вы умеете хоть как-то обращаться с сервером
MySQL и знаете в целом, что такое базы данных и для чего они
служат. В противном случае, не могу ничем помочь, кроме как
посоветовать обратиться к друзьям, владеющим искусством
составлять SQL-запросы... Хотя, в принципе, вы можете просто
скопировать мой код и все. Однако, сама база данных все же
должна быть настроена...
Итак, постепенно переходим от теории к практической
эпостаси. В PHP, к сожалению (да и в других серверных языках
веб-программирования), отсутствует такая, на мой взгляд,
полезная технология, которая позволяла бы определять момент
времени, в который человек покинул сайт. Неважно, каким
способом, он это сделал: закрыл окно броузера или перешел по
другой ссылке. Раз PHP пасует, сами сделаем кое-какую подобную
технологию; естественно, о точности и отсутствии погрешностей
здесь не говорю... Однако, все так делают и мы так сделаем.
Далее опишу, как мы будем, собственно, определять кол-во
юзеров на линии теоретически (не касаясь MySql и PHP
конкретно). Если вы уловите мысль, то тотчас же реализуете эту
возможность на любом языке веб-программирования и любым
доступным для вас методом (файлы, к примеру)...
Для начала, нам нужно установить переменную
Точность - время, в течении которого
посетитель будет считаться на линии, т.е. бродящем по сайту.
Значит, при заходе на страницу, мы должны определить
сперва-наперво IP-адрес зашедшего и его
timestamp. Никакой экзотики,
TimeStamp - это представление времени,
которое равняется "кол-ву секунд, прошедших с полуночи 1
января 1970 года по Гринвичу до настоящего момента". Это
весьма универсальное представление времени и, в частности,
именно с этим форматом работает большинство PHP-х ф-й для
работы с "датой-временем". Весьма удобная метка, поверьте мне
на слово. Т.е., чем больше число TimeStamp,
чем дольше "мы живем" и чем больше "сейчас времени", извиняюсь
за сумбурность. После, мы открываем какое-либо хранилище
(файлы, базы данных, сессионный массив и т.п.) и удаляем из
него все записи (каждая запись - информация об одном зашедшем
на страничку пользователе), в которых TimeStamp +
Точность меньше текущего TimeStamp'а, или где
IP-адрес совпадает с текущим Ip'м. Т.е., уничтожаем старые
записи. Далее записываем данные о зашедшем пользователе
(оставляем запись): IP и timestamp. Все, подсчитываем
количество записей - это и есть кол-во человек на сайте в
данное время.
Честно говоря, получилось так, что ориентир все равно велся
на MySQL, а не на файлы. В самом деле, наше ли это дело,
сначала лезть в файл и удалять там-то, потом опять лезть в
него, чтобы записать, а потом только считывать. Куда проще
сначала считать файл в массив, удалить из массива старые
записи и добавить запись о юзере, если это требуется и уж
потом записать массив обратно в файл. При выводе данных же
руководствоваться кол-м значений в массиве.
Надеюсь, основную мысль вы все же уловили. Мы просто
подсчитываем кол-во юзверей, со времени захода которых не
прошло время, которое мы установили (Точность).
Итак, переходим наконец-то к практике. Повторюсь, для
хранения информации будет юзаться база MySQL. Для всего этого
дела мы создадим отдельную таблицу. Назовем её
online. В таблице создадим 3 поля:
id - ключевое
авто_инкрементирующееся поле типа INT с максимальным
размеров в 10 символов. Нужно для более оптимизированной
работы с таблицой, хотя его можно и опустить. При каждом
заходе человека на сайт, поле будет увеличивать свое
значение на 1.
- 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` ( `id` int(10) NOT NULL
auto_increment, `ip` varchar(20) NOT NULL default
'0', `unix` varchar(60) NOT NULL default '', KEY `id`
(`id`) )
Выполнили? Молодцы. Напомню, что команды синтаксиса MySQL
лучше всего привыкать писать в верхнем регистре и не для
понта, как думают некоторые, а для повышении удобочитаемости
кода и просто потому, что так принято.
После выполнения запроса, нам остается только написать код,
который будет заниматься, собственно, подсчетом кол-а человек
на линии. Этот код я запихнул в отдельную функцию, которая
хранится у меня в файле, а сам файл инклюдится ( include(),
require() ) на каждой странице моего сайта где-нибудь в самом
начале. Я привожу вам пример функции точь-в-точь, какую я
написал для своего сайта, разве только немного измененную в
целях публичного использования. При наличии необходимых
знаний, вы легко сможете отредактировать её под себя.
#------ Файл online.php
/* ф-я подсчитывает
пользователей на линии; возвращает кол-во пользователей в
отформатированном виде, т.е. для вывода результата нужно лишь
прописать в нужном месте типа: echo on_line(); */ function
on_line() { $host = "localhost"; // хост, где расположена
база данных MySql $db_name = ""; // имя базы данных; как
правило совпадает с именем юзера (переменная ниже), хотя я
категорически против одинаковых имен, ориентируясь на
защиту... $db_user = ""; // пользователь, которому разрешен
доступ к базе $db_password = ""; // пароль
пользователя $wine = 300; // точность он-лайн (секунды);
время, в течении которого пользователя, зашедшего на
страничку, мы считаем находящимся на сайте $table_online =
"online"; // имя таблицы
// делаем доступной глобальную
переменную ИП-адреса global $REMOTE_ADDR;
//
соединяемся с сервером MySQL и выбираем нужную
базу mysql_connect($host,$db_user,$db_password) or
die(mysql_error()); mysql_select_db($db_name) or
die(mysql_error());
// удаляем всех, кто уже пробыл
$wine секунд или у кого ИП текущий $sql_update = "DELETE
FROM $table_online WHERE `unix`+$wine < ".time()." OR `ip`
= '$REMOTE_ADDR'"; $result_update =
mysql_query($sql_update) or die(mysql_error());
//
вставляем свою запись $sql_insert = "INSERT INTO
$table_online VALUES
('','$REMOTE_ADDR','".time()."')"; $result_insert =
mysql_query($sql_insert) or die(mysql_error());
//
считаем уников он-лайн $sql_sel = "SELECT `id` FROM
$table_online"; $result_sel = mysql_query($sql_sel) or
die(mysql_error());
$online_people =
mysql_num_rows($result_sel); // кол-во On-Line пользователей
$online_people = (string) $online_people; // приводим к
строковому типу (так надо.. см. дальше)
$rain =
strlen($online_people) - 1; // номер последнего символа в
числе on-line юзеров
// форматирование вывода (я все
сделал за вас
=) if($online_people[$rain]==2||$online_people[$rain]==3 ||$online_people[$rain]==4 ||(strlen($online_people)!=1&&$online_people[strlen($online_people)-2]!=1)) $line
= "человека"; else $line = "человек"; // $line - переменная,
определяющая формат вывода
// возвращем
результат return "На сайте
<strong>".$online_people."</strong>$line"; }
Вот такая вот функция. Где-нибудь в начале файла вам надо
будет вставлять её как-нибудь по типу:
include 'online.php';
А в том месте, где нужно вывести кол-во пользователей,
писать:
echo on_line();
Теперь разъясню немного код функции, так как в ней самой я
все подробно откомментировал. Сначала идут переменные, нужные
для удачного коннекта к базе, а также переменная
$wine - наша точность. Также делается
доступной из функции глобальная переменная
$REMOTE_ADDR, которая возвращает IP-адрес
клиентского компьютера. После происходит соединение с сервером
MySQL. И уже после начинается самое интересное.
Первым запросом к базе ( запросы выполняются ф-й
mysql_query() ) мы удаляем все записи, в
которых timestamp + $wine меньше текущего
timestamp или в которых ИП-адрес совпадает с нашим. Т.е. мы
удаляем из таблицы либо старых пользователей, либо самих себя,
чтобы не повторяться.
Вторым запросом мы вставляем свою запись со своим IP'м и
timestamp'м. Обратите внимание ,что значение первого поля мы
оставляем пустым, так как оно инкрементируется от вставки к
вставке и само собой заполнится (увеличенным на 1 предыдущим
значением).
После всех манипуляций с таблицой, в ней остается
действительно истинное кол-во человек на сайте, с момента
прихода которых не прошло $wine секунд. Нам остается лишь
простым запросом выбрать все записи и подсчитать их кол-во.
Это и будет кол-во пользователей в Он-Лайне. Обратите
внимание, что мы с вами, как люди умные, не выбираем сразу все
поля из всех записей (зачем нам лишние данные, если нужно
только подсчитать количество записей), а выбираем только поле
id. Это тоже прием для оптимизации запросов,
хотя многие о нем забывают или не знают.
А вот потом идет, собственно, форматирование данных. На мой
взгляд, я сделал его очень лаконичным и элегантным. Смотреть
приятно, хотя с первого раза и не совсем понятно, как
происходит процесс. Возможно, такое форматирование вам не
понадобится. Вдруг вы захотите как-либо по-другому выводить
информацию о кол-во юзверей. Тогда вам остается или убрать
форматирование, или подредактировать его (в том числе и под
свой дизайн). Так или иначе, переменная
$online_people хранит кол-во пользователей и
дальше вы вольны делать с ней все, что хотите. Можете просто
возвратить её ( return $online_people; ) и сам
формат данных осуществлять при непосредственном выводе, а не в
теле функции, либо вообще, как я уже говорил, не осуществлять
форматирования:
echo "On-Line: ".on_line()
Возможно, так будет даже красивее.
Важные замечания:
- Переменная $wine на моем сайте равна
300 секундам, т.е. 5 минутам. Вы можете произвольно
выставить её значение.
- При коннекте к базе и выполнении запросов мы используем
конструкцию or die(), которая в случае
неудачного действия завершает сценарий, но перед этим
выводит в выходной поток (броузер) какую-либо строку. В
нашем случае мы применяем ф-ю
mysql_error(), которая возвращает в
строковом виде ошибку, случившуюся во время манипуляции с
базой\таблицой. Если вы не хотите завершать сценарий (в
самом деле, зачем это надо: ведь из-за одной ошибки в ф-и
сайт перестанет работать!), то просто не используйте эту
конструкцию. Тем более что при какой-либо ошибке и наличии
этой конструкции, пользователь, возможно (если ошибка при
соединении с сервером), сможет узнать некоторые данные
вашего сервера MySQL, а именно хост, логин пользователя и
имя базы, что чревато взломом сайта (я пессимист по натуре -
не верьте мне).
- Переменную $online_people мы приводим к
строковому типу, так при формате информации (проверке, что
выводить: "человек" или "человека") мы "крутим строкой"! Как
мы крутим - думаю, разберетесь сами, после некоторого
брожжения мозгов :-). Возможно, можно было сделать все
элегантнее и написать меньше кода - не знаю... Если вы так
считаете, то пишите на е-майл с кодом,
который, на ваш взгляд, лучше моего... или оставляйте
комментарии к этой статье. Я их просматриваю иногда
(периодически раз в полгода ...=)
- Ф-я time() занимается тем, что
возвращает время в секундах, прошедшее с полуночи 1 января
1970 года по Гринвичу до настоящего момента. Но мы то знаем,
что по научному это называется TimeStamp...
$-)
- Форматирование я разделил символами перехода строки,
т.к. строка проверок (где много знаков || =) очень длинная,
а это приводит к растяжению статьи в ширину, в результате
чего становится очень неудобно производить чтении статьи,
т.к. глаза бегают туда-сюда-обратно (я не о том, что вы
подумали). Вообщем вы меня поняли.
- Код рабочий - у меня такой же =) Но: несколько
дополнений были сделаны только при написании статьи, в
частности:
- Добавлены переменные для коннекта к базе и коннект
происходит внутри функции. Естественно, у меня на сайте он
происходит задолго до этого и ф-я, используя открытое
соединение с MySQL-демоном, выполняет запросы.
- Форматирование я разделил символом перевода строки
(причину см. выше), так что, если сценарий не заработает и
выдаст тупую ошибку, типа parse error in
..., то преобразуйте строку проверок в единое
целое (чтобы на одной строчке все было). Но, я думаю, вы
меня поняли.
- Ошибки маловероятны, но возможны, так как я правил
комменты и т.п. при написании статьи, вдруг какой-нибудь
символ точки с запятой забыл. Исправляйте все сами 5=).
Из добавлений, пожалуй, все. Да и статье приходит Зе Енд.
Рад, что вы дочитали пособие до этого места, а еще большее
эстетического наслаждение мне принисет тот факт, что статья
показалось вам занимательной и оставила хорошие впечатления и
знания в баш... голове.
Автор: Makswell
Источник: www.progers.ru
|