12. díl - Objektové počítadlo návštěv v PHP a PDO

PHP Objektově orientované programování Objektové počítadlo návštěv v PHP a PDO American English version English version

V minulém tutoriálu o objektově orientovaném programování v PHP jsme dokončili statiku. Na dnešek máme slíbený opět nějaký reálný příklad. Půjde o objektovou práci s databází pomocí ovladače PDO, se kterým se v tomto dílu seznámíme.

Původně jsem chtěl vytvořit anketu, ale ta již je vysvětlená v tutoriálu se začátky PHP a jistě byste si ji do objektů dokázali převést. Dnes si tedy zkusíme naprogramovat webové počítadlo návštěv.

Metodika počítání přístupů

Při počítání návštěv webu se většinou rozlišuje mezi třemi termíny:

  1. Zobrazení - Počet všech zobrazení webu. Započítá se při každém přístupu. Pokud tedy nějaký uživatel zobrazí na webu 10 stránek za hodinu, připočte se 10 zobrazení.
  2. Návštěva - Návštěvník se započítá jen jednou asi za 30 minut. Pokud si tedy za hodinu 1 uživatel přečte 10 článků, bere se to jako že web 2x navštívil.
  3. UIP - Unikátní návštěvníci, přesněji počet unikátních IP adres za určité období. Pokud si uživatel přečte za měsíc 1000 článků, bere se to jen jako 1 unikátní zobrazení.

Zobrazení jsou samozřejmě nejvyšší a UIP nejnižší. UIP mají nejvyšší vypovídací hodnotu. Návštěvy jsou něco mezi a v našem případě je ukládat nebudeme, jelikož je není úplně jednoduché rozlišit. Budeme ukládat pouze zobrazení stránek a počet UIP z nich později jednoduše zjistíme tak, že si vybereme jen unikátní zobrazení za určitý časový úsek.

Databáze

Zobrazení tedy budeme ukládat do databáze. Při každém zobrazení stránky na našem webu vložíme do databáze řádek s aktuálním datem a IP adresou návštěvníka. Daly by se ukládat i další věci, jako prohlížeč nebo jazyk, ale to zanedbáme.

U hodně navštěvovaných webů se návštěvnost neukládá do databáze při každém zobrazení stránky, jelikož by to databázi příliš zatěžovalo. Zobrazení se logují do textového souboru a za nějaký čas se spustí skript, který je ze souboru uloží do databáze. K DB tedy není přistupováno tak často a zátěž je nižší. V našem případě toto můžeme určitě zanedbat a budeme ukládat zobrazení rovnou do databáze.

Zakládací skripty

Vytvořme si databázovou tabulku zobrazeni, která bude mít 3 sloupce:

  • zobrazeni_id (int, AI, primární klíč)
  • ip (varchar 40)
  • datum (int)

Datum a čas zde uložíme jako celé číslo. Je to druhá alternativa oproti databázovému typu DATETIME. Já osobně ji používám více, tak si alespoň zkusíme zas něco jiného. Datum uložíme jako počet vteřin od roku 1970. Dělá se to tak často a rok 1970 není náhodný, jedná se o začátek Unixové epochy. PHP na to má samozřejmě funkce.

Tabulku si klidně naklikejte v PHPMyAdmin:

MySQL tabulka pro počítadlo návštěv

Případně zde máte zakládací skripty:

CREATE TABLE IF NOT EXISTS `zobrazeni` (
  `zobrazeni_id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` varchar(40) COLLATE utf8_czech_ci NOT NULL,
  `datum` int(11) NOT NULL,
  PRIMARY KEY (`zobrazeni_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=1 ;

Databázi máme připravenou.

První seznámení s PDO

Minule jsme si vysvětlili, že se v PHP pro práci s databází používá téměř výhradně objektový ovladač PDO. PDO je třída, která je součástí jazyka PHP. Ukažme si, jak by vypadalo připojení se k databázi a vložení nového řádku do tabulky zobrazeni pomocí tohoto ovladače.

Připojení

Vytvoříme si úplně nový projekt (novou složku, třeba s názvem pocitadlo) a dovnitř umístíme index.php. Do indexu vložíme následující řádky:

<?php

$nastaveni = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
);

$spojeni = new PDO("mysql:host=localhost;dbname=pocitadlo_db", 'root', '', $nastaveni);

Nejprve si vytvoříme pole s nastavením pro PDO. První klíč je způsob, jakým chceme, aby byly zpracovávány chyby. Zvolili jsme výjimky (exceptions), k těm se dostaneme dále v seriálu. Ten druhý určuje, že nechceme, aby PDO emulovalo prepared statements pro starší verze MySQL, které ho nepodporovaly. Bez tohoto nastavení bychom nemohli používat např. parametry v klauzuli LIMIT. Třetí klíč je inicializační příkaz pro databázi, zde chceme nastavit kódování na UTF-8.

Klíčové je vytvoření spojení, což provedeme jako vytvoření instance PDO. První parametr konstruktoru PDO je řetězec obsahující připojovací údaje. Prvním je host (localhost), druhým název databáze (u mně pocitadlo_db). Další 2 parametry konstruktoru jsou uživatelské jméno (u mne root) a heslo (u mne prázdné). Jako poslední parametr předáme naše nastavení. Pokud vám to po zapsání tohoto řádku nevypsalo žádnou chybu, jste úspěšně připojení k DB. Pokud ne, opravte si připojovací údaje.

Dotazy

Jakmile máme instanci PDO spojení, můžeme na ni volat databázové dotazy. Na rozdíl od zastaralých ovladačů podporuje PDO tzv. prepared statements. Jedná se o oddělení vkládání samotného dotazu a parametrů do tohoto dotazu. Jelikož je dotaz od svých parametrů oddělený, nemůže dojít k SQL injekci. Databáze si přijaté parametry sama ošetřuje. V minulosti se v PHP pro podobnou ochranu používaly funkce jako mysql_real_es­cape_string(), na které už můžete zapomenout :)

Připišme do index.php další řádky:

$dotaz = $spojeni->prepare('INSERT INTO `zobrazeni` (`ip`, `datum`) VALUES (?, ?)');
$parametry = array($_SERVER['REMOTE_ADDR'], time());
$dotaz->execute($parametry);

Kód si popišme. Nejprve si vytvoříme instanci dotazu. Tu nám vrátí metoda prepare() na instanci PDO spojení. Do parametru metody napíšeme normálně SQL dotaz jako textový řetězec. Namísto parametrů dotazu však vložíme otazníky. Nikdy nebudeme vkládat proměnné nebo hodnoty přímo do dotazu! Jedná se o bezpečnostní riziko.

Parametry potom vložíme do nového pole v tom pořadí, v jakém jsou otazníky v dotazu. $_SERVER['REMO­TE_ADDR'] obsahuje IP adresu (na lokálním počítači budete mít dost možná hodnotu :1 nebo něco podobného). Funkce time() vrátí aktuální čas jako UNIX timestamp (počet sekund od 1.1.1970).

Vytvořený dotaz nakonec spustíme metodou execute(), které předáme pole s parametry, které se do dotazu mají vložit. Zkuste index.php navštívit a podívat se do tabulky, bude tam nový řádek.

POZOR! Pokud máte v PHP zapnuté chybové hlášky a máte nějakou chybu v dotazu, vypíše se chybová zpráva. Ovladač PDO vyhazuje při chybách výjimky (což je správně) a jelikož se ty vypisují spolu se stopou stacku, mohou zobrazit spolu s částí kódu i vaše heslo k databázi! Je velmi důležité, abyste o tom věděli a měli vypnuté chyby na produkčním serveru (kde samozřejmě vypnuté být mají).

To by bylo pro dnešek vše, příště budeme v počítadle pokračovat a vytvoříme si objekt, který bude návštěvy zaznamenávat, analyzovat a vypisovat. Dnešní zdrojový kód včetně exportu DB je jako vždy připojen pod článkem ke stažení.


 

Stáhnout

Staženo 525x (1.81 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

  Aktivity (3)

Článek pro vás napsal David Čápka
Avatar
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (14 hlasů) :
55555


 



 

 

Komentáře

Avatar
domino.turak
Člen
Avatar
domino.turak:

Viem že je ešte skoro nad touto otázkou rozmýšľať, ale čo sa stane 19.januára 2038 keď to 32-bitové číslo so znamienkom pretečie? To budú akože všetky databázy opravovať alebo ako to bude riešené neviete náhodou? Iba tak ma to zaujíma, ináč skvelý seriál :-) .

Odpovědět  +4 10.6.2014 20:41
"Never give up!"
Avatar
tomass
Člen
Avatar
tomass:

Mohl bych se zeptat, co přesně dělá ten operátor => u tohoto příkazu ?
PDO::ATTR_ERRMODE => PDO::ERRMODE_EX­CEPTION,

Chápu, že PDO::ATTR_ERRMODE je volání statické metody z třídy PDO stejně tak ERRMODE_EXEPCTION tan oprátor slouží jako nějaké volání metody, nebo nějaký ukazatel? Díky.;)

 
Odpovědět 4.12.2014 20:00
Avatar
tomass
Člen
Avatar
Odpovídá na tomass
tomass:

Omlouvám se, ono je to asociativní pole, nějak mi to v první chvíli nedošlo :[.

 
Odpovědět 4.12.2014 20:04
Avatar
Odpovídá na domino.turak
Michal Žůrek (misaz):

buď to vrátí chybu, nebo to přeteče na rok 1970. každopádně nemusíš se bát, do té doby se něco vymyslí a vyjde update MySQL.

Odpovědět  +2 8.2.2015 10:19
Nesnáším {}, proto se jim vyhýbám.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 4 zpráv z 4.