Упрощенный способ расчета посетителя, или Как найти флудера?

Упрощенный способ расчета посетителя, или Как найти флудера?

Итак, сегодня мы будем заниматься статистикой посещаемости нашего сайта. Первое, что нам необходимо определить — что нужно знать администратору сайта для корректировки его контента, времени обновления и др.

Конечно, пока сайт не раскручен, можно просто названия компьютеров и время посещения их пользователями нашего сайта записывать в простой текстовый файл. Однако это хорошо, когда посещений не больше нескольких сотен. А когда их число переваливает за тысячу, анализировать такой файл не просто трудно, а очень трудно. Хотя на первых порах многие так и делают, после чего приходится этот файл переводить в более читаемый вид, что, надо сказать, весьма неудобно. Можно затем написать пару-другую скриптов для анализа этого файла. Однако это все будет работать страшно медленно, и намучаетесь вы со скриптами — просто в сказке не рассказать. Но зачем изобретать велосипед и придумывать разные там поисковики по своим логам? Все уже придумано до нас — остается только это под себя сконфигурировать. Итак, решено: используем в своем супермегасчетчике СУБД MySQL. Как правило, чаще всего о своих посетителях необходимо знать следующее: время, дату посещения, IP-адрес, имя компьютера. Также необходимо, чтобы счетчик не менял своего значения, когда на сайт заходит его администратор и при обновлении странички (иначе будет очень много ложных посещений). Связка PHP+MySQL поможет нам решить поставленные задачи.

Очевидно, что, если использовать одну таблицу, в ней будет очень много полей, и делать запросы будет неудобно (конечно, можно все запросы раз и навсегда зашить в веб-интерфейс, а не делать время от времени запросы вручную, но на стадии отладки и в процессе развития проекта вашего сайта могут возникнуть разные ситуации). Первая таблица будет служить нам собственно хранилищем информации о посетителях, вторая будет служебной, т.е. в ней будут храниться данные, необходимые для корректной работы счетчика: минута последнего посещения, его IP и др. Но начнем с начала. В данной статье я использовал консольные программы для работы с СУБД MySQL 3.23.38, которые присутствуют в дистрибутиве. С помощью этих программ можно подключаться и к удаленной СУБД, прописав соответствующие ключи при их загрузке. Создаем базу данных mysqladmin -h hostname -u username -p create shetchik. При наличии ключа -p система спросит у вас пароль на подключение. Как вы, наверное, уже поняли, вместо hostname и username следует подставить соответствующие свои значения. Shetchik — имя нашей с вами базы данных счетчика. Если база данных находится на локальном компьютере, то -h hostname можно опустить. Если вы используете свежеустановленную MySQL на своем компьютере, то никаких ключей писать не нужно, просто необходимо дать команду mysqladmin creante databasename. Итак, мы создали базу данных. Теперь необходимо создать таблицы в этой базе. Для этого пишем в консоли:

mysql -h hostname -u username -p
mysql> use shetchik;
create table last_use (ip char(16),min int(2),nom int(9),ipa char(16),mainhost char(10));
create table hosts (ID int (9),ip char(16),hostname char (10),year int(4),month int(2), day int(2),day_week char(10), hour int(2),minit int(2),second int(2));

(Естественно, перед всеми этими командами необходимо сначала сменить текущий каталог со стандартного (в WinXP C:\Documents and Settings\ username, например) на каталог, в котором расположены программы mysqladmin.exe и mysql.exe соответственно. Это можно сделать, дав команду cd "c:\Program Files\mysql\bin", например, где путь необходимо заменить на свой). Этим мы создаем две таблицы, как было уже оговорено выше: одна для хранения данных, вторая — служебная. Начнем с последней. В ней пять колонок. Первая колонка типа char будет хранить у нас IP-адрес последнего посетителя, вторая — min типа int — минуту последнего посещения. Колонка ipa необходима для хранения IP-адреса администратора сайта (полезна на случай статического IP-адреса), и, наконец, последняя колонка будет содержать в себе имя компьютера администратора. Для чего все это необходимо? Для того, чтобы не вводить в заблуждение ни себя, ни других высокими показателями посещаемости, если вы часто любите любоваться своим детищем в онлайне:-). Приступим к описанию второй, и главной, таблицы. Я ее сделал с несколько избыточным количеством полей. Возможно, она покажется слишком большой, но ведь никто не запрещает изменить данную команду:-)? Итак, по порядку. ID — порядковый номер посетителя (при желании можно сделать эту колонку с инкрементированием). Ip — IP-адрес посетителя, hostname — название компьютера посетителя, year — год посещения вашего сайта (если он столько проживет:-)), month — месяц, когда была произведена загрузка, day — номер дня, day_week — текстовое название дня недели, hour — час, minit — минута, second — секунда. Итак, база данных создана, теперь необходимо придать начальные значения первой таблице (это необходимо для того, чтобы наш будущий скрипт работал корректно). Для этого нам нужно всего лишь дать команду mysql> insert into last_use (ipa,mainhost,min,nom) values ('IP_adress','host','0','0');. Здесь IP_address и host — IP-адрес и имя компьютера администратора сайта (с которого производится администрирование портала:-). Этой командой мы задаем начальные значения поля первой таблицы. Теперь приступаем собственно к написанию скрипта. Использовать мы будем PHP как один из самых простых скриптовых языков. Мы напишем PHP-файл, который вы после можете встроить в свою заглавную страницу, причем, когда она будет открываться, этот скрип будет выполняться — но это уже ваши проблемы:-), как вы будете его конкретно использовать. Итак, для начала подконнектимся к нашей базе данных:

<?php
mysql_connect("hostname", "username","password");
mysql_select_db("shetchik");
где, как вы, наверное, уже поняли, hostname, username, password необходимо заменить на свои. Далее:
$result = mysql_query("SE-LECT ip,ipa,min,nom,mainhost from last_use");
$row = mysql_fetch_array ($result);
Этими строками мы запрашиваем из нашей базы данных (а конкретней, из служебной таблицы) те данные, которые необходимо будет потом внести в обе наши таблицы.
$w=mysql_error();
echo $w;

А вот эти строчки необходимы для того, чтобы получить текст ошибки, которая, не дай Бог:-), произойдет при запросе к СУБД. Далее получаем информацию от всеми нами любимого web-сервера:
$ip=$row["ip"];
$ipa=$row["ipa"];
$min=$row["min"];
$mainhost=$row["mainhost"];
$ID=$row["nom"];

Несколько поясню, что значит сей код. Дело в том, что функция mysql_query() делает запрос, который придается ей в качестве параметра. Выходные данные этой функции нельзя прямо использовать, т.к. она возвращает т.н. идентификатор запроса. Для того, чтобы использовать полученные данные, их необходимо поместить в массив, для чего, собственно, и служит функция mysql_ fetch_array(). После чего можно присваивать переменным значения элементов массива, возвращаемого этой функцией. Что мы, собственно, и делаем. Теперь получаем значения, не содержащиеся в БД, а именно дату, время и др.:
$ip_now = getenv ("REMOTE_ ADDR");
$hostname= gethostbyaddr($ip);
$year=(date("Y"));
$month=(date("m"));
$day=(date("d"));
$day_week=(date("D"));
$hour=(date("H"));
$minit=(date ("i"));
$second=(date("s"));

Итак, первая функция получает IP-адрес компьютера, который загрузил вашу страничку. Следующая функция получает имя компьютера, имеющего этот IP-адрес. Далее следует несколько вызовов функции date() с различными параметрами. Эта функция "возвращает строку, отформатированную согласно данной строке и используя данную временную метку или текущее локальное время, если не задана временная метка". По-русски это означает, что данная функция может возвращать дату-время в том формате, в котором мы ее "попросим". Год мы получаем в виде числа (2003, например), месяц — также в виде числа, day — как число месяца, day_week — название дня недели (вернее, первые три буквы английского названия), hour — час в 24-часовом формате, minit, second — также числа. Все это присваивается соответствующим переменным для того, чтобы затем можно было занести в таблицу. Но предварительно необходимо сделать вот что. Необходимо произвести проверку на совпадение IP-адреса, имени хоста и минуты последнего подключения. Зачем это нужно? Представьте себе такую ситуацию. Заходит к вам на сайт человек с IP_1. И начинает "нервно" жать в своем браузере кнопочку "обновить". Если не проверять время последнего захода человека с этим IP_1, счетчик будет прибавлять при каждом обновлении нового "посетителя". Чтобы этого не происходило, мы и проверяем, не было ли прошлое подключение этого человека менее минуты назад. Теперь представьте себе, что минуты с последней загрузки сайта не прошло, а к вам на сервер заходит другой человек, но уже с IP_2. Чтобы учесть это посещение, и необходимо получить его IP_2 и сравнить с IP предыдущего посетителя. В этом же сравнении мы отсекаем срабатывания счетчика при подключении к серверу "администраторского" компьютера. Таким образом мы учитываем все "полезные" посещения и отсекаем все "вредные". А конкретно скрипт выглядит так:
if((($ip_now<> $ipa) && ($min <> $minit)) || ($ip<> $ip_now))
{
$ID=$ID+1;
mysql_query("INSERT INTO hosts (ID,ip,hostname,year, month,day,day_week,hour,minit,second) values ('$ID','$ip_now', '$hostname','$year','$month','$day','$day_week','$hour','$minit','$second')");
mysql_query("UPDATE last_use SET ip='$ip_now',min='$minit', nom='$ID'");
$w=mysql_error();
echo $w;
};
echo $ID;
?>

Инкрементирование $ID (собственно, это и есть показатель посещаемости наш искомый) происходит только при выполнении вышеперечисленных условий. Далее следует уже известная вам функция запроса к серверу СУБД с подстановкой соответствующих переменных mysql_query(). Второй вызов этой функции обновляет значения в нашей служебной таблице last_use. Этим достигается актуальность хранимой в ней информации. Теперь нам остается только вывести в соответствующем месте странички число посетителей. Можно это сделать не только через простую функцию echo, а несколько "красивее". Правда, нам придется несколько доработать наш скрипт. Мы будем выводить количество посетителей при помощи картинок цифр. Для этого заведем файл, в который будем дополнительно записывать количество посетителей. А затем считывать по одной цифре и подставлять в нашу генерируемую страничку вместо символов картинки. Естественно, нам понадобится десять картинок цифр с соответствующими названиями (0, 1, 2… 9) и одинаковым расширением. Итак, наш дополнительный скрипт допишем в конец уже созданного:
$fp = fopen("nom.txt" ","w+");
fwrite ($fp, $ID);
fclose($fp);

Открываем файл и после его очистки (флаг w+ в функции) записываем в него значение нашего счетчика. Таким образом в этом файле будет храниться текущее значение счетчика. Конечно, можно кусок данного скрипта поместить в фигурные скобки выражения if(), для того чтобы лишний раз файл не переписывался при ложном посещении, тем самым экономя ресурсы, но это делать необязательно — должно и так все работать:-). Далее нам уже необходимо открыть этот же файл на чтение и, считывая по символу, заменить их в конечном (сгенерированном) документе на картинки, что мы далее и делаем. Каждый раз мы в while() проверяем подход к концу файла. После этого fgets() считывает символ, после чего он заменяется на картинку с именем, совпадающим с цифрой, считанной из файла. Картинки взяты с расширением *.bmp, которое, естественно, может быть изменено. А сами картинки находятся в директории /num, которая, в свою очередь, находится в одной директории со скриптом счетчика:
$fp = fopen ("nom.txt", "r");
while (!feof ($fp))
{
$nn = fgets($num, 2);
$c="num/$nn.bmp";
echo "<img border=0 src=$c border=0> ";
};
fclose ($fp); ?>

Ну, а теперь самое вкусное. А именно подведение итогов:-). Всегда, знаете ли, приятно посмотреть, как меняется посещаемость сайта в течение месяца. Кстати, описанный ниже скрипт по обрисовке графика посещаемости за месяц может быть легко переделан в скрипт по анализу посещаемости за неделю, час:-). Как это сделать конкретно, я покажу ниже. Что мы имеем? Мы имеем базу данных посетителей, созданную за несколько месяцев "упорного труда" вышеописанного счетчика. И нам хотелось бы получить наглядное представление загрузки нашего "портала":-) за месяц. Итак, создаем форму с выбором месяца, за который нам хотелось бы получить статистику:
<html>
<head>
<title> analiz </title>
</head>
<form name="form1" method= "post" action="analiz.php?ok=1">
<select name="month">
<option value="1"> Январь </option>
<option value="2"> Февраль</option>
.....
<option value="12"> Декабрь</option>
</select>
<input type="submit" name= "Submit" value="Просмотреть">
</form>

Теперь ко всему этому "счастью" необходимо добавить скрипт, который анализировал бы загрузку (трафик). Конечно, предлагаемый скрипт не "сверкает" красотой, но для начала пойдет — ежели захотите доработать, вам никто этого не запрещает. Я надеюсь, пояснять HTML-теги нет необходимости.
<?php
error_reporting(0);
if($ok==1)
{

Первая функция необходима нам для того, чтобы интерпретатор языка PHP не ругался, мол, "переменные неопределенны и т.д." Дело в том, что, как вы, наверное, уже заметили, обработку формы производит этот же файл. Чтобы скрипт "знал", что это уже 2-я загрузка скрипта, и используется конструкция action="analiz.php?ok=1". При помощи нее мы придаем в скрипт дополнительно еще одну переменную ($ok=1). А IF() необходим для того, чтобы сценарий выполнился ТОЛЬКО при вторичной загрузке странички. Теперь приступаем собственно к обработке данных. Коннектимся к СУБД MySQL и распечатываем возможные ошибки:

mysql_connect("hostname", "username","password");
mysql_select_db("shetchik");
$w=mysql_error();
echo $w;
Сейчас необходимо получить максимальное значение количеств посещений за день. Для этого нам нужен следующий код:
$key=0;
for($i=1;$i<=31;$i++)
{$res = mysql_query("SELECT day from hosts where day='$i' and month='$month'");
$kol=mysql_num_rows($res);
if ($key<$kol)
$key=$kol;
};

В цикле мы последовательно опрашиваем базу данных на записи, в которых значения полей day и month равны соответствующим интересующим нас значениям. Для простоты будем считать, что во всех месяцах по 31 дню. (Для особо дотошных можно добавить дополнительное условие, тогда все будет корректно выглядеть — для данного блока кода примерно так: for($i=1;$i<=$KOL_ DNEY;$i++). $KOL_DNEY можно будет получать из формы — правда, тогда придется соответственно изменить и остальные части скрипта. Но я думаю, что это не составит труда сделать без моей помощи). Сразу после запроса идет вызов функции mysql_num_rows(), которая возвращает количество строчек в ответе на запрос. Таким образом, мы далее получаем максимальное количество посещений в день за целый месяц. (Если такого дня 31 в феврале точно нет, количество посещений за этот день будет, соответственно, нулевым и никак не повлияет на общую картину.) Идем дальше:
$mas=bcdiv("10",$key,"2");
echo "<table border=1 cellspacing=0> ";

Итак, как же мы будем отображать статистику? Сделаем это следующим образом. Нарисуем таблицу 31*10 и пропорционально загруженности этого дня в месяце будем закрашивать ячейки в таблице. Для этого нам нужно знать коэффициент пропорциональности количества закрашенных ячеек относительно посещаемости. А это и есть $mas, который мы и находим, после чего рисуем заголовок этой самой таблицы.
Запускаем цикл прорисовки таблицы. В этом цикле MySQL опять получает запросы, как и в предыдущем куске кода. Затем вновь подсчитывается количество посещений за день, и это количество умножается на коэффициент $mas, что в результате дает количество ячеек, которое необходимо закрасить.

for($i=0;$i<=31;$i++)
{
$res = mysql_query("SELECT day from hosts where day='$i' and month='$month' ");
$kol=mysql_num_rows($res);
$n=bcmul($mas,$kol,"1");
if($n==0)
$n="0.1";/* Две последние строки необходимы для корректной прорисовки таблицы в случае нулевого количества посетителей в данный день */
Теперь нам остается только нарисовать нашу таблицу:
echo "<tr> ";
if($i==0)
{
echo "<td> День\Загрузка</td> ";
}
else echo "<td> $i</td> ";// Выводим номера дней месяца
for($j=1;$j<$n;$j++)
{
echo "<td bgcolor=#FF0000> _ </td> ";//Выводим закрашенные ячейки (красным)
};
for($g=1;$g<9-$n;$g++)
echo "<td> _</td> ";/* Выводим незакрашенные ячейки таблицы. Разделитель "_" можно заменить на любой символ, в том числе и непечатный */
echo "</tr> ";
};
};
?>

Таким образом, на выходе скрипта мы получаем таблицу, с левой стороны которой идут номера дней месяца, а с правой — что-то типа диаграммы. Теперь о том, каким образом можно переделать данный "анализатор" на анализ посещений, допустим, за день. Для этого просто необходимо переделать запрос для MySQL-сервера следующим образом: mysql_query("SELECT hour from hosts where hour='$i' and day='$day'"); и второй запрос: mysql_query("SELECT hour from hosts where hour='$i' day='$day' ");. Также необходимо число 31 в циклах заменить на 24 (я думаю, понятно, почему:-) — в сутках ведь не 31 день). Как изменить масштаб "диаграммы"? Да очень просто. При делении ($mas=bcdiv ("10",$key,"2");) число 10 замените на нужное вам, соответственно заменив 9 в выражении for($g=1;$g<9-$n;$g++). Согласен, алгоритм работы вышеизложенного скрипта далек от идеального, но, как показал практический опыт его применения, он довольно-таки удобен в использовании (конечно, с добавлением идентификатора пользователя и как часть администраторского интерфейса). А описанная выше база данных, которая заполняется этим счетчиком, содержит избыток информации, которой будет вполне достаточно для написания сколь угодно сложной системы анализа посещаемости. Собственно, показанный здесь скрипт по анализу посещаемости — всего лишь пример, который очень прост в использовании и настройке.

Спичеков Александр aka MentALZavR, Zavr6@mail.ru


Компьютерная газета. Статья была опубликована в номере 46 за 2003 год в рубрике интернет :: вебмастеру

©1997-2024 Компьютерная газета