Графический вывод статистики
Задача ставится так - выводим данные о посещениях и просмотрах в виде диаграммы, для сравнения - еще и вчерашние данные, заодно сравниваем сегодняшние показатели со вчерашними. Вот то, что видит посетитель на странице (если мы ему это, конечно, покажем):
А вот что можем увидеть мы. Можно обновить эту страницу, посмотреть, как меняются показания счетчика на странице и статистика на диаграмме. Перейдем к самому скрипту. Вот он целиком:
<?php
function yesterday(){
$ct=mktime(0,0,0,date('m'),date('d')-1,date("Y"));
$y=date('d-m',$ct);
return $y;}
function get_count($fn){
$dtf=@file_get_contents($fn);
$dtr=explode("|",$dtf);
return $dtr;}
function get_date(){
$m=date('m');
$nm=array("января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря");
return date('d').chr(32).$nm[intval($m-1)].chr(32).date('Y')." года: ";
}
function picture($dat,$daty,$si){
if(file_exists(date('d-m').".gif")){unlink(date('d-m').".gif");}
$img = imageCreate(600, 480);
$linelen=2;
$gray = imageColorAllocate($img, 220, 220, 220);
$black = imageColorAllocate($img, 0, 0, 0);
$white = imageColorAllocate($img, 255, 255, 255);
$green = imageColorAllocate($img, 100, 255, 100);
$red = imageColorAllocate($img, 255, 0, 0);
$pink = imageColorAllocate($img, 240, 200, 240);
imageFill($img, 1, 1, $white);
$h=intval(date('H'));
$tt=array_sum($dat);
$ty=0;
for($i=0;$i<=$h;$i++){$ty=$ty+$daty[$i];}
$dif=$tt-$ty;
if($dif>=0){$col=$green;$sign="+";}else{$col=$red;$sign="";}
$dats=$dat;
sort($dats);
$datsy=$daty;
sort($datsy);
$ymax0= array_pop($dats);
$ymax1= array_pop($datsy);
if($ymax0>$ymax1){$ymax=$ymax0;}else{$ymax=$ymax1;}
$xtl=30;
$xbr=560;
$ybr=380;
$ytl=30;
$tlm=array(0,10,20,40,100,200,400,1000,2000,5000,10000,20000);
$tlk=array(1,2,4,5,10,20,50,100,200,500,1000,4000);
for($i=0;$i<count($tlm);$i++){
if($ymax>$tlm[$i]&$ymax<=$tlm[$i+1]){$km=$i;break;}
}
$mf = imageloadfont ('fontc.phpfont');
$mx=($xbr-$xtl)/24;
$my=(($ybr-$ytl)/$tlm[$km+1]);
$h=intval(date('H'));
for($i=0;$i*$mx<$xbr-$mx;$i++){
imageline($img,$xtl+$i*$mx,$ytl,$xtl+$i*$mx,$ybr,$gray);
imageline($img,$xtl+$i*$mx,$ybr,$xtl+$i*$mx,$ybr+$linelen,$black);
imagefttext ($img, 8,0, $ytl+$i*$mx-5,$ybr+12,$black, "arial.ttf",$i);
if($i<=$h){imagefilledrectangle($img,$xtl+$i*$mx,$ybr-$daty[$i]*$my,$xtl+$i*$mx-10,$ybr,$pink);
imagefilledrectangle($img,$xtl+$i*$mx,$ybr-$dat[$i]*$my,$xtl+$i*$mx+10,$ybr,$green);
imagefttext ($img, 5,0, $xtl+$i*$mx-7,$ybr-$daty[$i]*$my-5,$red, "arial.ttf",$daty[$i]);
imagefttext ($img, 5,0, $xtl+$i*$mx+1,$ybr-$dat[$i]*$my-5,$black, "arial.ttf",$dat[$i]);}
}
$n=$tlk[$km+1];
$z=$tlm[$km+1]/$n;
$ind=0;
for($i=$ybr;$i>=$ytl;$i=$i-$my*$n){
imageline($img,$xtl,$i,$xbr,$i,$gray);
imageline($img,$xtl,$i,$xtl-$linelen,$i,$black);
imagefttext ($img, 8,0, $xtl-strlen($ind*$n)*3-15, $i+3,$black, "arial.ttf",$ind*$n);
$ind=$ind+1;
}
imageline($img,$xtl,$ytl,$xtl,$ybr,$black);
imageline($img,$xtl,$ybr,$xbr,$ybr,$black);
imagefilledrectangle($img,180,$ybr+28,190,$ybr+38,$green);
imagefilledrectangle($img,280,$ybr+28,290,$ybr+38,$pink);
$txtt="Сегодня";
$txty="Вчера";
$txtc="Время";
$txtv="ПОСЕТИТЕЛИ";
$txtl="ПРОСМОТРЫ";
if($si==0){$txti=$txtl;} else{$txti=$txtv;}
$txts="СТАТИСТИКА за ".get_date();
imagestring($img, $mf, 200, $ybr+30, $txtt, $black);
imagestring($img, $mf, 300, $ybr+30, $txty, $black);
imagestring($img, $mf, $xbr/2, 5, $txti, $black);
imagestring($img, $mf, $xbr-30, $ybr+20, $txtc, $black);
imagestring($img, $mf, $xtl+30, $ybr+50, "Всего сегодня: ".$tt, $black);
imagestring($img, $mf, $xtl+200, $ybr+50,$sign.$dif, $col);
imagestring($img, $mf, 5, 5, $txts, $black);
imagejpeg($img,date('d-m').".jpg");
}
$mode=$_GET['mode'];
if(!$mode)$mode=hit;
if($mode=="hit"){
$dt=get_count("stat/hit/".date('d-m').".hit");
$dty=get_count("stat/hit/".yesterday().".hit");
}
if($mode=="host"){
$dt=get_count("stat/hst/".date('d-m').".hst");
$dty=get_count("stat/hst/".yesterday().".hst");
}
$pic=picture($dt,$dty,$h);
$mnu="<center><a href='stat.php?mode=hit'>ПРОСМОТРЫ</a>
<a href='stat.php?mode=host'>ПОСЕТИТЕЛИ</a>";
$out= "<img src=".date('d-m').".jpg >";
?>
<HTML>
<head>
</head>
<body>
<?echo $mnu."<BR><BR>".$out?>
</body>
</HTML>
И, как обычно подробно обо всем. В начале - блок функций. Первая функция получает вчерашнюю дату - это нужно, чтобы была возможность вывести на диаграмму число просмотров и посетителей вчера.
function yesterday(){
$ct=mktime(0,0,0,date('m'),date('d')-1,date("Y"));
$y=date('d-m',$ct);
return $y;}
Следующая функция читает содержимое файла статистики и возвращает это содержимое в виде массива:
function get_count($fn){
$dtf=@file_get_contents($fn);
$dtr=explode("|",$dtf);
return $dtr;}
Функция get_date() возвращает текущую дату в формате число-месяц-год, причем месяц - по-русски. То же самое можно сделать и установкой местной (российской) локали, но эта установка немного отличается в различных версиях PHP. Функцией - проще:
function get_date(){
$m=date('m');
$nm=array("января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря");
return date('d').chr(32).$nm[intval($m-1)].chr(32).date('Y')." года: ";
}
И, наконец, самая главная и самая громоздкая функция скрипта, та, которая строит график. Функции передается массив сегодняшних данных $dat, вчерашних $daty и переменная режима $si - она нужна для формирования комментариев. Функция рисует график и сохраняет его в виде файла, поэтому при обращении к функции первым делом изничтожаем предыдущую картинку, если такая существует:
function picture($dat,$daty,$si){
if(file_exists(date('d-m').".jpg")){unlink(date('d-m').".jpg");}
Определяем идентификатор рисунка(в скобках - его размеры) и вспомогательную переменную $linelen для вывода координатной сетки:
$img = imageCreate(600, 480);
$linelen=2;
Определяем те цвета, которые будем использовать и заполняем поле рисунка белым цветом (последняя строка этого фрагмента):
$gray = imageColorAllocate($img, 220, 220, 220);
$black = imageColorAllocate($img, 0, 0, 0);
$white = imageColorAllocate($img, 255, 255, 255);
$green = imageColorAllocate($img, 100, 255, 100);
$red = imageColorAllocate($img, 255, 0, 0);
$pink = imageColorAllocate($img, 240, 200, 240);
imageFill($img, 1, 1, $white);
Получаем значение текущего часа и число посетителей или просмотров с начала суток и по настоящее время. Число посетителей или просмотров за вчерашний день обнуляем:
$h=intval(date('H'));
$tt=array_sum($dat);
$ty=0;
Теперь предстоит просуммировать число посетителей или просмотров за прошлые сутки от начала суток до текущего часа (первая строка, процесс организован в цикл), вычислить разность между сегодняшними и вчерашними показателями и определить цвет, которым эта разность будет выводиться, рассортировать массивы вчерашней и сегодняшней статистики по возрастанию и найти в каждом массиве наибольшее значение:
for($i=0;$i<=$h;$i++){$ty=$ty+$daty[$i];}
$dif=$tt-$ty;
if($dif>=0){$col=$green;$sign="+";}else{$col=$red;$sign="";}
$dats=$dat;
sort($dats);
$datsy=$daty;
sort($datsy);
$ymax0= array_pop($dats);
$ymax1= array_pop($datsy);
Выбираем из двух максимальных значений наибольшее - оно потребуется для определения вертикального масштаба графика:
if($ymax0>$ymax1){$ymax=$ymax0;}else{$ymax=$ymax1;}
Задаем координаты углов графика:
$xtl=30;
$xbr=560;
$ybr=380;
$ytl=30;
И два массива масштабов: первый - полное число по вертикали, второй - на единицу масштаба:
$tlm=array(0,10,20,40,100,200,400,1000,2000,5000,10000,20000);
$tlk=array(1,2,4,5,10,20,50,100,200,500,1000,4000);
Определяем масштаб, который будем использовать:
for($i=0;$i<count($tlm);$i++){
if($ymax>$tlm[$i]&$ymax<=$tlm[$i+1]){$km=$i;break;}
}
и шрифт:
$mf = imageloadfont ('fontc.phpfont');
Теперь от единиц переходим к пикселям:
$mx=($xbr-$xtl)/24;
$my=(($ybr-$ytl)/$tlm[$km+1]);
Определяем текущий час и строим координатную сетку:
$h=intval(date('H'));
for($i=0;$i*$mx<$xbr-$mx;$i++){
рисуя деления горизонтальной оси черным цветом, а вспомогательную сетку (пока только вертикальную) - серым:
imageline($img,$xtl+$i*$mx,$ytl,$xtl+$i*$mx,$ybr,$gray);
imageline($img,$xtl+$i*$mx,$ybr,$xtl+$i*$mx,$ybr+$linelen,$black);
Подписываем значения делений оси Х, используя шрифт arial (он легко масштабируется до нужного размера):
imagefttext ($img, 8,0, $ytl+$i*$mx-5,$ybr+12,$black, "arial.ttf",$i);
Строим диаграмму в виде закрашенных прямоугольников, над каждым - пишем числовое значение:
if($i<=$h){imagefilledrectangle($img,$xtl+$i*$mx,$ybr-$daty[$i]*$my,$xtl+$i*$mx-10,$ybr,$pink);
imagefilledrectangle($img,$xtl+$i*$mx,$ybr-$dat[$i]*$my,$xtl+$i*$mx+10,$ybr,$green);
imagefttext ($img, 5,0, $xtl+$i*$mx-7,$ybr-$daty[$i]*$my-5,$red, "arial.ttf",$daty[$i]);
imagefttext ($img, 5,0, $xtl+$i*$mx+1,$ybr-$dat[$i]*$my-5,$black, "arial.ttf",$dat[$i]);}
}
Рисуем горизонтальную вспомогательную сетку, используя полученное раньше значение масштаба, и расставляем деления:
$n=$tlk[$km+1];
$z=$tlm[$km+1]/$n;
$ind=0;
for($i=$ybr;$i>=$ytl;$i=$i-$my*$n){
imageline($img,$xtl,$i,$xbr,$i,$gray);
imageline($img,$xtl,$i,$xtl-$linelen,$i,$black);
imagefttext ($img, 8,0, $xtl-strlen($ind*$n)*3-15, $i+3,$black, "arial.ttf",$ind*$n);
$ind=$ind+1;
}
Проводим линии координат черным цветом и рисуем два маленких вспомогательных квадрата - заготовки к подписи графика:
imageline($img,$xtl,$ytl,$xtl,$ybr,$black);
imageline($img,$xtl,$ybr,$xbr,$ybr,$black);
imagefilledrectangle($img,180,$ybr+28,190,$ybr+38,$green);
imagefilledrectangle($img,280,$ybr+28,290,$ybr+38,$pink);
Подготавливаем текст подписей с учетом режима (посетители или просмотры):
$txtt="Сегодня";
$txty="Вчера";
$txtc="Время";
$txtv="ПОСЕТИТЕЛИ";
$txtl="ПРОСМОТРЫ";
if($si==0){$txti=$txtl;} else{$txti=$txtv;}
$txts="СТАТИСТИКА за ".get_date();
Выводим текстовые переменные, сохраняем рисунок и заканчиваем функцию:
imagestring($img, $mf, 200, $ybr+30, $txtt, $black);
imagestring($img, $mf, 300, $ybr+30, $txty, $black);
imagestring($img, $mf, $xbr/2, 5, $txti, $black);
imagestring($img, $mf, $xbr-30, $ybr+20, $txtc, $black);
imagestring($img, $mf, $xtl+30, $ybr+50, "Всего сегодня: ".$tt, $black);
imagestring($img, $mf, $xtl+200, $ybr+50,$sign.$dif, $col);
imagestring($img, $mf, 5, 5, $txts, $black);
imagejpeg($img,date('d-m').".jpg");
}
Уф! Наконец мы у ворот Мадрида! - так, кажется у классиков... Осталось самая малость. Основной блок: получаем переменную $mode, которая определит, что будем рассматривать - посетителей или просмотры, и, если, просмотры - то считываем из файлов статистики данные за сегодняшний и вчерашний день:
$mode=$_GET['mode'];
if(!$mode)$mode=hit;
if($mode=="hit"){
$dt=get_count("stat/hit/".date('d-m').".hit");
$dty=get_count("stat/hit/".yesterday().".hit");
}
а если посетителей - то делаем то же самое, только читаем другие файлы:
if($mode=="host"){
$dt=get_count("stat/hst/".date('d-m').".hst");
$dty=get_count("stat/hst/".yesterday().".hst");
}
и передаем функции построения графика все необходимые значения:
$pic=picture($dt,$dty,$h);
Формируем меню режима вывода, переменную вывода нарисованной картинки и завершаем скрипт:
$mnu="<center><a href='stat.php?mode=hit'>ПРОСМОТРЫ</a>
<a href='stat.php?mode=host'>ПОСЕТИТЕЛИ</a>";
$out= "<img src=".date('d-m').".jpg >";
?>
Важный момент: в меню ссылки на сам файл скрипта, его название в этом примере stat.php. Название может быть любым, расширение - только таким. Если меняем название файла, то меряем и адреса ссылок в меню. Дальше HTML-блок с вкраплениями PHP-кода:
<HTML>
<head>
</head>
<body>
<?echo $mnu."<BR><BR>".$out?>
</body>
</HTML>
Вот и все. Для просмотра статистики в некоторых обозревателях необходимо обновить страницу после выбора соответствующего пункта меню. Шрифты для работы скрипта (скачиваем) - fontc и arial. Теперь - о зашите от автоматических регистраций и спама.
1