Cookies: koláčky jako zákusek

Dnes nás čeká poslední díl seriálu, jehož cílem bylo seznámit vás se základy tvorby internetových aplikací na str...


Dnes nás čeká poslední díl seriálu, jehož cílem bylo seznámit vás se základy
tvorby internetových aplikací na straně serveru. Na závěr se budeme věnovat
koláčkům v originále cookies což je velice zajímavá technologie, která dala
název i dnešnímu článku.
Vlastnosti protokolu HTTP
Zopakujme si nejprve stručně, na jakém principu cookies pracují. Samotný
protokol HTTP je bezstavový pro stažení každé stránky se musí vytvořit nové
spojení, po kterém se obsah stránky přenese. Server tedy neví, zda danou
stránku posílá podesáté jednomu uživateli anebo zda stránku desetkrát poskytl
různým uživatelům. Přitom na mnoha stránkách by šlo tuto informaci využít.
Server by monitoroval pohyb uživatele po stránkách a na základě jeho
vyhodnocení by uživateli poskytoval personalizované stránky např. se
specifickou reklamou či informacemi.
Výše zmíněného nedostatku si byla vědoma firma Netscape a vytvořila proto
cookies, které brzy začaly podporovat i všechny další významné firmy ve svých
prohlížečích. Cookies jsou rozšířením protokolu HTTP přidávají do něj dvě nové
hlavičky.
První hlavičku Set-Cookie používá server při odesílání odpovědi prohlížeči. V
této hlavičce může server prohlížeči poslat informace. Získané informace si
prohlížeč uloží do souboru. Pokud pak uživatel v budoucnu přistupuje ke
stejnému serveru, prohlížeč uložené informace pošle zpět serveru v hlavičce
Cookie. Server na základě obdržených informací v cookies zjistí, že uživatel se
k serveru připojil již dříve a může na to patřičně zareagovat.
Každá cookie má své jméno a můžeme do ní uložit hodnotu. Kromě toho lze u každé
cookie nastavit dobu její platnosti a další atributy.
Cookies v PHP
Práce s cookies je v PHP velice snadná. K odeslání cookie klientovi slouží
funkce SetCookie(). Tuto funkci musíme volat ještě předtím, než náš skript
generuje nějaký výstup v HTML, protože cookies jsou součástí HTTP-hlaviček.
Naopak cookies, které v požadavku na náš skript odeslal prohlížeč, máme
přístupné v proměnných odpovídajícího jména, podobně jako pole formuláře.
Použití cookies si ukážeme na jednoduchém příkladě vytvoříme stránku, která
každému uživateli zobrazí, kolikrát ji navštívil:
<? if (!IsSet($pocetPristupu)) $pocetPristupu = 0; $pocetPristupu++;
SetCookie("pocetPristupu", $pocetPristupu);
?>
<HTML>
<HEAD>
<TITLE>Vítejte na serveru s podporou koláčků
</TITLE>
</HEAD>
<BODY>
<? if ($pocetPristupu==1):
?> <H1>Vítejte nový uživateli</H1>
<?else:?> <H1>Ahoj starý brachu my už se známe</H1> Na našem serveru jste již
po <?echo $pocet
Pristupu?>.
<?endif?>
</BODY>
</HTML>
Skript nejprve testuje, zda mu prohlížeč poslal cookie s názvem pocetPristupu.
Pokud ne, zinicializuje proměnnou $pocetPristupu. Následně počet přístupů
zaktualizujeme a odešleme zpět klientovi. Zobrazená stránka se liší podle toho,
zda uživatel ke stránce přistupuje poprvé nebo již poněkolikáté (viz obr. 1 a
2).
Funkce SetCookie má i několik nepovinných parametrů. Celkem můžeme použít šest
následujících parametrů:
SetCookie(jméno, hodnota, platnost, cesta, doména, zabezpečení)
Platnost udává časový okamžik, do kdy je obsah cookie platný. Čas se udává jako
počet sekund od začátku 1. ledna 1970. S výhodou můžeme použít funkci Time(),
který vrací aktuální čas v tomto formátu. K nastavení cookie s platností jedna
hodina (3 600 s) můžeme použít volání:
SetCookie("Kategorie", "obchod", Time()+3600)
Pomocí parametrů cesta a doména můžeme rozšířit platnost cookie. Normálně je
cookie platná je zasílána prohlížečem zpět serveru pouze pokud se shoduje
doména a úvodní část cesty ke skriptu, který cookie odeslal prohlížeči. Pokud
chceme rozšířit platnost cookie na celý server, použijeme jako parametr cesta
lomítko "/". Pomocí parametru doména můžeme rozšířit platnost cookie na celou
doménu. Pokud jako hodnotu uvedeme např. "firma.cz", bude cookie platná pro
všechny servery v doméně firma.cz.
Pokud jako hodnotu posledního parametru zabezpečení uvedeme true, bude cookie
zaslána pouze, pokud je mezi serverem a klientem vytvořeno bezpečné spojení
pomocí SSL (Secure Socket Layer).
Cookies můžeme z prohlížeče smazat dvěma způsoby buď jako hodnotu cookie
pošleme prázdný řetězec, nebo platnost cookie nastavíme do minulosti. V obou
dvou případech je nepotřebná cookie odstraněna z prohlížeče a nezabírá zbytečné
místo na disku uživatele.
Další příklady použití
Použití cookies si nyní ukážeme na složitějším příkladě. Naším úkolem bude
vytvořit server, který si od každého uživatele při vstupu na hlavní stránku
vyžádá zodpovězení jedné z otázek. Otázka bude pro uživatele vybrána náhodně,
ale zároveň bychom jednomu uživateli neměli vícekrát pokládat tutéž otázku.
Budeme dále předpokládat, že jednotlivé otázky máme uloženy v databázové
tabulce Dotaznik. U každé otázky máme uloženo její identifikační číslo, znění a
počet hlasů pro a proti.
V řešení našeho úkolu nám výborně pomohou cookies, protože právě pomocí nich si
budeme u každého uživatele evidovat, na které otázky již odpověděl. Z databáze
při přihlášení k serveru vybereme vždy dosud nepokládanou otázku to zamezí
zbytečnému zkreslení výsledků tím, že někdo vícekrát odpoví na jednu otázku.
Protože pro každého uživatele potřebujeme evidovat větší počet zodpovězených
otázek, využijeme toho, že více cookies může mít stejné jméno a různou hodnotu
v PHP s nimi pak pracujeme jako s polem. My si cookie pojmenujeme
zodpovezeneDotazy. Následující skript z tabulky náhodně vybere jeden dosud
nepoložený dotaz a zobrazí jej:
<HTML>
<HEAD>
<TITLE>NÁZORY.CZ</TITLE>
</HEAD>
<BODY>
<? $sql = "select * from Dotaznik"; if (IsSet($zodpovezeneDotazy)) $sql .= "
where ID not in (". Implode($zodpovezeneDotazy, ","). ")"; do {
MySQL_Connect("localhost"); $vysledek = MySQL("test", $sql); $pocet =
MySQL_NumRows($vysledek); if ($pocet==0) break; SRand((double)MicroTime()*1e6);
$aktualni = Rand() % $pocet; $id = MySQL_Result($vysledek, $aktualni, "ID");
$dotaz = MySQL_Result($vysledek, $aktualni, "Otazka"); } while (false); if
(IsSet($id)): ?> <H1>Pro vstup na server odpovězte na následující
otázku:</H1> <FORM ACTION="17-03.php3"> <?echo $dotaz?><BR><BR> <INPUT
TYPE=Submit NAME=Odpoved VALUE="Ano"> <INPUT TYPE=Submit NAME=Odpoved
VALUE="Ne"> <INPUT TYPE=Hidden NAME=id VALUE="<?echo $id?>"> </FORM>
<?else:?> <H1>Dnes to bude bez otázky</H1> <A HREF="17-03.php3">Vstupte na náš
server</A>
<?endif?>
</BODY>
</HTML>
Pochopení skriptu nechám na laskavém čtenáři, zmíním se jen o několika funkcích
PHP, se kterými jsme se dosud nesetkali. Funkce IsSet() zjišťuje, zda daná
proměnná obsahuje nějakou hodnotu. Funkce Implode() vezme jednotlivé prvky pole
a navzájem je spojí do jednoho řetězce k oddělení prvků pole v řetězci se
používá znak předaný jako druhý parametr. Voláním Implode($zodpovezeneDotazy,
",") tedy získáme seznam identifikačních čísel již zodpovězených dotazů, který
s výhodou použijeme při zadávání SQL dotazu, který vybírá pouze dosud
nepoložené otázky.
Příkaz SRand((double)MicroTime()*1e6) zinicializuje generátor náhodných čísel.
Funkce Rand() vrací náhodné číslo. Použitím operátoru modulo (zbytek po dělení)
upravíme náhodné číslo na potřebný rozsah.
Nyní nadešel pravý čas pro skript, který zpracuje odpověď uživatele. Skript
18-03.php3 má na starosti mnoho věcí předně musí klientovi odeslat cookie,
která obsahuje číslo zodpovězené otázky. Poté musí v databázi aktualizovat
počet odpovědí pro/ /proti u dané otázky. Nakonec skript vypíše přehled
odpovědí na všechny otázky, abychom měli přehled.
Podívejte se tedy na poslední skript našeho seriálu.
<? if(IsSet($id)) SetCookie("zodpovezene
Dotazy[$id]", $id,
Time()+2592000);
?>
<HTML>
<HEAD>
<TITLE>NÁZORY.CZ</TITLE>
</HEAD>
<BODY>
<H1>Výsledky hlasování pro
všechny dotazy</H1>
<TABLE CELLSPACING=0
BGCOLOR=BLACK>
<TR BGCOLOR=YELLOW><TH>Otázka<TH
WIDTH=120>Ano<TH
WIDTH=120>Ne</TR>
<? MySQL_Connect("localhost"); $sql = "update Dotaznik"; if ($Odpoved=="Ano")
$sql .= " set Ano = Ano +
1"; else $sql .= " set Ne = Ne +
1"; $sql .= " where ID = $id"; $vysledek = MySQL("test",
$sql); if (!$vysledek) echo "Nepodařilo se
zapsat vaši odpověď."; $sql = "select * from Dotaznik order by Otazka";
$vysledek = MySQL("test",
$sql); $pocet = MySQL_NumRows
$vysledek); define("SirkaGrafu", 100); for ($i=0; $i<$pocet;
$i++): $ano = MySQL_Result($vysledek, $i,
"Ano"); $ne = MySQL_Result($vysledek, $i,
"Ne"); echo "<TR><TD COLSPAN=3></TR>". "<TR VALIGN=TOP BGCOLOR='#FFFF80'><TD>".
MySQL_Result($vysledek,
$i, "Otazka"). "<TD ALIGN=RIGHT>$ano&nbsp;". ($ano ? "<IMG SRC=bluedot.gif
WIDTH=". Round(SirkaGrafu/($ano+$ne)*$
ano). " HEIGHT=10>" : ""). "<TD ALIGN=LEFT>". ($ne ? "<IMG SRC=reddot.gif
WIDTH=".
Round(SirkaGrafu/($ano+$ne)*$
ne). " HEIGHT=10>" : "")."&nbsp;$ne". "</TR>"; endfor;
?>
</TABLE>
</BODY>
</HTML>
U odesílané cookie jsme nastavili platnost na 30 dní nepředpokládáme, že jeden
dotaz bude na serveru delší dobu a je zbytečné, aby byl prohlížeč uživatele
zavalen nepotřebnými cookies. V hranatých závorkách za názvem cookie uvádíme
jedinečný index PHP nám následně umožní s cookie pracovat jako s polem (to
využíváme v prvním skriptu).
Při psaní aplikací nesmíme však na cookies spoléhat. U většiny prohlížečů lze
podporu cookies vypnout a někteří uživatelé to také dělají, protože se zcela
neoprávněně bojí úniku osobních informací. Profesionální aplikace by si měla
poradit i s touto situací a pracovat správně třebaže jen s omezeným
uživatelským komfortem.
8 2212 / pah









Komentáře
K tomuto článku není připojena žádná diskuze, nebo byla zakázána.