Navigace

Hlavní menu

 

Submenu

 

Statistika přístupů v PHP – počet unikátních návštěvníků

Tímto článkem začínáme seriál, v jehož průběhu si postupně ukážeme, jak vytvořit rozsáhlou statistiku přístupů, která bude zjišťovat a vyhodnocovat mnoho důležitých údajů o návštěvnících webových stránek. Kromě klasických informací, jako je počet unikátních návštěvníků a IP adres, budeme zjišťovat i typy prohlížečů a operačních systémů, vyhledávací fráze, regionální polohu a další.

Dnes si kromě nutného úvodu povíme, jak zjistit počet unikátních návštěvníků za den.

Hotovou aplikaci si lze jako obvykle prohlédnout a vyzkoušet. V této ukázkové verzi se provádí statistika přístupů stránek www.czechia.cz/help.

Hned na úvod se nabízí otázka: "Potřebují naše stránky vůbec nějakou statistiku přístupů?" Technické informace zahrnující statistiku prohlížečů a rozlišení se mohou hodit tvůrcům stránek, kteří tak mají alespoň základní přehled o tom, jaké počítače a software používají návštěvníci stránek. Ostatní informace, jako je regionální lokalizace, nejvíce a nejméně prohlížené stránky, vyhledávací fráze a podobně, se dají využít v oblasti marketingu, kde mohou pomoci při prodeji reklamy a při dalším vývoji stránek.

Nyní podrobněji rozeberu, co vše bude tato statistika přístupů zjišťovat a vyhodnocovat. Kromě zmíněného počtu unikátních návštěvníků a unikátních IP adres to bude samozřejmě i celkový počet shlédnutých stránek. Dále se bude určovat návštěvnost v hodinách (0 - 23) a dnech (Pondělí - Neděle) a podíl jednotlivých typů prohlížečů, operačních systémů, rozlišení obrazovky a barevné hloubky. Budeme zjišťovat, ze kterých stránek návštěvníci přicházejí a jaké fráze používají ve vyhledávačích (Seznam, Google a další). Na základě doménové adresy budeme moci zjistit, které jsou nejčastější domény nejvyšší úrovně a v kterém kraji a městě se návštěvník nachází. Struktura celé aplikace však umožňuje přidat i další funkce, záleží tedy jen na nás.

Celá aplikace se skládá pouze z několika souborů - counter.php (počítá přístupy, zjišťuje údaje, zapisuje do databáze), stat.php (vyhodnocuje údaje uložené v databázi), db.php (zajišťuje připojení k databázi) a calendar.php (kalendář). Aplikace samozřejmě využívá databázi, kterou tvoří celkem 13 tabulek, což znázorňuje následující schéma (kliknutím lze zvětšit):

DB schéma - kliknutím zvětšíte

Tabulka access

Ze schématu vyplývá, že nejdůležitější je tabulka access, kam se ukládá každý přístup na naše stránky. Tabulku access, která má celkem 13 položek, vytvoříme pomocí následujícího SQL příkazu:

CREATE TABLE access (
     id int NOT NULL AUTO_INCREMENT,
     access_date datetime,
     visit int,
     browser int,
     os int,
     resolution int,
     colordepth int,
     referer int,
     path int,
     area int,
     ip varchar(25),
     ip_name varchar(60),
     domain int,
     PRIMARY KEY (id)
);

  • id – unikátní označení každého přístupu (primární klíč)
  • access_date – datum a čas přístupu ve formátu RRRR–MM–DD HH:MM:SS
  • visit – jedná se o visit (unikátní návštěvník / den) nebo ne
  • browser – prohlížeč
  • os – operační systém
  • resolution – rozlišení obrazovky
  • colordepth – barevná hloubka
  • referer – stránka, ze které návštěvník přišel
  • path – stránka, kterou si návštěvník prohlédl
  • area – oblast (město, kraj, VŠ), ze které je návštěvník
  • ip – IP adresa počítače
  • ip_name – doménová adresa počítače
  • domain – doména nejvyšší úrovně

V položkách jako jsou browser, os nebo resolution nebudeme uvádět konkrétní údaj, ale pouze označení daného údaje v související tabulce, což dobře znázorňuje databázové schéma. O tom všem budou další díly tohoto seriálu.

Připojení k databázi

K databázi se připojíme pomocí souboru db.php.

<?
$server_name = "localhost"; // jméno databázového serveru
$db_user = "";                     // uživatel
$db_pass = "";                     // heslo
$db_name = "counter";        // jméno databáze

MySQL_Connect($server_name, $db_user, $db_pass) or die('Nepodařilo se připojit k MySQL databázi'); // připojení k databázi
MySQL_Select_DB($db_name) or die('Nepodařila se otevřít databáze.'); // výběr databáze
?>

Datum a unikátní návštěvník za den

V dnešním dílu si představíme první 3 položky z tabulky access. Položka id obsahuje unikátní označení každého přístupu, což zajišťuje příkaz AUTO_INCREMENT a je tedy primárním klíčem celé tabulky. Položka access_date obsahuje datum a čas přístupu ve formátu RRRR-MM-DD HH:MM:SS. Úvodní část souboru counter.php tedy vypadá takto:

// zabráníme cashování
Header("Cache-Control: no-cache");
Header("Pragma: no-cache");
Header("Expires: ".GMDate("D, d M Y H:i:s")." GMT");

// připojení k databázi
require("db.php");

// DATUM
$date = Date("Y-m-d H:i:s"); // aktuální datum a čas

Třetí položka visit určuje, zda se jedná o visit nebo ne. Za visit přitom považujeme vstup návštěvníka na naše stránky, přičemž se nemusí nutně jednat o úvodní stránku. Každý návštěvník však může za den vytvořit pouze jeden visit. Vůbec tedy nezáleží na tom, jestli si prohlédne 15 stránek nebo pouze 3. Sečteme-li všechny visits v určitý den, dostaneme počet unikátních návštěvníků za tento den.

Teoreticky to vypadá celkem jednoduše, ale v praxi se tato veličina měří velmi těžko. Nemůžeme totiž využít IP adres, protože jedna IP adresa může představovat i několik desítek či stovek uživatelů internetu a naopak jeden uživatel se může skrývat pod několika IP adresami. Jediným způsobem, jak od sebe odlišit jednotlivé uživatele, je proto použití cookies. I to však má své mouchy. Někteří uživatelé si totiž podporu cookies vypínají. Další problém může nastat, pokud počítadlo vkládáme jako obrázek z cizích stránek, stále častěji se stává, že takováto "cookie třetí strany" je filtrována. Navíc na jednom počítači může pracovat několik lidí. Z toho vidíme, že určit přesně počet unikátních návštěvníků za nějaké časové období (v našem případě den), je záležitost velmi komplikovaná, takřka nemožná.

Náš skript bude měřit počet unikátních návštěvníků za den kombinací cookies a IP adres. Nejprve uložíme cookie s názvem visit, která bude platit pouze dnes. Toho docílíme použitím známé funkce MkTime() vracející počet sekund od 1. 1. 1970 až do zadaného období. Jako čtvrtý parametr funkce SetCookie() musíme uvést "/" - cookie bude poté platná pro všechny dokumenty v rámci domény.

// VISIT - unikátní návštěvník/den
SetCookie("visit", "PAGEVIEW", MkTime(23,59,59, Date("m"), Date("d"), Date("Y")), "/"); // cookie platí pouze dnes

V další části zjistíme, zda cookie existuje. Pokud ano, o visit se nejedná ($visit = 0). V opačném případě musíme zjistit, zda uživatel s danou IP adresou ($ip) přistoupil na stránky v posledních 20 minutách. K tomu použijeme dvě databázové funkce DATE_ADD(datum, období) a NOW(). DATE_ADD umožňuje přičíst k datu určité období. My k datu přístupu (access_date) přičteme oněch 20 minut a porovnáme s aktuálním datem a časem, tuto hodnotu vrací funkce NOW(). Pokud v databázi existuje alespoň jeden takový záznam, znamená to, že uživatel s danou IP adresou přistoupil před časovým úsekem kratším než 20 minut a tudíž se nejedná o visit. V opačném případě se jedná o visit ($visit = 1).

Ani tato metoda však bohužel neurčí přesně počet unikátních návštěvníků za den. Může se stát, že na stránkách se současně pohybuje několik uživatelů se stejnou IP adresou, kteří mají vypnuté cookies – bude započítán pouze jeden visit. Naopak uživatel s vypnutými cookies může v průběhu dne navštívit stránky třeba 5x a vytvořit tak 5 visits.

// IP ADRESA
if(IsSet($HTTP_X_FORWARDED_FOR)):
     $explode_ip = Explode(",", $HTTP_X_FORWARDED_FOR);
    $ip = $explode_ip[0];
else:
    $ip = $REMOTE_ADDR;
endif;

// pokud cookie existuje, nejedná se o visit
// v opačném případě zjistíme, zda daná IP adresa přistoupila v posledních 20 minutách (pokud ne, jedná se o visit)
if(IsSet($visit)):
     $visit = 0;
else:
     $query = MySQL_Query("SELECT access_date FROM access WHERE ip = '$ip' AND DATE_ADD(access_date, INTERVAL 20 MINUTE) > NOW() LIMIT 0,1");
     if($result = MySQL_Fetch_Array($query))
          $visit = 0;
     else
          $visit = 1;
endif;

Poznámka: Postup, kterým zjišťujeme IP adresu, bude popsán v některém z dalších dílů týkajícím se domén.

Souhrnná statistika

Nyní si představíme úvodní část souboru stat.php, který provádí vyhodnocení získaných údajů. Nejprve musíme deaktivovat časový limit na provedení skriptu, protože výpočet všech statistik může někdy trvat delší dobu.

<?
// zabráníme cashování
Header("Cache-Control: no-cache");
Header("Pragma: no-cache");
Header("Expires: ".GMDate("D, d M Y H:i:s")." GMT");
Set_Time_Limit(0); // deaktivuje časový limit na provedení skriptu
?>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1250">
<link href="style.css" rel="stylesheet" type="text/css">
<title>Statistika přístupů ver 1.0</title>
</head>

Součástí statistiky je i možnost zvolit si na kalendáři období, pro které se zpracuje. O vytvoření kalendáře bude některý z dalších dílů. Pokud nebylo na kalendáři zvoleno datum, vložíme do proměnných $from_date (datum OD) a $to_date (datum DO) standardní hodnoty, tj dnešní datum. Do proměnných $sql_access_date a $sql_search_date poté vložíme podmínku omezující výběr záznamů z databáze pouze na dané období.

require("db.php"); // připojení k databázi
require("calendar.php"); // kalendář

// standardní hodnoty proměnných
if(!IsSet($from_date)) $from_date = Date("Y-m-d");
if(!IsSet($to_date)) $to_date = Date("Y-m-d");

// omezení statistiky na určité období
$sql_access_date = "access_date >= '$from_date' AND access_date <= '$to_date 23:59:59'";
$sql_search_date = "search_date >= '$from_date' AND search_date <= '$to_date 23:59:59'";

Nyní tedy můžeme získat hodnoty základních statistických veličin za dané období. Jedná se o pageviews (počet shlédnutých stránek), visits (součet denních visits za dané období), počet unikátních IP adres (UIP) a poslední přístup. SQL dotazy jsou vcelku jednoduché. Za zmínku stojí snad jen použití agregačních funkcí count() a max() vracejících počet záznamů, respektive maximální hodnotu v určitém sloupci. Pro někoho je možná neznámý i modifikátor DISTINCT - při jeho použití se z databáze vyberou jen unikátní záznamy, v našem případě unikátní IP adresy.

// PAGEVIEWS - shlédnuté stránky
$query = MySQL_Query("SELECT count(*) FROM access WHERE $sql_access_date");
$result = MySQL_Fetch_Array($query);
$pageviews = $result["count(*)"];

// VISITS - součet denních visits za dané období
$query = MySQL_Query("SELECT count(*) FROM access WHERE visit = 1 AND $sql_access_date");
$result = MySQL_Fetch_Array($query);
$visits = $result["count(*)"];

// UNIKÁTNÍ IP
$query = MySQL_Query("SELECT DISTINCT ip FROM access WHERE $sql_access_date");
$unique_ip = MySQL_Num_Rows($query);

// POSLEDNÍ PŘÍSTUP
$query = MySQL_Query("SELECT max(access_date) AS maxdate FROM access WHERE $sql_access_date");
$result = MySQL_Fetch_Array($query);
$maxdate = $result["maxdate"];

V databázi je datum a čas uložen ve formátu RRRR-MM-DD HH:MM:SS. U nás je zvykem psát datum ve formátu DD. MM. RRRR HH:MM:SS. Převod provedeme tak, že řetězec nejprve rozdělíme na dvě části – datum a čas, které jsou odděleny mezerou. Poté rozdělíme na jednotlivé části ještě datum a na závěr poskládáme vše dohromady. Některé řetězce ještě přetypujeme na čísla pomocí příkazu (int), čímž se zbavíme počátečních nul.

// převod na český zápis data
$explode1 = Explode(" ", $maxdate);
$explode2 = Explode("-", $explode1[0]);
$maxdatecz = (int)$explode2[2] . ". " . (int)$explode2[1] . ". " . $explode2[0] . " " . $explode1[1];

Nad celou statistikou uvedeme období, pro které byla statistika vypracována:

$from = Explode("-", $from_date); // od
$to = Explode("-", $to_date); // do
$period = (int)$from[2] . ". " . (int)$from[1] . ". " . $from[0] . " - " . (int)$to[2] . ". " . (int)$to[1] . ". " . $to[0];

echo '<p align="center" class="heading">Období: ' . $period . '</p>';

Získané hodnoty zapíšeme do tabulky:

<p align="center" class="heading">Souhrnné statistiky</p>
<table cellspacing="0" align="center">
 <tr><td>Pageviews</td><td><?echo $pageviews;?></td></tr>
 <tr><td>Visits</td><td><?echo $visits;?></td></tr>
 <tr><td>Unikátních IP</td><td><?echo $unique_ip;?></td></tr>
 <tr><td>Poslední přístup</td><td><?echo $maxdatecz;?></td></tr>
</table>
<br>

Tím úvodní díl končí. Příště si povíme, jak provést detekci prohlížeče.

Kebrt, Michal (13.5. 2002)
Diskuze: Statistika přístupů v PHP – počet unikátních návšt ...
2002-05-13 00:12:42Premysl HeroldTrochu kazi dojem...
2002-05-13 08:52:56Vilem MalekTrochu kazi dojem...
2002-05-13 14:19:30Premysl HeroldTrochu kazi dojem...
2002-05-13 15:58:50Marek ŠalandaTrochu kazi dojem...
2002-05-13 09:21:12Marek ŠalandaTrochu kazi dojem...
2002-05-17 20:18:07AdmiXTak co je s dalším dílem?
2002-05-22 17:16:33Petr Hlaváček...už se taky těším na další díl
2002-05-22 17:19:03Marek Šalanda...už se taky těším na další díl
2002-09-22 17:02:24Tomáš VondraTrochu vylepšit ty SQL dotazy...
2003-02-10 14:16:54patrickOpravdu nepochopitelné
2003-02-10 19:05:41Michal KebrtOpravdu nepochopitelné