Teljes példa (második rész)

Az elõzõ órában felépítettük a klubok számára a bejegyzõ és karbantartó felületet,
amivel új klubok és rendezvények kerülhetnek a rendszerbe. Most az átlagos
felhasználók számára elérhetõ programokat kell elkészítenünk, melyek lehetõvé
teszik a listák böngészését.
Ebben az órában a következõket tanuljuk meg:
• Hogyan készítsünk olyan függvényeket, amelyek egyetlen lekérdezéssel
több táblából hívnak le adatokat?
• Hogyan készíthetünk a paramétereiktõl függõ SQL parancsokat végrehajtó
függvényeket?
• Hogyan menthetjük a felhasználó régebbi beállításait munkamenetf
üggvényekkel?
• Hogyan kell átalakítanunk az egyszerû szöveges adatokat, hogy
a HTML kódba írhassuk azokat?
Az eseménynaptár nyilvános oldalai
Miután a tagok bejegyeztethetik klubjaikat és az eseményeket, itt az ideje, hogy
az átlagos felhasználó számára is elérhetõ oldalak készítésébe fogjunk.
Ezek az oldalak a listák böngészésére és nem a bennük való keresésre szolgálnak
majd, bár nem lenne túl bonyolult ez utóbbit sem megvalósítani.
Ebben az órában négy oldalt készítünk el, amelyek lehetõséget adnak a felhaszná-
lónak, hogy kiírassa egy adott terület vagy téma rendezvényeit, bármilyen idõpont
szerinti szûréssel párosítva.
esemenyekinfo.php
Az esemenyekinfo.php oldal lehetõséget ad a rendszerben lévõ rendezvények
böngészésére. Bizonyos szempontból hasonlít az esemenylista.php oldalra,
amit az elõzõ órában tárgyaltunk, de nagyobb rugalmasságot és több információt
nyújt a felhasználónak.
24.1. program esemenyekinfo.php
1: 2: include("adatbazis.inc");
3: include("datum.inc");
4: include("kozosfv.inc");
5:
6: if ( isset($mitkelltenni) && $mitkelltenni ==
"esemenyLista" )
7: $munkamenet["esemenyek"] = $urlap;
8: elseif ( $munkamenet["esemenyek"] )
9: $urlap = $munkamenet["esemenyek"];
10: else
11: {
12: $datum_tomb = getDate( time() );
13: $munkamenet["esemenyek"]["terulet"] = "BÁRMELY";
14: $munkamenet["esemenyek"]["tipus"] = "BÁRMELY";
15: $munkamenet["esemenyek"]["honap"] = $datum_tomb["mon"];
16: $munkamenet["esemenyek"]["ev"] = $datum_tomb["year"];
17: }
18:
19: $idoszak = datumIdoszak(
$munkamenet["esemenyek"]["honap"],
20: $munkamenet["esemenyek"]["ev"] );
470 24. óra
24.1. program (folytatás)
21: function esemenyLista( )
22: {
23: global $idoszak, $munkamenet;
24:
25: $esemenyek = esemenyekLekeres( 0, $idoszak,
$munkamenet["esemenyek"]["terulet"],
26: $munkamenet["esemenyek"]["tipus"] );
27: if ( ! $esemenyek )
28: {
29: print "Nincs megjeleníthetõ esemény

";
30: return;
31: }
32: print "

\n";
33: print "\n";
34: print "\n";
35: print "\n";
36: print "\n";
37: print "\n";
38: foreach ( $esemenyek as $sor )
39: {
40: print "\n";
41: print "\n";
42: print "\n";
44: print "\n";
46: print "\n";
47: print "\n";
48: print "\n";
49: }
50: print "
DátumEseményKlubTerületTípus
".date("j M Y H.i",
$sor["edatum"])."
href=\"esemenyinfo.php?eazonosito=".
$sor["eazonosito"]."&".SID."\">".
43: html($sor["enev"])."
$sor["eklub"]."&".SID."\">".
45: html($sor["klubnev"])."
".$sor["teruletnev"]."".$sor["tipusnev"]."
\n";
51: }
52: ?>
53:
54:
55:
56: Esemény információk
Teljes példa (második rész) 471
24
24.1. program (folytatás)
57:
58:
59: 60: include("kozosnav.inc");
61: ?>
62:

Esemény információk


63:


64:


65: value="esemenyLista">
66: name=""
67: value="">
68:
71:
72:
75:
76:
80:
81:
85:
86:
87:

88:


89:
90: 91: esemenyLista( );
92: ?>
93:
94:
95:
472 24. óra
Szokás szerint az adatbazis.inc és a kozosfv.inc külsõ állományok beilleszt
ésével kezdjük. Amellett, hogy elérhetjük majd az ezekben tárolt függvé-
nyeket, biztosak lehetünk abban, hogy élõ adatbáziskapcsolattal rendelkezünk és
aktív munkamenettel dolgozhatunk.
Ezután ellenõrizzük, hogy érkezett-e ûrlapadat. Ezt a már ismert mitkelltenni
ûrlapelembõl származó $mitkelltenni változó vizsgálatával tehetjük meg.
Ha kitöltött ûrlap adatai érkeztek, azok elõnyt élveznek minden korábban elraktá-
rozott adattal szemben. Az elõzõ órában láthattuk, hogyan rendeltünk egy asszociat
ív tömböt a munkamenethez, hogy a belépett tag adatait nyilvántartsuk.
Ebben az órában új elemeket adunk ehhez, amelyek a felhasználó beállításait
tartalmazzák majd.
A $munkamenet változót a kozosfv.inc állományban rendeltük a munkamenethez
(mint azt már az elõzõ órában láttuk):
session_start();
session_register( "munkamenet" );
Most ezt a $munkamenet tömböt többdimenziós tömbbé alakítjuk, mivel
a $munkamenet["esemenyek"] tömbelemnek egy asszociatív tömböt adunk
értékül. Ebben a tömbben fogjuk tárolni a csak ehhez az oldalhoz tartozó beállítá-
sokat. Ezek a terület, típus, hónap és év értékek. Ha ûrlap adat érkezett, a korábbi
beállításokat ezzel írjuk felül.
Lehetséges, hogy a program futásakor éppen nem érkezett ûrlapinformáció, de
korábban már tároltuk a felhasználó által elõnyben részesített beállításokat.
Ebben az esetben a $mitkelltenni változó nincs beállítva, viszont
a $munkamenet["esemenyek"] tömb már tartalmaz elemeket. Ebben az esetben
az $urlap tömböt írjuk felül a korábban tárolt értékekkel. Ez biztosítja, hogy
az ûrlapban a megfelelõ beállítások látsszanak.
Ha a felhasználó nem küldött be ûrlap adatokat és korábban sem tároltuk a beállí-
tásait, nekünk kell alapértékekkel feltöltenünk a $munkamenet["esemenyek"]
tömböt. A getDate() beépített PHP függvényt használjuk arra, hogy elemeire
bontsuk a dátumot. A visszaadott tömb alapján állítjuk be
a $munkamenet["esemenyek"]["honap"] és
$munkamenet["esemenyek"]["ev"] elemeket az aktuális hónap
és év értékekre. Már tudjuk, hogy az év és hónap értékek érvényes adatot tartalmaznak,
akár ûrlapértékekbõl, akár korábbi beállításból, akár az aktuális dátumb
ól származnak. Ezeket az értékeket a datum.inc egy új függvényének,
a datumIdoszak() függvénynek adjuk át. Ez a függvény hónap és év paramétereket
vár és két idõbélyeggel tér vissza, megjelölve a hónap kezdetét és végét.
Teljes példa (második rész) 473
24
24.2. program Részlet a datum.inc fájlból
1: function datumIdoszak( $honap, $ev )
2: {
3: $eleje = mktime( 0, 0, 0, $honap, 1, $ev );
4: $vege = mktime( 0, 0, 0, $honap+1, 1, $ev );
5: $vege--;
6: return array( $eleje, $vege );
7: }
A függvény által visszaadott tömböt az $idoszak globális változónak adjuk
értékül.
Létrehozunk egy új esemenyLista() függvényt, amely a megfelelõ esemé-
nyekrõl ír majd információkat a böngészõbe. Ezt késõbb a HTML törzsrészében
hívjuk meg.
Ahhoz, hogy az események listáját megkapjuk, az esemenyekLekeres()
függvényt használjuk, amely az adatbazis.inc állományban található. Ezzel
a függvénnyel érintõlegesen már az elõzõ órában is találkoztunk, de kevés jó tulajdons
ágát ismerhettük meg.
24.3 program Részlet az adatbazis.inc fájlból
1: function esemenyekLekeres( $kazonosito=0, $idoszak=0,
$terulet=0, $tipus=0 )
2: {
3: global $kapcsolat;
4: $lekeres = "SELECT klubok.klubnev, esemenyek.*,
teruletek.terulet as teruletnev,
tipusok.tipus as tipusnev ";
5: $lekeres .= "FROM klubok, esemenyek, teruletek,
tipusok WHERE ";
6: $lekeres .= "klubok.azonosito=esemenyek.eklub
7: AND esemenyek.eterulet=teruletek.azonosito
8: AND esemenyek.etipus=tipusok.azonosito ";
9: if ( ! empty( $kazonosito ) && $kazonosito
!="BÁRMELY" )
10: $lekeres .= "AND esemenyek.eklub=
'$kazonosito' ";
11: if ( ! empty($idoszak) )
474 24. óra
24.3 program (folytatás)
12: $lekeres .= "AND esemenyek.edatum
>= '$idoszak[0]' AND
esemenyek.edatum
<='$idoszak[1]' ";
13: if ( ! empty($terulet) && $terulet != "BÁRMELY" )
14: $lekeres .= "AND
esemenyek.eterulet='$terulet' ";
15: if ( ! empty($tipus) && $tipus != "BÁRMELY" )
16: $lekeres .= "AND esemenyek.etipus='$tipus' ";
17: $lekeres .= "ORDER BY esemenyek.edatum";
18: $eredmeny = mysql_query( $lekeres, $kapcsolat );
19: if ( ! $eredmeny )
20: die ( "esemenyLekeres hiba: ".mysql_error() );
21: $vissza = array();
22: while ( $sor = mysql_fetch_array( $eredmeny ) )
23: array_push( $vissza, $sor );
24: return $vissza;
25: }
A függvény neve nem igazán fejezi ki sokoldalúságát. Négy paramétert vár:
egy klubazonosítót, egy két idõbélyeget tartalmazó tömbbõl álló idõszakot,
egy terület- és egy típuskódot. Minden paramétere elhagyható vagy hamis, illetve
üres értékkel helyettesíthetõ.
A függvény lényegében egy SQL kérést állít össze a paraméterek alapján. A lekérés
alapvetõen összekapcsolja az adatbázisban lévõ táblákat, ezzel biztosítva, hogy
a klubnév, területnév és típusnév mezõk is elérhetõk legyenek az eredménytábl
ában.
$lekeres = "SELECT klubok.klubnev, esemenyek.*,
teruletek.terulet as teruletnev,
tipusok.tipus as tipusnev ";
$lekeres .= "FROM klubok, esemenyek, teruletek,
tipusok WHERE ";
$lekeres .= "klubok.azonosito=esemenyek.eklub
AND esemenyek.eterulet=teruletek.azonosito
AND esemenyek.etipus=tipusok.azonosito ";
Ezután a függvény további feltételeket ad ehhez, attól függõen, hogy a megfelelõ
függvényparaméter be van-e állítva. A $tipus és $terulet paraméterek akkor is
figyelmen kívül maradnak, ha a "BÁRMELY" karakterláncot tartalmazzák.
Teljes példa (második rész) 475
24
A gyakorlatban ez azt jelenti, hogy minél több paramétert kap a függvény,
annál szûkebb eredménytáblát fogunk kapni. Ha nem adunk át semmilyen param
étert, az összes esemény információit megkapjuk. Ha csupán
egy $kazonosito paramétert adunk meg, csak az adott klubhoz tartozó esemé-
nyeket kapjuk vissza. Ha csak a második $idoszak paramétert adjuk meg,
csak az adott idõszakba esõ rendezvényeket láthatjuk és így tovább.
Végül a függvény az SQL parancsot végrehajtja és egy kétdimenziós tömbbel
tér vissza, amely a kiválasztott események részleteit tartalmazza.
Miután a függvény által visszaadott kétdimenziós tömböt az $esemenyek változó-
ba helyeztük, végig kell lépkednünk annak elemein. Az edatum elemeket felhaszn
álva kiírjuk a formázott dátumokat a date() beépített függvény segítségével.
Ezután egy hivatkozást készítünk az esemenyinfo.php oldalra, ahol több inform
áció érhetõ el egy rendezvényrõl. Ehhez az esemény azonosítóját és a SID álland
ót kell átadnunk. Ebben a ciklusban egy újabb HTML hivatkozást is készítünk
a klubinfo.php oldalra, a klub azonosítójával és a SID állandóval, végül kiírjuk
a terület- és típusneveket a böngészõbe.
Talán feltûnt az elõzõ órában, hogy egy html() nevû függvényt használtunk arra,
hogy szöveges adatokat írjunk ki a böngészõbe. Az esemenyLista() függvényben,
ahogy az események információin végiglépkedünk, ismét a html() függv
ényt hívjuk meg. Ez az általunk írt függvény a kozosfv.inc állományban találhat
ó. Egy karakterláncot vár és annak böngészõbe íráshoz alkalmassá tett,
átalakított változatával tér vissza. A különleges karakterek HTML elemekké alakulnak,
az újsor karakterek például
-é.
24.4. program Részlet a kozosfv.inc fájlból
1: function html( $szoveg )
2: {
3: if ( is_array( $szoveg ) )
4: {
5: foreach ( $szoveg as $kulcs=>$ertek )
6: $szoveg[$kulcs] = htmlszoveg( $ertek );
7: return $szoveg;
8: }
9: return htmlszoveg( $szoveg );
10: }
11:
476 24. óra
24.4. program (folytatás)
12: function htmlszoveg( $szoveg )
13: {
14: $szoveg = htmlspecialchars( $szoveg );
15: $szoveg = nl2br( $szoveg );
16: return $szoveg;
17: }
Látható, hogy ez valójában nem egy, hanem két függvény. A html() egy karakterl
áncot vagy egy tömböt vár paraméterül. Ha tömböt kap, végiglépked rajta,
átalakítva minden elemet, egyéb esetben magát a kapott karakterláncot alakítja át.
A tényleges átalakítás egy másik függvényben, a htmlszoveg()-ben valósul
meg, amely két beépített függvényt alkalmaz a kapott karakterláncra.
A htmlspecialchars() minden karaktert, ami nem jelenne meg helyesen
a HTML kódban, a hozzá tartozó HTML elemre cserél. Az nl2br() minden újsor
karaktert
sortöréssel helyettesít.
Visszatérve az esemenyekinfo.php oldalra, miután beállítottuk az alapadatokat és
létrehoztuk az események kiírására szolgáló függvényt, már csak annyi van hátra,
hogy egy ûrlapot biztosítsunk a felhasználónak, amely lehetõséget ad a lista szûkíté-
sére, illetve bõvítésére.
A felhasználónak választási lehetõséget adó ûrlap egyszerûen elkészíthetõ
az elõzõ órában megismert függvényekkel, melyek közvetlenül OPTION HTML
elemeket írnak ki a böngészõbe.
Az esemenyekinfo.php egy lehetséges kimenetét a 24.1. ábra mutatja.
Teljes példa (második rész) 477
24
24.1. ábra
Az esemenyekinfo.php
kimenete
klubokinfo.php
A felhasználó jogos igénnyel nem csak rendezvények, hanem klubok szerint is
ki szeretné íratni az adatbázis adatait, típus vagy terület szerint szûkítve azokat.
A klubokinfo.php oldal ezt az igényt elégíti ki.
24.5. program klubokinfo.php
1: 2: include("adatbazis.inc");
3: include("datum.inc");
4: include("kozosfv.inc");
5: if ( isset($mitkelltenni) &&
$mitkelltenni == "klubLista" )
6: $munkamenet["klubok"] = $urlap;
7: elseif ( $munkamenet["klubok"] )
8: $urlap = $munkamenet["klubok"];
9: else
10: {
11: $munkamenet["klubok"]["terulet"] = "BÁRMELY";
12: $munkamenet["klubok"]["tipus"] = "BÁRMELY";
13: }
14: function klubLista( )
15: {
16: global $munkamenet;
17: $klubok = klubokLekeres
( $munkamenet["klubok"]["terulet"],
18: $munkamenet["klubok"]["tipus"] );
19: if ( ! $klubok )
20: {
21: print "Nincs megjeleníthetõ klub

\n";
22: return;
23: }
24: print "

\n";
25: print "\n";
26: print "\n";
27: print "\n";
28: foreach ( $klubok as $sor )
29: {
30: print "\n";
478 24. óra
24.5. program (folytatás)
31: print "\n";
33: print "\n";
34: print "\n";
35: print "\n";
36: }
37: print "
KlubTerületTípus
href=\"klubinfo.php?[kazonosito]=".
$sor["azonosito"]."&".SID."\">".
32: html($sor["klubnev"])."
$sor["teruletnev"]$sor["tipusnev"]
\n";
38: }
39: ?>
40:
41:
42: Klub információk
43:
44:
45: 46: include("kozosnav.inc");
47: ?>
48:


49:

Klub információk


50:


51:


52: value="klubLista">
53: 54: value="">
55:
59:
63:
64:

Teljes példa (második rész) 479
24
24.5. program (folytatás)
65:


66: 67: klubLista( );
68: ?>
69:
70:
Láthatjuk, hogy ez a program szerkezetében és logikájában igencsak hasonlít
az elõzõ példában szereplõre. Az ehhez az oldalhoz tartozó „memória” azonban
a $munkamenet["klubok"] tömbbe kerül. Ha ûrlapadatok érkeznek, azokkal
írjuk felül a korábbi tartalmát, ha nem érkezett ûrlap és már be van állítva, akkor
az $urlap tömböt írjuk felül a $munkamenet["klubok"] változóval. Ha egyik
feltétel sem teljesül, alapértékekkel töltjük fel.
Egy klubLista() függvényt hozunk létre, amelyben az adatbazis.inc
egy új függvényét, a klubokLekeres()-t hívjuk meg. Ez a függvény a klub
területére, illetve típusára vonatkozó elhagyható paramétereket vár.
24.6. program Részlet az adatbazis.inc fájlból
1: function klubokLekeres( $terulet="", $tipus="" )
2: {
3: global $kapcsolat;
4: $lekeres = "SELECT klubok.*, teruletek.terulet
as teruletnev, tipusok.tipus
as tipusnev ";
5: $lekeres .= "FROM klubok, teruletek,
tipusok WHERE ";
6: $lekeres .= "klubok.terulet=teruletek.azonosito
AND klubok.tipus=tipusok.azonosito ";
7: if ( $terulet != "BÁRMELY" &&
! empty( $terulet ) )
8: $lekeres .= "AND klubok.terulet=’$terulet’ ";
9: if ( $tipus != "BÁRMELY" && ! empty( $tipus ) )
10: $lekeres .= "AND klubok.tipus='$tipus' ";
11: $lekeres .= "ORDER BY klubok.terulet,
klubok.tipus, klubok.klubnev";
12: $eredmeny = mysql_query( $lekeres, $kapcsolat );
13: if ( ! $eredmeny )
14: die ( "klubokLekeres hiba: ".mysql_error() );
480 24. óra
24.6. program (folytatás)
15: $vissza = array();
16: while ( $sor = mysql_fetch_array( $eredmeny ) )
17: array_push( $vissza, $sor );
18: return $vissza;
19: }
A klubokLekeres() függvény paraméterei függvényében dinamikusan állít elõ
egy SQL utasítást. Alapesetben csupán összekapcsolja a klubok, teruletek és
tipusok táblákat. Ha üres karakterláncon és a "BÁRMELY" karaktersorozaton kí-
vül bármi mást kap a $terulet vagy $tipus paraméterekben, tovább szûkíti
az eredménytáblát a WHERE feltételhez adott újabb elemekkel. Végül egy kétdimenzi
ós tömbbel tér vissza.
A klubokinfo.php oldalon végiglépkedünk ezen a tömbön, kiírva
a teruletnev és tipusnev értékeket is a böngészõ számára. Mint eddig,
a klub neve most is egy hivatkozásban szerepel, amely a klubinfo.php
oldalra mutat.
klubinfo.php
A klubinfo.php oldal lehetõséget ad egyetlen klub minden adatának megtekint
ésére. Hivatkozások segítségével juthat ide a felhasználó, akár
az esemenyekinfo.php, az esemenyinfo.php vagy a klubokinfo.php
oldalakról is. Az oldalt az eddig megismert megoldások és függvények segítsé-
gével építhetjük fel, amint az alábbi kód mutatja.
24.7. program klubinfo.php
1: 2: include("adatbazis.inc");
3: include("kozosfv.inc");
4: if ( ! isset($kazonosito) )
5: header( "Location: klubokinfo.php?".SID );
6: $klub = klubLekeres( $kazonosito );
7:
8: $klub = html( $klub );
9: if ( $klub["email"] != "" )
10: $klub["email"] = "">".$klub["email"]."";
Teljes példa (második rész) 481
24
24.7. program (folytatás)
11: function klubEsemenyei ()
12: {
13: global $kazonosito;
14: $esemenyek = esemenyekLekeres( $kazonosito );
15: if ( ! $esemenyek )
16: {
17: print "Nincs megjeleníthetõ esemény

";
18: return;
19: }
20: print "

\n";
21: print "\n";
22: print "\n";
23: print "\n";
24: print "\n";
25: foreach ( $esemenyek as $sor )
26: {
27: print "\n";
28: print "\n";
29: print "\n";
30: print "\n";
31: print "\n";
32: print "\n";
33: }
34: print "
DátumEseményTerületTípus
".date("j M Y H.i",
$sor["edatum"])."
href=\"esemenyinfo.php?eazonosito=".
$sor["eazonosito"]."&".SID."\">".htm
l($sor["enev"])."
".$sor["teruletnev"]."".$sor["tipusnev"]."
\n";
35: }
36: ?>
37:
38:
39: Klub részletek
40:
41:
42: 43: include("kozosnav.inc");
44: ?>
45:


46:

Klub részletek


47:


482 24. óra
24.7. program (folytatás)
48:


49: Terület:
50:

51: Típus:
52:

53: Email:
54:


55: Ismertetõ:

56:
57:

58: 59: klubEsemenyei();
60: ?>
61:
62:
A program egy $azonosito paramétert vár, amely egy klub azonosítószámát kell,
hogy tartalmazza. Ha az oldal nem kapott ilyen paramétert, a felhasználót
a klubokinfo.php oldalra küldjük. A klub adatainak kiderítésére egy új
adatbazis.inc függvényt, a klubLekeres()-t alkalmazzuk. Ez a függvény
egy klubazonosítót vár és egy tömböt ad vissza:
24.8. program Részlet az adatbazis.inc fájlból
1: function klubLekeres( $kazonosito )
2: {
3: global $kapcsolat;
4: $lekeres = "SELECT klubok.*, teruletek.terulet
as teruletnev, tipusok.tipus
as tipusnev ";
5: $lekeres .= "FROM klubok, esemenyek, teruletek,
tipusok WHERE ";
6: $lekeres .= "klubok.terulet=teruletek.azonosito
7: AND klubok.tipus=tipusok.azonosito
8: AND klubok.azonosito='$kazonosito'";
9: $eredmeny = mysql_query( $lekeres, $kapcsolat );
10: if ( ! $eredmeny )
11: die ( "klubLekeres hiba: ".mysql_error() );
12: return mysql_fetch_array( $eredmeny );
13: }
Teljes példa (második rész) 483
24
A klub adatainak megszerzésére a sorLekeres() függvényt is használhattuk
volna. Azért készítettünk mégis egy célfüggvényt erre a feladatra, mivel így
az eredménytábla a teruletnev és tipusnev elemeket is tartalmazza majd.
Ezt a klubok, teruletek és tipusok táblák összekapcsolásával érhetjük el.
A klubLekeres()által visszaadott tömböt a $klub változóban tároljuk,
tartalmát pedig a HTML törzsrészében írjuk ki a böngészõ számára. Az oldalon
létrehozunk még egy klubEsemenyei() nevû függvényt is, amely a klubhoz
tartozó események kiírását végzi, felhasználva az esemenyekLekeres() néven
korábban létrehozott függvényünket. A klubinfo.php egy lehetséges kimenetét
a 24.2. ábra mutatja.
esemenyinfo.php
Az esemenyinfo.php az utolsó oldal, amit az alkalmazáshoz el kell készíten
ünk. Erre az oldalra bármely eseményinformációkat adó lapról el lehet jutni
egy hivatkozás segítségével. Az oldal minden információt megad
az $eazonosito segítségével kiválasztott eseményrõl.
484 24. óra
24.2. ábra
A klubinfo.php kimenete
24.9. program esemenyinfo.php
1: 2: include("adatbazis.inc");
3: include("kozosfv.inc");
4: if ( ! isset($eazonosito) )
5: header( "Location: esemenyeklista.php?".SID );
6: $esemeny = esemenyLekeres( $eazonosito );
7: html( $esemeny );
8: ?>
9:
10:
11: Esemény részletei
12:
13:
14: 15: include("kozosnav.inc");
16: ?>
17:


18:

Esemény részletei


19:


20:


21: Klub:
22:
23: $esemeny["eklub"]."&".SID."\">
24: $esemeny["klubnev"]"
25: ?>
26:

27:

28: Terület:
29:

30: Típus:
31:


32: Ismertetõ:

33:
34:
35:
Az eddigiek után ez az oldal már elég egyszerûnek látszik. Egyetlen új függvénnyel
találkozhatunk, az adatbazis.inc állomány esemenyLekeres() függvényével.
Ennek segítségével kapjuk meg az adott $eazonosito-hoz tartozó esemény részleteit.
Miután ezek egy tömbben rendelkezésre állnak, már csak ki kell írnunk azokat
a böngészõbe.
Teljes példa (második rész) 485
24
Az esemenyLekeres() függvényt a 24.10. példában láthatjuk. Tulajdonképpen
csupán egy egyszerû SQL lekérésbõl áll, amely a klubok és az esemenyek
táblákat kapcsolja össze.
24.10. program Részlet az adatbazis.inc fájlból
1: function esemenyLekeres( $eazonosito )
2: {
3: global $kapcsolat;
4: $lekeres = "SELECT klubok.klubnev as klubnev,
esemenyek.*, teruletek.terulet
as teruletnev, tipusok.tipus
as tipusnev ";
5: $lekeres .= "FROM klubok, esemenyek, teruletek,
tipusok WHERE ";
6: $lekeres .= "klubok.azonosito=esemenyek.eklub
7: AND esemenyek.eterulet=teruletek.azonosito
8: AND esemenyek.etipus=tipusok.azonosito
9: AND esemenyek.eazonosito='$eazonosito'";
10: $eredmeny = mysql_query( $lekeres, $kapcsolat );
11: if ( ! $eredmeny )
12: die ( "esemenyLekeres hiba: ".mysql_error() );
13: return mysql_fetch_array( $eredmeny );
14: }
A jövõ
Mostanra elkészültünk a teljes rendezvénynaptárral. Remélem sikerült érzékeltetni
ezzel a valós életbeli kisalkalmazások dinamikus kialakításának lehetõségeit és
a PHP szerteágazó képességeit.
Különösen érdemes megfigyelni, mennyire megkönnyítik munkánkat a PHP 4
munkameneteket kezelõ függvényei, mivel ezek használatával igen egyszerû
az adatok megõrzése kérésrõl kérésre .Ha a felhasználónk a munkamenet során
késõbb visszatér mondjuk az esemenyekinfo.php oldalra, pontosan azokat
a beállításokat fogja találni, mint amelyeket legutóbb otthagyott. A munkamenetf
üggvények nélkül feltehetõen sokkal több információt kellett volna kérésrõlk
érésre átadnunk oldalainknak az URL-ekben.
486 24. óra
Bár az eseménynaptár bizonyos megközelítésbõl teljesnek tekinthetõ, mindazon
által csak egy jó prototípus, amit meg tudunk mutatni a megrendelõnek, ahogy
haladunk a munkával. Az alkalmazás hasznára válna néhány további szolgáltatás,
különösképpen egy kulcsszavas keresés. Kellemes lenne lehetõséget adni a látogat
óknak, hogy megjegyzéseket fûzhessenek a rendezvényekhez. Ez új dimenziót
nyitna az alkalmazás számára, igazán érdekes környezetté alakítva azt.
Lehetõséget adhatnánk a tagok számára, hogy képekre mutató hivatkozásokat
helyezzenek el a klubok ismertetõiben. Akár azt is megoldhatnánk, hogy képeket
tölthessenek fel böngészõjük segítségével.
A tagok feltehetõen örülnének, ha az eseményeket lemásolhatnák vagy a rendezv
ények ismétlõdõ jellegét is kezelhetnék.
Mielõtt az alkalmazást átnyújtanánk a megbízónak, szükségünk lesz egy karbantart
ó felületre, amely alkalmas arra, hogy egy technikailag képzetlen adminisztr
átor is módosíthasson vagy törölhessen tagokat, illetve az eseményeket, valamint
a terület- és típuskategóriákat megváltoztathassa.
Valószínûleg feltûnt már, hogy programjaink kimenete eléggé spártai. Végül át kell
adnunk a munkát egy grafikus tervezõnek, aki ügyes vezérlõsávot, komoly grafik
át és más elemeket ad az oldalhoz. Szerencsére a legtöbb PHP kód külsõ állomá-
nyokban található, a HTML-tõl függetlenül, de elképzelhetõ, hogy szükség lesz
ránk is a ciklusok újraírásánál.
Összefoglalás
Ebben és az elõzõ órában elkészítettünk egy teljesen mûködõ többoldalas PHP
alkalmazást. Gyakoroltuk az állapot mentésének, a felhasználói azonosításnak,
az adatbázis-adatok módosításának és megjelenítésének módjait és sok más
kérdést is érintettünk.
Egy többoldalas alkalmazás végigvitele egy könyvben nem könnyû dolog, de
megéri a kitartást. Olyan kérdésekre adtunk válaszokat, olyan problémákat oldottunk
meg, amelyekkel munkánk során idõrõl idõre találkozni fogunk. Majdnem
minden programnak, amit írunk, egynél több felhasználó kéréseit kell majd
egyidõben kiszolgálnia, tehát ügyes megoldásokra van szükség az állapotok
mentésére.
Teljes példa (második rész) 487
24
Kérdések és válaszok
Ennyi volt. Hogyan tovább?
Ez már nem a könyvön múlik. Elég információt találhatunk ebben a könyvben
ahhoz, hogy saját kifinomult alkalmazásainkat el tudjuk készíteni. Ezzel és
a Világhálón elérhetõ rengeteg információval nincs, ami megállíthatna bárkit is
a fejlõdésben!
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. Melyik függvény használható új elem tömb végére való beszúrásához?
2. Lehetséges egy új elem felvétele a tömb végére függvény használata nélkül is?
3. Melyik függvény alkalmazható a különleges karakterek átalakítására HTMLki
írás céljából?
4. Melyik függvény alakítja át az újsor karaktereket
elemekké?
5. A SID állandó a munkamenet-azonosító oldalról-oldalra küldéséhez hivatkoz
ások készítésénél használható. Hogyan érhetõ el ugyanez a hatás ûrlap
készítésekor?
Feladatok
1. Tekintsünk végig az órában tárgyalt forráskódokon. Találunk olyan megoldá-
sokat, amiket fel tudunk használni saját programjainkban?
2. Lapozzuk át a könyvet és jegyzeteinket, ha írtunk ilyeneket. Jusson késõbb
eszünkbe, hogy érdemes kis idõ elteltével újra átnézni a jegyzeteket, hogy
minél több hasznunk legyen a befektetett munkából.

Teljes példa (elsõ rész)

Ha figyelmesen követtük az egyes órák anyagát, jó alapokkal rendelkezünk a PHP
programozáshoz. Ebben és a következõ órában egy teljes, mûködõ programot
készítünk, amely az elõzõ órákban tárgyalt eljárásokból építkezik.
Az órában a következõket tanuljuk meg:
• Hogyan készítsünk tervet?
• Hogyan használjuk az include() nyelvi szerkezetet, hogy függvénykönyvt
árakat és újrahasznosítható navigációs elemeket készítsünk?
• Hogyan tartsuk nyilván az állapotokat GET típusú lekérdezésekkel, adatbá-
zisokkal és munkamenet-függvényekkel?
• Hogyan válasszuk el a HTML és a PHP kódot, hogy a programozásban
járatlan grafikus is dolgozhasson az oldalon?
• Hogyan védjük meg szolgáltatásunk oldalait felhasználó-azonosítással?
A feladat rövid leírása
Tegyük fel, hogy egy közösségi webhely tulajdonosai felkértek bennünket, hogy
készítsünk el egy kis interaktív eseménynaptárt az általuk kiszolgált kisváros
számára. Klubok és együttesek jegyeztethetik be magukat, hogy reklámozzák
rendezvényeiket. A webhely felhasználói ezután különbözõ formákban kiírathatj
ák majd az adatbázist, hogy lássák, milyen rendezvények lesznek a városban.
A felhasználók képesek lesznek a lista szûkítésére a klubok típusa vagy akár
a szervezett rendezvény helye szerint is.
Az oldalak felépítése
Mielõtt akár egy sor kódot is írnánk, el kell döntenünk, hogyan fog mûködni
programunk. Milyen módon fogják elérni a felhasználók a rendszer különbözõ
elemeit? Milyen oldalakra van szükségünk?
A program természetesen két részre tagolódik. Az elsõ a tagok számára kialakított
terület, amely a klubok információinak kezelésére, új események hozzáadására
szolgál majd. A második a felhasználók területe, ahol az adatbázison lekérdezéseket
kell majd végrehajtani.
A 23.1. ábra az alkalmazás felépítését mutatja.
430 23. óra
A továbbiakban tagoknak nevezzük azokat a személyeket,
akik klubjukat bejegyezve felügyeleti feladatokat látnak el, és
felhasználóknak azokat az érdeklõdõket, akik a listákat böngészve
barangolnak a klubok és események között.
23.1. ábra
Az alkalmazás
felépítése
Az új tagok a csatlakozas.php oldalon csatlakozhatnak a rendszerhez (itt jegyeztethetik
be magukat a tagok közé), egy név–jelszó pár megadásával. Ha a vá-
lasztott név még nem foglalt, a leendõ tag a klubfrissites.php oldalra kerül,
ahol egy ûrlapon meg kell adnia a klubról a szükséges információkat. Amíg ki
nem tölti ezt az ûrlapot, nem vihet be új rendezvényeket a rendszerbe. Ha a tag
a hozzá tartozó klub adatait sikeresen bevitte, a tagok menüjéhez kerül
(tagmenu.php), ahonnan a tagok részére készített valamennyi oldal elérhetõ.
A már bejegyzett tagok a belépõ oldalról indulnak (belepes.php). Ha a megadott
név és jelszó helyesnek bizonyult, egyenesen a tagmenu.php oldalra kerülnek.
A menü oldalról indulva a tagok új rendezvényeket adhatnak a rendszerhez
(esemenyfrissites.php) és megtekinthetik az adatbázisban levõ rendezvé-
nyeik listáját (esemenylista.php). A klub adatait a klubfrissites.php
oldalon bármikor módosíthatják.
Minden felhasználó képes lesz az események hónapok, napok, típusok és terü-
letek alapján történõ rendezett kiíratására, egyetlen PHP oldal segítségével
(esemenyekinfo.php). Lehetõség lesz a klubok felsoroltatására is, terület vagy
típus alapján (klubokinfo.php). Végül a felhasználók egy klubra vagy
eseményre kattintva bõvebb információkat tudhatnak meg (esemenyinfo.php,
klubinfo.php).
Az adatbázis kialakítása
Az alkalmazás adatainak tárolásához létre kell hoznunk a szervezo adatbázist és
ebben négy táblát: klubok, esemenyek, teruletek, tipusok. Nyilvánvaló,
hogy a klubok és rendezvények adatait külön táblákban kell tárolnunk, hiszen
egy klubhoz több rendezvény is tartozhat. A területek és típusok számára kialak
ított táblák jelentõsen megkönnyítik a listázáshoz és adatbevitelhez szükséges
lenyíló menük kialakítását. A táblákat SQL parancsokkal hozzuk létre, „kézi úton”.
A klubok tábla a következõképpen hozható létre:
CREATE TABLE klubok (
azonosito INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
klubnev VARCHAR(50),
tipus CHAR(3),
terulet CHAR(3),
email VARCHAR(50),
ismerteto BLOB,
nev VARCHAR(8),
jelszo VARCHAR(8)
);
Teljes példa (elsõ rész) 431
23
A tagok a klubnev, email, ismerteto, nev és jelszo mezõk adatait fogják
megadni. A tipus és terulet mezõk értelemszerûen a tipusok és
teruletek megfelelõ soraira vonatkozó azonosítókat tartalmazzák majd.
Az esemenyek tábla az eseményekre vonatkozó valamennyi információt
tartalmazza:
CREATE TABLE esemenyek (
eazonosito INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
etipus CHAR(3),
eterulet CHAR(3),
edatum INT,
enev VARCHAR(100),
ehelyszin VARCHAR(100),
ecim VARCHAR(255),
eirsz CHAR(4),
eismerteto BLOB,
eklub INT NOT NULL
);
Vegyük észre, hogy ez a tábla is tartalmaz etipus és eterulet mezõket, hiszen
elõfordulhat, hogy egy klub a város északi részén található, de valamelyik rendezv
ényét a déli városrészben tartja. Egy társadalmi csoport tarthat oktatási szemináriumot,
de politikai találkozót is. Az eklub mezõ annak a klubnak az azonositó-
számát tartalmazza, amelyik az adott esemény szervezõje. A kapcsolat arra
használható fel, hogy egy klub összes rendezvényét felsoroljuk, illetve hogy elérj
ük az eseményhez köthetõ klub adatait.
A teruletek és tipusok táblák igen egyszerûek:
CREATE TABLE teruletek ( azonosito CHAR(3),
å terulet VARCHAR(30));
CREATE TABLE tipusok ( azonosito CHAR(3),
å tipus VARCHAR(30));
A tagok számára nem adunk lehetõséget ezen táblák módosítására, inkább elõre
meghatározott csoportokat alakítunk ki, melyeket INSERT SQL parancsokkal
adunk a táblákhoz. A tagok ezekbõl a listákból választhatnak majd.
INSERT INTO tipusok (azonosito, tipus) VALUES
å ("CSA", "Családi");
A 23.1. és 23.2. táblázatban az említett táblákba illesztendõ adatok láthatók.
432 23. óra
23.1. táblázat A teruletek táblához adott adatok
azonosito terulet
ESZ Észak
DEL Dél
KEL Kelet
NYU Nyugat
23.2. táblázat A tipusok táblához adott adatok
azonosito tipus
ZEN Zenei
CSA Családi
TRS Társadalmi
KZS Közösségi
Tervezési döntésünk
Az elõzõ bekezdésekben már láttuk, milyen szerkezetû alkalmazást készítünk.
Úgy döntöttünk, hogy a különbözõ szolgáltatásokhoz különbözõ PHP programokat
készítünk, ahelyett, hogy egyetlen hatalmas programot építenénk fel, amely a körülm
ényeknek megfelelõen más-más oldalakat szolgáltat. Ennek a döntésnek termé-
szetesen vannak elõnyei és hátrányai is.
Ha egy ilyen dinamikus környezetet több oldalból építünk fel, a kódok ismétlésének
hibájába eshetünk és a program növekedésével megnehezíthetjük a fejlesztõk dolgát.
Másrészt viszont a befejezett prototípust átadhatjuk grafikusainknak, akik majdnem
úgy kezelhetik azt, mintha pusztán HTML kódot tartalmazna.
A tagoknak szánt oldalak
Most már itt az ideje, hogy megkezdjük a kód írását. Az óra további részében
az alkalmazás tagoknak szánt oldalait készítjük el. Jó ötlet ezekkel kezdeni, mivel
így könnyebben vihetünk be próbaadatokat a rendszerbe. Mielõtt azonban
az adatbevitelt megkezdhetnénk, képesnek kell lennünk a tagok felvételére.
Teljes példa (elsõ rész) 433
23
csatlakozas.php és adatbazis.inc
A csatlakozas.php tartalmazza azt az ûrlapot, amelyen keresztül az új tagok
egy név és jelszó segítségével bejegyeztethetik klubjukat a rendszerbe. Ahhoz, hogy
felvehessük az adatokat és kiszûrhessük az ismétlõdéseket, elõször meg kell
nyitnunk egy kapcsolatot az adatbázis felé. Ez az ilyen alkalmazásoknak annyira
jellemzõ eleme, hogy célszerû külön függvényt készíteni erre a célra, melyet jelen
esetben egy külsõ állományban fogunk tárolni. Ezt a külsõ fájlt késõbb minden
oldalon az include() nyelvi elemmel illesztjük a kódba. Tulajdonképpen minden
adatbázissal kapcsolatos függvényt ebben tárolunk majd, ezért az adatbazis.inc
nevet kapja, szerepe és a beillesztés módja után. Ezzel a fájllal a további PHP oldalakat
mindennemû SQL parancstól mentesítjük.
Az adatbázissal kapcsolatot tartó kódok külön fájlba helyezése könnyebbé teszi
a program késõbbi módosítását vagy más adatbázismotorra való átültetését.
Elõfordulhat, hogy késõbb újra kell írnunk a függvényeket, de a hívó kódok
módosítására nem lesz szükség.
Hozzuk létre a függvényt, amely végrehajtja a csatlakozást:
23.1. program Részlet az adatbazis.inc fájlból
1: $kapcsolat;
2: dbCsatlakozas();
3: function dbCsatlakozas()
4: {
5: global $kapcsolat;
6: $kapcsolat = mysql_connect( "localhost",
"felhasznalo", "jelszo" );
7: if ( ! $kapcsolat )
8: die( "Nem lehet csatlakozni a MySQL-hez" );
9: mysql_select_db( "szervezo", $kapcsolat )
10: or die ( "Nem lehet megnyitni az adatbázist:
".mysql_error() );
11: }
A dbCsatlakozas() függvény a $kapcsolat globális változót használja arra,
hogy a mysql_connect() által visszaadott kapcsolatazonosítót tárolja. Mivel
a változó globális, a többi adatbázisfüggvény is elérheti. Nem csupán a MySQL
kiszolgálóhoz csatlakozunk ebben a függvényben, hanem megpróbáljuk kivá-
lasztani a szervezo adatbázist is. Mivel ezen mûveletek sikere döntõ fontosságú
a teljes alkalmazás mûködése szempontjából, a mysql_connect() vagy
mysql_select_db() végrehajtásának kudarca esetén befejezzük a program
futását.
434 23. óra
A munkamenetek követése és az azonosítással kapcsolatos feladatokat ellátó függv
ények számára egy újabb külsõ állományt használunk. A munkamenet-függvényeket
arra használjuk, hogy egy $munkamenet nevû asszociatív tömböt õrizzünk
meg kérésrõl kérésre. A kozosfv.inc állomány session_start() függvénye
arra szolgál, hogy megkezdjünk vagy folytassunk egy munkamenetet, a változónkat
pedig a session_register() függvénnyel rendeljük ehhez:
23.2. program Részlet a kozosfv.inc fájlból
1: session_start();
2: session_register( "munkamenet" );
Emlékezzünk rá, hogy minden PHP kód, amit ezen külsõ fájlokba írunk, PHP blokk
kezdõ () elemek között kell, hogy legyen. Értelmetlen bonyolí-
tásnak tûnhet, hogy a különbözõ szolgáltatásokat külsõ állományokba helyezzük,
de ez rengeteg kódismétléstõl kímél majd meg bennünket, amikor oldalainkat elké-
szítjük. Most már készen állunk a csatlakozas.php oldal megírására.
23.3. program csatlakozas.php
1: 2: include("adatbazis.inc");
3: include("kozosfv.inc");
4:
5: $uzenet="";
6:
7: if ( isset( $mitkelltenni ) &&
$mitkelltenni=="csatlakozas")
8: {
9: if ( empty( $urlap["nev"] ) ||
10: empty( $urlap["jelszo"] ) ||
11: empty( $urlap["jelszo2"] ) )
12: $uzenet .= "Ki kell töltenie minden
mezõt!
\n";
13:
14: if ( $urlap["jelszo"] != $urlap["jelszo2"] )
15: $uzenet .= "A jelszavak nem
egyeznek!
\n";
16:
Teljes példa (elsõ rész) 435
23
23.3. program (folytatás)
17: if ( strlen( $urlap["jelszo"] ) > 8 )
18: $uzenet .= "A jelszó hossza legfeljebb
19: 8 karakter lehet!
\n";
20:
21: if ( strlen( $urlap["nev"] ) > 8 )
22: $uzenet .= "A tagsági név hossza
legfeljebb
23: 8 karakter lehet!
\n";
24:
25: if ( sorLekeres( "klubok", "nev",
$urlap["nev"] ) )
26: $uzenet .= "A megadott tagsági néven.\""
$urlap["nev"] ."\"
27: már van bejegyzett tagunk.
28: Kérjük, adjon meg más
nevet!
\n";
29:
30: if ( $uzenet == "" ) // nem találtunk hibát
31: {
32: $azon = ujTag( $urlap["nev"],
$urlap["jelszo"] );
33: munkamenetFeltoltes( $azon, $urlap["nev"],
$urlap["jelszo"] );
34:
35: header( "Location:
klubfrissites.php?".SID );
36: exit;
37: }
38: }
39: ?>
40:
41:
42:
43: Csatlakozás
44:
45:
46:
47: 48: include("kozosnav.inc");
49: ?>
50:


51:

Csatlakozás


436 23. óra
23.3. program (folytatás)
52:
53: 54: if ( $uzenet != "" )
55: {
56: print "$uzenet

";
57: }
58: ?>
59:
60:


61:


62: value="csatlakozas">
63: 64: value="">
65: Tagsági név:

66: 67: value=""
maxlength=8>
68:


69:


70: Jelszó:

71: value="" maxlength=8>
72:


73:


74: Jelszó megerõsítés:

75: value="" maxlength=8>
76:


77:


78:
79:


80:

81:
82:
83:
Elõször az include() használatával beillesztjük a külsõ állományokat, tehát
azonnal rendelkezésünkre áll egy adatbáziskapcsolat és egy aktív munkamenet.
Létrehozunk egy $uzenet nevû változót. Ezzel a kettõs célú változóval még
Teljes példa (elsõ rész) 437
23
számos más oldalon találkozni fogunk. Az $uzenet célja egyrészt, hogy tartalmazza
a hibaüzenetet, amit késõbb kiírhatunk a böngészõ számára, másrészt haszn
álhatjuk feltételes kifejezésekben, hogy ellenõrizzük, volt-e hibaüzenet vagy sem.
Ha a változó üres marad, feltételezhetjük, hogy minden ellenõrzés sikeresen
végrehajtódott.
Ezután a $mitkelltenni változó létezését és tartalmát vizsgáljuk. Ez is olyan
elem, amely többször felbukkan majd az alkalmazásban. Minden általunk készített
ûrlapon beállítunk egy mitkelltenni nevû rejtett elemet és egy, az adott szolgáltat
ásra vonatkozó értéket adunk neki. Ha PHP programunkban a $mitkelltenni
változó létezik és a várt érték található benne, biztosak lehetünk abban, hogy az ûrlapot
kitöltötte valaki, így folytathatjuk a programot az ûrlap adatainak ellenõrzésé-
vel. Ha a változó nem létezik, tudhatjuk, hogy a látogató egy hivatkozáson keresztül
vagy a böngészõjében lévõ könyvjelzõ révén érkezett az oldalra és nem töltötte ki
az ûrlapot.
Egyelõre ugorjunk a HTML rész tárgyalására. A body HTML elemen belül elõször
egy újabb külsõ fájlt illesztünk be, amely a különbözõ oldalakra mutató hivatkozá-
sokat tartalmazza. Célszerû már a kezdetektõl beilleszteni a navigációs sávot, mivel
ez megkönnyíti az alkalmazás ellenõrzését, ahogy folyamatosan fejlesztjük azt.
A navigációs elemeket a kozosnav.inc nevû állományban helyezzük el.
Egyelõre ez a fájl csak a látogatók számára is elérhetõ oldalakra mutató hivatkoz
ásokat tartalmazza.
23.4. program Részlet a kozosnav.inc fájlból
1:


2: Klubinformációk |
3: Eseményinformációk |
4: Csatlakozás |
5: Belépés |
6: Honlap
7:


Azzal, hogy a navigációs elemeket külön állományba helyezzük, egyetlen mozdulattal
módosíthatjuk a hivatkozásokat, illetve az elemek kinézetét a teljes alkalmaz
ásra vonatkozóan.
438 23. óra
Visszatérve a csatlakozas.php oldalra, miután kiírjuk az oldal címsorát, ellen-
õrizzük az $uzenet változót. Ha nem üres, kiírjuk a tartalmát a böngészõ számára.
Az összegyûjtött hibaüzenetek kiírásával jelezhetjük a tagnak, hogy a bevitt adatok
nem dolgozhatók fel.
A HTML ûrlap elemei között három látható mezõt hoztunk létre, az urlap[nev],
urlap[jelszo] és urlap[jelszo2] mezõket. Azért használjuk ezeket
az elsõre esetleg furcsának látszó elnevezéseket, mert a PHP az így megadott
nevekkel érkezõ értékeket egy asszociatív tömbbe rendezi, amit $urlap néven
érhetünk majd el. Ez megóv bennünket attól, hogy a globális változók környezetét
„beszennyezzük”, azaz feleslegesen sok globális változót hozzunk létre. Programjainkban
így minden munkamenet-érték a $munkamenet asszociatív tömbben,
az ûrlapértékek pedig az $urlap asszociatív tömbben érhetõk el. Ez megvéd
bennünket a változók ütközésétõl. Célszerû a lehetõ legkevesebbre csökkenteni
a globális változók számát egy ilyen méretû programban, hogy megelõzzük
a kavarodást. A továbbiakban minden ûrlapot tartalmazó oldalon az $urlap
tömbbel fogunk találkozni.
Az ûrlapban létrehozzuk a már korábban említett mitkelltenni rejtett elemet is,
valamint egy másikat, amely a munkamenet nevét és értékét tartalmazza majd.
Az alkalmazás elkészítése során mindig oldalról-oldalra fogjuk adni a munkamenetazonos
ítót, mivel nem kívánjuk elveszteni azokat a látogatókat, akik nem tudnak
vagy nem akarnak sütiket fogadni.
Most, hogy megnéztük a HTML ûrlapot, rátérhetünk arra a kódra, amely a bemenõ
adatok ellenõrzését végzi. Elõször meg kell bizonyosodnunk róla, hogy a leendõ
tag valóban kitöltötte-e az összes mezõt és hogy egyik mezõ hossza sem haladja
meg a nyolc karaktert. Ezután meghívjuk az új sorLekeres() függvényt.
Ez azon függvények egyike, amelyek az adatbazis.inc fájlban találhatók.
Elsõ paramétere egy táblanév, a második egy mezõnév, a harmadik egy érték.
Ezen adatok alapján a függvény egy illeszkedõ sort keres az adatbázisban,
visszaadva azt egy tömbben.
Teljes példa (elsõ rész) 439
23
Ha munkameneteket használó programokat ellenõrzünk,
célszerû kikapcsolni a böngészõben a sütik elfogadását.
Így pontosan tudni fogjuk, hogy a munkamenet azonosítóját
sikeresen át tudjuk-e adni oldalról oldalra ezen szolgáltatás
nélkül is vagy sem.
23.5. program Részlet az adatbazis.inc fájlból
1: function sorLekeres( $tabla, $mezonev, $mezoertek )
2: {
3: global $kapcsolat;
4: $eredmeny = mysql_query( "SELECT * FROM $tabla
WHERE $mezonev='$mezoertek'",
$kapcsolat );
5: if ( ! $eredmeny )
6: die ( "sorLekeres hiba: ".mysql_error() );
7: return mysql_fetch_array( $eredmeny );
8: }
A függvénynek a klubok táblanevet, a nev mezõnevet és a látogatók által bevitt
$urlap["nev"] mezõértéket adjuk át. Ha a mysql_fetch_array() nem
üres tömböt ad vissza, tudhatjuk, hogy egy ilyen belépési névvel rendelkezõ tag
már van a rendszerben, ezért hibaüzenetet kell adnunk.
Ha az ellenõrzések után az $uzenet változó még mindig üres, létrehozhatjuk
az új tagot a bevitt adatokkal. Ez két lépésbõl tevõdik össze. Elõször is frissíteni kell
az adatbázist. Ehhez egy új függvény tartozik az adatbazis.inc állományból,
ujTag() néven:
23.6. program Részlet az adatbazis.inc fájlból
1: function ujTag( $nev, $jelszo )
2: {
3: global $kapcsolat;
4: $eredmeny = mysql_query( "INSERT INTO klubok
(nev, jelszo)
5: VALUES('$nev', '$jelszo')",
$kapcsolat);
6: return mysql_insert_id( $kapcsolat );
7: }
A függvény egy név és egy jelszó paramétert vár, majd ezeket új sorként felveszi
a klubok táblájába. A függvény a mysql_insert_id()-t használja, hogy
megkapja a felvett új tag azonosítóját.
440 23. óra
Mivel már rendelkezünk az új tag azonosítójával, meghívhatjuk a felvételéhez
szükséges újabb függvényt, ami a kozosfv.inc fájlban található.
A munkamenetFeltoltes() függvény egy azonosítót, egy belépési nevet és
egy jelszót vár paraméterül és hozzáadja azokat a $munkamenet tömbhöz.
Így ezek az értékek már elérhetõek lesznek minden munkamenetet kezelõ oldalunk
számára. Ezzel képesek leszünk a tag azonosítására a további oldalakon is.
23.7. program Részlet a kozosfv.inc fájlból
1: function munkamenetFeltoltes( $azonosito, $nev,
$jelszo )
2: {
3: global $munkamenet;
4: $munkamenet["azonosito"] = $azonosito;
5: $munkamenet["nev"] = $nev;
6: $munkamenet["jelszo"] = $jelszo;
7: $munkamenet["belepett"] = true;
8: }
Az azonosító, név és jelszó megadása mellett a belépési állapotot jelzõ értéket
(belepett) is beállítjuk a munkameneteket kezelõ oldalaink számára.
Végül, miután a csatlakozas.php oldal frissítette az adatbázist és a munkamenethez
rendelt értékeket, útjára engedhetjük új tagunkat. Meghívjuk a header()
függvényt, átirányítva a böngészõt a klubfrissites.php oldalra, ahol a tagnak
be kell majd állítania az újonnan bejegyzett klub részletes adatait.
A csatlakozas.php kimenetét a 23.2. ábrán láthatjuk.
Teljes példa (elsõ rész) 441
23
23.2. ábra
A csatlakozas.php
kimenete
klubfrissites.php
Ez az oldal kettõs célt szolgál. Egyrészt az új tagoknak itt kell megadniuk a klub
részletes adatait, a bejegyzett tagok pedig itt módosíthatják ezeket.
23.8. program klubfrissites.php
1: 2: include("adatbazis.inc");
3: include("kozosfv.inc");
4:
5: $klub_sor = azonositas();
6:
7: $uzenet = "";
8:
9: if ( isset( $mitkelltenni ) &&
$mitkelltenni=="frissites" )
10: {
11: if ( empty( $urlap["klubnev"] ) )
12: $uzenet .="A klubnév mezõ nincs
kitöltve!
\n";
13:
14: if ( ! sorLekeres( “teruletek”, “azonosito”,
$urlap["terulet"] ) )
15: $uzenet .= "KRITIKUS HIBA: A terület kódja
nem található!
";
16:
17: if ( ! sorLekeres( "tipusok", "azonosito",
$urlap["tipus"] ) )
18: $uzenet .= "KRITIKUS HIBA: A típus kódja
nem található!
";
19:
20: if ( $uzenet == "" )
21: {
22: klubFrissites( $munkamenet["azonosito"],
$urlap["klubnev"],
$urlap["terulet"],
23: $urlap["tipus"],
$urlap["email"],
$urlap["ismerteto"] );
24: header("Location: tagmenu.php?".SID);
25: exit;
26: }
27: }
442 23. óra
23.8. program (folytatás)
28: else
29: {
30: $urlap = $klub_sor;
31: }
32: ?>
33:
34:
35:
36: Klubinformációk frissítése
37:
38:
39:
40: 41: include("kozosnav.inc");
42: ?>
43:

Klubinformációk frissítése


44: 45: if ( $uzenet != "" )
46: {
47: print "$uzenet

";
48: }
49: ?>
50:
51:


52: value="frissites">
53: 54: value="">
55:
56:


57: Klub neve:

58: 59: value="stripslashes($urlap["klubnev"]) ?>">
60:


61:


62: Klub helye:

63:
66:


67:


68: Klub típusa:

69:
72:


73:


74: Kapcsolattartó e-mail címe:

75: 76: value="stripslashes($urlap["email"]) ?>">
77:


78:


79: Klub ismertetõje:

80:
83:


84:


85:
86:


87:

88:
89:
90:
Beillesztjük az adatbazis.inc és kozosfv.inc nevû külsõ állományainkat,
így rögtön kész adatbáziskapcsolattal és munkamenettel kezdjük az oldalt. Ezután
meghívjuk az új azonositas() nevû függvényt, ami a kozosfv.inc fájlban
található. Ez összehasonlítja a munkamenet adatait az adatbázissal.
23.9. program Részlet a kozosfv.inc fájlból
1: function azonositas( )
2: {
3: global $munkamenet, $belepett;
4: $munkamenet["belepett"] = false;
444 23. óra
23.9. program (folytatás)
5: $klub_sor = sorLekeres( "klubok", "azonosito",
$munkamenet["azonosito"] );
6: if ( ! $klub_sor ||
7: $klub_sor["nev"] != $munkamenet["nev"] ||
8: $klub_sor["jelszo"] != $munkamenet["jelszo"] )
9: {
10: header( "Location: belepes.php" );
11: exit;
12: }
13: $munkamenet["belepett"] = true;
14: return $klub_sor;
15: }
Az azonositas() jól átlátható függvény. A $munkamenet["azonosito"] elem
ét használjuk arra, hogy a sorLekeres() függvény segítségével lekérjük a klubhoz
tartozó sort az adatbázisból. Ezt a $klub_sor asszociatív tömbben tároljuk és
ellenõrizzük a nev és jelszo elemek egyezését a $munkamenet megfelelõ tömbelemeivel.
Ha nem egyeznek, a belepes.php oldalra küldjük a tagot.
Miért vállaljuk fel az adatbázis lekérdezésének költségét az azonosításhoz? Miért
nem egyszerûsítjük a problémát a belepett elem ellenõrzésére? Ez visszaéléseknek
engedne teret, mivel egy rosszindulatú látogató egyszerûen hozzáadhatna az
oldal címéhez egy ilyen részt:
munkamenet%5Bbelepett%5D=1&munkamenet%5Bazonosito%5D=1
így átvéve az 1-es azonosítóval rendelkezõ tag fölött az irányítást, a PHP ugyanis
ezt a $munkamenet tömbbé alakítja, amely egy felületesebb ellenõrzésen túljuthatna.
A rosszindulatú látogató most is alkalmazhat egy hasonló trükköt, hogy
belépést nyerjen, de mivel az adatbázisban lévõ névvel és jelszóval történõ egyez
ést vizsgáljuk, a „hamisított” $munkamenet változónak helyes tartalommal kell
rendelkeznie, így pedig felesleges a csalás.
Az azonositas() függvény mellékterméke a visszaadott tömb, amely a kérdéses
klubról az adatbázisban található összes adatot tartalmazza. Késõbb az oldalak ezt
az információt saját céljaikra használhatják fel. Miután az azonositas() függv
ény visszatér a klub adatait tartalmazó tömbbel, ezt a $klub_sor változónak
adjuk értékül.
Ismételten ugorjunk a HTML részre. Itt elõször a kozosnav.inc állományt
illesztjük be. Ebben a fájlban azonban továbblépünk az eddigieknél és szerepeltetj
ük a tagok menüjét is:
Teljes példa (elsõ rész) 445
23
23.10. program kozosnav.inc
1:


2:
Klubinformációk
|
3:
Eseményinformációk
|
4:
Csatlakozás
|
5: Belépés |
6: Honlap
7:


8: 9: if ( $munkamenet["belepett"] )
10: {
11: ?>
12:


13: ">
Bejegyzett események
|
15:
Új esemény
|
16:
Tagok honlapja

17:


18: 19: }
20: ?>
21:

Ha a $munkamenet["belepett"] igazra van állítva, a csak tagok számára
megjelenítendõ hivatkozásokat is kiírjuk. Vegyük észre, hogy minden hivatkozásban
megadjuk a SID állandót. Ez tartalmazza a munkamenet nevét és azonosító-
ját, így biztosítjuk, hogy az azonosító oldalról-oldalra átadódjon, még akkor is, ha
a sütik nincsenek bekapcsolva.
A klubfrissites.php oldal ûrlapja igazán figyelemreméltó. Az eddigieknek
megfelelõen a mitkelltenni és a munkamenetet azonosító rejtett mezõket is
felvesszük az ûrlapba. Szövegmezõket biztosítunk a klub neve, ismertetõje és
a kapcsolattartó elektronikus levélcíme számára. A klubtípusok és területek
lenyíló menüinek elõállítására egy új függvény, az optionLista() szolgál.
446 23. óra
23.11. program Részlet az adatbazis.inc fájlból
1: function optionLista( $tabla, $azon )
2: {
3: global $kapcsolat;
4: $eredmeny = mysql_query( "SELECT * FROM $tabla",
$kapcsolat );
5: if ( ! $eredmeny )
6: {
7: print "Nem lehet megnyitni: $tabla

";
8: return false;
9: }
10: while ( $egy_sor = mysql_fetch_row( $eredmeny ) ){
11: print "

Tagok honlapja


20:
21:
Klub részletei


22:
Bejegyzett események


23:
Új esemény


24:
25:
26:
Az oldalon egyetlen újdonság található. Miután meghívjuk az azonositas()
függvényt, hogy meggyõzõdjünk róla, hogy a látogatónk tag, az általa visszaadott
tömböt egy új függvénynek adjuk át. Ez a függvény, a klubAdatEllenorzes(),
a kozosfv.inc állományban található és azt ellenõrzi, hogy a tag megadta-e már
a klub adatait. Amíg egy tag ki nem tölti legalább a klub nevét, nem adhat rendezv
ényeket a rendszerhez.
Teljes példa (elsõ rész) 449
23
23.14. program Részlet a kozosfv.inc fájlból
1: function klubAdatEllenorzes( $klubtomb )
2: {
3: if ( ! isset( $klubtomb["klubnev"] ) )
4: {
5: header( "Location: klubfrissites.php?".SID );
6: exit;
7: }
8: }
belepes.php
Mielõtt továbblépünk a rendezvényeket kezelõ oldalakra, el kell készítenünk
a belepes.php programot. Ez az oldal ad lehetõséget a bejegyzett tagoknak,
hogy a késõbbiekben belépjenek a rendszerbe.
23.15. program belepes.php
1: 2: include("adatbazis.inc");
3: include("kozosfv.inc");
4:
5: $uzenet="";
6:
7: if ( isset( $mitkelltenni ) && $mitkelltenni ==
"belepes" )
8: {
9: if ( empty( $urlap["nev"] ) || empty(
$urlap["jelszo"] ) )
10: $uzenet .= "Ki kell töltenie minden
mezõt!
\n";
11:
12: if ( ! ( $sor_tomb =
13: jelszoEllenorzes( $urlap["nev"],
$urlap["jelszo"] ) ) )
14: $uzenet .= "Hibás név vagy jelszó, próbálkozzon
újra!
\n";
15:
450 23. óra
23.15. program (folytatás)
16: if ( $uzenet == "" ) // nem találtunk hibát
17: {
18: munkamenetFeltoltes( $sor_tomb["azonosito"],
$sor_tomb["nev"],
19: $sor_tomb["jelszo"] );
20: header( "Location: tagmenu.php?".SID );
21: }
22: }
23: ?>
24:
25:
26:
27: Belépés
28:
29:
30:
31:
32: 33: include("kozosnav.inc");
34: ?>
35:
36:

Belépés


37:
38: 39: if ( $uzenet != "" )
40: {
41: print "

$uzenet

";
42: }
43: ?>
44:
45:


46:


47: value="belepes">
48: 49: value="">
50:


51: Tagsági név:

52: 53: value="">
Teljes példa (elsõ rész) 451
23
23.15. program (folytatás)
54:


55: Jelszó:

56: value="">
57:


58:
59:


60:
61:
62:
Az oldal szerkezete már ismerõs kell, hogy legyen. Az adatbazis.inc és
kozosfv.inc állományokat használjuk, hogy adatbáziskapcsolatot létesítsünk és
aktív munkamenettel rendelkezzünk.
Ha a $mitkelltenni változó be van állítva és a várt "belepes" értéket
tartalmazza, ellenõrizzük az ûrlapról érkezett adatokat. Az új adatbazis.inc
függvényt használjuk arra, hogy az urlap["nev"] és urlap["jelszo"] érté-
keket vizsgáljuk.
23.16. program Részlet az adatbazis.inc fájlból
1: function jelszoEllenorzes( $nev, $jelszo )
2: {
3: global $kapcsolat;
4: $eredmeny = mysql_query( "SELECT azonosito, nev,
jelszo FROM klubok
5: WHERE nev='$nev' and
jelszo='$jelszo'",
6: $kapcsolat );
7: if ( ! $eredmeny )
8: die ( "jelszoEllenorzes hiba: "
.mysql_error() );
9: if ( mysql_num_rows( $eredmeny ) )
10: return mysql_fetch_array( $eredmeny );
11: return false;
12: }
452 23. óra
A jelszoEllenorzes() egy belépési nevet és egy jelszót vár. Ezek felhaszná-
lásával egy egyszerû SELECT lekérdezést küld az adatbázisnak a klubok táblájára
vonatkozóan.
Visszatérve a belepes.php oldalra, ha nem találunk hibát, meghívjuk
a munkamenetFeltoltes() függvényt, amely beállítja az azonosito, nev,
jelszo és belepett elemeket a $munkamenet tömbben. Ezután a tagot átirá-
nyítjuk a tagmenu.php oldalra.
esemenyfrissites.php
Most, hogy a tagok már képesek csatlakozni és belépni a rendszerbe, valamint
módosítani is tudják az adataikat, lehetõséget kell adnunk a rendezvények bevitelére
és módosítására. A teljes esemenyfrissites.php oldal a 23.17. programban
látható.
23.17. program esemenyfrissites.php
1: 2: include("adatbazis.inc");
3: include("kozosfv.inc");
4: include("datum.inc");
5:
6: $klub_sor = azonositas();
7: klubAdatEllenorzes( $klub_sor );
8:
9: $edatum = time();
10: $uzenet = "";
11:
12: if ( ! empty( $eazonosito ) )
13: $esemeny_sor = sorLekeres( "esemenyek",
"eazonosito", $eazonosito );
14: else
15: $eazonosito = false;
16:
17: if ( isset( $mitkelltenni ) &&
$mitkelltenni=="esemenyFrissites" )
18: {
19: if ( empty( $urlap["enev"] ) )
20: $uzenet .="Az eseménynek névvel kell
rendelkeznie!
\n";
21:
Teljes példa (elsõ rész) 453
23
23.17. program (folytatás)
22: if ( ! sorLekeres( "teruletek", "azonosito",
$urlap["eterulet"] ) )
23: $uzenet .= "KRITIKUS HIBA: A terület
kódja nem található!
";
24:
25: if ( ! sorLekeres( "tipusok", "azonosito",
$urlap["etipus"] ) )
26: $uzenet .= "KRITIKUS HIBA: A típus
kódja nem található!
";
27:
28: foreach ( array( "ehonap", "eev", "enap",
"eperc" )
29: as $datum_egyseg )
30: {
31: if ( ! isset( $urlap[$datum_egyseg] ) )
32: {
33: $uzenet .= "KRITIKUS HIBA: A dátum
nem értelmezhetõ!";
34: break;
35: }
36: }
37: $edatum = mktime( $urlap["eora"],
$urlap["eperc"], 0,
$urlap["ehonap"],
38: $urlap["enap"], $urlap["eev"] );
39:
40: if ( $edatum < time() )
41: $uzenet .= "Múltbeli dátum nem
fogadható el!";
42:
43: if ( $uzenet == "" )
44: {
45: esemenyModositas( $urlap["enev"],
$urlap["ehelyszin"],
$urlap["eterulet"],
46: $urlap["etipus"],
$urlap["ecim"], $urlap["eirsz"],
47: $urlap["eismerteto"],
$munkamenet["azonosito"],
$edatum,
48: $eazonosito );
49: header( "Location:
esemenylista.php?".SID );
50: }
454 23. óra
23.17. program (folytatás)
51: }
52: elseif ( $eazonosito )
53: {
54: //foreach( $esemeny_sor as $kulcs=>$ertek )
55: // $urlap[$kulcs] = $ertek;
56: $urlap = $esemeny_sor;
57: $edatum = $esemeny_sor["edatum"];
58: }
59: else
60: {
61: $urlap["eterulet"] = $klub_sor["terulet"];
62: $urlap["etipus"] = $klub_sor["tipus"];
63: }
64: ?>
65:
66:
67:
68: Esemény hozzáadása/frissítése
69:
70:
71:
72: 73: include("kozosnav.inc");
74: ?>
75:
76:

Esemény hozzáadása/frissítése


77:
78: 79: if ( $uzenet != "" )
80: {
81: print "$uzenet";
82: }
83: ?>
84:


85:


86: value="esemenyFrissites">
87: 88: value="">
Teljes példa (elsõ rész) 455
23
23.17. program (folytatás)
89: 90: value="">
91: Esemény neve:

92: 93: value="stripslashes($urlap["enev"]) ?>">
94:


95:


96: Dátum és idõ:

97:
100:
101:
104:
105:
108:
109:
112:
113:
116:


117:


118: Esemény helye:

119:
122:


123:


124: Esemény típusa:

125:
456 23. óra
23.17. program (folytatás)
128:


129:


130: Esemény ismertetõje:

131:
134:


135:


136: Helyszín:

137: 138: value="stripslashes($urlap["ehelyszin"])?>">
139:


140:


141: Helyszín címe:

142:
145:


146:


147: Helyszín irányítószáma:

148: 149: value="stripslashes($urlap["eirsz"]) ?>">
150:


151:


152:
153:


154:

155:
156:
157:
Ezen az oldalon az esemenyek táblának megfelelõ elemekkel készítünk egy ûrlapot.
Szokás szerint ellenõriznünk kell a beérkezõ értékeket és frissítenünk kell az adatbá-
zist. Ha azonban az oldal meghívása alapján úgy ítéljük, hogy nem esemény hozzá-
adása a cél, hanem módosítás, akkor le kell kérdeznünk az adatbázisból a módosí-
tandó adatokat. Az oldal meghívása során az $eazonosito változót kapja,
Teljes példa (elsõ rész) 457
23
ha egy meglévõ esemény módosítását kell elvégezni. Ha a változó nem üres,
a sorLekeres() függvényt alkalmazva kapjuk meg az $esemeny_sor tömbben
a rendezvény adatait. Ha az $eazonosito nincs megadva vagy üres, akkor hamis
értékre állítjuk.
Ha az oldal ûrlapkitöltés hatására hívódott meg, ellenõriznünk kell a beérkezett
adatokat. A dátummal kapcsolatban meg kell vizsgálnunk, hogy az nem egy múltbeli
érték-e. Ennek érdekében beállítunk egy $edatum nevû globális változót
a beadott adatok függvényében.
Ha az adatok megfelelnek az általunk támasztott követelményeknek,
az adatbazis.inc egy új függvényét hívjuk meg, melynek neve
esemenyModositas(). Ez a függvény minden olyan értéket vár, amit
az esemenyek táblában el kell helyeznünk. Az utolsó paraméter a rendezvény
azonosítószáma. Ezt az esemenyModositas() függvény arra használja, hogy
megállapítsa, új eseményt kell felvennie vagy módosítania kell egy már létezõt.
Figyeljük meg, hogy a klub azonosítószáma a $munkamenet["azonosito"]
változóban található, így ezt helyezzük az esemenyek tábla eklub mezõjébe.
A dátum adatbázisban történõ tárolására idõbélyeget használunk.
23.18. program Részlet az adatbazis.inc fájlból
1: function esemenyModositas( $enev, $ehelyszin,
$eterulet, $etipus, $ecim, $eirsz,
$eismerteto, $eklub, $edatum, $eazonosito )
2: {
3: global $kapcsolat;
4: if ( ! $eazonosito )
5: {
6: $lekeres = "INSERT INTO esemenyek (enev,
ehelyszin, eterulet, etipus,
7: ecim, eirsz, eismerteto, eklub,
edatum )
8: VALUES( '$enev', '$ehelyszin',
'$eterulet', '$etipus',
'$ecim',
9: '$eirsz', '$eismerteto', '$eklub',
'$edatum')";
10: }
11: else
12: {
458 23. óra
23.18. program (folytatás)
13: $lekeres = "UPDATE esemenyek SET enev='$enev',
ehelyszin='$ehelyszin',
14: eterulet='$eterulet',
etipus='$etipus',
ecim='$ecim',
eirsz='$eirsz',
15:
eismerteto='$eismerteto', eklub='$eklub', edatum='$edatum'
16: WHERE eazonosito='$eazonosito'";
17: }
18: $eredmeny = mysql_query( $lekeres, $kapcsolat );
19: if ( ! $eredmeny )
20: die ( "esemenyModositas hiba: "
.mysql_error() );
21: }
Látható, hogy a függvény az $eazonosito paraméter értékétõl függõen mûködik.
Ha hamis értékû, egy INSERT SQL parancs hajtódik végre a megadott adatokkal.
Egyéb esetben az $eazonosito egy UPDATE kérés feltételében szerepel.
Miután az adatbázist frissítettük, a tagot az esemenylista.php oldalra irányítjuk,
ahol a teljes rendezvénynaptárt láthatja.
Ha a tag még nem töltötte ki az ûrlapot, átugorjuk az ellenõrzõ és adatbázis-frissítõ
kódokat. Ha azonban rendelkezünk az $eazonosito változóval, már lekértük
az esemény információit az adatbázisból és az ûrlapra írhatjuk azokat. Ezt úgy tehetj
ük meg, hogy az $esemeny_sor változót értékül adjuk az $urlap változónak,
az $edatum változót pedig az $esemeny_sor["edatum"] értékével töltjük fel.
Ha nem kaptunk ûrlapértékeket és $eazonosito változónk sincs,
az $urlap["terulet"] és $urlap["tipus"] elemeknek a klubnak megfelel
õ adatokat adjuk értékül a $klub_sor tömbbõl. Ezzel a megfelelõ lenyíló men
ükben a klubokhoz tartozó értékek lesznek alapbeállításban kiválasztva.
A HTML ûrlapon az egyetlen említésre méltó kód a dátum és idõ számára készített
lenyíló menüket állítja elõ. Ezeket a menüket elég egyszerûen beépíthettük volna
a PHP kódba, de szükségünk van arra, hogy alapbeállításban az aktuális idõt,
a tag által korábban választott idõt, vagy az esemenyek táblában tárolt idõt jelezz
ék. Az alapbeállításban kiválasztandó értéket már elhelyeztük az $edatum változ
óban. Ezt a program elején az aktuális idõre állítottuk be. Ha beérkezõ adatokat
észlelünk, annak megfelelõen állítjuk be ezt az értéket. Egyéb esetben, ha már
meglévõ eseményt módosítunk, az esemenyek tábla edatum mezõjének értékét
adjuk az $edatum változónak.
Teljes példa (elsõ rész) 459
23
Minden lenyíló menühöz az $edatum változóban lévõ idõbélyeget adjuk át
a megfelelõ függvénynek. Ezek az új datum.inc nevû külsõ állományban
találhatók.
23.19. program Részlet a datum.inc fájlból
1: function honapLehetosegek( $datum )
2: {
3: $datum_tomb = getDate( $datum );
4: $honapok = array( "Jan","Feb","Már",
"Ápr","Máj","Jún",
5: "Júl","Aug","Szep",
"Okt","Nov","Dec" );
6: foreach ( $honapok as $kulcs=>$ertek )
7: {
8: print "VALUE=\"".($kulcs+1)."\"";
9: print ( ( $datum_tomb["mon"] ==
($kulcs+1) )?"SELECTED":"" );
10: print ">$ertek\n";
11: }
12: }
13: function napLehetosegek( $datum )
14: {
15: $datum_tomb = getDate( $datum );
16: for ( $x = 1; $x<=31; $x++ )
17: {
18: print "

Hibakeresés

E könyv írásakor a PHP 4 semmilyen hibakeresõ eszközt nem tartalmazott.
A fejlesztõk ígéretet tettek hibakeresõ szolgáltatások beépítésére, például hogy
a verem tartalmát nyomon követhessük, ezért elképzelhetõ, hogy mire e könyv az
Olvasó kezébe kerül, a legfrissebb kiadás már tartalmaz valamilyen fejlettebb hibakeres
õ eszközt. Ebben a fejezetben a kódban rejlõ hibák felderítésének néhány
egyszerû módját mutatjuk be.
Az órában a következõ témákkal foglalkozunk:
• A PHP beállításainak lekérdezése
• A PHP által automatikusan elérhetõvé tett változók
• Hibaüzenetek kiírása naplófájlba
• Az adatok nyomon követése a programban
• A gyakori hibák felfedezése
• Információk a PHP-rõl és adott programokról
Ha egy program nem mûködik megfelelõen, érdemes elõször is a PHP beállításait
megvizsgálnunk. Ezután jöhetnek a PHP által létrehozott és a saját változók, és
ha még mindig nem találjuk a hibát, akkor megvizsgálhatjuk a forráskódot
egy olyan eszközzel, amely színkiemeléssel jelzi a nyelvtani elemeket – így hamar
rábukkanhatunk a problémás részre. Ebben a részben két módszert is megvizsgá-
lunk arra, hogyan szerezhetünk információkat a használt PHP-értelmezõrõl és
magáról a futó programról.
A phpinfo()
A phpinfo() függvény az egyik leghasznosabb hibakeresõ eszköz: részletes
információkkal szolgál magáról a PHP-rõl, a kiszolgálói környezetrõl és a futó
program változóiról. A függvénynek nem kell átadnunk semmilyen paramétert és
csak egy logikai értéket ad vissza, viszont egy csinos HTML oldalt küld a böngé-
szõnek. A phpinfo() kimenetét a 22.1. ábrán láthatjuk.
Az oldal tetején a használt PHP-változatról, a webkiszolgáló típusáról, a rendszerr
õl és a szerzõkrõl találunk információkat. A következõ táblázat részletezi a PHP
beállításait – ezeket a php.ini fájlban módosíthatjuk. Tegyük fel például, hogy
van egy "felhasznalo" nevû ûrlapmezõnk, de a programban valamilyen okból
nem jön létre a $felhasznalo változó. Vessünk egy pillantást a következõ beáll
ításokra:
track_vars On
register_globals Off
410 22. óra
22.1. ábra
PHP információk
megjelenítése
Már meg is találtuk a probléma forrását. A track_vars hatására a GET változók
a $HTTP_GET_VARS[] tömbben tárolódnak, a POST változók
a $HTTP_POST_VARS[] tömbben, míg a sütik a $HTTP_COOKIE_VARS[]
tömbben. Ez eddig rendben is van, a register_globals kikapcsolása azonban
azt jelenti, hogy a változók nem jönnek létre globális PHP változók formájában.
Alapállapotban mindkét lehetõség engedélyezett. Ebben az esetben két lehetõsé-
günk van. Keressük meg a register_globals bejegyzést a php.ini fájlban
és változtassuk On-ra. Nem tudjuk, merre keressük a php.ini fájlt? Nos,
a phpinfo() táblázataiban errõl is kaphatunk információt. A másik lehetõsé-
günk, hogy a "felhasznalo" mezõ tartalmára a program ne $felhasznalok
ént, hanem $HTTP_POST_VARS["felhasznalo"]-ként hivatkozzunk.
Egy olyan táblát is találnunk kell, amely a felhasználói munkamenetek kezelésére
vonatkozó beállításokat tartalmazza. Ha ez hiányzik, akkor a PHP-változatunkba
nem fordítottuk bele a munkamenetek kezelésének támogatását. A táblázatban
hasznos információkat találunk a munkamenetek kezelését megvalósító kód hibakeres
éséhez. Tegyük fel például, hogy olyan munkameneteket szeretnénk létrehozni,
amelyek bizonyos ideig fennmaradnak. Ha a munkamenet elvész, amikor
a felhasználó bezárja a böngészõ ablakát, és a phpinfo() a következõ beállítást
mutatja:
session.cookie_lifetime 0
már meg is találtuk a probléma forrását. A session.cookie_lifetime értéket
kell átállítanunk a php.ini fájlban, annak megfelelõen, hogy hány másodpercig
szeretnénk fenntartani a munkameneteket.
Ha a php.ini állomány a következõ sort tartalmazza:
session.use_cookies 0
a sütik nem engedélyezettek a munkamenetek kezelése során. Ebben az esetben
az azonosítás során a lekérdezõ karakterláncra kell hagyatkoznunk vagy módosí-
tanunk kell a beállítást a php.ini-ben.
A phpinfo() a webkiszolgálóról is rengeteg hasznos információval szolgál,
különösen akkor, ha Apache fut a gépünkön. Láthatjuk például a programmal
kapcsolatban forgalmazott összes kérés- és válaszfejlécet, illetve a kiszolgáló
környezeti változóit is (például HTTP_REFERER).
Ha a PHP-t adatbázis-támogatással fordítottuk, az erre vonatkozó beállításokat is
láthatjuk, például az alapértelmezett felhasználót, IP címet és kaput.
Hibakeresés 411
22
Az egyik legfontosabb információforrásunk lehet az a tábla, amelyben a PHP által
létrehozott globális változók vannak felsorolva az értékeikkel együtt. Lássunk erre
egy példát. A 22.1. példa egy egyszerû programot tartalmaz, amely létrehoz egy
HTML ûrlapot és beállít egy sütit.
22.1. program A phpinfo() függvény kipróbálása
1: 2: setcookie( "azonosito", "2344353463433",
time()+3600, "/" );
3: ?>
4:
5:
6: 22.1. program A phpinfo() függvény<br />kipróbálása
7:
8:
9:

"
METHOD="get"">
10:
11:

12:
18:

19:
20:

21:


22:

23:


24: 25: phpinfo();
26: ?>
27:
28:
Ha a „Lássuk!” gombra kattintunk, a program megkapja a felhasználó által megadott
adatokat és a süti is beállítódik. Ha meghívjuk a phpinfo() függvényt,
látni fogjuk ezeket a változókat – a kimenet lényeges részét a 22.2. ábrán láthatjuk.
412 22. óra
Látható, hogy a süti és a $HTTP_GET_VARS változó elérhetõ. Az ûrlap tartalmazott
egy olyan listát is, amelybõl több elemet is kiválaszthattunk – a változók között
a teljes tömb megjelenik.
Nagyobb lélegzetû feladatoknál gyakran gondot okoz az ûrlapváltozók és a sütik
nyomon követése, ilyenkor a phpinfo() felbecsülhetetlen segítséget nyújthat.
A forráskód megjelenítése színkiemeléssel
Ha nem találjuk meg a probléma forrását a phpinfo() függvény segítségével,
talán nem is a beállításokkal van baj. Jó ötlet lehet egy újabb pillantást vetni
a forráskódra. A PHP segítségével megtekinthetjük a program forráskódját,
ráadásul a kulcsszavakat, a karakterláncokat, a megjegyzéseket és a HTML kódot
színkiemeléssel is megjeleníthetjük.
Ha Apache kiszolgálót használunk, a beállítófájlhoz (többnyire httpd.conf) kell
hozzáadnunk a következõ sort:
AddType application/x-httpd-php-source .phps
Ezután minden .phps kiterjesztésû fájl színkiemeléssel fog megjelenni a böngé-
szõablakban. Ha nincs jogunk megváltoztatni a kiszolgáló beállítóállományát,
használjuk a show_source() függvényt, amely a paraméterül megadott fájlt
színkiemeléssel jeleníti meg a böngészõablakban.
Hibakeresés 413
22
22.2. ábra
Globális változók
elérése
A 22.2. példaprogram segítségével megtekinthetjük programjaink forráskódját.
22.2. program Dokumentum forrásának megjelenítése
1:
2:
3: 22.2. program Dokumentum forrásának<br />megjelenítése
4:
5:
6:
"
method="get">
7: Kérem a fájl nevét:
8:
9:



10: 11: if ( isset( $file ) )
12: show_source( $file ) or print "nem lehet
megnyitni a következõ fájlt: \"$file\"";
13: ?>
14:
15:
A 22.3. ábra a 22.2. példaprogramot mutatja mûködés közben.
Miért hasznos ez a lehetõség? Hiszen megnézhetnénk a kódot megszokott szövegszerkeszt
õnkkel is. A legnagyobb elõny a színkiemelésben rejlik. Igen könnyû
észrevenni például az elgépeléseket, hiszen ezeket nem kulcsszóként értelmezi
a megjelenítõ, ezért más színnel jelöli.
414 22. óra
22.3. ábra
Színkiemelés
használata
Egy másik gyakori probléma, hogy elég nehéz nyomon követni egy félig nyitott
idézõjel-párt. Mivel a PHP az idézõjel utáni szöveget karakterláncként értelmezi,
gyakran rossz helyen jelzi a hibát. Az idézõjelben lévõ karakterláncok szintén más
színnel jelöltek, így ez a típusú hiba nagyon könnyen észrevehetõ.
A 22.1. táblázat a színkiemelések jelentését tartalmazza.
22.1. táblázat Színkiemelések
php.ini bejegyzés Alapértel- Kód Jelentés
mezett szín
highlight.string Vörös #DD0000 Idézõjelek és
karakterláncok
highlight.comment Narancs #FF8000 PHP megjegyzések
highlight.keyword Zöld #007700 Mûveletjelek, nyelvi
elemek és a legtöbb
beépített függvény
highlight.default Kék #0000BB Minden egyéb PHP kód
highlight.html Fekete #000000 HTML kód
PHP hibaüzenetek
Miközben e könyv segítségével elsajátítottuk a PHP programozás alapjait, bizonyára
elõfordult, hogy hibaüzeneteket kaptunk a várt eredmény helyett. Például elfelejtett
ünk zárójelbe tenni egy kifejezést vagy elgépeltük egy függvény nevét. A hibaüzenetek
nagyon fontosak a hibakeresés során. Állítsuk a php.ini fájlban
a display_errors bejegyzést "On"-ra, ezzel biztosíthatjuk, hogy a PHP elküldje
a hibaüzeneteket a böngészõnek. Ne feledjük, hogy a phpinfo() függvény segíts
égével megnézhetjük, hogy be van-e kapcsolva ez a lehetõség.
Miután meggyõzõdtünk arról, hogy programunk tudatni fogja velünk az esetleges
hibákat, meg kell adnunk, hogy mennyire legyenek „szigorúak” az üzenetek.
Ha be akarunk állítani egy alapértelmezett szintet, rendeljünk a php.ini fájlban
az error_reporting bejegyzéshez egy számot. Szerencsére nem kell fejben
Hibakeresés 415
22
Ne tegyük ezt a programot elérhetõvé webhelyünkön, mert így
bárki belenézhet forrásainkba. Csak fejlesztéskor használjuk ezt
a kódot!
tartanunk az összes számot, mivel rendelkezésünkre állnak azok az állandók,
amelyeket a hibakezelés szintjének beállításához használhatunk. A különbözõ
értékeket a 22.2. táblázat tartalmazza.
22.2. táblázat Hibakezelési szintek
Állandó Név Leírás Mi történik?
E_ALL Mind Mindenféle hiba Függ a hiba típusától
E_ERROR Hibák Végzetes hibák Felhasználó értesítése és
(például memória- a program futásának
kiosztási problémák) megállítása
E_WARNING Figyelmeztetések Nem végzetes hibák Értesíti a felhasználót,
(például nem szabá- de nem szakítja meg
lyos paraméterátadás) a program futását
E_PARSE Értelmezõ hiba Az értelmezõ nem Felhasználó értesítése és
érti az utasítást a program futásának
megállítása
E_NOTICE Megjegyzések Lehetséges problé- Értesíti a felhasználót és
maforrás (például folytatja a program
egy kezdeti értékkel futtatását
el nem látott változó)
E_CORE_ERROR Belsõ hiba az értel- Az értelmezõ indítása- Megszakítja
mezõ indításakor kor fellépõ végzetes az értelmezõ indítását
hibák
E_CORE_WARNING Figyelmeztetõ Az értelmezõ indítása- Értesíti a felhasználót és
üzenet az értel- kor fellépõ nem folytatja a program
mezõ indításakor végzetes hibák futtatását
Ezekkel a beállításokkal nem változtathatjuk meg, mi történjen a hiba felbukkaná-
sakor, csak abba van beleszólásunk, hogy a hibaüzenetet el akarjuk-e küldeni
a böngészõnek vagy sem.
Természetesen egyszerre több hibakezelési szintet is engedélyezhetünk, ekkor
az egyes szinteket a VAGY (|) jellel elválasztva kell megadnunk. A következõ sor
például engedélyezi a hibaüzenetek és a figyelmeztetések megjelenítését is:
error_reporting = E_ERROR|E_WARNING
416 22. óra
Ha a hibakezelést az összes hibatípusra ki akarjuk terjeszteni, használjuk az E_ALL
állandót. Mi a teendõ akkor, ha az összes típust engedélyezni szeretnénk, kivéve
egyet? A következõ sor éppen ezt valósítja meg:
error_reporting = E_ALL & ~E_NOTICE
Az értelmezõ a megjegyzéseken kívül minden felmerülõ üzenetet elküld
a böngészõnek.
Az E_ERROR|E_WARNING és az E_ALL&~E_NOTICE tulajdonképpen kettes
számrendszerbeli aritmetikai mûveletek, melyek eredménye egy új hibakezelési
szintet megadó szám. A kettes számrendszerbeli aritmetikával ebben a könyvben
nem foglalkozunk, de a módszer ettõl még remélhetõleg érthetõ marad.
A php.ini beállítását az error_reporting() függvénnyel bírálhatjuk felül,
melynek bemenõ paramétere a hibakezelési szintet megadó egész szám, visszaté-
rési értéke pedig a megelõzõ hibakezelési beállítás. Természetesen ennél a függv
énynél is használhatjuk az elõzõekben megismert állandókat. Lássunk egy példát
egy olyan esetre, ahol a hibakezelési szint módosítása a segítségünkre lehet.
Lássuk, észrevesszük-e a szándékolt hibát a 22.3. programban.
22.3. program Egy szándékos hiba
1: 2: error_reporting( E_ERROR|E_WARNING|E_PARSE );
3: $flag = 45;
4: if ( $flg == 45 ) {
5: print "Tudom, hogy a \$flag változó értéke 45";
6: } else {
7: print "Tudom, hogy a \$flag változó értéke NEM 45";
8: };
9: ?>
Mint látható, a $flag változó értékét akarjuk vizsgálni, de elgépeltük. Nincs végzetes
hiba a programban, így minden további nélkül lefut és
az E_ERROR|E_WARNING|E_PARSE hibakezelési beállítás mellett még csak üzenetet
sem küld a böngészõnek. A kód bekerül a programba és a lehetõ legrosszabb
pillanatban mûködésbe lép. Ha azonban az error_reporting() függvénynek
az E_ERROR|E_WARNING|E_PARSE|E_NOTICE értéket adnánk át (ez magában
foglalja a megjegyzések elküldését is), a program a következõ kimenetet küldené:
Hibakeresés 417
22
Warning: Undefined variable: flg in /home/httpd/htdocs/
å peldak/22.3.program.php on line 4
Tudom, hogy a $flag változó értéke NEM 45
Azaz:
Figyelem: Nem meghatározott változó: flg a /home/httpd/htdocs/
å peldak/22.3.program.php fájlban a 4. sorban
Tudom, hogy a $flag változó értéke NEM 45
Az üzenetbõl nem csak az derül ki számunkra, hogy valami nincs rendben,
de még a problémás sor számát is megtudtuk. Ugyanezt a hatást úgy is elérhetjük,
ha az error_reporting() függvénynek az E_ALL állandót adjuk át paramé-
terként, ennek azonban lehetnek nem kívánt mellékhatásai is. Elképzelhetõ az is,
hogy szándékosan alkalmazunk nem meghatározott változókat. Vegyük például
a következõ kódrészletet:

Itt azt használjuk ki, hogy ha egy nem meghatározott változó értékét íratjuk ki,
akkor annak hasonló a hatása ahhoz, mintha egy üres karakterláncot jelenítenénk
meg (tulajdonképpen semmilyen hatása nincs). A "felhasznalo" mezõ
egy elõzõleg elküldött értéket vagy semmit sem tartalmaz. Ha a megjegyzések
elküldését is engedélyeztük, hibaüzenetet kapunk.
Hibaüzenetek kiírása naplófájlba
Azok a hibák, amelyekre eddig vadásztunk, nagyobb részben azonnali, fejlesztés
közben keletkezõ hibák voltak. Vannak azonban olyan problémák is, amelyek
késõbb jönnek elõ, például azért, mert megváltozik a futtató környezet. Tegyük fel
például, hogy szükségünk van egy programra, amely a felhasználó által kitöltött
ûrlap adatait írja fájlba. Elkészítjük a programot, kipróbáljuk, mérjük a teljesítm
ényét éles körülmények között, majd magára hagyjuk, hogy végezze a feladatát.
Néhány héttel késõbb azonban véletlenül töröljük azt a könyvtárat, amely az adott
fájlt tartalmazza.
A PHP error_log() függvénye pontosan az ilyen esetekre kifejlesztett hibakeres
õ eszköz. Ez egy beépített függvény, amellyel a kiszolgáló naplófájljába vagy egy
általunk megadott fájlba naplózhatjuk a felmerülõ hibákat. Az error_log()
függvénynek két bemenõ paramétere van: egy karakterlánc, amely a hiba szövegét
tartalmazza és egy egész szám, amely a hiba típusát írja le. A hiba típusától függõ-
en egy további paramétert is meg kell adnunk az error_log() függvénynek:
egy elérési utat vagy egy e-mail címet.
418 22. óra
A 22.3. táblázat az elérhetõ hibatípusokat sorolja fel.
22.3. táblázat Az error_log() függvény hibatípusai
Érték Leírás
0 A hibaüzenetet a php.ini fájl error_log bejegyzésénél
megadott fájlba kell kiírni.
1 A hibaüzenetet a harmadik paraméterben megadott
e-mail címre kell küldeni.
3 A hibaüzenetet a harmadik paraméterben megadott fájlba
kell kiírni.
Ha hibanaplózást szeretnénk, adjunk meg egy naplófájlt a php.ini error_log
bejegyzésénél. Természetesen a phpinfo() függvénnyel megnézhetjük, van-e
már ilyen beállítás a php.ini fájlban. Ha nincs, adjuk hozzá a fájlhoz például
a következõ bejegyzést:
error_log = /home/httpd/logs/php_errors
Ha NT vagy Unix operációs rendszert használunk, a "syslog" karakterláncot is
hozzárendelhetjük az error_log bejegyzéshez. Ekkor a 0-ás hibatípussal
meghívott error_log() hibaüzenetek a rendszernaplóba (Unix), illetve
az eseménynaplóba (NT) kerülnek. A következõ kódrészlet egy hibaüzenetet
hoz létre, ha nem tudunk megnyitni egy fájlt:
fopen( "./fontos.txt", "a" )
or error_log( __FILE__.", ".__LINE__.". sor:
å Nem lehet megnyitni a következõ fájlt: ./fontos.txt", 0 );
A hibaüzenet a __FILE__ és __LINE__ állandókat használja, amelyek az éppen
futó program elérési útját, illetve az aktuális sor számát tartalmazzák. A 0-ás hibatí-
pussal azt adjuk meg, hogy a hibaüzenet a php.ini fájlban megadott helyre kerülj
ön. Ezek alapján valami ilyesmi bejegyzés kerül a naplófájlba:
/home/httpd/htdocs/proba5.php, 4. sor:
å Nem lehet megnyitni a következõ fájlt: ./fontos.txt
Ha a hibaüzenetet adott fájlba akarjuk kiküldeni, használjuk a 3-as hibatípus
paramétert:
Hibakeresés 419
22
if ( ! $megvan = mysql_connect( "localhost", "jozsi",
"valami" ) )
{
error_log( date("d/m/Y H I")." Nem lehet csatlakozni
az adatbázishoz",
3, "dbhiba.txt" );
return false;
}
Ha 3-as típusú hibaüzenetet hozunk létre, egy harmadik paraméterben azt is meg
kell adnunk az error_log() függvénynek, hogy hová kerüljön a hibaüzenet.
Az error_log() függvénynek azt is megadhatjuk, hogy a hibaüzenetet egy
e-mail címre postázza. Ehhez az 1-es típuskódot kell használnunk:
if ( ! file_exists( "kritikus.txt" ) )
or error_log( "Ó, nem! kritikus.txt-nek vége van!",
å 1, "veszeset@kritikus.hu" );
Ha 1-es típusú hibaüzenetet küldünk, az error_log() harmadik paraméterében
meg kell adnunk az e-mail címet is.
A hibaüzenet elfogása
Ha hibaüzeneteket írunk egy fájlba vagy elektronikus levélben küldjük el azokat,
hasznos lehet, ha hozzáférünk a PHP által elõállított hibaüzenethez.
Ehhez a php.ini fájlban a track_errors bejegyzést "On"-ra kell állítanunk –
ennek hatására a legutolsó PHP hibaüzenet bekerül a $php_errormsg változóba
(hasonlóan a Perl $! változójához).
A $php_errormsg változó felhasználásával a hibaüzeneteket és naplóbejegyz
éseket beszédesebbé tehetjük.
A következõ kódrészlet által létrehozott hibaüzenet már sokkal használhatóbb,
mint az elõzõek:
fopen( "./fontos.txt", "a" )
or error_log( __FILE__.", ".__LINE__.". sor:
".$php_errormsg, 0 );
Az üzenet így fog festeni:
/home/httpd/htdocs/proba.php, 21. sor:
fopen("./fontos.txt","a") - Permission denied
420 22. óra
Kézi hibakeresés
Mindig nagyon nehéz azonban az olyan hibák kijavítása, amelyek nem váltanak ki
hibaüzenetet.
A hibakeresés egyik kézenfekvõ módja, ha megtûzdeljük a kódunkat print utasí-
tásokkal és kiíratjuk a fontosabb változók értékét. A futás során a változók ugyanis
gyakran nem várt értékeket vesznek fel
Egy jellemzõ nyomkövetõ sor:
print "

\$valtozo: $valtozo

";
Ez egy gyors próba, amit beszúrhatunk a programba, a $valtozo értékének
ellenõrzésére.
Természetesen a fent alkalmazott módszer nem kötelezõ érvényû – mindenki
kialakíthatja a saját módszerét, például:
print "

".__LINE__.": \$teszt értéke: $teszt

";
Talán a legkényelmesebb módszer, ha írunk egy függvényt a változók értékének
nyomon követésére és az include() használatával elérhetõvé tesszük a fejleszt
ési szakaszban. A 22.4. példa egy olyan függvényt tartalmaz, amely lehetõvé teszi
a fejlesztõ által megadott formátumú nyomkövetési üzenetek megjelenítését.
22.4. program Formázott nyomkövetési üzenetek megjelenítése
1: 2: function debug( $sor, $uzenet)
3: {
4: static $hivasok = 1;
5: print "


\n";
6: print "DEBUG $hivasok: $sor. sor: $uzenet
";
7: $argumentumok = func_get_args();
8: if ( count( $argumentumok ) % 2 )
9: print "Páratlan számú paraméter!
";
10: else
11: {
12: for ( $x=2; $x< count($argumentumok); $x += 2 )
13: {
14: print "   \$$argumentumok[$x]: "
.$argumentumok[$x+1];
Hibakeresés 421
22
22.4. program (folytatás)
15: print " .... (".gettype(
$argumentumok[$x+1] ).")
\n";
16: }
17: }
18: print "

\n";
19: $hivasok++;
20: }
21: $proba = 55;
22: debug( __LINE__, "Elsõ üzenet:", "proba", $proba );
23: $teszt = 66;
24: $proba2 = $proba/2;
25: debug( __LINE__, "Második üzenet", "proba", $proba,
"proba2", $proba2 );
26: ?>
A debug() függvénynek egy sorszámot, egy üzenetet, illetve tetszõleges számú
név–érték párt adhatunk át. A sor számát és az üzenetet kiírni a feladat könnyebbik
része. Ezután ki kell használnunk a PHP 4 azon tulajdonságát, hogy egy függvényt
változó számú paraméterrel is meghívhatunk. A func_get_args() által visszaadott
tömb függvényünk összes paraméterét tartalmazza – ezeket a változókat
töltjük be az $argumentumok tömbbe. Mivel név–érték párokat várunk, hibaüzenetet
kell adnunk, ha páratlan számú elem érkezik a tömbben. Egyébként végigl
épkedünk a tömb összes elemén (a harmadikkal kezdve) és kiíratjuk az összes
párt a változó adattípusával együtt. A 22.4. ábra a 22.4. program kimenetét mutatja.
422 22. óra
22.4. ábra
A debug() függvény
használata
Gyakori hibák
Mindannyian követünk el hibákat, különösen akkor, ha vészesen közeledik
a leadási határidõ. Vannak olyan csapdák, amelyekbe elõbb-utóbb minden programoz
ó beleesik.
Észrevesszük a hibát a következõ kódrészletben?
$valtozo=0;
while ( $valtozo < 42 );
{
print "$valtozo
";
$valtozo++;
}
A kapkodás sokszor vezet hibához – például az utasítássort jelölõ pontosvesszõt
gyakran kitesszük olyan helyeken is, ahol nem kellene. Így kerülhetett a fenti
while kifejezés mögé is pontosvesszõ, ami azt jelzi az értelmezõnek, hogy
a ciklus törzse üres – a $valtozo értéke soha nem fog nõni, ezért a program
végtelen ciklusba kerül.
Lássunk még egy példát:
$ertek = 1;
while ( $ertek != 50 )
{
print $ertek;
$ertek+=2;
}
Az elöltesztelõ ismétléses vezérlési szerkezet ciklustörzsének végrehajtása a záró-
jelben található kifejezés logikai értékétõl függ. A fenti példában ez a kifejezés
csak akkor lesz hamis, ha az $ertek változó értéke 50. Vagyis a ciklustörzs addig
ismétlõdik, amíg az $ertek értéke nem 50. Csakhogy ez soha nem fog bekövetkezni,
mivel a változó értéke 1-rõl indul és minden lépésben kettõvel növekszik –
vagyis csak páratlan értékeket vesz fel. Ismét sikerült végtelen ciklusba ejtenünk
a PHP-t.
A következõ kódrészletben rejlõ hiba elég alattomos:
if ( $proba = 4 )
{
print "

A \$proba értéke 4

\n";
}
Hibakeresés 423
22
A végrehajtást vezérlõ logikai kifejezésben nyilvánvalóan ellenõrizni akartuk
a $proba változó értékét. A kód azonban ehelyett 4-et rendel a $proba-hoz.
Mivel a hozzárendelés mint kifejezés értéke a jobb oldali operandussal egyenlõ
(jelen esetben 4-gyel), a logikai kifejezés értéke a $proba-tól függetlenül mindig
igaz lesz. Ezt a típusú hibát azért nehéz felfedezni, mert semmilyen üzenetet nem
hoz létre, a program egyszerûen nem úgy fog mûködni, ahogyan azt elvárjuk.
A karakterláncok kezelése során szintén elkövethetünk típushibákat. Az alábbi
elég gyakori:
$datum = "A mai dátum: . date('d/m/Y H I’);
print $datum;
Mivel nem zártuk le az idézõjelet, az értelmezõnek fogalma sincs, hol végzõdik
a karakterlánc. Ez szinte mindig hibajelzéssel jár, de nehézkes visszakeresni, mivel
gyakran rossz sorszámot kapunk. A zárójelpárok hibás kezelése szintén hasonló
jelenséghez vezet.
A következõ hibát viszont elég könnyû megtalálni:
print "Ön a $tartomany-ról "$felhasznalo"-kent
å jelentkezett be";
Ha idézõjelet akarunk kiíratni, jeleznünk kell az értelmezõnek, hogy itt nem különleges
karakterként kell kezelnie. Az elõbbi kódrészlet a következõképpen fest
helyesen:
print "Ön a $tartomany-ról \"$felhasznalo\"-kent
å jelentkezett be";
Összefoglalva, ebben a részben a következõ gyakori hibatípusokkal foglalkoztunk:
• Üres ciklustörzs létrehozása hibásan alkalmazott pontosvesszõvel.
• Végtelen ciklus létrehozása hibás vezérlõfeltétellel.
• Hozzárendelés használata az „egyenlõ” logikai mûveletjel helyett.
• Levédetlen idézõjelek használata miatt elcsúszott karakterlánc-határok.
424 22. óra
Összefoglalás
A fejlesztés talán egyik leghálátlanabb része a hibakeresés. A megfelelõ módszerekkel
azonban megkönnyíthetjük az életünket.
Ebben az órában tanultunk arról, hogy a phpinfo() függvény segítségével
hogyan nyerhetünk információkat a rendszer beállításairól és a környezeti változ
ókról. Az error_log() függvénnyel hibaüzeneteket írtunk ki fájlba és küldt
ünk el elektronikus levélben. Tanultunk a kézi hibakeresésrõl a fontosabb változ
ók értékének kiíratásával és írtunk egy függvényt a feladat megkönnyítésére.
Ha ismerjük az adatokat, amelyekkel programunk dolgozik, viszonylag könnyen
és gyorsan megtalálhatjuk a hibákat. Végül megnéztünk néhány olyan típushibát,
amelyek még a tapasztaltabb programozók életét is megkeserítik.
Kérdések és válaszok
Létezik módszer, amellyel csökkenthetjük a kódba kerülõ hibákat?
Legyünk szemfülesek! Tulajdonképpen szinte lehetetlen egy olyan nagyobb lélegzet
û programot létrehozni, amely elsõre tökéletesen mûködik. Használjunk modul
áris tervezést, hogy gyorsan elkülöníthessük a hibát tartalmazó kódrészletet. Olyan
gyakran ellenõrizzük a kódot, amilyen gyakran csak lehetséges. Rossz megközelí-
tés, ha megírjuk a programot, elindítjuk, azután várjuk, mi történik. Oldjunk meg
egy részfeladatot (lehetõleg függvények formájában), majd próbáljuk ki az elké-
szült kódot. Ha tökéletesen mûködik, mehetünk a következõ részfeladatra. Próbáljunk
„bolondbiztos” kódot készíteni és ellenõrizzük mûködését szélsõséges körülm
ények között. Ha az egyik leglényegesebb lépés például az adatok kiírása egy
megadott fájlba, nézzük meg, mi történik, ha a fájl hiányzik.
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. Melyik függvénnyel kaphatunk hasznos információkat a PHP-rõl és a rendszer
ünkrõl?
2. Melyik függvénnyel jeleníthetjük meg a színekkel kiemelt forráskódot
a böngészõablakban?
Hibakeresés 425
22
3. Melyik php.ini bejegyzéssel szabályozhatjuk a hibaüzenetek kijelzésének
szintjét?
4. Melyik függvénnyel bírálhatjuk felül ezt a beállítást?
5. Melyik függvénnyel naplózhatjuk a hibákat?
6. Melyik beépített változó tartalmazza a hibaüzenetet, ha a track_errors
bejegyzés engedélyezett a php.ini fájlban?
Feladatok
1. Vizsgáljuk meg eddig elkészült programjaink kódját és felépítését az ebben
az órában tanult módszerek segítségével.