Állapotok tárolása sütikkel és GET típusú lekérdezésekkel

A HTTP állapot nélküli protokoll. Ez azt jelenti, hogy ahány oldalt a felhasználó
letölt kiszolgálónkról, annyi önálló kapcsolat létesül, ráadásul az egyes oldalakon
belül a képek, külsõ fájlok letöltésére is külön kapcsolatok nyílnak. Másrészt
viszont a felhasználók és a weboldalak készítõi környezetként, azaz olyan térként
érzékelik a weboldalakat, amelyben egyetlen oldal is egy nagyobb egész része.
Így viszont nem meglepõ, hogy az oldalról oldalra való információátadás módszerei
egyidõsek magával a Világhálóval.
Ezen az órán az információtárolás azon két módszerével fogunk megismerkedni,
amelyek lehetõvé teszik, hogy egy adott oldalon található adat a következõ oldalakon
is elérhetõ legyen. Az óra során a következõket tanuljuk meg:
• Mik a sütik és hogyan mûködnek?
• Hogyan olvassuk a sütiket?
• Hogyan írjunk sütiket?
• Hogyan tároljuk adatbázisban a weboldalak lekérési statisztikáját sütik segíts
égével?
• Mik azok a GET módú lekérések?
• Hogyan írjunk olyan függvényt, amely egy asszociatív tömböt egy lekérdezõ
karakterlánccá alakít át?
Sütik
A Netscape munkatársai által kiötölt „csodasüti” (magic cookie) kifejezés még
a Netscape 1 aranykorából származik. A kifejezés pontos eredete mindmáig viták
tárgya, bár meglehetõsen valószínûnek tûnik, hogy a szerencsesütinek valami
köze lehetett hozzá. Azóta viszont már más böngészõk is alkalmazzák
ezt a szabványt.
A süti (cookie) kis mennyiségû adat, amelyet a felhasználó böngészõje
tárol egy kiszolgáló vagy egy program kérésének eleget téve. Egy gép
legfeljebb 20 sütit tárolhat a felhasználó böngészõjében. Minden süti egy nevet,
egy értéket, a lejárati idõpontot és a gazdagépre és elérési útra vonatkozó inform
ációkat tartalmazza. Az egyes sütik mérete legfeljebb 4 KB lehet.
A süti értékeinek beállítása után csak az a számítógép olvashatja az adatokat,
amely azokat létrehozta, ezzel is garantálva a felhasználó biztonságát. A felhaszn
áló azt is beállíthatja böngészõjében, hogy az értesítse az egyes sütik létrehozá-
sának kérelmérõl, vagy elutasíthatja az összes sütikérelmet. Ezekbõl adódóan
a sütiket módjával kell használni, nem lehet teljesen rájuk támaszkodni a környezet
megtervezésekor anélkül, hogy a felhasználót elõször ne értesítenénk.
Mindezekkel együtt a sütik kiválóan alkalmasak arra, hogy kis mennyiségû inform
ációt tároljunk velük, mialatt a felhasználó oldalról-oldalra lépdel, vagy akár
hosszabb távon is, a webhely egyes látogatásai között.
A sütik felépítése
A sütik létrehozása általában a HTTP fejlécében történik (bár a JavaScript közvetlen
ül a böngészõvel is létre tudja hozni a sütiket). Egy sütibeállító PHP program
ilyesféle HTTP fejlécelemet kell, hogy létrehozzon:
Set-Cookie: zoldseg=articsoka; expires=Friday,
å 04-Feb-00 22:03:38 GMT; path=/; domain=kiskapu.hu
ÚJDONSÁG
362 19. óra
Mint ahogy azt láthatjuk, a Set-Cookie fejléc egy név–érték párt, egy greenwichi
középidõ szerinti lejárati idõpontot (expires), egy elérési utat (path) és egy tartom
ányt (domain) tartalmaz. A név és az érték URL felépítésû kell, hogy legyen. A lejá-
rat mezõ (expires) arra ad utasítást a böngészõnek, hogy mikor „felejtse el” a sütit.
Az elérési út a weboldalon azt a helyet jelöli, amelynek elérésekor a sütit vissza kell
küldeni a kiszolgálóra. A tartomány mezõ azokat az internetes tartományokat jelöli ki,
ahová a sütit el kell küldeni. A tartomány nem különbözhet attól, ahonnan a sütit
küldték, viszont egy bizonyos szintû rugalmasságot is meghatározhat. Az elõzõ péld
ánál a böngészõ a www.kiskapu.hu és a leeloo.kiskapu.hu kiszolgálóknak
egyaránt hajlandó elküldeni a sütit. A HTTP fejlécérõl a tizenharmadik óra anyagában
többet is olvashattunk.
Ha a böngészõ úgy van beállítva, hogy tárolja a sütiket, akkor az azokban tárolt
adatok a süti lejártáig elérhetõk maradnak. Ha a felhasználó a böngészõvel olyan
oldalra jut, amely egyezik a sütiben tárolt elérési útvonallal és tartománnyal, akkor
elküldi a sütit a kiszolgálónak. Ehhez általában az alábbihoz hasonló fejlécelemet
állít elõ:
Cookie: zoldseg=articsoka
Így aztán a PHP program hozzáférhet a sütihez a HTTP_COOKIE környezeti változ
ón keresztül (amely az összes süti nevét és értékét tárolja), de a $zoldseg
globális változón keresztül vagy a $HTTP_COOKIE_VARS[“zoldseg”] globális
tömbváltozó segítségével is elérhetjük azt:
print "$HTTP_COOKIE
"; // azt írja ki, hogy
å "zoldseg=articsoka"
print getenv("HTTP_COOKIE")."
"; // azt írja ki, hogy
å "zoldseg=articsoka"
print "$zoldseg
"; // azt írja ki, hogy "articsoka"
print "$HTTP_COOKIE_VARS["zoldseg"]
"; // azt írja ki, hogy
å "articsoka"
Sütik beállítása a PHP-vel
A PHP-vel kétféleképpen hozhatunk létre egy sütit. Egyrészt a kilencedik óra során
megismert header() függvény segítségével beállíthatjuk a fejléc Set-Cookie
sorát. A header() egy karakterláncot vár, amit az oldal HTTP fejlécébe ír. Mivel
a fejlécek automatikusan kerülnek kiírásra, a header() függvényt még azelõtt kell
meghívnunk, mielõtt bármi egyebet küldenénk a böngészõnek. Figyeljünk arra,
hogy a PHP blokk kezdõeleme elé írt egyetlen szóköz vagy újsor karakter is kimenetk
ént jelenik meg a böngészõben.
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 363
19
header ("Set_Cookie: zoldseg=articsoka; expires=Friday,
å 04-Feb-00 22:03:38 GMT; path=/; domain=kiskapu.hu");
Bár ez a módszer nem túl bonyolult, mégis írnunk kell egy olyan függvényt, amely
elõállítja a fejléc szövegét. Ez persze nem túl rázós feladat, hiszen csak a megfelelõ
formátumú dátumot, illetve az URL formátumú név–érték párt kell elõállítanunk.
Kár azonban ezzel veszõdnünk, mert létezik egy olyan PHP függvény, amely pontosan
ezt végzi el helyettünk.
A setcookie() függvény neve önmagáért beszél: a fejléc Set-Cookie sorát
állítja elõ. Ennek megfelelõen azelõtt kell még meghívnunk, mielõtt valamit kikülden
énk a böngészõnek. A függvény bemenetét a süti neve, értéke, UNIX idõbé-
lyeg formátumban megadott lejárata, elérési útja, a feljogosított tartomány, valamint
egy egész szám alkotja. Ezt a legutolsó paramétert 1-re állítva biztosíthatjuk,
hogy a süti csak biztonságos kapcsolaton keresztül tudjon közlekedni. A süti
nevén kívül egyik paraméter sem kötelezõ.
A 19.1. programban arra láthatunk példát, ahogy a setcookie() függvény segíts
égével beállítunk egy sütit.
19.1. program Süti értékének beállítása és kiíratása
1: 2: setcookie( "zoldseg", "articsoka", time()+3600, "/",
3: "kiskapu.hu", 0 );
4: ?>
5:
6:
7: 19.1. program Süti értékének beállítása és<br />kiíratása
8:
9:
10: 11: if ( isset( $zoldseg ) )
12: print "

Üdv, az ön által kiválasztott zöldség a(z)
$zoldseg

";
13: else
14: print "

Üdvözöljük! Ez az ön elsõ látogatása.

";
15: ?>
16:
17:
364 19. óra
Bár a program elsõ lefuttatásakor már beállítjuk a sütit, a $zoldseg változó ekkor
még nem jön létre. A süti csak akkor lesz hozzáférhetõ, amikor a böngészõ elküldi
azt a kiszolgálónak. Ez csak akkor következik be, ha a felhasználó újra meglátogatja
tartományunkat. A példában egy "zoldseg" nevû sütit hozunk létre, melynek
értéke "articsoka". A time() függvénnyel lekérdezzük a pillanatnyi idõt, majd
ebbõl 3600-at hozzáadva számítjuk ki a lejárat idejét. (A 3600 másodpercben értend
õ, tehát a süti 1 óra elteltével fog elavulni.) Útvonalként a "/"-t adjuk meg,
amibõl az következik, hogy sütink a webhely összes oldaláról elérhetõ lesz.
A tartományt "kiskapu.hu"-ra állítottuk, aminek következtében ennek a tartom
ánynak mindegyik kiszolgálója jogosult a süti fogadására (a www.kiskapu.hu
tehát ugyanúgy megkapja a sütit, mint a leeloo.kiskapu.hu). Ha azt szeretn
énk, hogy egy sütihez csak az a kiszolgáló férjen hozzá, amelyik a sütit létrehozó
programot szolgáltatta, használjuk a $SERVER_NAME környezeti változót, ahelyett,
hogy a tartomány, illetve kiszolgálónevet beépítenénk a programba. Ez a megoldás
azzal az elõnnyel is rendelkezik, hogy a programok módosítás nélkül átvihetõk egy
másik kiszolgálóra és ott is az elvárásoknak megfelelõen fognak futni. Végül egy
nullát is átadunk a setcookie()-nak, jelezvén, hogy a sütit nem biztonságos
kapcsolaton keresztül is el szabad küldeni. Bár az elsõ kivételével mindegyik param
éter elhagyható, hasznos, ha minden paramétert megadunk és csak a tartomány
és biztonság adatok meghatározásától tekintünk el. Erre azért van szükség, mert bizonyos
böngészõk csak az útvonal megadása esetén képesek a sütik rendeltetésszer
û használatára. Az útvonal elhagyásával a süti használatát az aktuális, illetve az
alatta elhelyezkedõ könyvtárak oldalai számára korlátozzuk.
Ha a setcookie() szöveges paramétereiként ""-t, azaz üres karakterláncot
adunk át, a szám paramétereinek pedig 0-t, a függvény ezeket a paramétereket
nem veszi figyelembe.
Süti törlése
A sütik törlésének „hivatalos” módja az, hogy a setcookie() függvényt egyetlen
paraméterrel, mégpedig a törlendõ süti nevével hívjuk meg:
setcookie( "zoldseg" );
Ebben a megoldásban nem bízhatunk meg teljesen, mert nem minden esetben
mûködik kifogástalanul. Ezért célszerûbb, ha egy múltbeli dátummal új értéket
adunk a sütinek:
setcookie( "zoldseg", "", time()-60, "/", "kiskapu.hu", 0);
Ennek alkalmazásakor viszont ügyelnünk kell, hogy a megadott útvonal, tartomány
és biztonsági paraméter tökéletesen egyezzen a süti létrehozásakor megadottakkal.
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 365
19
Munkamenet-azonosító sütik
Ha olyan sütit szeretnénk létrehozni, amely csak addig létezik, amíg a felhasználó
be nem zárja a böngészõt, csak annyi a teendõnk, hogy a süti élettartamát nullára
állítjuk. Amíg ki nem lépünk a böngészõbõl, az így készített sütiket a kiszolgáló
gond nélkül megkapja, ám ha bezárjuk a programot, a sütik megszûnnek,
így hiába indítjuk újra a böngészõt, már nem érjük el azokat.
Ezen eljárás legfõbb alkalmazási területe a felhasználók azonosítása. A felhasználó
elküldi a nevét és jelszavát, válaszként pedig egy olyan oldalt kap, amely egy sütit
hoz létre a böngészõben. Ezek után a böngészõ a sütit minden személyes adatokat
tartalmazó laphoz történõ hozzáféréskor visszaküldi a kiszolgálónak, az pedig
ennek hatására engedélyezi a hozzáférést. Ilyen esetekben nem kívánatos, hogy
a böngészõ újraindítása után is hozzáférhessünk ezekhez a lapokhoz, mert nem
lehetünk biztosak benne, hogy nem egy másik felhasználó indította el a böngé-
szõt. A munkamenet-azonosítót hagyományosan sessionid-nek nevezik,
a böngészõ bezárásáig élõ sütit pedig session cookie-nak.
setcookie( "session_id", "55435", 0 );
Példa: Webhelyhasználat nyomon követése
Képzeljük el, hogy egy tartalomszolgáltató azzal bízott meg bennünket, hogy
sütik, valamint egy MySQL adatbázis segítségével kimutatást készítsünk a látogat
ókról. Szükség van a látogatók számára, a látogatások alkalmával letöltött lapok
számának átlagára és az olvasók által a webhelyen töltött átlagidõre, látogatókra
lebontva.
Az elsõ dolgunk, hogy megértessük megbízónkkal a sütik alkalmazásának
korlátait. Nem mindegyik felhasználó böngészõjében engedélyezett a sütik
használata. Ilyen esetben a lekért oldal mindig úgy fog tûnni, mintha ez lenne az
adott felhasználó elsõ látogatása. Így hát a kapott eredményeket kissé meghamisítj
ák azok a böngészõk, amelyek nem tudják vagy nem akarják kezelni a sütiket.
Továbbá abban sem lehetünk biztosak, hogy egy felhasználó mindig ugyanazt
a böngészõt használja, és abban sem, hogy egy adott böngészõn nem osztozik-e
esetleg több ember.
Ha megbízónk mindezt tudomásul vette, nekiveselkedhetünk a tényleges megval
ósításnak. Egy mûködõ mintát kevesebb, mint 90 sorból összerakhatunk!
Szükségünk lesz elõször is egy adatbázistáblára, mely a 19.1-es táblázatban felsorolt
mezõkbõl áll.
366 19. óra
19.1. táblázat Adatbázismezõk
Név Típus Leírás
vendeg_azon egész Automatikusan növekvõ mezõ, amely
minden látogató számára egyedi
azonosítót állít elõ és tárol.
elso_latogatas egész A látogató elsõ látogatásának idõbélyege.
utolso_latogatas egész A legutóbb lekért lap idõpontjának
idõbélyege.
latogatas_szam egész Az elkülöníthetõ látogatások száma.
ossz_ido egész A webhelyen töltött idõ közelítõ értéke.
ossz_letoltes egész A látogató összes letöltési kérelmeinek
száma.
A vendeg_naplo MySQL tábla létrehozásához a következõ CREATE utasításra
lesz szükség:
create table vendeg_naplo (
vendeg_azon INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY( vendeg_azon ),
elso_latogatas INT,
utolso_latogatas INT,
latogatas_szam INT,
ossz_ido INT,
ossz_letoltes INT
);
Most, hogy elkészítettük a táblát, amivel dolgozhatunk, írnunk kell egy programot,
amely megnyit egy adatbázis-kapcsolatot és képes ellenõrizni a süti jelenlétét.
Ha a süti nem létezik, új sort hoz létre a táblában és feltölti az új látogató adataival.
Ennek megvalósítása látható a 19.2. példában.
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 367
19
19.2 program A MySQL adatbázist új felhasználó adataival bõvítõ program
1: 2: $adatbazis = mysql_connect( "localhost", "janos",
"majomkenyerfa" );
3: if ( ! $adatbazis )
4: die( "Nem lehet a mysql-hez kapcsolódni!" );
5: mysql_select_db( "minta", $adatbazis ) or die (
mysql_error() );
6: if ( ! isset ( $vendeg_azon ) )
7: $vendeg_allapot = ujvendeg( $adatbazis );
8: else
9: print "Örülünk, hogy ismét körünkben
üdvözölhetjük, $vendeg_azon

";
10: function ujvendeg( $adatbazis )
11: {
12: // egy új vendég!
13: $vendeg_adatok = array (
14: "elso_latogatas" => time(),
15: "utolso_latogatas" => time(),
16: "latogatas_szam" => 1,
17: "ossz_ido" => 0,
18: "ossz_letoltes" => 1
19: );
20: $lekerdezes = "INSERT INTO vendeg_naplo
( elso_latogatas,
21: utolso_latogatas,
22: latogatas_szam,
23: ossz_ido,
24: ossz_letoltes ) ";
25: $lekerdezes .= "values ( ".
$vendeg_adatok["elso_latogatas"].", ".
26: $vendeg_adatok["utolso_latogatas"].", ".
27: $vendeg_adatok["latogatas_szam"].", ".
28: $vendeg_adatok["ossz_ido"].", ".
29: $vendeg_adatok["ossz_letoltes"]." )";
30: $eredmeny = mysql_query( $lekerdezes );
31: $vendeg_adatok["vendeg_azon"] =
mysql_insert_id();
32: setcookie( "vendeg_azon",
$vendeg_adatok["vendeg_azon"],
33: time()+(60*60*24*365*10), "/" );
34: return $vendeg_adatok;
35: }
36: ?>
368 19. óra
A szokványos módon csatlakozunk a MySQL kiszolgálóhoz és kiválasztjuk
azt az adatbázist, amelyben a vendeg_naplo tábla található (a MySQL adatbáziskiszolg
áló kezelését a tizenkettedik óra tartalmazza). Ellenõrizzük a $vendeg_azon
változó jelenlétét, amely a felhasználót azonosító egyedi egész számot tartalmazza.
Ha ez a változó nem létezik, feltételezzük, hogy új felhasználóról van szó és bejegyz
éséhez meghívjuk az ujvendeg() nevû függvényt.
Az ujvendeg() függvény egy hivatkozás-azonosítót kér és egy tömböt ad vissza.
A függvényben létrehozunk egy $vendeg_adatok nevû tömböt. A tömb
elso_latogatas és utolso_latogatas elemeit a pillanatnyi idõre állítjuk.
Mivel ez az elsõ látogatás, így a latogatas_szam és az ossz_letoltes
elemeket 1-re állítjuk. Az ossz_ido 0 lesz, hiszen ezen látogatás alkalmával
még nem telt el idõ.
A létrehozott tömb alapján elkészítjük a táblába illesztendõ új sort, úgy, hogy
a tömb mindegyik elemét a tábla azonos nevû oszlopának adjuk értékül.
Mivel a vendeg_azon mezõ automatikusan növekszik, megadásától eltekinthet
ünk. A süti beállításakor azonban szükség lesz erre az újonnan elõállított azonosí-
tóra. Ezt válaszként a mysql_insert_id() függvénytõl kaphatjuk meg.
Most, hogy elláttuk az új látogatót egy azonosítóval, nincs más hátra, mint kibõví-
teni a tömböt az azonosítóval, amely így már megfelel az adatbázisrekordnak, amit
az imént létrehoztunk.
Végsõ lépésként létrehozzuk a vendeg_azon nevû sütit egy setcookie()
hívással és visszaadjuk a $vendeg_adatok tömböt a hívó programnak.
Legközelebb, amikor a látogató mûködésbe hozza a programot, a PHP már látni
fogja a $vendeg_azon változón keresztül a vendeg_azon sütit. A program
ezt úgy értékeli, hogy egy régi ismerõs visszatérésérõl van szó és ennek megfelel
õen frissíti a vendeg_naplo táblát, majd üdvözli a felhasználót.
A frissítés elvégzéséhez meg kell még vizsgálnunk, hogy a program futását
egy folyamatban lévõ böngészés eredményezte vagy új látogatás elsõ lépésérõl
van szó. Ennek eldöntésében egy globális változó lesz segítségünkre, mely
egy másodpercben mért idõtartamot tárol. Ha a program által érzékelt legutolsó
letöltés ideje az elõbb említett idõtartamnál régebbi, akkor a mostani letöltés
egy újabb látogatás kezdetének tekintendõ, ellenkezõ esetben a folyamatban lévõ
látogatás részének tekintjük.
A 19.3. példa a regivendeg() függvénnyel bõvíti a 19.2. programot.
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 369
19
19.3 program Felhasználókövetõ program sütik és MySQL adatbázis
felhasználásával
1: 2: $lhossz = 300; // a látogatás hossza 5 perc,
másodpercben kifejezve
3: $adatbazis = mysql_connect( "localhost", "janos",
"majomkenyerfa" );
4: if ( ! $adatbazis )
5: die( "Nem lehet a mysqld-hez kapcsolódni!" );
6: mysql_select_db( "minta"", $adatbazis ) or
die ( mysql_error() );
7: if ( ! isset ( $vendeg_azon ) )
8: $vendeg_allapot = ujvendeg( $adatbazis );
9: else
10: {
11: $vendeg_allapot = regivendeg( $adatbazis,
$vendeg_azon, $lhossz );
12: print "Örülünk, hogy ismét körünkben
üdvözölhetjük, $vendeg_azon

";
13: }
14: function ujvendeg( $adatbazis )
15: {
16: // egy új vendég!
17: $vendeg_adatok = array (
18: "elso_latogatas" => time(),
19: "utolso_latogatas" => time(),
20: "latogatas_szam" => 1,
21: "ossz_ido" => 0,
22: "ossz_letoltes" => 1
23: );
24: $lekerdezes = "INSERT INTO vendeg_naplo
( elso_latogatas,
25: utolso_latogatas,
26: latogatas_szam,
27: ossz_ido,
28: ossz_letoltes ) ";
29: $lekerdezes .= "values ( ".
$vendeg_adatok["elso_latogatas"].", ".
30: $vendeg_adatok["utolso_latogatas"].", ".
31: $vendeg_adatok["latogatas_szam"].", ".
32: $vendeg_adatok["ossz_ido"].", ".
33: $vendeg_adatok["ossz_letoltes"]." )";
34: $eredmeny = mysql_query( $lekerdezes );
35: $vendeg_adatok["vendeg_azon"] =
mysql_insert_id();
370 19. óra
19.3 program folytatás
36: setcookie( "vendeg_azon",
$vendeg_adatok["vendeg_azon"],
37: time()+(60*60*24*365*10), "/" );
38: return $vendeg_adatok;
39: }
40: function regivendeg( $adatbazis, $vendeg_azon, $lhossz )
41: {
42: // egy ismerõs vendég,
aki már járt nálunk korábban!
43: $lekerdezes = "SELECT * FROM vendeg_naplo WHERE
vendeg_azon=$vendeg_azon";
44: $eredmeny = mysql_query( $lekerdezes );
45: if ( ! mysql_num_rows( $eredmeny ) )
46: // süti van ugyan, de azonosító nincs — tehát
mégiscsak új vendég
47: return ujvendeg( $adatbazis );
48: $vendeg_adatok = mysql_fetch_array( $eredmeny,
$adatbazis );
49: // ez most egy újabb letöltés, tehát növeljük
a számlálót
50: $vendeg_adatok["ossz_letoltes"]++;
51: if ( ( $vendeg_adatok["utolso_latogatas"]
+ $lhossz ) > time() )
52: // még mindig ugyanaz a látogatás,
tehát növeljük az összidõt.
53: $vendeg_adatok["ossz_ido"] +=
54: ( time() - $vendeg_adatok["utolso_latogatas"] );
55: else
56: // ez már egy új látogatás,
57: $vendeg_adatok["latogatas_szam"]++;
58: // ennek megfelelõen módosítjuk az adatbázist
59: $lekerdezes = "UPDATE vendeg_naplo SET
utolso_latogatas=".time().",
60: "latogatas_szam=".$vendeg_adatok
["latogatas_szam"].", ".
61: "ossz_ido=".$vendeg_adatok["ossz_ido"].", ".
62: "ossz_letoltes=".
$vendeg_adatok["ossz_letoltes"]." ";
63: $lekerdezes .= "WHERE vendeg_azon=$vendeg_azon";
64: $eredmeny = mysql_query( $lekerdezes );
65: return $vendeg_adatok;
66: }
67: ?>
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 371
19
Látható, hogy a programot az $lhossz nevû változóval bõvítettük. Ebben adjuk
meg azt az idõtartamot, amely alapján megítéljük, hogy a letöltés mely látogatáshoz
tartozik. A $vendeg_azon változó jelenlétének érzékelése azt jelenti számunkra,
hogy kaptunk egy sütit. Erre válaszul meghívjuk a regivendeg() függvényt,
átadva annak az adatbázisra hivatkozó, a $vendeg_azon és az $lhossz változót,
amit 300 másodpercre, azaz 5 percre állítottunk.
A regivendeg() függvény elsõ lépésként lekérdezi a felhasználóról tárolt
adatokat. Ezt egyszerûen úgy tesszük, hogy kikeressük a vendeg_naplo tábla
azon sorát, melyben a vendeg_azon mezõ egyenlõ a $vendeg_azon változó
értékével. A mysql_query() által visszaadott sorok számát megtudhatjuk,
ha meghívjuk a mysql_num_rows() függvényt az eredménysorok azonosítójá-
val. Ha a mysql_num_rows() válasza 0, akkor mégis új felhasználóról van szó,
tehát meg kell hívnunk az ujvendeg() függvényt.
Tegyük fel, hogy találtunk egy megfelelõ sort, melynek azonosítója egyezik a süti érté-
kével. Ezt a sort a mysql_fetch_array() függvénnyel emelhetjük át egy PHP
tömbbe (esetünkben a $vendeg_adatok nevûbe). A program mostani futása egy oldal
letöltésének következménye, tehát a $vendeg_adatok["ossz_letoltes"]
változó értékét eggyel növelnünk kell, hogy rögzítsük ezt a tényt.
Megvizsgáljuk, hogy a $vendeg_adatok["utolso_latogatas"] és az
$lhossz összege a pillanatnyi idõnél késõbbi idõpont-e. Ha késõbbi, akkor az azt
jelenti, hogy a legutóbbi letöltés óta kevesebb, mint $lhossz idõ telt el, vagyis
a legutóbbi látogatás még folyamatban van és ez a letöltés még annak a része. Ennek
tényét úgy õrizzük meg, hogy a legutóbbi letöltés óta eltelt idõt hozzáadjuk
a $vendeg_adatok["ossz_ido"] változóhoz.
Ha úgy találtuk, hogy már új látogatásról van szó, egyszerûen növeljük
a $vendeg_adatok["latogatas_szam"] változó értékét.
Befejezésül a $vendeg_adatok tömb tartalmával frissítjük a vendeg_naplo
táblát és a hívó program is megkapja ezt a tömböt. Bár ezt külön nem emeltük ki,
természetesen az utolso_latogatas mezõt is a pillanatnyi idõhöz igazítottuk.
Most, hogy a feladaton túl vagyunk, írhatunk egy kis programot, hogy ellen-
õrizzük, az elmélet valóban mûködik-e a gyakorlatban. Elkészítjük
az allapotMegjelenites() függvényt, amely kiszámolja a lekérõ felhasználó
átlagértékeit és megjeleníti azokat a böngészõben. A valóságban persze komolyabb
megjelenésû, átfogóbb képet kell adnunk a látogatókról, de a lényeg megért
éséhez ez a példa is bõven elegendõ. A függvény megvalósítását a 19.4. példában
találjuk. A korábbi példák kódjához az include() függvény alkalmazásával
férhetünk hozzá.
372 19. óra
19.4 program A 19.3-as program által begyûjtött letöltési statisztikák
megjelenítése
1: 2: include("19.3.program.php");
3: allapotMegjelenites();
4: function allapotMegjelenites()
5: {
6: global $vendeg_allapot;
7: $letoltesek = sprintf( "%.2f",
8: ($vendeg_allapot["ossz_letoltes"]/
/$vendeg_allapot["latogatas_szam"])
);
9: $idotartam = sprintf( "%.2f",
10: ($vendeg_allapot["ossz_ido"]/
/$vendeg_allapot["latogatas_szam"]) );
11: print "

Üdvözöljük! Az Ön azonosítója".
$vendeg_allapot["vendeg_azon"]."

\n\n";
12: print "

Az Ön látogatásainak száma
13: $vendeg_allapot["latogatas_szam"]."

\n\n";
14: print "

Letöltések átlagos száma
látogatásonként: $letoltesek

\n\n";
15: print "

Átlagos látogatási idõtartam: $idotartam
másodperc

\n\n";
16: }
17: ?>
A 19.1 ábra a 19.4 program kimenetét mutatja. Az include() sorral biztosítottuk,
hogy a felhasználókövetõ kód lefusson. Hasonló sorral kell bõvítenünk
webhelyünk minden olyan oldalát, melyet be szeretnénk vonni a statisztikába. Az
allapotMegjelenites() függvény a $vendeg_allapot globális változó
alapján dolgozik. Ezt vagy az ujvendeg(), vagy a regivendeg() függvény
hozza létre és tölti fel a vendeg_naplo tábla megfelelõ sorának értékeivel.
Azt, hogy egy felhasználó látogatásonként átlagosan hányszor kattintott olyan
hivatkozásra, mely a webhely valamelyik oldalára mutatott, úgy számoljuk ki,
hogy elosztjuk a $vendeg_allapot["ossz_letoltes"] változót a látogatá-
sok számával. Ugyanezzel az értékkel a $vendeg_allapot["ossz_ido"]-t elosztva
a látogatások átlagidejét kaphatjuk meg. Ezeket a számokat az sprintf()
segédletével kerekítjük két tizedesjegyre, majd mondatokká formálva megjelen
ítjük azokat a felhasználónak.
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 373
19
Természetesen a példát úgy is bõvíthetnénk, hogy a program rögzítse a felhaszná-
ló érdeklõdési területeit a webhelyen belül, de akár naplóztathatnánk a látogatáshoz
használt böngészõ típusát vagy a látogatók IP címeit is. Hogy mire lehet mindezt
használni? Könnyíthetjük felhasználóink eligazodását webhelyünkön, úgy,
hogy böngészési szokásaikat kielemezve, vastag betûvel kiemeljük a számukra
feltehetõleg különösképp érdekes mondanivalót.
Lekérdezõ karakterláncok használata
A sütik hatalmas hátránya azok felhasználó-függõsége. Nem csak a felhasználó
kénye-kedvének vagyunk kitéve, ha sütiket használunk, de a felhasználó böngé-
szõjétõl is függ használatuk. A felhasználó letilthatja a sütik használatát, a böngé-
szõk pedig nem mindig egyformán valósítják meg a szabványt. Egyikük-másikuk
a sütik kezelése területén dokumentált hibákkal is rendelkezik. Ha csak egy látogat
ás folyamán szeretnénk állapot-adatokat tárolni, jobban járunk, ha egy sokkal
hagyományosabb megoldáshoz folyamodunk.
Ha egy ûrlapot a GET eljárással küldünk el, akkor annak mezõit és azok értékeit
URL kódolásban hozzáillesztjük ahhoz a címhez (URL-hez), ahová az ûrlapot küldj
ük. Az értékek ekkor elérhetõk lesznek a kiszolgáló, illetve az általa futtatott programok
számára. Vegyünk példaként egy olyan ûrlapot, amely egy felhasznalo
és egy nev mezõt tartalmaz. Ekkor a lekérés a következõképp fog festeni:
http://php.kiskapu.hu/proba5.php?nev=
å 344343&felhasznalo=Szy+Gyorgy
374 19. óra
19.1. kép
A használati statisztika
megjelenítése
Minden mezõ nevét egy egyenlõségjel (=) választja el annak értékétõl; ezeket
a név–érték párokat pedig ÉS jelek (&) határolják. A PHP visszafejti a jeleket,
a talált adatokat a $HTTP_GET_VARS asszociatív tömbben teszi elérhetõvé
a program számára, és emellett a mezõk nevével azonos nevû globális változókat
is létrehoz, a megfelelõ tartalommal. A felhasznalo nevû GET változóhoz így
az alábbi két módon férhetünk hozzá:
$HTTP_GET_VARS["felhasznalo"];
$felhasznalo;
A GET lekérések szerencsére nem csak ûrlapokkal kapcsolatban használhatók;
viszonylag könnyen készíthetünk mi is ilyen karakterláncokat, így a fontos
adatokat könnyedén továbbíthatjuk lapról lapra.
Lekérdezõ karakterlánc készítése
Alapvetõ feladatunk a lekérdezõ karakterláncok készítésekor, hogy a kulcs–érték
párokat URL formára alakítsuk. Tegyük fel, hogy egy címet (URL-t) szeretnénk átadni
egy lapnak paraméterként, azaz egy lekérdezõ karakterlánc részeként. Erre
a PHP urlencode() függvénye használható, mely egy tetszés szerinti karakterl
áncot vár és annak kódolt változatával tér vissza:
print urlencode("http://www.kiskapu.hu");
// azt írja ki, hogy http%3A%2F%2Fwww.kiskapu.hu
Az URL kódolású szövegek elõállítása így nem okoz gondot, akár saját GET leké-
réseket is összerakhatunk. A következõ kódrészlet két változóból épít fel
egy lekérdezõ karakterláncot:
$erdeklodes = "sport";
$honlap = "http://www.kiskapu.hu";
$lekerdezes = "honlap=".urlencode( $honlap );
$lekerdezes .= "&erdeklodes=".urlencode( $erdeklodes );
?>
Gyerünk!
Ennek hatására a böngészõhöz az URL már a kódolt lekérdezõ karakterlánccal
bõvítve jut el:
masiklap.php?honlap=http%3A%2F%2Fwww.kiskapu.hu&
å erdeklodes=sport
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 375
19
A honlap és az erdeklodes paraméterek a masiklap.php programon belül
ugyanilyen nevû, URL-bõl visszafejtett globális változókként lesznek elérhetõk.
Ez így a problémának kissé kezdetleges megoldása, mert a változónevek kódba
ágyazásával megnehezítjük a kód újrahasznosítását. Ahhoz, hogy hatékonyan
küldhessünk adatokat lapról-lapra, egyszerûvé kell tennünk a lekérdezõ karakterl
áncokat tartalmazó hivatkozások készítését. Ez különösen fontos, ha meg szeretn
énk tartani a PHP azon hasznos tulajdonságát, miszerint a nem kifejezetten programoz
ók is könnyedén eligazodhatnak rajta.
A 19.5. példa egy olyan lsztring() nevû függvény megvalósítását tartalmazza,
amely a kapott asszociatív tömb alapján elkészít és visszaad egy lekérdezõ karakterl
áncot.
19.5. program Lekérdezõ karakterláncot készítõ függvény
1:
2:
3: 19.5 program Lekérdezõ karakterláncot készítõ<br />függvény
4:
5:
6: 7: function lsztring( $lekerdezes )
8: {
9: global $QUERY_STRING;
10: if ( ! $lekerdezes ) return $QUERY_STRING;
11: $lsztring = "";
12: foreach( $lekerdezes as $kulcs => $ertek )
13: {
14: if ( strlen( $lsztring ) ) $lsztring .= "&";
15: $lsztring .= urlencode( $kulcs ) .
"=" . urlencode( $ertek );
16: }
17: return $lsztring;
18: }
19: $lekerdezes = array ( "nev" => "Kis Lajos Bence",
20: "erdeklodes" => "Filmek (fõleg
mûvészfilmek)",
21: "honlap" => "http://www.kiskapu.hu/lajos/"
22: );
23: print lsztring( $lekerdezes );
376 19. óra
19.5. program (folytatás)
24: // azt írja ki, hogy nev=Kis+Lajos+Bence&erdeklodes=
Filmek+%28f%F5leg+m%FBv%E9szfilmek
25: // %29&honlap=http%3A%2F%2Fwww.kiskapu.hu%2Flajos%2F
26: ?>
27:


28: Gyerünk!
29:


30:
31:
Az lsztring() egy asszociatív tömböt vár paraméterként, amit jelen esetben
a $lekerdezes változó képében adunk át neki. Ha a $lekerdezes még nem
kapott volna értéket, a programot tartalmazó lap lekérdezõ karakterláncát adjuk
vissza, amit a $QUERY_STRING változóval érhetünk el. Ezzel oldhatjuk meg azt,
hogy a GET-tel továbbított, módosítatlan ûrlapadatok könnyedén továbbadhatóak
legyenek más lapok számára.
Ha a $lekerdezes tömb nem üres, a visszaadandó lekérdezõ karakterláncot
az $lsztring változóba helyezzük.
A foreach segítségével sorra vesszük a tömb elemeit, úgy, hogy azok a $kulcs és
$ertek változókon keresztül legyenek elérhetõk.
A kulcs–érték párokat & jellel kell elválasztanunk, így ha nem a ciklus elsõ lefutá-
sánál tartunk – azaz az $lsztring változó már nem üres –, ezt a karaktert is
hozzátesszük a lekérdezõ karakterlánchoz.
A $kulcs és $ertek változókat az urlencode() függvénnyel kódolva és
egy egyenlõségjellel (=) elválasztva adjuk hozzá az $lsztring végéhez.
Ezek után már csak vissza kell adnunk az összeállított, kódolt karakterláncot.
E függvény alkalmazásával pár sornyi PHP kód is elég, hogy adatokat adhassunk át
egyes lapjaink között.
Állapotok tárolása sütikkel és GET típusú lekérdezésekkel 377
19
Összefoglalás
Ezen az órán a weblapok közti információátadás két módjával ismerkedhettünk
meg. Segítségükkel több oldalból álló webes alkalmazások alakíthatók ki, melyek
a felhasználók igényeit is figyelembe veszik.
Tudjuk, hogyan használjuk a setcookie() függvényt sütik létrehozására. Ennek
kapcsán láthattuk, hogyan tárolhatók adatok a webhely felhasználóinak szokásair
ól sütik és egy adatbázis felhasználásával. Láttunk lekérdezõ karakterláncokat is.
Tudjuk, hogyan kell azokat kódolni és egy hasznos eszközt is a magunkénak
mondhatunk, amely jelentõsen egyszerûsíti ezek használatát.
Kérdések és válaszok
Van e valamiféle komoly biztonságot vagy személyiségi jogokat sértõ
velejárója a sütik használatának?
A kiszolgáló csak a saját tartományán belül levõ gépek sütijeihez férhet hozzá.
Azon túl, hogy a süti a felhasználó fájlrendszerében tárolódik, azzal semmiféle
további kapcsolatba nem kerül. Lehetõség van azonban arra, hogy sütit állítsunk be
egy kép letöltésének válaszaként. Tehát ha sok webhely jelentet meg egy külsõ
reklámszolgáltató vagy számláló programot oldalain, ezek szolgáltatója képes lehet
a látogatók követésére különbözõ webhelyek között is.
Mûhely
A mûhelyben kvízkérdések találhatók, melyek segítenek megszilárdítani az órában
szerzett tudást. A válaszokat az A függelékben helyeztük el.
Kvíz
1. Milyen függvénnyel vehetjük rá a weboldalunkat letöltõ felhasználó böngé-
szõjét, hogy létrehozzon egy sütit és tárolja azt?
2. Hogyan törölhetjük a sütiket?
3. Milyen függvénnyel tehetünk egy tetszõleges karakterláncot alkalmassá arra,
hogy lekérdezõ karakterláncban szerepelhessen?
4. Melyik beépített változó tartalmazza a lekérdezõ karakterláncot nyers formában?
5. A lekérdezõ karakterlánc formájában elküldött név–érték párok globális változ
ókként válnak elérhetõvé. Létezik azonban egy tömb is, amely tartalmazza
õket. Mi ennek a tömbnek a neve?
378 19. óra
Feladatok
1. Tegyük lehetõvé, hogy a webhelyünket meglátogató felhasználó beállíthassa
a weboldalak háttérszínét, valamint hogy megadhassa, milyen néven
köszöntsék a webhely oldalai. Oldjuk meg sütikkel, hogy minden oldal
köszönjön, illetve a megfelelõ háttérszínnel jelenjen meg.
2. Írjuk át az elõbbi feladat programját úgy, hogy az adatokat lekérdezõ karakterl
áncban tároljuk, ne sütikben.