oldi

<% ASP на блюдечке %>. Часть 19

Система сбора и обработки статистики по посещаемости Web-сайта своими руками — 2

Рубен Садоян  (rouben@iname.com)

Введение

Популярность – что это?

Какие методы увеличения популярности существуют?

Внесем ясность

Организация работ

Создание и подготовка базы данных

Интеграция системы в уже готовый сайт

Когда же фиксировать посещения?

Что такое Global.asa

Регистрация посещений – файл global.asa

Сервисные функции системы – файл Utils.asp

Главная страница системы – файл Index.asp

Основное меню системы – файл StatMain.asp

Статистика уникальных посещений (хостов) – файл Hosts.asp

Симпатичный календарь – файл Calendar.asp

Статистика всех посещений (хитов) – файл Hits.asp

Графическое представление статистики (хитов) по датам – файл HitsGraph.asp

Заключение

Введение

Как мы уже не раз отмечали в предыдущих статьях серии <% ASP на блюдечке %>, популярность того или иного Интернет-ресурса Всемирной паутины обусловливается множеством самых разнообразных факторов. В предыдущей статье настоящей серии мы рассмотрели процесс создания системы сбора и обработки статистики посещений гипотетического сервера. Однако, как мы говорили, эта система может быть существенным образом доработана и оснащена целым рядом дополнительных функциональных возможностей. Это мы и собираемся предпринять в настоящей статье.

Итак, теперь нам надлежит заняться усовершенствованием системы, а именно разработкой системы фильтров хитов и хостов по датам, декодирования предыдущей страницы (страницы-referrer’a, с которой пользователь обратился к данному ресурсу). Однако прежде всего освежим в памяти разработанную нами систему и дадим определения некоторых понятий.

В начало В начало

Популярность – что это?

Обобщая, можно сказать, что популярность – это прежде всего большое количество посещений сайта. Но здесь сразу же возникает множество разнообразных вопросов: что считать посещением? откуда «пришел» пользователь? какие из страниц его больше всего заинтересовали? или как часто он заглядывал на тот или иной сайт? какова среднесуточная нагрузка на сервер? какое время суток можно считать пиковым с точки зрения посещаемости?

Согласитесь, что ответы на эти и многие другие вопросы позволят настроить Web-мастерам тот или иной ресурс Всемирной сети  на конкретную аудиторию пользователей более целевым образом и тем самым добиться увеличения количества посетителей, а следовательно, и популярности.

Решению этой проблемы (усовершенствованию системы учета и анализа посещений) и посвящена настоящая статья.

В начало В начало

Какие методы увеличения популярности существуют?

Систематический анализ статистики посещений сайта — инструмент, позволяющий грамотно и своевременно среагировать на изменения  посещаемости в ту или иную сторону. Под реакцией прежде всего следует понимать:

  1. Обновление материалов сайта. Лучше не пользоваться стандартными фразами. Имеют значение оригинальность новостей и философствование в меру способностей. Новости или хотя бы их анонсы желательно вынести на основную страницу. Для оригинальности можно писать не только дату обновления, но и время с точностью до минуты.
  2. Обмен баннерами с сайтами такой же популярности (не ниже) с помещением на главные страницы на специальном и видном месте.
  3. Сотрудничество с популярными сайтами. Например, можно договориться на размещение на главных страницах рекламных баннеров сроком до 1 месяца — больше не имеет смысла. Прошел месяц — ищите другой сайт-партнер. Таким образом вы будете привлекать постоянных посетителей сайта-партнера, которые, возможно, станут и вашими постоянными посетителями.  
  4. Баннерную рекламу. Эффективно, если ваш баннер имеет CTR (коэффициент полезного действия) свыше 4%. Баннер меняйте с периодичностью 1-2 месяца.  
  5. Устраивайте на сайте интересные викторины. Желательно с призами.
  6. Настройте вашу почтовую программу, чтобы в конце письма приписывался адрес вашего сайта с кратким описанием. Эффективно в том случае, если вы часто посылаете письма большому количеству людей.
  7. Производите регулярную кампанию по почтовой рассылке информации о сайте большому количеству потенциально заинтересованных клиентов по электронной почте с помощью специальных программ (Bulk Mailing).
  8. Неназойливая и интригующая реклама, например, с периодичностью раз в неделю, на нескольких популярных форумах и/или чатах тоже сыграет вам на руку. Однако если посетители форума или чата отзываются на рекламу негативно, лучше прекратить, иначе приобретете дурную репутацию.
  9. Индексация сайте в разнообразных поисковых машинах как в зоне .ru (Rambler, Yandex, Aport…), так и в зоне .com (AltaVista, Yahoo, HotBot, Lycos…) для успешного нахождения вашего сайта этими поисковыми машинами.

Этот список можно продолжать, однако мы перечислили основные методы улучшения посещаемости.

В начало В начало

Внесем ясность

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

Посещение — однократное пребывание пользователя на том или ином ресурсе. Причем это может быть как один и тот же пользователь, так и несколько разных. Другими словами, посещение иногда называют «хитом» (от английского hit).

Уникальное посещение — однократное пребывание данного пользователя на том или ином ресурсе. Причем речь идет о посещении ресурса именно данным пользователем. Компьютеры разных пользователей отличаются друг от друга IP-адресами. Именно это обстоятельство и используется при вычислении уникальных посещений, или так называемых хостов (от английского host).

Клиент — под клиентом здесь подразумевается тип, версия браузера и операционная система, с помощью которого и под управлением которой было осуществлено посещение или уникальное посещение ресурса.

Реферер (referer) — адрес Всемирной сети, где пользователь «находился» непосредственно до осуществления посещения или уникального посещения данного ресурса. Это, как правило, поисковые машины. Таким образом, можно определять эффективность той или иной поисковой машины или ссылки во Всемирной сети применительно именно к данному сайту.

Страна принадлежности хоста — страна, в доменной зоне которой находится тот или иной пользователь (вычисляется из IP-адреса путем декодирования его в доменное имя).

В начало В начало

Организация работ

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

Во-первых, нам необходимо регистрировать (записывать в базу данных) все уникальные посещения (хосты) нашего сайта с учетом IP-адресов и «Клиентов».

Во-вторых, то же самое нам придется проделывать и с обычными посещениями (хитами), причем делать это подневно, фиксируя при этом количество посещений за каждый день. Это позволит нам в дальнейшем перейти и к большим единицам измерения времени, как то: недели, месяцы, годы. Хотя в общем случае, когда в этом есть необходимость, можно регистрировать хиты и ежечасно. Но это может иметь смысл исключительно  в применении к сайтам с очень большим количеством хитов.

В-третьих, необходимо разработать подсистему контроля за доступом статистической информации — во избежание несанкционированного доступа к ней.

Далее требуется разработать дружественный интерфейс, позволяющий пользователям просматривать желаемую статистику в удобной и читабельной форме (этот пункт имеет массу вариантов развития — вплоть до генерации отчетов в формате MS Excel).

В начало В начало

Создание и подготовка базы данных

Для организации хранения данных о посещениях нам понадобятся две таблицы. В первой мы будем хранить хиты наших пользователей, а во второй — хосты.

Таблица хитов будет хранить количество хитов по дням следующим образом: .

Таблица хостов будет хранить количество хостов по датам посещения и с учетом IP-адреса, Referer’а и Клиента следующим образом: .

Для организации удобного встраивания системы в уже существующие сайты рекомендуется спланировать еще одну таблицу для организации хранения имен и паролей пользователей, которым будет делегировано право просмотра и анализа статистики по посещениям данного ресурса: .

Далее необходимо прописать нашу базу данных в соответствующем разделе источников данных системы. Для этого проделайте следующее:

  • Запустите программу — конфигуратор источников данных (Data Sources ODBC) — Start->Settings->Control Panel->Administrative Tools->Data Sources ODBC.
  • Перейдите во вкладку System DSN и создайте новый источник данных, нажав на Add…
  • В появившемся списке драйверов выберите драйвер баз данных — Microsoft SQL Server и нажмите на Next.
  • В строке Data Source Name задайте имя нашей базы данных — в данном случае SiteStat (это имя, по которому мы в дальнейшем будем к ней обращаться).
  • В строке Server укажите сервер, к которому будет осуществлено подключение, и нажмите на Next.
  • Выберите режим аутентификации With SQL Server…, задайте имя пользователя и пароль для подключения к SQL-серверу, определите протокол связи с сервером (кнопка Client Configuration — TCP/IP) и два раза нажмите на Next, после чего нажмите на Finish.
  • Вы увидите статистику о проделанных действиях, а для проверки источника данных можете воспользоваться кнопкой Test Data Source.
  • Перед вами появится строка в списке источников данных в вашей системе.

Теперь, когда база данных готова, можно переходить к созданию и самой системы статистики.

В начало В начало

Интеграция системы в уже готовый сайт

Дело в том, что сама по себе система сбора и анализа статистики не имеет смысла. Посудите сами, кому нужен сайт, предназначенный исключительно для сбора и обработки посещаемости? Поэтому ключевым моментом в  разработке такой системы является в первую очередь простота и удобство ее встраивания в уже существующий ресурс Всемирной компьютерной сети. Следовательно, моментам, связанным с упрощением встраивания системы в уже готовые сайты, надо уделить особое внимание.

В начало В начало

Когда же фиксировать посещения?

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

В начало В начало

Что такое Global.asa

Итак, Global.asa позволяет выполнять определенные скрипты в начале работы клиентской сессии или при инициализации IIS. Более того, допустимо использовать множественные файлы Global.asa. Однако следует помнить, что ASP-скрипт ищет самый близкий (расположенный в том же каталоге) файл Global.asa и использует именно его.

По сути, этот файл может содержать четыре скрипта: первый будет выполняться при инициализации службы IIS/PWS (Application_OnStart), второй — при остановке службы IIS/PWS (Application_OnEnd) (обычно эти первые два скрипта отрабатывают в процессе перезагрузки компьютера), и еще два скрипта выполняются дополнительно при инициализации сессии пользователя (Session_OnStart) и по ее окончании (Session_OnEnd). Данная схема очень сильно напоминает пары «конструктор-деструктор». Неспроста всякая переменная, которая должна быть использована (например, в текущей сессии), может быть инициализирована в Session_OnStart с тем, чтобы быть использованной в процессе работы сессии, уничтожается (обнуляется) же она в Session_OnEnd.

Global.asa не может содержать тэгов HTML. Недопустимо использование JavaScript. Не рекомендуется писать файл Global.asa с помощью каких-либо HTML-редакторов, для этого лучше использовать NotePad. И еще один совет: прежде чем вставлять скрипт в файл Global.asa, попробуйте его в работе в обычном ASP-файле.

<OBJECT RUNAT=Server
SCOPE=Session
ID=Tool1
PROGID="MSWC.Tools">
</OBJECT>
 
<SCRIPT LANGUAGE = "VBScript" RUNAT="Server">
Sub Session_OnStart
Dim strUserLogon
Dim StrUserSecurity
' Эти переменные сессии будут держать
' значения имени пользователя ( logon) и права его доступа
strUserLogon = Request.ServerVariables("USER_LOGON" )
strUserSecurity = "PUBLIC"
End Sub
 
Sub Session_OnEnd
' Этот код уничтожает компонент Tools для текущей сессии.
Set Tool1 = Nothing
'А этот обнуляет переменные сессии.
strUserLogon = ""
strUserSecurity = ""
‘ Внимание!: Данный код применять в этом смысле совсем не обязательно
' так как объекты будут выгружены из памяти Web-сервером
' автоматически по закрытии текущей сессии.
End Sub
 
</SCRIPT>
В начало В начало

Регистрация посещений – файл global.asa

С нашей точки зрения интерес представляет метод Session_OnStart, поскольку именно он отрабатывает при заходе на сайт (при порождении сессии). Итак, нам необходимо вставить в тело этого метода код, который будет осуществлять:

  1. Запись в таблицу хитов всех посещений в подневном режиме.
  2. Запись в таблицу хостов уникальных хостов с фиксацией даты посещения, клиента, IP-адреса и Referer’а посетителя.
<SCRIPT LANGUAGE = VBScript RUNAT=Server>
    <!-- Metadata type="typelib" File="c:\program files\common    files\system\ado\msado15.dll" -->
   </SCRIPT>
   <OBJECT RUNAT=Server SCOPE=Session ID=MyInfo PROGID="MSWC.MyInfo"></OBJECT>
   
   <script language="vbscript" runat=server>
   Sub Application_OnStart
    Session.TimeOut = 1
   End Sub
   
   Sub Application_OnEnd
    Session.Abandon
   End Sub
   
   Sub Session_OnStart
    Session.TimeOut = 1
    dim strConn, objConn
    dim dsn,conn,rs,sql
   …

Объявим переменные, посредством которых будем осуществлять соединение с базой данных:

 …
   dsn = "DSN=SiteStat; UID=SiteStat;PWD=SiteStat;database=SiteStat"
    set conn = server.createobject("adodb.connection")
    set rs = server.createobject("adodb.recordset")
    conn.open dsn
   …

Получим IP-адрес пользователя, его «клиент» и реферер:

 … 
 ' Insert  incoming IP & Client
  dim IP, Browser
  IP = Request.ServerVariables("REMOTE_ADDR")
  Browser = Request.ServerVariables("HTTP_USER_AGENT")
 Referer = Request.ServerVariables("HTTP_REFERER")  
…

Добавим запись в таблицу хостов, если IP-адреса с таким значением там не обнаружено:

 …
    sql = "select * from Hosts where IPAddress='" & IP &    "'"
    rs.open sql, conn, adOpenStatic, adLockOptimistic
    if rs.EOF then
      rs.addnew
      rs("IPAddress") = IP
      rs("HTTPClient") = Browser
      rs("Referer") = Referer
      rs.update
    end if
    rs.close
   
   …

Вычислим сессионную переменную с суммарным количеством хитов за все время существования сайта для отображения на главной страничке:

 …
    ' ---------------------------------
    sql = "select SUM(Hits) As HitsNum from Hits"
    rs.open sql, conn
    Session("Hits") = rs("HitsNum")
    rs.close
   
   …

Увеличим значение хитов за текущий день в таблице хитов. Здесь используются операторы работы с датами языка Transact-SQL. Для того чтобы нижеследующий код был вполне понятен, приведем краткую справку:

   Day(datetime) – возвращает значение дней с начала месяца для заданной даты datetime.
   Month(datetime) – возвращает значение месяцев с начала года для заданной даты    datetime.
   Year(datetime) – возвращает значение лет для заданной даты datetime.
   GetDate() – возвращает текущую дату и время на сервере.
   
   …
    ' ---------------------------------
    sql = "SELECT * FROM Hits WHERE Day(DayDate) = DAY(Getdate()) "
    sql = sql & "AND MONTH(DayDate) = MONTH(GetDate()) AND YEAR(DayDate)    = YEAR(GetDate())"
    rs.open sql, conn
    If NOT rs.EOF THEN
      sql = "UPDATE Hits SET Hits = Hits + 1 WHERE Day(DayDate)    = DAY(Getdate()) "
      sql = sql & "AND MONTH(DayDate) = MONTH(GetDate()) AND    YEAR(DayDate) = YEAR(GetDate())"
      conn.execute(sql)
    Else
      sql = "INSERT INTO Hits (DayDate, Hits) VALUES (GETDATE(),    1)"
      conn.execute(sql)
    End If
    rs.close
   
   …

Вычислим сессионную переменную с суммарным количеством хостов за все время существования сайта для отображения на главной страничке

 …
    
   ' Count hosts ---------------------
    sql = "select COUNT(*) AS HostsNum FROM Hosts"
    rs.open sql, conn, adOpenStatic, adLockOptimistic
    Session("Hosts") = rs("HostsNum")
    rs.close
   
   …

Закроем соединение с базой данных и обнулим переменные

 …
    ' ---------------------------------
    set rs = nothing
    conn.close
    set conn = nothing
   End Sub 
Sub Session_OnEnd
  Session.Abandon
 End Sub
 </script>  
В начало В начало

Сервисные функции системы – файл Utils.asp

Прежде чем мы начнем, целесообразно вынести сервисные функции в отдельный файл, который мы будем «включать» в код по мере необходимости. Это избавит нас от повторений часто используемых функций и частей кода:

<SCRIPT LANGUAGE = VBScript RUNAT=Server>
  <!-- Metadata type="typelib" File="c:\program files\common files\system\ado\msado15.dll" -->
 </SCRIPT>  
…

Функции подключения к базе данных и отключения от нее.

 …
   
   <%
    option explicit
    response.buffer=true
    Response.Buffer = true
   
    dim strConn, objConn
    dim dsn,conn,rs,sql, conn1, rs1, sql1 
 dsn = "DSN=SiteStat; UID=SiteStat;PWD=SiteStat;database=SiteStat"  
 Sub Connect()
   set conn = server.createobject("adodb.connection")
   set rs = server.createobject("adodb.recordset")
   conn.open dsn
  End Sub  
 Sub Connect1()
   set conn1 = server.createobject("adodb.connection")
   set rs1 = server.createobject("adodb.recordset")
   conn1.open dsn
  End Sub
 
  Sub Close()
    rs.close
    set rs = nothing
    conn.close
    set conn = nothing
  End Sub  
 Sub Close1()
      rs1.close
      set rs1 = nothing
      conn1.close
      set conn1 = nothing
    End Sub
   
   …

Функция контроля доступа вызывается в начале каждой странички, информацию на которой по тем или иным признакам можно считать доступной только для определенного круга лиц. В случае несовпадения константы  с сессионной переменной, инициализируемой при входе в систему, пользователь перенаправляется на страничку с сообщением об ошибке доступа .

 …
   
    Sub secure_general()
     If session("status") <> "admin" Then
      Response.Redirect "error.htm"
     End If
    End Sub
   %> 
В начало В начало

Главная страница системы – файл Index.asp

Теперь настала пора изготовить форму ввода имени пользователя и пароля, замкнуть форму на себе самой и, обработав пользовательский ввод уже известным вам из предыдущих серий настоящей статьи образом, перенаправить пользователя на страничку с основным меню системы:

<!--#include file="utils.asp"-->
   <%
    dim useraction,username,password,forumid
   
   …

Анализ пользовательского ввода. Из введенного имени пользователя и пароля удаляются пробелы и производится выборка из таблицы пользователей системы с совпадением имени и пароля с заданными. В случае совпадения инициализируется сессионная переменная, делигирующая доступ к остальным страничкам статистики; в случае несовпадения выводится сообщение об ошибке.

 …
   
    useraction = request("action")
   
    Select Case userAction
     Case "login"
        username = Trim (request.form("username"))
        password = Trim (request.form("password"))
        Call Connect()
        sql="select * from StatUsers where username='"&username&"'    and password='"&password&"'"
        rs.open sql,conn
        If rs.eof AND rs.bof Then
         Response.Write "<b>Проверьте правильность    ввода имени и/или пароля</b><br><br>"
        Else
         Session("status") = "admin"
         Response.Redirect "StatMain.asp"
        End If
        Call Close()
    End Select
   %> 
…

Реализация формы ввода имени и пароля выглядит следующим образом:

 …
   
   <html>
   <head>
   <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
   <link rel="stylesheet" href="grc.css" type="text/css">
   <title>SiteStat - Администрирование</title>
   </head> 
<body>
 <div align="center">
 <h2><p align="center">Статистика посещений Web-сайта <a href="http://www.SiteStat.ru">www.SiteStat.ru</a></p></h2>
 <hr>
 <p>Введите Login и пароль доступа к системе статистики</p>
 <table border=1 bgcolor = "#FFFFeF" width="270">
 <form action="index.asp?action=login" method="post">
 <tr><td colspan=2 align = center>Администратор системы</td></tr>
 <tr><td>Имя:</td><td>
 <input type="text" name="username" size=20 maxlength=20>
 </td></tr>
 <tr><td>Пароль:</td><td>
 <input type="password" name="password" size=20 maxlength=20>
 </td></tr>
 <tr><td colspan=2 align=center><input type="submit" name="submit" value="Вход"></td></tr>
 </form>
 </table>
 <br>
 <hr>
 <a href="javascript:history.back(-1)">Назад</a> | <a href="../main.asp">Главная страница сайта</a>
 </div>
 </body>
 </html>  
В начало В начало

Основное меню системы – файл StatMain.asp

После того как процедура идентификации пользователя пройдена, можно реализовать страничку с основным меню системы, с которой будут осуществлены переходы в режим просмотра данных по хостам, по хитам и в режим графического просмотра динамики хитов за интервалы времени (по дням и по месяцам):

<!--#include file="utils.asp"-->
 <%
  Call secure_general()
 %>            
<html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
 <link rel="stylesheet" href="grc.css">
 <title>ASP на блюдечке.Часть 18.Статистика посещений</title>
 </head>  
<body>
 <h2><p align="center">Статистика посещений Web-сайта <a href="http://www.SiteStat.ru">www.SiteStat.ru</a></p></h2>
 <hr>  
<div align="center">
   <h3>Выберите режим работы <br><br></h3>
   <p><a href="Hosts.asp">Статистика уникальных посещений    Web-сайта (хосты)</a></p>
   <p><a href="Hits.asp">Статистика всех посещений Web-сайта    (хиты)</a></p>
   <p><a href="HitsGraph.asp">Графическое представление хитов    по датам</a></p>
   <hr>
   <p>
   <a href="javascript:history.back(-1)">Назад</a> | <a    href="../main.asp">Главная страница</a>
   </p>
   </div>
   </body>
   </html>
В начало В начало

Статистика уникальных посещений (хостов) – файл Hosts.asp

Выборка статистики по уникальным посещениям основана на таблице Hosts и содержит те ее значения, которые соответствуют дате, задаваемой посредством интерфейса пользователя, и отсортированы по дате начиная с самого свежего хоста. Для реализации последнего нам потребуется разработать фильтр хостов по дням. Сделать это лучше всего в дополнительном, включаемом файле, который необходимо включить в тело нижеследующего модуля Hosts.asp:

<!--#include file="utils.asp"-->
 <%
  Call secure_general()
 %>            
<html>
   <head>
   <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
   <link rel="stylesheet" href="grc.css">
   <title>ASP на блюдечке. Часть 19. Статистика посещений</title>
   
   </head>
   <body>
   
   <%
    Dim DayPassed, MonthPassed, YearPassed, DateDisplayed, adSQL
   …
   Опросим переменные, содержащие дату, хосты по которой требуется показать
   …
    DayPassed   = Request("DayPassed")
    MonthPassed = Request("MonthPassed")
    YearPassed  = Request("YearPassed")
    Session("DisplayDate") = DayPassed & "." &    MonthPassed & "." & YearPassed
   …

Построим SQL-запрос — фильтр наших данных

 …
    If DayPassed <> "" AND MonthPassed <> ""    AND YearPassed <> "" Then
     adSQL = " WHERE DAY(DateVisited) = " & DayPassed &    " AND MONTH(DateVisited) = " & MonthPassed
     adSQL = adSQL  & " AND YEAR(DateVisited) = " &    YearPassed
     DateDisplayed = CStr(DayPassed) & "." & CStr(MonthPassed)    & "." & CStr(YearPassed)
    Else
     adSQL = " WHERE DAY(DateVisited) = DAY(GETDATE()) AND MONTH(DateVisited)    = MONTH(GETDATE())"
     adSQL = adSQL  & " AND YEAR(DateVisited) = YEAR(GETDATE())"
     DateDisplayed = "сегодня - " & Date()
     Session("DisplayDate") = Day(Date()) & "." &    Month(Date()) & "." & Year(Date())
    End If
   
    call connect()
    sql="SELECT COUNT(*) AS HostsNum FROM HOSTS" & adSQL
    rs.open sql,conn
   
   %>
   
   <h2><p align="center">Статистика посещений Web-сайта <a    href="http://www.centpart.ru">www.centpart.ru</a></p></h2>
   <hr>
   <div align="center">
   <h3>Выборка по уникальным заходам на сайт за <% Response.Write "    за " & DateDisplayed %> (всего <% = rs("HostsNum")%>    хост(ов))</h3>
   …

Вот сюда и включим файл нашего компонента-календаря

…
   <!--#include file="calendar.asp"--> 
<br>
 <table border=2 width=960 align=center>
   <tr align = left>
     <td colspan = 2 width="170"><h4>Дата посещения</h4></td>
     <td colspan = 2 width="120"><h4>IP-адрес</h4></td>
     <td colspan = 2 width="220"><h4>Реферер</h4></td>
     <td colspan = 2 width="450"><h4>HTTP Клиент (браузер)</h4></td>
   </tr>
 
  <%
  rs.close
 
  sql="SELECT * FROM Hosts " & adSQL & " ORDER BY DateVisited DESC"
  rs.open sql,conn
  Do While NOT rs.EOF
 %>
   <tr align = left>
     <td colspan = 2><% =rs("DateVisited") %></td>
     <td colspan = 2><% =rs("IPAddress") %></td>
     <td colspan = 2><a href="><% =rs("Referer") %>"><% =rs("Referer") %></a></td>
     <td colspan = 2><% =rs("HTTPClient") %></td>
     <% 
  rs.MoveNext
 Loop
 %>
   </tr>
   <%  call close() %>
 </table>
 <br>  
<p>
 <a href="javascript:history.back(-1)">Назад</a> | <a href="StatMain.asp">Главная страница статистики</a>
 </p>
 </div>
 </body>
 </html>  
В начало В начало

Симпатичный календарь – файл Calendar.asp

Теперь, пожалуй, настала пора разобраться с интерфейсом даты, хосты по которой мы, собственно, и будем предоставлять пользователям. Вопреки традиции откажемся от использования формы, в которую необходимо «вбить» значения дня, месяца и года, а реализуем гораздо более удобный элемент управления, похожий на обычный настенный календарь. Страничка со списком хостов с таким календарем (встроенным, как мы описали выше) будет выглядеть гораздо привлекательнее и удобнее ().

Работает такой компонент очень просто. По умолчанию он отображает текущую дату. Дни месяца выполнены в виде линков, которые приводят к показу хостов соответствующей даты (что, собственно, и реализует SQL-фильтр по дате в модуле Hosts.asp). Кроме того, существуют линки, переходящие от месяца к месяцу вперед и назад. Для реализации такого компонента нам для начала потребуется четыре функции обработки дат. Давайте рассмотрим их:

' Функция подсчета количества дней в месяце
  Function GetDaysInMonth(iMonth, iYear)
    Dim dTemp
    dTemp = DateAdd("d", -1, DateSerial(iYear, iMonth + 1, 1))
    GetDaysInMonth = Day(dTemp)
  End Function   
 ' Функция подсчета дня начала месяца
  Function GetWeekdayMonthStartsOn(dAnyDayInTheMonth)
    Dim dTemp
    dTemp = DateAdd("d", -(Day(dAnyDayInTheMonth) ), dAnyDayInTheMonth)
    GetWeekdayMonthStartsOn = WeekDay(dTemp)
  End Function  
 ' Функция-декрементор месяцев, которая будет отрабатываться при переходе к предыдущему месяцу
  Function SubtractOneMonth(dDate)
    SubtractOneMonth = DateAdd("m", -1, dDate)
  End Function
 
  ' Функция-инкрементор месяцев, которая будет отрабатываться при переходе к следующему месяцу
  Function AddOneMonth(dDate)
    AddOneMonth = DateAdd("m", 1, dDate)
  End Function  

Далее мы просто должны прочитать дату из сессионной переменной (она может быть текущей, а может задаваться пользователем). После этого, прежде чем рисовать таблицу со значениями, требуется вычислить параметры для цикла, а именно: количество дней в месяце и день недели, с которого начинается месяц. А дальше все очень просто:

<%
  Dim dDate             ' Дата показа календаря
  Dim iDIM               ' Дней в месяце
  Dim iDOW              ' День недели, с которого начинается месяц
  Dim iCurrent          ' Текущий день месяца
  Dim iPosition         ' Текущая позиция в таблице
  Dim DayStr, MonStr    ' День и месяц в правильном формате ( с 0 в начале, если день однозначен)  
 Response.write Session("DisplayDate")
 
  dDate = CDate(Session("DisplayDate"))
 
 …

Получим значение дней в месяце и дня недели, с которого он начинается

 …
  iDIM = GetDaysInMonth(Month(dDate), Year(dDate))
  iDOW = GetWeekdayMonthStartsOn(dDate)
 %>  
<!-- Внешняя таблица для рисования контура-->
   <TABLE BORDER=5 CELLSPACING=0 CELLPADDING=0>
   <TR><TD>
   <TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1 BGCOLOR=#99CCFF>
   <TR>
     <TD BGCOLOR=#B4AF94 ALIGN="center" COLSPAN=7>
     <TABLE WIDTH=100% BORDER=0 CELLSPACING=0 CELLPADDING=0>
     <TR>
   …

Построим строку и передадим ее модулю Hosts.asp, где  в качестве параметров передадим день, месяц и год даты, данные по которой необходимо представить пользователю. Как видите, передается строка, в которой переменным DayPassed, MonthPassed и YearPassed присваиваются значения дня, месяца и года предыдущего и последующего месяцев соответственно, в зависимости от линка, которым воспользуется пользователь (дата генерируется функциями, возвращающими значение следующего и предыдущего месяцев):

 …
      <TD ALIGN="right"><A HREF="Hosts.asp?DayPassed=<%=Day(SubtractOneMonth(dDate))%>&MonthPassed=<%=Month(SubtractOneMonth(dDate))%>
&YearPassed=<%=Year(SubtractOneMonth(dDate))%>"><FONT    COLOR=#5c0000 SIZE="-1">&lt;&lt;</FONT></A></TD>  
   <TD ALIGN="center"><FONT COLOR=#5c0000><B><%= MonthName(Month(dDate)) & "  " & Year(dDate) %></B></FONT></TD>
    <TD ALIGN="left"><A HREF="Hosts.asp?DayPassed=<%= Day(AddOneMonth(dDate)) %>&MonthPassed=<%= Month(AddOneMonth(dDate))
 %>&YearPassed=<%= Year(AddOneMonth(dDate)) %>"><FONT COLOR=#5c0000 SIZE="-1">&gt;&gt;</FONT></A></TD>
   </TR>  
</TABLE>
 </TD>
 </TR>
 <TR>
  <TD ALIGN="center" BGCOLOR=#B4AF94><FONT COLOR=#5c0000><B>Пн.</B></FONT></TD>
  <TD ALIGN="center" BGCOLOR=#B4AF94><FONT COLOR=#5c0000><B>Вт.</B></FONT></TD>
  <TD ALIGN="center" BGCOLOR=#B4AF94><FONT COLOR=#5c0000><B>Ср.</B></FONT></TD>
  <TD ALIGN="center" BGCOLOR=#B4AF94><FONT COLOR=#5c0000><B>Чт.</B></FONT></TD>
  <TD ALIGN="center" BGCOLOR=#B4AF94><FONT COLOR=#5c0000><B>Пт.</B></FONT></TD>
  <TD ALIGN="center" BGCOLOR=#B4AF94><FONT COLOR=#5c0000><B>Сб.</B></FONT></TD>
  <TD ALIGN="center" BGCOLOR=#B4AF94><FONT COLOR=#5c0000><B>Вск.</B></FONT></TD>
 </TR>  
<%
   …

  Заполним часть первого ряда пустыми ячейками, если месяц начинается не с первого дня недели

 … 
 If iDOW <> 1 Then
     Response.Write vbTab & "<TR>" & vbCrLf
     iPosition = 1
     Do While iPosition < iDOW
      Response.Write vbTab & vbTab & "<TD BGCOLOR=#E0DDCE>&nbsp;</TD>"    & vbCrLf
      iPosition = iPosition + 1
     Loop
    End If
   …

Далее  заполним нашу таблицу днями, подсветим текущий

 … 
 iCurrent = 1
    iPosition = iDOW
   
    Do While iCurrent <= iDIM
     ' Если мы в начале ряда, пишем tr
     If iPosition = 1 Then  Response.Write vbTab & "<TR>"    & vbCrLf End If         
   
     ' Подсветим текущий день
     If iCurrent = Day(dDate) Then
      Response.Write vbTab & vbTab & "<TD BGCOLOR=#B4AF94><FONT    COLOR=#5c0000 SIZE=""-1""><B>" & iCurrent    & "</B></FONT><BR></TD>"
     Else
      DayStr = CStr(iCurrent)
      If Len(DayStr) = 1 Then DayStr = "0" & DayStr
      MonStr = CStr(Month(dDate))
      If Len(MonStr) = 1 Then MonStr = "0" & MonStr
   …

Аналогичным образом формируется и ссылка на конкретную дату (конкретный день месяца)

 …
   
      Response.Write  vbTab & vbTab & "<TD BGCOLOR=#E0DDCE><A    HREF='Hosts.asp?DayPassed=" & DayStr & "&MonthPassed="    
& MonStr & "&YearPassed=" & Year(dDate) & "'><FONT    SIZE=""-1"">" & iCurrent & "</FONT></A><BR></TD>"
     End If    
  ' Если мы в конце ряда, пишем /tr
   If iPosition = 7 Then
    Response.Write vbTab & "</TR>" & vbCrLf
    iPosition = 0
   End If  
  iCurrent = iCurrent + 1
   iPosition = iPosition + 1
  Loop  
…

Заполним остаток ячеек дней месяца пустотами

 … 
 If iPosition <> 1 Then
   Do While iPosition <= 7
    Response.Write vbTab & vbTab & "<TD BGCOLOR=#E0DDCE>&nbsp;</TD>" & vbCrLf
    iPosition = iPosition + 1
   Loop
   Response.Write vbTab & "</TR>" & vbCrLf
  End If
 %>  
В начало В начало

Статистика всех посещений (хитов) – файл Hits.asp

Выборка статистики по всем посещениям основана на таблице Hits и содержит выборку по дням всех ее значений, отсортированных по дате начиная с самого свежего хита:

<!--#include file="utils.asp"-->
 <%
  Call secure_general()
 %>  
<html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
 <link rel="stylesheet" href="grc.css">
 <title>ASP на блюдечке. Часть 18.Статистика посещений</title>
 </head>
 <body>
   <%
  call connect()
  sql="SELECT COUNT(*) AS DaysNum, SUM(Hits) As HitsNum FROM Hits"
  rs.open sql,conn
 %>  
<h2><p align="center">Статистика посещений Web-сайта <a href="http://www.SiteStat.ru">www.SiteStat.ru</a></p></h2>
 <hr>
 <div align="center">
 <h3>Выборка по всем заходам на сайт (по <% = rs("HitsNum") %> хитам, произошедшим за <% = rs("DaysNum")%> дней)</h3>
 <br>
 <table border=2 width=830 align=center>
   <tr align = left>
     <td colspan = 2 width="170"><h4>День посещения</h4></td>
     <td colspan = 2 width="500"><h4>Количество хитов</h4></td>
   </tr>
 <%
  rs.close
  sql="SELECT * FROM Hits ORDER BY DayDate DESC"
  rs.open sql,conn
  Do While NOT rs.EOF
 %>
   <tr align = left>
     <td colspan = 2>
       <% =rs("DayDate") %>
     </td>
     <td colspan = 2>
       <% =rs("Hits") %>
     </td>
     <% 
  rs.MoveNext
 Loop
 %>
   </tr>
   <%
  call close()
 %>
 </table>
 <br>
 
   
<p>
 <a href="javascript:history.back(-1)">Назад</a> | <a href="StatMain.asp">Главная страница статистики</a>
 </p>
 </div>
 
 </body>
 </html>  
В начало В начало

Графическое представление статистики (хитов) по датам – файл HitsGraph.asp

Выборка статистики по всем посещениям основана на таблице Hits и содержит выборку по дням всех ее значений, отсортированных по дате начиная с самого свежего хита. Страничка реализована в двух режимах: режим просмотра по дням и режим просмотра по месяцам. В каждом из режимов помимо численной информации представлена и графическая информация в виде горизонтальных и вертикальных столбиков соответственно:

<!--#include file="utils.asp"-->
 <%
  DIM ScaleFactor, I, MonthStr, MaxMonthHits, Month, Year
  Call secure_general()
 %>  
<html>
   <head>
   <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
   <link rel="stylesheet" href="grc.css">
   <title>Централ Партнершип - статистика посещений</title>
   </head>
   
   <body>
   
   …

Для начала определим суммарное количество хитов и количество дней, за которые ведется статистика:

 … 
<%
  call connect()
  sql="SELECT COUNT(*) AS DaysNum, SUM(Hits) As HitsNum FROM Hits"
  rs.open sql,conn
 %>
 
 <h2><p align="center">Статистика посещений Web-сайта <a href="http://www.SiteStat.ru">www.SiteStat.ru</a></p></h2>
 <hr>
 <div align="center">
 <h3>Выборка по всем заходам на сайт (по <% = rs("HitsNum") %> хитам, произошедшим за <% = rs("DaysNum")%> дней)</h3>
 
 <%
  rs.close  
…

Затем опросим переменную режима работы и сформируем форму в зависимости от ее значения. Обратите внимание на то, каким образом реализована обработка нажатия на радиокнопки. Submit формы происходит не по нажатию на кнопку Submit (которой в данном случае вообще нет), а по непосредственному переключению режима. Это достигается посредством встраивания кода "javascript:document.ViewStyleForm.submit();" в функцию обработки нажатия на радиокнопку OnClick:

 … 
 Dim VS
  VS = request("vs")
  If VS = "" THEN VS = 1
 %>  
<table>
   <tr><td>
   <form name="ViewStyleForm" method="post" action="HitsGraph.asp">
   <input type="radio" name="vs" value="1" OnClick="javascript:document.ViewStyleForm.submit();"
   <% If VS = 1 THEN Response.Write "checked" %> >Просмотр по    дням<br>
   <input type="radio" name="vs" value="2" OnClick="javascript:document.ViewStyleForm.submit();"
   <% If VS = 2 THEN Response.Write "checked" %> >Просмотр по    месяцам
   </form>
   </td></tr>
   </table>
   
   …

Далее в зависимости от выбранного режима работы:

 … 
<%
  If VS = 1 Then
     Response.Write "<table border=2 width=830 align=center><tr align = left>"
     Response.Write "<td colspan = 2 width='170'><h4>Дата посещения</h4></td>"
     Response.Write "<td colspan = 2 width='660'><h4>Хитов</h4></td></tr>"
 
     sql="SELECT MAX(Hits) AS MaxHits FROM Hits"
     rs.open sql,conn
     ScaleFactor = 650 / rs("MaxHits")
     rs.close  
    sql="SELECT * FROM Hits ORDER BY DayDate DESC"
     rs.open sql,conn  
    I = 1  
    Do While NOT rs.EOF
      Response.Write "<tr align = left><td colspan = 2>"
      Response.Write rs("DayDate")
      Response.Write "</td><td colspan = 2>"
      Response.Write "<img src = images/char"& I &".gif width=" & rs("Hits") * ScaleFactor & " height=10>"
      Response.Write "&nbsp;" & rs("Hits")
      Response.Write "</td>"  
     I = I + 1
      IF I = 11 Then I = 1
     rs.MoveNext
     Loop  
    Response.Write "</tr>"
     call close()  
 Else
 %>  
<table cellspacing=0 cellpadding=0 width=830 height=550 style="BORDER-RIGHT:    rgb(0,0,0) 0px outset; BORDER-TOP: rgb(0,0,0) 0px
   outset; BORDER-LEFT: rgb(128,128,128) 1px outset; BORDER-BOTTOM: rgb(128,128,128)    1px
   outset"vAlign=top width="830"  height=1>
   
   <tr align="left">
   <td width="5">&nbsp;</td>
   
   …

Необходимо сосчитать количество хитов, произошедших за месяц. Для этого создадим вычисляемое поле, однозначно идентифицирующее совокупность записей в таблице хитов за месяц. Сделать это очень просто — прибавив к значению года значение месяца, умноженное на 12. Далее будем оперировать этим значением для реализации поиска количества месяцев, вычисления суммы хитов за месяц и фактора масштабирования, для корректного отображения графических элементов на экране независимо от фактических значений:

 …
   
   <%
     MaxMonthHits = 0 
  sql = "SELECT DISTINCT YEAR(DayDate) * 12 + MONTH(DayDate) AS UniqueMonth FROM Hits"
   rs.open sql,conn
 
   Do While NOT rs.EOF
     Call Connect1()
      sql1="SELECT Hits, MONTH(DayDate) AS Month, YEAR(DayDate) AS Year "
      sql1 = sql1 & " FROM Hits WHERE (YEAR(DayDate) * 12 + MONTH(DayDate)) = "
      sql1 = sql1 & rs("UniqueMonth") & " ORDER BY DayDate"
      rs1.open sql1,conn1
      MonthStr = CStr(rs1("Month")) & "." & CStr(rs1("Year"))
     Call Close1()
     Call Connect1()
      sql1="SELECT SUM(Hits) AS MonthHits FROM Hits WHERE YEAR(DayDate) * 12 + MONTH(DayDate) = " & rs("UniqueMonth")
     rs1.open sql1,conn1
      If MaxMonthHits < rs1("MonthHits") Then MaxMonthHits = rs1("MonthHits")
     Call Close1()
     rs.MoveNext
   Loop   
  rs.close
 
   I = 1
   ScaleFactor = 550 / MaxMonthHits  
  sql = "SELECT DISTINCT YEAR(DayDate) * 12 + MONTH(DayDate) AS UniqueMonth FROM Hits"
   rs.open sql,conn  
  Do While NOT rs.EOF
     Call Connect1()
      sql1="SELECT Hits, MONTH(DayDate) AS Month, YEAR(DayDate) AS Year "
      sql1 = sql1 & " FROM Hits WHERE (YEAR(DayDate) * 12 + MONTH(DayDate)) = "
      sql1 = sql1 & rs("UniqueMonth") & " ORDER BY DayDate"
      rs1.open sql1,conn1
      Month = rs1("Month")
      Year = rs1("Year")
     Call Close1()
     Call Connect1()
 
      sql1="SELECT SUM(Hits) AS MonthHits FROM Hits WHERE YEAR(DayDate) * 12 + MONTH(DayDate) = " & rs("UniqueMonth")
      rs1.open sql1,conn1
      Response.Write "<td width='2' valign='bottom' align='left'>"
      Response.Write "<img src = images/char" & I & ".gif width=20 height="
      Response.Write rs1("MonthHits") * ScaleFactor & "></td>"
      Response.Write "<td width='5' valign='bottom' align='left'>"
      Response.Write "<img src = images/Months/" & Month & ".gif </td>"
     Call Close1()  
    I = I + 1
     If I = 11 Then I = 1
     rs.MoveNext
   Loop   
  rs.close
 %>  
<td width=100%>&nbsp;</td>
 </tr>
 </table>
 
 <%
  End If
 %>  
</table>
 <br>
 <p>
 <a href="javascript:history.back(-1)">Назад</a> | <a href="StatMain.asp">Главная страница статистики</a>
 </p>
 </div>
 
 </body>
 </html>  
В начало В начало

Заключение

Рассмотренная нами система сбора и анализа статистики по посещению Интернет-ресурса достаточно удобна и позволяет отслеживать основную информацию по динамике посещений. Благодаря модульной реализации система легко встраиваема в сайт практически любой степени сложности. Среди новых возможностей нужно отметить регистрацию реферера пользователя и наличие компонент-календаря. Последний, в частности, может быть с успехом применен не только в системах сбора и обработки информации, но и везде, где необходим удобный и наглядный фильтр по дате именно в виде календаря. Благодаря модульной реализации встраивание его в любую такую систему займет не более 10 минут.

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

В заключение хотелось бы отметить, что система анализа статистики обращений является достаточно мощным и удобным инструментом, позволяющим пользователю получить доступ к информации, качественным образом повышающей посещаемость того или иного Интернет-ресурса, независимо от характера и структуры последнего.

КомпьютерПресс 4'2002