You are on page 1of 506

000cimnegyed.

qxd 8/3/2001 6:09 PM Page iii

Matt Zandstra

a
PHP4
használatát
000cimnegyed.qxd 8/3/2001 6:09 PM Page iv

A kiadvány a következõ angol eredeti alapján készült:

Matt Zandstra: Teach Yourself PHP4 in 24 Hours


Copyright © 2000 by Sams Publishing. All rights reserved. No part of this book, including interior
desing, cover design, and icons, may be reproduced or transmitted in any form, by any means
(electronic, photocopying, recording, or otherwise) without the prior written permission of the
publisher.
Acquisitions Editor: Jeff Schultz Project Editor: Paul Schneider
Development Editor: Scott D. Meyers Copy Editor: Geneil Breeze
Managing Editor: Charlotte Clapp
Trademarked names appear throughout this book. Rather than list the names and entities that own
the trademarks or insert a trademark symbol with each mention of the trademarked name, the
publisher states that it is using the names for editorial purposes only and to the benefit of the
trademark owner, with no intention of infringing upon that trademark.
A szerzõk és a kiadó a lehetõ legnagyobb körültekintéssel járt el e kiadvány elkészítésekor. Sem
a szerzõ, sem a kiadó nem vállal semminemû felelõsséget vagy garanciát a könyv tartalmával,
teljességével kapcsolatban. Sem a szerzõ, sem a kiadó nem vonható felelõsségre bármilyen baleset
vagy káresemény miatt, mely közvetve vagy közvetlenül kapcsolatba hozható e kiadvánnyal.
Fordítás és magyar változat © 2001 Szy György, Kiskapu Kft. Minden jog fenntartva!
Translation and Hungarian edition © 2001 György Szy, Kiskapu Kft. All rights reserved!
Sorozatszerkesztõ: Szy György Mûszaki szerkesztõ: Csutak Hoffmann Levente
Nyelvi lektor: Rézmûves László
Szakmai lektor: Hojtsy Gábor
Felelõs kiadó a Kiskapu Kft. ügyvezetõ igazgatója
© 2001 Kiskapu Kft.
1081 Budapest Népszínház u. 29.
Tel: (+36-1) 477-0443 Fax: (+36-1) 303-1619
http://www.kiskapu.hu/
e-mail: kiskapu@kiskapu.hu

ISBN: 963 9301 30 2

Készült a debreceni Kinizsi nyomdában


Felelõs vezetõ: Bördõs János
000cimnegyed.qxd 8/3/2001 6:09 PM Page vii

A szerzõrõl
Matt Zandstra (matt@corrosive.co.uk) a Corrosive Web Design céget vezeti
(http://www.corrosive.co.uk/) üzleti partnerével, Max Guglielminóval.
Mint a parancsnyelvekért rajongó programozó, PHP, Java, JavaScript, Perl, Lingo és
AppleScript nyelveken fejlesztett különbözõ programokat. Elõször bölcsészdiplomát
szerzett, majd úgy tanulta ki mesterségét, hogy „újra feltalálta a kereket” és kiele-
mezte, miért nem halad egyenesen. HTML, JavaScript, Perl és PHP tanfolyamokon
oktatott, majd szerzõként közremûködött a Dynamic HTML Unleashed címû könyv-
ben. Amikor nem kódot ír, Matt elkötelezett városi biciklista, Guinness-ivó, megszál-
lott olvasó és novellista, aki kiadhatatlan történeteket alkot. Azt állítja, egyszer talán
még regényt is fog írni.
000cimnegyed.qxd 8/3/2001 6:09 PM Page ix

Köszönetnyilvánítás
A nyílt forráskódú programoknak köszönhetem karrieremet és e könyv létrejöttét
is. Szeretném megköszönni mindazoknak, akiknek önzetlen segítõkészsége
mindig felülmúlja a kapott elismerést.

Különösen köszönöm a PHP közösségnek, legfõképpen a PHP levelezõlisták


résztvevõinek, akik leveleikkel feltárták a buktatókat, programozási módszereket
ajánlottak és mindig ámulatba ejtettek.

A Macmillantõl szeretném megköszönni Randi Rogernek, hogy engem ajánlott


e könyv szerzõjéül, valamint Jeff Schultznak, Paul Schneidernek és Scott
Meyersnek, támogatásukért és megértésükért, ahogy a határidõ közeledett és ki-
tört a pánik.

Köszönet illet mindenkit a Corrosive-nél, hogy eltûrték folyamatos hiányzásomat és


nagyfokú határozatlanságomat a nem PHP-vel kapcsolatos kérdésekben. Legfõkép-
pen üzlettársamnak, Massimo Guglieminónak vagyok hálás, hogy mûködtette
a Corrosive céget a megterhelõ körülmények között. Köszönet Dave Urmsonnak is,
aki átvette a formázást, amikor a munka megkívánta. A Corrosive további munka-
társai: Anisa Swaffield, Jeff Coburn, Mai Chokelumlerd és Moira Govern.

Meg kell köszönnöm a Small Planetnek (http://www.smallpla.net/), hogy


további fejlesztési teret adtak nekem és engedélyezték a bétaprogramok kipróbá-
lását. Kifejezetten hálás vagyok Mohamed Abbának és Clive Hillsnek, hogy oly
sokszor újrafordították a PHP-t a Small Planet kiszolgálón.

Az oktatási anyagok kipróbálásának egyik legjobb módja a tanfolyamon való fel-


használás. Köszönet tanulóimnak, akik kegyesen beleegyeztek, hogy kísérleti
nyulak legyenek.

Köszönöm kedvesemnek, Louise-nek, és lányunknak, Hollynak, hogy jelen voltak


és elviselték a könyv írása alatt kialakult zsörtölõdõ, visszahúzódó és megszállott
jellememet.

Amint magánéletem a PHP után második helyre került, menedékemmé a törzshe-


lyem vált, ahol összekapcsoltam a sörözést a munkával. Köszönet Alannek és
Dorának a kifogástalan Prince Arthur ivó fenntartásáért.

Végül köszönet a halaknak, akik mindig felvidítanak, ha bámulom õket.


002tartalom.qxd 8/3/2001 6:09 PM Page xiii

Tartalomjegyzék

Bevezetõ

I. rész Az elsõ lépések

1. óra PHP: személyes honlaptól a portálig . . . . . 3


Mi a PHP? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
A PHP fejlõdése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
A PHP 4 újdonságai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
A Zend Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Miért a PHP? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
A fejlesztés sebessége . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
A PHP nyílt forráskódú . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Teljesítmény . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Hordozhatóság . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2. óra A PHP telepítése . . . . . . . . . . . . . . . . . . . . 11


Operációs rendszerek, kiszolgálók, adatbázisok . . . . . . . . . . . . . . 12
A PHP beszerzése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
A PHP 4 telepítése Apache webkiszolgálót
használó Linuxra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
A configure néhány paramétere . . . . . . . . . . . . . . . . . . . . . . . . . . 14
--enable-track-vars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
--with-gd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
--with-mysql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Az Apache beállítása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
php.ini . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
002tartalom.qxd 8/3/2001 6:09 PM Page xiv

xiv

short_open_tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Hibajelentések beállításai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Változókra vonatkozó beállítások . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Segítség! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

3. óra Elsõ PHP oldalunk . . . . . . . . . . . . . . . . . . 23


Elsõ programunk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
PHP blokkok kezdése és befejezése . . . . . . . . . . . . . . . . . . . . . . . . . 26
A print() függvény . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
HTML és PHP kód egy oldalon . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Megjegyzések a PHP kódokban . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

II. rész A PHP nyelv

4. óra Az alkotóelemek . . . . . . . . . . . . . . . . . . . . 35
Változók . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Dinamikus változók . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Hivatkozások a változókra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Adattípusok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Típus módosítása a settype() segítségével . . . . . . . . . . . . . . . . . . . . . 43
Típus módosítása típusátalakítással . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Mûveletjelek és kifejezések . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Hozzárendelés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Aritmetikai mûveletek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Összefûzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
További hozzárendelõ mûveletek . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Összehasonlítás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Bonyolultabb összehasonlító kifejezések létrehozása
logikai mûveletek segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
002tartalom.qxd 8/3/2001 6:09 PM Page xv

xv

Egész típusú változók értékének növelése és csökkentése . . . . . . . . 51


A mûveletek kiértékelési sorrendje . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Állandók . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Minden programban használható állandók . . . . . . . . . . . . . . . . . . . . 54
Összegzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

5. óra Vezérlési szerkezetek . . . . . . . . . . . . . . . . 57


Elágazások . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Az if utasítás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Az if utasítás else ága . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Az if utasítás elseif ága . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
A switch utasítás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Ciklusok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
A while ciklus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
A do..while ciklus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
A for ciklus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Ciklus elhagyása a break utasítás segítségével . . . . . . . . . . . . . . . . . . 69
Következõ ismétlés azonnali elkezdése
a continue utasítás segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Egymásba ágyazott ciklusok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Összegzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

6. óra Függvények . . . . . . . . . . . . . . . . . . . . . . . 75
Mit nevezünk függvénynek? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Függvények hívása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Függvények létrehozása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Függvények visszatérési értéke . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Dinamikus függvényhívások . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Változók hatóköre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Hozzáférés változókhoz a global kulcsszó segítségével . . . . . . . . . . . 84
Állapot megõrzése a függvényhívások között
a static kulcsszó segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Paraméterek további tulajdonságai . . . . . . . . . . . . . . . . . . . . . . . . 89
Paraméterek alapértelmezett értéke . . . . . . . . . . . . . . . . . . . . . . . . . . 89
002tartalom.qxd 8/3/2001 6:09 PM Page xvi

xvi

Hivatkozás típusú paraméterek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91


Összegzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

7. óra Tömbök . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Mit nevezünk tömbnek? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Tömbök létrehozása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Tömbök létrehozása az array() függvény segítségével . . . . . . . . . . . . 99
Tömb létrehozása vagy elem hozzáadása a tömbhöz
szögletes zárójel segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Asszociatív tömbök . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Asszociatív tömbök létrehozása
az array() függvény segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Asszociatív tömbök létrehozása
és elérése közvetlen értékadással . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Többdimenziós tömbök . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Tömbök elérése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Tömb méretének lekérdezése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Tömb bejárása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Asszociatív tömb bejárása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Többdimenziós tömb bejárása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Mûveletek tömbökkel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Két tömb egyesítése az array_merge() függvény segítségével . . . . . 110
Egyszerre több elem hozzáadása egy tömbhöz
az array_push() függvény segítségével . . . . . . . . . . . . . . . . . . . . . . 110
Az elsõ elem eltávolítása
az array_shift() függvény segítségével . . . . . . . . . . . . . . . . . . . . . . . 112
Tömb részének kinyerése
az array_slice() függvény segítségével . . . . . . . . . . . . . . . . . . . . . . . 113
Tömbök rendezése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Számmal indexelt tömb rendezése
a sort() függvény segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Asszociatív tömb rendezése érték szerint
az asort() függvény segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Asszociatív tömb rendezése kulcs szerint
a ksort() függvény segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Összegzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
002tartalom.qxd 8/3/2001 6:09 PM Page xvii

xvii

8. óra Objektumok . . . . . . . . . . . . . . . . . . . . . . 119


Mit nevezünk objektumnak? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Objektum létrehozása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Objektumtulajdonságok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Az objektumok tagfüggvényei . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Egy bonyolultabb példa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Az osztály tulajdonságai . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
A konstruktor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Az ujSor() tagfüggvény . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Az ujNevesSor() tagfüggvény . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
A kiir() tagfüggvény . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Összeáll a kép . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Ami még hiányzik... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Miért használjunk osztályt? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Öröklés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
A szülõ tagfüggvényeinek felülírása . . . . . . . . . . . . . . . . . . . . . . . . . 134
A felülírt tagfüggvény meghívása . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Egy példa az öröklésre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
A HTMLTablazat saját tulajdonságai . . . . . . . . . . . . . . . . . . . . . . . . . 137
A konstruktor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
A cellaMargoAllit() tagfüggvény . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
A kiir() tagfüggvény . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
A Tablazat és a HTMLTablazat osztályok
a maguk teljességében . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Miért alkalmazzunk öröklést? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Összegzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

III. rész Munka a PHP-vel

9. óra Ûrlapok . . . . . . . . . . . . . . . . . . . . . . . . . . 149


Globális és környezeti változók . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Adatok bekérése a felhasználótól . . . . . . . . . . . . . . . . . . . . . . . . 152
Több elem kiválasztása a SELECT elemmel . . . . . . . . . . . . . . . . 153
Az ûrlap minden mezõjének
hozzárendelése egy tömbhöz . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Különbségek a GET és a POST továbbítás között . . . . . . . . . . . . 157
002tartalom.qxd 8/3/2001 6:09 PM Page xviii

xviii

PHP és HTML kód összekapcsolása egy oldalon . . . . . . . . . . . . 159


Állapot mentése rejtett mezõkkel . . . . . . . . . . . . . . . . . . . . . . . . 161
A felhasználó átirányítása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Fájlfeltöltõ ûrlapok és programok . . . . . . . . . . . . . . . . . . . . . . . . 165
Összegzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

10. óra Fájlok használata . . . . . . . . . . . . . . . . . 171


Fájlok beágyazása az include() függvénnyel . . . . . . . . . . . . . . . . . 172
Fájlok vizsgálata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Fájl létezésének ellenõrzése a file_exists() függvénnyel . . . . . . . . . 175
Fájl vagy könyvtár? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
Fájl állapotának lekérdezése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
Fájl méretének lekérdezése a filesize() függvénnyel . . . . . . . . . . . . 177
Különféle fájlinformációk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Több fájltulajdonságot egyszerre megadó függvény . . . . . . . . . . . . 178
Fájlok létrehozása és törlése . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Fájl megnyitása írásra, olvasásra, hozzáfûzésre . . . . . . . . . . . . . . 180
Olvasás fájlból . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Sorok olvasása fájlból az fgets() és feof() függvényekkel . . . . . . . . . 181
Tetszõleges mennyiségû adat olvasása fájlból . . . . . . . . . . . . . . . . . 182
Fájl karakterenkénti olvasása az fgetc() függvénnyel . . . . . . . . . . . . 184
Fájlba írás és hozzáfûzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Fájlok zárolása az flock() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . 186
Munka könyvtárakkal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Könyvtár létrehozása az mkdir() függvénnyel . . . . . . . . . . . . . . . . . 187
Könyvtár törlése az rmdir() függvénnyel . . . . . . . . . . . . . . . . . . . . . 188
Könyvtár megnyitása olvasásra . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Könyvtár tartalmának olvasása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Összegzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

11. óra A DBM függvények használata . . . . . . . 193


DBM adatbázis megnyitása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Adatok felvétele az adatbázisba . . . . . . . . . . . . . . . . . . . . . . . . . 195
Adatok módosítása az adatbázisban . . . . . . . . . . . . . . . . . . . . . . 196
002tartalom.qxd 8/3/2001 6:09 PM Page xix

xix

Adatok kiolvasása DBM adatbázisból . . . . . . . . . . . . . . . . . . . . . 197


Elemek meglétének lekérdezése . . . . . . . . . . . . . . . . . . . . . . . . . 199
Elem törlése az adatbázisból . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Összetett adatszerkezetek tárolása
DBM adatbázisban . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Egy példa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

12. óra Adatbázisok kezelése – MySQL . . . . . . 211


(Nagyon) rövid bevezetés az SQL nyelvbe . . . . . . . . . . . . . . . . . . 212
Csatlakozás a kiszolgálóhoz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Az adatbázis kiválasztása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Hibakeresés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Adatok hozzáadása táblához . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Automatikusan növekvõ mezõ
értékének lekérdezése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
Adatok lekérdezése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Az eredménytábla sorainak száma . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Az eredménytábla elérése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Adatok frissítése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Információk az adatbázisokról . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Az elérhetõ adatbázisok kiíratása . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Adatbázistáblák listázása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
Információk a mezõkrõl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
Az adatbázis szerkezete – összeáll a kép . . . . . . . . . . . . . . . . . . . 230
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

13. óra Kapcsolat a külvilággal . . . . . . . . . . . . . 237


Környezeti változók . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
A HTTP ügyfél-kiszolgáló kapcsolat
rövid ismertetése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
A kérés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
A válasz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Dokumentum letöltése távoli címrõl . . . . . . . . . . . . . . . . . . . . . . 245
002tartalom.qxd 8/3/2001 6:09 PM Page xx

xx

Átalakítás IP címek és gépnevek között . . . . . . . . . . . . . . . . . . . 246


Hálózati kapcsolat létesítése . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
NNTP kapcsolat létrehozása az fsockopen()-nel . . . . . . . . . . . . . . . 251
Levél küldése a mail() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . 254
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257

14. óra Dinamikus képek kezelése . . . . . . . . . . 259


Képek létrehozása és megjelenítése . . . . . . . . . . . . . . . . . . . . . . 260
A szín beállítása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Vonalak rajzolása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Alakzatok kitöltése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Körív rajzolása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
Téglalap rajzolása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Sokszög rajzolása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
A színek átlátszóvá tétele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
Szövegek kezelése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Szövegírás az imageTTFtext() függvénnyel . . . . . . . . . . . . . . . . . . . 269
Szöveg kiterjedésének ellenõrzése . . . . . . . . . . . . . . . . . . . . . . . . . . 271
az imageTTFbox() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
A fenti elemek összegyúrása . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281

15. óra Dátumok kezelése . . . . . . . . . . . . . . . . . 283


A dátum kiderítése a time() függvénnyel . . . . . . . . . . . . . . . . . . . 284
Az idõbélyeg átalakítása a getdate() függvénnyel . . . . . . . . . . . . 284
Az idõbélyeg átalakítása a date() függvénnyel . . . . . . . . . . . . . . . 286
Idõbélyeg készítése az mktime() függvénnyel . . . . . . . . . . . . . . . 288
A dátum ellenõrzése a checkdate() függvénnyel . . . . . . . . . . . . . . . 289
Egy példa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
A felhasználó által bevitt adatok ellenõrzése . . . . . . . . . . . . . . . . . . 290
A HTML ûrlap létrehozása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
A naptár táblázatának létrehozása . . . . . . . . . . . . . . . . . . . . . . . . . . 294
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
002tartalom.qxd 8/3/2001 6:09 PM Page xxi

xxi

Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298


Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299

16. óra Az adatok kezelése . . . . . . . . . . . . . . . . 301


Újra az adattípusokról . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Egy kis ismétlés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Összetett adattípusok átalakítása . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
Az adattípusok automatikus átalakítása . . . . . . . . . . . . . . . . . . . . . . 304
Az adattípusok ellenõrzése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
Az adattípus-váltás további módjai . . . . . . . . . . . . . . . . . . . . . . . . . 306
Miért olyan fontosak az adattípusok? . . . . . . . . . . . . . . . . . . . . . . . . 307
A változók meglétének és ürességének ellenõrzése . . . . . . . . . . 309
További tudnivalók a tömbökrõl . . . . . . . . . . . . . . . . . . . . . . . . . . 310
Tömbök bejárása más megközelítésben . . . . . . . . . . . . . . . . . . . . . 310
Elem keresése tömbben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Elemek eltávolítása a tömbbõl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Függvények alkalmazása a tömb összes elemére . . . . . . . . . . . . . . . 312
Tömbök egyéni rendezése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318

17. óra Karakterláncok kezelése . . . . . . . . . . . . 319


Karakterláncok formázása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
A printf() függvény használata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
A printf() és a típusparaméterek . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
A kitöltõ paraméter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
A mezõszélesség meghatározása . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
A pontosság meghatározása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Átalakító paraméterek (Ismétlés) . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Formázott karakterlánc tárolása . . . . . . . . . . . . . . . . . . . . . . . . . . 328
Részletesebben a karakterláncokról . . . . . . . . . . . . . . . . . . . . . . 329
Szövegek indexelése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Szöveg hosszának megállapítása az strlen() függvénnyel . . . . . . . . 329
Szövegrész megkeresése az strstr() függvénnyel . . . . . . . . . . . . . . . 330
Részlánc elhelyezkedésének meghatározása
az strpos() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
002tartalom.qxd 8/3/2001 6:09 PM Page xxii

xxii

Szövegrészlet kinyerése a substr() függvénnyel . . . . . . . . . . . . . . . . 331


Karakterlánc elemekre bontása az strtok() függvénnyel . . . . . . . . . 331
A karakterláncok kezelése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Szöveg tisztogatása a trim() típusú függvényekkel . . . . . . . . . . . . . . 333
Karakterlánc részének lecserélése
a substr_replace() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Az összes részlánc lecserélése az str_replace() függvénnyel . . . . . . 334
Kis- és nagybetûk közti váltás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
Karakterláncok tömbbé alakítása az explode() függvénnyel . . . . . . 336
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338

18. óra A szabályos kifejezések használata . . . . 339


A POSIX szabályos kifejezések függvényei . . . . . . . . . . . . . . . . . 340
Minta keresése karakterláncokban az ereg() függvénnyel . . . . . . . . 340
Egynél többször elõforduló karakter keresése
mennyiségjelzõvel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
Karakterlánc keresése karakterosztályokkal . . . . . . . . . . . . . . . . . . . 343
Az atomok kezelése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
Elágazások . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
A szabályos kifejezés helye . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
A tagazonosítót keresõ példa újragondolása . . . . . . . . . . . . . . . . . . 346
Minták lecserélése karakterláncokban
az ereg_replace() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Visszautalás használata az ereg_replace() függvénnyel . . . . . . . . . . 347
Karakterláncok felbontása a split() függvénnyel . . . . . . . . . . . . . . . 348
Perl típusú szabályos kifejezések . . . . . . . . . . . . . . . . . . . . . . . . 348
Minták keresése a preg_match() függvénnyel . . . . . . . . . . . . . . . . . 349
A Perl típusú szabályos kifejezések és a mohóság . . . . . . . . . . . . . . 349
A Perl típusú szabályos kifejezések és . . . . . . . . . . . . . . . . . . . . . . 350
a fordított perjeles karakterek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Teljeskörû keresés a preg_match_all() függvénnyel . . . . . . . . . . . . 351
Minták lecserélése a preg_replace() függvénnyel . . . . . . . . . . . . . . 354
Módosító paraméterek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
002tartalom.qxd 8/3/2001 6:09 PM Page xxiii

xxiii

19. óra Állapotok tárolása sütikkel


és GET típusú lekérdezésekkel . . . . . . . 361
Sütik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
A sütik felépítése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Sütik beállítása a PHP-vel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
Süti törlése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
Munkamenet-azonosító sütik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
Példa: Webhelyhasználat nyomon követése . . . . . . . . . . . . . . . . . . 366
Lekérdezõ karakterláncok használata . . . . . . . . . . . . . . . . . . . . . . 374
Lekérdezõ karakterlánc készítése . . . . . . . . . . . . . . . . . . . . . . . . 375
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379

20. óra Állapotok tárolása


munkamenet-függvényekkel . . . . . . . . . 381
Mik azok a munkamenet-függvények? . . . . . . . . . . . . . . . . . . . . . 382
Munkamenet indítása
a session_start() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
Munkamenet-változók . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
A munkamenet és a változók
bejegyzésének törlése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
Munkamenet-azonosítók a lekérdezõ
karakterláncban . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Munkamenet-változók kódolása és visszafejtése . . . . . . . . . . . . . 390
Munkamenet-változó bejegyzésének ellenõrzése . . . . . . . . . . . . 391
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393

21. óra Munka kiszolgálói környezetben . . . . . . 395


Folyamatok összekötése a popen() függvénnyel . . . . . . . . . . . . . 396
Parancsok végrehajtása az exec() függvénnyel . . . . . . . . . . . . . . 399
Külsõ programok futtatása
a system() függvénnyel vagy
a ' mûveletjel segítségével . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
Biztonsági rések megszüntetése
az escapeshellcmd() függvény használatával . . . . . . . . . . . . . . . . 401
002tartalom.qxd 8/3/2001 6:09 PM Page xxiv

xxiv

Külsõ programok futtatása


a passthru() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
Külsõ CGI program meghívása
a virtual() függvénnyel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408

22. óra Hibakeresés . . . . . . . . . . . . . . . . . . . . . 409


A phpinfo() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
A forráskód megjelenítése színkiemeléssel . . . . . . . . . . . . . . . . . 413
PHP hibaüzenetek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
Hibaüzenetek kiírása naplófájlba . . . . . . . . . . . . . . . . . . . . . . . . . 418
A hibaüzenet elfogása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Kézi hibakeresés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Gyakori hibák . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426

IV. rész Összefoglaló példa

23. óra Teljes példa (elsõ rész) . . . . . . . . . . . . . 429


A feladat rövid leírása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
Az oldalak felépítése . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
Az adatbázis kialakítása . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
Tervezési döntésünk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
A tagoknak szánt oldalak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
csatlakozas.php és adatbazis.inc . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
klubfrissites.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
tagmenu.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
belepes.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
esemenyfrissites.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
esemenylista.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
002tartalom.qxd 8/3/2001 6:09 PM Page xxv

xxv

Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467

24. óra Teljes példa (második rész) . . . . . . . . . . 469


Az eseménynaptár nyilvános oldalai . . . . . . . . . . . . . . . . . . . . . . 470
esemenyekinfo.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470
klubokinfo.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
klubinfo.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
esemenyinfo.php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484
A jövõ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487
Kérdések és válaszok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488
Mûhely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488
Kvíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488
Feladatok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488

A függellék Válaszok a kvízkérdésekre. . . . . . . . 489

Tárgymutató
003bevezeto.qxd 8/3/2001 6:10 PM Page xxvii

Bevezetõ
Ez a könyv egy nyílt forráskódú webes parancsnyelvrõl (szkriptrõl), a PHP-rõl
szól, amely csatlakozott a Perl-höz, az ASP-hez és a Javához a dinamikus webes
alkalmazások készítéséhez rendelkezésre álló nyelvek palettáján. A kötet progra-
mozási ismeretekkel is foglalkozik. A rendelkezésre álló lapokon nem jut elég
hely egy teljes PHP programozási útmutató közlésére vagy a PHP összes lehetõsé-
gének és eljárásának ismertetésére, mindazonáltal a könyvben található lépések
elég információt adnak ahhoz, hogy használni kezdhessük a PHP-t, akár rendel-
kezünk programozói tapasztalttal, akár újak vagyunk a parancsnyelvek világában.

Kiknek szól ez a könyv?


A könyv az alapoktól indulva hasznos gyakorlati tudást ad a PHP 4-es programo-
zási nyelv használatához. Semmilyen korábbi programozási tapasztalatra nincs
szükség, de ha a C vagy a Perl nyelvekkel már dolgoztunk korábban, az egyes
órákon könnyebb lesz haladni.

A PHP 4 webes programozási nyelv. Ahhoz, hogy a lehetõ legtöbb hasznát ve-
gyük a könyvnek, célszerû némi ismerettel rendelkezni a Világhálóval és a HTML-
lel kapcsolatban. Ha nem rendelkezünk ilyen ismeretekkel, akkor is hasznos lehet
e könyv, ám meggondolandó egy HTML ismertetõ beszerzése. Ha kényelmesen
létre tudunk hozni egyszerû HTML dokumentumokat táblázatokkal, akkor ele-
gendõ tudással rendelkezünk.

A PHP 4-esben az adatbázisok kezelése igen egyszerû. A könyv néhány példájában


a MySQL ingyenes adatbázisrendszert használtuk. Az SQL nyelvet röviden ismertet-
jük, de ha komolyabban kívánjuk használni az adatbáziskezelõ szolgáltatásokat,
célszerû elmélyednünk néhány kapcsolódó anyagban. Az Interneten számos beve-
zetõ szintû SQL ismertetõ érhetõ el. Ha mégsem a MySQL adatbázisrendszerrel
kívánunk dolgozni, a könyv példáit könnyen más adatbázisokhoz igazíthatjuk.

Könyvünk szerkezete
Kötetünk négy fõ részbõl áll:

• Az elsõ rész bevezetõ a PHP alapjaihoz.


• A második rész az alapvetõ szolgáltatásokat mutatja be. Ha még nincs progra-
mozási tapasztalatunk, ezt a részt különös figyelemmel olvassuk!
003bevezeto.qxd 8/3/2001 6:10 PM Page xxviii

xxviii Tanuljuk meg a PHP4 használatát 24 óra alatt

• A harmadik rész részletesebben ismerteti a PHP 4-es változatának lehetõségeit,


felsorakoztatva a függvényeket és megoldásokat, melyekre szükségünk van,
ha gyakorlott PHP programozók szeretnénk lenni.
• A negyedik rész egy teljesen önállóan mûködõ példaprogramot mutat be.

Az elsõ rész az elsõtõl a harmadik óráig tart és egy egyszerû parancsfájl futtatásáig
vezeti el az olvasót:

• Az elsõ óra „PHP: személyes honlaptól a portálig” címmel bemutatja a PHP tör-
ténetét és képességeit, valamint a PHP tanulása mellett néhány érvet sorol fel.
• A második óra „A PHP telepítése” címmel végigvezeti az olvasót a PHP telepí-
tésén UNIX rendszeren, valamint azon fordítási és beállítási lehetõségekkel
foglakozik, amelyek a környezet kialakítása szempontjából fontosak lehetnek.
• A harmadik óra „Elsõ PHP oldalunk” címmel bemutatja, hogyan építhetünk
PHP kódot HTML oldalainkba és hogyan készíthetünk a böngészõ számára
kimenetet adó programot.

A második részben a negyediktõl a nyolcadik óráig megismerjük a PHP alapvetõ


elemeit:

• A negyedik óra „Az alkotóelemek” címmel a PHP alapjait mutatja be.


Az óra anyagát változók, adattípusok, mûveletjelek (operátorok) és kifejezé-
sek képezik.
• Az ötödik óra „Vezérlési szerkezetek” címmel a programok futását vezérlõ
elemek utasításformájával (nyelvtanával) foglalkozik. Az if és switch szerke-
zetek után megtanuljuk a for és while ciklusvezérlõ elemek használatát is.
• A hatodik óra „Függvények” címmel a függvények készítését és használatát
tárgyalja.
• A hetedik óra „Tömbök” címmel a lista jellegû adatok tárolására használható
tömb adattípussal foglalkozik, valamint a tömbök használatához néhány
PHP 4 függvényt is ismertetet.
• A nyolcadik óra „Objektumok” címmel bemutatja a PHP 4 osztály- és objek-
tumtámogatását. Ebben az órában egy mûködõ példán keresztül vesszük
górcsõ alá az objektumok használatát.

A harmadik részben a kilencediktõl a huszonkettedik óráig alaposan megismerjük


a nyelv szolgáltatásait és megoldási módszereit:

• A kilencedik óra „Ûrlapok” címmel a HTML ûrlapok használatát, vagyis


a felhasználótól érkezõ adatok feldolgozását vezeti be. Megtanuljuk, miként
érjük el a beérkezõ információkat.
• A tizedik óra „Fájlok használata” címmel bemutatja a fájlok és könyvtárak
kezelésének lehetõségeit.
003bevezeto.qxd 8/3/2001 6:10 PM Page xxix

Bevezetõ xxix

• A tizenegyedik óra „A DBM függvények használata” címmel a PHP DBM-


támogatásával foglalkozik, amely a legtöbb operációs rendszeren elérhetõ.
• A tizenkettedik óra „Adatbázisok kezelése – MySQL” címmel az SQL alapjait
tárgyalja, valamint bemutatja a PHP 4 MySQL adatbázisok kezelésére szolgáló
függvényeit.
• A tizenharmadik óra „Kapcsolat a külvilággal” címmel a HTTP kéréseket
veszi szemügyre, illetve a PHP hálózati függvényeit ismerteti.
• A tizennegyedik óra „Dinamikus képek kezelése” címmel a GIF, PNG és
JPEG képek készítését lehetõvé tevõ függvényeket mutatja be.
• A tizenötödik óra „Dátumok kezelése” címmel a dátummûveletekhez haszná-
latos függvényeket és eljárásokat ismerteti. Ebben az órában egy naptár
példát is elkészítünk.
• A tizenhatodik óra „Az adatok kezelése” címmel visszatér az adattípusokhoz
és az addig nem említett, de a hatékony használathoz elengedhetetlen további
függvényeket mutatja be. A tömbökkel kapcsolatban is újabb függvényeket
említünk.
• A tizenhetedik óra „Karakterláncok kezelése” címmel a karakterláncok keze-
léséhez jól használható PHP függvényekkel foglalkozik.
• A tizennyolcadik óra „A szabályos kifejezések használata” címmel bemutatja
a bonyolultabb minták keresésére és cseréjére szolgáló szabályos
kifejezéseket.
• A tizenkilencedik óra „Állapotok tárolása sütikkel és GET típusú lekérdezé-
sekkel” címmel a különbözõ programok és HTTP kérések közötti informá-
cióátadás néhány módját mutatja be.
• A huszadik óra „Állapotok tárolása munkamenet-függvényekkel” címmel
az elõzõ órában tanultakat a PHP 4-es beépített munkamenet-kezelõ függvé-
nyeivel bõvíti ki.
• A huszonegyedik óra „Munka kiszolgálói környezetben” címmel a külsõ
programok futtatását és kimenetük felhasználásának lehetõségeit mutatja be.
• A huszonkettedik óra „Hibakeresés” címmel a kódok hibakeresésére ad ötle-
teket, valamint bemutat néhány szokásos hibát.

A negyedik részben – a huszonharmadik és huszonnegyedik órákon – a könyvben


tanult módszerek felhasználásával egy mûködõ példát készítünk.

• A huszonharmadik óra egy tervet mutat be helyi klubok számára készülõ


programunkhoz. Megírjuk a felhasználók bejegyzéséhez és a klubok prog-
ramjának beviteléhez szükséges elemeket.
• A huszonnegyedik óra befejezésként a látogatók számára készült felület meg-
valósításához szükséges kódot tartalmazza, amely lehetõvé teszi a klubok
programjainak böngészését.

A könyvel kapcsolatos észrevételeiket a http://www.kiskapu.hu/konyvek/PHP4/ címen


tehetik meg, ugyancsak ezen az oldalon található a hibajegyzék is.
01_ora.qxd 8/3/2001 6:10 PM Page 1

I. RÉSZ
Az elsõ lépések
1. óra PHP: személyes honlaptól a portálig
2. óra A PHP telepítése
3. óra Elsõ PHP oldalunk
01_ora.qxd 8/3/2001 6:10 PM Page 2
01_ora.qxd 8/3/2001 6:10 PM Page 3

1. ÓRA
PHP: személyes honlaptól
a portálig
Üdvözlet a PHP világában! Ebben a könyvben végigtekintjük a PHP nyelv majd-
nem minden elemét. Mielõtt azonban részletesebben megnéznénk, mire lehetünk
képesek segítségével, tárjuk fel múltját, fõbb tulajdonságait és jövõjét.

Ebben az órában a következõket tanuljuk meg:

• Mi a PHP?

• Hogyan fejlõdött a nyelv?

• Mik a PHP 4 újdonságai?

• Hogyan tehetjük optimálissá a PHP-t?

• Miért pont a PHP-t válasszuk?


01_ora.qxd 8/3/2001 6:10 PM Page 4

4 1. óra

Mi a PHP?
A PHP nyelv túlnõtt eredeti jelentõségén. Születésekor csupán egy makrókészlet
volt, amely személyes honlapok karbantartására készült. Innen ered neve is:
Personal Home Page Tools. Késõbb a PHP képességei kibõvültek, így egy önál-
lóan használható programozási nyelv alakult ki, amely képes nagyméretû webes
adatbázis-alapú alkalmazások mûködtetésére is.

A PHP nyelv népszerûsége képességeinek bõvülésével folyamatosan nõtt. A NetCraft


elemzõ cég (http://www.netcraft.com/) felmérései szerint a PHP-t 2000 feb-
ruárjában 1,4 millió kiszolgálón használták és októberre ez a szám 3,3 millióra ugrott.
Ezzel megközelítette a Microsoft IIS kiszolgálók számát, ami 3,8 millió. Az E-Soft
szerint a PHP a legnépszerûbb Apache modul, a ModPerlt is maga mögé utasítva.

A PHP jelenleg hivatalosan a PHP: Hypertext Preprocessor elnevezést használja.


Tulajdonképpen kiszolgálóoldali programozási nyelv, amit jellemzõen HTML olda-
lakon használnak. A hagyományos HTML lapokkal ellentétben azonban a kiszol-
gáló a PHP parancsokat nem küldi el az ügyfélnek, azokat a kiszolgáló oldalán
a PHP-értelmezõ dolgozza fel. A programjainkban lévõ HTML elemek érintetlenül
maradnak, de a PHP kódok lefutnak. A kódok végezhetnek adatbázis-lekérdezé-
seket, dinamikusan létrehozhatnak képeket, fájlokat olvashatnak és írhatnak,
kapcsolatot létesíthetnek távoli kiszolgálókkal – a lehetõségek száma végtelen.
A PHP kódok kimenete a megadott HTML elemekkel együtt kerül az ügyfélhez.

A PHP fejlõdése
A PHP elsõ változatát – amely néhány webalkalmazás-készítést segítõ makrót tar-
talmazott – Rasmus Lerdorf készítette 1994-ben. Ezen eszközöket együttesen
a Personal Home Page Tools névvel azonosították. Késõbb, a kód újraírása után,
egy friss elem került a csomagba, a Form Interpreter (Ûrlapfeldolgozó), így
PHP/FI néven vált ismertebbé. A felhasználók szemszögébõl a PHP/FI nagyon
hasznos segédeszköz volt, így népszerûsége töretlenül nõtt. Több fejlesztõ is felfi-
gyelt rá, így 1997-re már számos programozó dolgozott rajta.

A következõ kiadás, a PHP 3-as, már egy csapat együttmûködésébõl született.


Ehhez a változathoz Zeev Zuraski és Andi Gutmans újjáalkotta a teljes feldolgozó-
egységet, valamint újabb elemeket és szabályokat adott a nyelvhez. Ez a változat
megalapozottá tette a PHP helyét a legjobb kiszolgálóoldali nyelvek között, így
felhasználói tábora rendkívüli mértékben nõtt.

Az Apache- és MySQL-támogatás megerõsítette a PHP pozícióját. Az Apache jelenleg


a legnépszerûbb kiszolgáló a világon és a PHP 3-as már modulként illeszthetõ hozzá.
A MySQL igen hatékony, ráadásul ingyenes SQL adatbázisrendszer, amelyhez a PHP
átfogó támogatást nyújt. Az Apache-MySQL-PHP együttes egyszerûen verhetetlen.
01_ora.qxd 8/3/2001 6:10 PM Page 5

PHP: személyes honlaptól a portálig 5

Ez természetesen nem jelenti azt, hogy a PHP nem használható más környezetben,
más eszközökkel. A PHP számos adatbázis-alkalmazással és webkiszolgálóval
képes együttmûködni. 1
A PHP népszerûségének növekedésére hatással volt a webes alkalmazások fejlesz-
tésében történt váltás is. Az 1990-es évek közepén természetesnek számított, hogy
akár egy nagyobb webhelyet is több száz, egyenként kézzel kódolt HTML lap fel-
használásával készítsenek el. Mára azonban a fejlesztõk egyre inkább kihasználják
az adatbázisok nyújtotta kényelmi szolgáltatásokat, hogy a megjelenítendõ tartal-
mat hatékonyan kezeljék és az egyes felhasználóknak lehetõséget adjanak
a webhelyek testreszabására.

Egyre gyakoribb adatbázisok használata a tartalom tárolására és az információk


visszakeresésére különbözõ felületeken. Az adatok egy központból több környe-
zetbe is érkezhetnek, beleértve a mobiltelefonokat, a digitális személyi titkárokat
(PDA), digitális televíziókat és szélessávú internetes rendszereket is.

Ebben a környezetben már nem meglepõ, hogy egy ilyen kifinomult és rugalmas
nyelv, mint a PHP, ekkora népszerûségre tett szert.

A PHP 4 újdonságai
A PHP 4-es változata számos – a programozók életét megkönnyítõ – új szolgálta-
tással rendelkezik. Nézzük ezek közül a legfontosabbakat:

• A Perl nyelvben találhatóhoz hasonló új foreach vezérlési szerkezet, ami le-


egyszerûsíti a tömbökön végrehajtandó ciklusok készítését. Ezt fogjuk hasz-
nálni a könyv legtöbb tömbbel kapcsolatos példájában. Ezen túl számos új
tömbkezelõ függvény került a nyelvbe, amelyek megkönnyítik a tömbökkel
végzett mûveleteket.

• A nyelv tartalmazza a boolean (logikai) adattípust.

• A PHP 3 felettébb hasznos szolgáltatása volt, hogy a HTML ûrlap elemeit


tömbnevekkel láthattuk el, így ezek neve és értéke a program számára egy
tömbként került átadásra. Ez a szolgáltatás a többdimenziós tömbök támo-
gatásával bõvült.

• A PHP 3 csak kezdetleges szinten támogatta az objektumközpontú progra-


mozást. Ezen a téren is jelentõs fejlesztés történt, a PHP 4-esben például már
lehetséges egy felülírt metódus meghívása egy leszármazott osztályból.
01_ora.qxd 8/3/2001 6:10 PM Page 6

6 1. óra

• A PHP 4-be beépítették a felhasználói munkamenetek (session) támogatását


is. Ezek kezelése sütik (cookie) vagy GET metódusú lekérdezések (query
string) formájában történhet. Lehetõségünk van változókat rendelni egy mun-
kamenethez és más oldalakon újra elérni ezeket.

• Két új összehasonlító mûveletet vezettek be (=== és !==), melyekkel


egyidõben értékek és típusok egyezését, illetõleg nem egyezését is ellenõriz-
hetjük.

• A kiszolgálói és környezeti adatok tárolására új „beépített” asszociatív tömbö-


ket hoztak létre, valamint egy új változót, amelybõl információkat kaphatunk
a feltöltött fájl(ok)ról.

• A PHP 4-es beépített támogatással rendelkezik a Java és XML nyelvekhez.

Ezek és más új szolgáltatások ugyan jelentõsen bõvítették a nyelvet, de a legfonto-


sabb változás a felszín alatt következett be.

A Zend Engine
A PHP 3 készítésekor az alapoktól indulva teljesen új feldolgozóegységet írtak
a nyelvhez. A PHP 4-esben hasonló változás figyelhetõ meg a programokat futtató
magban, ez azonban jelentõsebb.

A Zend Engine a PHP modulok mögött található, a programokat futtató mag elne-
vezése. Kifejezetten a teljesítmény jelentõs növelésére fejlesztették ki.

A hatékonysági változások minden bizonnyal biztosítani fogják a PHP további


sikerét. A PHP 3-as változata számára készült kódok legnagyobb része minden
módosítás nélkül tovább mûködik, sõt, akár 200-szoros sebességgel futhat.

A Zend Technologies Ltd. (http://www.zend.com/) egyik kereskedelmi fej-


lesztése a PHP kódok fordítását teszi lehetõvé. Ez további teljesítménynövekedést
jelent, amivel a mérések szerint a PHP messze maga mögött hagyja legtöbb
versenytársát.

A Zend Engine a teljesítmény és a rugalmasság növelésére íródott. A kiszolgálókap-


csolatok továbbfejlesztésével lehetõvé vált, hogy olyan PHP modulok készüljenek,
amelyek a kiszolgálók széles körével képesek együttmûködni. Míg CGI-feldolgozó-
ként minden lekéréshez új PHP-értelmezõt kell elindítani, addig modulként a PHP
folyamatosan a memóriában van. Ez gyorsabb futást jelent, hiszen nem kell mindig
elindítani egy újabb feldolgozóprogramot, ha kérés érkezik.
01_ora.qxd 8/3/2001 6:10 PM Page 7

PHP: személyes honlaptól a portálig 7

Miért a PHP?
Van néhány megcáfolhatatlan érv, amiért a PHP 4-est érdemes választani. Ha más 1
programnyelveket is ismerünk, számos alkalmazás fejlesztése során észlelni fog-
juk, hogy a programozási szakasz érezhetõen gyorsabb, mint várnánk. A PHP,
mint nyílt forráskódú termék jó támogatással rendelkezik, amit a képzett fejlesztõi
gárda és az elkötelezett közösség nyújt számunkra. Ráadásul a PHP a legfontosabb
operációs rendszerek bármelyikén képes futni, a legtöbb kiszolgálóprogrammal
együttmûködve.

A fejlesztés sebessége
Mivel a PHP lehetõséget ad a HTML elemek és a programkódok elkülönítésére,
az alkalmazások fejlesztésekor lehetõség van elválasztani a kódolási, tervezési, és
összeállítási szakaszt. Ez jelentõsen megkönnyíti a programozók életét, azzal, hogy
elmozdítja az akadályokat a hatékony és rugalmas alkalmazások kialakításának
útjából.

A PHP nyílt forráskódú


Számos felhasználó szemében a „nyílt forráskódú” egyet jelent azzal, hogy ingye-
nes, ami természetesen már önmagában is elõnyös. Egy idézet a PHP hivatalos
webhelyérõl (http://www.php.net/):

Talán idegennek hangozhat azok számára, akik nem UNIX-háttérrel ol-


ÚJDONSÁG
vassák-e sorokat, hogy a PHP nem kerül semmibe. Használható keres-
kedelmi és/vagy nem kereskedelmi célra, ahogy tetszik. Odaadhatjuk barátaink-
nak, kinyomtathatjuk és felakaszthatjuk a falra vagy akár elfogyaszthatjuk ebédre.
Légy üdvözölve a nyílt forráskódú programok világában! Mosolyogj, légy boldog,
a világ jó! További információkért lásd a hivatalos licenszet.

A jól szervezett nyílt forráskódú projektek újabb elõnyökkel szolgálnak a felhasz-


nálóknak. Felvehetjük a kapcsolatot a könnyen elérhetõ és elkötelezett felhaszná-
lói közösséggel, ahol számos nagy tapasztalattal rendelkezõ embert találunk. Nagy
az esély rá, hogy bármilyen problémával is kerüljünk szembe, némi kutatással
gyorsan és könnyen választ találunk rá. Ha mégsem, egy levelezõlistára küldött
üzenetre általában hamar érkezik intelligens és hiteles válasz.

Úgyszintén bizonyos, hogy a feldolgozóprogram hibáinak javítása nem sokkal fel-


fedezésük után megtörténik és a felmerült új igényeket kielégítõ szolgáltatások is
hamar beépülnek a nyelvbe. Nem kell várni a következõ hivatalos kiadásra, hogy
a fejlesztések elõnyeit élvezzük.
01_ora.qxd 8/3/2001 6:10 PM Page 8

8 1. óra

Nincs a PHP mûködtetéséhez egyedileg kiválasztott kiszolgáló vagy operációs


rendszer. Szabadon választhatunk olyan rendszert, amely kielégíti saját vagy
ügyfeleink igényeit. Biztos, hogy kódunk továbbra is futtatható lesz, bármi mellett
is döntünk.

Teljesítmény
A hatékony Zend Engine-nek köszönhetõen a PHP 4-es jól vizsgázik az ASP-vel
szemben végzett méréseken, néhányban megelõzve azt. A lefordított PHP messze
maga mögött hagyja az ASP-t.

Hordozhatóság
A PHP-t alapvetõen úgy tervezték, hogy alkalmas legyen számos operációs rend-
szeren való használatra, együttmûködve különbözõ kiszolgálókkal és adatbázis-
kezelõkkel. Fejleszthetünk UNIX rendszerre és áttérhetünk NT alapokra minden
probléma nélkül. A PHP alkalmazásokat kipróbálhatjuk Personal Web Serverrel és
késõbb telepíthetjük azokat egy UNIX rendszerre, ahol a PHP-t Apache modulként
használjuk.

Összefoglalás
Ebben az órában bemutattuk a PHP-t. Láttuk, hogyan alakult át a nyelv egyszerû
makrókészletbõl hatékony programnyelvvé. Megismertük a Zend Engine-t, és
megnéztük, milyen új lehetõségeket teremt a PHP 4-es változatában. Végül átte-
kintettünk néhány tulajdonságot, amelyek ellenállhatatlanná teszik a PHP-t.

Kérdések és válaszok
Könnyû megtanulni a PHP nyelvet?
Röviden: igen! Valóban meg lehet tanulni a PHP alapjait 24 órában! A PHP meg-
számlálhatatlanul sok függvényt bocsát rendelkezésünkre, melyek megvalósításá-
hoz más nyelvekben saját kódot kellene írni. A PHP automatikusan kezeli a külön-
bözõ adattípusokat és memóriafoglalásokat (hasonlóan a Perl-höz).

Egy programozási nyelv nyelvtanának és szerkezeteinek megértése azonban


csak az út kezdetét jelenti. Végsõsoron a saját programok készítésébõl és a hibák
kijavításából lehet igazán sokat tanulni. Ezt a könyvet kiindulópontként érdemes
tekinteni.
01_ora.qxd 8/3/2001 6:10 PM Page 9

PHP: személyes honlaptól a portálig 9

Mûhely
A mûhelyben kvízkérdések találhatók, melyek segítenek megszilárdítani az órában 1
szerzett tudást. A válaszokat az A függelékben helyeztük el.

Kvíz
1. Mit jelentett eredetileg a PHP betûszó?

2. Ki készítette a PHP elsõ változatát?

3. Mi az új mag neve a PHP 4-es változatában?

4. Soroljuk fel a PHP 4 néhány új szolgáltatását!

Feladatok
1. A könyvet átlapozva annak felépítése alaposabban szemügyre vehetõ.
Gondolkozzunk el a témákon, és azon, hogyan segíthetnek jövõbeni
alkalmazásaink elkészítésében.
02_ora.qxd 8/3/2001 6:10 PM Page 11

2.ÓRA
A PHP telepítése
Mielõtt megkezdenénk az ismerkedést a PHP nyelvvel, be kell szereznünk, telepí-
tenünk és beállítanunk a PHP-értelmezõt. A feldolgozóprogram számos operációs
rendszerre elérhetõ és több kiszolgálóval is képes együttmûködni.

Ebben az órában a következõket tanuljuk meg:

• Milyen platformokat, kiszolgálókat és adatbázisokat támogat a PHP?

• Honnan szerezhetjük be a PHP-t és más nyílt forráskódú programokat?

• Hogyan telepíthetõ a PHP Linux rendszerre?

• Hogyan állíthatók be a fontosabb paraméterek?

• Hol található segítség, ha nem sikerül a telepítés?


02_ora.qxd 8/3/2001 6:10 PM Page 12

12 2. óra

Operációs rendszerek, kiszolgálók, adatbázisok


A PHP teljesen platformfüggetlen, ami azt jelenti, hogy fut Windows operációs rend-
szeren, a legtöbb UNIX rendszeren – beleértve a Linuxot –, sõt még Macintosh gépe-
ken is. A támogatott kiszolgálók köre igen széles. A legnépszerûbbek: Apache
(szintén nyílt forráskódú és platformfüggetlen), Microsoft Internet Information Server,
WebSite Pro, iPlanet Web Server, OmniHTTPD és Microsoft Personal Web Server.
Az utóbbi kettõ akkor tehet nagy szolgálatot, ha internetkapcsolat nélkül szeretnénk
fejleszteni, bár az Apache is alkalmas erre Windows környezetben.

A PHP fordítható önálló alkalmazássá is, így az értelmezõ parancssorból is hívható.


Ebben a könyvben webalkalmazások fejlesztéséhez fogjuk használni a PHP-t, de
nem szabad alábecsülni a szerepét általános programozói eszközként sem.

A PHP-t alapvetõen úgy tervezték, hogy könnyen összhangba hozható legyen


a különbözõ adatbázisokkal. Ez az egyik oka a PHP népszerûségének a webalkal-
mazások készítése terén. Számos adatbázis – Adabas D, InterBase, Solid, dBASE,
mSQL, Sybase, Empress, Microsoft SQL, MySQL, Velocis, FilePro, Oracle, UNIX
dbm, Informix és PostgreSQL – közvetlenül csatlakoztatható a PHP-hez. A közvet-
lenül nem támogatott adatbázisok mellett a PHP-ben kapcsolatot létesíthetünk az
ODBC szabványt használó programokkal is.

A könyv példáiban Linux operációs rendszer alatt Apache és MySQL programokat


használunk. Ezek ingyenesen letölthetõk az Internetrõl, valamint könnyen telepíthe-
tõk és használhatók majdnem minden PC-n. A Linux rendszer telepítésérõl további in-
formáció a http://www.linux.org/help/beginner/distributions.html
címen található. A Linux PowerPC gépen is használható, a LinuxPPC rendszerrel:
http://www.linuxppc.org/. Magyarországon a Linux közösség honlapja
a http://www.linux.hu/.

A MySQL adatbázisrendszer, amit ebben a könyvben használni fogunk,


a http://www.mysql.com/ címrõl tölthetõ le. Számos operációs rendszerre el-
érhetõ, beleértve a UNIX, Windows és OS/2 rendszereket. A MySQL magyar tükör-
kiszolgálója a http://mysql.sote.hu/.

Természetesen nyugodtan dolgozhatnánk Windows NT vagy MacOS rendszer alatt


is, mivel a PHP platformfüggetlen nyelv.
02_ora.qxd 8/3/2001 6:10 PM Page 13

A PHP telepítése 13

A PHP beszerzése
A PHP 4-es változata a http://www.php.net/ címrõl tölthetõ le. Mivel a PHP
nyílt forráskódú, nem kell a bankkártyánkat kéznél tartanunk, amikor letöltjük
az értelmezõt. Magyarországon a http://hu.php.net/ tükörkiszolgálót érde-
mes meglátogatni.

A PHP webhelye kiváló információforrás PHP programozóknak.


A http://www.php.net/manual/ címen a teljes kézikönyv elolvasható,
2
kiegészítve más programozók által írt hasznos megjegyzésekkel. Ezen a címen
olvasható a magyar PHP kézikönyv is. A PHP honlapról a dokumentáció is letölt-
hetõ különbözõ formátumokban.

A Zend Engine és más Zend termékek honlapja a http://www.zend.com/.


Itt híreket, illetve cikkeket olvashatunk a PHP és a Zend világából.

A PHP 4 telepítése
Apache webkiszolgálót használó Linuxra
Ebben a részben végigvezetünk egy PHP telepítést egy Apache webkiszolgálót
használó Linux rendszeren. A folyamat többé-kevésbé ugyanez más UNIX platfor-
mokon is. Elképzelhetõ, hogy az általunk használt rendszerre készült elõre fordított
változat is, így még egyszerûbben telepíthetnénk az értelmezõt, a PHP fordítása
azonban nagyobb szabadságot ad a feldolgozóba kerülõ szolgáltatásokat illetõen.

Mielõtt megkezdjük a telepítést, ellenõrizzük, hogy rendszergazdaként (root) jelent-


keztünk-e be a rendszerbe. Ha a kiszolgálót nem érhetjük el root felhasználóként,
forduljunk a rendszergazdához a PHP telepítésével kapcsolatos kéréseinkkel.

A PHP-t kétféleképpen lehet Apache modulként elõállítani. Egyrészt újrafordíthat-


juk a webkiszolgálót és beépíthetjük a PHP-értelmezõt, másrészt a PHP-t dinami-
kusan megosztott objektumként (DSO, Dynamic Shared Object) is fordíthatjuk. Ha
Apache kiszolgálónk DSO-támogatással ellátott, képes lesz az új modul használa-
tára anélkül, hogy újrafordítanánk a programot. Ez a legegyszerûbb módja annak,
hogy beüzemeljük a PHP-t, ezért ezt az eljárást fogjuk tárgyalni.

Ha ellenõrizni kívánjuk, hogy az Apache rendelkezik-e DSO-támogatással, el kell


indítanunk az Apache futtatható állományát (httpd) az -l paraméterrel.

/www/bin/httpd -l
02_ora.qxd 8/3/2001 6:10 PM Page 14

14 2. óra

A program ekkor egy listát ad a rendelkezésre álló beépített modulokról.


Ha a mod_so.c elem szerepel a listában, akkor az Apache alkalmas az alább
bemutatott módszerrel történõ bõvítésre. Egyéb esetben újra kell fordítani,
amihez a dokumentáció tartalmazza az összes szükséges információt.

Ha még nem tettük meg, le kell töltenünk a PHP legfrissebb változatát. A tar fájl
gzip-pel tömörített, így elsõ lépésben ki kell csomagolnunk:

tar -xvzf php-4.x.x.tar.gz

Ha sikeresen kibontottuk a csomagot, lépjünk át a keletkezett könyvtárba:

cd ../php-4.x.x

Ebben a könyvtárban található a configure program, melynek a megfelelõ


paraméterekkel megadhatjuk, milyen szolgáltatásokat építsen be a PHP-be.
Ebben a példában csak néhány hasznos parancssori paramétert adunk meg,
de természetesen számos más lehetõség is rendelkezésre áll. Késõbb megnézünk
néhány további elemet a configure paraméterei közül.

./configure --enable-track-vars \
--with-gd \
--with-mysql \
--with-apxs=/www/bin/apxs

Lehetséges, hogy a --with-apxs paraméternek átadott elérési útnak a rendsze-


rünkön másnak kell lennie, mivel telepítéskor az apxs esetleg éppen az Apache
futtatható állománnyal megegyezõ könyvtárba került.

Amikor a configure lefutott, elindítható a make program. Ennek futtatásához


a rendszernek tartalmaznia kell egy C fordítót.

make
make install

Ezekkel a parancsokkal a PHP fordítása és telepítése befejezõdött, már csak


az Apache beállítására és futtatására van szükség.

A configure néhány paramétere


Amikor lefuttattuk a configure-t, megadtunk néhány parancssori paramétert,
melyek meghatározták, milyen lehetõségekkel ruházzuk fel a PHP-t. Ha a kibon-
tott PHP csomag könyvtárában a következõ parancsot adjuk ki, a configure
megadja a lehetséges paramétereket:
02_ora.qxd 8/3/2001 6:10 PM Page 15

A PHP telepítése 15

./configure --help

Mivel a lista rendkívül hosszú, célszerû elõbb egy szövegfájlba irányítani, így
kényelmesebben elolvasható:

./configure --help > lehetosegek.txt

Annak ellenére, hogy a fenti parancs kimenete eléggé érthetõ, néhány fontos lehe-
tõséget meg kell említenünk – mégpedig azokat, amelyek a könyv szempontjából
2
számunkra érdekesek.

--enable-track-vars
Ez a szolgáltatás automatikusan elõállítja számunkra a PHP oldalakon kívülrõl érke-
zõ adatokhoz tartozó asszociatív tömböket. Ezek a GET vagy POST kéréssel érkezett
adatok, a visszaérkezõ süti-értékek, a kiszolgálói és környezeti változók. A tömbök-
kel a hetedik órában foglalkozunk bõvebben, a HTTP kapcsolatokat a tizenharma-
dik órában részletezzük. A fenti rendkívül gyakran használt configure paraméter,
mivel nagyon kellemes lehetõség a beérkezõ adatok követésére. A PHP 4.0.2-es
változatától kezdve mindig be van kapcsolva, így nem kell külön megadni.

--with-gd
A --with-gd paraméter engedélyezi a GD könyvtár támogatását. Amennyiben
a GD könyvtár telepítve van a rendszeren, ez a paraméter lehetõséget ad dinamikus
GIF, JPEG vagy PNG képek készítésére a PHP programokból. A dinamikus képek
elõállításáról a tizennegyedik órában írunk. Ha a GD-t korábban nem az alapbeállí-
tású könyvtárba telepítettük, megadható a szokásostól eltérõ elérési út is:

--with-gd=/eleresi/ut/a/megfelelo/konyvtarhoz

--with-mysql
A --with-mysql engedélyezi a MySQL adatbázisok támogatását. Ha a rendszeren
a MySQL nem az alapbeállítású könyvtárban található, megadható a szokásostól
eltérõ elérési út is:

--with-mysql=/eleresi/ut/a/megfelelo/konyvtarhoz

Mint már tudjuk, a PHP támogat számos más adatbázisrendszert is. Az 1.2-es táblá-
zatban ezek közül láthatunk néhányat, a hozzájuk tartozó configure paramé-
terekkel.
02_ora.qxd 8/3/2001 6:10 PM Page 16

16 2. óra

2.1. táblázat Néhány adatbázis és a hozzá tartozó configure paraméter


Adatbázis configure paraméter
Adabas D --with-adabas
FilePro --with-filepro
mSQL --with-msql
Informix --with-informix
iODBC --with-iodbc
OpenLink ODBC --with-openlink
Oracle --with-oracle
PostgreSQL --with-pgsql
Solid --with-solid
Sybase --with-sybase
Sybase-CT --with-sybase-ct
Velocis --with-velocis
LDAP --with-ldap

Az Apache beállítása
Miután sikeresen lefordítottuk az Apache-t és a PHP-t, módosítanunk kell
az Apache beállításait tartalmazó httpd.conf fájlt. Ez az Apache könyvtárának
conf alkönyvtárban található.
A következõ sorok hozzáadása szükséges:

AddType application/x-httpd-php .php .php3


AddType application/x-httpd-php-source .phps

Keressünk rá ezekre a sorokra a httpd.conf fájlban! Az újabb Apache kiadások-


ban ez már szerepel, csak egy megjegyzésjelet kell kitörölnünk a sorok elejérõl. Ezzel
biztosítjuk, hogy a PHP-elemzõ fel fogja dolgozni a .php és .php3 kiterjesztéssel
rendelkezõ fájlokat. A .php3 kiterjesztésre azért lehet szükség, mert számos régebbi
program ezt használja, így módosítás nélkül tovább alkalmazhatjuk ezeket is.
A .phps kiterjesztéssel rendelkezõ fájlok PHP forrásként kerülnek a böngészõhöz,
ami azt jelenti, hogy a forráskód HTML formátumúvá alakul és a nyelvtani elemek
színkiemeléssel jelennek meg, ami hasznos segítség lehet a programok hibáinak fel-
derítésében. Ha ügyfeleink miatt esetleg a hagyományos oldalaknál megszokott
.html kiterjesztést választjuk a PHP számára, a következõ beállítást kell alkalmaz-
nunk:

AddType application/x-httpd-php .html


02_ora.qxd 8/3/2001 6:10 PM Page 17

A PHP telepítése 17

Tulajdonképpen bármilyen kiterjesztéshez köthetjük a PHP-feldolgozót. Az aján-


lott a .php, a .html kiterjesztés azonban nem feltétlenül jó választás, ugyanis
ilyen beállítás esetén minden kiküldött HTML lap áthalad a PHP-elemzõn, ezáltal
jelentõsen csökkenhet a kiszolgálás sebessége.

Ha a PHP elõretelepítve található meg a kiszolgálón és nincs elérésünk az Apache


beállításait tartalmazó fájlhoz, létrehozhatunk egy .htaccess nevû állományt a sa-
ját könyvtárunkban és abban is megadhatjuk a fenti sorokat. A .htaccess fájlok
hatása kiterjed az adott könyvtárra és annak minden alkönyvtárára is. Ez a megoldás
2
azonban csak akkor mûködõképes, ha az Apache AllowOverride beállítása az
adott könyvtárra a FileInfo vagy az All értéket tartalmazza.

A .htaccess az alapbeállítású fájlnév, amit a könyvtár speciális beállításaihoz


használhatunk, de az adott rendszeren más is lehet. Ezt a httpd.conf állomány
AccessFileName beállítása határozza meg. Ez a fájl általában akkor is olvasha-
tó, ha nem rendelkezünk rendszergazdai jogokkal a kiszolgálón.

A .htaccess fájl tökéletes módja annak, hogy testreszabjuk a tárhelyünket, ha


a kiszolgáló beállítófájljában nem módosíthatjuk a paramétereket. A PHP mûködé-
sét közvetlenül azonban a php.ini szabályozza.

php.ini
A PHP mûködését a fordítás vagy telepítés után is befolyásolhatjuk, a php.ini hasz-
nálatával. UNIX rendszereken az alapbeállítású könyvtár a php.ini fájl számára
a /usr/local/lib, Windows rendszereken a Windows könyvtára. Emellett
a feldolgozásra kerülõ PHP oldal könyvtárában – a munkakönyvtárban – elhelye-
zett php.ini fájlban felülbírálhatjuk a korábban beállított értékeket, így akár
könyvtáranként különbözõ beállításokat adhatunk meg.

A letöltött PHP csomag könyvtárában található egy minta php.ini fájl, amely
a „gyári beállításokat” tartalmazza. Ezek az értékek lépnek érvénybe akkor, ha
a PHP nem talál egy php.ini fájlt sem.

Az alapértékek elegendõek lehetnek ahhoz, hogy a könyv példáit futtassuk, ám


célszerû néhány módosítást elvégezni; ezeket a huszonkettedik órában tárgyaljuk.

A php.ini fájl beállításai egy névbõl, egy egyenlõségjelbõl és egy értékbõl áll-
nak. A szóközöket a feldolgozó figyelmen kívül hagyja.

Ha a PHP elõretelepítve állt rendelkezésre a rendszerünkön, ellenõrizzük a php.ini


fájlban található beállításokat. Ha esetleg nem lenne jogosultságunk a fájl módosítá-
sára, a PHP programjaink könyvtárába helyezett saját php.ini fájllal felülírhatjuk
02_ora.qxd 8/3/2001 6:10 PM Page 18

18 2. óra

az alapbeállítást. Másik lehetõségünk, hogy létrehozunk egy PHPRC nevû környezeti


változót, amely kijelöli php.ini fájlunkat.

A php.ini beállításait bármikor módosíthatjuk, de ha feldolgozónk Apache modul-


ként fut, a változtatások érvénybe léptetéséhez újra kell indítani a webkiszolgálót.

short_open_tag
A short_open_tag beállítás határozza meg, hogy használhatjuk-e a rövid <?
kód ?> formát a PHP kódblokkok írására. Ha ez ki van kapcsolva, az alábbi sorok
valamelyikét láthatjuk:

short_open_tag = Off
short_open_tag = False
short_open_tag = No

Ahhoz, hogy engedélyezzük ezt a beállítást, a következõ sorok egyikét kell


használnunk:

short_open_tag = On
short_open_tag = True
short_open_tag = Yes

A PHP blokkok kezdõ- és záróelemeirõl a következõ órában lesz szó.

Hibajelentések beállításai
Ha hibákat keresünk programjainkban, hasznos a hibaüzenetek kiírása a HTML
oldalba a böngészõ számára. Ez alapbeállításban bekapcsolt:

display_errors = On

Beállíthatjuk a hibajelentési szintet is. Ez azt jelenti, hogy mivel többféle hibaüzenet-
típus is rendelkezésre áll, letilthatjuk egyik vagy másik típust, amennyiben nem
szeretnénk PHP oldalaink kimenetében látni az abba a csoportba tartozó hibákat.
A hibakezelés beállításával alaposabban a huszonkettedik órában foglalkozunk,
addig az alábbi értékadás tökéletesen megfelel:

error_reporting = E_ALL & ~ E_NOTICE

Ezzel a PHP minden hibát jelezni fog a lehetséges problémákat jelölõ figyelmezte-
tések kivételével. Ezek a figyelmeztetések megakadályoznák néhány szokásos
PHP módszer alkalmazását, ezért ez az alapbeállítás.
02_ora.qxd 8/3/2001 6:10 PM Page 19

A PHP telepítése 19

Változókra vonatkozó beállítások


A PHP a GET és POST kérésekbõl, sütikbõl, kiszolgálói és környezeti értékekbõl lét-
rehoz bizonyos változókat. Ennek mûködését is a php.ini fájlban szabályozhatjuk.

A track_vars beállítás azt adja meg, hogy létrejöjjenek-e asszociatív tömbök


egy HTTP lekérés eredményeként. Ez alapbeállításban engedélyezett, a PHP 4.0.2-
es változat óta nem is lehet kikapcsolni:
2
track_vars = On

A register_globals beállítás azt határozza meg, hogy a HTTP lekéréskor


ezek a változók globális változókként jöjjenek-e létre. A PHP fejlõdésével egyre in-
kább azt javasolják a programozóknak, hogy mellõzzék ennek a szolgáltatásnak
a használatát, mivel így rendkívül sok változó jöhet létre és ez ütközéseket okoz-
hat, ha nem jól választjuk meg a változók neveit. Ennek ellenére ma a PHP prog-
ramok legnagyobb része – többek között a könyv számos példája is – arra épít,
hogy ez a beállítás be van kapcsolva:

register_globals = On

Segítség!
A segítség mindig kéznél van az Interneten, különösen a nyílt forráskódú progra-
mokkal kapcsolatos problémák esetén. Ezért mielõtt a levelezõprogramunk „Küldés”
gombját megnyomnánk, gondolkozzunk el egy kicsit. Akármennyire is mûködés-
képtelennek tûnhet a telepített értelmezõnk, beállításunk vagy programozási megol-
dásunk, jó esélyünk van rá, hogy nem vagyunk ezzel egyedül. Valaki talán már
megválaszolta kérdésünket.

Ha falba ütközünk, az elsõ hely, ahol segítséget kereshetünk, a PHP hivatalos hon-
lapja a http://www.php.net/ címen, különösen az ott található, olvasói kiegészí-
tésekkel ellátott kézikönyv: http://www.php.net/manual/. Sok segítséget és
információt találhatunk a Zend webhelyén is: http://www.zend.com/. A magyar
PHP fejlesztõk a weblabor.hu webmester honlapon találhatnak rengeteg információt:
http://weblabor.hu/php/. Itt készítjük a magyar PHP dokumentációt is.

Ha nem sikerült megtalálni a megoldást, hasznos segítség lehet, hogy a PHP hivatalos
webhelyén keresést is végezhetünk. A tanács, ami után kutatunk, talán egy sajtóköz-
leményben, vagy egy FAQ-fájlban rejtõzik. Egy másik kitûnõ forrás a PHP
Knowledge Base: http://www.faqts.com/knowledge-base/index.phtml.
Keresés itt is végezhetõ.
02_ora.qxd 8/3/2001 6:10 PM Page 20

20 2. óra

Még mindig sikertelenek próbálkozásaink? A PHP levelezõlisták kereshetõ archí-


vumaira mutató hivatkozások megtalálhatóak
a http://www.php.net/support.php oldalon, számos más hivatkozással
együtt. Ezek az archívumok óriási mennyiségû információt tartalmaznak a PHP kö-
zösség legjobbjaitól. Eltölthetünk némi idõt pár kulcsszó kipróbálásával.

Amennyiben ezek után is meg vagyunk gyõzõdve arról, hogy problémánk még nem
merült fel korábban, jó szolgálatot tehetünk a PHP közösségnek, ha felhívjuk rá
a figyelmet.

A PHP levelezõlistákra való jelentkezéshez az archívumokat felsoroló oldalon talá-


lunk hivatkozásokat. A listák gyakran nagy forgalmúak, de ezt ellensúlyozza, hogy
rendkívül sokat lehet belõlük tanulni. Ha érdeklõdünk a PHP programozás iránt,
legalább egy kötegelt kézbesítésû (digest) listára iratkozzunk fel. A kötegeltség azt
jelenti, hogy a listára érkezõ leveleket nem egyenként, hanem naponta egy-két
levélben összefûzve kapjuk meg. Ha sikerül megtalálni az érdeklõdési körünknek
megfelelõ levelezõlistát a számos lehetõség közül, beküldhetjük oda a problémán-
kat. A PHP honlapján nemzetközi levelezõlisták oldalaira mutató hivatkozásokat is
találunk. A magyar PHP levelezõlista és annak archívuma
a http://weblabor.hu/wl-phplista/ címen érhetõ el.

Mielõtt elküldenénk egy kérdést, gyûjtsük össze a probléma szempontjából fontos


információkat, de ne írjunk túl sokat! A következõ elemek gyakran szükségesek:

• A használt operációs rendszer

• A telepítés alatt álló vagy futó PHP-változat száma

• A beállításkor használt configure paraméterek

• Bármilyen configure vagy make kimenet, ami elõjelezhette a telepítési hibát

• Egy ésszerûen teljes részlet a kódból, ami a problémát okozza

Miért kell ilyen sok szempontot figyelembe vennünk, mielõtt egy levelezõlistára
postáznánk kérdésünket? Elõször is a fejlesztési problémák megoldásában szerzett
tapasztalat elõnyös lehet a késõbbi munka során. Egy tapasztalt programozó álta-
lában gyorsan és hatékonyan tud problémákat megoldani. Egy alapvetõ kérdés
feltevése technikai jellegû listán többnyire egy-két olyan választ eredményez,
amelyben felhívják figyelmünket, hogy erre a kérdésre az archívumban megtalál-
ható a válasz.
02_ora.qxd 8/3/2001 6:10 PM Page 21

A PHP telepítése 21

Másodszor, egy levelezõlista nem hasonlítható össze egy kereskedelmi termék


támogatási központjával. Senki sem kap fizetést, hogy megválaszolja kérdéseinket.
Ennek ellenére lenyûgözõ szellemi erõforráshoz nyújt elérést, beleértve a PHP
néhány fejlesztõjét is. A kérdések a válasszal együtt az archívumba kerülnek, hogy
késõbb más programozók segítségére lehessenek. Ezért felesleges olyan kérdések
feltevése, amelyek már többször szerepeltek a listán.

Ezek megfontolása után ne vonakodjunk kérdéseket küldeni a levelezõlistákra.


A PHP fejlesztõk civilizált, segítõkész emberek és a probléma felvetésével esetleg
2
másoknak is segíthetünk egy hasonló kérdés megoldásában.

Végül, ha úgy tûnik, hogy a probléma nem a mi kódunkban, hanem a PHP-


értelmezõprogramban található, küldjünk egy hibajelentést a fejlesztõknek
a http://bugs.php.net/ címen. Ha a gubanc valóban új, a hibát a PHP
következõ kiadásában többnyire kijavítják.

Összefoglalás
A PHP 4 nyílt forráskódú. Nyílt abban az értelemben is, hogy nem szükséges egy
meghatározott kiszolgálót, operációs rendszert vagy adatbázist használnunk
a fejlesztéshez. Ebben az órában láttuk, honnan szerezhetõ be a PHP és más –
a webhelyek szolgáltatásaiban segítõ – nyílt forráskódú programok. Megnéztük,
hogyan fordítható le a PHP Apache modulként Linux rendszeren. Ha nem a for-
ráskódot töltjük le a hálózatról, hanem egy lefordított változatot, akkor a csomag-
ban részletes információkat találunk a telepítéssel kapcsolatban. Áttekintettünk
néhány configure paramétert, melyekkel a feldolgozó képességeit befolyásol-
hatjuk. Tanultunk a php.ini fájlról és néhány beállítási lehetõségrõl, amit meg-
adhatunk benne. Végül megnéztük, hol találhatunk segítséget, ha problémáink
akadnak. Ezzel készen állunk arra, hogy megbirkózzunk a PHP nyelvvel.

Kérdések és válaszok
A telepítést Apache webkiszolgálót használó Linux operációs rendszeren
vezettük végig. Ez azt jelenti, hogy a könyv nem megfelelõ más rendszer
vagy kiszolgálóprogram használata esetén?
A PHP egyik nagy erõssége, hogy több rendszeren is képes futni. Ha problémák
adódnak az adott rendszeren a PHP telepítésével, olvassuk el a csomagban talál-
ható dokumentációt és a PHP kézikönyv megfelelõ fejezetét. Általában széles körû
lépésrõl-lépésre leírt utasításokat kapunk a telepítéshez. Ha továbbra sem sikerül
megoldani a problémát, a „Segítség!” címû részben ismertetett módszerek célrave-
zetõk lehetnek.
02_ora.qxd 8/3/2001 6:10 PM Page 22

22 2. óra

Hogyan érhetõk el böngészõbõl a PHP állományok, ha a gépre telepítettük


a webkiszolgálót?
A PHP alkalmazások fejlesztéséhez és teszteléséhez nem szükséges, hogy számító-
gépünk az Internetre legyen kapcsolva, bár az éles környezetben való ellenõrzés
hasznosabb lehet. Bármilyen operációs rendszert is használunk, akár hálózatba
kötött gépen dolgozunk, akár nem, a saját gépünk IP-címe 127.0.0.1, neve akkor
is localhost lesz. Ezért ha a saját gépünkön lévõ webkiszolgáló gyökérkönyvtárá-
ban lévõ elso.php fájlt szeretnénk megnyitni,
a http://localhost/elso.php címen érhetjük el. Windows operációs rend-
szeren feltétlenül telepíteni kell a TCP/IP támogatást, hogy ez a lehetõség rendelke-
zésre álljon.

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. Hol érhetõ el a PHP kézikönyv?

2. UNIX rendszeren hogyan kaphatunk bõvebb információkat a beállítási lehe-


tõségekrõl (milyen paramétereket kell átadni a configure-nak)?

3. Hogy hívják általában az Apache beállításait tartalmazó fájlt?

4. Milyen sort kell az Apache beállítófájlhoz adni, hogy a kiszolgáló felismerje


a .php kiterjesztést?

5. Mi a PHP beállításait tartalmazó fájl neve?

Feladatok
1. Telepítsük a PHP-t. Ha sikerült, nézzük át a PHP beállítófájlt és ellenõrizzük
a telepítés helyességét.
03_ora.qxd 8/3/2001 6:10 PM Page 23

3.ÓRA
Elsõ PHP oldalunk
A PHP telepítése és beállítása után eljött az ideje, hogy elkezdjünk vele dolgozni.
Ebben az órában elkészítjük az elsõ programunkat és elemezzük a kódot. Az óra
végére képesek leszünk olyan oldalak készítésére, amelyek HTML és PHP kódot is
tartalmaznak.

Ebben az órában a következõket tanuljuk meg:

• Hogyan hozzunk létre, töltsünk fel és futtassunk egy PHP programot?

• Hogyan vegyítsünk HTML és PHP kódot egy dokumentumon belül?

• Hogyan tehetjük a kódunkat olvashatóbbá megjegyzések használatával?


03_ora.qxd 8/3/2001 6:10 PM Page 24

24 3. óra

Elsõ programunk
Vágjunk a közepébe és kezdjük egy kész PHP oldallal! A kezdéshez nyissuk meg
kedvenc szövegfájl-szerkesztõnket! A HTML dokumentumokhoz hasonlóan a PHP
állományok is formázás nélküliek, tisztán szövegfájlok. Ez azt jelenti, hogy bármi-
lyen szövegfájl szerkesztésére íródott programmal készíthetünk PHP állományokat.
Ilyenek például a Windows Jegyzettömbje, a Simple Text vagy a BBEdit MacOS
alatt, vagy a VI és az Emacs UNIX esetében. A legnépszerûbb HTML-szerkesztõk
általában nyújtanak valamilyen különleges támogatást PHP-szerkesztéshez is.
Ilyenek például a kódszínezés, a kifejezésszerkesztõ vagy a tesztelõ.

Gépeljük be a 3.1. programot, és mentsük elso.php néven.

3.1. program Az elsõ PHP program


1: <?php
2: print ("Hello Web!");
3: ?>

A 3.1. ábra a 3.1. program kódját mutatja a KEdit programban.

3.1. ábra
Elsõ PHP oldalunk
begépelve a KEdit
programban

A kiterjesztés igen fontos, mivel ez jelzi a kiszolgáló számára, hogy a fájl PHP kó-
dot tartalmaz és futtatásához meg kell hívni a feldolgozót. Az alapbeállítású PHP
kiterjesztés a .php, ez azonban a kiszolgáló beállításainak módosításával megvál-
toztatható. Ezzel az elõzõ órában részletesen foglalkoztunk.

Ha nem közvetlenül a kiszolgálóprogramot futtató gépen dolgozunk, feltehetõen


az FTP nevû szolgáltatást kell használnunk arra, hogy PHP oldalunkat a kiszolgá-
lóra juttassuk. A Windowsban többek között a WS-FTP használható erre a célra,
MacOS használata esetén a Fetch lehet hasznos.
03_ora.qxd 8/3/2001 6:10 PM Page 25

Elsõ PHP oldalunk 25

Ha sikerült elhelyeznünk a dokumentumot a kiszolgálón, elérhetjük egy


webböngészõ segítségével. Ha minden rendben ment, az ablakban a program
kimenetét láthatjuk. A 3.2. ábra az elso.php kimenetét mutatja.

3.2. ábra
Siker: a 3.1. program
kimenete

Ha a PHP-t nem sikerült telepíteni a kiszolgálóra vagy nem a megfelelõ kiterjesztést


használtuk, feltehetõen nem az elõzõ ábrán látható kimenetet kapjuk. Ebben az
esetben általában a PHP program forráskódját látjuk viszont. Ezt mutatja a 3.3. ábra.

3.3. ábra
Kudarc: a kiterjesztés
nem azonosítható

Ha ez történik, elõször ellenõrizzük a mentett fájl kiterjesztését. A 3.3. ábrán látha-


tó lapot véletlenül elso.nphp névvel mentettük. Ha a kiterjesztéssel nincs prob-
léma, ellenõriznünk kell, hogy a PHP sikeresen felkerült-e a rendszerre és hogy
a kiszolgálót beállítottuk-e a megfelelõ kiterjesztés felismerésére. Ezekkel a kérdé-
sekkel az elõzõ órában foglalkoztunk részletesen.

Miután sikerült feltölteni és kipróbálni elsõ programunkat, kielemezhetjük az


imént begépelt kódot.
03_ora.qxd 8/3/2001 6:10 PM Page 26

26 3. óra

PHP blokkok kezdése és befejezése


Amikor PHP oldalakat írunk, tudatnunk kell a feldolgozóval, mely részeket hajtsa
végre. Ha nem adjuk meg, hogy a fájl mely részei tartalmaznak PHP kódot, az ér-
telmezõ mindent HTML-nek tekint és változtatás nélkül továbbküldi a böngészõ
számára. A 3.1. táblázat a PHP kód blokkjainak kijelölésére szolgáló elemeket so-
rolja fel:

3.1. táblázat PHP blokkok kezdõ- és záróelemei


Elnevezés Kezdõelem Záróelem
Hagyományos <?php ?>
Rövid <? ?>
ASP stílusú <% %>
Script elem <SCRIPT LANGUAGE="PHP"> </SCRIPT>

A 3.1. táblázatban látható lehetõségek közül csak az elsõ és az utolsó áll minden
beállítás esetén rendelkezésre. A rövid és ASP stílusú elemeket engedélyezni kell
a php.ini fájlban. Az elõzõ órában tárgyaltuk a beállítás módszerét.

A rövid kezdõelemek felismerését a short_open_tag beállítással engedélyez-


hetjük, ha „On” állapotba tesszük:

short_open_tag = On

A rövid kezdõelemek alapbeállításban engedélyezettek, ezért nem kell szerkeszte-


nünk a php.ini fájlt, hacsak valaki elõzõleg ki nem kapcsolta.

Az ASP stílusú elemek engedélyezéséhez az asp_tags beállítást kell bekapcsolni:

asp_tags = On

Ez akkor lehet hasznos, ha olyan termékkel készítünk PHP oldalakat, amely törli
a PHP blokkokat, de az ASP részeket érintetlenül hagyja.

A php.ini fájl módosítása után lehetõségünk van választani a bekapcsolt típusok


közül. Rajtunk múlik, hogy melyik elemet választjuk, de ha XML-lel is szeretnénk
dolgozni, mindenképpen a hagyományos formát kell alkalmaznunk és le kell
tiltanunk a rövid stílust. Mivel a hagyományos forma minden rendszeren rendelke-
zésre áll, a fejlesztõk programjaikban általában ezt alkalmazzák, így a könyvben is
ezzel fogunk találkozni.
03_ora.qxd 8/3/2001 6:10 PM Page 27

Elsõ PHP oldalunk 27

Nézzük meg, hogyan fest egy PHP fájl, amely a fent említett formákat használja az
elõzõ program kibõvítéseként. Ha engedélyeztük, bármely négy kezdõ- és
záróelemet használhatjuk a programban:

<?
print ("Hello Web!");
?>

<?php
print ("Hello Web!");
?>

<%
print ("Hello Web!");
%>
3
<SCRIPT LANGUAGE="PHP">
print ("Hello Web!");
</SCRIPT>

Ha PHP-ben egysoros kódot írunk, nem kell külön sorba tennünk a kezdõ- és
záróelemeket, illetve a programsort:

<?php print("Hello Web!"); ?>

Miután megtanultuk, hogyan határozhatunk meg egy PHP kódblokkot, nézzük


meg még közelebbrõl a 3.1. programot.

A print() függvény
A print() függvény kiírja a kapott adatokat. A legtöbb esetben minden,
ami a print() függvény kimenetén megjelenik, a böngészõhöz kerül. A függvé-
nyek olyan parancsok, amelyek valamilyen mûveletet végeznek, többnyire attól
függõen, hogy milyen adatokat kapnak. A függvényeknek átadott adatokat majd-
nem mindig zárójelbe kell tennünk a függvény neve után. Ebben az esetben
a print() függvénynek egy karakterláncot adtunk át. A karakterláncokat mindig
(egyes vagy kettõs) idézõjelbe kell tenni.

A függvények általában megkövetelik, hogy zárójeleket helyez-


zünk a nevük után, akár küldünk adatokat számukra, akár nem.
A print() ebbõl a szempontból kivételes, mivel hívása esetén
a zárójelek elhagyhatók. Ez a print() függvény megszokott
formája, ezért a továbbiakban ezt alkalmazzuk.
03_ora.qxd 8/3/2001 6:10 PM Page 28

28 3. óra

A 3.1. program egyetlen sorát pontosvesszõvel fejeztük be. A pontosvesszõ tudatja


a feldolgozóval, hogy az utasítás véget ért.

Az utasítás a feldolgozónak adott parancs. Általánosságban a PHP szá-


ÚJDONSÁG
mára azt jelenti, mint az írott vagy beszélt nyelvben a mondat. Az utasí-
tásokat a legtöbb esetben pontosvesszõvel kell lezárni, a mondatokat írásjellel. Ez
alól kivételt képeznek azok az utasítások, amelyeket más utasítások vesznek kö-
rül, illetve azok, amelyek blokk végén állnak. A legtöbb esetben azonban az utasí-
tás végérõl lefelejtett pontosvesszõ megzavarja az elemzõt és hibát okoz.

Mivel a 3.1. programban az egyetlen megadott utasítás a blokk végén áll, a pon-
tosvesszõ elhagyható.

HTML és PHP kód egy oldalon


3.2. program PHP program HTML tartalommal
1: <html>
2: <head>
3: <title>3.2. program PHP program HTML
tartalommal</title>
4: </head>
5: <body>
6: <b>
7: <?php
8: print ("Hello Web!");
9: ?>
10: </b>
11: </body>
12: </html>

Látható, hogy HTML kód beépítése a PHP oldalakba egyszerûen a HTML tartalom
begépelésébõl áll. A PHP feldolgozó figyelmen kívül hagy mindent a PHP nyitó-
és záróelemeken kívül. Ha a 3.2. programot megnézzük böngészõvel, a „Hello
Web!” szöveget látjuk vastagon, mint ahogy ez a 3.4. ábrán megfigyelhetõ. Ha
a dokumentum forrását is megnézzük, ahogy a 3.5. ábra mutatja, a kód hagyomá-
nyos HTML dokumentumnak tûnik.
03_ora.qxd 8/3/2001 6:10 PM Page 29

Elsõ PHP oldalunk 29

Egy dokumentumban a HTML elemek közé tetszõleges számú PHP kódblokk


írható. Bár több kódblokkot helyezhetünk el egy dokumentumon belül, ezek
együttesen alkotnak egy programot. Bármi, amit egy megelõzõ blokkban hatá-
roztunk meg, (változók, függvények vagy osztályok) a dokumentumon belül
elérhetõ lesz a késõbbi blokkokban is. A több együttmûködõ, összességében egy
nagyobb programot megvalósító PHP fájlt nevezzük PHP alkalmazásnak.

3.4. ábra
Ha a 3.2 programot
megnézzük böngé-
szõvel, a „Hello Web!”
szöveget látjuk
vastagon
3

3.5. ábra
Ha a dokumentum
forrását nézzük, a
kód hagyományos
HTML dokumen-
tumnak tûnik
03_ora.qxd 8/3/2001 6:10 PM Page 30

30 3. óra

Megjegyzések a PHP kódokban


Az íráskor átlátható programkód hat hónappal késõbb reménytelenül kuszának
tûnhet. Ha azonban megjegyzéseket fûzünk a kódhoz, miközben írjuk, a késõbbi-
ekben sok idõt takaríthatunk meg magunknak és más programozóknak, akik az
adott kóddal fognak dolgozni.

A megjegyzések a kódban található olyan szövegrészek, amelyeket


ÚJDONSÁG
a feldolgozó figyelmen kívül hagy. Segítségükkel olvashatóbbá tehetjük
a programot és jegyzeteket fûzhetünk hozzá.

A PHP egysoros megjegyzései két perjellel (//) vagy egy kettõskereszt karakterrel
(#) kezdõdhetnek. Az ezen jelzések után található szöveget a PHP-értelmezõ
mindig figyelmen kívül hagyja, a sor vagy a PHP blokk végéig.

// Ez megjegyzés
# Ez is megjegyzés

A többsoros megjegyzések egy perjelet követõ csillag karakterrel kezdõdnek (/*)


és egy csillagot követõ perjellel (*/) fejezõdnek be.

/*
Ez egy megjegyzés.
A PHP-értelmezõ
ezen sorok egyikét
sem fogja feldolgozni.
*/

Összefoglalás
Mostanra rendelkezésünkre állnak azok az eszközök, melyekkel képesek vagyunk
egy egyszerû PHP program futtatására egy megfelelõen beállított kiszolgálón.

Ebben az órában elkészítettük elsõ PHP programunkat. Láttuk, hogyan használható


egy szöveges szerkesztõ, hogy létrehozzunk és mentsünk egy PHP dokumentumot.
Elemeztük a négy rendelkezésre álló blokk kezdõ- és záróelemet. Megtanultuk,
miként kell használnunk a print() függvényt, hogy a böngészõ számára kime-
netet küldjünk, majd összeállítottunk egy HTML és PHP kódot is tartalmazó állo-
mányt. Végül tanultunk a megjegyzésekrõl és arról, hogyan építhetjük be ezeket
a PHP dokumentumokba.
03_ora.qxd 8/3/2001 6:10 PM Page 31

Elsõ PHP oldalunk 31

Kérdések és válaszok
Melyik a legjobb kezdõ- és záróelem?
Ez nagyrészt saját döntésünkön múlik. A hordozhatóság szem elõtt tartásával
a hagyományos <?php ?> megoldás a legjobb döntés. A rövid kezdõelemek alap-
esetben engedélyezettek és rendelkeznek a tömörség elõnyös tulajdonságával.

Milyen szerkesztõprogramokat kell elkerülni a PHP kódok készítésekor?


Ne használjunk olyan szövegszerkesztõket, amelyek saját formátummal rendel-
keznek, mint a Microsoft Word. Ha ilyen típusú szerkesztõvel mentjük szöveges
fájlként az elkészült dokumentumot, a kódban megbújó rejtett karakterek biztos
gondot fognak okozni.

Mikor kell megjegyzéseket fûzni a kódokhoz?


Ez is nagyrészt a programozó döntésén múlik. A rövid programokhoz nem érde-
3
mes magyarázatot fûzni, mivel ezek még hosszú idõ után is érthetõek maradnak.
Ha a program azonban akár csak egy kicsit is bonyolult, már javasolt megjegyzé-
sekkel bõvíteni. Ez hosszú távon idõt takarít meg számunkra és kíméli idegeinket.

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. A felhasználó böngészõjével elolvashatja-e a PHP kódot?

2. Adjuk meg a PHP hagyományos kezdõ- és záróelemeit!

3. Adjuk meg az ASP stílusú kezdõ- és záróelemeket!

4. Adjuk meg a Script kezdõ- és záróelemeket!

5. Mely függvény használatos a böngészõ számára küldött adatok kiírásához?

Feladatok
1. Gyakoroljuk a PHP oldalak elkészítését, feltöltését és futtatását!
04_ora.qxd 8/3/2001 6:10 PM Page 33

II. RÉSZ
A PHP nyelv
4. óra Az alkotóelemek
5. óra Vezérlési szerkezetek
6. óra Függvények
7. óra Tömbök
8. óra Objektumok
04_ora.qxd 8/3/2001 6:10 PM Page 34
04_ora.qxd 8/3/2001 6:10 PM Page 35

4. ÓRA
Az alkotóelemek
Ebben az órában már mélyebben elmerülünk a nyelv rejtelmeiben. Az alapokkal
kezdünk, így a kezdõ programozónak rengeteg új információt kell majd feldol-
goznia. Aggodalomra azonban semmi ok, bármikor vissza lehet lapozni a könyv-
ben. A lényeg, hogy a fejezetben leírtak megértésére törekedjünk, ne csupán
a memorizálásra.
A gyakorlott programozóknak is ajánlatos legalábbis átlapozniuk ezen óra anya-
gát. Az órában a következõket tanuljuk meg:

• Mik a változók és hogyan használjuk azokat?

• Hogyan hozhatunk létre változókat és hogyan érhetjük el azokat?

• Mik azok az adattípusok?

• Melyek a leggyakrabban használt mûveletek?

• Hogyan hozhatunk létre kifejezéseket mûveletjelek használatával?

• Hogyan határozhatunk meg állandókat és hogyan használhatjuk azokat?


04_ora.qxd 8/3/2001 6:10 PM Page 36

36 4. óra

Változók
A változók különleges tárolók, amiket abból a célból hozunk létre, hogy értéket he-
lyezzünk el bennük. A változók egy dollárjelbõl ($) és egy „tetszõlegesen” választott
névbõl tevõdnek össze. A név betûket, számokat és aláhúzás karaktereket (_) tartal-
mazhat (számmal azonban nem kezdõdhet!), szóközöket és más olyan karaktereket,
amelyek nem számok vagy betûk, nem. Íme néhány érvényes változónév:

$a;
$egy_hosszabb_valtozonev;
$elalszom_zzzzzzzzzzzzzz;

Ne feledjük, hogy a pontosvesszõ (;) a PHP utasítás végét jelzi, így az elõzõekben
a pontosvesszõ nem része a változók nevének.

A változók adatokat – számokat, karakterláncokat, objektumokat, tömböket


ÚJDONSÁG
vagy logikai értékeket – tárolnak, tartalmuk bármikor módosítható.

Amint látjuk, rengeteg féle nevet adhatunk változóinknak, bár a csak számokból
álló változónevek nem szokványosak. Változó létrehozásához (deklarálásához, va-
gyis bevezetéséhez) egyszerûen csak bele kell írni azt a programunkba. Létreho-
záskor általában rögtön értéket is szoktunk adni a változónak.

$szam1 = 8;
$szam2 = 23;

Itt két változót hoztunk létre és a hozzárendelõ mûveletjellel (=) értéket is adtunk
azoknak. Az értékadásról bõvebben a Mûveletjelek és kifejezések címû részben ta-
nulunk, az óra késõbbi részében. Miután értéket adtunk változóinknak, úgy kezel-
hetjük azokat, mintha maguk lennének az értékek. Vagyis a fenti példánál marad-
va a létrehozás után írt

print $szam1;

hatása megegyezik a

print 8;

hatásával, feltéve, hogy a $szam1 változó értéke 8 maradt.


04_ora.qxd 8/3/2001 6:10 PM Page 37

Az alkotóelemek 37

Dinamikus változók
Változót tehát úgy hozunk létre, hogy egy dollárjel után írjuk a változó nevét. Szo-
katlan, ám hasznos, hogy a változó nevét is tárolhatjuk változóban. Tehát ha az
alábbi módon értéket rendelünk egy változóhoz

$felhasznalo = "Anna";

az megegyezik azzal, mintha ezt írnánk:

$tarolo = "felhasznalo";
$$tarolo = "Anna";

A $tarolo változó a "felhasznalo" szöveget tartalmazza, ezért a $$tarolo-t


úgy tekinthetjük, mint egy dollárjelet, melyet egy változó neve követ ($tarolo),
a $tarolo viszont ismét csak egy változó, amit a PHP a változó értékével helyette-
sít, vagyis "felhasznalo"-val. Tehát a fenti kifejezés a $felhasznalo-val
egyenértékû.

Dinamikus változókat karakterlánc-konstanssal (állandóként


4
meghatározott karakterlánccal) is létrehozhatunk. Ekkor a válto-
zó nevéül szolgáló karakterláncot kapcsos zárójelbe tesszük:
${"felhasznalonev"} = "Anna";
Ez elsõ ránézésre nem tûnik túl hasznosnak. Ha azonban
a karakterlánc-összefûzõ mûveletjellel ciklusban használjuk
(lásd a Vezérlési szerkezetek címû ötödik órát), e módszerrel
dinamikus változók tucatjait hozhatjuk létre.

A dinamikus változók elérése ugyanúgy történik, mint a „hagyományos” változóké,


tehát a

$felhasznalo = "Anna";
print $felhasznalo;

azonos a

$felhasznalo = "Anna";
$tarolo = "felhasznalo";
print $$tarolo;

kóddal, eltekintve természetesen attól, hogy itt létrehoztunk egy $tarolo nevû
változót, melynek értéke "felhasznalo".
04_ora.qxd 8/3/2001 6:10 PM Page 38

38 4. óra

Ha egy dinamikus változót egy karakterláncon belül szeretnénk kiírni, az értelme-


zõnek némi segítséget kell adnunk. Az alábbi print utasítás hatására

$felhasznalo = "Anna";
$tarolo = "felhasznalo";
print "$$tarolo";

a böngészõ nem az "Anna" szöveget jeleníti meg, mint ahogy várnánk, hanem
kiírja a dollárjelet, majd a "felhasznalo" szöveget, vagyis összességében azt,
hogy "$felhasznalo".

Ha egy változót kettõs idézõjelek közé teszünk, a PHP szolgálatkészen


ÚJDONSÁG
beilleszti annak értékét.

A mi esetünkben a PHP a $tarolo karaktersorozatot a "felhasznalo" szö-


vegre cserélte, az elsõ dollárjelet pedig a helyén hagyta. Annak érdekében, hogy
egyértelmûvé tegyük a PHP számára, hogy a karakterláncon belüli változó egy di-
namikus változó része, kapcsos zárójelbe kell tennünk. Az alábbi kódrészlet print
utasítása

$felhasznalo = "Anna";
$tarolo = "felhasznalo";
print "${$tarolo}";

már az "Anna" szöveget írja ki, ami a $felhasznalo nevû változó értéke.

A 4.1. példaprogram egy PHP oldalon belül tartalmazza a korábbi programrészlete-


ket és változóban tárolt karakterláncokat használ a $felhasznalo kezdeti érté-
kének beállítására és elérésére.

4.1. program Dinamikusan beállított és elért változók


1: <html>
2: <head>
3: <title>4.1. program Dinamikusan beállított és elért
változók</title>
4: </head>
5: <body>
6: <?php
7: $tarolo = "felhasznalo";
8: $$tarolo = "Anna";
9: // lehetne egyszerûen csak:
10: // $felhasznalo = "Anna";
11: // vagy
04_ora.qxd 8/3/2001 6:10 PM Page 39

Az alkotóelemek 39

4.1. program (folytatás)


12: // ${"felhasznalo"} = "Anna"
13: // persze ekkor nem kellenek dinamikus változók
14: print "$felhasznalo<br>";
15: print $$tarolo;
16: print "<br>";
17: print "${$tarolo}<br>";
18: print "${'felhasznalo'}<br>";
19: ?>
20: </body>
21: </html>

Hivatkozások a változókra
A PHP alapértelmezés szerint értékadáskor a változók értékeit használja. Ez azt jele-
nti, hogy ha az $egyikValtozo-t hozzárendeljük egy $masikValtozo-hoz,
akkor a $masikValtozo-ba az $egyikValtozo értékének másolata kerül.
Az $egyikValtozo tartalmának késõbbi módosítása nincs semmiféle hatással 4
a $masikValtozo-ra. A 4.2. példaprogram ezt mutatja be.

4.2. program Változók érték szerinti hozzárendelése


1: <html>
2: <head>
3: <title>4.2. program Változók érték szerinti
hozzárendelése</title>
4: </head>
5: <body>
6: <?php
7: $egyikValtozo = 42;
8: $masikValtozo = $egyikValtozo;
9: // $masikValtozo-ba $egyikValtozo tartalmának
másolata kerül
10: $egyikValtozo = 325;
11: print $masikValtozo; // kiírja, hogy 42
12: ?>
13: </body>
14: </html>
04_ora.qxd 8/3/2001 6:10 PM Page 40

40 4. óra

Itt a 42 értéket adjuk az $egyikVatozo-nak, majd a $masikValtozo-hoz hozzá-


rendeljük az $egyikValtozo-t. Ekkor a $masikValtozo-ba az $egyikValtozo
értékének másolata kerül. A print utasítás igazolja ezt, mivel a böngészõben
a 42 jelenik meg.

A PHP 4-es kiadásában ezt a viselkedésmódot megváltoztathatjuk. Kikényszeríthet-


jük, hogy a $masikValtozo-ba ne az $egyikValtozo értéke kerüljön, hanem
egy hivatkozás, amely az $egyikValtozo-ra mutat. Ezt illusztrálja a 4.3. példa-
program.

4.3. program Változóra mutató hivatkozás


1: <html>
2: <head>
3: <title>4.3. program Változóra mutató
hivatkozás</title>
4: </head>
5: <body>
6: <?php
7: $egyikValtozo = 42;
8: $masikValtozo = &$egyikValtozo;
9: // $masikValtozo-ba $egyikValtozo-ra mutató
hivatkozás kerül
10: $egyikValtozo = 325;
11: print $masikValtozo; // kiírja, hogy 325
12: ?>
13: </body>
14: </html>

A 4.2. példaprogramhoz képest a változás mindössze egy karakter.


Az $egyikValtozo elé tett & jel gondoskodik róla, hogy az érték másolata helyett
a $masikValtozo-ba a változóra mutató hivatkozás kerül. Ezután
a $masikValtozo elérésekor az $egyikValtozo-ra vonatkozó mûveletek ered-
ményét láthatjuk. Más szavakkal: mind az $egyikValtozo,
mind a $masikValtozo ugyanazt a „tárolódobozt” használja, így értékeik
mindig egyenlõk. Mivel ez az eljárás kiküszöböli az egyik változóból a másikba tör-
ténõ értékmásolás szükségességét, csekély mértékben növelheti a teljesítményt.
Hacsak nem használunk nagyon gyakran értékadásokat, ez a teljesítménybeli nö-
vekedés alig érezhetõ.

A hivatkozások a PHP 4-es változatában kerültek a nyelvbe.


04_ora.qxd 8/3/2001 6:10 PM Page 41

Az alkotóelemek 41

Adattípusok
A különféle típusú adatok több-kevesebb helyet foglalnak a memóriában, a nyelv
pedig mindegyiket némileg más módon kezeli. Ezért néhány programozási nyelv
megköveteli, hogy a programozó elõre meghatározza a változótípusát. A PHP 4
gyengén típusos, ami azt jelenti, hogy az adattípusokat úgy kezeli, mintha a típus
az adathoz rendelt kiegészítõ információ lenne. A PHP vegyes megközelítést hasz-
nál. Egyfelõl ez azt jelenti, hogy a változók rugalmasan használhatók: egyszer
karakterlánc, másszor esetleg szám lehet bennük. Másfelõl, nagyobb méretû prog-
ramokban zavar forrása lehet, ha egy adott típusú változót várunk egy változóban,
miközben valami teljesen más van benne.
A 4.1. táblázat a PHP 4-ben elérhetõ hat fontosabb adattípust tartalmazza, rövid le-
írással és példával.

4.1. táblázat Adattípusok


Típus Példa Leírás
Integer 5 Egész szám
Double 3.234 Lebegõpontos szám
String "hello" Karakterek sorozata, karakterlánc 4
Boolean true Logikai változó. Értéke igaz vagy hamis
(true vagy false) lehet
Object Objektum, lásd a nyolcadik, objektumokkal
foglalkozó órát
Array Tömb, lásd a hetedik, tömbökkel foglalkozó órát

Az adattípusok közül a tömböket és az objektumokat késõbbre hagyjuk.


A változó típusának meghatározására a PHP 4 beépített gettype() függvényét
használhatjuk. Ha a függvényhívás zárójelei közé változót teszünk, a gettype()
egy karakterlánccal tér vissza, amely a változó típusát adja meg. A 4.4. példaprog-
ram egy változóhoz négy különbözõ típusú értéket rendel, majd meghívja
a gettype() függvényt.

A függvényekrõl bõvebben a hatodik órában, a „Függvények”


címû részben tanulunk.
04_ora.qxd 8/3/2001 6:10 PM Page 42

42 4. óra

4.4. program Változó típusának vizsgálata


1: <html>
2: <head>
3: <title>4.4. program Változó típusának
vizsgálata</title>
4: </head>
5: <body>
6: <?php
7: $proba = 5;
8: print gettype( $proba ); // integer
9: print "<br>"; // új sor, hogy ne follyanak össze
a típusnevek
10: $proba = "öt";
11: print gettype( $proba ); // string
12: print "<br>";
13: $proba = 5.0;
14: print gettype( $proba ); // double
15: print "<br>";
16: $proba = true;
17: print gettype( $proba ); // boolean
18: print "<br>";
19: ?>
20: </body>
21: </html

Az elõbbi program a következõ kimenetet eredményezi:

integer
string
double
boolean

Az integer egész szám, vagyis olyan szám, amelyben nincs tizedesjegy („tizedes-
pont”).

Könyvünk ugyan magyar nyelvû, a PHP 4 azonban az angol kife-


jezéseket használja. A gettype ezért adja meg az integer, string,
double és boolean szavakat. Ugyanígy az angol írásmód szerint
a szám egészrészét a törtrésztõl nem tizedesvesszõ, hanem tize-
despont választja el. Annak érdekében, hogy ne kövessünk
elgépelési hibákat, a könyv hátralevõ részében a magyarul kicsit
szokatlanul csengõ tizedespont kifejezést használjuk.
04_ora.qxd 8/3/2001 6:10 PM Page 43

Az alkotóelemek 43

A string karakterek sorozata. Ha programunkban karakterláncokkal dolgozunk,


mindig aposztrófok (') vagy macskakörmök (") közé kell azokat tennünk.
A double lebegõpontos szám, vagyis olyan szám, amely tartalmazhat tizedespontot.
A boolean a két logikai érték, a true (igaz) és a false (hamis) egyikét veheti fel.

A PHP-ben a 4-es változat elõtt nem létezett a boolean típus.


Ott is használhattuk a true értéket, de azt az értelmezõ egysze-
rûen integer típusú 1-re fordította.

Típus módosítása a settype() segítségével


A PHP a változó típusának módosítására a settype() függvényt biztosítja.
A settype()-ot úgy kell használnunk, hogy a megváltoztatandó típusú változót,
valamint a változó új típusát a zárójelek közé kell tennünk, vesszõvel elválasztva.
A 4.5. példaprogramban a 3.14-et (lebegõpontos szám, vagyis double) olyan típu-
sokká alakítjuk, mely típusokat ebben a fejezetben részletesen tárgyalunk.

4.5. program Változó típusának módosítása a settype() függvény segítségével 4


1: <html>
2: <head>
3: <title>4.5. program Változó típusának módosítása
a settype() függvény segítségével</title>
4: </head>
5: <body>
6: <?php
7: $ki_tudja_milyen_tipusu = 3.14;
8: print gettype( $ki_tudja_milyen_tipusu ); // double
9: print " - $ki_tudja_milyen_tipusu<br>"; // 3.14
10: settype( $ki_tudja_milyen_tipusu, "string" );
11: print gettype( $ki_tudja_milyen_tipusu ); // string
12: print " - $ki_tudja_milyen_tipusu<br>"; // 3.14
13: settype( $ki_tudja_milyen_tipusu, "integer" );
14: print gettype( $ki_tudja_milyen_tipusu ); // integer
15: print " - $ki_tudja_milyen_tipusu<br>"; // 3
16: settype( $ki_tudja_milyen_tipusu, "double" );
17: print gettype( $ki_tudja_milyen_tipusu ); // double
18: print " - $ki_tudja_milyen_tipusu<br>"; // 3.0
19: settype( $ki_tudja_milyen_tipusu, "boolean" );
20: print gettype( $ki_tudja_milyen_tipusu ); // boolean
21: print " - $ki_tudja_milyen_tipusu<br>"; // 1
04_ora.qxd 8/3/2001 6:10 PM Page 44

44 4. óra

4.5. program (folytatás)


22: ?>
23: </body>
24: </html>

A típusmódosítás után minden esetben a gettype() függvényt használtuk,


hogy meggyõzõdjünk arról, hogy a típus módosítása sikerült, majd kiírjuk
a $ki_tudja_milyen_tipusu nevû változó értékét a böngészõbe. Amikor
a "3.14" karakterláncot egésszé alakítjuk, a tizedespont utáni információ elvész.
Ezért történhet meg, hogy a $ki_tudja_milyen_tipusu változónak még
akkor is 3 az értéke, amikor újból lebegõpontos számmá alakítjuk.
A végén a $ki_tudja_milyen_tipusu változót logikai típusúvá alakítottuk.
Az ilyen átalakításoknál a 0-tól különbözõ számok értéke – akárcsak a nem nulla
hosszúságú karakterláncoké – mindig true lesz. Amikor a PHP-ben kiírunk egy
logikai változót, akkor ha a változó értéke true, a kimeneten 1-et látunk, míg
a false értékû változók semmilyen kimenetet nem eredményeznek. Így már ért-
hetõ, hogy az utolsó kiíratás miért eredményezett 1-et.

Típus módosítása típusátalakítással


A változó neve elé zárójelbe írt adattípus segítségével a változó értékének általunk
meghatározott típusúvá alakított másolatát kapjuk. A lényegi különbség
a settype() függvény és a típusátalakítás között, hogy az átalakítás során
az eredeti változó típusa és értéke változatlan marad, míg a settype() alkal-
mazása során az eredeti változó típusa és értéke az új adattípus értelmezési
tartományához idomul. A 4.6. program ezt hivatott illusztrálni.

4.6. program Változó típusának módosítása


típusátalakítás segítségével
1: <html>
2: <head>
3: <title>4.6. program Változó típusának módosítása
típusátalakítás segítségével</title>
4: </head>
5: <body>
6: <?php
7: $ki_tudja_milyen_tipusu = 3.14;
8: $tarolo = ( double ) $ki_tudja_milyen_tipusu;
9: print gettype( $tarolo ) ; // double
10: print " - $tarolo<br>"; // 3.14
04_ora.qxd 8/3/2001 6:10 PM Page 45

Az alkotóelemek 45

4.6. program (folytatás)


11: $tarolo = ( string ) $ki_tudja_milyen_tipusu;
12: print gettype( $tarolo ); // string
13: print " - $tarolo<br>"; // 3.14
14: $tarolo = ( integer ) $ki_tudja_milyen_tipusu;
15: print gettype( $tarolo ); // integer
16: print " - $tarolo<br>"; // 3
17: $tarolo = ( double ) $ki_tudja_milyen_tipusu;
18: print gettype( $tarolo ); // double
19: print " - $tarolo<br>"; // 3.14
20: $tarolo = ( boolean ) $ki_tudja_milyen_tipusu;
21: print gettype( $tarolo ); // boolean
22: print " - $tarolo<br>"; // 1
23: ?>
24: </body>
25: </html>

A $ki_tudja_milyen_tipusu változó típusát a program egyik pontján sem 4


változtattuk meg, az végig lebegõpontos szám marad. Csupán másolatokat hozunk
létre, amelyek az általunk meghatározott típusúvá alakulnak és az új érték kerül
aztán a $tarolo nevû változóba. Mivel a $ki_tudja_milyen_tipusu máso-
latával dolgozunk, a 4.5. példaprogrammal ellentétben az eredeti változóban
semmilyen információt nem veszítünk el.

Mûveletjelek és kifejezések
Most már képesek vagyunk adatokat helyezni változóinkba, meghatározhatjuk,
sõt meg is változtathatjuk egy változó típusát. Egy programozási nyelv azonban
nem túl hasznos, ha a tárolt adatokkal nem végezhetünk mûveleteket. A mûvelet-
jelek (operátorok) olyan jelek, amelyek azon mûveleteket jelzik, melyek lehetõvé
teszik, hogy egy vagy több értékbõl egy új értéket hozzunk létre. Az értéket,
amellyel a mûveletet végezzük, operandusnak hívjuk.

Az operátor (mûveletjel) jel vagy jelsorozat, amelyet ha értékek össze-


ÚJDONSÁG
kapcsolására használunk, valamilyen mûveletet végezhetünk, amely
általában új értéket eredményez.

Az operandus egy érték, amelyet a mûveletjellel kapcsolatban használunk.


ÚJDONSÁG
Egy mûveletjelhez általában két operandus tartozik.
04_ora.qxd 8/3/2001 6:10 PM Page 46

46 4. óra

Kapcsoljunk össze két operandust és hozzunk létre egy új értéket:

4 + 5

Itt a 4 és az 5 az operandusok. Az összeadó operátor (+) végez rajtuk mûveletet


és ez szolgáltatja a 9 értéket. A mûveletjelek többsége két operandus között
helyezkedik el, bár az óra késõbbi részében látni fogunk néhány kivételt is.

Az operandusok és mûveletjelek együttesét kifejezésnek hívjuk. Annak ellenére,


hogy még a legelemibb kifejezéseket is mûveletjelek segítségével hozzuk létre,
a kifejezésnek nem kell szükségszerûen operátort tartalmaznia. Valójában a PHP
mindent, ami értéket határoz meg, kifejezésnek tekint. Így az állandók, például
az 543; változók, mint a $felhasznalo és a függvényhívások, például
a gettype() is kifejezések, a 4+5 kifejezés pedig két további kifejezésre (4 és
5) és egy operátorra bontható.

A kifejezés a függvények, értékek és mûveletjelek olyan együttese,


ÚJDONSÁG
amely értéket határoz meg. Általánosságban azt mondhatjuk, hogy
ha értékként használhatunk valamit, akkor az kifejezés.

Most, hogy az alapelveket tisztáztuk, ideje megismerkednünk a PHP 4 alapvetõ


mûveleteivel.

Hozzárendelés
Már találkoztunk a hozzárendelõ mûveletjellel, valahányszor értéket adtunk válto-
zóinknak. A hozzárendelõ operátor egyetlen karakterbõl áll, az egyenlõségjelbõl
(=). Jelentése: a mûveletjel jobb oldalán álló kifejezés értékét hozzárendeljük a bal
oldali operandushoz.

$nev = "Kõmûves Kelemen";

A $nev változó ekkor a "Kõmûves Kelemen" szöveget fogja tartalmazni. Érdekes


módon, ez az értékadás maga is egy kifejezés. Elsõ látásra úgy tûnik, hogy a hozzá-
rendelés csak a $nev értékét változtatja meg, de valójában a kifejezés, amely a hoz-
zárendelõ mûveletjelbõl áll, mindig a jobb oldalon álló kifejezés értékének másolatát
adja vissza. Így a

print ( $nev = "Kõmûves Kelemen" );

utasítás kiírja a böngészõbe, hogy "Kõmûves Kelemen", azon felül, hogy


a "Kõmûves Kelemen" szöveget a $nev változóhoz rendeli.
04_ora.qxd 8/3/2001 6:10 PM Page 47

Az alkotóelemek 47

Aritmetikai mûveletek
Az aritmetikai mûveletek pontosan azt teszik, amit elvárunk tõlük. A 4.2. táblázat
a megfelelõ mûveletjeleket sorolja fel. Az összeadó mûveletjel hozzáadja a jobb
oldali operandust a bal oldalihoz, a kivonó mûveletjel a jobb oldali operandust
kivonja a bal oldaliból, az osztó mûveletjel a bal oldali operandust elosztja a jobb
oldalival, a szorzó mûveletjel pedig összeszorozza a bal és a jobb oldali
operandusokat. A maradékképzõ (modulus) mûveletjel a bal és a jobb operandus
egész osztásának maradékát adja.

4.2. táblázat Aritmetikai mûveletek


Mûveletjel Név Példa Érték
+ Összeadás 10+3 13
- Kivonás 10-3 7
/ Osztás 10/3 3.333333333333
* Szorzás 10*3 30
% Maradék 10%3 1 4

Összefûzés
Az összefûzés jele a pont (.). Mindkét operandust karakterláncnak tekintve,
a jobb oldali elemet hozzáfûzi a bal oldalihoz. Vagyis a

"Para" . " Zita"

kifejezés értéke:

"Para Zita"

Az elemek típusuktól függetlenül karakterláncként értékelõdnek ki és az eredmény


is mindig karakterlánc lesz.

További hozzárendelõ mûveletek


Annak ellenére, hogy valójában csak egy hozzárendelõ mûvelet van, a PHP 4
számos további mûveletjelet biztosít, amelyek a bal oldali operandust módosítják.
A mûveletek az operandusokat általában nem változtatják meg, ez alól azonban
a hozzárendelés kivétel.
04_ora.qxd 8/3/2001 6:10 PM Page 48

48 4. óra

Az összetett hozzárendelõ mûveletjelek egy hagyományos mûveletjelbõl és az azt


követõ egyenlõségjelbõl állnak. Az összetett mûveletjelek megkímélnek minket at-
tól, hogy két operátort kelljen használnunk és az elgépelés esélyét is csökkentik. A

$x = 4;
$x += 4; // $x most 8

például egyenértékû a következõvel:

$x = 4;
$x = $x + 4; // $x most 8

Hozzárendelõ mûveletjelet minden aritmetikai és összefûzõ jelhez kapcsolhatunk.


A 4.3. táblázat a leggyakoribb párosításokat tartalmazza.

4.3. táblázat Néhány összetett hozzárendelõ mûveletjel


Mûveletjel Példa Egyenértékû kifejezés
+= $x += 5 $x = $x + 5
-= $x -= 5 $x = $x - 5
*= $x *= 5 $x = $x * 5
/= $x /= 5 $x = $x / 5
%= $x %= 5 $x = $x % 5
.= $x .= "próba" $x = $x . "próba"

A 4.3. táblázat minden példájában a $x változó értéke változik meg, a jobb oldali
operandusnak megfelelõen.

Összehasonlítás
Az összehasonlító mûveletek az operandusokon vizsgálatokat végeznek. Logikai
értékkel térnek vissza, vagyis értékük true lesz, ha a feltételezett viszony fennáll,
és false, ha nem. Ez a típusú kifejezés az olyan vezérlési szerkezetekben hasz-
nos, mint az if és while utasítások. Ezekkel az ötödik órában találkozunk majd.

Ha meg szeretnénk vizsgálni, hogy az $x-ben tárolt érték kisebb-e 5-nél, a kisebb,
mint jelet használhatjuk:

$x < 5
04_ora.qxd 8/3/2001 6:10 PM Page 49

Az alkotóelemek 49

Ha $x értéke 3, a kifejezés értéke true, ha $x értéke 7, a kifejezés értéke false lesz.

Az összehasonlító mûveletjeleket a 4.4. táblázatban találhatjuk. $x értéke 4.

4.4. táblázat Összehasonlító mûveletek


Mûveletjel Név Igaz, ha Példa Eredmény
== egyenlõ a két érték megegyezik $x == 5 false
!= nem egyenlõ a két érték különbözõ $x != 5 true
=== azonos a két érték és típus $x === 5 false
megegyezik
!== nem azonos a két érték vagy típus $x !== 5 true
különbözõ
> nagyobb, mint a bal oldal nagyobb $x > 4 false
a jobb oldalnál
>= nagyobb, vagy
egyenlõ
a bal oldal nagyobb
a jobb oldalnál,
$x >= 4 true
4
vagy egyenlõ
< kisebb, mint a bal oldal kisebb $x < 4 false
a jobb oldalnál
<= kisebb, vagy a bal oldal kisebb $x <= 4 true
egyenlõ a jobb oldalnál,
vagy egyenlõ

Ezeket a mûveletjeleket többnyire egészekkel vagy lebegõpontos számokkal hasz-


náljuk, bár az egyenlõség karakterláncok esetében is vizsgálható.

Bonyolultabb összehasonlító kifejezések létrehozása


logikai mûveletek segítségével
A logikai mûveletjelek logikai értékeken végeznek mûveleteket. A vagy operátor
például true-val tér vissza, ha bal vagy jobb operandusa true.

true || false

A fenti eredménye true.


04_ora.qxd 8/3/2001 6:10 PM Page 50

50 4. óra

Az és operátor csak akkor ad true-t, ha mindkét operandusa true.

true && false

A fenti értéke false. Valószínûtlen azonban, hogy a gyakorlatban logikai állan-


dókon akarunk mûveleteket végezni. Sokkal több értelme van, hogy két vagy
több kifejezést vizsgáljunk meg. Például:

( $x > 2 ) && ( $x < 15 )

Az eredmény itt true, ha az $x-ben tárolt érték nagyobb, mint 2, de kisebb,


mint 15. A zárójeleket azért tettük be, hogy a programkód átláthatóbb legyen.
A 4.5. táblázat a logikai mûveleteket sorolja fel.

4.5. táblázat Logikai mûveletek


Mûveletjel Név Igaz, ha Példa Eredmény
|| vagy a bal vagy a jobb true || false true
operandus igaz
or vagy a bal vagy a jobb true or false true
operandus igaz
xor kizáró vagy vagy a bal, vagy a jobb true xor true false
operandus igaz,
de csak az egyikük
&& és a bal és a jobb true && false false
operandus is igaz
and és a bal és a jobb true and false false
operandus is igaz
! tagadás az egyetlen operandus !true false
hamis

Miért kell kétféle vagy és és mûveletjel? A magyarázat a mûveletek kiértékelési


sorrendjében rejlik, amelyrõl a fejezet késõbbi részében tanulunk.
04_ora.qxd 8/3/2001 6:10 PM Page 51

Az alkotóelemek 51

Egész típusú változók értékének növelése


és csökkentése
Amikor PHP-ben programozunk, gyakran kerülünk olyan helyzetbe, hogy egy
egész típusú változó értékét kell eggyel növelnünk vagy csökkentenünk. Ez jel-
lemzõen abban az esetben fordul elõ, amikor egy ciklusban számolunk valamit.
Már két módját is tanultuk annak, hogyan tehetjük ezt meg. Egyrészt lehetõségünk
van az összeadó mûveletjellel növelni a változó értékét:

$x = $x + 1; // $x értéke eggyel nõ

De használhatunk összetett értékadó-összeadó mûveletjelet is:

$x += 1; // $x értéke eggyel nõ

Az eredmény mindkét esetben $x-be kerül. Mivel az ilyen típusú kifejezések


nagyon gyakoriak, ezért a PHP (a C nyelv mintájára) biztosít egy különleges mûve-
letet, amely lehetõséget ad arra, hogy egy egész típusú változóhoz hozzáadjunk
egyet vagy kivonjunk belõle egyet. A megfelelõ mûveletjelek a növelõ, illetve csök- 4
kentõ operátorok. Ezeknek utótagként (poszt-inkrementáló és poszt-dekrementáló)
és elõtagként (pre-inkrementáló és pre-dekrementáló) használt változata is létezik.
Az utótagként használt növelõ mûveletjel a változó neve után írt két pluszjelbõl áll.

$x++; // $x értéke eggyel nõ

Ha hasonló módon két mínuszjelet írunk a változó neve után, a változó értéke
eggyel csökken.

$x-; // $x értéke eggyel csökken

Ha a növelõ vagy csökkentõ mûveletjelet feltételes kifejezésen belül használjuk,


fontos, hogy az operandus értéke csak a feltétel kiértékelése után változik meg:

$x = 3;
$x++ < 4; // igaz

A fenti példában $x értéke 3, amikor a 4-gyel hasonlítjuk össze, így a kifejezés


értéke igaz. Miután az összehasonlítás megtörtént, $x értéke eggyel nõ. Bizonyos
körülmények között arra lehet szükség, hogy a változó értéke a kiértékelés elõtt
csökkenjen vagy nõjön. Erre szolgálnak az elõtagként használt változatok. Önma-
gukban ezek a mûveletjelek ugyanúgy viselkednek, mint utótagként alkalmazott
formáik, csak a két plusz- vagy mínuszjelet ekkor a változó neve elé kell írnunk.
04_ora.qxd 8/3/2001 6:10 PM Page 52

52 4. óra

++$x; // $x értéke eggyel nõ


-$x; // $x értéke eggyel csökken

Ha ezek a mûveletjelek egy nagyobb kifejezés részei, a változó értékének módosí-


tása a vizsgálat elõtt történik meg.

$x = 3;
++$x < 4; // hamis

Ebben a kódrészletben $x értéke eggyel nõ, mielõtt összehasonlítanánk 4-gyel.


Az összehasonlítás értéke false, mivel a 4 nem kisebb 4-nél.

A mûveletek kiértékelési sorrendje


Az értelmezõ a kifejezéseket általában balról jobbra olvassa. A több mûveletjelet
tartalmazó összetettebb kifejezéseknél már bonyolultabb a helyzet. Elõször vegyünk
egy egyszerû esetet:

4 + 5

Itt minden tiszta és érthetõ, a PHP hozzáadja a 4-et az 5-höz. De mi a helyzet


a következõ esetben?

4 + 5 * 2

Itt már egy problémával találkozunk szembe: a kifejezés azt jelenti, hogy „vedd
a négyet és az ötöt, add össze õket, majd az eredményt szorozd meg kettõvel”,
vagyis 18 az értéke? Esetleg azt, hogy „add hozzá a négyhez az öt és a kettõ
szorzatát”, vagyis az eredmény 14? Ha egyszerûen balról jobbra olvasnánk, akkor
az elsõ változatot kellene elfogadnunk. A PHP-ben azonban minden mûveletjelhez
tartozik egy „elsõbbségi tényezõ” (prioritás). Mivel a szorzás elsõbbséget élvez az
összeadással szemben, így (iskolai tanulmányainkkal összhangban) a második vá-
lasz a helyes megoldás.

Természetesen van rá lehetõség, hogy kikényszerítsük, hogy elõször az összeadás


hajtódjon végre. Erre a zárójelek használata ad lehetõséget:

( 4 + 5 ) * 2

Bármilyen sorrendben értékelõdjenek is ki a mûveletek, ha hosszú kifejezésekkel


dolgozunk vagy nem vagyunk biztosak a dolgunkban, érdemes zárójeleket hasz-
nálnunk, így érthetõbbé válik a program és megkíméljük magunkat a hibakeresés
fáradalmaitól. A 4.6. táblázatból az ebben az órában tárgyalt mûveletek elsõbbségét
tudhatjuk meg (csökkenõ sorrendben).
04_ora.qxd 8/3/2001 6:10 PM Page 53

Az alkotóelemek 53

4.6. táblázat A mûveletek elsõbbsége csökkenõ sorrendben.


Mûveletjelek
! ++ -- (típusátalakítás)
/ * %
+ - .
< <= => >
== === != !==
&&
||
= += -= /= %= .=
and
xor
or

Mint látjuk, az or késõbb értékelõdik ki, mint a || mûveletjel, az and-del szem- 4


ben pedig elsõbbséget élvez a &&, így a kisebb prioritású logikai mûveletjeleket
használva az összetett logikai kifejezések olvasásmódját módosíthatjuk. Ez nem
feltétlenül mindig jó ötlet. Bár a következõ két kifejezés egyenértékû, a második
kifejezés könnyebben olvasható:

$x || $y and $z
( $x || $y ) && $z

Állandók
A változók rugalmas adattárolási lehetõséget nyújtanak számunkra. Megváltoztat-
hatjuk értéküket, sõt típusukat is, bármely pillanatban. Ha azonban azt szeretnénk,
hogy egy adott név alatt tárolt érték ne változzon a program futása során, létrehoz-
hatunk állandókat (konstansokat) is. Ezt a PHP beépített define() függvénye
segítségével tehetjük meg. Miután az állandót létrehoztuk, annak értékét nem
szabad (nem tudjuk) megváltoztatni. Az állandó nevét, mint karakterláncot és
az értéket vesszõvel elválasztva a zárójeleken belülre kell írnunk.

define( "ALLANDO_NEVE", 42);

Az állandó értéke természetesen lehet szám, karakterlánc vagy logikai típusú is.
Az a szokás, hogy az állandók neve CSUPA NAGYBETÛBÕL áll. Az állandók neve
nem tartalmaz dollárjelet, így az állandók elérése csupán a név leírásából áll.
04_ora.qxd 8/3/2001 6:10 PM Page 54

54 4. óra

A 4.7. példaprogramban láthatunk egy példát állandók elérésére és használatára.

4.7. program Állandó létrehozása


1: <html>
2: <head>
3: <title>4.7. program Állandó létrehozása</title>
4: </head>
5: <body>
6: <?php
7: define ( "FELHASZNALO", "Virág" );
8: print "Üdvözlöm ".FELHASZNALO;
9: ?>
10: </body>
11: </html>

Figyeljük meg, hogy az állandónak a karakterláncba ágyazásakor összefûzést


kellett használnunk. Ez azért szükséges, mert az értelmezõ nem tudja megkülön-
böztetni a kettõs idézõjelbe írt egyszerû szöveget az állandók nevétõl.

Minden programban használható állandók


A PHP néhány beépített állandót automatikusan biztosít. Ilyen például a __FILE__,
amely az értelmezõ által beolvasott fájl nevét tartalmazza. A __LINE__ az aktuális
sor számát tartalmazza. Ezek az állandók hibaüzeneteink kiírásánál hasznosak. Az ép-
pen használt PHP változatszámát többek között a PHP_VERSION állandóból tudhat-
juk meg. Ez akkor lehet elõnyös, ha egy program csak a PHP egy adott változatával
futtatható.

Összefoglalás
Ebben az órában végigvettük a PHP nyelv néhány alapvetõ tulajdonságát. Tanul-
tunk a változókról és arról, hogyan rendelhetünk hozzájuk értéket. Hallottunk
a dinamikus, vagyis „változó” változókról. Megtanultuk azt is, hogyan kell a válto-
zó értékének másolata helyett a változókra hivatkozni. Új mûveletjeleket ismer-
tünk meg és megtanultuk, hogyan kell azokat összetettebb kifejezésekké össze-
gyúrni. Végül megtanultuk, hogyan kell állandókat létrehozni és használni.
04_ora.qxd 8/3/2001 6:10 PM Page 55

Az alkotóelemek 55

Kérdések és válaszok
Mikor kell tudnunk egy változó típusát?
Elõfordul, hogy a változó típusa behatárolja, milyen mûveleteket végezhetünk vele.
Például mielõtt egy matematikai kifejezésben használunk egy változót, megnézhet-
jük, hogy egyáltalán egész vagy lebegõpontos számot tartalmaz-e. Az ehhez hason-
ló kérdésekkel kicsit késõbb, a tizenhatodik fejezetben foglalkozunk.

Muszáj követnünk a változók nevére vonatkozó szokásokat?


A cél mindig az, hogy a program egyszerûen olvasható és érthetõ legyen. Az olyan
változónevek, mint az $abc12345 nem mondanak semmit a változó programbeli
szerepérõl és elgépelni is könnyû azokat. Ezért érdemes rövid és jellemzõ neveket
választanunk.
Az $f név, bár rövid, bizonyára nem árul el semmit a változó szerepérõl.
Ezt most talán nehéz elhinni, de amikor egy hónap elteltével próbáljuk meg folytat-
ni a program írását, majd megtapasztaljuk. A $fajlnev már sokkal jobb választás.

Meg kell tanulnunk a mûveletjelek kiértékelési sorrendjét?


Nincs semmi akadálya, hogy megtanuljuk, de tartogassuk energiánkat fontosabb
dolgokra. Használjunk zárójeleket a kifejezésekben, így programunk jobban olvas- 4
ható lesz és nem kell törõdnünk a kiértékelési sorrenddel.

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. Az alábbiak közül melyek NEM lehetnek változónevek?
$egy_felhasznalo_altal_elkuldott_ertek
$44444444444xyz
$xyz44444444444
$______________szamlalo______________
$az elso
$fajl-nev

2. Hogyan használhatjuk fel az alábbi változót dinamikus változó létrehozására?


A változónak adjuk a 4 értéket! Hogyan érhetjük el az új változót?
$en_valtozom = "dinamikus";

3. Milyen kimenetet eredményez az alábbi programsor?


print gettype("4");
04_ora.qxd 8/3/2001 6:10 PM Page 56

56 4. óra

4. Mit ír ki az alábbi néhány sor?


$proba_valtozo = 5.4566;
settype ( $proba_valtozo, "integer");
print $proba_valtozo;

5. Az alábbi sorok melyike nem tartalmaz kifejezést?


4;
gettype(44);
5/12;

6. Az elõzõ kérdésben szereplõ sorok melyikében van mûveletjel?

7. Az alábbi kifejezés milyen értéket ad vissza?


5 < 2
Milyen típusú a kérdéses érték?

Feladatok
1. Készítsünk programot, amely legalább öt különbözõ változót tartalmaz.
Adjunk nekik különbözõ típusú értékeket, majd használjuk a gettype()
függvényt a változók típusainak meghatározására.

2. Rendeljünk értéket két változóhoz. Használjuk az összehasonlító mûveleteket


annak eldöntésére, hogy az elsõ változó értéke

• azonos-e a második változó értékével

• kisebb-e a második változó értékénél

• nagyobb-e a második változó értékénél

• kisebb-e a második változó értékénél vagy egyenlõ-e azzal

Írassuk ki az összehasonlítások eredményét a böngészõbe!


Változtassuk meg a változók értékét és futtassuk le újból a programot!
05_ora.qxd 8/3/2001 6:11 PM Page 57

5. ÓRA
Vezérlési szerkezetek
Az elõzõ órában létrehozott programok minden futtatáskor ugyanazt az eredményt
adták, mindig ugyanazok az utasítások hajtódtak végre ugyanabban a sorrendben.
Ez nem biztosít túl nagy teret a rugalmasságnak.

Ebben az órában néhány olyan szerkezettel ismerkedünk meg, melyek segítségével


programunk alkalmazkodhat a körülményekhez. A következõket tanuljuk meg:

• Hogyan használjuk az if szerkezetet arra, hogy bizonyos sorok csak adott


feltételek teljesülése mellett hajtódjanak végre?
• Hogyan adhatunk meg csak bizonyos feltételek nem teljesülése esetén végre-
hajtandó mûveleteket?
• Hogyan használjuk a switch utasítást, hogy egy kifejezés értékétõl függõen
hajtsunk végre utasításokat?
• Hogyan ismételjük egy kódrészlet végrehajtását a while utasítás segítségével?
• Hogyan készíthetünk elegánsabb ciklusokat a for utasítás segítségével?
• Hogyan lépjünk ki a ciklusokból?
• Hogyan ágyazzuk egymásba a ciklusokat?
05_ora.qxd 8/3/2001 6:11 PM Page 58

58 5. óra

Elágazások
A legtöbb program feltételeket értékel ki és azok eredményének megfelelõen
változtatja viselkedését. A lehetõséget, hogy a PHP oldalak tartalma dinamikussá
váljék, az teszi lehetõvé, hogy a programok kimenete bizonyos feltételektõl
függhet. A legtöbb programozási nyelvhez hasonlóan a PHP 4-es változata is
biztosítja erre a célra az if utasítást.

Az if utasítás
Az if utasítás kiértékeli a zárójelek közötti kifejezést. Ha a kifejezés értéke igaz,
az utasításhoz tartozó programrész végrehajtódik. Ha a kifejezés hamis, a blokk
egyszerûen figyelmen kívül marad. Ez teszi lehetõvé a programoknak, hogy
döntéseket hozzanak.

if ( kifejezés )
{
// ha a kifejezés értéke igaz,
// ez a blokk végrehajtódik
}

Az 5.1. példaprogramban csak akkor hajtódik végre az if utáni rész, ha a kifejezés


értéke igaz

5.1. program Az if utasítás


1: <html>
2: <head>
3: <title>5.1. program Az if utasítás</title>
4: </head>
5: <body>
6: <?php
7: $hangulat = "boldog";
8: if ( $hangulat == "boldog" )
9: {
10: print "Hurrá, jó kedvem van!";
11: }
12: ?>
13: </body>
14: </html>
05_ora.qxd 8/3/2001 6:11 PM Page 59

Vezérlési szerkezetek 59

A $hangulat változó értékét a "boldog"-gal az összehasonlító mûveletjel (==)


segítségével hasonlítottuk össze. Ha egyeznek, a kifejezés értéke igaz, így az if
kifejezéshez tartozó programblokk végrehajtódik. Bár az elõbbi programban
a print utasítást kapcsos zárójelek közé zártuk, ez csak akkor szükséges,
ha az if kifejezéstõl függõen több utasítást akarunk végrehajtani. A következõ
két sor így elfogadható:

if ( $hangulat == "boldog" )
print "Hurrá, jó kedvem van!";

Ha a $hangulat értékét "szomorú"-ra változtatjuk és újból lefuttatjuk progra-


munkat, az if kifejezés értéke hamis lesz, így a print utasítás nem hajtódik végre
és programunk nem ad kimenetet.

Az if utasítás else ága


Amikor az if utasítást használjuk, gyakran szeretnénk, hogy legyen egy olyan
alternatív programrész, amely akkor hajtódik végre, ha a vizsgált feltétel nem igaz.
Ezt úgy érhetjük el, hogy az if utasítás programrésze után kiírjuk az else kulcs-
szót, majd az alternatív programrészt. A séma a következõ:

if (feltétel)
{
// itt következik az a programrész, amely akkor kerül
// végrehajtásra, ha a feltétel értéke igaz
}
5
else
{
// itt pedig az a programrész található, amely akkor fut le,
// ha a feltétel értéke hamis
}

Az 5.2. példaprogram az 5.1. példaprogram kiegészített változata. Egy olyan


programblokkot tartalmaz, amely akkor hajtódik végre, ha a $hangulat értéke
nem "boldog".

5.2. program Az else ággal kiegészített if utasítás


1: <html>
2: <head>
3: <title>5.2. program Az else ággal kiegészített if
utasítás</title>
4: </head>
05_ora.qxd 8/3/2001 6:11 PM Page 60

60 5. óra

5.2. program (folytatás)


5: <body>
6: <?php
7: $hangulat = "szomorú";
8: if ( $hangulat == "boldog" )
9: {
10: print "Hurrá, jó kedvem van!";
11: }
12: else
13: {
14: print "$hangulat vagyok, nem boldog.";
15: }
16: ?>
17: </body>
18: </html>

A példában a $hangulat értéke "szomorú", ami persze nem "boldog",


így az if utasítás feltétele hamis lesz, vagyis az elsõ programrész nem kerül
végrehajtásra. Az else-et követõ programblokk azonban lefut és a böngészõbe
a "szomorú vagyok, nem boldog." szöveg kerül.

Az if utasítás else ágának segítségével programunkban kifinomultabb döntése-


ket hozhatunk, de egy feltétel eredménye alapján még így is csak kétféle dolgot
tehetünk. A PHP 4 azonban többre képes: több kifejezés értéke alapján sokféle-
képp reagálhatunk.

Az if utasítás elseif ága


Mielõtt az else ágban alternatív kódrészt adnánk meg, több kifejezés értékétõl
függõen – az if - elseif - else szerkezet segítségével – a programmal mást és
mást végeztethetünk. A használandó utasításforma a következõ:

if ( feltétel )
{
// ez a rész akkor fut le, ha a feltétel igaz
}
elseif ( másik feltétel )
{
// ez a rész akkor fut le, ha a másik feltétel igaz,
// és minden elõzõ feltétel hamis
}
// itt még tetszõleges számú elseif rész következhet
05_ora.qxd 8/3/2001 6:11 PM Page 61

Vezérlési szerkezetek 61

else
{
// ez a rész akkor kerül végrehajtásra, ha egyik
// feltétel sem volt igaz
}

A Perl nyelvben gyakorlattal rendelkezõk figyeljenek rá, hogy


a kulcsszót itt elseif-nek hívják!

Ha az elsõ feltétel értéke hamis, a hozzá tartozó programrész nem kerül végre-
hajtásra. Ezután a PHP megvizsgálja az elseif kifejezés értékét. Ha a kifejezés
igaz, a hozzá tartozó programblokk fut le. Végül, ha egyik feltétel sem igaz,
az else utáni rész kerül végrehajtásra. Annyi elseif-et írhatunk a programba,
amennyi csak jólesik. Sõt, ha nincs szükségünk else ágra, vagyis olyan program-
részre, amely akkor hajtódik végre, ha egyik feltétel sem igaz, akár el is hagyhatjuk.

Az 5.3. példaprogram az elõzõeket egészíti ki egy elseif ággal.

5.3. program Egy else és elseif ággal bõvített if utasítás


1: <html>
2: <head>
3: <title>5.3. program Egy else és elseif ággal bõví-
tett if utasítás</title>
5
4: </head>
5: <body>
6: <?php
7: $hangulat = "szomorú";
8: if ( $hangulat == "boldog" )
9: {
10: print "Hurrá, jó kedvem van!";
11: }
12: elseif ( $hangulat == "szomorú" )
13: {
14: print "Szomorú vagyok.";
15: }
16: else
17: {
18: print "Sem boldog, sem szomorú nem vagyok, hanem
$hangulat.";
05_ora.qxd 8/3/2001 6:11 PM Page 62

62 5. óra

5.3. program (folytatás)


19: }
20: ?>
21: </body>
22: </html>

A $hangulat értéke itt "szomorú". Ez nem azonos a "boldog"-gal, ezért


az elsõ blokk nem kerül végrehajtásra. Az elseif kifejezés a $hangulat válto-
zó értékét hasonlítja össze a "szomorú" szöveggel. Mivel az egyenlõség fennáll,
ehhez a feltételhez tartozó programrész hajtódik végre.

A switch utasítás
A switch utasítás egy lehetséges módja annak, hogy egy kódrészletet egy kifeje-
zés értékétõl függõen hajtsunk végre. Van azonban néhány különbség az imént
tanult if és a switch között. Az if-et az elseif-fel használva több kifejezés
értékétõl tehetjük függõvé, hogy mi történjen. A switch esetében a program
csak egy kifejezést vizsgál meg és annak értékétõl függõen különbözõ sorokat
futtat. A kifejezésnek egyszerû típusnak kell lennie (szám, karakterlánc vagy
logikai érték). Az if feltétele csak igaz vagy hamis lehet, a switch kifejezését
akárhány értékkel összehasonlíthatjuk. De nézzük inkább az általános szerkezetet:

switch ( kifejezés )
{
case érték1:
// ez történjen, ha kifejezés értéke érték1
break;
case érték2:
// ez történjen, ha kifejezés értéke érték2
break;
default:
// ez történjen, ha a kifejezés értéke
// egyik felsorolt értékkel sem egyezett meg
break;
// az ördög nem alszik, jobban járunk, ha kitesszük
// ezt a “felesleges” break utasítást
}

A switch utasítás kifejezése gyakran egyszerûen egy változó. A switch-hez tartozó


programblokkban vannak a case címkék. Az utánuk írt érték kerül összehasonlításra
a switch kifejezésének értékével. Ha értékük megegyezik, a program ott folytató-
dik, a break utasítás pedig azt eredményezi, hogy a program futása a switch
05_ora.qxd 8/3/2001 6:11 PM Page 63

Vezérlési szerkezetek 63

blokkja utáni részre kerül. Ha a break-et elfelejtjük, a program átlép a következõ


case kifejezéshez tartozó programrészre és azt is végrehajtja. Ha a kifejezés értéke
egyik elõzõ értékkel sem egyezik és a switch blokkján belül szerepel default
címke, akkor az utána levõ programrész kerül végrehajtásra. Ez sokszor bosszantó,
de néha hasznos is lehet. Vegyük a következõ kis példát.

switch( $hetnapja )
{
case "Péntek":
print "Kikapcsolni a vekkert, holnap nem kell
dolgozni!<br>";
case "Hétfõ":
case "Szerda":
print "Ma délelõtt dolgozom<br>";
break;
case "Kedd":
case "Csütörtök":
print "Ma délután dolgozom<br>";
break;
case "Vasárnap":
print "Bekapcsolni a vekkert!<br>";
case "Szombat":
print "Hurrá, szabadnap!<br>";
break;
default:
print "Azt hiszem ideje lenne egy új programo-
5
zót és/vagy egy jobb naptárat
keríteni<br>";
break;
}

A fenti kis program azt közli, mikor kell mennünk dolgozni és az ébresztõóra keze-
lésében is segít. A programot úgy építettük fel, hogy több esetben is ugyanazt a kó-
dot kelljen végrehajtani, így hasznos, hogy nem adtuk meg minden case címkénél
a break utasítást. Elég gyakori azonban, hogy a kezdõ programozó elfelejti meg-
adni a break utasítást. Hasonló helyzetekben jusson eszünkbe ez a példa.

A case címkével elkezdett részeket ne felejtsük el break utasítá-


sokkal lezárni. Ha ezt nem tesszük meg, a program a következõ
case részt is végrehajtja és végül a default utáni rész is lefut.
A legtöbb esetben nem ez a switch kívánatos viselkedése.
05_ora.qxd 8/3/2001 6:11 PM Page 64

64 5. óra

Az 5.4. példaprogram a korábbi, if-fel megoldott példát alakítja át a switch


segítségével.

5.4. program A switch utasítás


1: <html>
2: <head>
3: <title>5.4. program A switch utasítás</title>
4: </head>
5: <body>
6: <?php
7: $hangulat = "szomorú";
8: switch ( $hangulat )
9: {
10: case "boldog":
11: print "Hurrá, jó kedvem van!";
12: break;
13: case "szomorú":
14: print "Szomorú vagyok.";
15: break;
16: default:
17: prin "Sem boldog, sem szomorú nem
vagyok, hanem $hangulat.";
18: }
19: ?>
20: </body>
21: </html>

A $hangulat változónak a "szomorú" értéket adtuk. A switch utasítás kifejezé-


se ez a változó lesz. Az elsõ case címke a "boldog" szöveggel való egyezést vizs-
gálja. Mivel nincs egyezés, a program a következõ case címkére ugrik. A "szomo-
rú" szöveg megegyezik a $hangulat változó pillanatnyi értékével, így az ehhez
tartozó programrész fog lefutni. A programrész végét a break utasítás jelzi.

A ?: mûveletjel
A ?: ternális (háromoperandusú) mûveletjel egy olyan if utasításhoz hasonlít,
amely értéket is képes visszaadni. A visszaadott értéket a vizsgált feltétel
határozza meg:

( feltétel ) ? érték_ha_a_feltétel_igaz : érték_ha_a_feltétel_hamis ;


05_ora.qxd 8/3/2001 6:11 PM Page 65

Vezérlési szerkezetek 65

Ha a vizsgált feltétel igaz, a ? és a : közti kifejezés értékét adja, ha hamis, akkor


a : utánit. Az 5.5. példaprogram ezt a mûveletet használja, hogy egy változó
értékét a $hangulat változó értékétõl függõen állítsa be.

5.5. program A ?: mûveletjel használata


1: <html>
2: <head>
3: <title>5.5. program A ?: mûveletjel
használata</title>
4: </head>
5: <body>
6: <?php
7: $hangulat = "szomorú";
8: $szoveg = ( $hangulat=="boldog" ) ? “Hurrá,
jó kedvem van!" : "$hangulat vagyok, nem boldog.";
9: print "$szoveg";
10: ?>
11: </body>
12: </html>

A $hangulat-ot "szomorú"-ra állítottuk, majd megnéztük, hogy értéke


"boldog"-e. Mivel ez nem igaz, a $szoveg változó értéke a : utáni szöveg lesz.
Az e mûveletet használó programokat eleinte nehéz megérteni, de a mûvelet
hasznos lehet, ha csak két lehetõség közül lehet választani és szeretünk tömör
5
programot írni.

Ciklusok
Most már láttuk, hogyan kell döntések eredményétõl függõen különbözõ program-
részleteket futtatni. PHP programokkal arra is képesek vagyunk, hogy megmond-
juk, hányszor kell lefuttatni egy adott programrészt. Erre valók a ciklusok. Segítsé-
gükkel elérhetjük, hogy egyes programrészletek ismétlõdjenek. Szinte kivétel
nélkül igaz, hogy egy ciklus addig fut, amíg egy feltétel teljesül, vagy meg nem
mondjuk, hogy fejezõdjön be az ismétlés.
05_ora.qxd 8/3/2001 6:11 PM Page 66

66 5. óra

A while ciklus
A while ciklus szerkezete rendkívül hasonlít az if elágazáséhoz:

while ( feltétel )
{
// valamilyen tevékenység
}

Amíg a while feltétele igaz, a hozzá tartozó programrész újból és újból végrehaj-
tódik. A programrészen belül általában megváltoztatunk valamit, ami hatással lesz
a while feltételére; ha ezt nem tesszük meg, a ciklusunk a végtelenségig futni
fog. Az 5.6. példaprogram a while ciklus segítségével írja ki a kettes szorzótáblát.

5.6. program A while ciklus


1: <html>
2: <head>
3: <title>5.6. program A while ciklus</title>
4: </head>
5: <body>
6: <?php
7: $szamlalo = 1;
8: while ( $szamlalo <= 12 )
9: {
10: print "$szamlalo kétszerese ".($szamlalo*2)."<br>";
11: $szamlalo++;
12: }
13: ?>
14: </body>
15: </html>

A példában létrehoztuk a $szamlalo nevû változót. A while kifejezés feltétele


megvizsgálja, hogy ez a változó mekkora. Ha az érték nem nagyobb, mint 12,
a ciklus folytatódik (vagy elkezdõdik). A ciklusban a $szamlalo értéke és annak
kétszerese kiírásra kerül, majd a $szamlalo értéke eggyel nõ. Ez az utasítás
rendkívül fontos, mert ha elfelejtjük, a while feltétele soha nem lesz hamis, ezért
végtelen ciklusba kerülünk.
05_ora.qxd 8/3/2001 6:11 PM Page 67

Vezérlési szerkezetek 67

A do..while ciklus
A do..while ciklus kicsit hasonlít a while-hoz. A lényegi különbség abban van,
hogy ebben a szerkezetben elõször hajtódik végre a kód és csak azután értékelõdik
ki a feltétel:

do
{
// végrehajtandó programrész
} while ( feltétel );

A do..while ciklus feltételét tartalmazó zárójel után mindig ki kell


tenni a pontosvesszõt.

Ez a ciklus akkor lehet hasznos, ha mindenképpen szeretnénk, hogy a ciklushoz


tartozó programrész még akkor is legalább egyszer lefusson, ha a feltétel már
az elsõ végrehajtáskor hamis. Az 5.7. példaprogram a do..while szerkezet
egy alkalmazását mutatja be. A programrész mindig legalább egyszer lefut.

5.7. program A do..while ciklus


1: <html>
2:
3:
<head>
<title>5.7. program A do..while ciklus</title>
5
4: </head>
5: <body>
6: <?php
7: $szam = 1;
8: do
9: {
10: print "Végrehajtások száma: $szam<br>\n";
11: $szam++;
12: } while ( $szam > 200 && $szam < 400 );
13: ?>
14: </body>
15: </html>

A do..while ciklus megnézi, hogy a $szam változó értéke 200 és 400 között
van-e. Mivel a $szam változónak az 1 kezdeti értéket adtuk, így a feltétel hamis.
Ennek ellenére a programblokk egyszer végrehajtódik, mégpedig a feltétel kiérté-
kelése elõtt, ezért a böngészõben egy sor kiírásra kerül.
05_ora.qxd 8/3/2001 6:11 PM Page 68

68 5. óra

A for ciklus
A for semmi újat nem nyújt a while ciklushoz képest. A for ciklus használatával
azonban sokszor takarosabb, biztonságosabb módon közelíthetjük meg ugyanazt
a problémát. Korábban – az 5.6. példaprogramban – létrehoztunk egy változót
a while cikluson kívül, majd a while kifejezése megvizsgálta ennek a változónak
az értékét. Végül a változó értékét a ciklus végén eggyel növeltük. A for ciklus
mindezt egyetlen sorban teszi lehetõvé. Ez tömörebb programot eredményez és rit-
kábban fordulhat elõ, hogy a változót elfelejtjük növelni, ami végtelen ciklust okoz.

for ( változó_hozzárendelése; feltétel; számláló_növelése)


{
// a végrehajtandó programblokk
}

Az ezt megvalósító egyenértékû while:

változó_hozzárendelése;
while ( feltétel )
{
// a végrehajtandó programblokk
számláló_növelése;
}

A zárójelekben levõ kifejezéseket pontosvesszõvel kell elválasztanunk egymástól.


Az elsõ kifejezés rendszerint egy számlálónak ad kezdeti értékét, a második egy felté-
tel, ami alapján eldõl, hogy folytatódik-e a ciklus; a harmadik egy számlálót növelõ
utasítás. Az 5.8. példaprogram az 5.6. példaprogram for ciklusos megoldása.

A feltétel, a számláló_növelése és a változó_hozzárendelése pa-


raméterek helyére bármilyen érvényes PHP állítás írható. A kez-
dõk bánjanak óvatosan ezzel a lehetõséggel.

5.8. program A for ciklus használata


1: <html>
2: <head>
3: <title>5.8. program A for ciklus használata</title>
4: </head>
5: <body>
6: <?php
05_ora.qxd 8/3/2001 6:11 PM Page 69

Vezérlési szerkezetek 69

5.8. program (folytatás)


7: for ( $szamlalo = 1; $szamlalo <= 12; $szamlalo++ )
8: {
9: print "$szamlalo kétszerese ".( $szamlalo * 2
)."<br>";
10: }
11: ?>
12: </body>
13: </html>

Az 5.6. és az 5.8. példaprogram kimenete teljesen azonos. A for ciklus használata


a programot összefogottabbá tette. Mivel a $szamlalo nevû változó létrehozása
és módosítása egy sorban van, így a ciklus egészének logikája elsõ látásra világos.
A for zárójelében az elsõ utasítás a $szamlalo változót egyre állítja. A feltételes
kifejezés megnézi, hogy a $szamlalo értéke nem nagyobb-e, mint 12. Az utolsó
kifejezés a $szamlalo-t eggyel növeli.

Amikor a program a for ciklushoz ér, megtörténik az értékadás, majd rögtön


utána a feltétel kiértékelése. Ha a feltétel igaz, a ciklus végrehajtódik, majd
a $szamlalo értéke eggyel nõ és a feltétel kiértékelése újból végrehajtódik.
A folyamat addig folytatódik, amíg a feltétel hamissá nem válik.

Ciklus elhagyása a break utasítás segítségével


A while és for ciklusok lehetõséget biztosítanak arra, hogy egy beépített felté-
5
teles kifejezés segítségével kilépjünk belõlük. A break utasítás lehetõvé teszi,
hogy más feltételektõl függõen megszakítsuk egy ciklus futását. Ez jó lehet például
hibakezeléskor vagy hibák megelõzésekor. Az 5.9. példaprogram egy egyszerû
for ciklusból áll, amely egy nagy számot egy egyre növekvõ számmal oszt el és
a mûvelet eredményét meg is jeleníti.

5.9. program Egy for ciklus, amely a 4000-et tíz,


egyre növekvõ számmal osztja el
1: <html>
2: <head>
3: <title>5.9. program A for ciklus használata
2.</title>
4: </head>
5: <body>
6: <?php
05_ora.qxd 8/3/2001 6:11 PM Page 70

70 5. óra

5.9. program (folytatás)


7: for ( $szamlalo=1; $szamlalo <= 10, $szamlalo++ )
8: {
9: $seged = 4000/$szamlalo;
10: print "4000 $szamlalo részre osztva $seged.<br>";
11: }
12: ?>
13: </body>
14: </html>

A példában a $szamlalo nevû változónak az 1 kezdeti értéket adjuk. A for


utasítás feltételes kifejezése ellenõrzi, hogy a $szamlalo nem nagyobb-e, mint
10. A ciklus belsejében a 4000-et elosztjuk a $szamlalo-val és az eredményt
kiírjuk a böngészõbe.

Ez elég célratörõnek tûnik. De mi a helyzet akkor, ha a $szamlalo értéke


a felhasználótól származik? A változó értéke lehet negatív szám vagy akár szöveg
is. Vegyük az elsõ esetet: változtassuk meg a $szamlalo kezdõértékét 1-rõl -4-re.
Így a ciklusmag ötödik futtatása során nullával kellene osztani, ami nem elfogad-
ható. Az 5.10. példaprogram ezt azzal védi ki, hogy a ciklus futását befejezi,
ha a $szamlalo változóban a nulla érték van.

5.10. program A break utasítás használata


1: <html>
2: <head>
3: <title>5.10. program A break utasítás
használata</title>
4: </head>
5: <body>
6: <?php
7: $szamlalo = -4;
8: for ( ; $szamlalo <= 10; $szamlalo++ )
9: {
10: if ( $szamlalo == 0 )
11: break;
12: $seged = 4000/$szamlalo;
13: print "4000 $szamlalo részre osztva $seged.<br>";
14: }
15: ?>
16: </body>
17: </html>
05_ora.qxd 8/3/2001 6:11 PM Page 71

Vezérlési szerkezetek 71

A nullával való osztás nem eredményez végzetes hibát a PHP 4-


ben, csak egy figyelmeztetõ üzenet jelenik meg a böngészõben.
A program futása folytatódik.

Egy if utasítással megvizsgáljuk a $szamlalo értékét. Ha nullával egyenlõ,


azonnal kilépünk a ciklusból; a program ekkor a for ciklus utáni sorokat kezdi
feldolgozni. Figyeljük meg, hogy a $szamlalo-t a cikluson kívül hoztuk létre,
hogy olyan helyzetet utánozzunk, amikor a $szamlalo értéke „kívülrõl”
származik, például egy ûrlapról vagy egy adatbázisból.

A for ciklus fejébõl bármelyik kifejezés elhagyható, de figyel-


nünk kell arra, hogy a pontosvesszõket mindig kiírjuk.

Következõ ismétlés azonnali elkezdése


a continue utasítás segítségével
A continue utasítás segítségével az éppen folyó ismétlést befejezhetjük,
mégpedig úgy, hogy ez ne eredményezze az egész ciklusból való kilépést,
csak a következõ ismétlés kezdetét jelentse. Az 5.10. példában a break utasítás
használata kicsit drasztikus volt. Az 5.11. példaprogramban a nullával való
osztást úgy kerüljük el, hogy közben programunk nem lép ki az egész ciklusból.
5
5.11. program A continue utasítás használata
1: <html>
2: <head>
3: <title>5.11. program A continue utasítás
használata</title>
4: </head>
5: <body>
6: <?php
7: $szamlalo = -4;
8: for ( ; $szamlalo <= 10; $szamlalo++ )
9: {
10: if ( $szamlalo == 0 )
11: continue;
12: $seged = 4000/$szamlalo;
13: print "4000 $szamlalo részre osztva $seged.<br>";
14: }
05_ora.qxd 8/3/2001 6:11 PM Page 72

72 5. óra

5.11. program (folytatás)


15: ?>
16: </body>
17: </html>

Itt a break utasítást continue-ra cseréltük. Ha a $szamlalo értéke nullával egyen-


lõ, az éppen folyó ismétlés véget ér, a végrehajtás pedig rögtön a következõre kerül.

A break és continue utasítások a ciklus logikáját bonyolultabbá,


a programot pedig nehezebben olvashatóvá teszik, így furcsa
programhibákat idézhetnek elõ, ezért óvatosan használandók.

Egymásba ágyazott ciklusok


A ciklusok törzsében is lehetnek ciklusok. Ez a lehetõség különösen hasznos,
ha futási idõben elõállított HTML táblázatokkal dolgozunk. Az 5.12. példaprog-
ramban két egymásba ágyazott for ciklus segítségével egy szorzótáblát írunk ki
a böngészõbe.

5.12. program Két for ciklus egymásba ágyazása


1: <html>
2: <head>
3: <title>5.12. program Két for ciklus egymásba
ágyazása</title>
4: </head>
5: <body>
6: <?php
7: print "<table border=1>\n"; // HTML táblázat kezdete
8: for ( $y=1; $y<=12; $y++ )
9: {
10: print "<tr>\n"; // sor kezdete a HTML táblázatban
11: for ( $x=1; $x<=12; $x++ )
12: {
13: print "\t<td>"; // cella kezdete
14: print ($x*$y);
15: print "</td>\n"; // cella vége
16: }
17: print "</tr>\n"; // sor vége
18: }
05_ora.qxd 8/3/2001 6:11 PM Page 73

Vezérlési szerkezetek 73

5.12. program (folytatás)


19: print "</table>\n"; // táblázat vége
20: ?>
21: </body>
22: </html>

A külsõ for ciklus az $y változónak az 1 kezdeti értéket adja. A ciklus addig fog
futni, amíg a változó nem nagyobb 12-nél, az utolsó kifejezés pedig biztosítja,
hogy $y értéke minden ismétlés után eggyel nõjön. A ciklus törzse minden ismét-
lés során kiír egy tr (table row – táblázatsor) HTML elemet, majd egy újabb
for ciklus kezdõdik. A belsõ ciklus az $x változó értékét a külsõ ciklushoz
hasonlóan végigfuttatja 1-tõl 12-ig. A ciklus törzsében egy td (table data –
táblázatcella) elemet ír ki, amelybe az $x*$y érték kerül. Az eredmény egy
ízlésesen formázott szorzótábla lesz.

Összefoglalás
Ebben az órában a vezérlési szerkezetekrõl tanultunk és arról, hogyan segítenek
minket programjaink változatosabbá és rugalmasabbá tételében. A legtöbb megta-
nult szerkezet újból és újból meg fog jelenni a könyv hátralevõ részében.
Megtanultuk, hogyan hozzunk létre if utasításokat, hogyan egészítsük ki azokat
elseif és else ágakkal. Hallottunk arról, hogyan használjuk a switch utasítást,
hogy egy kifejezés adott értékei esetén más és más történjen. Tanultunk a ciklusok-
ról, pontosabban a while és a for ciklusokról, és arról, hogy a break és
5
a continue utasítások segítségével hogyan léphetünk ki végleg a ciklusból, illetve
hogyan hagyhatunk ki egy-egy ismétlést. Végül megtanultuk, hogyan kell cikluso-
kat egymásba ágyazni és erre gyakorlati példát is láttunk.

Kérdések és válaszok
A vezérlési szerkezetek feltételes kifejezéseinek mindenképpen logikai
értéket kell adniuk?
Végsõ soron igen, bár a feltételes kifejezéseknél a kiértékelés szempontjából min-
den, ami nulla, üres karakterlánc vagy nem meghatározott változó, false-nak,
minden egyéb true-nak számít.

A vezérlési szerkezetekhez tartozó programblokkot mindig kapcsos záró-


jelbe kell tenni?
Ha a programblokk csak egy utasításból áll, a kapcsos zárójel elhagyható, de ezt
tenni nem célszerû, mert ha a programblokkot új utasítással egészítjük ki, véletle-
nül hibákat idézhetünk elõ.
05_ora.qxd 8/3/2001 6:11 PM Page 74

74 5. óra

Ez az óra bemutatta az összes ciklust?


Nem, a hetedik, tömbökkel foglalkozó órában találkozunk még a foreach
ciklussal is, melynek segítségével egy tömb elemein haladhatunk végig.

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. Hogyan használnánk az if vezérlési szerkezetet olyan program írására, hogy
ha az $eletkor változó értéke 18 és 35 között van, az
"Üzenet fiataloknak" szöveget írja ki? Ha az $eletkor értéke
bármi más, az "Általános üzenet" szöveg jelenjen meg a böngészõben.

2. Hogyan egészíthetnénk ki az elsõ kérdésbeli programunkat úgy, hogy


az "Üzenet gyerekeknek" jelenjen meg akkor, ha az $eletkor változó
értéke 1 és 17 között van?

3. Hogyan készítenénk egy while ciklust, amely kiírja az 1 és 49 közötti


páratlan számokat?

4. Hogyan valósítanánk meg az elõzõ kérdésbeli programot for ciklus


segítségével?

Feladatok
1. Nézzük végig a vezérlési szerkezetek utasításformáját! Gondoljuk végig,
hogyan lehetnek ezek a szerkezetek a segítségünkre!

2. Nézzük meg a ?: mûveletet! Miben különbözik ez a többi vezérlési


szerkezettõl? Mikor lehet hasznos?
06_ora.qxd 8/3/2001 6:11 PM Page 75

6. ÓRA
Függvények
A függvény a jól szervezett program lelke, mert a programot könnyen olvashatóvá és
újrahasznosíthatóvá teszi. Függvények nélkül a nagy programok kezelhetetlenek len-
nének. Ebben az órában a függvényeket tanulmányozzuk és mutatunk rá néhány
példát, hogyan kímélhetnek meg minket az ismétlõdésekbõl adódó pluszmunká-
tól. Az órában a következõket tanuljuk meg:

• Hogyan hozhatunk létre függvényeket?

• Hogyan adjunk át a függvényeinknek értékeket és hogyan kapjuk meg tõlük


az eredményt?

• Hogyan hívjunk meg függvényeket dinamikusan, változóban tárolt karakter-


lánc segítségével?

• Hogyan érjük el a függvényekbõl a globális változókat?

• Hogyan érjük el, hogy függvényeinknek „emlékezete” legyen?

• Hogyan adjunk át a függvényeknek hivatkozásokat?


06_ora.qxd 8/3/2001 6:11 PM Page 76

76 6. óra

Mit nevezünk függvénynek?


A függvényt egy gépnek tekinthetjük. A gép a bele töltött nyersanyagokkal addig
dolgozik, amíg a kívánt terméket elõ nem állítja vagy el nem éri kitûzött célját.
A függvény értékeket vesz át tõlünk, feldolgozza azokat és végez velük valamit
(például kiírja az eredményt a böngészõbe) vagy visszaad egy értéket, esetleg
mindkettõt.

Ha a kedves Olvasónak egy süteményt kell csinálnia, maga süti meg. De ha több
ezret, akkor esetleg készít vagy beszerez egy süteménysütõ gépezetet. Hasonló-
képp, amikor elhatározzuk, hogy függvényt írunk, a legfontosabb szempont, amit
mérlegelnünk kell, az, hogy az ismétlõdések csökkentésével akkorává zsugorodik-
e a program, hogy rövidebb lesz a függvény használatával.

A függvény valójában egy zárt, önálló kódrészlet, melyet programunkból meghív-


hatunk. Amikor meghívjuk, a függvény törzse lefut. A függvénynek feldolgozás
céljából értékeket adhatunk át. Amikor a függvény véget ér, a hívónak egy értéket
ad vissza.

A függvény olyan kódrészlet, amely nem közvetlenül hajtódik végre,


ÚJDONSÁG
hanem a programból hívhatjuk meg: onnan, ahol épp szükség van rá.
A függvények lehetnek beépítettek vagy felhasználó által megadottak. Mûködé-
sükhöz szükségük lehet információkra és többnyire értéket adnak vissza.

Függvények hívása
Kétféle függvény létezik: a nyelvbe beépített függvény és az általunk létrehozott
függvény. A PHP 4-ben rengeteg beépített függvény van. A könyv legelsõ
PHP oldala egyetlen függvényhívásból állt:

print ("Hello Web!");

A print abból a szempontból nem jellegzetes függvény, hogy


paramétereit nem kell zárójelbe tenni. A
print ("Hello Web!");
és
print "Hello Web!";
egyaránt helyes megoldások. Ez egy különleges függvény.
Szinte az összes többi függvénynél kötelezõ a zárójel; akár kell
paramétert átadnunk, akár nem.
06_ora.qxd 8/3/2001 6:11 PM Page 77

Függvények 77

A fenti példában a print() függvényt a "Hello Web!" szövegparaméterrel


hívtuk meg. A program a karakterlánc kiírását hajtja végre. A függvényhívás egy
függvénynévbõl (ebben az esetben ez a print) és az utána tett zárójelekbõl áll.
Ha a függvénynek információt szeretnénk átadni, azt a függvény utáni zárójelbe
tesszük. Az információt, amit ily módon adunk át a függvénynek, paraméternek
hívjuk. Néhány függvénynek több paramétert kell átadni. A paramétereket vesszõ-
vel választjuk el.

A paraméter a függvénynek átadott érték. A paramétereket a függvény-


ÚJDONSÁG
hívás zárójelén belülre kell írnunk. Ha több paramétert kell átadnunk,
az egyes paramétereket vesszõvel kell elválasztanunk egymástól. A paraméterek
a függvényeken belül helyi (lokális) változóként érhetõk el.

valamilyen_fuggveny ( $elso_parameter, $masodik_parameter );

A print() abból a szempontból tipikus függvény, hogy van visszatérési értéke.


A legtöbb függvény, ha nincs „értelmes” visszatérési értéke, információt ad arról,
hogy munkáját sikeresen befejezte-e. A print() visszatérési értéke logikai típusú
(true, ha sikeres volt).

Az abs() függvény például egy szám típusú paramétert vár és a paraméter


abszolútértékét adja vissza. Próbáljuk is ki a 6.1. példaprogrammal!

6.1. program A beépített abs() függvény használata


1: <html>
2: <head>
3: <title>6.1. program A beépített abs() függvény
használata</title>
4: </head>
5: <body> 6
6: <?php
7: $szam = -321;
8: $ujszam = abs( $szam );
9: print $ujszam; // kiírja, hogy "321"
10: ?>
11: </body>
12: </html>
06_ora.qxd 8/3/2001 6:11 PM Page 78

78 6. óra

Ebben a példában a $szam nevû változóhoz a -321-es értéket rendeltük, majd


átadtuk az abs() függvénynek, amely elvégzi a szükséges számításokat és vissza-
adja az eredményt. Ezt az új értéket rendeljük az $ujszam nevû változóhoz és
kiírjuk az eredményt. A feladatot megoldhattuk volna segédváltozók segítsége
nélkül is, az abs() függvényt adva közvetlenül a print() paramétereként:

print( abs( -321 ) );

A felhasználó által megírt függvényeket teljesen hasonló módon kell meghívnunk.

Függvények létrehozása
Függvényt a function kulcsszó segítségével hozhatunk létre:

funcion valamilyen_fuggveny( $parameter1, $parameter2 )


{
// itt van a függvény törzse
}

A function kulcsszót a függvény neve követi, majd egy zárójelpár. Ha a függvény


paramétereket igényel, a zárójelbe vesszõvel elválasztott változókat kell tenni.
A változók értékei a függvényhíváskor átadott paraméterek lesznek. A zárójelpárt
akkor is ki kell írni, ha a függvény nem vesz át paramétereket.

A 6.2. példaprogram egy függvényt hoz létre.

6.2. program Függvény létrehozása


1: <html>
2: <head>
3: <title>6.2. program Függvény létrehozása</title>
4: </head>
5: <body>
6: <?php
7: function nagyHello()
8: {
9: print "<h1>HELLO!</h1>";
10: }
11: nagyHello();
12: ?>
13: </body>
14: </html>
06_ora.qxd 8/3/2001 6:11 PM Page 79

Függvények 79

A fenti program egyszerûen kiírja a "HELLO" szöveget egy <H1> HTML elemben.
A programban egy olyan nagyHello() nevû függvényt hoztunk létre, amely
nem vesz át paramétereket. Ezért hagytuk üresen a zárójelpárt. Bár a nagyHello()
mûködõ függvény, mégsem túl hasznos. A 6.3. példaprogramban olyan függvényt
láthatunk, amely egy paramétert fogad és valami hasznosat csinál vele.

6.3. program Egy paramétert váró függvény létrehozása


1: <html>
2: <head>
3: <title>6.3. program Egy paramétert váró függvény
létrehozása</title>
4: </head>
5: <body>
6: <?php
7: function sorKiir( $sor )
8: {
9: print ("$sor<br>\n");
10: }
11: sorKiir("Ez egy sor");
12: sorKiir("Ez már egy másik sor");
13: sorKiir("Ez megint egy új sor");
14: ?>
15: </body>
16: </html>

6.1. ábra

6
Függvény, amely egy
karakterláncot, majd
egy <br> HTML
elemet ír ki.
06_ora.qxd 8/3/2001 6:11 PM Page 80

80 6. óra

A 6.3. példaprogram kimenetét a 6.1. ábrán láthatjuk. A sorKiir() függvény


egy karakterláncot vár, ezért tettük a $sor nevû változót a zárójelbe.
Amit a sorKiir() függvény zárójelei közé teszünk, az kerül a $sor nevû válto-
zóba. A függvény törzsében kiírjuk a $sor nevû változót, majd egy <br> elemet
és egy újsor karaktert (hogy a HTML kód is olvasható legyen, ne csak a kimenet).

Ha most ki szeretnénk írni egy sort a böngészõbe, akkor meghívhatjuk


a sorKiir() függvényt, ahelyett, hogy a print() függvénnyel oldanánk meg
a problémát, így nem kell a sorvégi jeleket minden sor kiírásakor begépelnünk.

Függvények visszatérési értéke


A függvényeknek visszatérési értéke is lehet, ehhez a return utasításra van
szükség. A return befejezi a függvény futtatását és az utána írt kifejezést küldi
vissza a hívónak.

A 6.4. példaprogramban létrehozunk egy függvényt, amely két szám összegével


tér vissza.

6.4. program Visszatérési értékkel rendelkezõ függvény


1: <html>
2: <head>
3: <title>6.4. program Visszatérési értékkel rendelkezõ
függvény</title>
4: </head>
5: <body>
6: <?php
7: function osszead( $elsoszam, $masodikszam )
8: {
9: $eredmeny = $elsoszam + $masodikszam;
10: return $eredmeny;
11: }
12: print osszead(3,5); // kiírja, hogy "8"
13: ?>
14: </body>
15: </html>
06_ora.qxd 8/3/2001 6:11 PM Page 81

Függvények 81

A 6.4. példaprogram a 8-as számot írja ki. Az osszead() függvényt két paramé-
terrel kell meghívni (itt a két paraméter a 3 és az 5 volt). Ezek az $elsoszam és
a $masodikszam nevû változókban tárolódnak. Várhatóan az osszead()
függvény e két változó eredményét adja össze és tárolja az $eredmeny nevû
változóban. Az $eredmeny nevû segédváltozó használatát kiküszöbölhetjük:

function osszead( $elsoszam, $masodikszam )


{
return ( $elsoszam + $masodikszam );
}

A return segítségével értéket és objektumot is visszaadhatunk, vagy esetleg


„semmit”. Ha semmit sem adunk meg a return után, az csak a függvény futtatá-
sának befejezését eredményezi. A visszatérési érték átadásának módja többféle
lehet. Az érték lehet elõre „beégetett”

return 4;

de lehet kifejezés eredménye

return ( $a / $b );

vagy akár egy másik függvény visszatérési értéke is:

return ( masik_fuggveny( $parameter ) );

Dinamikus függvényhívások
Lehetõségünk van rá, hogy karakterláncba tegyük egy függvény nevét és ezt a vál-
tozót pontosan úgy tekintsük, mint ha maga a függvény neve lenne. Ezt a 6.5. pél-
daprogramon keresztül próbálhatjuk ki.
6
6.5. program Dinamikus függvényhívás
1: <html>
2: <head>
3: <title>6.5. program Dinamikus függvényhívás</title>
4: </head>
5: <body>
6: <?php
06_ora.qxd 8/3/2001 6:11 PM Page 82

82 6. óra

6.5. program (folytatás)


7: function koszon()
8: {
9: print "Jó napot!<br>";
10: }
11: $fuggveny_tarolo = "koszon";
12: $fuggveny_tarolo();
13: ?>
14: </body>
15: </html>

Itt a $fuggveny_tarolo változóhoz a koszon() függvény nevével azonos


karakterláncot rendeltünk. Ha ezt megtettük, a változót arra használhatjuk, hogy
meghívja nekünk a koszon() függvényt, csupán zárójeleket kell tennünk
a változó neve után.

Miért jó ez? A fenti példában csak még több munkát csináltunk magunknak azzal,
hogy a "koszon" karakterláncot rendeltük a $fuggveny_tarolo nevû válto-
zóhoz. A dinamikus függvényhívás akkor igazán hasznos, ha a program folyását
bizonyos körülményektõl függõen változtatni szeretnénk. Például szeretnénk mást
és mást csinálni egy URL-kérés paraméterétõl függõen. Ezt a paramétert feldolgoz-
hatjuk és értékétõl függõen más és más függvényt hívhatunk meg.

A PHP beépített függvényei még hasznosabbá teszik ezt a lehetõséget.


Az array_walk() függvény például egy karakterláncot használ arra,
hogy a tömb minden elemére meghívja a függvényt. Az array_walk()
alkalmazására a tizenhatodik órában láthatunk példát.

Változók hatóköre
A függvényben használt változók az adott függvényre nézve helyiek maradnak.
Más szavakkal: a változó a függvényen kívülrõl vagy más függvényekbõl nem lesz
elérhetõ. Nagyobb projektek esetén ez megóvhat minket attól, hogy véletlenül két
függvény felülírja azonos nevû változóik tartalmát.

A 6.6. példaprogramban létrehozunk egy változót a függvényen belül, majd meg-


próbáljuk kiíratni a függvényen kívül.
06_ora.qxd 8/3/2001 6:11 PM Page 83

Függvények 83

6.6. program Változók hatóköre: A függvényen belül létrehozott változó


a függvényen kívülrõl nem elérhetõ
1: <html>
2: <head>
3: <title>6.6. program Változók hatóköre: A függvényen
belül létrehozott változó a függvényen kívülrõl
nem elérhetõ</title>
4: </head>
5: <body>
6: <?php
7: function proba()
8: {
9: $probavaltozo = "Ez egy proba valtozo";
10: }
11: print "proba valtozo: $probavaltozo<br>";
12: ?>
13: </body>
14: </html>

6.2 ábra
Kísérlet függvényen
belüli változóra
hivatkozásra.

A 6.6. példaprogram kimenetét a 6.2. ábrán láthatjuk. A $probavaltozo értéke


nem íródik ki. Ez annak a következménye, hogy ilyen nevû változó a proba()
nevû függvényen kívül nem létezik. Figyeljük meg, hogy a nem létezõ változóra
történõ hivatkozás nem eredményez hibát.

Hasonlóképp, a függvényen kívül meghatározott változó nem érhetõ el automati-


kusan a függvényen belülrõl.
06_ora.qxd 8/3/2001 6:11 PM Page 84

84 6. óra

Hozzáférés változókhoz a global kulcsszó segítségével


Alapértelmezés szerint a függvényeken belülrõl nem érhetjük el a máshol megha-
tározott változókat. Ha mégis megpróbáljuk ezeket használni, akkor helyi változót
fogunk létrehozni vagy elérni. Próbáljuk ki ezt a 6.7. példaprogrammal:

6.7. program A függvényen kívül meghatározott változók a függvényen


belül alapértelmezés szerint nem elérhetõk
1: <html>
2: <head>
3: <title>6.7. program A függvényen kívül meghatározott
változók a függvényen belül alapértelmezés szerint
nem elérhetõk</title>
5: </head>
6: <body>
7: <?php
8: $elet = 42;
9: function eletErtelme()
10: {
11: print "Az élet értelme: $elet<br>";
12: }
13: eletErtelme();
14: ?>
15: </body>
16: </html>

6.3. ábra
Globális változó
elérési kísérlete
függvényen belülrõl
06_ora.qxd 8/3/2001 6:11 PM Page 85

Függvények 85

A 6.7. példaprogram kimenetét a 6.3. ábrán láthatjuk. Amint azt vártuk,


az eletErtelme() függvény nem tudta elérni az $elet változót; így az $elet
a függvényen belül üres. Ezt láthatjuk, amikor a függvény kiírja a változó értékét.
Mindent figyelembe véve ez egy jó dolog. Megmenekültünk az azonos nevû válto-
zók ütközésétõl és a függvény paramétert igényelhet, ha meg szeretne tudni valamit
a „külvilág”-ról. Esetenként azonban egy-egy fontos globális (függvényen kívüli)
változót anélkül szeretnénk elérni, hogy azt paraméterként át kellene adnunk.
Ez az a helyzet, ahol a global kulcsszónak létjogosultsága van. A 6.8. példa-
program a global kulcsszóval állítja vissza a világ rendjét.

6.8. program Globális változó elérése a global kulcsszó segítségével


1: <html>
2: <head>
3: <title>6.8. program Globális változó elérése
a global kulcsszó segítségével</title>
4: </head>
5: <body>
6: <?php
7: $elet=42;
8: function eletErtelme()
9: {
10: global $elet;
11: print "Az élet értelme: $elet<br>";
12: }
13: eletErtelme();
14: ?>
15: </body>
16: </html>
6
6.4. ábra
Globális változó
függvénybõl történõ
sikeres elérése a global
kulcsszó segítségével
06_ora.qxd 8/3/2001 6:11 PM Page 86

86 6. óra

A 6.8. példaprogram kimenetét a 6.4. ábrán láthatjuk. Miután az eletErtelme()


függvényben az $elet változó elé a global kulcsszót tesszük, a függvényen
belül a külsõ, globális $elet változót érhetjük el.
Minden függvényben, amely globális változót szeretne elérni, használnunk kell
a global kulcsszót.

Legyünk óvatosak! Ha most az $elet nevû változót a függvényen belül megváltoz-


tatjuk, annak a program egészére hatása lesz. A függvénynek átadott paraméter álta-
lában valamilyen érték másolata; a paraméter megváltoztatásának a függvény vége
után semmilyen hatása nincs. Ha azonban egy globális változó értékét változtatjuk
meg egy függvényen belül, akkor az eredeti változót változtattuk meg és nem egy
másolatot. Ezért a global kulcsszót lehetõleg minél kevesebbszer használjuk.

Állapot megõrzése a függvényhívások között


a static kulcsszó segítségével
A függvényen belüli változóknak egészében véve rövid, de boldog életük van.
Létrejönnek például akkor, amikor a szamozottCimsor() függvényt meghívjuk
és eltûnnek, amikor a függvény futása befejezõdik. Tulajdonképpen ennek így is
kell lennie. A lehetõ legjobb úgy felépíteni egy programot, hogy az független és kis
tudású függvényekbõl álljon. Esetenként azonban jól jönne, ha egy függvénynek
lehetne valamilyen kezdetleges memóriája.

Tegyük fel például, hogy tudni szeretnénk, hányszor fut le egy adott függvény.
Miért? Példánkban a függvény célja számozott címsor készítése, ami egy dinami-
kusan létrejövõ dokumentációt eredményez.

Itt persze használhatnánk a global kulcsszóról újonnan szerzett tudásunkat.


Ennek alapján a 6.9. példaprogramhoz hasonlót írhatnánk.

6.9. program Változó értékének függvényhívások közti megõrzése


a global kulcsszó segítségével
1: <html>
2: <head>
3: <title>6.9. program Változó értékének függvényhívások
közti megõrzése a global kulcsszó
segítségével</title>
4: </head>
5: <body>
6: <?php
06_ora.qxd 8/3/2001 6:11 PM Page 87

Függvények 87

6.9. program (folytatás)


7: $fvHivasokSzama = 0;
8: function szamozottCimsor( $cimszoveg )
9: {
10: global $fvHivasokSzama;
11: $fvHivasokSzama++;
12: print "<h1>$fvHivasokSzama. $cimszoveg</h1>";
13: }
14: szamozottCimsor("Alkatrészek");
15: print("Az alkatrészek széles skáláját gyártjuk<p>");
16: szamozottCimsor("Mütyürök");
17: print("A legjobbak a világon<p>");
18: ?>
19: </body>
20: </html>

6.5. ábra
A függvényhívások
számának nyomon
követése a global
kulcsszó használa-
tával

Ez úgy mûködik, ahogy azt vártuk. Létrehoztuk a $fvHivasokSzama nevû


6
változót a szamozottCimsor() függvényen kívül. A változót a függvény számára
a global kulcsszó segítségével tettük elérhetõvé. A 6.9. példaprogram kimenetét
a 6.5. ábrán láthatjuk.

Valahányszor meghívjuk az szamozottCimsor() nevû függvényt,


a $fvHivasokSzama változó értéke eggyel nõ, majd a megnövelt értékkel
a címsort teljessé tesszük.

Ez nem igazán elegáns megoldás. A global kulcsszót használó függvények nem


függetlenek, nem tekinthetõk önálló programrésznek. Ha a kódot olvassuk vagy
újrahasznosítjuk, figyelnünk kell az érintett globális változókra. Ez az a pont,
ahol a static kulcsszó hasznos lehet. Ha egy függvényen belül egy változót
06_ora.qxd 8/3/2001 6:11 PM Page 88

88 6. óra

a static kulcsszóval hozunk létre, a változó az adott függvényre nézve helyi


marad. Másrészt a függvény hívásról hívásra „emlékszik” a változó értékére.
A 6.10. példaprogram a 6.9. példaprogram static kulcsszót használó változata.

6.10. program Függvényhívások közötti állapot megõrzése


a static kulcsszó használatával
1: <html>
2: <head>
3: <title>6.10. program Függvényhívások közötti állapot
megõrzése a static kulcsszó
használatával</title>
4: </head>
5: <body>
6: <?php
7: function szamozottCimsor( $cimszoveg )
8: {
9: static $fvHivasokSzama = 0;
10: $fvHivasokSzama++;
11: print "<h1>$fvHivasokSzama. $cimszoveg</h1>";
12: }
13: szamozottCimsor("Alkatrészek");
14: print("Az alkatrészek széles skáláját gyártjuk<p>");
15: szamozottCimsor("Mütyürök");
16: print("A legjobbak a világon<p>");
17: ?>
18: </body>
19: </html>

A szamozottCimsor() függvény így teljesen független lett. Amikor a függvényt


elõször hívjuk meg, a $fvHivasokSzama nevû változó kezdeti értéket is kap.
Ezt a hozzárendelést a függvény további meghívásainál figyelmen kívül hagyja
a PHP, ehelyett az elõzõ futtatáskor megõrzött értéket kapjuk vissza.
Így a szamozottCimsor() függvényt már beilleszthetjük más programokba és
nem kell aggódnunk a globális változók miatt. Bár a 6.10. példaprogram kimenete
teljesen megegyezik a 6.9. példaprograméval, a programot elegánsabbá és
hordozhatóbbá tettük. Gondoljunk bele például, mi történne akkor, ha a függvény
6.9. példaprogrambeli változatát egy olyan programba illesztenénk bele, amelyben
van egy $fvHivasokSzama nevû változó.
06_ora.qxd 8/3/2001 6:11 PM Page 89

Függvények 89

Paraméterek további tulajdonságai


Már láttuk, hogyan kell függvényeknek paramétereket átadni, de van még néhány
hasznos dolog, amirõl még nem beszéltünk. Ebben a részben megtanuljuk, miként
lehet a függvényparamétereknek alapértelmezett értéket adni és megtanuljuk azt is,
hogyan kell változóinkra mutató hivatkozást átadni a változó értékének másolata
helyett.

Paraméterek alapértelmezett értéke


A PHP nyelv remek lehetõséget biztosít számunkra rugalmas függvények kialakí-
tásához. Eddig azt mondtuk, hogy a függvények többsége paramétert igényel.
Néhány paramétert elhagyhatóvá téve függvényeink rugalmasabbá válnak.

A 6.11. példaprogramban létrehozunk egy hasznos kis függvényt, amely


egy karakterláncot egy HTML font elembe zár. A függvény használójának
megadjuk a lehetõséget, hogy megváltoztathassa a font elem size tulaj-
donságát, ezért a karakterlánc mellé kell egy $meret nevû paraméter is.

6.11. program Két paramétert igénylõ függvény


1: <html>
2: <head>
3: <title>6.11. program Két paramétert igénylõ
függvény</title>
4: </head>
5: <body>
6: <?php
7: function meretez( $szoveg, $meret )
8: {
9: print "<font size=\"$meret\" 6
face=\"Helvetica,Arial,Sans-Serif\">$szoveg</font>";
10: }
11: meretez("Egy címsor<br>",5);
12: meretez("szöveg<br>",3);
13: meretez("újabb szöveg<BR>",3);
14: meretez("még több szöveg<BR>",3);
15: ?>
16: </body>
17: </html>
06_ora.qxd 8/3/2001 6:11 PM Page 90

90 6. óra

6.6. ábra
Függvény, amely
formázott karakter-
láncokat ír ki a bön-
gészõbe

A 6.11. példaprogram kimenetét a 6.6. ábrán láthatjuk. Függvényünk ugyan


hasznos, de valójában a $meret nevû paraméter majdnem mindig 3. Ha kezdõér-
téket rendelünk ehhez a paraméterhez, akkor az elhagyható lesz. Így ha a függ-
vényhívásban nem adunk értéket ennek a paraméternek, akkor az általunk meg-
határozott értéket fogja felvenni. A 6.12. példaprogram ennek a módszernek
a segítségével teszi a $meret paramétert elhagyhatóvá.

6.12. program Függvény elhagyható paraméterrel


1: <html>
2: <head>
3: <title>6.12. program Függvény elhagyható
paraméterrel</title>
4: </head>
5: <body>
6: <?php
7: function meretez( $szoveg, $meret=3 )
8: {
9: print "<font size=\"$meret\" face=\"Helvetica,
Arial,Sans-Serif\">$szoveg</font>";
10: }
11: meretez("Egy címsor<br>",5);
12: meretez("szöveg<br>");
13: meretez("újabb szöveg<BR>");
14: meretez("még több szöveg<BR>");
15: ?>
16: </body>
17: </html>
06_ora.qxd 8/3/2001 6:11 PM Page 91

Függvények 91

Ha a meretez() függvénynek van második paramétere, akkor a $meret nevû


változót ez fogja meghatározni. Ha a függvényhíváskor nem adunk meg második
paramétert, akkor a függvény a 3 értéket feltételezi. Annyi elhagyható paramétert
adhatunk meg, ahányat csak akarunk, de arra vigyáznunk kell, hogy az elhagy-
ható paramétereknek a paraméterlista végén kell szerepelniük.

Ezt a korlátozást kikerülhetjük, sõt még a paraméterek sorrendjét


sem kell fejben tartanunk, ha a paramétereket egyetlen asszoci-
atív tömbben adjuk át. (Errõl bõvebben a hetedik, tömbökrõl
szóló fejezetben lesz szó).

Hivatkozás típusú paraméterek


Amikor a függvényeknek paramétereket adunk át, a helyi paraméter-változókba
a paraméterek értékének másolata kerül. Az e változókon végzett mûveleteknek
a függvényhívás befejezõdése után nincs hatásuk az átadott paraméterekre.
Ennek igazolására futtassuk le a 6.13. példaprogramot.

6.13. program Függvényparaméter érték szerinti átadása


1: <html>
2: <head>
3: <title>6.13. program Függvényparaméter érték szerinti
átadása</title>
4: </head>
5: <body>
6: <?php
7: function ottelTobb( $szam )
8: { 6
9: $szam += 5;
10: }
11: $regiSzam = 10;
12: ottelTobb( $regiSzam );
13: print( $regiSzam );
14: ?>
15: </body>
16: </html>

Az ottelTobb() függvény egyetlen számot vár, majd ötöt ad hozzá. Visszatérési


értéke nincs. A fõprogramban a $regiSzam nevû változónak értéket adunk, majd
ezzel a változóval meghívjuk az ottelTobb() függvényt. A $regiSzam változó
06_ora.qxd 8/3/2001 6:11 PM Page 92

92 6. óra

értékének másolata kerül a $szam nevû változóba. Amikor kiíratjuk a függvényhí-


vás után a $regiSzam változó értékét, azt találjuk, hogy az érték még mindig
10. Alapértelmezés szerint a függvények paraméterei érték szerint adódnak át.
Más szavakkal, a változók értékérõl helyi másolat készül.

Lehetõségünk van arra is, hogy ne a változó értékét, hanem arra mutató hivatko-
zást adjunk át. (Ezt cím szerinti paraméterátadásnak is hívják.) Ez azt jelenti, hogy
a változóra mutató hivatkozással dolgozunk a függvényben és nem a változó érté-
kének másolatával. A paraméteren végzett bármilyen mûvelet megváltoztatja az
eredeti változó értékét is. Hivatkozásokat függvényeknek úgy adhatunk át, hogy
az átadandó változó vagy a paraméter neve elé egy & jelet teszünk. A 6.14. és
a 6.15. példaprogram az elõzõ problémára mutatja be a két elõbb említett
módszert.

6.14. program Cím szerinti paraméterátadás változóra mutatkozó


hivatkozás segítségével
1: <html>
2: <head>
3: <title>6.14. program Cím szerinti paraméterátadás
változóra mutató hivatkozás segítségével</title>
4: </head>
5: <body>
6: <?php
7: function ottelTobb( $szam )
8: {
9: $szam += 5;
10: }
11: $regiSzam = 10;
12: ottelTobb( &$regiSzam );
13: print( $regiSzam );
14: ?>
15: </body>
16: </html>
06_ora.qxd 8/3/2001 6:11 PM Page 93

Függvények 93

6.15. program Cím szerinti paraméterátadás


a függvénydeklaráció módosításával
1: <html>
2: <head>
3: <title>6.15. program Cím szerinti paraméterátadás
a függvénydeklaráció módosításával</title>
4: </head>
5: <body>
6: <?php
7: function ottelTobb( &$szam )
8: {
9: $szam += 5;
10: }
11: $regiSzam = 10;
12: ottelTobb( $regiSzam );
13: print( $regiSzam );
14: ?>
15: </body>
16: </html>

Ha az átadandó paramétert alakítjuk hivatkozássá, akkor nem fogjuk elfelejteni,


hogy az átadott paraméter értéke megváltozhat, hiszen mi tettük hivatkozássá.
Ennek a változatnak viszont az a veszélye, hogy elfelejtjük kitenni az & jelet.
(C programozók már biztosan tapasztalták...) Ha a második megoldást választjuk,
akkor lehet, hogy elfelejtjük, hogy a paraméter értéke megváltozhat, viszont nem
felejtjük el kitenni az & jelet, mivel nem is kell kitennünk. Mindent egybevéve
talán több értelme van annak, hogy a függvénydeklarációban írunk & jelet
a paraméter neve elé. Így biztosak lehetünk benne, hogy az egyes függvényhí-
vások azonos módon viselkednek. 6
Összefoglalás
Ebben az órában megtanultuk, mik azok a függvények és hogyan kell õket hasz-
nálni. Megtanultuk, hogyan kell létrehozni és paramétereket átadni nekik. Elsajátí-
tottuk a global és a static kulcsszavak használatát. Megtanultuk, hogyan kell
a függvényeknek hivatkozásokat átadni és a paramétereknek alapértelmezett
értéket adni.
06_ora.qxd 8/3/2001 6:11 PM Page 94

94 6. óra

Kérdések és válaszok
A global kulcsszón kívül van más mód arra, hogy egy függvény hozzá
tudjon férni vagy módosítani tudjon egy globális változót?
A globális változókat a programon belül bárhonnan elérhetjük a $GLOBALS nevû
asszociatív tömb segítségével. A $proba nevû globális változót például
$GLOBALS["proba"]-ként érhetjük el. Az asszociatív tömbökrõl a következõ
órában tanulunk.

A globális változót a függvényen belül akkor is módosíthatjuk, ha a függvény


paraméterként egy arra mutató hivatkozást kapott.

Kérdés: Lehet-e a függvényhívásokat a változókhoz hasonlóan karak-


terláncba ágyazni?
Nem. A függvényhívásoknak az idézõjeleken kívül kell lenniük.

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. Igaz-e, hogy ha egy függvénynek nem kell paramétert átadni, akkor a függ-
vény neve után nem szükséges kitenni a zárójelpárt?

2. Hogyan lehet függvénybõl értéket visszaadni?

3. Mit ír ki az alábbi kódrészlet?


$szam = 50;

function tizszer()
{
$szam = $szam * 10;
}

tizszer();
print $szam;
06_ora.qxd 8/3/2001 6:11 PM Page 95

Függvények 95

4. Mit ír ki az alábbi kódrészlet?


$szam = 50;

function tizszer()
{
global $szam;
$szam = $szam * 10;
}

tizszer();
print $szam;

5. Mit ír ki az alábbi kódrészlet?


$szam = 50;

function tizszer($sz)
{
$sz = $sz * 10;
}

tizszer($szam);
print $szam;

6. Mit ír ki az alábbi kódrészlet?


$szam = 50;

function tizszer(&$sz)
{
$sz = $sz * 10;
}

$tizszer($szam);
6
print $szam;

Feladatok
1. Írjunk függvényt, amely négy karakterlánc típusú értéket fogad és olyan karak-
terlánccal tér vissza, amely paramétereit HTML cellaelemekbe (TD) zárja!
06_ora.qxd 8/3/2001 6:11 PM Page 96
07_ora.qxd 8/3/2001 6:16 PM Page 97

7. ÓRA
Tömbök
A tömbök és a kezelésüket segítõ eszközök nagy mértékben növelik a PHP 4
programok rugalmasságát. Ha jól értünk a tömbökhöz, képesek vagyunk nagy
méretû, összetett adatokat tárolni és kezelni.

Ebben az órában bemutatjuk a tömböket és néhány beépített függvényt, amelyek


segítik a velük való boldogulást. Az órában a következõket tanuljuk meg:

• Mik a tömbök és hogyan hozhatók létre?

• Hogyan érhetjük el a tömbökben tárolt adatokat?

• Hogyan rendezhetjük a tömbökben tárolt adatokat?


07_ora.qxd 8/3/2001 6:16 PM Page 98

98 7. óra

Mit nevezünk tömbnek?


Mint már tudjuk, a változó egy „vödör”, amiben egy értéket lehet tárolni. Változók
segítségével olyan programot írhatunk, amely információt tárol, dolgoz fel és ír ki.
Egy változóban azonban sajnos csak egy értéket tárolhatunk. A tömb olyan külön-
leges szerkezetû változó, amelyben nincs ilyen korlátozás. Egy tömbbe annyi ada-
tot lehet beletenni, amennyit csak akarunk (amennyi memóriánk van). Minden ele-
met egy szám vagy egy karakterlánc segítségével azonosíthatunk. Ha a változó
„vödör”, akkor a tömb „iratszekrény”, tehát olyan tároló, amelyben sok-sok elemet
tárolhatunk.

A tömb változók listája. Több változót tartalmaz, amelyeket számok vagy


ÚJDONSÁG
karakterláncok segítségével azonosíthatunk, így a különbözõ értékeket
egyetlen névvel tárolhatjuk, rendezhetjük és érhetjük el.

Természetesen ha öt értéket kell tárolnunk, megadhatunk öt változót is. Akkor mi-


ért jó tömböt használni változók helyett? Elõször is azért, mert a tömb rugalma-
sabb adatszerkezet. Lehet benne két vagy akár kétszáz érték és ennek elérése ér-
dekében nem kell további változókat létrehozni. Másodszor, a tömbök elemeit
könnyedén kezelhetjük egységként is. Ha akarjuk, végighaladhatunk a tömbön
egy ciklussal vagy elérhetjük az elemeit egyenként. Lehetõségünk van a tömböt
rendezni szám szerint, szótári rendezés szerint vagy saját rendezõelv alapján.

A tömb elemeit az index segítségével könnyen elérhetjük. Az index lehet szám,


de akár karakterlánc is.

Alapértelmezés szerint a tömböket számokkal indexeljük, mégpedig úgy, hogy


az elsõ elem indexe 0. Ebbõl az következik, hogy az utolsó tömbelem indexe
mindig eggyel kisebb a tömb méreténél. Tehát az öt elemû tömb utolsó eleme
a 4-es indexû elem. Ezt ajánlatos mindig fejben tartani!

A 7.1. táblázatban a felhasznalok tömböt láthatjuk. Figyeljük meg, hogy példá-


ul a tömb harmadik elemének indexe 2.

7.1. táblázat A felhasznalok tömb elemei


Index Érték Hányadik elem
0 Berci Elsõ
1 Mariska Második
2 Aladár Harmadik
3 Eleonóra Negyedik
07_ora.qxd 8/3/2001 6:16 PM Page 99

Tömbök 99

A karakterlánccal való indexelés akkor lehet hasznos, ha egyedi nevek (kulcsok)


mellett más értékeket is tárolni kell.

A PHP 4 mind a számokkal, mind a „nevekkel” indexelt tömbök elérésére biztosít


segédeszközöket. Ezek közül néhánnyal ebben a fejezetben is találkozni fogunk,
másokat a tizenhatodik, adatmûveletekkel foglalkozó fejezetben ismerünk
majd meg.

Tömbök létrehozása
A tömbök alapértelmezés szerint értékek számmal indexelt listái. Értéket egy
tömbhöz kétféleképpen is rendelhetünk: Az egyik mód az array() függvény,
a másik a tömbazonosító használata szögletes zárójelekkel ([]). A következõ két
részben mind a kétféle változattal találkozni fogunk.

Tömbök létrehozása az array() függvény segítségével


Az array() függvény akkor hasznos, ha egyszerre több értéket szeretnénk egy
tömbhöz rendelni. Hozzunk létre egy $felhasznalok nevû tömböt és rendel-
jünk hozzá négy elemet!

$felhasznalok = array ("Berci", "Mariska", "Aladár", "Eleonóra");

Most a $felhasznalok tömb harmadik elemét, melynek indexe 2, írassuk ki!

print $felhasznalok[2];

Ez a következõ karakterláncot fogja kiírni: "Aladár". Az indexet a tömb neve


után közvetlenül következõ szögletes zárójelbe kell írni. A tömbelem írásakor és
olvasásakor is ezt a jelölést kell használni.

Ne felejtsük el, hogy a tömbök indexelése nullától indul, így bármely tömbelem
indexe eggyel kisebb a tömbelem tömbbéli helyénél. (Az elsõ elem indexe 0,
a második elem indexe 1.)

7
Tömb létrehozása vagy elem hozzáadása a tömbhöz
szögletes zárójel segítségével
Tömböket úgy is létrehozhatunk, illetve meglevõ tömbökhöz új elemeket adha-
tunk, ha a tömb neve után olyan szögletes zárójelpárt írunk, amelynek belsejében
nincs index.
07_ora.qxd 8/3/2001 6:16 PM Page 100

100 7. óra

Hozzuk létre újra a $felhasznalok nevû tömböt:

$felhasznalok[] = "Berci";
$felhasznalok[] = "Mariska";
$felhasznalok[] = "Aladár";
$felhasznalok[] = "Eleonóra";

Figyeljük meg, hogy nem kellett számot írnunk a szögletes zárójelbe. A PHP 4
automatikusan meghatározza az indexértéket, így nem kell nekünk bajlódni azzal,
hogy kiszámítsuk a következõ olyan indexet, amelyben még nincs érték.

Persze írhattunk volna számokat is a szögletes zárójelbe, de ez nem tanácsos.


Nézzük a következõ programrészletet:

$felhasznalok[0] = "Berci";
$felhasznalok[200] = "Mariska";

A tömbnek így mindössze két eleme van, de az utolsó elem indexe 200. A PHP 4
nem fog értéket adni a köztes elemeknek, ami félreértésekre adhat okot az elemek
elérésekor.

Tömbök létrehozása mellett a tömbváltozók szögletes zárójele segítségével


az array() függvénnyel létrehozott tömb végéhez új elemet is adhatunk.
Az alábbi kis programrészletben létrehozunk egy tömböt az array() függvény
segítségével, majd új elemet adunk a tömbhöz szögletes zárójellel.

$felhasznalok = array ("Berci", "Mariska", "Aladár", "Eleonóra");


$felhasznalok[] = "Anna";

Asszociatív tömbök
A számmal indexelt tömbök akkor hasznosak, ha abban a sorrendben szeretnénk
tárolni az elemeket, amilyen sorrendben a tömbbe kerültek. Néha azonban jó lenne,
ha a tömb elemeit meg tudnánk nevezni. Az asszociatív tömb egy karakterláncokkal
indexelt tömb. Képzeljünk el egy telefonkönyvet: melyik a jobb megoldás: a név
mezõt a 4-gyel vagy a “név”-vel indexelni?

A karakterlánccal indexelt tömböket asszociatív tömböknek


ÚJDONSÁG
(néha hash-nek) hívják.
07_ora.qxd 8/3/2001 6:16 PM Page 101

Tömbök 101

Asszociatív tömbök létrehozása a számokkal indexelt tömbökkel megegyezõen


történik, az array() függvény vagy a szögletes zárójelek segítségével.

A számmal és a karakterlánccal indexelt tömbök közti határvonal


a PHP-ben nem éles. Nem különbözõ típusok, mint a Perlben,
ennek ellenére helyes az a hozzáállás, ha külön-külön kezeljük
õket, mert az egyes típusok más hozzáférési és kezelési módot
igényelnek.

Asszociatív tömbök létrehozása


az array() függvény segítségével
Ha asszociatív tömböt szeretnénk létrehozni az array() függvény segítségével,
minden elemnek meg kell adni a kulcsát és az értékét. Az alábbi programrészlet
egy $karakter nevû asszociatív tömböt hoz létre négy elemmel.

$karakter = array
(
"nev" => "János",
"tevekenyseg" => "szuperhõs",
"eletkor" => 30,
"kulonleges kepesseg" => "röntgenszem"
);

Most elérhetjük a $karakter elemeit (mezõit):

print $karakter["eletkor"];

Asszociatív tömbök létrehozása és


elérése közvetlen értékadással
Asszociatív tömböt úgy is létrehozhatunk vagy új név–érték párt adhatunk hozzá,

7
ha egyszerûen a megnevezett elemhez (mezõhöz) új értéket adunk. Az alábbiak-
ban újra létrehozzuk a $karakter nevû tömböt, úgy, hogy az egyes kulcsokhoz
egyenként rendelünk értékeket.
07_ora.qxd 8/3/2001 6:16 PM Page 102

102 7. óra

$karakter["nev"] => "János";


$karakter["tevekenyseg"] => "szuperhõs";
$karakter["eletkor"] => 30;
$karakter["kulonleges kepesseg"] => "röntgenszem";

Többdimenziós tömbök
Eddig azt mondtuk, hogy a tömbök elemei értékek. A $karakter tömbünkben
az elemek közül három karakterláncot tartalmaz, egy pedig egy egész számot.
A valóság ennél egy kicsit bonyolultabb. Egy tömbelem valójában lehet érték, ob-
jektum vagy akár egy másik tömb is. A többdimenziós tömb valójában tömbök
tömbje. Képzeljük el, hogy van egy tömbünk, amelynek tömbök az elemei. Ha el
akarjuk érni a második elem harmadik elemét, két indexet kell használnunk:

$tomb[1][2]

A tömböt, amelynek elemei tömbök, többdimenziós tömbnek hívjuk.


ÚJDONSÁG

A tény, hogy egy tömbelem lehet tömb is, lehetõséget biztosít arra, hogy kifino-
multabb adatszerkezeteket kezeljünk viszonylag egyszerûen. A 7.1. példaprogram
egy tömböt ír le, amelynek elemei asszociatív tömbök.

7.1. program Többdimenziós tömb létrehozása


1: <html>
2: <head>
3: <title>7.1. program Többdimenziós tömb
létrehozása</title>
4: </head>
5: <body>
6: <?php
7: $karakter = array
8: (
9: array (
10: "nev" => "János",
11: "tevekenyseg" => "szuperhõs",
12: "eletkor" => 30,
13: "kulonleges kepesseg" => "röntgenszem"
14: ),
07_ora.qxd 8/3/2001 6:16 PM Page 103

Tömbök 103

7.1. program (folytatás)


15: array (
16: "nev" => "Szilvia",
17: "tevekenyseg" => "szuperhõs",
18: "eletkor" => 24,
19: "kulonleges kepesseg" => "nagyon erõs"
20: ),
21: array (
22: "nev" => "Mari",
23: "tevekenyseg" => "fõgonosz",
24: "eletkor" => 63,
25: "kulonleges kepesseg" =>
"nanotechnológia"
26: )
27: );
28:
29: print $karakter[0]["tevekenyseg"]; //kiírja, hogy
szuperhõs
30: ?>
31: </body>
32: </html>

Figyeljük meg, hogy array() függvényhívásokat építettünk egy array()


függvényhívásba. Az elsõ szinten adjuk meg a tömböt, melynek minden eleme
asszociatív tömb.

A $karakter[2] tömbelemhez történõ hozzáféréskor a legfelsõ szintû tömb


harmadik elemét, egy asszociatív tömböt kapunk. Az asszociatív tömb bármely
elemét elérhetjük, például a $karakter[2]["nev"] értéke "Mari" lesz,
a $karakter[2]["eletkor"] pedig 63.

Ha a fogalmak tiszták, asszociatív és hagyományos tömbök párosításával


egyszerûen hozhatunk létre összetett adatszerkezeteket.

7
07_ora.qxd 8/3/2001 6:16 PM Page 104

104 7. óra

Tömbök elérése
Eddig azt láttuk, hogyan kell tömböket létrehozni és elemeket adni azokhoz.
Most végignézünk néhány lehetõséget, amit a PHP 4 a tömbök elérésére biztosít.

Tömb méretének lekérdezése


A tömb bármely elemét elérhetjük indexének használatával:

print $felhasznalo[4];

A tömbök rugalmassága miatt nem mindig egyszerû feladat kideríteni, hány elem
van a tömbben. A PHP a count() függvényt biztosítja erre a feladatra.
A count() a tömbben levõ elemek számával tér vissza. Az alábbi programrész-
ben egy számokkal indexelt tömböt hozunk létre, majd a count() függvényt
használjuk a tömb utolsó elemének elérésére.

$felhasznalok = array ("Berci", "Marci", "Ödön", "Télapó");


$felhasznalok[count($felhasznalok)-1];

Figyeljük meg, hogy egyet ki kellett vonnunk a count() által visszaadott értékbõl.
Ez azért van így, mert a count() nem az utolsó elem indexét adja vissza, hanem
a tömbelemek számát.

Semmi sem garantálja, hogy ezzel a módszerrel bármilyen (számokkal indexelt)


tömb utolsó elemét megkapjuk. Vegyük például az alábbi programot:

$tomb = array("Ecc, pecc"); // Egyelemû tömb!


$tomb[2] = "kimehetsz";
print "Az utolsó elem: " . $tomb[count($tomb)-1];

A fenti kódot futtatva azt tapasztaljuk, hogy az "Az utolsó elem: " szöveg
után semmi nem íródik ki. Ez azért van, mert a tömbnek nincs 1 indexû eleme.
Az elsõ elem a 0 indexen található, a második a 2 indexen, mivel az értékadáskor
az indexet közvetlenül határoztuk meg.
A tömbök indexelése alapértelmezés szerint nullától indul, de ezt meg lehet
változtatni. Ha azonban világos és következetes programokat szeretnénk írni,
ne éljünk ezzel a lehetõséggel.

Tömb bejárása
Több módja van annak, hogy egy tömb minden elemét végigjárjuk. Mi most a PHP 4
igen hatékony foreach szerkezetét használjuk, de a tizenhatodik órában további
módszereket is megvizsgálunk.
07_ora.qxd 8/3/2001 6:16 PM Page 105

Tömbök 105

A foreach a PHP 4-es változatában került a nyelvbe.

A számmal indexelt tömbökre a foreach szerkezetet így kell használni:

foreach($tombnev as $atmeneti)
{
}

$tombnev a tömb neve, amit végig szeretnénk járni, az $atmeneti pedig


egy változó, amelybe minden ismétlés során a tömb egy-egy eleme kerül.

Az alábbi példában egy számmal indexelt tömböt hozunk létre és a foreach


vezérlési szerkezet segítségével érjük el annak elemeit:

$felhasznalok = array ("Berci", "Marci", "Ödön");


$felhasznalok[10] = "Télapó";
foreach($felhasznalok as $szemely)
{
print"$szemely<br>";
}

A program kimenetét a 7.1-es ábrán láthatjuk.

7.1. ábra
Tömb bejárása

A tömb minden eleme átmenetileg a $szemely változóba került, amit a program


kiír a böngészõbe. A Perlben gyakorlattal rendelkezõk vigyázzanak, a foreach
szerkezet a két nyelvben jelentõsen különbözik! A Perlben ha az átmeneti változó
értékét megváltoztatjuk, a megfelelõ tömbelem is megváltozik.
07_ora.qxd 8/3/2001 6:16 PM Page 106

106 7. óra

Ha ugyanezt az elõzõ példában tesszük, a $felhasznalok tömb értéke nem fog


megváltozni. A tizenhatodik órában látni fogjuk, hogyan módosíthatjuk
a foreach segítségével a tömbök tartalmát.

Figyeljük meg, hogy annak ellenére, hogy a tömb „lyukas”, a program a foreach
szerkezet segítségével bejárt tömb minden elemét kiírta és az utolsó sor elõtt nem
jelentek meg üres sorok, tehát a 3 és 9 indexek közötti tömbelemeket (melyek
nem meghatározottak, vagyis üres karakterláncok) nem írja ki a program.

Ahol csak mód van rá, ne használjunk tömbindexeket. A tömbö-


ket sokszor csak egyszerû listaként használjuk, ahol nem számít
az, hogy egy adott elemnek mi az indexe. A PHP a tömbök
elérésére a tömbindexek használatánál hatékonyabb és áttekint-
hetõbb függvényeket biztosít, programunk ezáltal rugalmasabb,
könnyebben módosítható és jól olvasható lesz.

Asszociatív tömb bejárása


Ha az asszociatív tömb kulcsát és értékét is el szeretnénk érni, egy kicsit másképpen
kell a foreach szerkezet használnunk.

Asszociatív tömböknél a foreach így alkalmazható:

foreach( $tomb as $kulcs => $ertek )


{
// a tömbelem feldolgozása
}

ahol $tomb a tömb neve, amin végig szeretnénk menni, $kulcs a változó,
amelyben az elem kulcsa jelenik meg, a $ertek pedig a kulcshoz tartozó tömb-
elem értéke.

A 7.2. példaprogramban létrehozunk egy asszociatív tömböt, majd egyesével


elérjük és kiírjuk a tömb elemeit
07_ora.qxd 8/3/2001 6:16 PM Page 107

Tömbök 107

7.2. program Asszociatív tömb bejárása a foreach segítségével


1: <html>
2: <head>
3: <title>7.2 példaprogram Asszociatív tömb bejárása
a foreach segítségével</title>
4: </head>
5: <body>
6: <?php
7: $karakter = array (
8: "nev" => "János",
9: "tevekenyseg" => "szuperhõs",
10: "eletkor" => 30,
11: "kulonleges kepesseg" => "röntgenszem"
12: );
13:
14: foreach ( $karakter as $kulcs => $ertek )
15: {
16: print "$kulcs = $ertek<br>";
17: }
18: ?>
19: </body>
20: </html>

A 7.2. példaprogram kimenetét a 7.2. ábrán láthatjuk.

7.2. ábra
Asszociatív tömb
bejárása

7
07_ora.qxd 8/3/2001 6:16 PM Page 108

108 7. óra

Többdimenziós tömb bejárása


Most már ismerünk olyan módszereket, amelyek segítségével a 7.1. példaprog-
ramban létrehozott többdimenziós tömböt bejárhatjuk. A 7.3. példaprogramban
létrehozunk egy többdimenziós tömböt és a foreach segítségével végigjárjuk
az elemeit.

7.3. program Többdimenziós tömb bejárása


1: <html>
2: <head>
3: <title>7.3. program - Többdimenziós tömb
bejárása</title>
4: </head>
5: <body>
6: <?php
7: $karakterek = array
8: (
9: array (
10: "nev" => "János",
11: "tevekenyseg" => "szuperhõs",
12: "eletkor" => 30,
13: "kulonleges kepesseg" => "röntgenszem"
14: ),
15: array (
16: "nev" => "Szilvia",
17: "tevekenyseg" => "szuperhõs",
18: "eletkor" => 24,
19: "kulonleges kepesseg" => "nagyon erõs"
20: ),
21: array (
22: "nev" => "Mari",
23: "tevekenyseg" => "fõgonosz",
24: "eletkor" => 63,
25: "kulonleges kepesseg" =>
"nanotechnológia"
26: )
27: );
07_ora.qxd 8/3/2001 6:16 PM Page 109

Tömbök 109

7.3. program (folytatás)


28: foreach ( $karakterek as $karakter )
29: {
30: foreach ( $karakter as $kulcs => $ertek )
31: {
32: print "$kulcs: $ertek<br>";
33: }
34: print "<br>";
35: }
36: ?>
37: </body>
38: </html>

A 7.3. példaprogram kimenetét a 7.3. ábrán láthatjuk. Két foreach ciklust hasz-
nálunk. A külsõ ciklusban a számmal indexelt $karakterek tömb elemeit
vesszük végig, az egyes elemek pedig a $karakter nevû változóba kerülnek.
A $karakter maga is egy tömb, ezért ennek értékeit is egy foreach ciklussal
járjuk végig. Mivel a $karakter egy asszociatív tömb, a foreach szerkezetet
az ennek megfelelõ formában használjuk, a kulcs-érték párok pedig a $kulcs és
az $ertek változókba kerülnek.

Annak érdekében, hogy ez a módszer jól mûködjön, biztosnak kell lennünk abban,
hogy a $karakter változó valóban mindig tömböt tartalmaz. A kódot megbízha-
tóbbá tehetnénk, ha meghívnánk a $karakter változóra az is_array() függ-
vényt. Az is_array() függvény számára egy paramétert kell megadnunk.
A visszatérési érték true lesz, ha a változó típusa tömb, minden más esetben
false értéket ad.

Bonyolultabb programok esetében gyakran elõfordul, hogy


kíváncsiak vagyunk egy tömb vagy valamilyen más összetett
változó tartalmára. Ilyenkor általában nem kell saját tömblistázó
kódot használnunk, hiszen a PHP 4 biztosítja számunkra
a print_r() függvényt, amely a paramétereként megadott változó
tartalmát írja ki. 7
07_ora.qxd 8/3/2001 6:16 PM Page 110

110 7. óra

Mûveletek tömbökkel
Most már fel tudunk tölteni tömböket elemekkel, elérhetjük azokat, de a PHP ren-
geteg függvénnyel segíti a tömbök feldolgozását is. A Perlben jártas olvasó bizo-
nyára ismerõsnek fogja találni ezen függvények nagy részét.

Két tömb egyesítése az array_merge() függvény


segítségével
Az array_merge() függvény legalább két paramétert vár: az egyesítendõ tömbö-
ket. A visszatérési érték az egyesített tömb lesz. Az alábbi példában létrehozunk két
tömböt, egyesítjük azokat, majd végigjárjuk a keletkezõ harmadik tömböt:

$elso = array( "a", "b", "c" );


$masodik = array( 1, 2, 3 );
$harmadik = array_merge( $elso, $masodik );
foreach( $harmadik as $ertek )
{
print "$ertek<br>";
}

A $harmadik tömb az $elso és a $masodik tömbök elemeinek másolatát tartal-


mazza. A foreach ciklus ennek a tömbnek az elemeit ("a", "b", "c", 1, 2, 3)
írja ki a böngészõbe. Az egyes elemeket a <br> (sortörés) választja el egymástól.

Az array_merge() függvény a PHP 4-es változatában került


a nyelvbe.

Egyszerre több elem hozzáadása egy tömbhöz


az array_push() függvény segítségével
Az array_push() függvény egy tömböt és tetszõleges számú további paramétert
fogad. A megadott értékek a tömbbe kerülnek. Figyeljük meg, hogy
az array_merge() függvénnyel ellentétben az array_push() megváltoztatja
elsõ paraméterének értékét. E függvény visszatérési értéke a tömbben lévõ elemek
száma (miután az elemeket hozzáadta). Hozzunk létre egy tömböt, majd adjunk
hozzá néhány elemet:
07_ora.qxd 8/3/2001 6:16 PM Page 111

Tömbök 111

$elso = array( "a", "b", "c" );


$elemszam = array_push( $elso, 1, 2, 3 );

print "Összesen $elemszam elem van az \$elso tömbben<P>";


foreach( $elso as $ertek )
{
print "$ertek<br>";
}

Mivel az array_push() függvény visszaadja a módosított tömb elemeinek


számát, az értéket (ami ebben az esetben 6) egy változóban tárolhatjuk és kiírat-
hatjuk a böngészõbe. Az $elso tömb ekkor az eredeti három betût tartalmazza,
melyekkel az elsõ sorban feltöltöttük, illetve a három számot, amit
az array_push() függvény segítségével adtunk hozzá. Az így létrehozott
tömb elemeit a foreach ciklus segítségével kiíratjuk a böngészõbe.

Figyeljük meg, hogy a "$elso" karakterlánc elé egy fordított perjelet kellett
tennünk. Ha a PHP egy macskakörmös (kettõs idézõjeles) karakterláncban egy
dollárjelet követõ betû- és/vagy számsorozatot talál, változóként próbálja értel-
mezni azt és megkísérli az értékét beírni. A fenti példában mi a '$elso' karak-
tersorozatot szerettük volna megjeleníteni, ezért kellett a dollárjel elé a fordított
perjel karakter. Így a PHP már nem próbálja meg változóként értelmezni, hanem
kiírja a karaktereket. Ezt a módszert a szakirodalomban gyakran escape-ként
emlegetik.

A Perlben gyakorlattal rendelkezõk figyeljenek arra, hogy ha


a PHP-ben az array_push() második paramétereként tömböt ad-
nak meg, a tömb egy tömb típusú elemmel bõvül, ezáltal több-
dimenziós tömb keletkezik. Ha két tömb elemeit szeretnénk
egyesíteni, használjuk az array_merge() függvényt.

Ha egy karakterláncban nem szeretnénk, hogy a változók behe-


lyettesítõdjenek, a karakterlánc jelölésére egyszeres idézõjeleket
használjunk; ekkor a ‘ és a \ karakterek helyett \’-t és \\-t kell ír-
nunk. 7
07_ora.qxd 8/3/2001 6:16 PM Page 112

112 7. óra

Az elsõ elem eltávolítása


az array_shift() függvény segítségével
Az array_shift() eltávolítja a paraméterként átadott tömb elsõ elemét és
az elem értékével tér vissza. A következõ példában az array_shift() függvény
segítségével eltávolítjuk a tömb elsõ elemét. Ezt a mûveletet egy while ciklusba
tesszük és a mûveletet addig ismételjük, amíg el nem fogy a tömb. Annak ellenõr-
zésére, hogy van-e még elem a tömbben, a count() függvényt használjuk.

<?php
$egy_tomb = array( "a", "b", "c" );

while ( count( $egy_tomb ) )


{
$ertek = array_shift( $egy_tomb );
print "$ertek<br>";
print '$egy_tomb-ben most ' . count( $egy_tomb )
. 'elem van<br>';
}
?>

A program kimenetét a 7.4. ábrán láthatjuk.

7.4. ábra
A tömb egyes elemei-
nek törlése és kiíratá-
sa az array_shift()
függvény segítségével

Az array_shift() akkor lehet hasznos, amikor egy sor elemein kell valamilyen
tevékenységet végezni, amíg a sor ki nem ürül.

Az array_shift() függvény a PHP 4-es változatában került


a nyelvbe.
07_ora.qxd 8/3/2001 6:16 PM Page 113

Tömbök 113

Tömb részének kinyerése


az array_slice() függvény segítségével
Az array_slice() függvény egy tömb egy darabját adja vissza. A függvény
egy tömböt, egy kezdõpozíciót (a szelet elsõ elemének tömbbeli indexét) és
egy (elhagyható) hossz paramétert vár. Ha ez utóbbit elhagyjuk, a függvény felté-
telezi, hogy a kezdõpozíciótól a tömb végéig tartó szeletet szeretnénk megkapni.
Az array_slice() nem változtatja meg a paraméterként átadott tömböt,
hanem újat ad vissza, amelyben a hívó által kért elemek vannak.

Az alábbi példában létrehozunk egy tömböt, majd egy új, három elemû tömböt ál-
lítunk elõ belõle:

$elso = array( "a", "b", "c", "d", "e", "f" );


$masodik = array_slice( $elso, 2, 3 );

foreach( $masodik as $ertek )


{
print "$ertek<br>";
}

A fenti példa a "c", "d" és "e" elemeket írja ki, a <br> kódelemmel elválasztva.
Mivel kezdõpozícióként a kettõt adtuk meg, így az elsõ elem, ami a $masodik
tömbbe kerül, az $elso[2].

Ha kezdõpozícióként negatív számot adunk meg, a tömbszelet elsõ eleme hátulról


a megadott számú elemtõl kezdõdik. Ez azt jelenti, hogy ha a második paraméter
értéke -1, a tömbszelet az utolsó elemtõl fog kezdõdni.

Ha hossz paraméterként nullánál kisebb számot adunk meg, a visszakapott tömb-


szelet a tömb hátulról a megadott számú eleméig tart.

Az array_slice() függvény a PHP 4-es változatában jelent meg.

7
Tömbök rendezése
Talán a rendezés a legnagyszerûbb mûvelet, amit egy tömbön el lehet végezni.
A PHP 4 függvényeinek köszönhetõen egykettõre rendet teremthetünk a káosz-
ban. A következõ rész néhány olyan függvényt mutat be, amelyek számmal és ka-
rakterlánccal indexelt tömböket rendeznek.
07_ora.qxd 8/3/2001 6:16 PM Page 114

114 7. óra

Számmal indexelt tömb rendezése


a sort() függvény segítségével
A sort() függvény egy tömb típusú paramétert vár és a tömb rendezését végzi el.
Ha a tömbben van karakterlánc, a rendezés (alapbeállításban angol!) ábécésorrend
szerinti lesz, ha a tömbben minden elem szám, szám szerint történik. A függvény-
nek nincs visszatérési értéke, a paraméterként kapott tömböt alakítja át.
Ebbõl a szempontból különbözik a Perl hasonló függvényétõl. Az alábbi program-
részlet egy karakterekbõl álló tömböt hoz létre, rendezi, majd a rendezett tömb
elemeit egyenként kiírja:

$tomb = array( "x", "a", "f", "c" );


sort( $tomb );

foreach ($tomb as $elem)


{
print "$elem<br>";
}

Nézzük egy kis példát egy tömb kétféle rendezési módjára!

$tomb = array( 10, 2, 9 );


sort( $tomb );

print '___Rendezés szám szerint___'<br>;


foreach ($tomb as $elem)
{
print "$elem<br>";
}
$tomb[]="a";
sort( $tomb );

print '___Rendezés ábécésorrend szerint___<br>';


foreach ($tomb as $elem)
{
print "$elem<br>";
}

A fenti példa kimenete:

___Rendezés szám szerint___


2
9
10
07_ora.qxd 8/3/2001 6:16 PM Page 115

Tömbök 115

___Rendezés ábécésorrend szerint___


10
2
9
a

A sort() függvényt ne használjuk asszociatív (karakterlánccal


indexelt) tömbökre! Ha mégis megtesszük, azt fogjuk tapasztal-
ni, hogy a tömb elemei ugyan rendezettek lesznek, de az
elemek kulcsai elvesznek, az egyes elemek így nullától kezdõdõ
számokkal érhetõk el, ugyanis a tömb számmal indexelt tömbbé
alakul át.

Ha csökkenõ sorrendben szeretnénk rendezni egy tömb elemeit, használjuk


a sort() függvényhez hasonlóan mûködõ rsort() függvényt.

Asszociatív tömb rendezése érték szerint


az asort() függvény segítségével
Az asort() függvény egy asszociatív tömb típusú paramétert vár és a tömböt
a sort() függvényhez hasonlóan rendezi. Az egyetlen különbség,
hogy az asort() használata után megmaradnak a karakterlánc-kulcsok:

$a_tomb = array( "elso"=>5, "masodik"=>2, "harmadik"=>1 );

asort( $a_tomb );
foreach( $a_tomb as $kulcs => $ertek )
{
print "$kulcs = $ertek<br>";
}

7
Ennek a programocskának a kimenetét a 7.5. ábrán láthatjuk.
07_ora.qxd 8/3/2001 6:16 PM Page 116

116 7. óra

7.5. ábra
Asszociatív tömb
érték szerinti rende-
zése az asort() függ-
vény segítségével

Ha csökkenõ sorrendben szeretnénk rendezni egy asszociatív tömb elemeit,


használjuk a arsort() függvényt.

Asszociatív tömb rendezése kulcs szerint


a ksort() függvény segítségével
A ksort() a paraméterben megadott asszociatív tömböt rendezi kulcs szerint.
A többi tömbrendezõ függvényhez hasonlóan ez a függvény sem ad vissza semmi-
féle visszatérési értéket, hanem a tömböt alakítja át:

$tomb = array( "x" => 5, "a" => 2, "f" => 1 );

ksort( $tomb );

foreach( $tomb as $kulcs => $ertek )


{
print "$kulcs = $ertek<BR>";
}

A program kimenetét a 7.6. ábrán láthatjuk.

7.6. ábra
Asszociatív tömb
rendezése kulcs
szerint a ksort() függ-
vény segítségével
07_ora.qxd 8/3/2001 6:16 PM Page 117

Tömbök 117

Összefoglalás
Ebben az órában a tömbökrõl és a hozzájuk kapcsolódó eszközökrõl tanultunk,
melyeket a PHP 4 a rajtuk végzett mûveletekhez nyújt. Most már tudunk normál
(számmal indexelt) és asszociatív (karakterlánccal indexelt) tömböket is létrehozni,
illetve tömböket bejárni a foreach ciklus segítségével.
Többdimenziós tömböket is létre tudunk hozni, a bennük levõ információt pedig
ki tudjuk nyerni egymásba ágyazott foreach ciklusokkal. A tömbökhöz egyszerre
több elemet is adhatunk, illetve onnan kivehetünk. Végül megtanultuk, hogy
a PHP 4-es változata milyen lehetõségeket nyújt a tömbök rendezésére.

Kérdések és válaszok
Ha a foreach ciklus csak a PHP 4-esben került a nyelvbe, akkor a PHP 3-as
változatát használó programozók hogyan jártak végig egy tömböt?
A PHP 3-asban az each() függvényt használták egy while() ciklusban.
Errõl bõvebben a tizenhatodik órában olvashatunk.

Van olyan tömböt kezelõ függvény, amellyel nem foglalkoztunk ebben


az órában?
A PHP 4-es változatában nagyon sok tömbkezelõ függvény van. Errõl bõvebben a ti-
zenhatodik órában fogunk tanulni. A kézikönyv errõl szóló része megtalálható az
Interneten, a http://www.php.net/manual/en/ref.array.php címen. (A
kézikönyv magyar változata a http://hu.php.net/manual/hu/ oldalon talál-
ható.)

Ha a tömb elemeinek számát ismerem, normál tömb bejárására a for


ciklust használjam? (Ekkor számláló segítségével címzem meg a tömb
elemeit.)
Nagyon óvatosan kell bánni ezzel a megközelítéssel. Nem lehetünk biztosak
abban, hogy az általunk használt tömb indexei 0-tól indulnak és egyesével nõnek.

Mûhely
7
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 hozhatunk létre tömböket?

2. Az alább létrehozott tömb utolsó elemének mi az indexe?


$torpek = array( "Tudor", "Vidor", "Kuka" );
07_ora.qxd 8/3/2001 6:16 PM Page 118

118 7. óra

3. Függvények használata nélkül hogyan tudnánk "Hapci"-t az imént létreho-


zott $torpek nevû tömbhöz adni?

4. Melyik függvény segítségével tudnánk "Morgó"-t a $torpek nevû tömbbe


felvenni?

5. Hogyan lehet egy tömb elemszámát megtudni?

6. A PHP 4-es változatában mi a legegyszerûbb módja egy tömb bejárásának?

7. Milyen függvény segítségével lehet két tömböt egyesíteni?

8. Hogyan rendeznénk egy asszociatív tömböt kulcsai szerint?

Feladatok
1. Hozzunk létre egy többdimenziós tömböt, amely filmeket tartalmaz, zsáner
szerint rendezve! Pontosabban hozzunk létre egy asszociatív tömböt, amelynek
kulcsai filmtípusok ("Scifi", "Akció", "Romantikus"…)! A tömb elemei
legyenek tömbök, amelyek filmcímeket tartalmaznak ("2001", "Alien",
"Terminator",...)!

2. Járjuk végig az elõzõ feladatban létrehozott tömböt és írjuk ki az összes


filmtípust és a hozzá tartozó filmcímeket!
08_ora.qxd 8/3/2001 6:19 PM Page 119

8. ÓRA
Objektumok
Az objektumközpontú programozás veszélyes. Megváltoztatja a programozásról való
gondolkodásmódunkat és ha egyszer a hatalmába kerít, nem tudunk tõle szabadul-
ni. A PHP a Perlhöz hasonlóan fokozatosan építette be az objektumközpontúságot
a nyelvtanba. A PHP 4-es változatának megjelenésével képessé váltunk arra, hogy
programjainkat teljes mértékben objektumközpontú szemléletmódban írjuk.

Ebben az órában a PHP 4-es változatának objektumközpontú tulajdonságaival


foglalkozunk és azokat valós életbõl vett példákra alkalmazzuk. Az órában
a következõket tanuljuk meg:

• Mik az osztályok és objektumok?

• Hogyan lehet osztályokat és objektumpéldányokat létrehozni?

• Hogyan lehet tagfüggvényeket és tulajdonságokat létrehozni és elérni?

• Hogyan lehet olyan osztályt létrehozni, mely más osztály leszármazottja?

• Miért jó az objektumközpontú programozás és hogyan segíti munkánk


szervezését?
08_ora.qxd 8/3/2001 6:19 PM Page 120

120 8. óra

Mit nevezünk objektumnak?


Az objektum változók és függvények egybezárt csomagja, amely egy különleges
sablonból jön létre. Az objektum belsõ mûködése nagy részét elrejti az objektumot
használó elõl, úgy, hogy egyszerû hozzáférési felületet biztosít, melyen keresztül
kéréseket küldhetünk és információt kaphatunk. A felület különleges függvények-
bõl, úgynevezett tagfüggvényekbõl (metódusokból) áll. A tagfüggvények mind-
egyike hozzáférhet bizonyos változókhoz, amelyeket tulajdonságoknak nevezünk.

A típus jellegzetességeit objektumtípusok (osztályok, class) létrehozásával határoz-


zuk meg. Objektumpéldányok (vagy röviden objektumok) létrehozásával pedig
egyedeket hozunk létre. Ezen egyedek rendelkeznek a típusuknak megfelelõ jel-
lemzõkkel, de természetesen a jellemzõk értéke más és más lehet. Például ha lét-
rehozunk egy gepkocsi osztályt, akkor az osztálynak lehet egy jellemzõje,
amelynek a szin nevet adjuk. Az objektumpéldányokban a szin tulajdonság ér-
téke lehet például "kék" vagy "zöld".

Az osztály tagfüggvények és tulajdonságok együttese. Az osztályokat a class


kulcsszó segítségével hozhatjuk létre. Az osztályok sablonok, amelyekbõl
objektumokat állíthatunk elõ.

Az objektum az osztály egy példánya, vagyis egy objektum nem más,


ÚJDONSÁG
mint az osztályban rögzített mûködési szabályok megtestesülése.
Egy adott típusú objektum a new kulcsszó után írt objektumtípus nevének
segítségével testesíthetõ meg. Amikor egy objektumpéldány létrejön, összes
tulajdonsága és tagfüggvénye elérhetõvé válik.

Az objektumközpontú program legnagyobb elõnye valószínûleg a kód újrahasz-


nosíthatósága. Mivel az osztályokat egységbezárt objektumok létrehozására hasz-
náljuk, egyszerûen vihetõk át egyik projektbõl a másikba, ráadásul lehetõség van
arra is, hogy gyermekosztályokat hozzunk létre, amelyek a szülõ tulajdonságait
öröklik és képesek azt kiegészíteni vagy módosítani. E módszer segítségével
rengeteg összetett vagy egyedi tulajdonsággal rendelkezõ objektumot, vagyis
objektumcsaládot lehet létrehozni, amelyek egy alaposztályra épülnek, de közben
egyéni tulajdonságokkal is rendelkeznek, egyedi tagfüggvényeket is biztosítanak.

Az objektumközpontú programozás bemutatásának talán legjobb módja,


ha a bemutatott példák alapján kísérletezgetünk.
08_ora.qxd 8/3/2001 6:19 PM Page 121

Objektumok 121

Objektum létrehozása
Ahhoz, hogy létre tudjunk hozni egy objektumot, elõször létre kell hozni
a sablont, amelyre épül. Ezt a sablont hívjuk osztálynak. A PHP 4-es változatában
ilyen sablont a class kulcsszóval hozhatunk létre:

class elso_osztaly
{
// ez egy nagyon buta osztály
}

Az elso_osztaly a minta, amely alapján tetszõleges számú elso_osztaly


típusú objektumot hozhatunk létre. Objektumot létrehozni a new kulcsszó segít-
ségével lehet:

$obj1 = new elso_osztaly();


$obj2 = new elso_osztaly();
print "\$obj1 " . gettype($obj1) . " típusú<br>";
print "\$obj2 " . gettype($obj2) . " típusú<br>";

A PHP gettype() függvényével ellenõriztük, hogy az $obj1 és az $obj2


változókban valóban objektum van-e. A gettype() számára egy tetszõleges típusú
változót kell átadnunk, a függvény pedig egy karakterlánccal tér vissza, ami a válto-
zó típusát tartalmazza. Az elõzõ programrészletben a gettype() visszatérési érté-
ke "object", amit a print segítségével a böngészõ számára kiírtunk.

Meggyõzõdhettünk róla, hogy két objektumunk van. A példának elsõ ránézésre


túl sok hasznát még nem látjuk, de segítségével újabb nézõpontból vizsgálhatjuk
az osztályokat. Az osztályokra úgy tekinthetünk, mint öntõmintára: annyi objektu-
mot önthetünk a segítségével, amennyit csak szeretnénk. Adjunk néhány további
szolgáltatást az osztályhoz, hogy objektumaink kicsit érdekesebbek legyenek.

Objektumtulajdonságok
Az objektumok a tulajdonság néven említett különleges változók révén mûköd-
nek. Ezek az osztályban bárhol létrehozhatók, de az átláthatóság kedvéért
az osztálymeghatározás elejére célszerû kigyûjteni azokat, így mi is ezt tesszük.
A tulajdonságok lehetnek értékek, tömbök, de más objektumok is:

class elso_osztaly
{
var $nev = "Gizike"; 8
}
08_ora.qxd 8/3/2001 6:19 PM Page 122

122 8. óra

Figyeljük meg, hogy a változót a var kulcsszó segítségével hoztuk létre; ha ezt egy
osztályon belül nem írjuk ki, értelmezési hibát (parse error) kapunk. Most, hogy ezt
a változót létrehoztuk, minden elso_osztaly típusú objektumnak lesz egy nev
tulajdonsága, melynek "Gizike" lesz a kezdeti értéke. Ehhez a tulajdonsághoz az
objektumon kívülrõl is hozzá lehet férni, sõt meg is lehet változtatni:

class elso_osztaly
{
var $nev = "Gizike";
}
$obj1 = new elso_osztaly();
$obj2 = new elso_osztaly();
$obj1->nev = "Bonifác";
print "$obj1->nev<br>";
print "$obj1->nev<br>";

A -> mûveletjel teszi lehetõvé, hogy egy objektum tulajdonságait elérhessük vagy
módosíthassuk. Bár az $obj1 és az $obj2 objektumokat "Gizike" névvel
hoztuk létre, rábírtuk az $obj2 objektumot, hogy meggondolja magát, a nev
tulajdonsághoz a "Bonifác" értéket rendelve, mielõtt a -> jelet ismét használva
kiítuk volna mindkét objektum nev tulajdonságának értékét.

Az objektumközpontú nyelvek, mint a Java, megkívánják, hogy


a programozó beállítsa a tulajdonságok és tagfüggvények bizton-
sági szintjét. Ez azt jelenti, hogy a hozzáférés úgy korlátozható,
hogy csak bizonyos, az objektumot kezelõ magas szintû függvé-
nyek legyenek elérhetõk, a belsõ használatra szánt tulajdonságok,
tagfüggvények pedig biztonságosan elrejthetõk. A PHP-nek nincs
ilyen védelmi rendszere. Az objektum összes tulajdonsága elérhe-
tõ, ami problémákat okozhat, ha a tulajdonságot (kívülrõl) nem
lenne szabad megváltoztatni.

Az objektumot adattárolásra is használhatjuk, de az objektumok többre képesek,


mint egy egyszerû asszociatív tömb utánzása. A következõ részben áttekintjük
az objektumok tagfüggvényeit, amelyek segítségével objektumaink életre kelnek.

Az objektumok tagfüggvényei
A tagfüggvény olyan függvény, amelyet egy osztályon belül hozunk létre. Minden
objektumpéldány képes meghívni osztálya tagfüggvényeit. A 8.1. példaprogram
az elso_osztaly nevû osztályt egy tagfüggvénnyel egészíti ki.
08_ora.qxd 8/3/2001 6:19 PM Page 123

Objektumok 123

8.1. program Egy osztály tagfüggvénnyel


1: <html>
2: <head>
3: <title>8.1. program Egy osztály
tagfüggvénnyel</title>
4: <body>
5: <?php
6: class elso_osztaly
7: {
8: var $nev;
9: function koszon()
10: {
11: print "Üdvözlöm!";
12: }
13: }
14: $obj1 = new elso_osztaly();
15: $obj1->koszon(); // kiírja, hogy "Üdvözlöm!"
16: ?>
17: </body>
18: </html>

Amint látjuk, a tagfüggvény a szokványos függvényekhez nagyon hasonlóan


viselkedik. A különbség csak annyi, hogy a tagfüggvényt mindig osztályon belül
hozzuk létre. Az objektumok tagfüggvényeit a -> mûveletjel segítségével hívhat-
juk meg. Fontos, hogy a tagfüggvények hozzáférnek az objektum változóihoz.
Már láttuk, hogyan lehet egy objektumtulajdonságot az objektumon kívülrõl
elérni, de hogyan hivatkozhat egy objektum saját magára? Lássuk a 8.2. példa-
programot:

8.2. program Tulajdonság elérése tagfüggvénybõl


1: <html>
2: <head>
3: <title>8.2. program Tulajdonság elérése
tagfüggvénybõl</title>
4: <body>
5: <?php
6: class elso_osztaly
7: {
8:
9:
var $nev = "Krisztián";
function koszon()
8
08_ora.qxd 8/3/2001 6:19 PM Page 124

124 8. óra

8.2. program (folytatás)


10: {
11: print"Üdvözlöm! $this->nev vagyok.<BR>";
12: }
13: }
14:
15: $obj1 = new elso_osztaly();
16: $obj1->koszon(); // kiírja, hogy "Üdvözlöm! Krisztián
vagyok."
17: ?>
18: </body>
19: </html>

Az osztálynak van egy különleges változója, a $this, ami az objektumpéldányra


mutat. Tekinthetjük személyes névmásnak. Bár programunkban az objektumra
hivatkozhatunk azzal a változóval, amihez hozzárendeltük (például $obj1),
az objektumnak hivatkoznia kell saját magára, erre jó a $this változó. A $this
változó és a -> mûveletjel segítségével az osztályon belülrõl az osztály minden
tulajdonságát és tagfüggvényét elérhetjük.

Képzeljük el, hogy minden egyes elso_osztaly típusú objektumhoz más és


más nev tulajdonságot szeretnénk rendelni. Ezt megtehetnénk „kézzel”, az objek-
tum nev tulajdonságát megváltoztatva, de létrehozhatunk egy tagfüggvényt is,
ami ezt teszi. Az utóbbi megoldást láthatjuk a 8.3. példaprogramban.

8.3. program Tulajdonság értékének módosítása tagfüggvényen belülrõl


1: <html>
2: <head>
3: <title>8.3. program Tulajdonság értékének módosítása
tagfüggvényen belülrõl</title>
4: </head>
5: <body>
6: <?php
7: class elso_osztaly
8: {
9: var $nev = "Krisztián";
10: function atkeresztel( $n )
11: {
12: $this->nev = $n;
13: }
08_ora.qxd 8/3/2001 6:19 PM Page 125

Objektumok 125

8.3. program (folytatás)


14: function koszon()
15: {
16: print"Üdvözlöm! $this->nev vagyok.<BR>";
17: }
18: }
19:
20: $obj1 = new elso_osztaly();
21: $obj1->atkeresztel("Aladár");
22: $obj1->koszon(); // kiírja, hogy "Üdvözlöm! Aladár
vagyok."
23: ?>
24: </body>
25: </html>

Az objektum nev tulajdonsága a létrehozáskor még "Krisztián" volt, de aztán


meghívtuk az objektum atkeresztel() tagfüggvényét, ami "Aladár" értékre
változtatta azt. Láthatjuk, hogy az objektum képes saját tulajdonságait módosítani.
Figyeljük meg, hogy a tagfüggvénynek a hagyományos függvényekhez hasonlóan
adhatunk át paramétereket.

Még mindig van egy fogás, amit nem ismertünk meg. Ha egy metódusnak éppen
azt a nevet adjuk, mint az osztálynak (az elõzõ példában ez az elso_osztaly),
akkor a metódus automatikusan meghívódik, amikor egy új objektumpéldány
létrejön. E módszer segítségével már születésükkor testreszabhatjuk objektuma-
inkat. A létrejövõ példány az ezen függvénynek átadott paraméterek vagy más
tényezõk alapján hozhatja magát alapállapotba. Ezeket a különleges metódusokat
konstruktoroknak (létrehozó függvényeknek) hívjuk. A 8.4. példaprogramban
az elso_osztaly objektumtípus konstruktorral kiegészített változatát láthatjuk.

8.4. program Konstruktorral rendelkezõ osztály


1: <html>
2: <head>
3: <title>8.4. program Konstruktorral rendelkezõ
osztály</title>
4: </head>
5: <body>
6: <?php
8
08_ora.qxd 8/3/2001 6:19 PM Page 126

126 8. óra

8.4. program (folytatás)


7: class elso_osztaly
8: {
9: var $nev;
10: function elso_osztaly( $n="Anonymous" )
11: {
12: $this->nev = $n;
13: }
14: function koszon()
15: {
16: print"Üdvözlöm! $this->nev vagyok.<BR>";
17: }
18: }
19:
20: $obj1 = new elso_osztaly("Krisztián");
21: $obj2 = new elso_osztaly("Aladár");
22: $obj1->koszon(); // kiírja, hogy "Üdvözlöm! Krisztián
vagyok."
23: $obj2->koszon(); // kiírja, hogy "Üdvözlöm! Aladár
vagyok."
24: ?>
25: </body>
26: </html>

Amikor egy elso_osztaly típusú objektumot létrehozunk, az elso_osztaly()


konstruktor automatikusan meghívásra kerül. Ha az objektum létrehozásakor nem
adunk meg nevet, a paraméter értéke "anonymus" lesz.

Egy bonyolultabb példa


Most készítsünk együtt egy kicsit bonyolultabb és hasznosabb programot: egy
táblázat osztályt hozunk létre, amelyben az egyes oszlopokat nevük alapján is
elérhetjük. Az adatszerkezet soralapú lesz, a böngészõben való megjelenítést
pedig egy butácska függvényre bízzuk. A táblázat takaros formázása a probléma
megoldásának ebben a fázisában nem szükséges.

Az osztály tulajdonságai
Elõször is el kell döntenünk, hogy milyen tulajdonságokat tároljunk az objektumban.
Az oszlopok neveit egy tömbben tároljuk, a sorokat pedig egy kétdimenziós tömb-
ben. A táblázat oszlopainak számát külön, egy egész típusú változóba helyezzük.
08_ora.qxd 8/3/2001 6:19 PM Page 127

Objektumok 127

class Tablazat
{
var $tablazatSorok = array();
var $oszlopNevek = array();
var $oszlopszam;
}

A konstruktor
A táblázat létrehozásakor a programnak már tudnia kell, mik lesznek a feldolgo-
zandó oszlopok nevei. Ez az információ az objektumhoz a konstruktor egy karak-
terlánc típusú tömbparamétere segítségével fog eljutni. Ha az oszlopok neveit
a konstruktor már ismeri, könnyûszerrel meghatározhatja az oszlopok számát és
beírhatja az $oszlopszam tulajdonságba:

function Tablazat( $oszlopNevek )


{
$this->oszlopNevek = $oszlopNevek;
$this->oszlopszam = count ( $oszlopNevek );
}

Ha feltesszük, hogy a konstruktor számára helyes információt adtunk át, az objektum


már tudni fogja oszlopainak számát és nevét. Mivel ez az információ tulajdonságok-
ban (mezõkben) tárolódik, minden tagfüggvény számára hozzáférhetõ.

Az ujSor() tagfüggvény
A Tablazat osztály a sorokat tömbök formájában kapja meg. Ez persze csak
akkor mûködik helyesen, ha a tömbben és a fejlécben az oszlopok sorrendje
azonos:

function ujSor( $sor )


{
if ( count ($sor) != $this->oszlopszam )
return false;
array_push($this->tablazatSorok, $sor);
return true;
}

Az ujSor() tagfüggvény egy tömböt vár, amit a $sor nevû változóban kap meg.
A táblázat oszlopainak számát már az $oszlopszam tulajdonságba helyeztük,
így most a count() függvénnyel ellenõrizhetjük, hogy a kapott $sor paraméter
megfelelõ számú oszlopot tartalmaz-e. Ha nem, akkor a függvény false értéket 8
ad vissza.
08_ora.qxd 8/3/2001 6:19 PM Page 128

128 8. óra

A PHP 4-es változatának array_push() függvénye segítségével az új sort


a $tablazatSor tömb végéhez fûzhetjük. Az array_push() két paramétert vár:
a tömböt, amihez az új elemet hozzá kell adni, illetve a hozzáadandó elemet.
Ha a második paraméter maga is egy tömb, akkor az egy elemként adódik az elsõ
tömbhöz, így többdimenziós tömb jön létre. Ezen eljárás segítségével tehát többdi-
menziós tömböket is létrehozhatunk.

Az ujNevesSor() tagfüggvény
Az ujSor() tagfüggvény csak akkor használható kényelmesen, ha a tömbként
átadott paraméterben az elemek sorrendje megfelelõ. Az ujNevesSor()
tagfüggvény ennél több szabadságot ad. A metódus egy asszociatív tömböt vár,
ahol az egyes elemek kulcsa az oszlopok neve. Ha olyan kulcsú elem kerül
a paraméterbe, amely a Tablazat objektum $oszlopNevek tulajdonságában nem
szerepel, az adott elem egyszerûen nem kerül bele a táblázatba. Ha egy oszlopnév
nem jelenik meg a paraméterben kulcsként, akkor az adott oszlopba egy üres
karakterlánc kerül.

function ujNevesSor( $asszoc_sor )


{
if ( count ($asszoc_sor) != $this->oszlopszam )
return false;
$sor = array();
foreach ( $this->oszlopNevek as $oszlopNev )
{
if ( ! isset( $asszoc_sor[$oszlopNev] ))
$asszoc_sor[$oszlopNev] = "";
$sor[] = $asszoc_sor[$oszlopNev];
}
array_push($this->tablazatSorok, $sor);
}

Az ujNevesSor()-nak átadott asszociatív tömb az $asszoc_sor nevû változóba


kerül. Elõször létrehozunk egy üres $sor tömböt, amely majd a táblázatba beillesz-
tendõ sort tartalmazza, az elemek helyes sorrendjével. Majd végigvesszük
az $oszlopNevek tömb elemeit, és megnézzük, hogy a tömbben kaptunk-e ilyen
kulcsú elemet az $asszoc_sor paraméterben. Ehhez a PHP 4-es isset()
függvényét használjuk, amely egy változót vár. Ha a változóhoz már rendeltünk
értéket, a függvény visszatérési értéke true, egyébként false lesz. A függvénynek
az $asszoc_sor tömb azon elemét kell átadnunk, melynek kulcsa megegyezik
a következõ oszlop nevével. Ha nem létezik ilyen elem az $asszoc_sor tömbben,
létrehozunk egy ilyet és üres karakterláncot írunk bele. Most már folytathatjuk
a végleges $sor tömb felépítését és hozzáadhatjuk az $asszoc_sor megfelelõ
elemét, hiszen épp az imént biztosítottuk, hogy az elem létezik. Mire befejezzük
08_ora.qxd 8/3/2001 6:19 PM Page 129

Objektumok 129

az $oszlopNevek tömb bejárását, a $sor tömb már tartalmazni fogja


az $asszoc_sor tömbben átadott elemeket, mégpedig a megfelelõ sorrendben,
a nem meghatározott értékeket üres karakterláncokkal kitöltve.

Most már van két tagfüggvényünk, amelyek segítségével sorokat adhatunk


a Tablazat típusú objektumok $tablazatSorok nevû mezõjéhez. Errõl azon-
ban jó lenne valahogy meggyõzõdni: hiányzik még egy olyan tagfüggvény, amely
képes megjeleníteni a táblázatot.

A kiir() tagfüggvény
A kiir() tagfüggvény kiírja a böngészõbe a táblázat fejlécét és
a $tablazatSorok tömböt. A függvény csak nyomkövetési célokat szolgál.
Az óra késõbbi részében egy sokkal szebb megoldást fogunk látni.

function kiir()
{
print "<pre>";
foreach ( $this->oszlopNevek as $oszlopNev )
print "<B>$oszlopNev</B> ";
print "\n";
foreach ( $this->tablazatSorok as $y )
{
foreach ( $y as $xcella )
print "$xcella ";
print "\n";
}
print "</pre>";
}

A program magáért beszél. Elõször az $oszlopNevek elemeit írjuk ki, majd


a $tablazatSorok sorait. Mivel a $tablazatSorok tulajdonság kétdimenziós
tömb, vagyis a tömb minden eleme maga is egy tömb, kettõs ciklust kell használ-
nunk.

Összeáll a kép
A 8.5. példaprogram eddigi munkánk gyümölcsét, a Tablazat osztályt tartalmazza,
majd a program végén létrehoz egy Tablazat típusú objektumot és meghívja
valamennyi tagfüggvényét.

8
08_ora.qxd 8/3/2001 6:19 PM Page 130

130 8. óra

8.5. program A Tablazat osztály


1: <html>
2: <head>
3: <title>8.5. program A Tablazat osztály</title>
4: </head>
5: <body>
6: <?php
7: class Tablazat
8: {
9: var $tablazatSorok = array();
10: var $oszlopNevek = array();
11: var $oszlopszam;
12: function Tablazat( $oszlopNevek )
13: {
14: $this->oszlopNevek = $oszlopNevek;
15: $this->oszlopszam = count ( $oszlopNevek );
16: }
17:
18: function ujSor( $sor )
19: {
20: if ( count ($sor) != $this->oszlopszam )
21: return false;
22: array_push($this->tablazatSorok, $sor);
23: return true;
24: }
25:
26: function ujNevesSor( $asszoc_sor )
27: {
28: if ( count ($asszoc_sor) != $this->oszlopszam )
29: return false;
30: $sor = array();
31: foreach ( $this->oszlopNevek as $oszlopNev )
32: {
33: if ( ! isset( $asszoc_sor[$oszlopNev] ))
34: $asszoc_sor[$oszlopNev] = "";
35: $sor[] = $asszoc_sor[$oszlopNev];
36: }
37: array_push($this->tablazatSorok, $sor);
38: }
39:
08_ora.qxd 8/3/2001 6:19 PM Page 131

Objektumok 131
8.5. program (folytatás)
40: function kiir()
41: {
42: print "<pre>";
43: foreach ( $this->oszlopNevek as $oszlopNev )
44: print "<B>$oszlopNev</B> ";
45: print "\n";
46: foreach ( $this->tablazatSorok as $y )
47: {
48: foreach ( $y as $xcella )
49: print "$xcella ";
50: print "\n";
51: }
52: print "</pre>";
53: }
54: }
55:
56: $proba = new Tablazat( array("a","b","c"));
57: $proba->ujSor( array(1,2,3));
58: $proba->ujSor( array(4,5,6));
59: $proba->ujNevesSor( array ( "b"=>0, "a"=>6, "c"=>3 ));
60: $proba->kiir();
61: ?>
62: </body>
63: </html>

A 8.5. példaprogram kimenetét a 8.1. ábrán láthatjuk.

8.1. ábra
Egy Tablazat típusú
objektum kimenete

8
08_ora.qxd 8/3/2001 6:19 PM Page 132

132 8. óra

A kimenet csak akkor jelenik meg helyesen, ha az egy oszlopban levõ elemek
egyforma hosszúak.

Ami még hiányzik...


Bár az osztály hatékonyan elvégzi a munkát, amit neki szántunk, ha több idõnk és
helyünk lenne, kibõvíthetnénk néhány további szolgáltatással és adatvédelmi
lehetõséggel.

Mivel a PHP gyengén típusos nyelv, a mi felelõsségünk megbizonyosodni arról,


hogy a tagfüggvényeknek átadott paraméterek a megfelelõ típusúak-e. Ehhez
a tizenhatodik, az adatkezelésrõl szóló fejezetben tárgyalt függvényeket használ-
hatjuk. Ezen kívül írhatnánk tagfüggvényeket a táblázat bármely oszlop szerinti
rendezésére is.

Miért használjunk osztályt?


Miért jobb osztályt használni erre a célra ahelyett, hogy egyszerûen írnánk néhány
tömbkezelõ függvényt? Vagy miért ne írhatnánk bele egyszerûen a programba
a tömbkezelést? Azért, mert ez nem lenne hatékony, mert így az elvont adatok
tárolását végzõ programokba valami egészen más is bekerülne. De vajon miért
okoz ez nekünk problémát?

Elõször is a kódot újra fel lehet használni. Ennek célja jól meghatározott: bizonyos
általános adatkezelést tesz lehetõvé, amelyet ezután beilleszthetünk bármely prog-
ramba, melynek arra van szüksége, hogy ilyen típusú adatokat kezeljen és kiírjon.

Másodszor, a Tablazat osztály tevékeny: megkérhetjük arra, hogy adatokat írjon ki,
anélkül, hogy bajlódnunk kellene azzal, hogy végigjárjuk a $tablazatSorok
elemeit.

Harmadszor, az objektumba egy felületet is beépítettünk. Ha elhatározzuk, hogy


késõbb javítunk az osztály mûködésén, anélkül tehetjük meg, hogy a program
többi részét módosítanánk, ha a korábban létrehozott tagfüggvények kívülrõl
ugyanúgy viselkednek.

Végül, létrehozhatunk újabb osztályokat is, amelyek már korábban létrehozott


osztályoktól örökölnek, kiterjeszthetik vagy módosíthatják a már meglévõ tagfügg-
vényeket. Ez teszi igazán hatékonnyá az objektumközpontú programozást,
melynek kulcsszavai az egységbezárás, az öröklés és a kód-újrahasznosítás.
08_ora.qxd 8/3/2001 6:19 PM Page 133

Objektumok 133

Öröklés
Ahhoz, hogy olyan osztályt hozzunk létre, amely szolgáltatásait szülõjétõl örökli,
egy kicsit módosítanunk kell az osztály meghatározását. A 8.6. példaprogram
ismét a fejezet elsõ felében levõ témakörbõl mutat egy példát.

8.6. program Másik osztálytól öröklõ osztály


1: <html>
2: <head>
3: <title>8.6. program Másik osztálytól öröklõ osztály
</title>
4: </head>
5: <body>
6: <?php
7: class elso_osztaly
8: {
9: var $nev = "Krisztián";
10: function elso_osztaly( $n )
11: {
12: $this->nev = $n;
13: }
14: function koszon()
15: {
16: print "Üdvözlöm! $this->nev vagyok.<BR>";
17: }
18: }
19:
20: class masodik_osztaly extends elso_osztaly
21: {
22:
23: }
24:
25: $proba = new masodik_osztaly("Krisztián fia");
26: $proba->koszon(); // kiírja, hogy "Üdvözlöm! Krisztián
fia vagyok."
27: ?>
28: </body>
29: </html>

8
08_ora.qxd 8/3/2001 6:19 PM Page 134

134 8. óra

Figyeljük meg, hogyan származtattunk az elso_osztaly-tól egy új osztályt!


Az extends kulcsszót az osztály meghatározásában kell használnunk. Ezzel
azt adjuk meg, hogy a kulcsszó után meghatározott osztály minden tulajdonságát
és tagfüggvényét örökölni szeretnénk. Az összes masodik_osztaly típusú
objektum rendelkezni fog egy koszon() nevû tagfüggvénnyel és egy $nev nevû
tulajdonsággal, mint ahogyan minden elso_osztaly típusú objektum is rendel-
kezik ezekkel.

Ha ez nem lenne elég, nézzük tovább a 8.6. példaprogramot és keressünk szokat-


lan dolgokat! Például figyeljük meg, hogy még konstruktort sem adtunk meg
a masodik_osztaly osztálynak. Akkor hogy lehet az, hogy az objektum $nev
tulajdonsága az alapértelmezett "Krisztián" karakterláncról arra a "Kriszti-
án fia" karakterláncra változott, amit a konstruktor létrehozásakor átadtunk?
Mivel nem hoztunk létre új konstruktort, a szülõ objektumtípus (elso_osztaly)
konstruktora hívódott meg.

Ha egy osztályból egy másikat származtatunk, amelynek nincsen


saját konstruktora, akkor a szülõ osztály konstruktora hívódik
meg, amikor egy gyermekobjektumot hozunk létre. Ez a PHP 4-es
változatának újdonsága.

A szülõ tagfüggvényeinek felülírása


A masodik_osztaly típusú objektumok most pontosan úgy viselkednek, mint
az elso_osztaly típusúak. Az objektumközpontú világban a gyermek osztályban
felül lehet írni a szülõ osztály tagfüggvényeit, ezáltal lehetõvé válik, hogy a gyermek
objektumok bizonyos tagfüggvényei a szülõkétõl eltérõen viselkedjenek (többalakú-
ság, polimorfizmus), más tagfüggvények viszont érintetlenül hagyva ugyanúgy jelen-
jenek meg a gyermek osztályban. A 8.7. példában lecseréljük a masodik_osztaly
koszon() tagfüggvényét.

8.7. program Egy felülírt tagfüggvény


1: <html>
2: <head>
3: <title>8.7. program Egy felülírt tagfüggvény</title>
4: </head>
5: <body>
6: <?php
08_ora.qxd 8/3/2001 6:19 PM Page 135

Objektumok 135

8.7. program (folytatás)


7: class elso_osztaly
8: {
9: var $nev = "Krisztián";
10: function elso_osztaly( $n )
11: {
12: $this->nev = $n;
13: }
14: function koszon()
15: {
16: print "Üdvözlöm! $this->nev vagyok.<BR>";
17: }
18: }
19:
20: class masodik_osztaly extends elso_osztaly
21: {
22: function koszon()
23: {
24: print "Azért se mondom meg a nevem!<BR>";
25: }
26: }
27:
28: $proba = new masodik_osztaly("Krisztián fia");
29: $proba->koszon(); // kiírja, hogy "Azért se mondom
meg a nevem!"
30: ?>
31: </body>
32: </html>

A gyermek koszon() tagfüggvénye hívódik meg, mert elõnyt élvez a szülõ


hasonló nevû tagfüggvényével szemben.

A felülírt tagfüggvény meghívása


Elõfordulhat, hogy a szülõ osztály szolgáltatásait szeretnénk használni, de újakat is
be szeretnénk építeni. Az objektumközpontú programozásban ez megvalósítható.
A 8.8. példaprogramban a masodik_osztaly koszon() tagfüggvénye
meghívja az elso_osztaly tagfüggvényét, amelyet éppen felülír.

8
08_ora.qxd 8/3/2001 6:19 PM Page 136

136 8. óra

8.8. program Felülírt tagfüggvény meghívása


1: <html>
2: <head>
3: <title>8.8. program Felülírt tagfüggvény
meghívása</title>
4: </head>
5: <body>
6: <?php
7: class elso_osztaly
8: {
9: var $nev = "Krisztián";
10: function elso_osztaly( $n )
11: {
12: $this->nev = $n;
13: }
14: function koszon()
15: {
16: print "Üdvözlöm! $this->nev vagyok.<BR>";
17: }
18: }
19:
20: class masodik_osztaly extends elso_osztaly
21: {
22: function koszon()
23: {
24: print "Azért se mondom meg a nevem! - ";
25: elso_osztaly::koszon();
26: }
27: }
28:
29: $proba = new masodik_osztaly("Krisztián fia");
30: $proba->koszon(); // kiírja, hogy "Azért se mondom
meg a nevem! - Üdvözlöm! Krisztián fia vagyok."
31: ?>
32: </body>
33: </html>
A

szuloOsztalyNeve::tagfuggvenyNeve()

sémát használva bármely felülírt tagfüggvényt meghívhatunk. A séma új, a PHP 3-as
változatában még hibát okozott volna.
08_ora.qxd 8/3/2001 6:19 PM Page 137

Objektumok 137

Egy példa az öröklésre


Már láttuk, hogyan tud egy osztály egy másiktól örökölni, annak tagfüggvényeit
felülírni és képességeit kibõvíteni. Most a tanultaknak hasznát is vehetjük. Készít-
sünk egy osztályt, amely a 8.5. példaprogramban szereplõ Tablazat osztálytól
örököl! Az új osztály neve HTMLTablazat lesz. Ezt az osztály azért szükséges,
hogy kiküszöbölje a Tablazat kiir() tagfüggvénynek szépséghibáit és a bön-
gészõ lehetõségeit kihasználva szép kimenetet eredményezzen.

A HTMLTablazat saját tulajdonságai


A HTMLTablazat arra szolgál, hogy a már korábban létrehozott Tablazat típu-
sú objektumot szabványos HTML formában jeleníthessük meg. Példánkban a táblá-
zat cellPadding és a cellák bgColor tulajdonságai módosíthatók, a valós prog-
ramokban azonban természetesen több tulajdonságot szeretnénk majd beállítani.

class HTMLTablazat extends Tablazat


{
var $hatterSzin;
var $cellaMargo = 2;
}

Egy új osztályt hoztunk létre, amely a Tablazat osztálytól fog örökölni. Két új
tulajdonságot adtunk meg, az egyiknek a kezdõértékét is meghatároztuk.

A konstruktor
Már láthattuk, hogy a szülõ konstruktora hívódik meg, ha a gyermekosztályban
nem hozunk létre konstruktort. Most azonban azt szeretnénk, hogy konstruktorunk
többre legyen képes, mint amennyit a Tablazat osztály konstruktora tett, ezért
azt felül kell írnunk.

function HTMLTablazat( $oszlopNevek, $hatter="#ffffff" )


{
Tablazat::Tablazat($oszlopNevek);
$this->hatterSzin=$hatter;
}

A HTMLTablazat paramétereiben az oszlopok neveinek tömbjét, illetve egy ka-


rakterláncot vár. A karakterlánc lesz a HTML táblázat bgColor tulajdonsága. Meg-
adtunk egy kezdeti értéket is, így ha nem adunk át második paramétert
a konstruktornak, a háttér színe fehér lesz. A konstruktor meghívja a Tablazat
osztály konstruktorát a kapott oszlopnév-tömbbel. A lustaság erény a programozás 8
terén: hagyjuk, hogy a Tablazat konstruktora tegye a dolgát és a továbbiakban
08_ora.qxd 8/3/2001 6:19 PM Page 138

138 8. óra

nem foglalkozunk a táblázat kezelésével (ha egyszer már megírtuk, akkor használ-
juk is…). A konstruktor másik dolga a HTMLTablazat hatterSzin tulajdonsá-
gának beállítása.

Ha a gyermek osztály rendelkezik konstruktorral, akkor a szülõ


osztály konstruktora már nem kerül automatikusan meghívásra.
Ezért ha szükséges, a gyermek osztályból kell meghívni a szülõ
konstruktorát.

A cellaMargoAllit() tagfüggvény
A származtatott osztály saját, új tagfüggvényeket is létrehozhat.
A cellaMargoAllit() tagfüggvény segítségével a felhasználó a táblázat
szövege és a táblázat közötti üres rés nagyságát állíthatja be. Persze megtehetné
ezt a cellaMargo tulajdonság közvetlen elérésével is ,de ez nem túl jó ötlet.
Alapszabály, hogy az objektumot használó személy érdekében legjobb tagfügg-
vényeket létrehozni erre a célra. Az osztályok bonyolultabb leszármazottaiban
a cellaMargoAllit() tagfüggvény esetleg más tulajdonságokat is kénytelen
módosítani, hogy megváltoztathassa a margó méretét. Sajnos nincs elegáns mód
ennek a kikényszerítésére.

function cellaMargoAllit( $margo )


{
$this->cellaMargo = $margo;
}

A kiir() tagfüggvény
A kiir() tagfüggvény felülírja a Tablazat osztály azonos nevû tagfüggvényét.
Ez a függvény a szülõ osztály logikájával azonos módon írja ki a táblázatot, de
a HTML table elemét használja a táblázat formázására.

function kiir()
{
print "<table cellPadding=\"$this->cellaMargo\"
border=1>\n";
print "<tr>\n";
foreach ( $this->oszlopNevek as $oszlopNev )
print "<th bgColor=\"$this
->hatterSzin\”>$oszlopNev</th>”;
print "</tr>\n";
08_ora.qxd 8/3/2001 6:19 PM Page 139

Objektumok 139

foreach ( $this->tablazatSorok as $sor => $cellak )


{
print "<tr>\n";
foreach ( $cellak as $cella )
print "<td bgColor=\"$this
->hatterSzin\">$cella</td>\n";
print "</tr>\n";
}
print "</table>";
}

Ha a Tablazat osztálybeli változat világos, az itteni kiir() tagfüggvény is elég


áttekinthetõ kell, hogy legyen. Elõször az $oszlopNevek elemeit írjuk ki, majd
a $tablazatSorok sorait. A formázást a HTML table elemének cellPadding
és bgColor tulajdonságai segítségével szabályozhatjuk.

A Tablazat és a HTMLTablazat osztályok


a maguk teljességében
A 8.9. példaprogramban a Tablazat és a HTMLTablazat példákat egy helyen
láthatjuk. Létrehozunk egy HTMLTablazat típusú objektumot, megváltoztatjuk
cellaMargo tulajdonságát, írunk bele néhány sort, majd meghívjuk a kiir()
tagfüggvényt. A valóságban az adatok minden bizonnyal közvetlenül egy adat-
bázisból származnának.

8.9. program A Tablazat és a HTMLTablazat osztályok


1: <html>
2: <head>
3: <title>8.9. program A Tablazat és a HTMLTablazat
osztályok</title>
4: </head>
5: <body>
6: <?php
7: class Tablazat
8: {
9: var $tablazatSorok = array();
10: var $oszlopNevek = array();
11: var $oszlopszam;

8
08_ora.qxd 8/3/2001 6:19 PM Page 140

140 8. óra

8.9. program (folytatás)


12: function Tablazat( $oszlopNevek )
13: {
14: $this->oszlopNevek = $oszlopNevek;
15: $this->oszlopszam = count ( $oszlopNevek );
16: }
17:
18: function ujSor( $sor )
19: {
20: if ( count ($sor) != $this->oszlopszam )
21: return false;
22: array_push($this->tablazatSorok, $sor);
23: return true;
24: }
25:
26: function ujNevesSor( $asszoc_sor )
27: {
28: if ( count ($asszoc_sor) != $this->oszlopszam )
29: return false;
30: $sor = array();
31: foreach ( $this->oszlopNevek as $oszlopNev )
32: {
33: if ( ! isset( $asszoc_sor[$oszlopNev] ))
34: $asszoc_sor[$oszlopNev] = "";
35: $sor[] = $asszoc_sor[$oszlopNev];
36: }
37: array_push($this->tablazatSorok, $sor);
38: }
39:
40: function kiir()
41: {
42: print "<pre>";
43: foreach ( $this->oszlopNevek as $oszlopNev )
44: print "<B>$oszlopNev</B> ";
45: print "\n";
46: foreach ( $this->tablazatSorok as $y )
47: {
48: foreach ( $y as $xcella )
49: print "$xcella ";
50: print "\n";
51: }
08_ora.qxd 8/3/2001 6:19 PM Page 141

Objektumok 141

8.9. program (folytatás)


52: print "</pre>";
53: }
54: }
55:
56: class HTMLTablazat extends Tablazat
57: {
58: var $hatterSzin;
59: var $cellaMargo = 2;
60: function HTMLTablazat( $oszlopNevek,
$hatter="#ffffff" )
61: {
62: Tablazat::Tablazat($oszlopNevek);
63: $this->hatterSzin=$hatter;
64: }
65:
66: function cellaMargoAllit( $margo )
67: {
68: $this->cellaMargo = $margo;
69: }
70: function kiir()
71: {
72: print "<table cellPadding=\"$this->cellaMargo\"
border=1>\n";
73: print "<tr>\n";
74: foreach ( $this->oszlopNevek as $oszlopNev )
75: print "<th bgColor=\"$this->hatterSzin\"
>$oszlopNev</th>";
76: print "</tr>\n";
77: foreach ( $this->tablazatSorok as $sor => $cellak )
78: {
79: print "<tr>\n";
80: foreach ( $cellak as $cella )
81: print "<td bgColor=\"$this->hatterSzin\"
>$cella</td>\n";
82: print "</tr>\n";
83: }
84: print "</table>";
85: }
86: }
87: 8
08_ora.qxd 8/3/2001 6:19 PM Page 142

142 8. óra

8.9. program (folytatás)


88: $proba = new HTMLTablazat( array("a","b","c"),
"#00FF00");
89: $proba->cellaMargoAllit( 7 );
90: $proba->ujSor( array(1,2,3));
91: $proba->ujSor( array(4,5,6));
92: $proba->ujNevesSor( array ( "b"=>0, "a"=>6, "c"=>3 ));
93: $proba->kiir();
94: ?>
95: </body>
96: </html>
A 8.9. példaprogram kimenetét a 8.2. ábrán láthatjuk.

8.2. ábra
Egy HTMLTablazat
típusú objektum
kimenete

Miért alkalmazzunk öröklést?


Miért vágtuk ketté a feladatot egy Tablazat és egy HTMLTablazat részre?
Biztos, hogy idõt és fáradságot takaríthattunk volna meg, ha a HTML táblázat
képességeit beépítjük a Tablazat osztályba? A válasz kulcsa a rugalmasság
kérdése.

Képzeljük el, hogy egy ügyfél azt a megbízást adja nekünk, hogy hozzunk létre egy
osztályt, amely olyan táblázatok kezelésére képes, ahol a táblázat oszlopainak neve
van. Ha egyetlen részbõl álló osztályt hozunk létre, amelybe minden szolgáltatást
(a HTML megjelenítés minden apró részletével) beleépítünk, elsõ látásra minden
szépnek és jónak tûnhet. De ha visszajön az ügyfél, hogy szeretné, ha a program
ízlésesen formázott szöveges kimenetet eredményezne, valószínûleg újabb tagfügg-
vényeket kellene megpróbálnunk felvenni, melyek megoldják a problémát.
08_ora.qxd 8/3/2001 6:19 PM Page 143

Objektumok 143

Egy-két héten belül ügyfelünk ráébred, hogy szeretné a programot elektronikus


levelek küldésére használni és ha már úgyis fejlesztünk a programon, a cég belsõ
hálózata az XML nyelvet használja, nem lehetne beépíteni a támogatást ehhez is?
Ennél a pontnál, ha minden szolgáltatást egyetlen osztályba építünk bele, a prog-
ram kezd ormótlanul nagy lenni, esetleg a teljes átírását fontolgatjuk.

Játsszuk el ezt a forgatókönyvet a Tablazat és a HTMLTablazat osztályainkkal!


Alaposan sikerült elkülöníteni az adatok feldolgozását és megjelenítését. Ha ügyfe-
lünk azzal a kéréssel fordul hozzánk, hogy szeretné a táblázatot fájlba menteni,
csak egy új osztályt kell származtatnunk a Tablazat osztályból. Nevezzük ezt
TablazatFajl osztálynak. Eddigi osztályainkhoz hozzá sem kell nyúlnunk.
Ez igaz a TablazatLevel és az XMLTablazat osztályokra is. A 8.3. ábra
az osztályok közötti kapcsolatokat (függõségeket, leszármazásokat) mutatja.

8.3. ábra
Kapcsolatok
a Tablazat osztály és
gyermekei között

Sõt, tudjuk, hogy minden, a Tablazat osztályból származtatott osztálynak van


egy kiir() tagfüggvénye, így azokat egy tömbbe is gyûjthetjük. Azután végig-
szaladunk a tömbön, meghívjuk minden elem kiir() tagfüggvényét és nem kell
azzal foglalkoznunk, hogy az adott elem a Tablazat melyik leszármazottja,
a megfelelõ kiíró függvény kerül meghívásra. Egy egyszerû Tablazat osztályból
származtatott típusú objektumok tömbje segítségével elektronikus leveleket írha-
tunk, illetve HTML, XML vagy szöveges állományokat állíthatunk elõ a kiir()
függvény meghívásával.

Összefoglalás
Sajnos nincs rá mód, hogy az objektumközpontú programozást minden szempontból
megvizsgáljuk egy rövidke óra alatt, de remélem, hogy a fontosabb lehetõségeket
sikerült bemutatni.

Azt, hogy milyen mértékben használunk osztályokat a programokban, nekünk kell


eldöntenünk. Az objektumközpontú megközelítést intenzíven használó programok
általában némileg több erõforrást igényelnek, mint a hagyományosak, viszont
a rugalmasság és átláthatóság jelentõsen nõ. 8
08_ora.qxd 8/3/2001 6:19 PM Page 144

144 8. óra

Ebben az órában arról tanultunk, hogyan hozhatunk létre osztályokat és belõlük


objektumpéldányokat. Megtanultunk tulajdonságokat és tagfüggvényeket létre-
hozni és elérni. Végül azt is megtanultuk, hogyan hozhatunk létre új osztályokat
más osztályokból az öröklés és a tagfüggvény-felülírás segítségével.

Kérdések és válaszok
Ebben az órában néhány barátságtalan fogalommal találkoztunk. Való-
ban szükséges az objektumközpontúságot megérteni ahhoz, hogy jó
PHP programozó válhasson az emberbõl?
Erre a rövid válasz: nem. A legtöbb PHP programozó alig vagy egyáltalán nem ír
objektumközpontú programot. Az objektumközpontú megközelítés nem tesz
számunkra olyan dolgokat lehetõvé, amelyek eddig elérhetetlenek voltak. A dolog
lényege a programok szervezésében, az egyszer megírt programrészek újrahasz-
nosításában és a könnyû fejleszthetõségben rejlik. Még ha el is határoznánk, hogy
soha nem fogunk objektumközpontú programot írni, elõfordulhat, hogy bele kell
javítanunk mások által írt programokba, amelyekben osztályok vannak, ezért érte-
nünk kell a szemlélet alapjait. Ez az óra ebben is segítséget nyújthat.

Nem értem a $this változó szerepét.


Egy osztályon belül szükséges az osztály tagfüggvényeit vagy tulajdonságait elérni.
Ekkor a $this változót kell használni, amely egy mutató az adott objektumra,
amelynek valamely tagfüggvényét meghívtuk. Mivel a $this változó mutató
(hivatkozás), összetevõinek eléréséhez a -> mûveletjelet kell használni.

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. Hogyan hoznánk létre egy uresOsztaly nevû osztályt, amelynek nincsenek
tagfüggvényei és tulajdonságai?

2. Adott egy uresOsztaly nevû osztály. Hogyan hoznánk létre egy példányát?

3. Hogyan lehet az osztályba egy tulajdonságot felvenni?

4. Hogyan kell a konstruktor nevét megválasztani?

5. Hogyan lehet egy osztályban konstruktort létrehozni?


08_ora.qxd 8/3/2001 6:19 PM Page 145

Objektumok 145

6. Hogyan lehet létrehozni közönséges tagfüggvényeket?

7. Hogyan lehet osztályon belülrõl az osztály tulajdonságaihoz és tagfüggvénye-


ihez hozzáférni?

7. Hogyan lehet osztályon kívülrõl az osztály tulajdonságaihoz és tagfüggvénye-


ihez hozzáférni?

8. Mit kell tennünk, ha azt szeretnénk, hogy egy osztály más osztálytól
örököljön?

Feladatok
1. Hozzuk létre a Szamolo nevû osztályt, amely két egész számot tárol.
Írjunk hozzá egy kiszamol() nevû tagfüggvényt, amely kiírja a két számot
a böngészõbe!

2. Hozzuk létre az Osszead osztályt, amely a Szamolo osztálytól örököl.


Írjuk át ennek kiszamol() tagfüggvényét úgy, hogy az a két tulajdonság
összegét írja ki a böngészõbe!

3. Az elõzõ feladathoz hasonlóan módon készítsük el a Kivon osztályt!

8
08_ora.qxd 8/3/2001 6:19 PM Page 146
09_ora.qxd 8/3/2001 6:20 PM Page 147

III. RÉSZ
Munka a PHP-vel
9. óra Ûrlapok
10. óra Fájlok használata
11. óra A DBM függvények használata
12. óra Adatbázisok kezelése – MySQL
13. óra Kapcsolat a külvilággal
14. óra Dinamikus képek kezelése
15. óra Dátumok kezelése
16. óra Az adatok kezelése
17. óra Karakterláncok kezelése
18. óra A szabályos kifejezések használata
19. óra Állapotok tárolása sütikkel és GET típusú lekérdezésekkel
20. óra Állapotok tárolása munkamenet-függvényekkel
21. óra Munka kiszolgálói környezetben
22. óra Hibakeresés
09_ora.qxd 8/3/2001 6:20 PM Page 148
09_ora.qxd 8/3/2001 6:20 PM Page 149

9. ÓRA
Ûrlapok
A könyv eddigi példáiban egy nagyon fontos dolgot nem láttunk. Létrehoztunk
változókat és tömböket, készítettünk és meghívtunk különbözõ függvényeket,
különféle objektumokkal dolgoztunk, eddigi ismereteink azonban értelmetlenek,
amíg a felhasználó által megadott adatokat kezelni nem tudjuk. Ebben az órában
ezt a témakört tekintjük át.

A Világhálón alapvetõen a HTML ûrlapokon keresztül áramlik az információ


a felhasználó és a kiszolgáló között. A PHP-t úgy tervezték, hogy a kitöltött
HTML ûrlapokat könnyen fel tudja dolgozni.

Ebben az órában a következõket tanuljuk meg:

• Hogyan férjünk hozzá a környezeti változókhoz és hogyan használjuk azokat?

• Hogyan férjünk hozzá az ûrlapmezõkben megadott információkhoz?

• Hogyan dolgozzunk az ûrlapok több elem kiválasztását engedélyezõ elemeivel?


09_ora.qxd 8/3/2001 6:20 PM Page 150

150 9. óra

• Hogyan készítsünk olyan kódot, amely egyszerre tartalmazza a HTML ûrlapot


és az ezt kezelõ PHP programot?

• Hogyan mentsük az állapotot rejtett mezõkkel?

• Hogyan irányítsuk a felhasználót új oldalra?

• Hogyan készítsünk fájlfeltöltõ HTML ûrlapot és hogyan írjunk olyan PHP


programot, amely kezeli ezt?

Globális és környezeti változók


Mielõtt elkészítenénk elsõ igazi ûrlapunkat, kis kitérõt kell tennünk, hogy újra
áttekintsük a globális változókat. A globális változókkal elõször a függvényekrõl
szóló hatodik órában találkoztunk. A globális változók azok a változók, amelyeket
a program legfelsõ szintjén, azaz a függvényeken kívül vezettünk be. Minden
függvény számára elérhetõ a beépített $GLOBALS nevû tömb. A $GLOBALS tömb
használatát láthatjuk a 9.1. példában, amelyben egy ciklussal kiírjuk programunk
összes globális változóját.

9.1. program A $GLOBALS tömb elemeinek kiírása


1: <html>
2: <head>
3: <title>9.1. program A $GLOBALS tömb elemeinek
kiírása</title>
4: </head>
5: <body>
6: <?php
7: $user1 = "Judit";
8: $user2 = "István";
9: $user3 = "János";
10: foreach ( $GLOBALS as $kulcs=>$ertek )
11: {
12: print "\$GLOBALS[\"$kulcs\"] == $ertek<br>";
13: }
14: ?>
15: </body>
16: </html>
09_ora.qxd 8/3/2001 6:20 PM Page 151

Ûrlapok 151

Három változót vezettünk be és a $GLOBALS tömb elemein végiglépkedve kiírtuk


a változók neveit és értékeit a böngészõben. Láthatjuk az általunk megadott válto-
zókat, de a program ezeken kívül másokat is kiírt, a PHP ugyanis automatikusan 9
bevezet néhány globális változót, amelyek a kiszolgáló és az ügyfél környezetét
írják le. Ezeket a változókat környezeti változóknak nevezzük. A kiszolgálótól,
a rendszertõl és a beállításoktól függõen különféle környezeti változók létezhetnek,
ezek ismerete rendkívül fontos. A 9.1. táblázatban a leggyakoribb környezeti válto-
zókat soroltuk fel. A környezeti változók értéke közvetlenül vagy a $GLOBALS
tömb részeként érhetõ el.

9.1. táblázat Környezeti változók


Változó Tartalma Példa
$HTTP_USER_AGENT A böngészõ neve és Mozilla/4.6 (X11;I;
változatszáma Linux2.2.6-15apmac ppc)
$REMOTE_ADDR Az ügyfél IP címe 158.152.55.35
$REQUESTED_METHOD A kérelem módja POST
(GET vagy POST)
$QUERY_STRING A GET kérelmeknél nev=janos&cim=
az URL-hez kapcsolt ismeretlen
kódolt adat
$REQUEST_URI A kérelem teljes címe /php-konyv/urlapok/
a lekérdezõ 9.14.program.php?nev=
karaktersorozattal janos
$HTTP_REFERER Az oldal címe, http://www.proba.hu/
amelyrõl a kérelem egy_oldal.html
érkezett

A PHP létrehoz más környezeti változókat is.


Például a $GLOBALS["PHP_SELF"] az éppen futó program elérési útját adja
meg. A szerzõ rendszerén az érték a következõ volt:

/php-konyv/urlapok/9.1.program.php
09_ora.qxd 8/3/2001 6:20 PM Page 152

152 9. óra

A változó értéke közvetlenül is elérhetõ, $PHP_SELF néven. Ebben az órában még


sokszor fogjuk használni ezt a változót. A HTML oldalt leíró és az ûrlapot elemzõ
PHP kódot gyakran tároljuk egy állományban. Az oldal nevének tárolásához
a $PHP_SELF változó értékét a HTML FORM elemének ACTION paraméteréhez
rendeljük.

A $GLOBALS tömb ezenkívül még sok másra is használható.

Adatok bekérése a felhasználótól


Jelenleg a HTML és PHP kódot külön állományban tároljuk. A 9.2. példában egy
egyszerû HTML ûrlap kódját láthatjuk.

9.2. program Egy egyszerû HTML ûrlap


1: <html>
2: <head>
3: <title>9.2. program Egy egyszerû HTML ûrlap</title>
4: </head>
5: <body>
6: <form action="9.3.program.php" method="GET">
7: <input type="text" name="felhasznalo">
8: <br>
9: <textarea name="cim" rows="5" cols="40">
10: </textarea>
11: <br>
12: <input type="submit" value="rendben">
13: </form>
14: </body>
15: </html>

Egy HTML ûrlapot hoztunk létre, amely egy "felhasznalo" nevû szövegmezõt,
egy "cim" nevû szövegterületet, és egy gombot tartalmaz. Könyvünk nem fogla-
kozik részletesen a HTML ismertetésével, ha mégis nehéznek találjuk a példákat,
olvassunk el egy, a HTML nyelvvel foglalkozó kötetet vagy számítógépes leírást.
A FORM elem ACTION paramétere a 9.3.program.php fájlra mutat, amely
feldolgozza az ûrlapon megadott adatokat. Mivel az ACTION csak a fájl nevét adja
meg, a HTML és PHP kódot tartalmazó fájloknak egy könyvtárban kell lenniük.

A 9.3. példaprogram kiírja a felhasználó által megadott információkat.


09_ora.qxd 8/3/2001 6:20 PM Page 153

Ûrlapok 153

9.3. progran A 9.2. példa ûrlapjának feldolgozása


1: <html>
2: <head>
9
3: <title>9.3. program A 9.2. példa ûrlapjának
feldolgozása</title>
4: </head>
5: <body>
6: <?php
7: print "Üdvözlet <b>$felhasznalo</b><P>\n\n";
8: print "A címe:<P>\n\n<b>$cim</b>";
9: ?>
10: </body>
11: </html>

Ez a könyv elsõ olyan programja, amelyet nem hivatkozáson keresztül hívunk meg
és nem közvetlenül a böngészõbe írjuk be a címét. A 9.3. példában található kódot
az 9.3.program.php fájlban tároljuk. A fájlban lévõ kódot akkor hívjuk meg,
amikor a felhasználó kitölti a 9.2. példában található ûrlapot. A program
a $felhasznalo és a $cim változók értékét írja ki, amelyek a HTML ûrlap
"felhasznalo" szövegmezõjének és "cim" területének értékét tartalmazzák.
Látható, hogy a PHP 4 segítségével milyen egyszerûen kezelhetõek az ûrlapok.
Bármilyen megadott információ globális változóként hozzáférhetõ és a változók ne-
ve megegyezik a megfelelõ HTML elem nevével.

Több elem kiválasztása a SELECT elemmel


Elõzõ példánkban olyan HTML ûrlap szerepelt, amely egy elemhez egyetlen érték
hozzárendelését engedélyezte. Most megtanuljuk a SELECT elem kezelését, mely-
nek segítségével több elem kiválasztását engedélyezhetjük. Ha a SELECT elemnek
egyszerû nevet adunk:

<select name="termekek" multiple>

akkor a feldolgozó program csak az egyik kiválasztott elemhez fér hozzá.


Ha minden elemet el szeretnénk érni a programból, az elem neve után írjunk
üres szögletes zárójeleket. Ezt láthatjuk a 9.4. példában.
09_ora.qxd 8/3/2001 6:20 PM Page 154

154 9. óra

9.4. program SELECT elemet tartalmazó HTML ûrlap


1: <html>
2: <head>
3: <title>9.4. program SELECT elemet tartalmazó HTML
ûrlap</title>
4: </head>
5: <body>
6: <form action="9.5.program.php" method="POST">
7: <input type="text" name="felhasznalo">
8: <br>
9: <textarea name="cim" rows="5" cols="40">
10: </textarea>
11: <br>
12: <select name="termekek[]" multiple>
13: <option>Ultrahangos csavarhúzó
14: <option>Tricorder
15: <option>ORAC AI
16: <option>HAL 2000
17: </select>
18: <br>
19: <input type="submit" value="rendben">
20: </form>
21: </body>
22: </html>

Az ûrlapot feldolgozó programban a SELECT elemben kiválasztott adatok


a $termekek tömbben találhatóak. Ezt mutatjuk be a 9.5. példában

9.5. program A 9.4. példában látott ûrlap feldolgozása


1: <html>
2: <head>
3: <title>9.5. program A 9.4. példában látott ûrlap
feldolgozása</title>
4: </head>
5: <body>
6: <?php
7: print "Üdvözlet <b>$felhasznalo</b><P>\n\n";
8: print "A címe:<P>\n\n<b>$cim</b>";
9: print "A következõ termékeket választotta:<p>\n\n";
10: print "<ul>\n\n";
09_ora.qxd 8/3/2001 6:20 PM Page 155

Ûrlapok 155

9.5. program (folytatás)


11:
12:
foreach ( $termekek as $termek )
{
9
13: print "<li>$termek<br>\n";
14: }
15: print "</ul>";
16: ?>
17: </body>
18: </html>

Nem csak a SELECT elem engedélyezi több elem kiválasztását. Ha több jelölõ-
négyzetnek ugyanazt a nevet adjuk, ahol a felhasználó több elemet is kiválaszthat,
csak az utolsó kiválasztott értéket kapjuk meg, de ha a nevet üres szögletes záróje-
lek követik, az adott nevû elemeket a PHP tömbként kezeli. A 9.4. példa SELECT
elemét jelölõnégyzetekre cserélhetjük és ugyanazt a hatást érjük el:

<input type="checkbox" name="termekek[]" value="Ultrahangos


å csavarhúzó">Ultrahangos csavarhúzó<br>
<input type="checkbox" name="termekek[]"
å value="Tricorder">Tricorder<br>
<input type="checkbox" name="termekek[]" value=
å "ORAC AI">ORAC AI<br>
<input type="checkbox" name="termekek[]" value=
å "HAL 2000">HAL 2000<br>

Az ûrlap minden mezõjének


hozzárendelése egy tömbhöz
Az eddig megtanult módszerek mindaddig jól mûködnek, amíg programunk tudja,
milyen mezõkkel dolgozik. Gyakran azonban olyan programra van szükségünk,
amely az ûrlap változásaihoz alkalmazkodik vagy egyszerre többféle ûrlapot képes
kezelni, anélkül, hogy keverné a mezõk neveit. A PHP 4 globális változói erre
a problémára is megoldást nyújtanak. Attól függõen, hogy a kitöltött ûrlap GET
vagy POST metódust használt, elérhetõvé válnak a $HTTP_GET_VARS vagy
a $HTTP_POST_VARS változók. Ezek az asszociatív tömbök tartalmazzák az ûrlap
mezõinek neveit és a hozzájuk rendelt értékeket. A 9.6. példa azt mutatja be,
hogyan listázható ki az ûrlap minden mezõje egy GET kérelem esetén.
09_ora.qxd 8/3/2001 6:20 PM Page 156

156 9. óra

9.6. program A $HTTP_GET_VARS tömb használata


1: <html>
2: <head>
3: <title>9.6. program A $HTTP_GET_VARS tömb
használata</title>
4: </head>
5: <body>
6: <?php
7: foreach ( $HTTP_GET_VARS as $kulcs => $ertek )
8: {
9: print "$kulcs == $ertek<BR>\n";
10: }
11: ?>
12: </body>
13: </html>

A fenti kód a GET kérelmen keresztül érkezett paraméterek neveit és értékeit írja ki.
Természetesen itt még nem kezeltük azt az esetet, amikor valamelyik átadott para-
méter tömb. Ha a 9.4. példaprogrammal olyan HTML ûrlapról érkezõ adatok feldol-
gozását végeztetjük, amelyben több elem kiválasztását engedélyezõ SELECT mezõ
szerepel, valami hasonlót olvashatunk:

felhasznalo == Kiss Iván


cim == Budapest, Magyarország
termekek == Array

A termekek tömböt tartalmazza a $HTTP_GET_VARS tömb, de kódunk még nem


tudja ezt kezelni. A 9.7. példaprogram ellenõrzi, hogy a paraméter típusa tömb-e
és ha igen, kiírja a tömb elemeit.

9.7. program A $HTTP_GET_VARS tömb használata,


ha tömböt tartalmaz
1: <html>
2: <head>
3: <title>9.7. program A $HTTP_GET_VARS tömb
használata, ha tömböt tartalmaz</title>
4: </head>
5: <body>
6: <?php
09_ora.qxd 8/3/2001 6:20 PM Page 157

Ûrlapok 157

9.7. program (folytatás)


7:
8:
foreach ( $HTTP_GET_VARS as $kulcs => $ertek )
{
9
9: if ( gettype( $ertek ) == "array" )
10: {
11: print "$kulcs == <br>\n";
12: foreach ( $ertek as $tombelem )
13: print ".........$tombelem<br>";
14: }
15: else
16: {
17: print "$kulcs == $ertek<br>\n";
18: }
19: }
20: ?>
21: </body>
22: </html>

Mielõtt a forearch segítségével a $HTTP_GET_VARS tömb elemein végiglépked-


nénk, a gettype() függvénnyel ellenõrizzük, hogy a következõ elem tömb-e.
Ha az elem tömb, egy második foreach segítségével végiglépkedünk az elemein
és kiírjuk azokat a böngészõbe.

Különbségek a GET és a POST továbbítás között


A program akkor rugalmas, ha el tudja dönteni, hogy $HTTP_POST_VARS vagy
$HTTP_GET_VARS tömbbõl olvassa-e ki az elemeket. A továbbítás típusát (GET
vagy POST) a legtöbb rendszerben a $REQUEST_METHOD környezeti változó
tartalmazza, értéke értelemszerûen "get" vagy "post". Érdemes tudni, hogy
a $HTTP_POST_VARS tömb csak POST továbbítási mód esetén tartalmaz
elemeket.

A 9.8. program mindig a megfelelõ tömbbõl olvassa ki a paramétereket.


09_ora.qxd 8/3/2001 6:20 PM Page 158

158 9. óra

9.8. program A GET és POST kérelmek kezelése


1: <html>
2: <head>
3: <title>9.8. program A GET és POST kérelmek
kezelése</title>
5: </head>
6: <body>
7: <?php
8: $PARAMETEREK = ( count( $HTTP_POST_VARS ) )
9: ? $HTTP_POST_VARS : $HTTP_GET_VARS;
10: foreach ( $PARAMETEREK as $kulcs => $ertek )
11: {
12: if ( gettype( $ertek ) == "array" )
13: {
14: print "$kulcs == <br>\n";
15: foreach ( $ertek as $tombelem )
16: print ".........$tombelem<br>";
17: }
18: else
19: {
20: print "$kulcs == $ertek<br>\n";
21: }
22: }
23: ?>
24: </body>
25: </html>

A feltételes mûveletjellel beállítjuk a $PARAMETEREK változó értékét. A count()


függvénnyel ellenõrizzük, hogy a $HTTP_POST_VARS változó tartalmaz-e eleme-
ket. A count() visszatérési értéke a tömb elemeinek száma: pozitív, ha a para-
méterében megadott változó tartalmaz elemeket és 0 (false), ha nem.
Ha a $HTTP_POST_VARS tartalmaz elemeket, akkor a $PARAMETEREK változót
egyenlõvé tesszük vele, egyébként a $PARAMETEREK a $HTTP_GET_VARS érté-
két veszi fel. Most már kiírathatjuk a $PARAMETEREK tömb tartalmát a korábban
látott módon.
09_ora.qxd 8/3/2001 6:20 PM Page 159

Ûrlapok 159

PHP és HTML kód összekapcsolása egy oldalon


Néhány esetben szükség lehet rá, hogy az ûrlapot leíró HTML kódot és az ûrlapot 9
kezelõ PHP kódot egyetlen fájlban tároljuk. Ez akkor lehet hasznos, amikor a fel-
használó számára többször adjuk át ugyanazt az ûrlapot. Természetesen kódunk
sokkal rugalmasabb, ha dinamikusan írjuk meg, de ekkor elveszítjük a PHP hasz-
nálatának elõnyét. A HTML és PHP kódot ne keverjük a közös fájlon belül, mert
így a forrás nehezebben lesz olvasható és módosítható. Ahol lehetséges, készít-
sünk HTML kódból meghívható PHP függvényeket, amelyeket késõbb fel tudunk
használni.

A következõ példákban olyan oldalt fejlesztünk, amely az ûrlapról beérkezõ egész


számról megmondja, hogy kisebb vagy nagyobb-e egy elõre megadott egész
értéknél.

A 9.9. példában a fenti feladat megoldását tartalmazó HTML kódot láthatjuk.


A kód egy egyszerû szövegmezõt és némi PHP kódot tartalmaz.

9.9. program Saját magát meghívó HTML kód


1: <html>
2: <head>
3: <title>9.9. program Saját magát meghívó
HTML kód</title>
4: </head>
5: <body>
6: <form action="<?php print $PHP_SELF?>" method="POST">
7: Ide írja a tippjét: <input type="text" name="tipp">
8: </form>
9: </body>
10: </html>

A fenti ûrlap saját magát hívja meg, mert a FORM elem ACTION paraméterének
a $PHP_SELF értéket adtunk. Vegyük észre, hogy nem készítettünk gombot,
amely elküldi a beírt számot. Az újabb böngészõk a szövegmezõ kitöltése és
az ENTER lenyomása után automatikusan elküldik a megadott adatot, viszont
néhány régebbi böngészõ ezt nem teszi meg.

A 9.9. példában lévõ program nem dinamikus, hiszen nem ír ki semmit, ami a fel-
használótól függ. A 9.10. példában további PHP kódot építünk az oldalba. Elõször
meg kell adnunk a számot, amit a felhasználónak ki kell találnia. A teljes változatban
valószínûleg véletlenszámot állítanánk elõ, most azonban egyszerûen megadjuk,
mondjuk a 42-t. Ezután megnézzük, hogy az ûrlapot kitöltötték-e már, különben
09_ora.qxd 8/3/2001 6:20 PM Page 160

160 9. óra

olyan változóval számolnánk, amely még nem létezik. A $tipp változó létezésének
ellenõrzésével megtudhatjuk, hogy az ûrlapot kitöltötték-e már. Amikor az ûrlap el-
küldi a "tipp" paramétert, a $tipp változó globális változóként hozzáférhetõ lesz
a programban. A $tipp változó létezése esetén egészen biztosak lehetünk benne,
hogy az ûrlapot a felhasználó kitöltötte, így elvégezhetjük a további vizsgálatokat.

9.10. program Számkitalálós PHP program


1: <?php
2: $kitalalando_szam = 42;
3: $uzenet = "";
4: if ( ! isset( $tipp ) )
5: {
6: $uzenet = "Üdvözlöm a számkitalálós játékban!";
7: }
8: elseif ( $tipp > $kitalalando_szam )
9: {
10: $uzenet = "A(z) $tipp túl nagy, próbáljon
egy kisebbet!";
11: }
12: elseif ( $tipp < $kitalalando_szam )
13: {
14: $uzenet = "A(z) $tipp túl kicsi, próbáljon
egy nagyobbat!";
15: }
16: else // egyenlõk kell, hogy legyenek
17: {
18: $uzenet = "Telitalálat!";
19: }
20: ?>
21: <html>
22: <head>
23: <title>9.10. program Számkitalálós PHP program</title>
24: </head>
25: <body>
26: <h1>
27: <?php print $uzenet ?>
28: </h1>
29: <form action="<?php print $PHP_SELF?>" method="POST">
30: Ide írja a tippjét: <input type="text" name="tipp">
31: </form>
32: </body>
33: </html>
09_ora.qxd 8/3/2001 6:20 PM Page 161

Ûrlapok 161

A program törzsében egy if szerkezettel vizsgáljuk a $tipp változót és adunk ér-


téket az $uzenet változónak. Ha a $tipp változó még nem létezik, a felhaszná-
ló csak most lépett az oldalra, ezért üdvözöljük. Különben megvizsgáljuk az elõre 9
megadott számot és a $tipp értékét, és ez alapján rendeljük az $uzenet válto-
zóhoz a megfelelõ szöveget. Végül a HTML oldal törzsében csak ki kell írnunk az
$uzenet értékét. A program persze még továbbfejleszthetõ. A PHP és a HTML
kódot szétválasztva tartva egy grafikus könnyen módosíthatja az oldalt, a
programozó közremûködése nélkül.

Állapot mentése rejtett mezõkkel


A 9.10. példában található program nem tudja, hogy a felhasználó hányszor tip-
pelt, egy rejtett mezõ bevezetésével azonban ez is számon tartható. A rejtett mezõ
ugyanúgy mûködik, mint a szövegmezõ, de a felhasználó nem látja, hacsak meg
nem nézi a HTML forráskódot. A 9.11. példában található programban bevezetünk
egy rejtett mezõt, amely a találgatások számát tartalmazza.

9.11. program Állapot mentése rejtett mezõvel


1: <?php
2: $kitalalando_szam = 42;
3: $uzenet = "";
4: $probalkozasok = ( isset( $probalkozasok ) ) ?
++$probalkozasok : 0;
5: if ( ! isset( $tipp ) )
6: {
7: $uzenet = "Üdvözlöm a számkitalálós játékban!";
8: }
9: elseif ( $tipp > $kitalalando_szam )
10: {
11: $uzenet = "A(z) $tipp túl nagy, próbáljon
egy kisebbet!";
12: }
13: elseif ( $tipp < $kitalalando_szam )
14: {
15: $uzenet = "A(z) $tipp túl kicsi, próbáljon
egy nagyobbat!";
16: }
17: else // egyenlõk kell, hogy legyenek
18: {
19: $uzenet = " Telitalálat!";
20: }
09_ora.qxd 8/3/2001 6:20 PM Page 162

162 9. óra

9.11. program (folytatás)


21: $tipp = (int) $tipp;
22: ?>
23: <html>
24: <head>
25: <title>9.11. program Állapot mentése rejtett
mezõvel</title>
26: </head>
27: <body>
28: <h1>
29: <?php print $uzenet ?>
30: </h1>
31: Tippelés sorszáma: <?php print $probalkozasok?>
32: <form action="<?php print $PHP_SELF?>" method="POST">
33: Ide írja a tippjét:
34: <input type="text" name="tipp" value="<?php
print $tipp?>">
35: <input type="hidden" name="probalkozasok"
value="<?php print $probalkozasok?>">
36: </form>
37: </body>
38: </html>

A rejtett mezõ neve "probalkozasok". A PHP segítségével kiírjuk


a "probalkozasok" és a "tipp" mezõ értékét, hogy a felhasználó tudja, hány-
szor próbálkozott és mit tippelt utoljára. Ez az eljárás akkor lehet hasznos, amikor
a kitöltött ûrlapot elemezzük. Ha az ûrlapot rosszul töltötték ki, a felhasználó tud-
ni fogja, mit rontott el. A beadott tipp értékét egész számmá alakítjuk a kérdõív-
be írás elõtt.

Egy kifejezés értékének kiírásához a böngészõben a print() vagy


az echo() utasításokat használhatjuk. PHP módban ezt egysze-
rûbben is megtehetjük. Ha egyenlõségjelet (=) teszünk a PHP
blokkot nyitó elem után, a böngészõ az azt következõ kifejezés
értékét kiírja, így a
<? print $proba?>
helyett írhatjuk a következõt is:
<?=$proba?>
09_ora.qxd 8/3/2001 6:20 PM Page 163

Ûrlapok 163

A PHP kód törzsében egy feltétellel megvizsgáljuk, hogy kell-e növelni


a $probalkozasok változó értékét. Ha a változó létezik, akkor növeljük
az értékét, különben 0-ra állítjuk. A HTML kód törzsében folyamatosan kiírjuk, 9
hányszor próbálkozott a felhasználó.

Ne bízzunk meg feltétel nélkül a rejtett mezõkben. Nem tudhatjuk,


hogy honnan származik az értékük. Nem mondjuk, hogy ne hasz-
náljuk õket, csak azt, hogy nagy körültekintéssel tegyük.
A felhasználó a forrás megváltoztatásával könnyedén csalhat
a programban. A rejtett mezõk használata nem biztonságos.

A felhasználó átirányítása
Programunknak van egy nagy hátulütõje. Az ûrlap mindig újratöltõdik, akár kita-
lálta a felhasználó a számot, akár nem. A HTML nyelvben sajnos elkerülhetetlen
az egész oldal újratöltése, a felhasználót azonban átirányíthatjuk egy gratuláló
oldalra, ha kitalálta a számot.

Amikor az ügyfélprogram elkezdi a kapcsolatot a kiszolgálóval, elküld egy fejlécet,


amely különbözõ információkat tartalmaz az azt követõ dokumentumról. A PHP
ezt automatikusan megteszi, de a header() függvénnyel mi is beállíthatjuk
a fejléc egyes elemeit. Ha a header() függvényt szeretnénk használni, biztosnak
kell benne lennünk, hogy a böngészõnek nem írtunk ki semmit, különben a függ-
vényhívás elõtt a PHP elküldi a saját fejlécét. Ez mindenféle kiírás, még sortörés és
szóköz karakter esetén is bekövetkezik. A header() függvény használatakor
semmi nem lehet a függvényhívás elõtt, így ellenõriznünk kell a felhasználandó
külsõ állományokat is. A 9.12. példában egy jellemzõ PHP fejlécet láthatunk.

9.12. példa Egy jellemzõ PHP fejléc


1: HEAD /php-konyv/urlapok/9.1.program.php HTTP/1.0
2: HTTP/1.1 200 OK
3: Date: Sun, 09 Jan 2000 18:37:45 GMT
4: Server: Apache/1.3.9 (Unix) PHP/4.0
5: Connection: close
6: Content-Type: text/html
09_ora.qxd 8/3/2001 6:20 PM Page 164

164 9. óra

A fejlécet a Telnet programmal írathatjuk ki. Kapcsolódjunk a 80-as


kapun a webkiszolgálóhoz és gépeljük be a következõt:
HEAD /utvonal/fajl.html HTTP/1.0

Az ügyfélprogram ekkor kiírja a fejlécet.

Egy "Location" fejléc elküldésével a böngészõt egy másik lapra irányíthatjuk:

header( "Location: http://www.kiskapu.hu/" );

Tegyük fel, hogy készítettünk egy "gratulacio.html" oldalt, ahova átirányítjuk


a felhasználót, amikor kitalálta a megadott számot. A megoldást a 9.13. példában
találjuk.

9.13. program Fejléc küldése a header() függvénnyel


1: <?php
2: $kitalalando_szam = 42;
3: $uzenet = "";
4: $probalkozasok = ( isset( $probalkozasok ) ) ?
++$probalkozasok : 0;
5: if ( ! isset( $tipp ) )
6: {
7: $uzenet = "Üdvözlöm a számkitalálós játékban!";
8: }
9: elseif ( $tipp > $kitalalando_szam )
10: {
11: $uzenet = "A(z) $tipp túl nagy, próbáljon
egy kisebbet!";
12: }
13: elseif ( $tipp < $kitalalando_szam )
14: {
15: $uzenet = "A(z) $tipp túl kicsi, próbáljon
egy nagyobbat!";
16: }
17: else // egyenlõk kell, hogy legyenek
18: {
19: header( "Location: gratulacio.html" );
20: exit;
21: }
22: $tipp = (int) $tipp;
09_ora.qxd 8/3/2001 6:20 PM Page 165

Ûrlapok 165

9.13. program (folytatás)


23: ?>
24: <html>
9
25: <head>
26: <title>9.13. program Fejléc küldése a header()
függvénnyel</title>
27: </head>
28: <body>
29: <h1>
30: <?php print $uzenet ?>
31: </h1>
32: Tippelés sorszáma: <?php print $probalkozasok?>
33: <form action="<?php print $PHP_SELF?>" method="POST">
34: Ide írja a tippjét:
35: <input type="text" name="tipp" value="<?php print
$tipp?>">
36: <input type="hidden" name="probalkozasok"
37: value="<?php print $probalkozasok ?>">
38: </form>
39: </body>
40: </html>

Az if szerkezet else ágában a böngészõt átirányítjuk a "gratulacio.html"


oldalra. A header() függvény meghívása után az oldalnak exit utasítással kell
végzõdnie, hogy befejezze az ûrlap vizsgálatát.

Fájlfeltöltõ ûrlapok és programok


Megtanultuk, hogyan kérhetünk be adatokat a felhasználótól, de a Netscape
Navigator 2-tõl és az Internet Explorer 4-tõl kezdve lehetõségünk van fájlok feltöl-
tésére is. Ebben a részben azzal foglalkozunk, hogyan lehet a fájlok feltöltését
kezelni a PHP 4 segítségével.

Elõször létre kell hoznunk egy HTML ûrlapot, amely tartalmazza a fájlfeltöltõ me-
zõt, melynek egyik paramétere kötelezõen a következõ:

ENCTYPE="multipart/form-data"

A feltöltõ mezõ elõtt meg kell adnunk egy rejtett mezõt is. Ennek neve
MAX_FILE_SIZE kell, hogy legyen, és a fogadandó fájl lehetséges legnagyobb
méretét adja meg, bájtban. Nem lehet nagyobb, mint a php.ini fájlban megadott
09_ora.qxd 8/3/2001 6:20 PM Page 166

166 9. óra

upload_max_filesize értéke, amely alapértelmezés szerint 2 megabájt.


Miután kitöltöttük a MAX_FILE_SIZE mezõt, a fájlt egy egyszerû INPUT elemmel
tölthetjük fel, melynek TYPE paramétere "file". Bármilyen nevet adhatunk
neki. A 9.14. példában a fájlt feltöltõ HTML kódot láthatjuk.

9.14. program Fájlfeltöltõ ûrlap


1: <html>
2: <head>
3: <title>9.14. program Fájlfeltöltõ ûrlap</title>
4: </head>
5: <body>
6: <form enctype="multipart/form-data"
action="<?print $PHP_SELF?>" method="POST">
7: <input type="hidden" name="MAX_FILE_SIZE"
value="51200">
8: <input type="file" name="fajl"><br>
9: <input type="submit" value="feltöltés!">
10: </form>
11: </body>
12: </html>

Vegyük észre, hogy a program meghívja az oldalt, amely tartalmazza, hogy PHP
kóddal kezeljük a fájlt. A legnagyobb fájlméretet 50 kilobájtban adjuk meg és
"fajl"-nak nevezzük el.

Amikor a fájlt feltöltöttük, az egy ideiglenes könyvtárban tárolódik (ez alapbeállí-


tásban a /tmp, ha UNIX rendszerrõl van szó). A fájl elérési útját a betöltõ mezõ
nevével megegyezõ globális változó tartalmazza (példánkban a $fajl). A fájlról
a különbözõ információkat a PHP globális változókban tárolja. Nevük a fájl elérési
útját tartalmazó változónév, kiegészítve a "name", "size" és "type" utótagok-
kal. A változók jelentését a 9.2. táblázat tartalmazza.

9.2. táblázat Feltöltött fájlhoz kapcsolódó globális változók


Változónév Tartalma Példa
$fajl A fájl ideiglenes elérési útja /tmp/php5Pq3fU
$fajl_name A feltöltött fájl neve test.gif
$fajl_size A feltöltött fájl mérete bájtban 6835
$fajl_type A feltöltött fájl típusa image/gif
09_ora.qxd 8/3/2001 6:20 PM Page 167

Ûrlapok 167

A PHP 4 a feltöltött fájlok adatainak tárolására beépített tömb típusú változókat


használ. Ha egy vagy több fájlt töltünk fel egy ûrlapon keresztül, a fájlok adatai
a $HTTP_POST_FILES tömbben tárolódnak. A tömb indexei a feltöltést meghatá- 9
rozó mezõk nevei. A 9.3. táblázatban láthatjuk a tömb elemeinek nevét és értékét.

9.3. táblázat Feltöltött fájlhoz kapcsolódó globális változók


Elem Tartalma Példa
$HTTP_POST_FILES["fajl"]["name"] A feltöltött fájl neve test.gif
$HTTP_POST_FILES["fajl"]["size"] A feltöltött fájl mérete 6835
bájtban
$HTTP_POST_FILES["fajl"]["type"] A feltöltött fájl típusa image/gif

A 9.15. példában látható program kiírja a rendelkezésre álló információkat


a feltöltött fájlról, és ha az GIF formátumú, megjeleníti.

9.15. program Fájlfeltöltõ program


1: <html>
2: <head>
3: <title>9.15. program - Fájlfeltöltõ program</title>
4: </head>
5: <?php
6: $feltoltes_konyvtar = "/home/httpd/htdocs/feltoltesek";
7: $feltoltes_url = "http://php.kiskapu.hu/feltoltesek";
8: if ( isset( $fajl ) )
9: {
10: print "elérési út: $fajl<br>\n";
11: print "név: $fajl_name<br>\n";
12: print "méret: $fajl_size bájt<br>\n";
13: print "típus: $fajl_type<p>\n\n";
14: if ( $fajl_type == "image/gif" )
15: {
16: copy ( $fajl, "$feltoltes_konyvtar/$fajl_name") or die
("Nem lehet másolni");
17:
18: print "<img
src=\"$feltoltes_url/$fajl_name\"><p>\n\n";
19: }
20: }
09_ora.qxd 8/3/2001 6:20 PM Page 168

168 9. óra

9.15. program (folytatás)


21: ?>
22: <body>
23: <form enctype="multipart/form-data" action="<?php print
$PHP_SELF?>" method="POST">
24: <input type="hidden" name="MAX_FILE_SIZE"
value="51200">
25: <input type="file" name="fajl"><br>
26: <input type="submit" value="feltöltés!">
27: </form>
28: </body>

A 9.15. példában elõször ellenõrizzük, hogy a $fajl globális változó létezik-e.


Ha létezik, feltehetjük, hogy a feltöltés sikeres volt (legalábbis e példa erejéig).

Mindig csak megbízható forrásból fogadjunk fájlt és ellenõrizzük,


hogy programunk számára megfelelõ formátumú-e. A rosszindu-
latú látogatók olyan ûrlapot készíthetnek, amelyben megegyezõ
nevû elemek találhatóak, de teljesen más tartalommal, így prog-
ramunk nem a várt adatokat kapja meg. Lehet, hogy ez paranoiá-
nak tûnik, de jegyezzük meg, hogy a kiszolgálóoldali programo-
zásban a paranoia jó dolog. Soha ne bízzunk külsõ forrásból
érkezõ adatokban, még akkor sem, ha a külsõ forrás egy olyan
ûrlap, amit éppen mi készítettünk.

Miután feltöltöttük a fájlt, a böngészõben megjelenítjük a $fajl, $fajl_name,


$fajl_size és $fajl_type változók tartalmát, amelyek a fájlról információkat
tartalmaznak.

Ezután ellenõrizzük a $fajl_type változót. Ha értéke "image/gif", akkor


az érkezett állományt GIF képként megjeleníthetjük. A típust a fájlkiterjesztés
alapján állapítja meg a rendszer, ezért érdemes ellenõrizni, hogy a fájl valóban
GIF formátumú-e. Ennek módjáról a tizenhetedik, karakterláncokkal foglalkozó
órában tanulunk.

A copy() függvénnyel a feltöltött fájlt a kiszolgáló másik könyvtárába másolhatjuk.


A copy() függvénynek két paramétert kell megadni: az elsõ a másolandó fájl elérési
útja, a második a fájl új elérési útja. A fájl eredeti elérési útja a $fajl változóban
található. Az új elérési út számára létrehozunk egy $feltoltes_konyvtar nevû
változót, amihez hozzáfûzzük a $fajl_name értéket. Ezután a copy() függvénnyel
átmásoljuk a fájlt. UNIX rendszerben a kiszolgálóprogramok a 'nobody' felhaszná-
09_ora.qxd 8/3/2001 6:20 PM Page 169

Ûrlapok 169

lónév alatt futnak, ezért mielõtt másolatot készítenénk a fájlról, ellenõriznünk kell,
hogy a mûvelet engedélyezett-e. Az or mûvelettel a die() függvényt használjuk,
ha a másolás sikertelen. Ezt a módszert a tizedik, a fájlokkal foglalkozó órában részle- 9
tesebben áttekintjük.

Másolás után az eredeti fájlt nem kell törölnünk, a PHP ezt megteszi helyettünk.
Ha nem másoljuk vagy helyezzük át a feltöltött állományt, a fájl elvész, mivel az
a PHP kód végrehajtása után törlõdik az ideiglenes könyvtárból.

Amikor létrehozzuk a $feltoltes_konyvtar változót, létrehozzuk


a $feltoltes_url változót is, a célkönyvtár URL címének tárolására. A lemá-
solt fájlt HTML kép elemként jelenítjük meg.

Összefoglalás
Eddig olyan dolgokat tanultunk, amelyek segítségével igazi interaktív környezetet
hozhatunk létre. Van azonban még néhány tanulnivaló. A felhasználóról képesek
vagyunk információkat szerezni, de mit tegyünk ezekkel? Például fájlba írhatjuk.
Ez lesz a következõ óra témája.

Ebben az órában megtanultuk, hogyan használjuk a $GLOBALS tömböt, az ûrlapok


adatait, a feltöltött fájlokat és a globális változókat. Megtanultuk, hogyan küldhe-
tünk fejlécet az ügyfélnek a böngészõ átirányítása érdekében. Megnéztük, hogyan
listázzuk ki az ûrlapról kapott adatokat és rejtett mezõket használtunk, adatok át-
adására a programtól a böngészõnek.

Kérdések és válaszok
Létre lehet hozni tömböt olyan elemek tárolására is, amelyek nem
választómezõvel vagy jelölõnégyzetekkel megadottak?
Igen. Minden elem, amely nevének végén üres szögletes zárójel van, tömbként tá-
rolódik, így az elemek csoportba rendezhetõk.

A header() függvény nagyon hasznosnak tûnik. Tanulunk még


a HTTP fejlécekrõl?
Magáról a HTTP-rõl még beszélünk a tizenharmadik órában.

Az elemek nevének automatikus változónévvé alakítása veszélyesnek


tûnik. Kikapcsolható valahol ez a lehetõség?
Igen a php.ini fájl register_globals elemét kell off-ra állítani a lehetõség
kikapcsolásához.
09_ora.qxd 8/3/2001 6:20 PM Page 170

170 9. óra

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 környezeti változó tartalmazza a felhasználó IP címét?

2. Melyik környezeti változó tartalmaz a böngészõrõl információkat?

3. Hogyan nevezzük el az ûrlap mezõjét, hogy a rá hivatkozó globális változó


$urlap_tomb nevû tömb legyen?

4. Melyik beépített tömb tartalmazza a GET kérelmen keresztül érkezõ


változókat?

5. Melyik beépített tömb tartalmazza a POST kérelmen keresztül érkezõ


változókat?

6. Melyik függvényt használjuk a böngészõ átirányítására? Milyen karakter-


sorozatot kell átadnunk a függvénynek?

7. Hogyan lehet korlátozni egy ûrlapról feltölthetõ fájl méretét?

8. Hogyan korlátozható az összes ûrlapról vagy programból feltölthetõ fájl


mérete?

Feladatok
1. Készítsünk számológép-programot, amelyben a felhasználó megadhat két
számot és a rajtuk végrehajtandó mûveletet (összeadás, kivonás, szorzás vagy
osztás – ezeket ismerje a program).

2. Készítsünk programot, amely rejtett mezõ használatával megmondja, hogy


a felhasználó hányszor használta az elsõ feladatban szereplõ számológépet.
10_ora.qxd 8/3/2001 6:20 PM Page 171

10. ÓRA
Fájlok használata
A programozási nyelvek egyik legfontosabb lehetõsége, hogy fájlokat lehet létre-
hozni, olvasni, írni velük. A PHP-nek szintén megvannak ezek a tulajdonságai.
Ebben a fejezetben ezeket a lehetõségeket fogjuk áttekinteni:

• Hogyan ágyazzunk be fájlokat a dokumentumokba?

• Hogyan vizsgáljuk a fájlokat és könyvtárakat?

• Hogyan nyissunk meg egy fájlt?

• Hogyan olvassunk adatokat a fájlokból?

• Hogyan írjunk egy fájlba vagy fûzzünk hozzá?

• Hogyan zárjunk le egy fájlt?

• Hogyan dolgozzunk könyvtárakkal?


10_ora.qxd 8/3/2001 6:20 PM Page 172

172 10. óra

Fájlok beágyazása az include() függvénnyel


Az include() függvény lehetõséget ad arra, hogy fájlt ágyazzunk be a PHP doku-
mentumokba. A fájlban szereplõ PHP kód úgy hajtódik végre, mintha a fõdokumen-
tum része lenne, ami hasznos, ha egy többoldalas programban külsõ kódokat sze-
retnénk beágyazni.

Eddig, ha olyan kódot írtunk, amelyet többször is fel akartunk használni, minden
egyes helyre be kellett másolnunk azt. Ha hibát találtunk benne vagy lehetõségeit
tovább akartuk bõvíteni, mindenütt át kellett írnunk. Ezekre a problémákra megol-
dás az include() függvény. Gyakran használt függvényeinket külsõ fájlba ment-
hetjük és az include() függvénnyel futási idõben tölthetjük be programunkba.
Az include() függvény paramétere a fájl elérési útja. A 10.1. példában látható,
hogyan ágyazható be egy fájl a PHP kódba az include() függvény segítségével.

10.1. program Az include() használata


1: <html>
2: <head>
3: <title>10.1. program Az include() használata</title>
4: </head>
5: <body>
6: <?php
7: include("10.2.program.php");
8: ?>
9: </body>
10: </html>

10.2. program A 10.1. példában szereplõ beillesztett fájl


1: Engem ágyaztak be!!

A 10.1. példában található kódba az 10.2.program.php fájl van beágyazva.


Amikor lefuttatjuk a 10.1. példában található kódot, az "Engem ágyaztak
be!!" szöveg jelenik meg, azaz szöveget ágyaztunk be a PHP kódba. Nem okoz
ez gondot? A beágyazott fájl tartalma alapértelmezésben HTML formátumban jele-
nik meg. Ha végrehajtandó PHP kódot szeretnénk beágyazni, akkor azt az eredeti
fájlban PHP címkék közé kell zárni. A 10.3. és 10.4. példában a beágyazott fájlban
van a megjelenítõ kód.
10_ora.qxd 8/3/2001 6:20 PM Page 173

Fájlok használata 173

10.3. program Az include() függvény használata


PHP kód végrehajtására más fájlban
1: <html>
2: <head>
3: <title>10.3. program Az include() függvény használata
PHP kód végrehajtására más fájlban</title>
4: </head>
5: <body>
6: <?php
10
7: include("10.4.program.php");
8: ?>
9: </body>
10: </html>

10.4. program PHP kódot tartalmazó beágyazott fájl


1: <?php
2: print "Engem ágyaztak be!!<br>""
3: print "De most már össze tudok adni ... 4 + 4 = ".(4+4);
4: ?>

A PHP 4-ben a beágyazott fájlokban szereplõ kódnak ugyanúgy lehet visszatérési


értéket adni, mint a függvényeknek. A visszatérési értéket a fájl vége elõtt egy
return utasítás után kell meghatározni. A 10.5. és 10.6. példákban olyan fájlokat
ágyazunk be a dokumentumba, amelyeknek visszatérési értékük van.

10.5. program PHP kód végrehajtása és visszatérési érték megadása


az include() függvény használatával
1: <html>
2: <head>
3: <title>10.5. program PHP kód végrehajtása és
visszatérési érték megadása az include()
függvény használatával</title>
4: </head>
5: <body>
6: <?php
7: $eredmeny = include("10.6.program.php");
8: print "A visszatérési érték $eredmeny";
9: ?>
10: </body>
11: </html>
10_ora.qxd 8/3/2001 6:20 PM Page 174

174 10. óra

10.6. program Visszatérési értékkel rendelkezõ beágyazott fájl


1: <?php
2: $vissza = ( 4 + 4 );
3: return $vissza;
4: ?>
5: Ez a HTML soha nem jelenik meg, mert a visszatérés
után írtuk!

PHP 3 használatakor a beágyazott fájlnak csak akkor lehet


visszatérési értéket adni a return utasítással, ha függvényben
szerepel. A 10.6. példa a PHP 3-ban hibát okoz.

Ha az include() függvényt alkalmazzuk, megadhatunk feltételeket is. A meg-


adott fájlt csak akkor ágyazza be az include(), ha a fájlra teljesülnek a feltételek.
A következõ kódban található beágyazás soha nem fog végrehajtódni:

$proba = false;
if ( $proba )
{
include( "egy_fajl.txt" ); //nem ágyazza be
}

Ha az include() függvényt ciklusban használjuk, az include()-ban megadott


fájl tartalma minden ismétlésnél bemásolódik és a fájlban lévõ kód minden hívásnál
végrehajtódik. A 10.7. példában található kódban az include() függvény egy
for ciklus belsejében szerepel. Az include() paramétere minden ismétlésnél
más fájlra mutat.

10.7. program Az include() használata cikluson belül


1: <html>
2: <head>
3: <title>10.7. program Az include() használata ciklu-
son belül</title>
4: </head>
5: <body>
6: <?php
7: for ( $x = 1; $x<=3; $x++ )
8: {
9: $incfajl = "incfajl$x.txt";
10_ora.qxd 8/3/2001 6:20 PM Page 175

Fájlok használata 175

10.7. program (folytatás)


10: print "Megpróbálom beágyazni az $incfajl –t";
11: include( "$incfajl" );
12: print "<p>";
13: }
14: ?>

10
15: </body>
16: </html>

A 10.7. programban található kód futás közben három különbözõ fájlt ágyaz be,
ezek az "incfajl1.txt", "incfajl2.txt" és "incfajl3.txt".
Mindegyik fájl tartalmazza a nevét és azt a szöveget, hogy beágyazták:

Megpróbálom beágyazni az incfajl1.txt -t


Ez a fájl az incfajl1.txt
Megpróbálom beágyazni az incfajl2.txt -t
Ez a fájl az incfajl2.txt
Megpróbálom beágyazni az incfajl3.txt -t
Ez a fájl az incfajl3.txt

Rendelkezésre áll egy másik PHP függvény is, a require(), amely


hasonlóan mûködik az include()-hoz. Ciklusban azonban
a require() nem használható úgy, mint az include(), ugyanis
a require() a program futásának kezdetekor helyettesítõdik be.
Még egy fontos különbség a két függvény között, hogy
a require()-nak nem lehet visszatérési értéke a PHP 4-esben.

Fájlok vizsgálata
Mielõtt elkezdünk ismerkedni a fájlokkal és könyvtárakkal, fussunk át néhány
velük kapcsolatos tudnivalót. A PHP 4 igen sok lehetõséget ad arra, hogy a rend-
szerünkben található fájlokon különbözõ mûveleteket hajtsunk végre. A következõ
bekezdésekben ezeket a függvényeket tekintjük át.

Fájl létezésének ellenõrzése a file_exists() függvénnyel


Fájl létezését a file_exists() függvénnyel vizsgálhatjuk. A file_exists()
paramétere egy karakterlánc, amely a kérdéses fájl elérési útját és nevét tartalmazza.
A függvény visszatérési értéke true, ha a fájl létezik, egyébként false.
10_ora.qxd 8/3/2001 6:20 PM Page 176

176 10. óra

if ( file_exists("proba.txt") )
print("A fájl létezik!");

Fájl vagy könyvtár?


Az is_file() függvény azt dönti el, hogy paramétere fájl-e. A paraméterben
meg kell adnunk egy elérési utat. Ha a megadott elérési út fájlt jelöl, a függvény
visszatérési értéke true, egyébként false lesz.

if ( is_file( "proba.txt" ) )
print("a proba.txt egy fájl");

Ellenõrizhetjük azt is, hogy az elérési út könyvtárat jelöl-e. Az ellenõrzést


az is_dir() függvény végzi. Ha a függvény paraméterében megadott elérési út
könyvtárat határoz meg, a visszatérési érték true, egyébként false lesz.

if ( is_dir( "/tmp" ) )
print "a /tmp egy könyvtár";

Fájl állapotának lekérdezése


Miután megtudtuk, hogy egy fájl létezik és valóban fájl, különféle dolgokat végez-
hetünk vele. Általában írunk bele, olvassuk vagy végrehajtjuk. A PHP-ben külön-
bözõ függvények állnak rendelkezésre ezen lehetõségek lekérdezésére.

Az is_readable() függvénnyel megtudhatjuk, hogy az adott fájl olvasható-e


számunkra. UNIX rendszerben lehet, hogy látjuk a fájlt a könyvtárszerkezetben, de
nincs jogosultságunk annak olvasására. Ha az is_readable() paraméterében
elérési úttal megadott fájl olvasható, visszatérési értéke true, egyébként false lesz.

if ( is_readable( "proba.txt" ) )
print "a proba.txt olvasható";

Az is_writeable() függvénnyel megtudhatjuk, hogy az adott fájl írható-e


számunkra. Ha az is_writeable() paraméterében elérési úttal megadott fájl
írható, visszatérési értéke true, egyébként false lesz.

if ( is_writeable( "proba.txt" ) )
print "a proba.txt írható";

Az is_executable() függvénnyel azt tudhatjuk meg, hogy az adott fájl futtat-


ható-e. A visszatérési érték jogosultságunktól és a fájl kiterjesztésétõl függ.
Ha az is_executable() paraméterében elérési úttal megadott fájl futtatható,
a visszatérési érték true, egyébként false lesz.
10_ora.qxd 8/3/2001 6:20 PM Page 177

Fájlok használata 177

if ( is_executable( "proba.txt" )
print "a proba.txt futtatható";

Fájl méretének lekérdezése a filesize() függvénnyel


A filesize() függvény a paraméterében elérési úttal megadott fájl bájtban
számított méretével tér vissza. A végeredmény false, ha bármilyen hiba történik.

print "A proba.txt mérete: ";


10
print filesize( "proba.txt" );

Különféle fájlinformációk
Szükségünk lehet rá, hogy tudjuk, mikor hozták létre a fájlt vagy mikor használták
utoljára. A PHP-vel ezeket az információkat is megszerezhetjük.

A fájl utolsó megnyitásának dátumát a fileatime() függvény segítségével


kaphatjuk meg. A függvény paraméterében meg kell adni a fájl elérési útját.
Visszatérési értékként az utolsó megnyitás dátumát kapjuk meg. A megnyitás
jelenthet írást vagy olvasást is. Ezen függvények visszatérési értéke UNIX idõbé-
lyeg formátumú, azaz mindig az 1970 január elseje óta eltelt másodpercek száma.
A következõ példában ezt a számot a date() függvény segítségével olvasható
formára alakítjuk. A date() függvény leírása a tizenötödik órában szerepel.

$atime = fileatime( "proba.txt" );


print "A proba.txt legutolsó megnyitásának dátuma:";
print date("Y.m.d. H:i", $atime);
//Egy minta végeredmény: 2000.01.23. 14:26

A filemtime() függvénnyel a fájl utolsó módosításának idejét kaphatjuk meg.


A függvény paramétere a fájl elérési útja, visszatérési értéke pedig UNIX idõbélyeg
formátumú. A módosítás azt jelenti, hogy a fájl tartalma valamilyen módon
megváltozott.

$mtime = filemtime( "proba.txt" );


print "A proba.txt utolsó módosításának dátuma:";
print date("Y.m.d. H:i", $mtime);
//Egy minta végeredmény: 2000.01.23. 14:26

A filectime() a fájl utolsó változásának idõpontját adja meg. UNIX rendszer-


ben a változás alatt azt értjük, amikor a fájl tartalma valamilyen módon módosul
vagy a jogosultságok, illetve a tulajdonos megváltozik. Más rendszerekben
a filectime() visszatérési értéke a fájl létrehozásának dátuma.
10_ora.qxd 8/3/2001 6:20 PM Page 178

178 10. óra

$ctime = filectime( "proba.txt" );


print "A proba.txt utolsó változásának dátuma:";
print date("Y.m.d. H:i", $ctime);
//Egy minta végeredmény: 2000.01.23. 14:26

Több fájltulajdonságot egyszerre megadó függvény


A 10.8. példában olyan függvényt hozunk létre, amely az elõzõekben látott lehetõ-
ségeket fogja össze egyetlen függvényben.

10.8. program Egyszerre több fájltulajdonságot megadó függvény


1: <html>
2: <head>
3: <title>10.8. program Egyszerre több fájltulajdonságot
megadó függvény</title>
4: </head>
5: <body>
6: <?php
7: $fajl = "proba.txt";
8: fileInformaciok( $fajl );
9: function fileInformaciok( $f )
10: {
11: if ( ! file_exists( $f ) )
12: {
13: print "$f nem létezik <BR>";
14: return;
15: }
16: print "$f ".(is_file( $f )?"":"nem ")."fájl<br>"
17: print "$f ".(is_dir( $f )?"":"nem ").
"könyvtár<br>"
18: print "$f ".(is_readable( $f )?"":"nem ").
"olvasható<br>"
19: print "$f ".(is_writeable( $f )?"":"nem ").
"írható<br>"
20: print "$f ".(is_executable( $f )?"":"nem ").
"futtatható<br>"
21: print "$f ".(filesize( $f ))."bájt méretû<br>"
22: print "$f utolsó megnyitásának dátuma: ".
date( "Y.m.d. H:i", fileatime( $f ) ).
"<br>";
23: print "$f utolsó módosításának dátuma: ".
date( "Y.m.d. H:i", filemtime( $f ) ).
"<br>";
10_ora.qxd 8/3/2001 6:20 PM Page 179

Fájlok használata 179

10.8. program (folytatás)


24: print "$f utolsó változásának dátuma: ".
date( "Y.m.d. H:i", filectime( $f ) ).
"<br>";
25: }
26:
27: ?>
28: </body>
29: </html>
10

Az egyszerûbb leírás kedvéért ? : mûveleteket használtunk. Nézzük meg ezek


közül az egyiket:

print "$f ".(is_file( $f )?"":"nem ")."fájl<br>"

A mûveletjel bal oldalára került az is_file() függvény. Ha ennek eredménye


true, akkor az operátor visszatérési értéke üres karakterlánc, egyébként a "nem "
szöveg. A visszatérési érték után a szövegösszefûzés jelet követõ karakterlánc is ki-
íródik. Az elõbbi kifejezés kevésbé tömör formában a következõképpen írható le:

$igen_vagy_nem = is_file( $f ) ? "" : "nem ";


print "$f $igen_vagy_nem"."fájl<br>"

Az if vezérlési szerkezettel még világosabb kódot írhatunk, ekkor azonban


a program mérete jelentõsen nõ.

if ( is_file( $f ) )
print "$f fájl<br>";
else
print "$f nem fájl<br>";

Mivel az elõzõ példák ugyanannak a feladatnak a megoldásai, szabadon választ-


hatjuk ki a nekünk tetszõt.

Fájlok létrehozása és törlése


Ha egy fájl nem létezik, a touch() függvény segítségével hozhatjuk létre.
A függvény paraméterében meg kell adni egy elérési utat. Ezen az elérési úton
próbál meg létrehozni a touch() egy üres fájlt. Ha a fájl már létezik, tartalma
nem változik meg, de a módosítás dátuma a touch() függvény végrehajtási
idejére módosul.
10_ora.qxd 8/3/2001 6:20 PM Page 180

180 10. óra

touch("sajat_fajl.txt");

Létezõ fájlt törölni az unlink() függvénnyel lehet. Az unlink() paramétere


a fájl elérési útja:

unlink("sajat_fajl.txt");

A létrehozás, törlés, írás, olvasás, módosítás csak akkor lehetséges egy fájlon,
ha a megfelelõ jogosultságokkal rendelkezünk.

Fájl megnyitása írásra, olvasásra, hozzáfûzésre


Mielõtt elkezdünk dolgozni egy fájllal, meg kell nyitnunk írásra vagy olvasásra.
Ezt az fopen() függvénnyel tehetjük meg. A függvény paraméterében meg kell
adni a fájl elérési útját és a megnyitási módot. A legtöbbször használt módok
az olvasás ("r"), írás ("w"), hozzáfûzés ("a"). A függvény visszatérési értéke
egy egész szám. Ez az egész szám az úgynevezett fájlazonosító, amelyet változó-
ként tárolhatunk. Ezzel hivatkozhatunk késõbb a fájlra. Fájl olvasásra való
megnyitásához a következõt kell beírnunk:

$fa = fopen( "proba.txt", 'r' );

Az írásra való megnyitáshoz a következõt:

$fa = fopen( "proba.txt", 'w' );

Ha a fájlt hozzáfûzésre akarjuk megnyitni, tehát nem kívánjuk felülírni a tartalmát,


csak a végéhez szeretnénk fûzni valamit, a következõt kell tennünk:

$fa = fopen( "proba.txt", 'a' );

Az fopen() false értékkel tér vissza, ha valamiért nem tudta megnyitni a fájlt,
ezért érdemes mindig ellenõrizni, hogy sikeres volt-e a megnyitás. Ezt például
az if vezérlési szerkezettel tehetjük meg:

if ( $fa = fopen( "proba.txt", "w" ) )


{
// $fa-val csinálunk valamit
}

Esetleg használhatunk logikai mûveletet, hogy megszakítsuk a végrehajtást,


ha a fájl nem létezik:
10_ora.qxd 8/3/2001 6:20 PM Page 181

Fájlok használata 181

( $fa = fopen( "proba.txt", "w" ) ) or die


å ("A fájl sajnos nem nyitható meg!");

Ha az fopen() true értékkel tér vissza, a die() nem hajtódik végre, különben
a kifejezés jobb oldalán a die() kiírja a paraméterében szereplõ karakterláncot és
megszakítja a program futását.

Amikor befejeztük a munkát egy fájllal, mindig be kell zárnunk azt. Ezt az fclose()
függvénnyel tehetjük meg, amelynek paraméterében azt a fájlazonosítót kell megad-
10
nunk, amelyet egy sikeres fopen() végrehajtása során kaptunk:

fclose( $fa );

Olvasás fájlból
A PHP-ben egy fájlból különbözõ függvények segítségével bájtonként, soronként
vagy karakterenként olvashatunk.

Sorok olvasása fájlból az fgets() és


feof() függvényekkel
Miután megnyitottunk egy fájlt, beolvashatjuk a tartalmát sorról sorra, az fgets()
függvénnyel. A függvény paraméterében meg kell adni az olvasandó fájl azonosító-
ját (amit az fopen() függvény ad a megnyitáskor), továbbá második paraméter-
ként kell adnunk egy egész számot is, amely meghatározza, hogy legfeljebb hány
bájtot olvasson ki a PHP, amíg sorvége vagy fájlvége jelet nem talál. Az fgets()
függvény addig olvas a fájlból, amíg újsor karakterhez ("\n") nem ér, a megadott
bájtnyi adatot ki nem olvassa vagy a fájl végét el nem éri.

$sor = fgets( $fa, 1024 ); // ahol az $fa az fopen() által


å visszaadott fájlazonosító

Tudnunk kell tehát, mikor érünk a fájl végére. Ezt az feof() függvény adja meg,
melynek visszatérési értéke true, ha a fájl végére értünk, egyébként false.
A függvény paraméterében egy fájlazonosítót kell megadni.

feof( $fa ); // ahol az $fa az fopen() által visszaadott


å fájlazonosító

A 10.9. példában láthatjuk, hogyan kell egy fájlt sorról sorra beolvasni.
10_ora.qxd 8/3/2001 6:20 PM Page 182

182 10. óra

10.9. program Fájl megnyitása és sorról sorra olvasása


1: <html>
2: <head>
3: <title>10.9. program Fájl megnyitása és sorról sorra
olvasása</title>
4: </head>
5: <body>
6: <?php
7: $fajlnev = "proba.txt";
8: $fa = fopen( $fajlnev, "r" ) or die("$fajlnev nem
nyitható meg");
9: while ( ! feof( $fa ) )
10: {
11: $sor = fgets( $fa, 1024 );
12: print "$sor<br>";
13: }
14: fclose($fa);
15: ?>
16: </body>
17: </html>

Az fopen() függvénnyel próbáljuk olvasásra megnyitni a fájlt. Ha a kísérlet sikerte-


len, a die() függvénnyel megszakítjuk a program futását. Ez legtöbbször akkor tör-
ténik meg, ha a fájl nem létezik vagy (UNIX rendszerben) nincs megfelelõ jogosultsá-
gunk a megnyitásra. Az olvasás a while ciklusban történik. A while ciklus minden
ismétlés alkalmával megnézi az feof() függvénnyel, hogy az olvasás elért-e a fájl
végéhez, tehát a ciklus addig olvas, amíg el nem éri a fájl végét. Az fgets() minden
ismétlésnél kiolvas egy sort vagy 1024 bájtot. A kiolvasott karaktersorozatot a $sor
változóba mentjük és kiírjuk a böngészõbe. Minden kiírásnál megadunk egy <br>
címkét, hogy a szöveg olvashatóbb legyen, végül bezárjuk a megnyitott állományt.

Tetszõleges mennyiségû adat olvasása fájlból


A fájlokból nem csak soronként, hanem elõre meghatározott méretû darabokat is
olvashatunk. Az fread() függvény paraméterében meg kell adni egy fájlazonosí-
tót és az egyszerre kiolvasandó adatok mennyiségét, bájtban. A függvény visszaté-
rési értéke a megadott mennyiségû adat lesz, kivéve, ha elérte a fájl végét.

$reszlet = fread( $fa, 16 );


10_ora.qxd 8/3/2001 6:20 PM Page 183

Fájlok használata 183

A 10.10. példaprogram 16 bájtonként olvassa be a fájlt.

10.10. program Fájl beolvasása az fread() függvénnyel


1: <html>
2: <head>
3: <title>10.10. program Fájl beolvasása az fread()

4: </head>
függvénnyel</title> 10
5: <body>
6: <?php
7: $fajlnev = "proba.txt";
8: $fa = fopen( $fajlnev, "r" ) or die("$fajlnev nem
nyitható meg");
9: while ( ! feof( $fa ) )
10: {
11: $reszlet = fread( $fa, 16 );
12: print "$reszlet<br>";
13: }
14: fclose($fa);
15: ?>
16: </body>
17: </html>

Bár az fread() függvénynek megadjuk, mennyi adatot olvasson ki, azt nem tudjuk
meghatározni, hogy honnan kezdje az olvasást. Erre az fseek() ad lehetõséget,
ezzel a függvénnyel állítható be az olvasás helye. Paraméterként egy fájlazonosítót
és egy egész számot kell megadnunk, amely a fájl elejétõl bájtban mérve meghatá-
rozza az új olvasási helyet:

fseek( $fa, 64 );

A 10.11. példában az fseek() és fread() függvényekkel a fájl tartalmának


második felét jelenítjük meg a böngészõben.

10.11. program Az fseek() használata


1: <html>
2: <head>
3: <title>10.11. program Az fseek() használata</title>
4: </head>
10_ora.qxd 8/3/2001 6:20 PM Page 184

184 10. óra

10.11. program (folytatás)


5: <body>
6: <?php
7: $fajlnev = "proba.txt";
8: $fa = fopen( $fajlnev, "r" ) or die("$fajlnev nem
nyitható meg");
9: $fajlmeret = filesize($fajlnev);
10: $felmeret = (int)( $fajlmeret / 2 );
11: print "A fájl felének mérete: $felmeret <br>\n"
12: fseek( $fa, $felmeret );
13: $reszlet = fread( $fa, ($fajlmeret - $felmeret) );
14: print $reszlet;
15: fclose($fa);
16: ?>
17: </body>
18: </html>

A felezõpontot úgy számoltuk ki, hogy a filesize() függvénnyel lekértük a fájl


méretét és elosztottuk kettõvel. Ezt az értéket használtuk az fseek() második
paramétereként. Végül az fread() segítségével kiolvastuk a fájl második felét és
kiírtuk a böngészõbe.

Fájl karakterenkénti olvasása az fgetc() függvénnyel


Az fgetc() függvény hasonlít az fgets() függvényhez, de minden alkalommal,
amikor meghívjuk, csak egyetlen karaktert olvas ki a fájlból. Mivel egy karakter
mindig egy bájt méretû, más paramétert nem kell megadnunk, csak a már
megszokott fájlazonosítót:

$karakter = fgetc( $fa );

A 10.12. példaprogram egy ciklus segítségével karakterenként kiolvassa


a "proba.txt" tartalmát és minden karaktert külön sorba ír ki a böngészõbe.

10.12. program Az fgetc() használata


1: <html>
2: <head>
3: <title>10.12. program Az fgetc() használata</title>
4: </head>
5: <body>
10_ora.qxd 8/3/2001 6:20 PM Page 185

Fájlok használata 185

10.12. program (folytatás)


6: <?php
7: $fajlnev = "program.txt";
8: $fa = fopen( $fajlnev, "r" ) or die("$fajlnev nem
nyitható meg");
9: while ( ! feof( $fa ) )
10: {
11:
12:
$karakter = fgetc( $fa );
print "$karakter<br>";
10
13: }
14: fclose($fa);
15: ?>
16: </body>
17: </html>

Fájlba írás és hozzáfûzés


A fájlba írás és a hozzáfûzés nagyon hasonlítanak egymáshoz. Az egyetlen különbség
az fopen() hívásában rejlik. Amikor írásra nyitjuk meg a fájlt, akkor az fopen()
második paramétereként a "w" karaktert kell megadnunk:

$fa = fopen( "proba.txt", "w" );

Minden írási próbálkozás a fájl elején történik. Ha a fájl még nem létezne, a rend-
szer létrehozza azt. Ha a fájl létezik, tartalma felülíródik a megadott adatokkal.

Ha a fájlt hozzáfûzésre nyitjuk meg, az fopen() második paramétereként az "a"


karaktert kell megadnunk:

$fa = fopen( "proba.txt", "a" );

Hozzáfûzésnél minden adat a fájl végére íródik, megtartva az elõzõ tartalmat.

Fájlba írás az fwrite() és fputs() függvényekkel


Az fwrite() függvény paramétereként egy fájlazonosítót és egy karakterláncot
kell megadni. A karakterlánc a megadott fájlba íródik. Az fputs() ugyanígy
mûködik.

fwrite( $fa, "hello világ" );


fputs( $fa, "hello világ" );
10_ora.qxd 8/3/2001 6:20 PM Page 186

186 10. óra

A 10.13. példában elõször az fwrite() függvény használatával egy fájlba írunk,


majd az fputs() függvénnyel adatokat fûzünk hozzá.

10.13. program Fájlba írás és hozzáfûzés


1: <html>
2: <head>
3: <title>10.11. program Fájlba írás és
hozzáfûzés</title>
4: </head>
5: <body>
6: <?php
7: $fajlnev = "proba.txt";
8: print "$fajlnev fájlba írás";
9: $fa = fopen( $fajlnev, "w" ) or die("$fajlnev nem
nyitható meg");
10: fwrite ( $fa, "Hello világ\n");
11: fclose( $fa );
12: print "$fajlnev fájlhoz hozzáfûzés";
13: $fa = fopen( $fajlnev, "a" ) or die("$fajlnev nem
nyitható meg");
14: fputs ( $fa, "És más dolgok");
15: fclose( $fa );
16: ?>
17: </body>
18: </html>

Fájlok zárolása az flock() függvénnyel


Az eddig megtanultak igen jól használhatók, ha programjaink csak egyetlen
felhasználót szolgálnak ki. A valóságban azonban egy alkalmazás oldalait általában
többen is el szeretnék érni egyidõben. Képzeljük el, mi történne, ha egyszerre két
felhasználó írna ugyanabba a fájlba. A fájl használhatatlanná válna.

Az flock() függvény használatával kizárhatjuk ezt a lehetõséget. Az flock()


függvénnyel zárolt fájlt nem olvashatja vagy írhatja más folyamat, amíg a zárolás
érvényben van. Az flock() függvény paramétereként egy fájlazonosítót és egy
egész számot kell megadni. Ez utóbbi a zárolás típusát határozza meg. A lehetséges
zárolásokat a 10.1. táblázat mutatja.
10_ora.qxd 8/3/2001 6:20 PM Page 187

Fájlok használata 187

10.1. táblázat Az flock() függvény második paraméterének lehetséges értékei


Egész Lezárás típusa Leírás
1 Megosztott Más folyamatok olvashatják a fájlt,
de nem írhatnak bele (akkor használjuk,
amikor olvassuk a fájlt)
2 Kizáró Más folyamatok nem olvashatják és nem
írhatják a fájlt (akkor használjuk, 10
amikor írunk a fájlba)
3 Felszabadítás A fájl zárolásának megszüntetése

Az flock() függvényt a fájl megnyitása után alkalmazzuk zárolásra és


az fclose() elõtt oldjuk fel vele a zárat.

$fa = fopen( "proba.txt", "a" );


flock( $fa, 2 ); // kizáró lefoglalás
// fájlba írás
flock( $fa, 3 ); // zárolás feloldása
fclose( $fa );

Az flock() a PHP zárolási megoldása. Csak azok a programok


veszik figyelembe ezt a fajta zárolást, ahol ugyanezt a módszert
alkalmazzuk, ezért elõfordulhat, hogy a nem-PHP programok
megnyitják a fájlunkat, akár írás közben is.

Munka könyvtárakkal
Az elõzõekben áttekintettük, hogyan kezelhetjük a fájlokat, most megnézzük,
hogyan hozhatunk létre, törölhetünk és olvashatunk könyvtárakat a PHP-ben.

Könyvtár létrehozása az mkdir() függvénnyel


Könyvtárat az mkdir() függvénnyel hozhatunk létre. Az mkdir() paraméteré-
ben meg kell adni egy karakterláncot, amely a létrehozandó könyvtár elérési útja,
valamint egy oktális (nyolcas számrendszerû) számot, amely a jogosultságokat
határozza meg. Az oktális számok elé mindig 0-t kell írni. A jogosultság megadásá-
nak csak UNIX rendszerekben van hatása. A jogosultsági mód három 0 és 7 közé
esõ számot tartalmaz, amelyek sorban a tulajdonos, a csoport, és mindenki más
10_ora.qxd 8/3/2001 6:20 PM Page 188

188 10. óra

jogait adják meg. A függvény visszatérési értéke true, ha a könyvtárat sikerült


létrehozni, egyébként false. A könyvtár létrehozása általában akkor nem sikeres,
ha a megadott elérési úton nincs jogosultságunk könyvtárat létrehozni, azaz nincs
jogosultságunk írásra.

mkdir( "proba_konyvtar", 0777 ); // teljes


å írás/olvasás/végrehajtás jogok

Könyvtár törlése az rmdir() függvénnyel


A rendszerbõl könyvtárat az rmdir() függvénnyel törölhetünk. A sikeres törlés-
hez megfelelõ jogosultsággal kell rendelkeznünk és a könyvtárnak üresnek kell
lennie. A függvény paraméterében a törlendõ könyvtár elérési útját kell megadni.

rmdir( "proba_konyvtar" );

Könyvtár megnyitása olvasásra


Mielõtt be tudnánk olvasni egy könyvtár tartalmát, szükségünk van egy könyvtára-
zonosítóra. Ezt az azonosítót az opendir() függvény adja meg. A függvény
paraméterében annak a könyvtárnak az elérési útját kell átadni, amelyet olvasni
szeretnénk. A függvény visszatérési értéke a könyvtár azonosítója, kivéve,
ha a könyvtár nem létezik vagy nincs jogosultságunk az olvasására. Ezekben
az estekben a visszatérési érték false.

$kvt = opendir( "proba_konyvtar" );

Könyvtár tartalmának olvasása


Ahogy az fgets() függvénnyel fájlból olvastunk, ugyanúgy használhatjuk
a readdir() függvényt, hogy fájl vagy könyvtárnevet olvassunk ki egy megnyitott
könyvtárból. A readdir() paraméterében meg kell adni az olvasandó könyvtár
azonosítóját. A függvény visszatérési értéke a könyvtár következõ elemének neve.
Ha a könyvtár végére értünk, a visszatérési érték false. A readdir() csak az elem
nevét és nem annak elérési útját adja meg. A 10.4. példában a readdir() függvény
használati módját láthatjuk.

10.14. program Könyvtár tartalmának kiíratása


1: <html>
2: <head>
3: <title>10.14. program Könyvtár tartalmának
kiíratása</title>
4: </head>
10_ora.qxd 8/3/2001 6:20 PM Page 189

Fájlok használata 189

10.14. program (folytatás)


5: <body>
6: <?php
7: $kvtnev = "proba_konyvtar";
8: $kvt = opendir( $kvtnev );
9: while ( gettype( $fajl = readdir( $kvt )) != boolean )

10
10: {
11: if ( is_dir( "$kvtnev/$fajl" ) )
12: print "(D)";
13: print "$fajl<br>";
14: }
15: closedir( $kvt );
16: ?>
17: </body>
18: </html>

A könyvtárat megnyitjuk az opendir() függvénnyel, majd egy while ciklussal vé-


giglépkedünk annak összes elemén. A while ciklus feltételes kifejezésében meg-
hívjuk a readdir() függvényt és a visszaadott értéket hozzárendeljük a $fajl
változóhoz. A ciklus törzsében az is_dir() függvénnyel vizsgáljuk, hogy
a $kvtnev és a $fajl változókból készített elérési út könyvtárat jelöl-e. Ha igen,
neve elé teszünk egy "(D)" jelet. Így kiírjuk a böngészõbe a könyvtár tartalmát.

A while ciklus feltételes kifejezésének megírásakor igen elõvigyázatosak voltunk.


Sok PHP programozó a következõt használta volna:

while ( $fajl = readdir( $kvt ) )


{
print "$fajl<br>\n";
}

Itt a readdir() visszatérési értékét vizsgáljuk. Minden "0"-tól különbözõ karak-


terlánc true-ként viselkedik, tehát ebbõl nem lehet probléma. Mi történik, ha
könyvtárunk négy fájlt tartalmaz, melyek nevei "0", "1", "2", "3". Az elõbbi
kód a következõ végeredményt adja:

.
..

Amikor a ciklus eléri a "0" nevû fájlt, a readdir() false értéknek veszi és
a ciklus leáll. A 10.14. példában a readdir() függvény visszatérési értékének
típusát vizsgáljuk és ezzel oldjuk meg a problémát.
10_ora.qxd 8/3/2001 6:20 PM Page 190

190 10. óra

Összefoglalás
Ebben az órában megtanultuk, hogyan ágyazhatunk be a dokumentumokba külsõ
fájlban tárolt PHP kódot. Áttekintettük a fájlok különbözõ tulajdonságainak ellen-
õrzését, megnéztünk, hogyan olvashatunk fájlokat sorról sorra, karakterenként,
vagy meghatározott részletekben. Megtanultuk, hogyan írhatunk fájlba és hogyan
fûzhetünk karakterláncokat hozzá. Végül áttekintettük, hogyan hozhatunk létre,
törölhetünk, vagy listázhatunk ki könyvtárakat.

Kérdések és válaszok
Az include() függvény lassítja a programok futását?
Mivel a beágyazott fájlt meg kell nyitni és a tartalmát be kell olvasni, ezért azt kell
mondjuk, hogy igen, a lassulás azonban nem számottevõ.

Mindig le kell állítani a program futását, ha egy fájlt nem sikerült


megnyitni írásra vagy olvasásra?
Ha a program futásához elengedhetetlen a fájl, akkor a die() függvénnyel érde-
mes leállítani. Más esetben a program futását nem fontos megszakítani, de érdemes
figyelmeztetni a felhasználót a hibára vagy feljegyezni a sikertelen megnyitási kísér-
letet egy naplóállományba. A huszonkettedik órában többet olvashatunk errõl
a megoldásról.

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 adható programunkhoz külsõ kódot tartalmazó fájl?

2. Melyik függvénnyel tudjuk meg, hogy rendszerünkben megtalálható-e egy fájl?

3. Hogyan kapható meg egy fájl mérete?

4. Melyik függvénnyel nyitható meg egy fájl írásra vagy olvasásra?

5. Melyik függvénnyel olvashatunk ki egy sort egy fájlból?

6. Honnan tudhatjuk meg, hogy elértük a fájl végét?


10_ora.qxd 8/3/2001 6:20 PM Page 191

Fájlok használata 191

7. Melyik függvényt használjuk, hogy egy sort írjunk egy fájlba?

8. Hogyan nyitunk meg egy könyvtárt olvasásra?

9. Melyik függvényt használjuk, hogy egy könyvtár elemeinek nevét megkapjuk,


miután megnyitottuk azt?

Feladatok 10
1. Készítsünk egy oldalt, amely bekéri a felhasználó vezeték- és keresztnevét.
Készítsünk programot, amely ezen adatokat fájlba menti.

2. Készítsünk programot, amely az elõbbi feladatban mentett adatokat kiolvassa


a fájlból. Írjuk ki azokat a böngészõbe (minden sor végén használjunk <BR>
címkét). Írjuk ki, hány sort tartalmaz a fájl, illetve a fájl méretét.
10_ora.qxd 8/3/2001 6:20 PM Page 192
11_ora.qxd 8/3/2001 6:20 PM Page 193

11. ÓRA
A DBM függvények használata
Ha nem is férünk hozzá valamilyen SQL adatbáziskezelõhöz (mint a MySQL vagy
az Oracle), majdnem biztos, hogy valamilyen DBM-szerû adatbázisrendszer ren-
delkezésünkre áll. Ha mégsem, a PHP akkor is képes utánozni számunkra egy
ilyen rendszer mûködését. A DBM függvények segítségével lényegében név–érték
párokat tárolhatunk és kezelhetünk.

Noha ezek a függvények nem biztosítják számunkra egy SQL adatbázis erejét, ru-
galmasak és könnyen használhatók. Mivel a formátum igen elterjedt, az e függvé-
nyekre épülõ kód általában hordozható, noha maguk a DBM adatokat tartalmazó
állományok nem azok.

Ebben az órában a következõ témákkal foglalkozunk:

• Megtanuljuk a DBM adatbázisok kezelését.


• Adatokkal töltünk fel egy adatbázist.
• Visszanyerjük adatainkat egy adatbázisból.
• Elemeket módosítunk.
• Megtanuljuk, hogyan tároljunk bonyolultabb adatokat egy DBM adatbázisban.
11_ora.qxd 8/3/2001 6:20 PM Page 194

194 11. óra

DBM adatbázis megnyitása


A DBM adatbázisokat a dbmopen() függvénnyel nyithatjuk meg, amelynek két
paramétert kell átadnunk: a DBM fájl elérési útvonalát és a megnyitás módjára
vonatkozó kapcsolókat. A függvény egy különleges DBM azonosítóval tér vissza,
amelyet aztán a különbözõ egyéb DBM függvényekkel az adatbázis elérésére és
módosítására használhatunk fel. Mivel a dbmopen()egy fájlt nyit meg írásra vagy
olvasásra, a PHP-nek joga kell, hogy legyen az adatbázist tartalmazó könyvtár
elérésére.

A dbmopen() függvénynek a 11.1. táblázatban felsorolt kapcsolókkal adhatjuk


meg, milyen mûveleteket kívánunk végrehajtani az adatbázison.

11.1. táblázat A dbmopen() kapcsolói


Kapcsoló Jelentés
r Az adatbázist csak olvasásra nyitja meg.
w Az adatbázist írásra és olvasásra nyitja meg.
c Létrehozza az adatbázist (ha létezik, akkor írásra/olvasásra
nyitja meg).
n Létrehozza az adatbázist (ha már létezik ilyen nevû, törli
az elõzõ változatot).

A következõ kódrészlet megnyit egy adatbázist, ha pedig nem létezne a megadott


néven, újat hoz létre:

$dbm = dbmopen( "./adat/termekek", "c" ) or


å die( "Nem lehet megnyitni a DBM adatbázist." );

Vegyük észre, hogy ha nem sikerülne az adatbázis megnyitása, a program futását


a die() függvénnyel fejezzük be.

Ha befejeztük a munkát, zárjuk be az adatbázist a dbmclose() függvénnyel.


Ez azért szükséges, mert a PHP automatikusan zárolja a megnyitott DBM adatbázist,
hogy más folyamatok ne férhessenek hozzá a fájlhoz, mialatt a tartalmát olvassuk
vagy írjuk. Ha az adatbázist nem zárjuk be, a várakozó folyamatok azután sem érhe-
tik el az adatbázist, amikor már befejeztük a munkát. A dbmclose() függvény
paramétere egy érvényes DBM azonosító:

dbmclose ( $dbm );
11_ora.qxd 8/3/2001 6:20 PM Page 195

A DBM függvények használata 195

Adatok felvétele az adatbázisba


Új név–érték párt a dbminsert() függvénnyel vehetünk fel az adatbázisba.
A függvénynek három paramétere van: egy érvényes DBM azonosító (amelyet
a dbmopen() adott vissza), a kulcs és a tárolandó érték. A visszatérési érték 0,
ha sikeres volt a mûvelet; 1, ha az elem már szerepel az adatbázisban; és -1
bármilyen más hiba esetén (például írási kísérlet egy csak olvasásra megnyitott
adatbázisba). A dbminsert()már létezõ elemet nem ír felül.

A 11.1. programban létrehozzuk és megnyitjuk a termekek nevû adatbázist és


feltöltjük adatokkal.

11.1. program Adatok felvétele DBM adatbázisba. 11


1: <html>
2: <head>
3: <title>11.1. program Adatok felvétele DBM adatbázis-
ba</title>
4: </head>
5: <body>
6: Termékek hozzáadása...
7:
8: <?php
9: $dbm = dbmopen( "./adat/termekek", "c" ) or
die( "Nem lehet megnyitni a DBM adatbázist." );
10:
11: dbminsert( $dbm, "Ultrahangos csavarhúzó", "23.20" );
12: dbminsert( $dbm, "Tricorder", "55.50" );
13: dbminsert( $dbm, "ORAC AI", "2200.50" );
14: dbminsert( $dbm, "HAL 2000", "4500.50" );
15:
16: dbmclose( $dbm );
17: ?>
18: </body>
19: </html>

Az adatbázisba illesztés során az összes érték karakterlánccá alakul, így a termé-


kek árainak megadásakor idézõjeleket kell használnunk. Természetesen az adat-
bázisból kiolvasás után ezeket az értékeket lebegõpontos számokként is kezelhet-
jük, amennyiben szükséges. Vegyük észre, hogy nem csak egyszavas kulcsokat
használhatunk.
11_ora.qxd 8/3/2001 6:20 PM Page 196

196 11. óra

Ha ezek után meghívjuk a dbminsert() függvényt egy olyan kulcsértékkel,


amely már létezik az adatbázisban, a függvény az 1 értéket adja vissza és nem
módosítja az adatbázist. Bizonyos körülmények között pontosan erre van szükség,
de elõfordulhat olyan eset is, amikor módosítani szeretnénk egy meglévõ adatot,
vagy ha nem található ilyen kulcs az adatbázisban, új adatot szeretnénk felvinni.

Adatok módosítása az adatbázisban


A DBM adatbázisban a bejegyzéseket a dbmreplace() függvénnyel módosít-
hatjuk. A függvény paraméterei: egy érvényes DBM azonosító, a kulcs neve és
az új érték. A visszatérési érték a hibakód: 0, ha minden rendben volt és –1,
ha valamilyen hiba lépett fel. A 11.2. példában az elõzõ program egy új változata
látható, amely a kulcsokat korábbi meglétüktõl függetlenül felveszi az adatbázisba.

11.2. program Elemek felvétele vagy módosítása DBM adatbázisban


1: <html>
2: <head>
3: <title>11.2. program Elemek felvétele vagy módosítása
DBM adatbázisban</title>
4: </head>
5: <body>
6: Termékek hozzáadása...
7: <?php
8: $dbm = dbmopen( "./adat/termekek", "c" )
9: or die( "Nem lehet megnyitni a DMB adatbá-
zist." );
10: dbmreplace( $dbm, "Ultrahangos csavarhúzó", "25.20" );
11: dbmreplace( $dbm, "Tricorder", "56.50" );
12: dbmreplace( $dbm, "ORAC AI", "2209.50" );
13: dbmreplace( $dbm, "HAL 2000", "4535.50" );
14: dbmclose( $dbm );
15: ?>
16: </body>
17: </html>

A program mûködésének módosításához mindössze át kell írnunk a dbminsert()


függvényhívást dbmreplace()-re.
11_ora.qxd 8/3/2001 6:20 PM Page 197

A DBM függvények használata 197

Adatok kiolvasása DBM adatbázisból


Egyetlen elemet a dbmfetch() függvény segítségével olvashatunk ki az adatbá-
zisból. Ebben az esetben két paramétert kell átadnunk: egy létezõ DBM azonosítót
és az elérni kívánt kulcs nevét. A függvény visszatérési értéke egy karakterlánc,
a kulcshoz tartozó érték lesz. A "Tricorder" elem árát például a következõ
függvényhívással kérdezhetjük le:

$ar = dbmfetch( $dbm, "Tricorder" );

Ha "Tricorder" elem nem található az adatbázisban, a dbmfetch()egy üres


karakterlánccal tér vissza.

Nem mindig ismerjük azonban az adatbázisban található kulcsokat. Mit tennénk


például akkor, ha ki kellene írni a böngészõablakba az összes terméket és a hoz-
11
zájuk tartozó árakat, anélkül, hogy „beleégetnénk” a programba a termékek nevét?
A PHP biztosít egy módszert, amellyel az adatbázisban szereplõ összes elemen
végiglépkedhetünk.

Az adatbázis elsõ kulcsát a dbmfirstkey() függvénnyel kérdezhetjük le.


A függvény paramétere egy érvényes DBM azonosító, visszatérési értéke pedig
a legelsõ kulcs. Természetesen ez nem feltétlenül egyezik meg az elsõként beil-
lesztett adattal, ugyanis a DBM adatbáziskezelõk gyakran saját rendezési eljárást
használnak. Miután megkaptuk a legelsõ kulcsot, az összes rákövetkezõ elemet
a dbmnextkey() függvény ismételt hívásával kérdezhetjük le. A függvény para-
méterként szintén egy érvényes DBM azonosítót vár, visszatérési értéke pedig
a következõ kulcs a sorban. Ha ezeket a függvényeket együtt használjuk
a dbmfetch()-csel, az adatbázis teljes tartalmát kiolvashatjuk.

A 11.3. példaprogram a termekek adatbázis teljes tartalmát kiírja a böngészõbe.

11.3. program DBM adatbázis összes bejegyzésének kiolvasása


1: <html>
2: <head>
3: <title>11.3. program DBM adatbázis összes bejegyzésének
4: kiolvasása</title>
5: </head>
6: <body>
7: A Hihetetlen Kütyük Boltja
8: a következõ izgalmas termékeket kínálja
9: Önnek:
11_ora.qxd 8/3/2001 6:20 PM Page 198

198 11. óra

11.3. program (folytatás)


10: <p>
11: <table border="1" cellpadding="5">
12: <tr>
13: <td align="center"> <b>Termék</b> </td>
14: <td align="center"> <b>Ár</b> </td>
15: </tr>
16: <?php
17: $dbm = dbmopen( "./adat/termekek", "c" )
18: or die( "Nem lehet megnyitni a DBM adatbázist."
);
19: $kulcs = dbmfirstkey( $dbm );
20: while ( $kulcs != "" )
21: {
22: $ertek = dbmfetch( $dbm, $kulcs );
23: print "<tr><td align = \"left\"> $kulcs </td>";
24: print "<td align = \"right\"> \$$ertek
</td></tr>";
25: $kulcs = dbmnextkey( $dbm, $kulcs );
26: }
27: dbmclose( $dbm );
28: ?>
29: </table>
30: </body>
31: </html>

A 11.1. ábrán a 11.3. program eredménye látható.

11.1. ábra
A DBM adatbázis
összes bejegyzésének
lekérdezése.
11_ora.qxd 8/3/2001 6:20 PM Page 199

A DBM függvények használata 199

Elemek meglétének lekérdezése


Mielõtt kiolvasnánk vagy módosítanánk egy elemet, hasznos lehet tudni, hogy
létezik-e egyáltalán ilyen kulcsú elem az adatbázisban vagy sem. Erre a célra
a dbmexists() függvény szolgál, amely paraméterként egy érvényes
DBM azonosítót vár, illetve az ellenõrizendõ elem nevét. A visszatérési érték
true, ha az elem létezik.

if ( dbmexists( $dbm, "Tricorder" ) )


print dbmfetch( $dbm, "Tricorder" );

Elem törlése az adatbázisból 11


Az adatbázisból elemeket a dbmdelete() függvénnyel törölhetünk. A függvény
bemenõ paramétere egy érvényes DBM azonosító és a törlendõ elem neve.
Sikeres törlés esetén a visszatérési érték true, egyéb esetben (például ha az elem
nem létezik) false.

dbmdelete( $dbm, "Tricorder" );

Összetett adatszerkezetek tárolása


DBM adatbázisban
A DBM adatbázisban minden adat karaktersorozat formájában tárolódik, ezért
az egész és lebegõpontos számokon, illetve karakterláncokon kívül minden egyéb
adattípus elvész. Próbáljunk meg például egy tömböt tárolni:

$tomb = array( 1, 2, 3, 4 );
$dbm = dbmopen( "./adat/proba", "c" ) or
å die("Nem lehet megnyitni a DBM adatbázist.");
dbminsert( $dbm, "tombproba", $tomb );
print gettype( dbmfetch( $dbm, "tombproba" ) );
// A kimenet: "string"

Itt létrehozunk egy tömböt és a $tomb változóba helyezzük. Ezután megnyitjuk az


adatbázist és beszúrjuk a tömböt tombproba néven, majd megvizsgáljuk
a dbmfetch() függvény visszatérési típusát, amikor megpróbáljuk visszaolvasni
a tombproba elemet – láthatjuk, hogy karakterláncot kaptunk vissza. Ha kiírattuk
volna a tombproba elem értékét, az "Array" karakterláncot kaptuk volna.
Úgy látszik, ezzel el is úszott minden reményünk arra, hogy tömböket vagy
más összetett adatszerkezetet tároljunk a DBM adatbázisban.
11_ora.qxd 8/3/2001 6:20 PM Page 200

200 11. óra

Szerencsére a PHP rendelkezik egy olyan lehetõséggel, amely segítségével


a bonyolultabb szerkezeteket is egyszerû karaktersorozattá alakíthatjuk.
Az így „kódolt” szerkezetet már tárolhatjuk késõbbi használatra, DBM adatbázisban
vagy akár fájlban is.

Az átalakítást a serialize() függvénnyel végezhetjük el, amelynek bemenõ


paramétere egy tetszõleges típusú változó, a visszaadott érték pedig egy karakterlánc:

$tomb = array( 1, 2, 3, 4 );
print serialize( $tomb );
// A kimenet: "a:4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;}"

A DBM adatbázisban ezt a karakterláncot tárolhatjuk. Ha vissza akarjuk állítani


eredeti formájára, az unserialize() függvényt kell használnunk.

Ezzel a módszerrel lehetõségünk nyílik összetett adatszerkezetek tárolására


a DBM adatbázisok által kínált egyszerû eszközökkel is. A 11.4. listában egy asszo-
ciatív tömb tartalmazza a termékekrõl rendelkezésre álló információkat – ezt ala-
kítjuk át karakterlánccá és helyezzük egy DBM adatbázisba.

11.4. program Összetett adatszerkezetek tárolása DBM adatbázisban


1: <html>
2: <head>
3: <title>11.4. program Összetett adatszerkezetek tárolása
DBM adatbázisban</title>
4: </head>
5: <body>
6: Összetett adatok tárolása
7: <?php
8: $termekek = array(
9: "Ultrahangos csavarhúzó" => array( "ar"=>"22.50",
10: "szallitas"=>"12.50",
11: "szin"=>"zöld" ),
12: "Tricorder" => array( "ar"=>"55.50",
13: "szallitas"=>"7.50",
14: "szin"=>"vörös" ),
15: "ORAC AI" => array( "ar"=>"2200.50",
16: "szallitas"=>"34.50",
17: "szin"=>"kék" ),
18: "HAL 2000" => array( "ar"=>"4500.50",
19: "szallitas"=>"18.50",
20: "szin"=>"rózsaszín" )
21: );
11_ora.qxd 8/3/2001 6:20 PM Page 201

A DBM függvények használata 201

11.4. program (folytatás)


22: $dbm = dbmopen( "./adat/ujtermekek", "c" )
23: or die("Nem lehet megnyitni a DBM adatbázist.");
24: foreach( $termekek as $kulcs => $ertek )
25: dbmreplace( $dbm, $kulcs, serialize( $ertek ) );
26: dbmclose( $dbm );
27: ?>
28: </body>
29: </html>

A listában egy többdimenziós tömböt építünk fel, amely kulcsként tartalmazza


a termék nevét és három tömbelemben tárolja a színt, az árat és a szállítás költségét.
Ezután egy ciklus segítségével feldolgozzuk az összes elemet: a termék nevét és
11
a karakterlánccá alakított tömböt átadjuk a dbmreplace() függvénynek. Ezután
lezárjuk az adatbázist.

A 11.5. program az adatok visszatöltésére ad megoldást.

11.5. program Összetett adatszerkezetek visszaolvasása DBM adatbázisból


1: <html>
2: <head>
3: <title>11.5. program Összetett adatszerkezetek
visszaolvasása
4: DBM adatbázisból</title>
5: </head>
6: <body>
7: A Hihetetlen Kütyük Boltja
8: a következõ izgalmas termékeket kínálja
9: Önnek:
10: <p>
11: <table border="1" cellpadding ="5">
12: <tr>
13: <td align="center"> <b>Termék</b> </td>
14: <td align="center"> <b>Szín</b> </td>
15: <td align="center"> <b>Szállítás</b> </td>
16: <td align="center"> <b>Ár</b> </td>
17: </tr>
18: <?php
11_ora.qxd 8/3/2001 6:20 PM Page 202

202 11. óra

11.5. program (folytatás)


19: $dbm = dbmopen( "./adat/ujtermekek", "c" )
20: or die(“Nem lehet megnyitni
a DBM adatbázist.");
21: $kulcs = dbmfirstkey( $dbm );
22: while ( $kulcs != "" )
23: {
24: $termektomb = unserialize( dbmfetch( $dbm,
$kulcs ) );
25: print "<tr><td align=\"left\"> $kulcs </td>";
26: print '<td align="left" $termektomb["szin"]
"</td>";
27: print '<td align="right"$
$termektomb["szallitas"] "</td>";
28: print '<td align="right"$ $termektomb["ar"]
"</td></tr>\n";
29: $kulcs = dbmnextkey( $dbm, $kulcs );
30: }
31: dbmclose( $dbm );
32: ?>
33: </table>
34: </body>
35: </html>

Ez a megoldás hasonló a 11.3. példában látottakhoz, de ebben az esetben több me-


zõt nyomtatunk ki. Megnyitjuk az adatbázist és a dbmfirstkey(), illetve
a dbmnextkey() függvénnyel beolvassuk az összes adatot az adatbázisból.
A ciklusban az unserialize() függvénnyel létrehozzuk a termékeket tartalmazó
tömböt. Így már egyszerû feladat kiíratni az összes elemet a böngészõablakba.
A 11.2. ábrán a 11.5. program kimenete látható.

11.2. ábra
Összetett adatszerke-
zetek visszaolvasása
DBM adatbázisból
11_ora.qxd 8/3/2001 6:20 PM Page 203

A DBM függvények használata 203

Egy példa
Már eleget tudunk ahhoz, hogy elkészítsünk egy mûködõképes programot
az ebben az órában tanult módszerekkel. A feladat a következõ: készítsünk egy
karbantartó oldalt, ahol a webhely szerkesztõje megváltoztathatja a 11.2. példa-
program által létrehozott adatbázis termékeinek árát. Tegyük lehetõvé a rendszer-
gazda számára, hogy új elemekkel bõvítse az adatbázist, illetve hogy a régi eleme-
ket törölje. Az oldalt nem tesszük nyilvános kiszolgálón elérhetõvé, ezért
a biztonsági kérdésekkel most nem foglalkozunk.

Elõször is fel kell építenünk az ûrlapot, amely az adatbázis elemeit tartalmazza.


A termékek árának módosításához szükségünk lesz egy szövegmezõre és minden
elemhez tartozni fog egy jelölõnégyzet is, melynek segítségével az adott elemet
törlésre jelölhetjük ki. A lapon el kell helyeznünk két további szövegmezõt is,
az új elemek felvételéhez. A 11.6. példában az oldalt elkészítõ program olvasható.
11
11.6. program HTML ûrlap készítése DBM adatbázis alapján
1: <?
2: $dbm = dbmopen( "./adat/termekek", "c" )
3: or die("Nem lehet megnyitni
a DBM adatbázist.");
4: ?>
5: <html>
6: <head>
7: <title>11.6. program HTML ûrlap készítése
8: DBM adatbázis alapján </title>
9: </head>
10: <body>
11: <form method="POST">
12: <table border="1">
13: <tr>
14: <td>Törlés</td>
15: <td>Termék</td>
16: <td>Ár</td>
17: </tr>
18: <?php
19: $kulcs = dbmfirstkey( $dbm );
20: while ( $kulcs != "" )
21: {
22: $ar = dbmfetch( $dbm, $kulcs );
23: print "<tr><td> <input type=\"checkbox"\
name=\"torles[]\" ";
11_ora.qxd 8/3/2001 6:20 PM Page 204

204 11. óra

11.6. program (folytatás)


24: print "value=\"$kulcs\"> </td>";
25: print "<td> $kulcs </td>";
26: print "<td> <input type=\"text\"
name=\"arak[$kulcs]\" ";
27: print "value=\"$ar\"> </td></tr>";
28: $kulcs = dbmnextkey( $dbm, $kulcs );
29: }
30: dbmclose( $dbm );
31: ?>
32: <tr>
33: <td>&nbsp;</td>
34: <td><input type="text" name="uj_nev"></td>
35: <td><input type="text" name="uj_ar"></td>
36: </tr>
37: <tr>
38: <td colspan="3" align="right">
39: <input type="submit" value="Változtat">
40: </td>
41: </tr>
42: </table>
43: </form>
44: </body>
45: </html>

Szokás szerint az elsõ lépés az adatbázis megnyitása. Ezután megkezdünk egy


ûrlapot és mivel nem adunk meg céloldalt, feldolgozó programként magát
az oldalt jelöljük ki.

Elkészítjük a táblázat fejlécét, majd végigolvassuk az adatbázist a dbmfirstkey()


és dbmnextkey() függvények segítségével, az értékeket a dbmfetch()
függvénnyel olvasva ki.

A táblázat elsõ mezõje minden sorban egy jelölõnégyzetet tartalmaz. Vegyük ész-
re, hogy mindegyik jelölõnégyzet neve "torles[]". Ennek hatására a PHP létre-
hozza a $torles tömböt, amely az összes bejelölt elemet tartalmazza. A jelölõ-
négyzetekhez tartozó értékek, így a $torles tömb elemei is azok az azonosítók
lesznek, amelyekkel a DBM adatbázis az adott terméket nyilvántartja (ezt az érté-
ket a $kulcs változóban tároljuk). Így, miután a rendszergazda kitöltötte és
elküldte az ûrlapot, a program $torles tömbje azon adatbázis-elemek kulcsait
fogja tárolni, amelyeket törölnünk kell.
11_ora.qxd 8/3/2001 6:20 PM Page 205

A DBM függvények használata 205

Ezután kiírjuk a böngészõablakba az elem nevét és létrehozunk egy szöveges


mezõt a termék árának. A mezõt ugyanolyan módon nevezzük el, mint az elõzõt,
ezúttal azonban a szögletes zárójelek közé beírjuk az azonosítót, amely alapján
a DBM adatbázis az elemet tárolja. A PHP ennek hatására létrehozza az $arak
tömböt, amelyben a kulcsok a termékek azonosítói.

Lezárjuk az adatbázist és visszatérünk HTML módba az új bejegyzés létrehozására


szolgáló uj_nev és uj_ar mezõk megjelenítéséhez. A 11.3. ábrán a 11.6. prog-
ram kimenetét láthatjuk.

11.3. ábra
HTML ûrlap készítése
DBM adatbázis
alapján
11

Miután elkészítettük az ûrlapot, meg kell írnunk a kódot, amely a felhasználó által
megadott adatokat kezeli. A feladat nem olyan nehéz, mint amilyennek látszik.
Elõször töröljük a kijelölt elemeket az adatbázisból, majd módosítjuk az árakat,
végül felvesszük az új elemet az adatbázisba.

Miután a karbantartó kitöltötte és elküldte az ûrlapot, a törlendõ elemek listája


a $torles tömbben áll rendelkezésünkre. Mindössze annyi a dolgunk, hogy
végigolvassuk a tömböt, és az összes elemét töröljük az adatbázisból.

if ( isset ( $torles ) )
{
foreach ( $torles as $kulcs => $ertek )
{
unset( $arak[$ertek]);
dbmdelete( $dbm, $ertek );
}
}
11_ora.qxd 8/3/2001 6:20 PM Page 206

206 11. óra

Elõször is megvizsgáljuk, hogy létezik-e a $torles változó. Ha a felhasználó


csak most érkezett az oldalra vagy nem jelölt ki törlése egyetlen terméket sem,
a változó nem létezik. Ellenkezõ esetben egy ciklus segítségével végigolvassuk és
minden elemére meghívjuk a dbmdelete() függvényt, amely eltávolítja
a DBM adatbázisból a paraméterként megadott elemet. Hasonlóan járunk el
az $arak tömb esetében is, itt azonban a PHP unset() függvényét kell hasz-
nálnunk a tömbelem törlésére. Az $arak tömb a felhasználótól érkezett, feltehe-
tõen részben módosított árakat tartalmazza. Ha nem törölnénk az $arak tömbbõl
a megfelelõ elemet, a következõ kód újra beillesztené.

Az adatbázis elemeinek frissítése során két választási lehetõségünk van. Az elsõ vál-
tozatot akkor alkalmazzuk, ha az adatbázis karbantartását nem egyetlen szerkesztõ
fogja végezni, tehát feltételezhetõ, hogy a programot egyidõben több felhasználó is
futtatni fogja – eszerint csak azokat az elemeket változtatjuk meg, amelyeket a fel-
használó kijelölt. A másik változat, amely az összes elemet megváltoztatja, akkor al-
kalmazható, ha a program csak egyetlen példányban futhat:

if ( isset ( $arak ) )
{
foreach ( $arak as $kulcs => $ertek )
dbmreplace( $dbm, $kulcs, $ertek );
}

Elõször is ellenõriznünk kell az $arak tömb meglétét. Ebben a tömbben az


adatbázis egy teljesen új változata lehet. Egy ciklus segítségével tehát végigolvassuk
az összes elemet és egyesével frissítjük az adatbázisban.

Végül ellenõriznünk kell, hogy a felhasználó kezdeményezte-e új elem felvételét


az adatbázisba:

if ( ! empty( $uj_nev ) && ! empty( $uj_ar ) )


dbminsert( $dbm, "$uj_nev", "$uj_ar" );

Ahelyett, hogy az $uj_nev és $uj_ar meglétét ellenõriznénk, azt kell ellen-


õriznünk, hogy értékük nem „üres”-e. Ez apró, de lényeges különbség. Amikor
a felhasználó elküldi az ûrlapot, a változók mindenképpen létrejönnek, de ha
a szövegmezõk nem kaptak értéket, a megfelelõ változók üres karakterláncot
tartalmaznak. Mivel nem akarunk üres elemeket tárolni az adatbázisban, fontos
ellenõrizni, hogy nem üresek-e a változók. Azért használjuk a dbminsert()
függvényt a dbmreplace() helyett, hogy elkerüljük a már bevitt termékek
véletlen felülírását.

A teljes kódot a 11.7. példa tartalmazza.


11_ora.qxd 8/3/2001 6:20 PM Page 207

A DBM függvények használata 207

11.7. program A teljes adatbázis-karbantartó program


1: <?php
2: $dbm = dbmopen( "./adat/termekek", "c" )
3: or die("Nem lehet megnyitni
a DBM adatbázist.”);
4:
5: if ( isset ( $torles ) )
6: {
7: foreach ( $torles as $kulcs => $ertek )
8: {
9: unset( $arak[$ertek]);
10: dbmdelete( $dbm, $ertek );
11:
12: }
}
11
13:
14: if ( isset ( $arak ) )
15: {
16: foreach ( $arak as $kulcs => $ertek )
17: dbmreplace( $dbm, $kulcs, $ertek );
18: }
19:
20: if ( ! empty( $uj_nev ) && ! empty( $uj_ar ) )
21: dbminsert( $dbm, "$uj_nev", "$uj_ar" );
22: ?>
23:
24: <html>
25: <head>
26: <title>11.7. program A teljes adatbázis-karbantartó
program </title>
27: </head>
28: <body>
29:
30: <form method="POST">
31:
32: <table border="1">
33: <tr>
34: <td>Törlés</td>
35: <td>Termék</td>
36: <td>Ár</td>
37: </tr>
38:
39: <?php
11_ora.qxd 8/3/2001 6:20 PM Page 208

208 11. óra

11.7. program (folytatás)


40: $kulcs = dbmfirstkey( $dbm );
41: while ( $kulcs != "" )
42: {
43: $ar = dbmfetch( $dbm, $kulcs );
44: print "<tr><td> <input type=\"checkbox"\
name=\"torles[]\" ";
45: print "value=\"$kulcs\"> </td>";
46: print "<td> $kulcs </td>";
47: print "<td> <input type=\"text\"
name=\"arak[$kulcs]\" ";
48: print "value=\"$ar\"> </td></tr>";
49: $kulcs = dbmnextkey( $dbm, $kulcs );
50: }
51:
52: dbmclose( $dbm );
53: ?>
54:
55: <tr>
56: <td>&nbsp;</td>
57: <td><input type="text" name="uj_nev"></td>
58: <td><input type="text" name="uj_ar"></td>
59: </tr>
60:
61: <tr>
62: <td colspan="3" align="right">
63: <input type="submit" value="Változtat">
64: </td>
65: </tr>
66:
67: </table>
68: </form>
69:
70: </body>
71: </html>
11_ora.qxd 8/3/2001 6:20 PM Page 209

A DBM függvények használata 209

Összefoglalás
Ebben az órában megtanultuk, hogyan használjuk a PHP hatékony DBM függvénye-
it adatok tárolására és visszaolvasására. Megtanultuk a dbmopen() használatát egy
új DBM azonosító létrehozására. Ezt az azonosítót használtuk az összes többi DBM
függvénynél is. Új adatokat adtunk az adatbázishoz a dbminsert() függvénnyel,
módosítottunk meglevõket a dbmreplace()-szel és töröltünk a dbmdelete()
használatával. Megtanultuk, hogyan használhatjuk a dbmfetch() függvényt
az adatok visszaolvasására. A serialize() és unserialize() függvényekkel
összetett adatszerkezeteket tároltunk DBM adatbázisban, végül egy gyakorlati
példán keresztül megnéztük, hogyan is használhatók fel e módszerek a valós
problémák megoldására.

11
Kérdések és válaszok
Mikor használjak DBM adatbázist SQL adatbázis helyett?
A DBM jó választás, ha kis mennyiségû és viszonylag egyszerû szerkezetû adatot sze-
retnénk tárolni (név–érték párokat). A DBM adatbázist használó programok rendel-
keznek a hordozhatóság nagyon fontos elõnyével, de ha nagyobb mennyiségû ada-
tot kell tárolnunk, válasszunk inkább egy SQL adatbáziskezelõt, például a MySQL-t.

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ényt használhatjuk egy DBM adatbázis megnyitásához?

2. Melyik függvénnyel szúrhatunk be új elemet egy DBM adatbázisba?

3. Melyik függvénnyel módosíthatunk egy elemet?

4. Hogyan érünk el egy elemet az adatbázisban, ha ismerjük a nevét?

5. Hogyan olvasnánk ki egy DBM adatbázisból a legelsõ elem nevét (nem az


értékét)?

6. Hogyan érjük el a további neveket?

7. Hogyan törlünk egy elemet a DBM adatbázisból, ha ismerjük a nevét?


11_ora.qxd 8/3/2001 6:20 PM Page 210

210 11. óra

Feladatok
1 Hozzunk létre egy DBM adatbázist a felhasználók azonosítóinak és jelszavai-
nak tárolására. Készítsünk egy programot, amellyel a felhasználók létrehoz-
hatják a rájuk vonatkozó bejegyzést. Ne feledjük, hogy két azonos nevû elem
nem kerülhet az adatbázisba.

2 Készítsünk egy bejelentkezõ programot, amely ellenõrzi a felhasználó azono-


sítóját és jelszavát. Ha a felhasználói bemenet egyezik valamelyik bejegyzés-
sel az adatbázisban, akkor üdvözöljük a felhasználót valamilyen különleges
üzenettel. Egyébként jelenítsük meg újra a bejelentkezõ ûrlapot.
12_ora.qxd 8/3/2001 6:20 PM Page 211

12. ÓRA
Adatbázisok kezelése – MySQL
A PHP nyelv egyik meghatározó tulajdonsága, hogy nagyon könnyen képes adat-
bázisokhoz csatlakozni és azokat kezelni. Ebben az órában elsõsorban a MySQL
adatbázisokkal foglalkozunk, de amint majd észre fogjuk venni, a PHP által támo-
gatott összes adatbázist hasonló függvények segítségével érhetjük el. Miért esett
a választás éppen a MySQL-re? Mert ingyenes, ugyanakkor nagyon hatékony
eszköz, amely képes megfelelni a valós feladatok által támasztott igényeknek is.
Az sem elhanyagolható szempont, hogy többféle rendszerhez is elérhetõ.
A MySQL adatbáziskiszolgálót a http://www.mysql.com címrõl tölthetjük le.
Ebben az órában a következõ témákkal foglalkozunk:

• Megnézünk néhány SQL példát.

• Csatlakozunk egy MySQL adatbáziskiszolgálóhoz.

• Kiválasztunk egy adatbázist.

• Tanulunk a hibakezelésrõl.

• Adatokat viszünk fel egy táblába.


12_ora.qxd 8/3/2001 6:20 PM Page 212

212 12. óra

• Adatokat nyerünk ki egy táblából.

• Megváltoztatjuk egy adattábla tartalmát.

• Megjelenítjük az adatbázis szerkezetét.

(Nagyon) rövid bevezetés az SQL nyelvbe


Az SQL jelentése Structured Query Language, vagyis strukturált lekérde-
ÚJDONSÁG
zõ nyelv. Az SQL szabványosított nyelvezete segítségével a különbözõ
típusú adatbázisokat azonos módon kezelhetjük. A legtöbb SQL termék saját bõví-
tésekkel látja el a nyelvet, ahogy a legtöbb böngészõ is saját HTML nyelvjárást „be-
szél”. Mindazonáltal SQL ismeretek birtokában nagyon sokféle adatbázist fogunk
tudni használni, a legkülönbözõbb operációs rendszereken.

A könyvben – terjedelmi okok miatt – még bevezetõ szinten sem tárgyalhatjuk


az SQL-t, de megpróbálunk megvilágítani egy-két dolgot a MySQL-lel és általában
az SQL-lel kapcsolatban.

A MySQL kiszolgáló démonként fut a számítógépen, így a helyi vagy akár távoli
gépek felhasználói bármikor csatlakozhatnak hozzá. Miután a csatlakozás megtör-
tént, ki kell választanunk a megfelelõ adatbázist, ha van jogunk hozzá.

Egy adatbázison belül több adattáblánk is lehet. Minden tábla oszlopokból és


sorokból áll. A sorok és oszlopok metszéspontjában tároljuk az adatokat. Minden
oszlopba csak elõre megadott típusú adatot tölthetünk, az INT típus például egész
számot, míg a VARCHAR változó hosszúságú, de egy adott értéknél nem hosszabb
karakterláncot jelent.

A kiválasztott adatbázisban a következõ SQL utasítással hozhatunk létre új táblát:

CREATE TABLE entablam ( keresztnev VARCHAR(30),


å vezeteknev VARCHAR(30), kor INT );

Ez a tábla három oszlopot tartalmaz. A keresztnev és vezeteknev oszlopokba


legfeljebb 30 karaktert írhatunk, míg a kor oszlopba egy egész számot.

A táblába új sort az INSERT paranccsal vehetünk fel:

INSERT INTO entablam ( keresztnev, vezeteknev, kor )


å VALUES ( 'János', 'Kovács', 36 );
12_ora.qxd 8/3/2001 6:20 PM Page 213

Adatbázisok kezelése – MySQL 213

A mezõneveket az elsõ, zárójelek közti kifejezéssel adjuk meg, míg az értékeket


a megfelelõ sorrendben a második zárójelpár között soroljuk fel.

A táblából az összes adatot a SELECT paranccsal kaphatjuk meg:

SELECT * FROM entablam;

A „*” szokásos helyettesítõ karakter, jelentése „az összes mezõ”. Ha nem az összes
mezõ tartalmát akarjuk lekérdezni, írjuk be az érintett mezõk neveit a csillag helyére:

SELECT kor, keresztnev FROM entablam;

Már létezõ bejegyzést az UPDATE paranccsal módosíthatunk.

UPDATE entablam SET keresztnev = 'Gábor';

Az utasítás az összes sorban "Gábor"-ra módosítja a keresztnev mezõ tartal-


mát. A WHERE záradékkal leszûkíthetjük a SELECT és UPDATE parancsok hatás-
körét. Például:
12
SELECT * FROM entablam WHERE keresztnev = 'Gábor';

Ez az utasítás csak azokat a sorokat írja ki, amelyekben a keresztnev mezõ értéke
"Gábor".

A következõ példa csak azokban a sorokban változtatja "Gábor"-ra


a keresztnev mezõ értékét, ahol a vezeteknev mezõ a "Szakács" karakter-
láncot tartalmazza.

UPDATE entablam SET keresztnev = "Gábor" WHERE vezeteknev =


å = "Szakács";

Az SQL-rõl további információkat találunk Ryan K. Stephens és szerzõtársai Teach


Yourself SQL in 21 Days címû könyvében.

Csatlakozás a kiszolgálóhoz
Mielõtt elkezdhetnénk dolgozni az adatbázissal, csatlakoznunk kell a kiszolgáló-
hoz. A PHP-ben erre a mysql_connect() függvény szolgál. A függvény három
karakterláncot vár paraméterként: a gazdagép nevét, a felhasználó nevét és
a jelszót. Ha ezek egyikét sem adjuk meg, a függvény feltételezi, hogy a kérés
a localhost-ra (azaz a helyi gépre) vonatkozik és felhasználóként a PHP-t futta-
tó felhasználót, jelszóként pedig egy üres karakterláncot ad át. Az alapértelmezés
12_ora.qxd 8/3/2001 6:20 PM Page 214

214 12. óra

a php.ini fájlban felülbírálható, de egy próbálkozásra szánt kiszolgálót kivéve


nem bölcs dolog ezzel próbálkozni, ezért a példákban mindig használni fogjuk
a felhasználónevet és a jelszót. A mysql_connect() függvény siker esetén egy
kapcsolatazonosítót ad vissza, amelyet egy változóba mentünk, hogy a késõbbiek-
ben folytathassuk a munkát az adatbáziskiszolgálóval.

Az alábbi kódrészlet a mysql_connect() függvény segítségével kapcsolódik


a MySQL adatbáziskiszolgálóhoz.

$kapcsolat = mysql_connect( "localhost", "root", "jelszo" );


if ( ! $kapcsolat )
die( "Nem lehet csatlakozni a MySQL kiszolgalohoz!" );

Ha a PHP-t az Apache kiszolgáló moduljaként használjuk, a mysql_pconnect()


függvényt is használhatjuk az elõzõekben megadott paraméterekkel. Fontos
különbség a két függvény között, hogy a mysql_pconnect()-tel megnyitott
adatbáziskapcsolat nem szûnik meg a PHP program lefutásával vagy
a mysql_close() függvény hatására (amely egy szokásos MySQL kiszolgáló-
kapcsolat bontására szolgál) , hanem továbbra is aktív marad és olyan programok-
ra várakozik, amelyek a mysql_pconnect() függvényt hívják. Más szóval
a mysql_pconnect() függvény használatával megtakaríthatjuk azt az idõt, ami
egy kapcsolat felépítéséhez szükséges és egy elõzõleg lefutott program által ha-
gyott azonosítót használhatunk.

Az adatbázis kiválasztása
Miután kialakítottuk a kapcsolatot a MySQL démonnal, ki kell választanunk, melyik
adatbázissal szeretnénk dolgozni. Erre a célra a mysql_select_db() függvény
szolgál, amelynek meg kell adnunk a kiválasztott adatbázis nevét és szükség szerint
egy kapcsolatazonosító értéket. Ha ez utóbbit elhagyjuk, automatikusan a legutoljá-
ra létrehozott kapcsolat helyettesítõdik be. A mysql_select_db() függvény igaz
értéket ad vissza, ha az adatbázis létezik és jogunk van a használatára. A következõ
kódrészlet a pelda nevû adatbázist választja ki.

$adatbazis = "pelda";
mysql_select_db( $adatbazis ) or die ( "Nem lehet
å megnyitni a következõ adatbázist: $adatbazis" );
12_ora.qxd 8/3/2001 6:20 PM Page 215

Adatbázisok kezelése – MySQL 215

Hibakezelés
Eddig ellenõriztük a MySQL függvények visszatérési értékét és hiba esetén a die()
függvénnyel kiléptünk a programból. A hibakezeléshez azonban hasznosabb lenne,
ha a hibaüzenetek valamivel több információt tartalmaznának. Ha valamilyen mûve-
let nem sikerül, a MySQL beállít egy hibakódot és egy hibaüzenetet. A hibakódhoz
a mysql_errno(), míg a hibaüzenethez a mysql_error() függvénnyel férhe-
tünk hozzá. A 12.1 példa az eddigi kódrészleteinket teljes programmá kapcsolja
össze, amely kapcsolódik az adatbáziskezelõhöz és kiválasztja az adatbázist. A hiba-
üzenetet a mysql_error() függvénnyel tesszük használhatóbbá.

12.1. program Kapcsolat megnyitása és az adatbázis kiválasztása


1: <html>
2: <head>
3: <title>12.1. program Kapcsolat megnyitása és
4: adatbázis kiválasztása</title>
5: </head>
6:
7:
<body>
<?php
12
8: $felhasznalo = "jozsi";
9: $jelszo = "bubosvocsok";
10: $adatbazis = "pelda";
11: $kapcsolat = mysql_connect( "localhost",
$felhasznalo, $jelszo );
12: if ( ! $kapcsolat )
13: die( "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!" );
14: print "Sikerült a kapcsolatfelvétel<P>";
15: mysql_select_db( $adatbazis )
16: or die ( "Nem lehet megnyitni a $adatbázist: "
.mysql_error() );
17: print "Sikeresen kiválasztott adatbázis: \"
$adatbazis\"<P>";
18: mysql_close( $kapcsolat );
19: ?>
20: </body>
21: </html>
12_ora.qxd 8/3/2001 6:20 PM Page 216

216 12. óra

Ha az $adatbazis változó értékét mondjuk "nincsmeg"-re módosítjuk,


a program egy nem létezõ adatbázist próbál meg elérni. Ekkor a die() kimenete
valami ilyesmi lesz:

Nem lehet megnyitni a nincsmeg adatbázist: Access denied


å for user: 'jozsi@localhost' to database 'nincsmeg'

Adatok hozzáadása táblához


Már sikerült hozzáférést szerezni az adatbázishoz, így ideje némi adatot is bevinni
a táblákba. A következõ példákhoz képzeljük el, hogy az általunk készítendõ
oldalon a látogatóknak lehetõségük lesz tartományneveket vásárolni.

A pelda adatbázisban készítsük el az öt oszlopot tartalmazó tartomanyok táb-


lát. Az azonosito mezõ lesz az elsõdleges kulcs, amely automatikusan növel
egy egész értéket, ahogy újabb bejegyzések kerülnek a táblába, a tartomany
mezõ változó számú karaktert tartalmazhat (VARCHAR), a nem mezõ egyetlen
karaktert, az email mezõ pedig a felhasználó elektronikus levélcímét.
A táblát a következõ SQL paranccsal készíthetjük el:

CREATE TABLE tartomanyok ( azonosito INT NOT NULL


å AUTO_INCREMENT,
PRIMARY KEY( azonosito ),
tartomany VARCHAR( 20 ),
nem CHAR( 1 ),
email VARCHAR( 20 ) );

Az adatok felviteléhez össze kell állítanunk és le kell futtatnunk egy SQL parancsot,
erre a célra a PHP-ben a mysql_query() függvény szolgál. A függvény paramé-
terként egy SQL parancsot tartalmazó karakterláncot és szükség szerint egy kapcso-
latazonosítót vár. Ha ez utóbbit elhagyjuk, a függvény automatikusan az utoljára
megnyitott kapcsolaton keresztül próbálja meg kiadni az SQL parancsot. Ha a prog-
ram sikeresen lefutott, a mysql_query()pozitív értéket ad vissza, ha azonban
formai hibát tartalmaz vagy nincs jogunk elérni a kívánt adatbázist, a visszatérési
érték hamis lesz. Meg kell jegyeznünk, hogy egy sikeresen lefutott SQL program
nem feltétlenül okoz változást az adatbázisban vagy tér vissza valamilyen ered-
ménnyel. A 12.2 példában kibõvítjük a korábbi programot és a mysql_query()
függvénnyel kiadunk egy INSERT utasítást a pelda adatbázis tartomanyok
tábláján.
12_ora.qxd 8/3/2001 6:20 PM Page 217

Adatbázisok kezelése – MySQL 217

12.2. program Új sor hozzáadása táblához


1: <html>
2: <head>
3: <title>12.2. program Új sor hozzáadása
táblához</title>
4: </head>
5: <body>
6: <?php
7: $felhasznalo = "jozsi";
8: $jelszo = "bubosvocsok";
9: $adatbazis = "pelda";
10: $kapcsolat = mysql_connect( "localhost",
$felhasznalo, $jelszo );
11: if ( ! $kapcsolat )
12: die( "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!" );
13: mysql_select_db( $adatbazis, $kapcsolat )
14: or die ( "Nem lehet megnyitni a $adatbázist:
".mysql_error() );
15: $parancs = "INSERT INTO tartomanyok ( tartomany,
12
nem, email )
16: VALUES ( '123xyz.com', 'F',
'okoska@tartomany.hu' )";
17: mysql_query( $parancs, $kapcsolat )
18: or die ( "Nem lehet adatot hozzáadni
a \"tartomanyok\" táblához: "
19: .mysql_error() );
20: mysql_close( $kapcsolat );
21: ?>
22: </body>
23: </html>

Vegyük észre, hogy nem adtunk értéket az azonosito mezõnek. A mezõ értéke
automatikusan növekszik az INSERT hatására.

Természetesen minden esetben, amikor a böngészõben újratöltjük a 12.2 példa-


programot, ugyanaz a sor adódik hozzá a táblához. A 12.3 példa a felhasználó
által bevitt adatot tölti be a táblába.
12_ora.qxd 8/3/2001 6:20 PM Page 218

218 12. óra

12.3.program A felhasználó által megadott adatok beszúrása a táblába


1: <html>
2: <head>
3: <title>12.3. program A felhasználó által megadott ada-
tok beszúrása a táblába</title>
4: </head>
5: <body>
6: <?php
7: if ( isset( $tartomany ) && isset( $nem ) &&
isset( $email ) )
8: {
9: // Ne feledjük ellenõrizni a felhasználó által
megadott adatokat!
10: $dbhiba = "";
11: $vissza = adatbazis_bovit( $tartomany, $nem,
$email, $dbhiba );
12: if ( ! $vissza )
13: print "Hiba: $dbhiba<BR>";
14: else
15: print "Köszönjük!";
16: }
17: else {
18: urlap_keszit();
19: }
20:
21: function adatbazis_bovit( $tartomany, $nem, $email,
&$dbhiba )
22: {
23: $felhasznalo = "jozsi";
24: $jelszo = "bubosvocsok";
25: $adatbazis = "pelda";
26: $kapcsolat = mysql_pconnect( "localhost",
$felhasznalo, $jelszo );
27: if ( ! $kapcsolat )
28: {
29: $dbhiba = "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!";
30: return false;
31: }
32: if ( ! mysql_select_db( $adatbazis, $kapcsolat ) )
33: {
34: $dbhiba = mysql_error();
12_ora.qxd 8/3/2001 6:20 PM Page 219

Adatbázisok kezelése – MySQL 219

12.3.program (folytatás)
35: return false;
36: }
37: $parancs = "INSERT INTO tartomanyok ( tartomany,
nem, email )
38: VALUES ( '$tartomany', '$nem', '$email' )";
39: if ( ! mysql_query( $parancs, $kapcsolat ) )
40: {
41: $dbhiba = mysql_error();
42: return false;
43: }
44: return true;
45: }
46:
47: function urlap_keszit()
48: {
49: global $PHP_SELF;

12
50: print "<form action=\"$PHP_SELF\"
method=\"POST\">\n";
51: print "A kívánt tartomány<p>\n";
52: print "<input type=\"text\" name=\"tartomany\"> ";
53: print "Email cím<p>\n";
54: print "<input type=\"text\" name=\"email\"> ";
55: print "<select name=\"nem\">\n";
56: print "\t<option value=\"N\"> Nõ\n";
57: print "\t<option value=\"F\"> Férfi\n";
58: print "</select>\n";
59: print "<input type=\"submit\"
value=\"Elküld\">\n</form>\n";
60: }
61: ?>
62: </body>
63: </html>

A tömörség érdekében a 12.3. példából kihagytunk egy fontos részt. Megbíztunk


a felhasználókban: semmilyen formában nem ellenõriztük a felhasználó által bevitt
adatokat. Ezt a feladatot a 17. órában tárgyalt karakterlánckezelõ függvényekkel
végezhetjük el. Meg kell jegyeznünk, hogy a beérkezõ adatok ellenõrzése mindig
fontos feladat, itt csak azért maradt el, mivel így jobban összpontosíthattunk az óra
témájára.
12_ora.qxd 8/3/2001 6:20 PM Page 220

220 12. óra

Ellenõrizzük a $tartomany, $nem és $email változókat. Ha megvannak,


nyugodtan feltehetjük, hogy a felhasználó adatokat küldött az ûrlap kitöltésével,
így meghívjuk az adatbazis_bovit() függvényt.

Az adatbazis_bovit()-nek négy paramétere van: a $tartomany, a $nem és


az $email változók, illetve a $dbhiba karakterlánc. Ez utóbbiba fogjuk betölteni
az esetlegesen felbukkanó hibaüzeneteket, így hivatkozásként kell átadnunk.
Ennek hatására ha a függvénytörzsön belül megváltoztatjuk a $dbhiba értékét,
a másolat helyett tulajdonképpen az eredeti paraméter értékét módosítjuk.

Elõször megkísérlünk megnyitni egy kapcsolatot a MySQL kiszolgálóhoz.


Ha ez nem sikerül, akkor hozzárendelünk egy hibaszöveget a $dbhiba változóhoz
és false értéket visszaadva befejezzük a függvény futását. Ha a csatlakozás sike-
res volt, kiválasztjuk a tartomany táblát tartalmazó adatbázist és összeállítunk egy
SQL utasítást a felhasználó által küldött értékek felhasználásával, majd az utasítást
átadjuk a mysql_query() függvénynek, amely elvégzi az adatbázisban a kívánt
mûveletet. Ha a mysql_select_db() vagy a mysql_query() függvény nem
sikeres, a $dbhiba változóba betöltjük a mysql_error() függvény által vissza-
adott értéket és false értékkel térünk vissza. Minden egyéb esetben, vagyis ha
a mûvelet sikeres volt, true értéket adunk vissza.

Miután az adatbazis_bovit() lefutott, megvizsgáljuk a visszatérési értéket.


Ha true, az adatok bekerültek az adatbázisba, így üzenetet küldhetünk a felhasz-
nálónak. Egyébként ki kell írnunk a böngészõbe a hibaüzenetet.
Az adatbazis_bovit() függvény által visszaadott $dbhiba változó most már
hasznos adatokat tartalmaz a hiba természetét illetõen, így ezt a szöveget is bele-
foglaljuk a hibaüzenetbe.

Ha a kezdeti if kifejezés nem találja meg a $tartomany, $nem vagy $email


valamelyikét, feltehetjük, hogy a felhasználó nem küldött el semmilyen adatot,
ezért meghívunk egy másik általunk írt függvényt, az urlap_keszit()-et,
amely egy HTML ûrlapot jelenít meg a böngészõben.

Automatikusan növekvõ mezõ értékének lekérdezése


Az elõzõ példákban úgy adtuk hozzá a sorokat a táblához, hogy nem foglalkoz-
tunk az azonosito oszlop értékével, hiszen az adatok beszúrásával az folyama-
tosan növekedett, értékére pedig nem volt szükségünk. Ha mégis szükségünk len-
ne rá, egy SQL lekérdezéssel bármikor lekérdezhetjük az adatbázisból. De mi van
akkor, ha azonnal szükségünk van az értékre? Fölösleges külön lekérdezést végre-
hajtani, hiszen a PHP tartalmazza a mysql_insert_id() függvényt, amely
a legutóbbi INSERT kifejezés során beállított automatikusan növelt mezõ értékét
adja vissza. A mysql_insert_id() függvénynek szükség esetén átadhatunk
12_ora.qxd 8/3/2001 6:20 PM Page 221

Adatbázisok kezelése – MySQL 221

egy kapcsolatazonosító paramétert, amelyet elhagyva a függvény alapértelmezés


szerint a legutoljára létrejött MySQL kapcsolat azonosítóját használja.

Így ha meg akarjuk mondani a felhasználónak, hogy milyen azonosító alatt rögzí-
tettük az adatait, az adatok rögzítése után közvetlenül hívjuk meg
a mysql_insert_id() függvényt.

$parancs = "INSERT INTO tartomanyok ( tartomany, nem,


å email ) VALUES ( '$tartomany', '$nem', '$email' )";
mysql_query( $parancs, $kapcsolat );
$azonosito = mysql_insert_id();
print "Köszönjük. Az Ön tranzakció-azonosítója:
å $azonosito. Kérjük jegyezze meg ezt a kódot.";

Adatok lekérdezése
Miután adatainkat már képesek vagyunk az adatbázisban tárolni, megismerkedhe-
tünk azokkal a módszerekkel, amelyek az adatok visszanyerésére szolgálnak. Mint
bizonyára már nyilvánvaló, a mysql_query() függvény használatával ki kell 12
adnunk egy SELECT utasítást. Az azonban már korántsem ilyen egyszerû, hogyan
jutunk hozzá a lekérdezés eredményéhez. Nos, miután végrehajtottunk egy sikeres
SELECT-et, a mysql_query() visszaad egy úgynevezett eredményazonosítót,
melynek felhasználásával elérhetjük az eredménytáblát és információkat nyerhe-
tünk róla.

Az eredménytábla sorainak száma


A SELECT utasítás eredményeként kapott tábla sorainak számát
a mysql_num_rows() függvény segítségével kérdezhetjük le. A függvény
paramétere a kérdéses eredmény azonosítója, visszatérési értéke pedig a sorok szá-
ma a táblában. A 12.4. példaprogramban lekérdezzük a tartomany tábla összes
sorát és a mysql_num_rows() függvénnyel megkapjuk a teljes tábla méretét.

12.4. program Sorok száma a SELECT utasítás eredményében.


1: <html>
2: <head>
3: <title>12.4. program A mysql_num_rows() függvény
használata</title>
4: </head>
5: <body>
6: <?php
12_ora.qxd 8/3/2001 6:20 PM Page 222

222 12. óra

12.4. program (folytatás)


7: $felhasznalo = "jozsi";
8: $jelszo = "bubosvocsok";
9: $adatbazis = "pelda";
10: $kapcsolat = mysql_connect( "localhost",
$felhasznalo, $jelszo );
11: if ( ! $kapcsolat )
12: die( "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!" );
13: mysql_select_db( $adatbazis, $kapcsolat )
14: or die ( "Nem lehet megnyitni a $adatbazis adatbá-
zist: ".mysql_error() );
15: $eredmeny = mysql_query( "SELECT * FROM tartomanyok" );
16: $sorok_szama = mysql_num_rows( $eredmeny );
17: print "Jelenleg $sorok_szama sor van a táblában<P>";
18: mysql_close( $kapcsolat );
19: ?>
20: </body>
21: </html>

A mysql_query() függvény egy eredményazonosítót ad vissza. Ezt átadjuk


a mysql_num_rows() függvénynek, amely megadja a sorok számát.

Az eredménytábla elérése
Miután végrehajtottuk a SELECT lekérdezést és az eredményazonosítót tároltuk,
egy ciklus segítségével férhetünk hozzá az eredménytábla soraihoz. A PHP egy
belsõ mutató segítségével tartja nyilván, hogy melyik sort olvastuk utoljára.
Ha kiolvasunk egy eredménysort, a program automatikusan a következõre ugrik.

A mysql_fetch_row() függvénnyel kiolvashatjuk a belsõ mutató által hivat-


kozott sort az eredménytáblából. A függvény paramétere egy eredményazonosító,
visszatérési értéke pedig egy tömb, amely a sor összes mezõjét tartalmazza.
Ha elértük az eredménykészlet végét, a mysql_fetch_row() függvény false
értékkel tér vissza. A 12.5. példa a teljes tartomany táblát megjeleníti
a böngészõben.
12_ora.qxd 8/3/2001 6:20 PM Page 223

Adatbázisok kezelése – MySQL 223

12.5. program Tábla összes sorának és oszlopának megjelenítése


1: <html>
2: <head>
3: <title>12.5. program Tábla összes sorának és
oszlopának megjelenítése</title>
4: </head>
5: <body>
6: <?php
7: $felhasznalo = "jozsi";
8: $jelszo = "bubosvocsok";
9: $adatbazis = "pelda";
10: $kapcsolat = mysql_connect( "localhost",
$felhasznalo, $jelszo );
11: if ( ! $kapcsolat )
12: die( "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!" );
13: mysql_select_db( $db, $kapcsolat )
14: or die ( "Nem lehet megnyitni a $adatbazis
adatbázist: ".mysql_error() );
15: $eredmeny = mysql_query( "SELECT * FROM tartomanyok"
12
);
16: $sorok_szama = mysql_num_rows( $eredmeny );
17: print "Jelenleg $sorok_szama sor van a táblában<P>";
18: print "<table border=1>\n";
19: while ( $egy_sor = mysql_fetch_row( $eredmeny ) )
20: {
21: print "<tr>\n";
22: foreach ( $egy_sor as $mezo )
23: print "\t<td>$mezo</td>\n";
24: print "</tr>\n";
25: }
26: print "</table>\n";
27: mysql_close( $kapcsolat );
28: ?>
29: </body>
30: </html>

Kapcsolódunk a kiszolgálóhoz és kiválasztjuk az adatbázist, majd


a mysql_query() függvénnyel egy SELECT lekérdezést küldünk az adatbázis
kiszolgálójához. Az eredményt az $eredmeny változóban tároljuk, amit az ered-
ménysorok számának lekérdezéséhez használunk, ahogy korábban láttuk.
12_ora.qxd 8/3/2001 6:20 PM Page 224

224 12. óra

A while kifejezésben a mysql_fetch_row() függvény visszatérési értékét


az $egy_sor változóba töltjük. Ne feledjük, hogy az értékadó kifejezés értéke
megegyezik a jobb oldal értékével, ezért a kiértékelés során a kifejezés értéke
mindig igaz lesz, amíg a mysql_fetch_row() függvény nem nulla értékkel
tér vissza. A ciklusmagban kiolvassuk az $egy_sor változóban tárolt elemeket és
egy táblázat celláiként jelenítjük meg azokat a böngészõben.

A mezõket név szerint is elérhetjük, méghozzá kétféle módon.


A mysql_fetch_array() függvény egy asszociatív tömböt ad vissza, ahol
a kulcsok a mezõk nevei. A következõ kódrészletben módosítottuk a 12.5. példa
while ciklusát, a mysql_fetch_array() függvény felhasználásával:

print "<table border=1>\n";


while ( $egy_sor = mysql_fetch_array( $eredmeny ) )
{
print "<tr>\n";
print
"<td>".$egy_sor["email"]."</td><td>".$egy_sor["tartomany"].
å "</td>\n";
print "</tr>\n";
}
print "</table>\n";

A mysql_fetch_object() függvény segítségével egy objektum tulajdonságai-


ként férhetünk hozzá a mezõkhöz. A mezõnevek lesznek a tulajdonságok nevei.
A következõ kódrészletben ismét módosítottuk a kérdéses részt, ezúttal
a mysql_fetch_object() függvényt használtuk.

print "<table border=1>\n";


while ( $egy_sor = mysql_fetch_object( $eredmeny ) )
{
print "<tr>\n";
print "<td>".$egy_sor->email."</td><td>".$egy_sor->
å tartomany."</td>\n";
print "</tr>\n";
}
print "</table>\n";

A mysql_fetch_array() és mysql_fetch_object() függvények lehetõvé


teszik számunkra, hogy a sorból kinyert információkat szûrjük és végrehajtásuk
sem kerül sokkal több idõbe, mint a mysql_fetch_row() függvényé.
12_ora.qxd 8/3/2001 6:20 PM Page 225

Adatbázisok kezelése – MySQL 225

Adatok frissítése
Az adatokat az UPDATE utasítással frissíthetjük, amelyet természetesen
a mysql_query() függvénnyel kell átadnunk az adatbázis kiszolgálójának.
Itt is igazak a korábban elmondottak, azaz egy sikeres UPDATE utasítás nem
feltétlenül jelent változást az adatokban. A megváltozott sorok számát
a mysql_affected_rows() függvénnyel kérdezhetjük le, amelynek szükség
szerint egy kapcsolatazonosítót kell átadnunk. Ennek hiányában a függvény –
mint azt már megszokhattuk – a legfrissebb kapcsolatra értelmezi a mûveletet.
A mysql_affected_rows() függvényt bármely olyan SQL lekérdezés után
használhatjuk, amely feltehetõen módosított egy vagy több sort az adattáblában.

A 12.6. példa egy olyan programot tartalmaz, amely lehetõvé teszi az adatbázis
karbantartója számára, hogy bármelyik sor tartomany mezõjét megváltoztassa.

12.6. program Sorok frissítése az adatbázisban


1: <html>
2: <head>
3: <title>12.6. program Sorok frissítése az adatbázisban
12
4: </title>
5: </head>
6: <body>
7: <?php
8: $felhasznalo = "jozsi";
9: $jelszo = "bubosvocsok";
10: $adatbazis = "pelda";
11: $kapcsolat = mysql_connect( "localhost",
$felhasznalo, $jelszo );
12: if ( ! $kapcsolat )
13: die( "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!” );
14: mysql_select_db( $adatbazis, $kapcsolat )
15: or die ( "Nem lehet megnyitni a $adatbazis
adatbázist: ".mysql_error() );
16: if ( isset( $tartomany ) && isset( $azonosito ) )
17: {
18: $parancs = "UPDATE tartomanyok SET tartomany =
'$tartomany' WHERE
azonosito=$azonosito";
19: $eredmeny = mysql_query( $parancs );
12_ora.qxd 8/3/2001 6:20 PM Page 226

226 12. óra

12.6. program (folytatás)


20: if ( ! $eredmeny )
21: die ("Nem sikerült a módosítás: "
.mysql_error());
22: print "<h1>A tábla módosítva, ".
mysql_affected_rows() .
23: " sor változott</h1><p>";
24: }
25: ?>
26: <form action="<? print $PHP_SELF ?>" method="POST">
27: <select name="azonosito">
28: <?
29: $eredmeny = mysql_query( "SELECT tartomany, azonosito
FROM tartomanyok" );
30: while( $egy_sor = mysql_fetch_object( $eredmeny ) )
31: {
32: print "<option value=\"$egy_sor->azonosito\"";
33: if ( isset($azonosito) && $azonosito ==
$egy_sor->azonosito )
34: print " selected";
35: print "> $egy_sor->tartomany\n";
36: }
37: mysql_close( $kapcsolat );
38: ?>
39: </select>
40: <input type="text" name="tartomany">
41: <input type="submit" value="Frissítés">
42: </form>
43: </body>
44: </html>

A mûvelet a szokásos módon indul: kapcsolódunk az adatbázis kiszolgálójához és


kiválasztjuk az adatbázist. Ezek után megvizsgáljuk a $tartomany és
az $azonosito változók meglétét. Ha mindent rendben találunk, összeállítjuk
az SQL utasítást, amely a $tartomany változó értékének megfelelõen frissíti
azt a sort, ahol az azonosito mezõ tartalma megegyezik az $azonosito változó
értékével. Ha nem létezõ azonosito értékre hivatkozunk vagy a kérdéses sorban
a $tartomany változó értéke megegyezik a tartomany mezõ tartalmával,
nem kapunk hibaüzenetet, de a mysql_affected_rows() függvény visszatérési
értéke 0 lesz. A módosított sorok számát kiírjuk a böngészõbe.
12_ora.qxd 8/3/2001 6:20 PM Page 227

Adatbázisok kezelése – MySQL 227

A karbantartó számára készítünk egy HTML ûrlapot, amelyen keresztül elvégezheti


a változtatásokat. Ehhez ismét a mysql_query() függvényt kell használnunk:
lekérdezzük az azonosito és tartomany oszlopok összes elemét és beillesztjük
azokat egy HTML SELECT listába. A karbantartó ezáltal egy lenyíló menübõl vá-
laszthatja ki, melyik bejegyzést kívánja módosítani. Ha a karbantartó már elküldte
egyszer az ûrlapot, akkor az utoljára hivatkozott azonosito érték mellé
a SELECTED módosítót is kitesszük, így a módosítások azonnal látszódni fognak
a menüben.

Információk az adatbázisokról
Mindezidáig egyetlen adatbázisra összpontosítottunk, megtanulva, hogyan lehet
adatokkal feltölteni egy táblát és az adatokat lekérdezni. A PHP azonban számos
olyan eszközzel szolgál, amelyek segítségével megállapíthatjuk, hány adatbázis
hozzáférhetõ az adott kapcsolaton keresztül és milyen ezek szerkezete.

Az elérhetõ adatbázisok kiíratása


A mysql_list_dbs() függvény segítségével listát kérhetünk az összes adatbá- 12
zisról, melyek az adott kapcsolaton keresztül hozzáférhetõk. A függvény paraméte-
re szükség szerint egy kapcsolatazonosító, visszatérési értéke pedig egy eredmény-
azonosító. Az adatbázisok neveit a mysql_tablename() függvénnyel
kérdezhetjük le, amelynek paramétere ez az eredményazonosító és az adatbázis
sorszáma, visszatérési értéke pedig az adatbázis neve. Az adatbázisok sorszámo-
zása 0-val kezdõdik. Az összes adatbázis számát a mysql_list_dbs() függvény
után meghívott mysql_num_rows() függvény adja meg.

12.7. program Adott kapcsolaton keresztül elérhetõ adatbázisok


1: <html>
2: <head>
3: <title>12.7. program Adott kapcsolaton keresztül
elérhetõ adatbázisok
4: </title>
5: </head>
6: <body>
7: <?php
8: $felhasznalo = "jozsi";
9: $jelszo = "bubosvocsok";
10: $kapcsolat = mysql_connect( "localhost",
$felhasznalo, $jelszo );
12_ora.qxd 8/3/2001 6:20 PM Page 228

228 12. óra

12.7. program (folytatás)


11: if ( ! $kapcsolat )
12: die( "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!" );
13: $adatbazis_lista = mysql_list_dbs( $kapcsolat );
14: $szam = mysql_num_rows( $adatbazis_lista );
15: for( $x = 0; $x < $szam; $x++ )
16: print mysql_tablename( $adatbazis_lista,
$x )."<br>";
17: mysql_close( $kapcsolat );
18: ?>
19: </body>
20: </html>

A mysql_list_dbs() függvény visszaad egy eredményazonosítót, amelyet


paraméterként átadunk a mysql_num_rows() függvénynek. Az így megkapott
adatbázisok számát a $szam változóba töltjük és felhasználjuk a for ciklusban.

Az $x indexet minden lépésben eggyel növeljük, 0-tól a talált adatbázisok számá-


ig, majd az eredményazonosítóval együtt átadjuk a mysql_tablename()
függvénynek az adatbázis nevének lekérdezéséhez. A 12.1 ábrán a 12.7 program
eredménye látható egy böngészõablakban.

12.1. ábra
Az elérhetõ adatbá-
zisok listája
12_ora.qxd 8/3/2001 6:20 PM Page 229

Adatbázisok kezelése – MySQL 229

A mysql_list_dbs() függvény által visszaadott eredményazonosítót


a mysql_query() eredményéhez hasonlóan is felhasználhatnánk, vagyis
a tényleges neveket a mysql_fetch_row() függvénnyel is lekérdezhetnénk.
Ekkor eredményül egy tömböt kapnánk, melynek elsõ eleme tartalmazná
az adatbázis nevét.

Adatbázistáblák listázása
A mysql_list_tables() függvénnyel egy adott adatbázis tábláinak nevét sorol-
tathatjuk fel. A függvény paraméterei az adatbázis neve és szükség szerint a kapcso-
lat azonosítója. A visszatérési érték egy eredményazonosító, ha az adatbázis létezik
és jogunk van hozzáférni. Az eredményazonosítót mysql_tablename() vagy
mysql_fetch_row() hívásokhoz használhatjuk fel, a fent látott módon.

A következõ kódrészlet a mysql_list_tables() függvény segítségével


az adatbázis összes tábláját kiírja.

$eredmeny = mysql_list_tables( "pelda", $kapcsolat );


while ( $tabla_sor = mysql_fetch_row( $eredmeny ) )
print $tabla_sor[0]."<BR>\n"; 12
Információk a mezõkrõl
A SELECT lekérdezés után az eredménytábla mezõinek számát
a mysql_num_fields() függvénnyel kaphatjuk meg. A függvény paramétere
egy eredményazonosító, visszatérési értéke pedig egy egész szám, amely a mezõk
számát adja meg.

$eredmeny = mysql_query( "SELECT * from tartomanyok" );


$mezok_szama = mysql_num_fields( $eredmeny );

A mezõkhöz sorszámokat rendelünk, a számozás 0-val kezdõdik. A sorszám és az


eredményazonosító alapján számos információt lekérdezhetünk a mezõrõl, bele-
értve a nevét, típusát, legnagyobb hosszát és egyéb jellemzõit is.

A mezõ nevének lekérdezésére a mysql_field_name() függvény szolgál.

$eredmeny = mysql_query( "SELECT * from tartomanyok" );


$mezok_szama = mysql_num_fields( $eredmeny );
for ( $x=0; $x<$mezok_szama; $x++ )
mysql_field_name( $eredmeny, $x ) . "<br>\n";
12_ora.qxd 8/3/2001 6:20 PM Page 230

230 12. óra

A mezõ legnagyobb hosszát a mysql_field_len() függvénnyel kaphatjuk meg.

$eredmeny = mysql_query( "SELECT * from tartomanyok" );


$mezok_szama = mysql_num_fields( $eredmeny );
for ( $x=0; $x<$mezok_szama; $x++ )
mysql_field_len( $eredmeny, $x ) . "<BR>\n";

A mezõ egyéb jellemzõit a mysql_field_flags() függvénnyel olvashatjuk ki:

$eredmeny = mysql_query( "SELECT * from tartomanyok" );


$mezok_szama = mysql_num_fields( $eredmeny );
for ( $x=0; $x<$mezok_szama; $x++ )
mysql_field_flags( $eredmeny, $x ) . "<BR>\n";

Lehetõségünk van még a mezõ típusának megállapítására,


a mysql_field_type() függvénnyel:

$eredmeny = mysql_query( "SELECT * from tartomanyok" );


$mezok_szama = mysql_num_fields( $eredmeny );
for ( $x=0; $x<$mezok_szama; $x++ )
mysql_field_type( $eredmeny, $x ) . "<BR>\n";

Az adatbázis szerkezete – összeáll a kép


A 12.8 példa egyesíti a fenti eljárásokat és megjelenít minden elérhetõ adatbázist,
táblát és mezõt.

12.8 program Minden adatbázis, tábla és mezõ megjelenítése


1: <html>
2: <head>
3: <title>12.8. program Minden adatbázis, tábla és
mezõ megjelenítése</title>
4: </head>
5: <body>
6: <?php
7: $felhasznalo = "root";
8: $jelszo = "titkos";
9: $kapcsolat = mysql_connect( "localhost",
$felhasznalo, $jelszo );
12_ora.qxd 8/3/2001 6:20 PM Page 231

Adatbázisok kezelése – MySQL 231

12.8 program (folytatás)


10: if ( ! $kapcsolat )
11: die( "Nem lehet kapcsolódni
a MySQL kiszolgálóhoz!" );
12: $adatbazis_lista = mysql_list_dbs( $kapcsolat );
13: while ( $adatbazisok = mysql_fetch_row
( $adatbazis_lista ) )
14: {
15: print "<b>".$adatbazisok[0]."</b>\n";
16: if ( !@mysql_select_db( $adatbazisok[0],
$kapcsolat ) )
17: {
18: print "<dl><dd>Nem lehet kiválasztani — " .
mysql_error() ." </dl>";
19: continue;
20: }
21: $tablak = mysql_list_tables( $adatbazisok[0],
$kapcsolat );
22:
23:
print "\t<dl><dd>\n";
while ( $tabla_sor = mysql_fetch_row( $tablak )
12
)
24: {
25: print "\t<b>$tabla_sor[0]</b>\n";
26: $eredmeny = mysql_query( "SELECT * from "
.$tabla_sor[0] );

27: $mezok_szama = mysql_num_fields( $eredmeny );


28: print "\t\t<dl><dd>\n";
29: for ( $x=0; $x<$mezok_szama; $x++ )
30: {
31: print "\t\t<i>";
32: print mysql_field_type( $eredmeny, $x );
33: print "</i> <i>";
34: print mysql_field_len( $eredmeny, $x );
35: print "</i> <b>";
36: print mysql_field_name( $eredmeny, $x );
37: print "</b> <i>";
38: print mysql_field_flags( $eredmeny, $x );
39: print "</i><br>\n";
40: }
41: print "\t\t</dl>\n";
42: }
12_ora.qxd 8/3/2001 6:20 PM Page 232

232 12. óra

12.8 program (folytatás)


43: print "\t</dl>\n";
44: }
45: mysql_close( $kapcsolat );
46: ?>
47: </body>
48: </html>

Elõször is a szokásos módon a MySQL kiszolgálóhoz kapcsolódunk, majd meghív-


juk a mysql_list_dbs() függvényt. A kapott eredményazonosítót átadjuk
a mysql_fetch_row() függvénynek és az $adatbazisok tömb elsõ elemébe
betöltjük az aktuális adatbázis nevét.

Ezután megpróbáljuk kiválasztani az adatbázist a mysql_select_db()


függvénnyel. Ha nincs hozzáférési jogunk, akkor megjelenítjük a hibaüzenetet
a böngészõablakban, majd a continue utasítással továbblépünk a következõ
adatbázisra. Ha ki tudjuk választani az adatbázist, a mûveletet a táblanevek
kiírásával folytatjuk.

Az adatbázis nevét átadjuk a mysql_list_tables() függvénynek, tároljuk


az új eredményazonosítót, majd a mysql_fetch_row() függvénnyel kiolvassuk
a táblák neveit. Minden táblán a következõ mûveletsort hajtjuk végre: kiírjuk
a tábla nevét, majd összeállítunk egy SQL utasítást, amely az összes oszlopot
lekérdezi az adott táblában. A mysql_query() függvénnyel végrehajtjuk
a lekérdezést, majd az eredményazonosító alapján a mysql_num_fields()
függvénnyel meghatározzuk a mezõk számát.

A for ciklusban minden mezõn elvégezzük a következõ mûveletsort: beállítjuk


az $x változót, hogy az aktuális mezõ sorszámát tartalmazza (ez kezdetben 0).
Ezután a sorszám ismeretében meghívjuk az elõzõ részben tárgyalt összes ellen-
õrzõ függvényt, eredményüket pedig átlátható formában, táblázatba rendezve
elküldjük a böngészõnek.

Ezeket a mûveleteket minden elérhetõ adatbázison elvégezzük.

A program egy áttekinthetõ szerkezeti vázlatot jelenít meg a böngészõablakban,


amely az adott kapcsolaton keresztül elérhetõ összes adatbázist, adattáblát és
mezõt tartalmazza. A 12.2. ábra a program kimenetét mutatja.
12_ora.qxd 8/3/2001 6:20 PM Page 233

Adatbázisok kezelése – MySQL 233

12.2. ábra
Az összes elérhetõ
adatbázis, tábla és
mezõ listája

Összefoglalás 12
Ebben az órában a MySQL adatbáziskezelés alapjait tanultuk meg: az adatok
tárolását és visszanyerését.

Megtanultuk, hogyan építsük fel a kapcsolatot a MySQL kiszolgálóval


a mysql_connect() és mysql_pconnect() függvények segítségével.

Az adatbázist a mysql_select_db() függvénnyel választottuk ki. Ha a kivá-


lasztás nem sikerült, lekérdeztük a hibát a mysql_error() függvénnyel.

SQL utasításokat adtunk ki a mysql_query() függvény segítségével és


a függvény által visszaadott eredményazonosító segítségével elértük az adatokat
vagy megtudtuk a módosított sorok számát.

A PHP MySQL függvényeinek segítségével kiírattuk az elérhetõ adatbázisokat,


táblákat és mezõket, és az egyes mezõkrõl is bõvebb információkat szereztünk.
12_ora.qxd 8/3/2001 6:20 PM Page 234

234 12. óra

Kérdések és válaszok
Ez az óra szigorúan a MySQL-re vonatkozik. Hogyan ültethetjük át ezeket
a fogalmakat más adatbázissal mûködõ rendszerekre?
Az mSQL-kezelõ függvények például szinte teljesen megegyeznek a MySQL függ-
vényekkel, de más SQL kiszolgálóknak is megvannak a saját PHP függvényeik.
SQL utasításokat minden adatbáziskiszolgálónak küldhetünk. Ha szabványos ANSI
SQL-lel dolgozunk, nem lesz különösebb problémánk az adatbáziskiszolgálók kö-
zötti átálláskor.

Hogyan írhatunk olyan kódot, amelyet könnyû átültetni egy másik


adatbázis kiszolgáló környezetbe?
Gyakran jó ötlet az adatbázis-lekérdezõ függvényeket egy egyszerû osztályba vagy
könyvtárba csoportosítani. Így ha fel kell készíteni a kódot egy másik
adatbáziskezelõvel való együttmûködésre, a kódnak csak kis részét kell átírni.

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. Hogyan kell csatlakozni a MySQL adatbáziskiszolgálóhoz?

2. Melyik függvény szolgál az adatbázis kiválasztására?

3. Melyik függvénnyel küldhetünk SQL utasítást a kiszolgálónak?

4. Mit csinál a mysql_insert_id() függvény?

5. Tegyük fel, hogy küldtünk egy SELECT lekérdezést a MySQL-nek. Nevez-


zünk meg három függvényt, amelyekkel hozzáférhetünk az eredményhez.

6. Tegyük fel, hogy küldtünk egy UPDATE lekérdezést a MySQL-nek. Melyik


függvénnyel állapíthatjuk meg, hány sort érintett a módosítás?

7. Melyik függvényt kellene használnunk, ha az adatbáziskapcsolaton keresztül


elérhetõ adatbázisok nevét szeretnénk megtudni?

8. Melyik függvénnyel kérdezhetjük le az adatbázisban található táblák neveit?


12_ora.qxd 8/3/2001 6:20 PM Page 235

Adatbázisok kezelése – MySQL 235

Feladatok
1. Hozzunk létre egy adattáblát három mezõvel: email (legfeljebb 70 karakter),
uzenet (legfeljebb 250 karakter) és datum (a UNIX idõbélyegzõt tartalmazó
egész szám). Tegyük lehetõvé a felhasználóknak, hogy feltöltsék az adat-
bázist.

2. Készítsünk programot, amely megjeleníti az 1. pontban elkészített tábla


tartalmát.

12
12_ora.qxd 8/3/2001 6:20 PM Page 236
13_ora.qxd 8/3/2001 6:21 PM Page 237

13. ÓRA
Kapcsolat a külvilággal
Ezen az órán olyan függvényekkel ismerkedünk meg, amelyek a „külvilággal” való
érintkezést teszik lehetõvé. Az óra során a következõkrõl tanulunk:

• Környezeti változók – részletesebben

• A HTTP kapcsolat felépítése

• Távoli kiszolgálón levõ dokumentumok elérése

• Saját HTTP kapcsolat létrehozása

• Kapcsolódás más hálózati szolgáltatásokhoz

• Levélküldés programból
13_ora.qxd 8/3/2001 6:21 PM Page 238

238 13. óra

Környezeti változók
Már találkoztunk néhány környezeti változóval; ezeket a PHP a kiszolgáló segítségé-
vel bocsátotta rendelkezésünkre. Néhány ilyen változóval több dolgot is megtudha-
tunk weboldalunk látogatóiról, arra azonban gondoljunk, hogy lehet, hogy ezek
a változók a mi rendszerünkön nem elérhetõk, esetleg a kiszolgálóprogram nem
támogatja azokat, így használatuk elõtt érdemes ezt ellenõrizni. A 13.1. táblázat ezek
közül a változók közül mutat be néhányat.

13.1. táblázat Néhány hasznos környezeti változó


Változó Leírás
$HTTP_REFERER A programot meghívó webhely címe.
$HTTP_USER_AGENT Információ a látogató böngészõjérõl és rendszerérõl.
$REMOTE_ADDR A látogató IP címe.
$REMOTE_HOST A látogató számítógépének neve.
$QUERY_STRING Az a (kódolt) karakterlánc, amely a webcímet
kiegészíti (formátuma
kulcs=ertek&masikkulcs=masikertek). E kul-
csok és értékek elérhetõvé kell, hogy váljanak progra-
munk részére a megfelelõ globális változókban is.
$PATH_INFO Az esetleg a webcímhez illesztett további információ.

A 13.1. példaprogram ezen változók értékét jeleníti meg a böngészõben.

13.1. program Néhány környezeti változó felsorolása


1: <html>
2: <head>
3: <title>13.1. program Néhány környezeti változó
felsorolása</title>
4: </head>
5: <body>
6: <?php
7: $korny_valtozok = array( "HTTP_REFERER",
"HTTP_USER_AGENT", "REMOTE_ADDR", "REMOTE_HOST",
"QUERY_STRING", "PATH_INFO" );
13_ora.qxd 8/3/2001 6:21 PM Page 239

Kapcsolat a külvilággal 239

13.1. program (folytatás)


8: foreach ( $korny_valtozok as $valtozo )
9: {
10: if ( isset( $$valtozo ) )
11: print "$valtozo: ${$valtozo}<br>";
12: }
13: ?>
14: </body>
15: </html>

Figyeljük meg, hogyan alakítottuk a szövegként tárolt változóneveket valódi


változókká. Ezt a módszert a negyedik órán tanultuk.

A 13.1. ábrán a 13.1. kód kimenetét láthatjuk. Az ábrán látható adatokat úgy
kaptuk, hogy a programot egy másik oldal hivatkozásán keresztül hívtuk meg.
A programot meghívó hivatkozás így nézett ki:

<A HREF='13.1.program.php/tovabbi/utvonal?nev=ertek'>gyerünk</A>

Amint láthatjuk, a hivatkozás relatív útvonalat használ a 13.1.program.php


meghívására.

13.1. ábra 13
Néhány környezeti
változó kiíratása
a böngészõben

Az elérési út azon része, mely programunk nevét követi, (jelen esetben


a /tovabbi/utvonal) a $PATH_INFO változóban áll majd rendelkezésünkre.
13_ora.qxd 8/3/2001 6:21 PM Page 240

240 13. óra

A lekérdezés szövegét nem dinamikusan illesztettük a hivatkozásba (nev=ertek),


de ettõl függetlenül az a $QUERY_STRING változóban lesz elérhetõ. A lekérdezõ
karakterláncokkal legtöbbször akkor találkozunk, ha egy GET metódust használó
ûrlap hívja meg a programot, de magunk is elõállíthatunk ilyet, hogy segítségével
adatokat továbbíthassunk lapról lapra. A lekérdezõ karakterlánc név–érték párok-
ból áll, melyeket ÉS jel (&) választ el egymástól. Az adatpárok URL kódolású formá-
ban kerülnek a webcímbe, hogy a bennük szereplõ, a webcímekben nem megen-
gedett vagy mást jelentõ karakterek ne okozzanak hibát. Ezt úgy oldották meg,
hogy a problémás karaktereket hexadecimális megfelelõjükre cserélik. Bár a teljes
karakterlánc elérhetõ a $QUERY_STRING környezeti változóban, nagyon ritkán le-
het szükségünk rá, pontosan a kódolt mivolta miatt. De azért is mellõzük a haszná-
latát, mert az összes név–érték pár rendelkezésünkre áll globális változók formájá-
ban is (jelen esetben például létrejön a $nev változó és az értéke ertek lesz).

A $HTTP_REFERER változó értéke akkor lehet hasznos számunkra, ha nyomon


szeretnénk követni, hogy programunkat mely hivatkozáson keresztül érték el.
Nagy körültekintéssel kell eljárnunk azonban, mert ez és tulajdonképpen bármely
másik környezeti változó is nagyon könnyen „meghamisítható”. (Az óra folyamán
azt is megtudhatjuk, hogyan.) A nevet sajnálatos módon a kezdetekkor egy fejlesz-
tõ elírta (helyesen HTTP_REFERRER-nek kellene neveznünk), módosítása
a korábbi változatokkal való összeegyeztethetõség megõrzése érdekében nem
történt meg. Ezenkívül nem minden böngészõ adja meg ezt az információt, így
használatát célszerû elkerülnünk.

A $HTTP_USER_AGENT változó szétbontásával rájöhetünk, milyen operációs


rendszert, illetve böngészõt használ a látogató, de tudnunk kell, hogy ezek
az adatok is hamisíthatók. A változóban elérhetõ értéket akkor használhatjuk, ha
a böngészõ típusától vagy a változattól függõen más és más HTML kódot vagy
JavaScriptet szeretnénk elküldeni a látogatónak. A tizenhetedik és tizennyolcadik
órában mindent megtanulunk arról, hogyan nyerhetjük ki a számunkra fontos ada-
tokat ebbõl a karakterláncból.

A $REMOTE_ADDR változó a látogató IP címét tartalmazza, így a webhely látogató-


inak azonosítására használható. Ne feledjük azonban, hogy a felhasználók IP címe
többnyire nem állandó, hiszen az internetszolgáltatók általában dinamikusan
osztják ki felhasználóiknak a címeket, így az minden csatlakozás során más lehet,
tehát ugyanaz az IP cím különbözõ látogatókat jelenthet és a különbözõ IP címek
is takarhatnak egyetlen felhasználót.

A $REMOTE_HOST változó nem biztos, hogy hozzáférhetõ; ez a kiszolgáló beállí-


tásaitól függ. Ha létezik, a felhasználó számítógépének nevét találhatjuk benne.
A változó meglétéhez a kiszolgálónak az IP cím alapján minden kéréskor le kell
kérdeznie a gép nevét, ami idõigényes feladat, így a kiszolgáló ezen képességét
13_ora.qxd 8/3/2001 6:21 PM Page 241

Kapcsolat a külvilággal 241

a hatékonyság kedvéért gyakran letiltják. Ha nem létezne ilyen változó, az infor-


mációhoz a $REMOTE_ADDR segítségével juthatunk hozzá; késõbb azt is látjuk
majd, hogyan.

A HTTP ügyfél-kiszolgáló kapcsolat rövid ismertetése


A kiszolgáló és az ügyfél közti adatforgalom részletes ismertetése túlmutat köny-
vünk keretein, többek között azért, mert a PHP ezen részletek szakszerû kezelésé-
rõl is gondoskodik helyettünk. A folyamatot azonban nem hiábavaló alapjaiban
megismerni, mert szükségünk lehet rá, ha olyan programot szeretnénk írni, amely
weboldalakat tölt le vagy webcímek állapotát ellenõrzi.

A HTTP jelentése hiperszöveg-átviteli protokoll. Nem más, mint szabályok


ÚJDONSÁG
halmaza, melyek elõírják, hogy az ügyfél milyen kérésekkel fordulhat
a kiszolgálóhoz és az milyen válaszokat kell, hogy adjon. Mind az ügyfél, mind a ki-
szolgáló információt szolgáltat magáról és a küldött adatokról. Ezen információk leg-
többjét a PHP-bõl környezeti változókon keresztül érhetjük el.

A kérés
Az ügyfél szigorú szabályok szerint kérhet adatokat a kiszolgálótól. A kérés legfel-
jebb három részbõl állhat:

• A kérés sora
13
• Fejléc

• Törzs

A legfontosabb a kérés sora. Itt határozzuk meg a kérés fajtáját (GET, HEAD vagy
POST), a kért dokumentum címét és az átviteli protokoll változatszámát
(HTTP/1.0 vagy HTTP/1.1). Egy jellemzõ kérés a következõképpen néz ki:

GET /egy_dokumentum.html HTTP/1.0

Ekkor az ügyfél egy GET kérést kezdeményez. Más szóval lekér egy dokumentumot,
de adatokat nem küld. (Valójában kisebb mennyiségû adat küldésére a GET kérés
alkalmazásakor is van lehetõség, ha azt lekérdezõ karakterlánc formájában hozzáír-
juk az URL végéhez.) A HEAD módszer akkor alkalmazandó, ha nem magára
a dokumentumra, csak annak tulajdonságaira vagyunk kíváncsiak, végül a POST
kérés arra szolgál, hogy adatokat küldjünk az ügyféltõl a kiszolgálónak. Ez legtöbb-
ször HTML ûrlapok esetében használatos.
13_ora.qxd 8/3/2001 6:21 PM Page 242

242 13. óra

A kifogástalan GET kéréshez egyetlen kérõsor elküldése is elegendõ. A kérés


végét úgy tudathatjuk a kiszolgálóval, hogy egy üres sort küldünk neki.

A legtöbb ügyfél (általában böngészõprogram) a kérõsoron kívül küld egy fejléc


részt is, amely név–érték párokból áll. Az oldal lekérésével érkezett fejlécek
legtöbbjéhez környezeti változók formájában hozzá is férhetünk programunkból.
Az ügyfél fejlécének minden sora egy kettõsponttal elválasztott névbõl és értékbõl
áll. A 13.2 táblázat néhány lehetséges fejléc-nevet sorol fel.

13.2 táblázat Néhány fejléc-kulcs


Név Leírás
Accept Az ügyfél által kezelhetõ dokumentumtípusok listája.
Accept-Encoding Az ügyfél számára elfogadható kódolási és
tömörítési formátumok listája.
Accept-Charset Az ügyfél által elõnyben részesített nemzetközi
karakterkészlet.
Accept-Language Az ügyfél által elõnyben részesített nyelv
(a magyar nyelv esetében „hu”).
Host Az ügyfél kérése által megcímzett gép neve. Egyes
kiszolgálók csak látszólagos (virtuális) kiszolgálók,
a beérkezõ kéréseket nem önálló számítógép kezeli.
Ilyen esetekben komoly jelentõsége van ennek
az adatnak.
Referer Azon dokumentum címe, melynek egyik hivatkozása
alapján a kérés létrejött.
User-Agent Az ügyfélprogram típusa és változatszáma.

A GET és a HEAD eljárásoknál a kérést a fejléc és az utána következõ üres sor


zárja, a POST típusnál azonban az üres sort az üzenet törzse követi. A törzs tartal-
mazza a kiszolgálónak szóló összes adatot, jobbára URL kódolású név–érték pá-
rok, a lekérdezõ karakterláncokhoz hasonlóan.

A 13.2 példában egy jellemzõ, mindennapos kérést mutatunk be, melyet egy
Netscape 4.7 kezdeményezett.
13_ora.qxd 8/3/2001 6:21 PM Page 243

Kapcsolat a külvilággal 243

13.2. példa Jellemzõ Netscape-kérés


GET / HTTP/1.0
Referer: http://www.linuxvilag.hu/index.html
Connection: Keep-Alive
User-Agent: Mozilla/4.7 [en] (X11; I; Linux 2.2.13 i686)
Host: www.kiskapu.hu
Accept: image/gif, image/x-xbitmap, image/jpeg,
image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8

A válasz
Miután a kiszolgáló fogadta az ügyfél kérését, választ küld. A válasz általában
a következõ három részbõl tevõdik össze:

• Állapot

• Fejléc

• Törzs

Amint látjuk, a kérés és a válasz szerkezete igen hasonló. A fejléc bizonyos sorai
13
tulajdonképpen ügyfél és kiszolgáló által küldve egyaránt megállják helyüket,
nevezetesen azok, amelyek a törzsre vonatkoznak.

Az állapot sor a kiszolgáló által használt protokollt (HTTP/1.0 vagy HTTP/1.1)


adja meg, illetve egy válaszkódot és egy azt magyarázó szöveget.

Számos válaszkód létezik, mindegyik a kérés sikerességérõl vagy sikertelenségérõl


ad információt. A 13.3-as táblázat a leggyakoribb kódok jelentését tartalmazza.
13_ora.qxd 8/3/2001 6:21 PM Page 244

244 13. óra

13.3 táblázat Néhány válaszkód


Kód Szöveg Leírás
200 OK A kérés sikeres volt és a törzsben
megtalálható a válasz.
301 Moved Permanently A kért adat nem található a kiszolgálón, de
a fejlécben megtalálható annak új helye.
302 Moved Temporarily A kért adatot ideiglenesen áthelyezték, de
a fejléc elárulja, hogy hová.
404 Not Found A kért adat nem található a megadott címen.
500 Internal Server A kiszolgáló vagy egy CGI program komoly
Error problémába ütközött a kérés teljesítése során.

Ennek megfelelõen a jellegzetes válaszsor a következõképpen fest:

HTTP/1.1 200 OK

A fejléc rész a válaszfejléc soraiból áll, melyek formátuma a kérésfejléc soraihoz


hasonló. A 13.4 táblázat a legsûrûbben alkalmazott fejlécelemekbõl szemezget.

13.4 táblázat A kiszolgáló válaszfejlécének leghétköznapibb elemei


Név Leírás
Date Az aktuális dátum
Server A kiszolgáló neve és változatszáma
Content-Type A törzsben szereplõ adat MIME típusa
Content-Length A törzs mérete bájtban
Location Egy alternatív dokumentum teljes elérési útja
(kiszolgálóoldali átirányítás esetén)

Miután a kiszolgáló elküldte a fejlécet és a szokásos üres sort, elküldi a törzset


(a kérésben tulajdonképpen igényelt dokumentumot). A 13.3 példa egy jellemzõ
választ mutat be.
13_ora.qxd 8/3/2001 6:21 PM Page 245

Kapcsolat a külvilággal 245

13.3. példa A kiszolgáló válasza


1: HTTP/1.1 200 OK
2: Date: Sun, 30 Jan 2000 18:02:20 GMT
3: Server: Apache/1.3.9 (Unix)
4: Connection: close
5: Content-Type: text/html
6:
7: <html>
8: <head>
9: <title>13.3. lista A kiszolgáló válasza</title>
10: </head>
11: <body>
12: Üdvözlet!
13: </body>
14: </html>

Dokumentum letöltése távoli címrõl


Bár a PHP kiszolgálóoldali nyelv, esetenként ügyfélként viselkedve adatokat kérhet
egy távoli címrõl és a kapott adatokat programunk rendelkezésére bocsáthatja.
Ha már jártasak vagyunk a kiszolgálón lévõ fájlok kezelésében, nem okozhat
komoly gondot a távoli helyen lévõ adatok lekérése sem. Az a helyzet ugyanis,
hogy a kettõ között – formailag – semmi különbség nincs. Az fopen()-nel
13
ugyanúgy megnyithatunk egy webcímet, ahogy azt egy fájl esetében tennénk.
A 13.4. példaprogram egy távoli kiszolgálóhoz kapcsolódva adatokat kér le, majd
megjeleníti azokat a böngészõben.

13.4. program Weboldal letöltése és megjelenítése az fopen()-nel


1: <html>
2: <head>
3: <title>13.4. program Weboldal letöltése és megjele-
nítése az fopen()-nel</title>
4: </head>
5: <body>
6: <?php
7: $weboldal = "http://www.php.net/index.php";
8: $fajlmutato = fopen( $weboldal, "r" ) or
die("A $weboldal nem nyitható meg");
13_ora.qxd 8/3/2001 6:21 PM Page 246

246 13. óra

13.4. program (folytatás)


9: while ( ! feof( $fajlmutato ))
10: print fgets( $fajlmutato, 1024 );
11: ?>
12: </body>
13: </html>

Ha megnézzük ezt az oldalt, akkor a PHP honlapját kell látnunk, azzal a kis
különbséggel, hogy a képek nem jelennek meg. Ennek oka, hogy az oldalon talál-
ható IMG hivatkozások általában relatívak, így az oldal megjelenítésekor a böngé-
szõ a mi kiszolgálónkon keresi azokat. Ezen úgy segíthetünk, hogy a HEAD HTML
elemet az alábbi sorral bõvítjük:

<base href="http://www.php.net/index.php">

Az esetek többségében azonban nem a letöltött adatok megjelenítése, hanem


a feldolgozás a feladat.

Az fopen() egy fájlmutatóval tér vissza, ha sikerült felépítenie a kapcsolatot és


false (hamis) értékkel, ha nem jött létre a kapcsolat vagy nem találta a fájlt.
A kapott fájlmutató a továbbiakban ugyanúgy használható az olvasáshoz, mint
a helyi fájlok kezelése esetében. A PHP a távoli kiszolgálónak úgy mutatkozik be,
mint egy PHP ügyfél. A szerzõ rendszerén a PHP a következõ kérést küldi el:

GET /index.php HTTP/1.0


Host: www.php.net
User-Agent: PHP/4.0.3

Ez a megközelítés elég egyszerû, így az esetek többségében elegendõ,


ha ezt alkalmazzuk weblapok letöltéséhez. Szükségünk lehet viszont más hálózati
szolgáltatásokhoz való kapcsolódásra, vagy épp csak többet szeretnénk megtudni
a dokumentumról, elemezve annak fejlécét. Ekkor már más eszközökhöz kell
folyamodnunk. Hogy ezt hogyan tehetjük meg? Nos, az óra folyamán lesz még
errõl szó.

Átalakítás IP címek és gépnevek között


Ha kiszolgálónk nem is bocsátja rendelkezésünkre a látogató gépének nevét
a $REMOTE_HOST változóban, a látogató címéhez minden bizonnyal hozzájutha-
tunk a $REMOTE_ADDR változóból. A változóra alkalmazva a gethostbyaddr()
függvényt megtudhatjuk a látogató gépének nevét. A függvény egy IP címet ábrázo-
13_ora.qxd 8/3/2001 6:21 PM Page 247

Kapcsolat a külvilággal 247

ló karakterláncot vár paraméterként és az annak megfelelõ gépnévvel tér vissza.


Ha hiba lép fel a név elõállítása során, kimenetként a beadott IP címet kapjuk meg
változatlanul. A 13.5-ös program a $REMOTE_HOST hiánya esetén
a gethostbyaddr() függvény segítségével elõállítja a felhasználó gépének nevét.

13.5. program Gépnév lekérdezése a gethostbyaddr() segédletével


1: <html>
2: <head>
3: <title>13.5. program Gépnév lekérdezése
a gethostbyaddr() segédletével</title>
4: </head>
5: <body>
6: <?php
7: if ( isset( $REMOTE_HOST ) )
8: print "Üdvözöljük $REMOTE_HOST<br>";
9: elseif ( isset ( $REMOTE_ADDR ) )
10: print " Üdvözöljük
".gethostbyaddr( $REMOTE_ADDR )."<br>";
11: else
12: print " Üdvözöljük, akárki is Ön.<br>";
13: ?>
14: </body>
15: </html>
13
Ha a $REMOTE_HOST változó létezik, egyszerûen megjelenítjük annak értékét.
Ha nem létezik, megpróbáljuk a $REMOTE_ADDR alapján a gethostbyaddr()
függvénnyel elõállítani a gépnevet. Ha minden kísérletünk csõdöt mondott, álta-
lános üdvözlõ szöveget jelenítünk meg.

Egy gép címének a név alapján történõ meghatározásához a gethostbyname()


függvényt használhatjuk. Ennek paramétere egy gépnév, visszatérési értéke pedig
hiba esetén ugyanez a gépnév, sikeres átalakítás esetén viszont a megnevezett gép
IP címe.

Hálózati kapcsolat létesítése


Eddig minden feladatunkat könnyen meg tudtuk oldani, mert a PHP a távoli
weblapok lekérését közönséges fájlkezeléssé egyszerûsítette számunkra.
Néha azonban nagyobb felügyeletet kell gyakorolnunk egy-egy hálózati kapcsolat
felett, de legalábbis a szokásosnál több jellemzõjét kell ismernünk.
13_ora.qxd 8/3/2001 6:21 PM Page 248

248 13. óra

A hálózati kiszolgálók felé az fsockopen() függvénnyel nyithatunk meg


egy kapcsolatot. Paramétere egy IP cím vagy gépnév, egy kapuszám és két válto-
zóhivatkozás. Változóhivatkozásokat úgy készítünk, hogy ÉS (&) jelet írunk
a változó neve elé. Megadhatunk továbbá egy nem kötelezõ idõkorlát-paramétert
is, amely annak az idõtartamnak a hossza (másodpercben), ameddig a függvény
vár a kapcsolat létrejöttére. Ha sikerült megteremtenie a kapcsolatot, egy fájlmuta-
tóval tér vissza, egyébként pedig false értéket ad.

A következõ kódrészlet kapcsolatot nyit egy webkiszolgáló felé.

$fajlmutato = fsockopen( "www.kiskapu.hu", 80, &$hibakod,


å &$hibaszoveg, 30 );

A webkiszolgálók általában a 80-as kapun várják a kéréseket.

Az elsõ hivatkozott változó, a $hibaszam sikertelen mûvelet esetén egy hiba-


kódot tartalmaz, a $hibaszoveg pedig bõvebb magyarázattal szolgál a hibáról.

Miután visszakaptuk a kapcsolat fájlmutatóját, a kapcsolaton keresztül az fputs()


és fgets() függvények segítségével írhatunk és olvashatunk is, ahogy ezt
egy közönséges fájl esetében is tehetjük. Munkánk végeztével a kapcsolatot
az fclose() függvénnyel bonthatjuk.

Most már elegendõ tudás birtokában vagyunk ahhoz, hogy kapcsolatot létesíthes-
sünk egy webkiszolgálóval. A 13.6-os programban megnyitunk egy HTTP kapcso-
latot, lekérünk egy fájlt, majd egy változóban tároljuk azt.

13.6. program Weboldal lekérése az fsockopen() használatával


1: <html>
2: <head>
3: <title>13.6. program Weboldal lekérése az fsockopen()
használatával</title>
4: </head>
5: <body>
6: <?php
7: $kiszolgalo = "www.kiskapu.hu";
8: $lap = "/index.html";
9: $fajlmutato = fsockopen( "$kiszolgalo", 80,
&$hibaszam, &$hibaszoveg);
10: if ( ! $fajlmutato )
13_ora.qxd 8/3/2001 6:21 PM Page 249

Kapcsolat a külvilággal 249

13.6. program (folytatás)


11: die ( "Nem sikerült kapcsolódni a $kiszolgalo
géphez:\nA hiba kódja: $hibaszam\nA hiba
szövege: $hibaszoveg\n" );
12:
13: $lekeres = "GET $lap HTTP/1.0\r\n";
14: $lekeres .= "Host: $kiszolgalo\r\n";
15: $lekeres .= "Referer:
http://www.linuxvilag.hu/index.html\r\n";
16: $lekeres .= "User-Agent: PHP browser\r\n\r\n";
17: $lap = array();
18: fputs ( $fajlmutato, $lekeres );
19: while ( ! feof( $fajlmutato ) )
20: $lap[] = fgets( $fajlmutato, 1024 );
21: fclose( $fajlmutato );
22: print "A kiszolgáló ".(count($lap))."
sort küldött el!";
23: ?>
24: </body>
25: </html>

Figyeljük meg, milyen kérésfejlécet küldtünk a kiszolgálónak. A távoli gép


webmestere a fejléc User-Agent sorában feltüntetett adatokat látni fogja
a webkiszolgáló naplójában. A webmester számára ráadásul úgy fog tûnni, mintha
13
a http://www.linuxvilag.hu/index.html címrõl mutatott volna
egy hivatkozás a kért oldalra és mi ennek segítségével kértük volna le az oldalt.
Emiatt programjainkban némi fenntartással kell kezelnünk az ezen fejlécekbõl
elõálló környezeti változók tartalmát és sokkal inkább segédadatoknak kell
azokat tekintenünk, mintsem tényeknek.

Vannak esetek, amikor meg kell hamisítani a fejléceket. Szükségünk lehet például
olyan adatokra, amelyeket a kiszolgáló csak Netscape böngészõnek küld el.
Ezek elérésének egyetlen módja, ha a User-Agent fejlécsorban egy Netscape
böngészõre jellemzõ karakterláncot küldünk. Ennek a webmesterek nem igazán
örülnek, hiszen döntéseiket a kiszolgáló gyûjtötte statisztikák alapján kell meghoz-
niuk. Hogy segíthessünk ebben nekik, lehetõleg ne hamisítsuk meg adatainkat,
hacsak feltétlenül nem szükséges.

A 13.6-os program nem sokkal bõvítette a PHP beépített lapkérõ módszereit.


A 13.7-es példa azonban már az fsockopen()-es módszert alkalmazza
egy tömbben megadott weboldalak letöltéséhez és közben a kiszolgáló által
visszaadott hibakódokat is ellenõrzi.
13_ora.qxd 8/3/2001 6:21 PM Page 250

250 13. óra

13.7. program Az állapotsor megjelenítése webkiszolgálók válaszaiból


1: <html>
2: <head>
3: <title>13.7. program Az állapotsor megjelenítése
webkiszolgálók válaszaiból</title>
4: </head>
5: <body>
6: <?php
7: $ellenorzendo = array ( "www.kiskapu.hu" =>
"/index.html",
8: "www.virgin.com" =>
"/nincsilyenlap.html",
9: "www.4332blah.com" =>
"/nemletezogep.html"
10: );
11: foreach ( $ellenorzendo as $kiszolgalo => $lap )
12: {
13: print "Csatlakozási kísérlet a $kiszolgalo géphez
...<BR>\n";
14: $fajlmutato = fsockopen( "$kiszolgalo", 80,
&$hibaszam, &$hibaszoveg, 10);
15: if ( ! $fajlmutato )
16: {
17: print "A $kiszolgalo géphez nem sikerült
csatlakozni:\n<br>A hiba kódja:
$hibaszam\n<br>Szövege: $hibaszoveg\n";
18: print "<br><hr><br>\n";
19: continue;
20: }
21: print "A $lap oldal fejlécének letöltése ...<br>\n";
22: fputs( $fajlmutato, “HEAD $lap HTTP/1.0\r\n\r\n" );
23: print fgets( $fajlmutato, 1024 );
24: print "<br><br><br>\n";
25: fclose( $fajlmutato );
26: }
27: ?>
28: </body>
29: </html>

Elõször létrehozunk egy asszociatív tömböt az ellenõrzendõ kiszolgálónevekbõl és


az oldalak címeibõl. Ezeket sorra vesszük a foreach utasítás segítségével. Minden
elemnél az fsockopen()-nel kezdeményezünk egy kapcsolatot az adott címmel,
13_ora.qxd 8/3/2001 6:21 PM Page 251

Kapcsolat a külvilággal 251

de a válaszra csak 10 másodpercig várunk. Ha ezen belül nem érkezne válasz,


üzenetet jelenítünk meg a böngészõben, majd a continue utasítással a következõ
címre lépünk. Ha a kapcsolatteremtés sikeres volt, kérelmet is küldünk a kiszolgá-
lónak. A kéréshez a HEAD eljárást használjuk, mert a lap tartalmára nem vagyunk
kíváncsiak. Az fgets() segítségével beolvassuk az elsõ sort, az állapotsort.
A jelen példában nem elemezzük a fejléc többi részét, ezért lezárjuk a kapcsolatot
az fclose() függvénnyel, majd továbblépünk a következõ címre.

A 13.2-es ábrán a 13.7. program kimenete látható.

13.2. ábra
Kiszolgálók válaszát
megjelenítõ program

13
NNTP kapcsolat létrehozása az fsockopen()-nel
Az fsockopen() függvény tetszõleges internetkiszolgálóval képes kapcsolatot
teremteni. A 13.8. példában egy NNTP (Usenet) kiszolgálóhoz kapcsolódunk:
kiválasztunk egy hírcsoportot, majd megjelenítjük elsõ üzenetének fejlécét.

13.8. program Egyszerû NNTP kapcsolat az fsockopen() használatával


1: <html>
2: <head>
3: <title>13.8. program Egyszerû NNTP kapcsolat az
fsockopen() használatával</title>
4: </head>
5: <body>
6: <?php
7: $kiszolgalo = "news"; // ezt saját hírkiszolgálónk
címére kell beállítanunk
13_ora.qxd 8/3/2001 6:21 PM Page 252

252 13. óra

13.8. program (folytatás)


8: $csoport = "alt.test";
9: $sor = "";
10: print "<pre>\n";
11: print "— Csatlakozás a $kiszolgalo
kiszolgálóhoz\n\n";
12: $fajlmutato = fsockopen( "$kiszolgalo", 119,
&$hibaszam, &$hibaszoveg, 10 );
13: if ( ! $fajlmutato )
14: die("Csatlakozás a $kiszolgalo géphez
sikertelen\n$hibaszam\n$hibaszoveg\n\n");
15: print "— Kapcsolat a $kiszolgalo géppel
felvéve\n\n";
16: $sor = fgets( $fajlmutato, 1024 );
17: $allapot = explode( " ", $sor );
18: if ( $allapot[0] != 200 )
19: {
20: fputs( $fajlmutato, "close" );
21: die("Hiba: $sor\n\n");
22: }
23: print "$sor\n";
24: print "— A $csoport kiválasztása\n\n";
25: fputs( $fajlmutato, "group ".$csoport."\n" );
26: $sor = fgets( $fajlmutato, 1024 );
27: $allapot = explode( " ", $sor );
28: if ( $allapot[0] != 211 )
29: {
30: fputs( $fajlmutato, "close" );
31: die("Hiba: $sor\n\n");
32: }
33: print "$sor\n";
34: print "— Az elsõ üzenet fejlécének lekérése\n\n";
35: fputs( $fajlmutato, "head\n" );
36: $sor = fgets( $fajlmutato, 1024 );
37: $allapot = explode( " ", $sor );
38: print "$sor\n";
39: if ( $allapot[0] != 221 )
40: {
41: fputs( $fajlmutato, "close" );
42: die("Hiba: $sor\n\n");
43: }
13_ora.qxd 8/3/2001 6:21 PM Page 253

Kapcsolat a külvilággal 253

13.8. program (folytatás)


44: while ( ! ( strpos($sor, ".") === 0 ) )
45: {
46: $sor = fgets( $fajlmutato, 1024 );
47: print $sor;
48: }
49: fputs( $fajlmutato, "close\n" );
50: print "</pre>";
51: ?>
52: </body>
53: </html>

A 13.8. program egy kicsit többet mutat annál, hogyan nyissunk az fsockopen()-
nel NNTP kapcsolatot. Valós alkalmazás esetén a visszakapott sorok elemzését
célszerû egy függvénnyel végezni, egyrészt azért, hogy megszabaduljunk az ismét-
lésektõl, másrészt azért, hogy több adatot is kinyerhessünk a válaszból. Mielõtt
azonban újra feltalálnánk a kereket, célszerû, ha megismerkedünk a PHP IMAP
függvényeivel, amelyekkel mindez a munka automatizálható.

A fenti programban a $kiszolgalo változó tárolja a hírkiszolgáló nevét,


a $csoport pedig annak a csoportnak a nevét, melyhez kapcsolódni szeretnénk.
Ha ki szeretnénk próbálni ezt a programot, javítsuk át a $kiszolgalo változó ér-
tékét az internetszolgáltatónk által megadott hírkiszolgáló nevére, a $csoport-ot
kedvenc csoportunkra. Az fsockopen()-nel a kiszolgáló 119-es kapujára csatla-
13
kozunk, mert ez a hírcsoport szolgáltatás szabványos kapuja. Ha nem kapunk
vissza használható fájlmutatót, a die() függvény segítségével megjelenítünk egy
hibaüzenetet a böngészõben és kilépünk a programból. Kapcsolódás esetén a ki-
szolgálótól kapnunk kell egy nyugtázó üzenetet, amit az fgets() függvénnyel
próbálunk fogadni. Ha minden zökkenõmentesen zajlott, a visszakapott szöveg
a 200-as állapotkóddal kezdõdik. Ennek ellenõrzéséhez az explode() függ-
vénnyel a szóközök mentén szétdaraboljuk a $sor változót és a darabokat egy
tömbbe helyezzük. Az explode() függvénnyel részletesebben a tizenhetedik órá-
ban foglalkozunk. Ha a kapott tömb elsõ eleme (a nullás indexû) 200, akkor to-
vábblépünk, egyébként pedig befejezzük a programot.

Ha minden az elvárásoknak megfelelõen haladt, akkor a "group" paranccsal ki-


választjuk a kívánt hírcsoportot. Ha ez is sikerült, a kiszolgálónak egy 211-es álla-
potkóddal kezdõdõ szöveget kell válaszul küldenie. Ezt is ellenõrizzük és sikerte-
lenség esetén kilépünk a programból.
13_ora.qxd 8/3/2001 6:21 PM Page 254

254 13. óra

A hírcsoport kiválasztása után küldünk egy "head" parancsot. Ennek hatására


visszakapjuk a csoport elsõ üzenetének fejlécét. Természetesen kérésünkre ez eset-
ben is elõször egy nyugta érkezik, mely a 211-es állapotkódot kell, hogy tartal-
mazza. A fejléc csak ezt követõen érkezik, számos hasznos információt tartalmazó
sorral. A fejlécet záró sor egyetlen pontot tartalmaz. Ezt a sort egy while ciklussal
keressük meg. Mindaddig, míg a kiszolgáló válaszsora nem ponttal kezdõdik,
további sorokat olvasunk be és mindegyiket megjelenítjük a böngészõben.

Végsõ lépésként bontjuk a kapcsolatot. A 13.3-as ábra a 13.8-as program


egy lehetséges eredményét mutatja be.

13.3. ábra
NNTP kapcsolat
megteremtése

Levél küldése a mail() függvénnyel


A PHP leveszi a vállunkról az elektronikus levelezés gondját is. A mail() függ-
vény három karakterláncot vár paraméterként. Az elsõ a címzett, a második a levél
tárgya, a harmadik pedig maga az üzenet. A mail() false értékkel tér vissza,
ha problémába ütközik a levél küldése során. A következõ kódrészlet egy rövid
levél küldését példázza:

$cimzett = "valaki@tartomany.hu";
$targy = "üdvözlet";
$uzenet = "ez csak egy próba üzenet! ";
mail( $cimzett, $targy, $uzenet ) or
å print "A levél elküldése sikertelen";
13_ora.qxd 8/3/2001 6:21 PM Page 255

Kapcsolat a külvilággal 255

Ha a PHP-t UNIX rendszeren futtatjuk, a Sendmailt fogja használni, más rendsze-


reken a helyi vagy egy távoli SMTP kiszolgálót fog feladata elvégzéséhez igénybe
venni. A kiszolgálót a php.ini fájl SMTP utasításával kell beállítani.

Nem kell a mail() kötelezõ paraméterei által elõállított fejlécekre szorítkoznunk.


A függvénynek van ugyanis egy elhagyható negyedik paramétere is, mellyel
szabadon alakíthatjuk az elküldendõ levél fejléceit. Az ebben felsorolt fejlécso-
rokat a CRLF (\r\n) karakterpárral kell elválasztanunk. Az alábbi példában egy
From (Feladó) és egy X-Priority (Fontosság) mezõvel bõvítjük a fejlécet.
Ez utóbbit csak bizonyos levelezõrendszerek veszik figyelembe. A példa
a következõ:

$cimzett = "valaki@tartomany.hu";
$felado = "masvalaki@masiktartomany.hu";
$targy = "üdvözlet ";
$uzenet = "ez csak egy proba üzenet! ";
mail( $cimzett, $targy, $uzenet,
å "From: $felado\r\nX-Priority: 1 (Highest)" )
or print "A levél elküldése sikertelen";

Összefoglalás
Ezen az órán megtudhattuk, hogyan vethetjük be a környezeti változókat, ha több
adatot szeretnénk megtudni látogatóinkról. Ha nem tudjuk a látogató gépének
nevét, a gethostbyaddr() függvénnyel kideríthetjük.
13
Láthattuk miként zajlik egy HTTP kapcsolat megteremtése a kiszolgáló és
az ügyfél között, megtanultuk, hogyan töltsünk le egy dokumentumot a webrõl
az fopen() segítségével és hogyan építsük ki saját HTTP kapcsolatunkat
az fsockopen() függvény felhasználásával. Az fsockopen()-nel más hálózati
szolgáltatásokhoz is kapcsolódtunk, végül pedig elektronikus levelet küldtünk
a programból a mail() függvény egyszerû meghívásával.

Kérdések és válaszok
A HTTP meglehetõsen misztikusnak tûnik. Tényleg szükség van az ismere-
tére, ha jó PHP kódot szeretnénk írni?
Nem. Kitûnõ programok készíthetõk a kiszolgáló-ügyfél párbeszéd részletes isme-
rete nélkül is. Másfelõl azonban szükség van ilyen alapvetõ ismeretekre, ha kicsit
bonyolultabb feladatokat szeretnénk programozottan végrehajtani, például
weboldalakat letölteni.
13_ora.qxd 8/3/2001 6:21 PM Page 256

256 13. óra

Ha én is könnyedén küldhetek hamis fejléceket, akkor mennyire bízhatok


a mások fejlécei alapján létrehozott környezeti változókban?
Az olyan környezeti változókban, mint a $HTTP_REFERER vagy
a $HTTP_USER_AGENT, nem szabad megbíznunk, amennyiben ezen információk
pontos ismerete programunkban alapvetõ követelmény. Az ügyfélprogramok
tekintélyes hányada azonban nem hazudik: ha a böngészõtípust és az egyéb
felhasználói jellemzõket olyan céllal gyûjtjük, hogy az abból készített statisztikák
elemzése alapján a felhasználókat jobban szolgálhassuk, nincs értelme foglalkoz-
nunk azzal, hogy nem minden adat feltétlenül helytálló.

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. Mely környezeti változó árulja el nekünk annak a lapnak a címét, amely
a programunkra hivatkozott?

2. Miért nem felel meg a $REMOTE_ADDR változó a látogató nyomon


követésére?

3. Minek a rövidítése és mit jelent a HTTP?

4. A fejléc mely sorából tudhatja meg a kiszolgáló, hogy milyen ügyfélprog-


ramtól érkezett a kérés?

5. Mit takar a kiszolgáló 404-es válaszkódja?

6. Anélkül, hogy külön kapcsolatot építenénk fel egy kiszolgálóval, mely


függvénnyel tölthetünk le egy weboldalt róla?

7. Adott IP cím alapján hogyan deríthetõ ki a hozzá tartozó gép neve?

8. Melyik függvény használható hálózati kapcsolat létrehozására?

9. A PHP mely függvényével küldenénk elektronikus levelet?


13_ora.qxd 8/3/2001 6:21 PM Page 257

Kapcsolat a külvilággal 257

Feladatok
1. Készítsünk egy programot, amely egy webcímet kér be (például
http://www.kiskapu.hu/) a felhasználótól, majd egy HEAD kérést
küldve felveszi a kapcsolatot azzal. Jelenítsük meg a kapott választ a böngé-
szõben. Ne feledkezzünk meg arról, hogy a kapcsolat nem mindig jön létre.

2. Készítsünk olyan programot, amely a felhasználónak lehetõvé teszi, hogy


begépeljen némi szöveget, majd elektronikus levél formájában továbbítsa
azt a mi e-mail címünkre. Áruljuk el a felhasználónak, hogy a környezeti
változók mit is állítanak róla.

13
13_ora.qxd 8/3/2001 6:21 PM Page 258
14_ora.qxd 8/3/2001 6:21 PM Page 259

14. ÓRA
Dinamikus képek kezelése
Az ezen az órán vett függvények a GD nevû nyílt forráskódú programkönyvtáron
alapulnak.

A GD könyvtár olyan eszközcsoport, melynek segítségével futásidõben képeket


hozhatunk létre és kezelhetjük azokat. A GD-rõl a http://boutell.com/gd/
weboldal szolgál bõvebb információval. Ha a könyvtárat telepítettük és a PHP-t is
lefordítottuk, elkezdhetünk dinamikus képeket létrehozni a PHP grafikus függvé-
nyeivel. Sok rendszer még mindig a könyvtár egy régebbi változatát futtatja, amely
a képeket GIF formátumban hozza létre. A könyvtár késõbbi változatai licenszokok
miatt nem támogatják a GIF formátumot. Ha rendszerünkre a könyvtár egy újabb
változatát telepítettük, úgy is lefuttathatjuk a PHP-t, hogy a képalkotó függvények
kimeneti formátuma PNG legyen, amelyet a legtöbb böngészõ támogat.

A GD könyvtár segítségével menet közben hozhatunk létre bonyolult alakzatokat


a PHP grafikus függvényeivel. Az óra során a következõket tanuljuk meg:

• Hogyan hozzunk létre és jelenítsünk meg egy képet?

• Hogyan dolgozzunk a színekkel?

• Hogyan rajzoljunk alakzatokat, például köríveket, téglalapokat és sokszögeket?


14_ora.qxd 8/3/2001 6:21 PM Page 260

260 14. óra

• Hogyan töltsünk ki színnel alakzatokat?

• Hogyan kezeljük a TrueType betûtípusokat?

Képek létrehozása és megjelenítése


Mielõtt elkezdhetnénk a képekkel foglalkozni, elõször szert kell tennünk
egy képazonosítóra. Ezt az imagecreate() függvény segítségével tehetjük meg.
Ennek két paramétere van, az egyik a kép magasságára vonatkozik, a másik
a szélességére. Ekkor egy képazonosítót kapunk vissza, amelyet az órán tárgyalt
majdnem mindegyik függvény esetében használni fogunk.

Miután megkaptuk az azonosítót, már majdnem készen állunk arra, hogy megjele-
nítsük elsõ képünket a böngészõben. Ehhez az imagegif() függvényre van
szükségünk, amelynek paramétere a képazonosító. A 14.1. programban a kép lét-
rehozásához és megjelenítéséhez használt függvényeket láthatjuk.

14.1. program Dinamikusan létrehozott kép


1: <?php
2: header("Content-type: image/gif");
3: $kep = imagecreate( 200, 200 );
4: imagegif($kep);
5: ?>

Fontos, hogy a Content-type fejlécsort minden egyéb elõtt küldtük a böngé-


szõnek. Közölnünk kell a böngészõvel, hogy egy képet küldünk, különben
a program kimenetét HTML-ként kezeli. A programot a böngészõ már közvetlenül
vagy egy IMG elem részeként hívhatja meg.

<img src="14.1.program.php" alt="egy PHP készítette kép">

A 14.1. ábrán láthatjuk a 14.1. program kimenetét.

Egy téglalapot hoztunk létre, de egyelõre nem tudjuk annak színét beállítani.
14_ora.qxd 8/3/2001 6:21 PM Page 261

Dinamikus képek kezelése 261

14.1. ábra
Dinamikusan létre-
hozott alakzat

A szín beállítása
A szín beállításához egy színazonosítóra van szükségünk. Ezt
az imagecolorallocate() függvénnyel kaphatjuk meg, amelynek paramétere
a képazonosító, illetve három 0 és 255 közötti egész szám, amelyek a vörös, zöld
és kék színösszetevõket jelentik. Egy színazonosítót kapunk vissza, amellyel ké-
sõbb alakzatok, kitöltések vagy szövegek színét határozhatjuk meg.

$piros = imagecolorallocate($kep, 255,0,0);

Az imagecolorallocate() függvény elsõ meghívásakor egyúttal átállítja


a paraméterül kapott alakzat színét is. Így ha az elõzõ kódrészletet hozzáadjuk
a 14.1. programhoz, egy vörös téglalapot kapunk.
14

Vonalak rajzolása
Mielõtt egy képre vonalat rajzolhatnánk, meg kell adnunk annak két végpontját.

A képet úgy képzeljük el, mint képernyõpontokból álló tömböt, melynek mindkét
tengelye 0-tól számozódik. A számozás kezdõpontja a kép bal felsõ sarka.

Más szóval az (5, 8) koordinátájú képpont a hatodik képpont fentrõl lefelé és


a kilencedik képpont balról jobbra számolva.
14_ora.qxd 8/3/2001 6:21 PM Page 262

262 14. óra

Az imageline() függvény két képpont közé rajzol egy egyenest. A függvény


paraméterként egy képazonosítót vár, négy egész számot, amelyek az egyenes két
végpontjának koordinátáit jelentik, valamint egy színazonosítót.

Ha a 14.2. programban megrajzoljuk a téglalap egy átlóját.

14.2. program Egyenes rajzolása az imageline() függvénnyel


1: <?php
2: header("Content-type: image/gif");
3: $kep = imagecreate( 200, 200 );
4: $piros = imagecolorallocate($kep, 255,0,0);
5: $kek = imagecolorallocate($kep, 0,0,255 );
6: imageline( $kep, 0, 0, 199, 199, $kek );
7: imagegif($kep);
8: ?>

Két színazonosítót kapunk, egyet a piros és egyet a kék színnek. Ezután a $kek
változóban tárolt azonosítót használjuk a vonal színének megadására. Fontos meg-
jegyeznünk, hogy a vonal a (199, 199) és nem a (200, 200) koordinátákban végzõ-
dik, tekintve, hogy a képpontokat 0-tól kezdve számozzuk. A 14.2. ábrán
a 14.2. program eredményét láthatjuk.

14.2. ábra
Egyenes rajzolása
az imageline()
függvénnyel
14_ora.qxd 8/3/2001 6:21 PM Page 263

Dinamikus képek kezelése 263

Alakzatok kitöltése
A PHP segítségével ugyanúgy kiszínezhetünk alakzatokat, mint kedvenc grafikai
programunkkal. Az imagefill() függvény bemenete egy képazonosító,
a kitöltés kezdõkoordinátái, valamint egy színazonosító. A függvény a kezdõ
képponttal megegyezõ színû szomszédos képpontokat a kijelölt színre állítja.
A 14.3. program a képet az imagefill() függvény meghívásával teszi egy kicsit
érdekesebbé.

14.3. program Az imagefill() függvény használata


1: <?php
2: header("Content-type: image/gif");
3: $kep = imagecreate( 200, 200 );
4: $piros = imagecolorallocate($kep, 255,0,0);
5: $kek = imagecolorallocate($kep, 0,0,255 );
6: imageline( $kep, 0, 0, 199, 199, $kek );
7: imagefill( $kep, 0, 199, $kek );
8: imagegif($kep);
9: ?>

A 14.3. ábrán a 14.3. program kimenetét láthatjuk.

14.3. ábra
Az imagefill() függ-
vény használata

14
14_ora.qxd 8/3/2001 6:21 PM Page 264

264 14. óra

Körív rajzolása
Az imagearc() függvény segítségével köríveket rajzolhatunk. Bemenete
egy képazonosító, a középpont koordinátája, a szélességet meghatározó egész
szám, a magasságot meghatározó egész szám, egy kezdõ- és egy végpont
(fokban mérve), valamint egy színazonosító. A köríveket az óramutató járásának
megfelelõen, 3 órától kezdve rajzoljuk. A következõ kódrészlet egy negyed körívet
rajzol ki:

imagearc( $kep, 99, 99, 200, 200, 0, 90, $kek );

Ez egy olyan körívrészletet jelenít meg, melynek középpontja a (99, 99) koordiná-
tájú pontban van. A teljes magasság és szélesség 200-200 képpontnyi. A körív 3
óránál kezdõdik és 90 fokot rajzolunk (azaz 6 óráig).

A 14.4. program teljes kört rajzol és kék színnel tölti ki.

14.4. program Kör rajzolása az imagearc() függvénnyel


1: <?php
2: header("Content-type: image/gif");
3: $kep = imagecreate( 200, 200 );
4: $piros = imagecolorallocate($kep, 255,0,0);
5: $kek = imagecolorallocate($kep, 0,0,255 );
6: imagearc( $kep, 99, 99, 180, 180, 0, 360, $kek );
7: imagefill( $kep, 99, 99, $kek );
8: imagegif($kep);
9: ?>

A 14.4. program kimenetét a 14.4. ábrán láthatjuk.


14_ora.qxd 8/3/2001 6:21 PM Page 265

Dinamikus képek kezelése 265

14.4. ábra
Kör rajzolása
az imagearc() függ-
vénnyel

Téglalap rajzolása
A PHP imagerectangle() függvényével téglalapot rajzolhatunk.
Az imagerectangle() bemenete egy képazonosító, a téglalap bal felsõ és jobb
alsó sarkának koordinátája, valamint egy színazonosító. A következõ kódrészlet
olyan téglalapot rajzol, melynek bal felsõ és jobb alsó koordinátái rendre (19, 19)
és (179, 179):

imagerectangle( $kep, 19, 19, 179, 179, $kek );

Az alakzatot ezután az imagefill() függvénnyel tölthetjük ki. Mivel ez megle-


hetõsen gyakori mûvelet, a PHP-ban létezik az imagefilledrectangle()
függvény, amely ugyanazokat a bemeneti értékeket várja, mint
14
az imagerectangle(), de az általunk meghatározott színnel ki is tölti a tégla-
lapot. A 14.5. program egy kiszínezett téglalapot hoz létre és megjeleníti a böngé-
szõben.
14_ora.qxd 8/3/2001 6:21 PM Page 266

266 14. óra

14.5. program Téglalap rajzolása az imagefilledrectangle() függvénnyel


1: <?php
2: header("Content-type: image/gif");
3: $kep = imagecreate( 200, 200 );
4: $piros = imagecolorallocate($kep, 255,0,0);
5: $kek = imagecolorallocate($kep, 0,0,255 );
6: imagefilledrectangle( $kep, 19, 19, 179, 179, $kek );
7: imagegif( $kep );
8: ?>

A 14.5. ábrán a 14.5. program által elõállított képet láthatjuk.

14.5. ábra
Téglalap rajzolása az
imagefilledrectangle()
függvénnyel

Sokszög rajzolása
Az imagepolygon() függvény segítségével kifinomultabb alakzatokat is rajzol-
hatunk. E függvény bemenete egy képazonosító, a pontok koordinátáiból álló
tömb, az alakzat pontjainak számát jelzõ egész szám és egy színazonosító.
Az imagepolygon() bemenetét képezõ tömbnek számmal indexeltnek kell
lennie. Az elsõ két elem az elsõ pont koordinátáit adja meg, a második kettõ
a második pontét és így tovább. Az imagepolygon() függvény megrajzolja
a pontok közötti vonalakat és az utolsó pontot automatikusan összeköti
az elsõvel. Az imagefilledpolygon() függvény segítségével színnel kitöltött
sokszögek hozhatók létre.
14_ora.qxd 8/3/2001 6:21 PM Page 267

Dinamikus képek kezelése 267

A 14.6. program egy kitöltött sokszöget rajzol és jelenít meg a böngészõben.

14.6. program Sokszög rajzolása az imagefilledpolygon() függvénnyel


1: <?php
2: header("Content-type: image/gif");
3: $kep = imagecreate( 200, 200 );
4: $piros = imagecolorallocate($kep, 255,0,0);
5: $kek = imagecolorallocate($kep, 0,0,255 );
6: $pontok = array (10, 10,
7: 190, 190,
8: 190, 10,
9: 10, 190
10: );
11: imagefilledpolygon( $kep, $pontok, count
( $pontok )/2, $kek );
12: imagegif($kep);
13: ?>

Vegyük észre, hogy az összekötendõ pontok száma az imagefilledpolygon()


függvény hívásakor megegyezik a $pontok tömb elemei számának felével. A 14.6.
ábrán a 14.6. program eredményét láthatjuk.

14.6. ábra
Sokszög rajzolása az
imagefilledpolygon()
függvénnyel

14
14_ora.qxd 8/3/2001 6:21 PM Page 268

268 14. óra

A színek átlátszóvá tétele


A PHP az imagecolortransparent() függvénnyel lehetõvé teszi, hogy
a kiválasztott színeket az ábrán belül áttetszõvé tegyük. A függvény bemenete
egy kép- és egy színazonosító. Ha a képet megjelenítjük egy böngészõben,
az imagecolortransparent() függvénynek átadott szín áttetszõ lesz.
A 14.7. program kimenete a sokszöget rajzoló programot úgy változtatja meg,
hogy az alakzat „úszni” fog a böngészõben, ahelyett, hogy egy háttérszín elõtt
jelenne meg.

14.7. program A színek átlátszóvá tétele


az imagecolortransparent() függvénnyel
1: <?php
2: header("Content-type: image/gif");
3:
4: $kep = imagecreate( 200, 200 );
5: $piros = imagecolorallocate($kep, 255,0,0);
6: $kek = imagecolorallocate($kep, 0,0,255 );
7:
8: $pontok = array (10, 10,
9: 190, 190,
10: 190, 10,
11: 10, 190
12: );
13:
14: imagefilledpolygon( $kep, $pontok, count
( $pontok )/2, $kek );
15: imagecolortransparent( $kep, $piros );
16: imagegif($kep);
17: ?>

A 14.7. ábrán a 14.7. program kimenetét láthatjuk.


14_ora.qxd 8/3/2001 6:21 PM Page 269

Dinamikus képek kezelése 269

14.7. ábra
A színek átlátszóvá
tétele az image-
colortransparent()
függvénnyel

Szövegek kezelése
Ha rendszerünkön vannak TrueType betûk, a képekre írhatunk is. A GD program-
könyvtár mellett szükségünk lesz a FreeType programkönyvtár telepítésére is. Ha
ezek rendelkezésünkre állnak, egy képben megjelenõ diagramokat és navigációs
elemeket is létrehozhatunk. A PHP biztosít számunkra egy olyan eszközt is, amellyel
ellenõrizhetjük, hogy a beírandó szöveg elfér-e a rendelkezésre álló helyen.

Szövegírás az imageTTFtext() függvénnyel


Az imageTTFtext() függvénnyel az ábrákra szöveget írhatunk. A függvény
nyolc bemenõ paramétere a következõ: képazonosító, méret, amely a kiírandó
szöveg magasságára utal, szög, a kezdõ x és y koordináták, színazonosító,
14
a TrueType betûtípus elérési útvonala és a kiírandó szöveg.

A kiírandó szöveg kezdõkoordinátája határozza meg, hol lesz a szöveg elsõ


karakterének alapvonala.

A 14.8. program egy karakterláncot ír az ábrára, majd az eredményt megjeleníti


a böngészõben.
14_ora.qxd 8/3/2001 6:21 PM Page 270

270 14. óra

14.8. program Szövegírás az imageTTFtext() függvénnyel


1: <?php
2: header("Content-type: image/gif");
3:
4: $kep = imagecreate( 400, 200 );
5: $piros = imagecolorallocate($kep, 255,0,0);
6: $kek = imagecolorallocate($kep, 0,0,255 );
7: $betukeszlet = "/usr/local/office52/share/fonts/
/TrueType/arial.ttf";
8:
9: imageTTFtext( $kep, 50, 0, 20, 100, $kek,
$betukeszlet, "Üdvözöljük!" );
10:
11: imagegif($kep);
12: ?>

Létrehozunk egy 400 képpontnyi széles és 200 képpontnyi magas vásznat, meg-
adunk két színt és a $betukeszlet változóban tároljuk a TrueType betûtípus el-
érési útját. Ezután ráírjuk az ábrára a “Üdvözöljük!” szöveget. Figyelem, a betûtí-
pusok a kiszolgálón feltehetõleg más könyvtárban találhatók! Ha nem vagyunk
biztosak a helyben, keressük a .ttf kiterjesztésû fájlokat.

Az imageTTFtext() meghívásához az 50-es magasságot, 0 fokos szöget és


(20, 100) kezdõkoordinátát adtuk át. Emellett a függvény megkapja még a $kek
változóban tárolt színazonosítót és a $betukeszlet változóban tárolt betûtípust,
végül a kiírandó szöveget. Az eredményt a 14.8. ábrán láthatjuk.

14.8. ábra
Szöveg írása az
imageTTFtext() függ-
vénnyel
14_ora.qxd 8/3/2001 6:21 PM Page 271

Dinamikus képek kezelése 271

Persze most még csak találgatunk, hová tegyük a szöveget. A betûméret nem árul
el sokat a szöveg magasságáról, a szélességérõl még kevesebbet.
Az imageTTFtext() függvény persze visszaad információt a szöveg kiterjedésé-
rõl, de akkorra már minden eldõlt. Szerencsére a PHP lehetõséget nyújt arra, hogy
próbálkozzunk, mielõtt még élesben elvégeznénk a mûveletet.

Szöveg kiterjedésének ellenõrzése


az imageTTFbox() függvénnyel
A szöveg kiterjedésérõl az imageTTFbox() függvénnyel szerezhetünk informá-
ciót, amely onnan kapta nevét, hogy a szöveget határoló dobozt írja le. A függvény
bemenete a betûméret, a szög, a betûtípus elérési útja és a kérdéses szöveg.
Azon kevés függvények egyike, melyekhez nem kell a képazonosító. Egy nyolc-
elemû tömböt ad vissza, amely a szöveg kiírásához szükséges terület paramétereit
(koordinátáit) tartalmazza. A 14.1. táblázatban a függvény által visszaadott tömböt
értelmezzük.

14.1. táblázat Az imageTTFbox() függvény által visszaadott tömb


Sorszám Leírás
0 bal alsó (vízszintes tengely)
1 bal alsó (függõleges tengely)
2 jobb alsó (vízszintes tengely)
3 jobb alsó (függõleges tengely)
4 jobb felsõ (vízszintes tengely)
5 jobb felsõ (függõleges tengely)
6
7
bal felsõ (vízszintes tengely)
bal felsõ (függõleges tengely)
14
A függõleges tengelyhez visszaadott számok (1-es, 3-as, 5-ös, és 7-es tömbelemek)
a szöveg alapvonalához viszonyulnak, amelynek koordinátája 0. A szöveg tetejének
a függõleges tengelyen mért értékei ehhez képest általában negatív számok, míg
a szöveg aljának itt mért értékei általában pozitívak. Így kapjuk meg, hány
képponttal nyúlik a szöveg az alapvonal alá. Az imageTTFbox() által figyelembe
vett koordinátarendszert úgy kell elképzelnünk, mintha a szöveg alapvonala lenne
az y irányban vett 0 érték és a negatív koordináták attól felfelé, a pozitívak pedig
attól lefelé helyezkednének el. Így például ha az imageTTFbox() függvénnyel
ellenõrizendõ szövegben van egy "y", a visszakapott tömbben az 1-es indexû
elem lehet, hogy 3 lesz, mivel az "y" alsó szára három képponttal nyúlik
14_ora.qxd 8/3/2001 6:21 PM Page 272

272 14. óra

az alapvonal alá. Lehetséges, hogy a 7-es elem –10 lesz, mivel a szöveg 10 kép-
ponttal van az alapvonal fölé emelve. A pontos értékek betûtípustól és betûméret-
tõl függnek.

Csak hogy bonyolítsuk a helyzetet, úgy tûnik, hogy az imageTTFbox() függvény


által visszaadott alapvonal és a rajzolás közben látható között 2 képpontos eltolás
van. Ezt úgy ellensúlyozhatjuk, hogy az alapvonalat két képpontnyival magasabb-
nak képzeljük, mint amilyennek az imageTTFbox() függvény mutatja.

A vízszintes tengelyen a bal oldali számok (a 0-ás és a 6-os elem) esetében


az imageTTFbox() függvény az adott kezdõpont elõtt kezdõdõ szöveget negatív
számmal kifejezett eltolással jelöli. Ez általában alacsony szám, mivel a betûk jellem-
zõen jelentõsebb eltérést mutatnak az alapvonaltól, mint az x irányú kezdõkoordiná-
tától (gondoljunk a p, g vagy j betûkre). A vízszintes tengelyen így már csak
az elvárt pontosság kérdése, hogy szükségünk van-e a koordináták kiigazítására.

Az imageTTFbox() függvény által visszaadott értékeket arra is használhatjuk,


hogy az ábrán belül a szöveget igazítsuk. A 14.9. program dinamikusan küldi
a böngészõnek a szöveget, úgy, hogy mind a vízszintes, mind a függõleges
tengelyen középre helyezi azt.

14.9. program Szöveg elhelyezése az imageTTFbox() függvény használatával


1: <?php
2: header("Content-type: image/gif");
3: $magassag = 100;
4: $szelesseg = 200;
5: $betumeret = 50;
6: if ( ! isset ( $szoveg ) )
7: $szoveg = "Változtasson meg!";
8: $kep = imagecreate( $szelesseg, $magassag );
9: $piros = imagecolorallocate($kep, 255,0,0);
10: $kek = imagecolorallocate($kep, 0,0,255 );
11: $betukeszlet = "/usr/local/office52/share/fonts/
/TrueType/arial.ttf";
12: $szovegszelesseg = $szelesseg;
13: $szovegmagassag;
14: while ( 1 )
15: {
16: $doboz = imageTTFbox( $betumeret, 0,
$betukeszlet, $szoveg );
17: $szovegszelesseg = abs( $doboz[2] );
18: $szovegmagassag = ( abs($doboz[7]) )-2;
14_ora.qxd 8/3/2001 6:21 PM Page 273

Dinamikus képek kezelése 273

14.9. program (folytatás)


19: if ( $szovegszelesseg < $szelesseg - 20 )
20: break;
21: $betumeret--;
22: }
23: $gifXkozep = (int) ( $szelesseg/2 );
24: $gifYkozep = (int) ( $magassag/2 );
25: imageTTFtext( $kep, $betumeret, 0,
26: (int) ($gifXkozep-($szovegszelesseg/2)),
27: (int) ($gifYkozep+($szovegmagassag/2)),
28: $kek, $betukeszlet, $szoveg );
29: imagegif($kep);
30: ?>

A kép magasságát és szélességét a $magassag és $szelesseg változókban


tároljuk, a betûtípus alapbeállítású méretét pedig 50-re állítjuk. Megvizsgáljuk,
hogy létezik-e már a $szoveg nevû változó; ha nem, beállítjuk egy alapértékre.
Ezzel az eljárással egy ábrának is lehetnek paraméterei, fogadhat adatot
egy weboldalról – akár egy URL keresõkifejezésébõl, akár egy kitöltött ûrlapról.
A képazonosító elõállításához az imagecreate() függvényt használjuk. A szín-
azonosítókat a szokásos módon állítjuk elõ, a $betukeszlet nevû változóban
pedig a TrueType betûtípus elérési útját rögzítjük.

Azt szeretnénk, hogy a $szoveg változóban tárolt karaktersorozat elférjen


a rendelkezésére álló helyen, de egyelõre nem tudhatjuk, hogy ez sikerülni fog-e.
A while utasításon belül átadjuk a betûtípus elérési útját és a szöveget
az imageTTFbox() függvénynek, az eredményül kapott tömböt pedig a $doboz
változóba helyezzük. A $doboz[2] tartalmazza a jobb alsó sarok helyét
a vízszintes tengelyen. Ezt vesszük a karaktersorozat szélességének és
a $szovegszelesseg változóban tároljuk.
14
A szöveget függõlegesen is középre szeretnénk helyezni, de a szöveg alapvonala
alatt lévõ részt figyelmen kívül hagyva. Az alapvonal feletti magasság meghatáro-
zásához használhatjuk a $doboz[7] változóban található szám abszolút értékét,
bár ezt még ki kell igazítanunk a fent említett két képponttal. Ezt az értéket
a $szovegmagassag változóban tároljuk.

Most, hogy kiszámítottuk a szöveg szélességének értékét, összevethetjük az ábra


szélességével (tíz képpontnyival kell kevesebbnek lennie, a keret miatt). Ha a szö-
veg keskenyebb, mint a kép szélessége, befejezzük a ciklust. Ellenkezõ esetben
csökkentjük a betûméretet és újra próbálkozunk.
14_ora.qxd 8/3/2001 6:21 PM Page 274

274 14. óra

A $magassag és a $szelesseg változók értékét elfelezve megkapjuk az ábra


hozzávetõleges középpontját. A szöveget az ábra középpontjából és a szöveg
magasságából, illetve szélességébõl kiszámított eltolással az ábrára írjuk, végül
megjelenítjük a képet a böngészõben. A 14.9. ábrán láthatjuk a 14.9. program ki-
menetét.

Ezt a kódot egy másik oldal is meghívhatja, egy IMG elem részeként. A következõ
részlet egy olyan programot hoz létre, amely lehetõvé teszi az egyes felhasználóknak,
hogy saját szöveget jelenítsenek meg az ábrán:

1: <?php
2: if ( ! isset( $szoveg ) )
3: $szoveg = "Dinamikus szöveg!";
4: ?>
5: <form action="<? print $PHP_SELF ?>" method="POST">
6: <input type="text" name="szoveg">
7: </form>
8: <p>
9: <img src="14.9.program.php?<? print
"szoveg=".urlencode($szoveg) ?>">

Amikor a 14.9. programot meghívjuk, egy olyan keresõkifejezéssel egészítjük ki


a hívást, amely tartalmazza a megjelenítendõ szöveget. A tizenkilencedik órában
többet is tanulhatunk az információk programról programra való átadásáról.

14.9. ábra
Szöveg elhelyezése az
imageTTFbox() függ-
vény használatával
14_ora.qxd 8/3/2001 6:21 PM Page 275

Dinamikus képek kezelése 275

A fenti elemek összegyúrása


Készítsünk egy példát az ezen az órán tanult függvények használatával! Tegyük
fel, hogy arra kértek bennünket, hogy készítsünk egy dinamikus oszlopgrafikont,
amely több címkézett számot hasonlít össze. Az egyes oszlopok alatt a megfelelõ
címkének kell lennie. Ügyfelünknek tudnia kell módosítani a grafikon oszlopainak
számát, a kép szélességét és magasságát és a grafikont körülvevõ keret méretét.
A grafikont fogyasztói szavazáshoz fogják használni, így az adatokat csak látszóla-
gos pontossággal kell megjeleníteni. Egy sokkal részletesebb lebontást az ábrát
tartalmazó oldal HTML részében találhatunk.

Az oszlopokat és értékeiket a legegyszerûbb módon egy asszociatív tömbben


tárolhatjuk. Miután megvan ez a tömb, ki kell számolnunk az oszlopok számát és
a tömb legnagyobb értékét:

$cellak = array ( "tetszik"=>200, "nem tetszik"=>400,


"közömbös"=>900 );
$max = max( $cellak );
$cellaszam = count( $cellak );

Létre kell hoznunk néhány változót, így ügyfelünk egyéni igényeihez igazíthatja
az ábrát:

$teljesszelesseg = 400;
$teljesmagassag = 200;
$xmargo = 20; // jobb és bal margó
$ymargo = 20; // felsõ és alsó margó
$oszlopkoz = 5; // az oszlopok közötti hely
$alsokeret = 40; // az ábra alján kimaradó hely
å (a margót nem számolva)
$betukeszlet = "/usr/local/office52/share/fonts/
å /TrueType/arial.ttf";
14
Ügyfelünk a változók módosításával meghatározhatja az ábra magasságát és széles-
ségét. Az $xmargo és $ymargo a grafikon körüli margóvastagságot adja meg.
Az $oszlopkoz az oszlopok közötti távolságot határozza meg, az $alsokeret
változó pedig az oszlopok alatti címkéknek szánt hely nagyságát.

Most hogy megvannak ezek az értékek, a némi számolgatás árán belõlük kapott
hasznos számokat változókba tesszük:
14_ora.qxd 8/3/2001 6:21 PM Page 276

276 14. óra

$vaszonszelesseg = ( $teljesszelesseg - $xmargo*2 );


$vaszonmagassag = ( $teljesmagassag - $ymargo*2 - $alsokeret
);
$xPoz = $xmargo; // a rajzolás kiindulópontja az x tengelyen
$yPoz = $teljesmagassag - $ymargo - $alsokeret; //
å a rajzolás kiindulópontja az y tengelyen
$cellaszelesseg = (int) (( $vaszonszelesseg - ( $oszlopkoz *
å ( $cellaszam-1 ) )) / $cellaszam) ;
$szovegmeret = (int)($alsokeret);

Kiszámítjuk a rajzfelületet (azt a területet, ahová majd az oszlopok kerülnek).


A vízszintes összetevõt úgy kapjuk meg, hogy a teljes szélességbõl kivonjuk
a margó kétszeresét. A függõleges mérethez az $alsokeret változót is számítás-
ba kell vennünk, hogy a címkéknek helyet hagyjunk. Az $xPoz tárolja azt az x
koordinátát, amelytõl az oszlopok rajzolását kezdjük, így ennek értékét
az $xmargo változó értékére állítjuk, amely a margó értékének vízszintes összete-
võjét tárolja. Az oszlopok talppontját tároló $yPoz változó értékét úgy
kapjuk meg, ha az ábra teljes magasságából kivonjuk a margót és a címkéknek
kihagyott hely nagyságát, amelyet az $alsokeret változóban tároltunk.

A $cellaszelesseg az egyes oszlopok szélességét tárolja. Ahhoz, hogy


az értékét megkapjuk, számoljuk ki az oszlopok közötti helyek összegét,
ezt vonjuk ki a diagram szélességébõl, majd az eredményt osszuk el az oszlopok
számával.
Kezdetben úgy állítjuk be a szöveg méretét, hogy egyezzen a szöveg számára
szabadon maradt terület magasságával (amit az $alsokeret változóban tárolunk).

Mielõtt megkezdenénk a munkát az ábrával, meg kell határoznunk a szöveg


méretét. Viszont nem tudjuk, milyen szélesek lesznek a címkék és mindenképpen
azt szeretnénk, hogy az egyes címkék elférjenek a felettük levõ oszlop szélessé-
gén belül. A $cellak tömbön egy ciklus segítségével meghatározzuk
a legnagyobb címke méretét:

forach( $cellak as $kulcs => $ertek )


{
while ( 1 )
{
$doboz = ImageTTFbBox( $szovegmeret, 0,
$betukeszlet, $kulcs );
$szovegszelesseg = $doboz[2];
if ( $szovegszelesseg < $cellaszelesseg )
break;
$szovegmeret—;
}
}
14_ora.qxd 8/3/2001 6:21 PM Page 277

Dinamikus képek kezelése 277

Minden elem esetében egy ciklust kezdve, az imageTTFbox() segítségével


információt szerzünk a címke méretét illetõen. A kapott értéket a $doboz[2]
változóban találhatjuk meg, amit összevetünk a $cellaszelesseg változóval,
amely egy oszlop szélességét tartalmazza. A ciklust abban az esetben állítjuk le,
ha a szöveg szélessége kisebb, mint az oszlopszélesség. Egyébként pedig
csökkentjük a $szovegmeret értékét és újra ellenõrizzük a méreteket.
A $szovegmeret addig csökken, míg a tömb összes címkéje kisebb nem lesz
az oszlopszélességnél.

Most már végre létrehozhatunk egy képazonosítót és elkezdhetünk dolgozni vele.

$kep = imagecreate( $teljesszelesseg, $teljesmagassag );


$piros = ImageColorAllocate($kep, 255, 0, 0);
$kek = ImageColorAllocate($kep, 0, 0, 255 );
$fekete = ImageColorAllocate($kep, 0, 0, 0 );
forach( $cellak as $kulcs => $ertek )
{
$cellamagassag = (int) (($ertek/$max) * $vaszonmagassag);
$kozeppont = (int)($xPoz+($cellaszelesseg/2));
imagefilledrectangle( $kep, $xPoz, ($yPoz-$cellamagassag),
($xPoz+$cellaszelesseg), $yPoz, $kek );
$doboz = ImageTTFBox( $szovegmeret, 0, $betukeszlet,
$kulcs );
$szovszel = $doboz[2];
ImageTTFText( $kep, $szovegmeret, 0, ($kozeppont-
($szovszel/2)),
($teljesmagassag-$ymargo), $fekete, $betukeszlet,
$kulcs );
$xPoz += ( $cellaszelesseg + $oszlopkoz);
}
imagegif( $kep ); 14
Ezt az imagecreate() függvénnyel tesszük meg, majd kiosztunk néhány színt is.
Újra végiglépkedünk a $cellak tömbön. Kiszámítjuk az oszlop magasságát és
az eredményt a $cellamagassag-ba helyezzük. Kiszámoljuk a középpont x koor-
dinátáját, amely megegyezik az $xPoz és a fél oszlop szélességének összegével.

Az imagefilledrectangle() függvénynek az $xPoz, $yPoz,


$cellamagassag és $cellaszelesseg változókat átadva megrajzoljuk
az oszlopot.
14_ora.qxd 8/3/2001 6:21 PM Page 278

278 14. óra

A szöveg középre igazításához megint szükségünk van az imageTTFbox()


függvényre, amelynek eredménytömbjét a $doboz változóban tároljuk.
A $doboz[2] értéket fogjuk munkaszélességnek választani, ezt bemásoljuk
a $szovszel átmeneti változóba. Most már elegendõ információ áll rendelkezé-
sünkre ahhoz, hogy kiírassuk a címkét. Az x koordináta a $kozeppont változó és
a szövegszélesség felének különbsége lesz, az y koordináta pedig az alakzat
magasságának és a margónak a különbsége.

Megnöveljük az $xPoz változót, felkészülve ezzel a következõ oszlop feldol-


gozására.

A ciklus végeztével megjelenítjük az elkészült képet.

A teljes programot a 14.10. példában láthatjuk, a végeredményt pedig


a 14.10. ábrán.

14.10. program Egy dinamikus oszlopdiagram


1: <?php
2: header("Content-type: image/gif");
3: $cellak = array ( "tetszik"=>200,
"nem tetszik"=>400,
"közömbös"=>900 );
4: $max = max( $cellak );
5: $cellaszam = count( $cellak );
6: $teljesszelesseg = 300;
7: $teljesmagassag = 200;
8: $xmargo = 20; // jobb és bal margó
9: $ymargo = 20; // fenti és lenti margó
10: $oszlopkoz = 10; // az oszlopok közötti hely
11: $alsokeret = 30; // az ábra alján kimaradó hely
(a margót nem számolva)
12: $betukeszlet = "/usr/local/office52/share/fonts/
/TrueType/arial.ttf";
13: $vaszonszelesseg = ( $teljesszelesseg - $xmargo*2 );
14: $vaszonmagassag = ( $teljesmagassag - $ymargo*2
- $alsokeret );
15: $xPoz = $xmargo; // a rajzolás kiindulópontja
az x tengelyen
16: $yPoz = $teljesmagassag - $ymargo - $alsokeret; //
a rajzolás kiindulópontja az y tengelyen
17: $cellaszelesseg = (int) (( $vaszonszelesseg -
( $oszlopkoz * ( $cellaszam-1 ) )) / $cellaszam) ;
14_ora.qxd 8/3/2001 6:21 PM Page 279

Dinamikus képek kezelése 279

14.10. program (folytatás)


18: $szovegmeret = (int)($alsokeret);
19: // betûméret kiigazítása
20: forach( $cellak as $kulcs => $ertek )
21: {
22: while ( 1 )
23: {
24: $doboz = ImageTTFbBox( $szovegmeret, 0,
$betukeszlet, $kulcs );
25: $szovegszelesseg = abs( $doboz[2] );
26: if ( $szovegszelesseg < $cellaszelesseg )
27: break;
28: $szovegmeret—;
29: }
30: }
31: $kep = imagecreate( $teljesszelesseg,
$teljesmagassag );
32: $piros = ImageColorAllocate($kep, 255, 0, 0);
33: $kek = ImageColorAllocate($kep, 0, 0, 255 );
34: $fekete = ImageColorAllocate($kep, 0, 0, 0 );
35: $szurke = ImageColorAllocate($kep, 100, 100, 100 );
36:
37: forach( $cellak as $kulcs => $ertek )
38: {
39: $cellamagassag = (int) (($ertek/$max) *
$vaszonmagassag);
40: $kozeppont = (int)($xPoz+($cellaszelesseg/2));
41: imagefilledrectangle( $kep, $xPoz,
($yPoz-$cellamagassag),
($xPoz+$cellaszelesseg),
$yPoz, $kek );
14
42: $doboz = ImageTTFbBox( $szovegmeret, 0,
$betukeszlet, $kulcs );
43: $szovszel = $doboz[2];
44: ImageTTFText( $kep, $szovegmeret, 0,
($kozeppont-($szovszel/2)),
45: ($teljesmagassag-$ymargo), $fekete,
$betukeszlet, $kulcs );
46: $xPoz += ( $cellaszelesseg + $oszlopkoz);
47: }
48: imagegif( $kep );
49: ?>
14_ora.qxd 8/3/2001 6:21 PM Page 280

280 14. óra

14.10. ábra
Egy dinamikus osz-
lopdiagram

Összefoglalás
A GD programkönyvtár PHP-s támogatása lehetõvé teszi, hogy dinamikus oszlop-
diagramokat és navigációs elemeket hozhassunk létre, viszonylag könnyen.

Ezen az órán megtanultuk, hogyan használjuk az imagecreate() és


az imagegif() függvényeket képek létrehozására és megjelenítésére.
Azt is megtanultuk, hogyan szerezzünk színazonosítót és hogyan töltsünk ki
színnel területeket az imagecolorallocate() és az imagefill() függvé-
nyekkel. Megnéztük, hogyan használjunk vonal- és alakzat függvényeket alakza-
tok körvonalainak megrajzolására és kitöltésére. Megtanultuk, hogyan használjuk
a PHP által támogatott FreeType programkönyvtárat a TrueType betûtípusokkal
való munkára, valamint elemeztünk egy programot, amelyben egy alakzatra
szöveget írtunk és megnéztünk egy példát, amelyben a tanult eljárásokat
a gyakorlatban is láthattuk.

Kérdések és válaszok
Fellépnek-e teljesítménybeli problémák dinamikus képek használata
esetén?
Egy dinamikusan létrehozott kép lassabban töltõdik be a böngészõbe, mint egy
már létezõ fájl. A program hatékonyságától függõen ezt a felhasználó nem feltétle-
nül veszi észre, de azért a dinamikus képeket módjával használjuk.
14_ora.qxd 8/3/2001 6:21 PM Page 281

Dinamikus képek kezelése 281

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 fejlécsort kell a böngészõnek küldenünk a GIF kép létrehozása és
megjelenítése elõtt?

2. Milyen függvényt használnánk egy képazonosító elõállításához, amelyet


a többi függvénynél használhatunk?

3. Milyen függvényt használnánk a létrehozott GIF kép megjelenítésére?

4. Milyen függvény segítségével szerezhetjük meg a színazonosítót?

5. Melyik függvénnyel rajzolnánk vonalat egy dinamikus képre?

6. Melyik függvénnyel töltenénk ki színnel egy dinamikus alakzatot?

7. Melyik függvényt használhatjuk körív rajzolására?

8. Hogyan rajzoljunk téglalapot?

9. Hogyan rajzoljunk sokszöget?

10. Melyik függvénnyel írnánk egy dinamikus alakzatra (a FreeType program-


könyvtár segítségével)?

Feladatok 14
1. Írjunk egy programot, amely egy folyamatjelzõt hoz létre, amely mutatja,
mennyi pénz folyt be egy gyûjtés alkalmával az adott célra szükséges pénzbõl.

2. Írjunk egy programot, amely egy fõcímet ábrázoló képet ír ki egy bejövõ ûr-
lap vagy lekérdezés adataiból. Tegyük lehetõvé, hogy a felhasználó határoz-
za meg a rajzterületet, az elõtér és a háttér színét, valamint az árnyék meglét-
ét és annak méretét.
14_ora.qxd 8/3/2001 6:21 PM Page 282
15_ora.qxd 8/3/2001 6:21 PM Page 283

15. ÓRA
Dátumok kezelése
A dátumok annyira mindennapjaink részét képezik, hogy nem is gondolkodunk,
amikor velük dolgozunk, naptárunk fortélyainak helyes kezelése azonban a prog-
ramokat meglehetõsen bonyolulttá teheti. Szerencsére a PHP hatékony eszközöket
biztosít a dátumszámításhoz, amely megkönnyíti a feladatot.

Ebben a fejezetben a következõkrõl tanulunk:

• Hogyan kérdezhetjük le a pontos idõt és dátumot?

• Hogyan szerezhetünk információt egy dátumról?

• Hogyan formázzunk meg egy dátumot?

• Hogyan ellenõrizzük a dátumok érvényességét?

• Hogyan állítsuk be a dátumot?

• Hogyan írjunk egyszerû naptárprogramot?


15_ora.qxd 8/3/2001 6:21 PM Page 284

284 15. óra

A dátum kiderítése a time() függvénnyel


A PHP time() függvénye mindent elárul, amire szükségünk lehet a pontos
idõvel és dátummal kapcsolatban. A függvénynek nincs bemenete (paramétere) és
egy egész számot ad vissza, amely egy kicsit nehezen értelmezhetõ, viszont
nagyon informatív.

A time() által visszaadott egész szám a greenwichi középidõ szerinti 1970. január 1.
éjfél óta eltelt másodpercek számát adja meg. Ez a dátum a „UNIX kor kezdete”
néven ismeretes, az azóta eltelt másodpercek számát pedig idõbélyegnek (néha idõ-
bélyegzõ, time stamp) nevezik. Az idõbélyeget a PHP eszközeivel „emberi fogyasz-
tásra alkalmasabb” formára hozhatjuk, de felmerül a kérdés: még ha ilyen nagyszerû
eszközök is állnak rendelkezésünkre, az idõbélyeg nem feleslegesen túlbonyolított
módja a dátum tárolásának? Nem, éppen ellenkezõleg: egyetlen számból rengeteg
információt szerezhetünk. És ami még ennél is jobb, az idõbélyeggel sokkalta
könnyebben lehet számításokat végezni, mint azt gondolnánk.

Képzeljünk csak el egy házi dátumrendszert, amelyben az éveket, hónapokat és


a hónapok napjait jegyezzük fel. Most képzeljünk el egy olyan programot, amellyel
egy napot kell hozzáadnunk egy adott dátumhoz. Ha ez a dátum éppenséggel
1999. december 31., akkor ahelyett, hogy 1-et adnánk a dátumhoz, olyan programot
kellene írni, amely a napot 1-re írná át, a hónapot januárra, az évet pedig 2000-re.
Az idõbélyegben viszont csak egy napnyi másodpercet kell hozzáadni az aktuális
dátumhoz és már készen is vagyunk. Ezt az új számot pedig kedvünk szerint alakít-
hatjuk át valamilyen barátságosabb formára.

Az idõbélyeg átalakítása a getdate() függvénnyel


Most, hogy rendelkezésünkre áll az idõbélyeg, át kell alakítanunk, mielõtt megmutat-
nánk a felhasználónak. A getdate() elhagyható bemenete egy idõbélyeg, visszaté-
rési értéke pedig egy asszociatív tömb. Ha nem adjuk meg az idõbélyeget, a függ-
vény az éppen aktuális idõbélyeggel dolgozik, mintha azt a time() függvénytõl
kapta volna. A 15.1. táblázat a getdate() által visszaadott tömb elemeit részletezi.

15.1. táblázat A getdate() függvény által visszaadott asszociatív tömb


Kulcs Leírás Példa
seconds A percbõl eltelt másodpercek száma (0-59) 28
minutes Az órából eltelt percek száma (0-59) 7
hours A nap órája (0-23) 12
mday A hónap napja (1-31) 20
15_ora.qxd 8/3/2001 6:21 PM Page 285

Dátumok kezelése 285

15.1. táblázat (folytatás)


wday A hét napja (0-6) 4
mon Az év hónapja (1-12) 1
year Év (négy számjeggyel) 2000
yday Az év napja (0-365) 19
weekday A hét napja (névvel) Thursday
month Az év hónapja (névvel) January
0 Az idõbélyeg 948370048

A 15.1. programban a getdate() függvénnyel szétbontjuk az idõbélyeget, majd


a foreach utasítással kiírjuk az egyes elemeket. A 15.1. ábrán a getdate() függ-
vény egy lehetséges kimenetét láthatjuk. A getdate() a helyi idõzóna szerinti dá-
tumot adja vissza.

15.1. program Dátum lekérdezése a getdate() függvénnyel


1: <html>
2: <head>
3: <title>15.1. program Dátum lekérdezése a getdate()
függvénnyel</title>
4: </head>
5: <body>
6: <?php
7: $datum_tomb = getdate(); // nem adtunk meg bemenetet,
így a mai dátumot fogja visszaadni
8: foreach ( $datum_tomb as $kulcs => $ertek )
9: {
10: print "$kulcs = $ertek<br>";
11: }
12: ?>
13: <hr>
14: <?
15: print "A mai dátum: " $datum_tomb["year"] "
15
" $datum_tomb["mon"] "
" $datum_tomb["mday"] <p>";
16: ?>
17: </body>
18: </html>
15_ora.qxd 8/3/2001 6:21 PM Page 286

286 15. óra

15.1. ábra
A getdate() függvény
használata

Az idõbélyeg átalakítása a date() függvénnyel


A getdate() függvényt akkor használjuk, amikor a kimenetét képezõ elemeket
szeretnénk használni, a dátumot azonban általában szövegként szeretnénk megje-
leníteni. A date() függvény a dátumot formázott karakterlánc formájában adja
vissza. A date() függvény által visszaadott érték formátuma a paraméterként
átadható formázó karakterlánccal nagymértékben befolyásolható. A formázó ka-
rakterláncon kívül a date() függvénynek átadhatjuk az idõbélyeget is, bár ez nem
kötelezõ. A 15.2. táblázatban láthatjuk azokat a kódokat, amelyeket a formázó ka-
rakterlánc tartalmazhat. A date() függvénynek átadott formázóban található min-
den egyéb szöveg a visszaadott értékben változatlanul meg fog jelenni.

15.2. táblázat A date() által használt formázási kódok.


Formátum Leírás Példa
a ‘am’ (délelõtt) vagy ‘pm’ (délután), kisbetûvel pm
A ‘AM’ (délelõtt) vagy ‘PM’ (délután), nagybetûvel PM
d A hónap napja (bevezetõ nullákkal írt szám) 05
D A hét napja (három betûvel) Thu
F A hónap neve January
h Óra (12 órás formátum, bevezetõ nullákkal) 03
H Óra (24 órás formátum, bevezetõ nullákkal) 05
g Óra (12 órás formátum, bevezetõ nullák nélkül) 3
G Óra (24 órás formátum, bevezetõ nullák nélkül) 5
15_ora.qxd 8/3/2001 6:21 PM Page 287

Dátumok kezelése 287

15.2. táblázat (folytatás)


Formátum Leírás Példa
i Perc 47
j A hónap napja (bevezetõ nullák nélkül) 5
l A hét napja (névvel) Thursday
L Szökõév (‘1’ ha igen, ‘0’ ha nem) 1
m Az év hónapja (számmal, bevezetõ nullákkal) 01
M Az év hónapja (három betûvel) Jan
n Az év hónapja (számmal, bevezetõ nullák nélkül) 1
s Az óra percei 24
U Idõbélyeg 948372444
y Év (két számjegy) 00
Y Év (négy számjegy) 2000
z Az év napja (0-365) 19
Z A greenwichi középidõtõl való eltérés másodpercben 0

A 15.2. program néhány formátumkódot mutat be.

15.2. program Dátum formázása a date() függvénnyel


1: <html>
2: <head>
3: <title>15.2. program Dátum formázása a date()
függvénnyel</title>
4: </head>
5: <body>
6: <?php
7: print date("Y.m.d. H:i:s<br>", time());
8: // 2000.12.10. 14:42:55
9:
10: $de_du = Array ("am" => "délelõtt", "pm"
15
=> "délután");
11: $honapok = Array("január", "február", "március",
"április",
12: "május", "június", "július", "augusztus",
"szeptember",
13: "október", "november", "december");
15_ora.qxd 8/3/2001 6:21 PM Page 288

288 15. óra

15.2. program (folytatás)


14:
15: $napszak = $de_du[date("a")];
16: $honap = $honapok[date("n")-1];
17:
18: print " Ma " . date("Y ") . $honap .
date(" j. \\n\ap\j\a v\a\\n, " );
19: print $napszak . date(" g ór\a i perc");
20: // Ma 2000 december tizedike van,
délután 2 óra 42 perc.
21: ?>
22: </body>
23: </html>

A magyar dátumok formázása kétségtelenül bonyolultabb, mint a belsõleg támo-


gatott angol dátumformátumok, ezért létre kell hoznunk egy tömböt, amely
a „délelõtt” és „délután” szavakat tartalmazza, valamint egy másik tömböt
a hónapok nevei számára. A $napszak egyszerûen a date() függvény "a"
formátumra adott kimenetébõl származtatható, a $honap-hoz pedig a tömb
date("n")-1-edik elemét kell vennünk, mivel a tömbök nullától számozódnak.

Bár a formázás bonyolultnak tûnik, nagyon könnyû elvégezni. Ha olyan szöveget


szeretnénk a formázáshoz adni, amely formátumkód-betûket tartalmaz, a fordított
perjel (\) karakterrel jelezhetjük, hogy az utána jövõ karakter nem formátumkód.
Azon karakterek esetében, amelyek a \ után válnak vezérlõkarakterré, ezt a \ elé
tett újabb \ segítségével kell jeleznünk. A "\n"-t például ennek megfelelõen
"\\n"-nek kell írnunk, ha egy “n”-t szeretnénk a formázási karaktersorozatba
írni. A fenti példában a formátumkarakterek ütközését elkerülendõ vettük külön
a $honap és $napszak kiírását, hogy a date() függvény ne tekintse ezek
karaktereit értelmezendõ formátum-meghatározásoknak. A date() függvény
a helyi idõzóna szerint adja vissza a dátumot. Ha azt szeretnénk, hogy greenwichi
középidõ (Greenwich Mean Time, GMT) szerint kapjuk meg, használjuk
a gmdate() függvényt, amely egyébként minden más tekintetben ugyanígy
mûködik.

Idõbélyeg készítése az mktime() függvénnyel


Már képesek vagyunk az aktuális dátumot használni, de tetszõleges dátumokat
még nem tudunk kezelni. Az mktime() függvény által visszaadott idõbélyeget
a date() vagy a getdate() függvényekkel használhatjuk. Az mktime()
függvény bemenete hat egész szám, a következõ sorrendben:
15_ora.qxd 8/3/2001 6:21 PM Page 289

Dátumok kezelése 289

óra
perc
másodperc
hónap
hónap napja
év

A 15.3. program az mktime() függvénnyel állít elõ idõbélyeget, amit aztán


a date() függvénnyel használ.

15.3. program Idõbélyeg készítése az mktime() függvénnyel


1: <html>
2: <head>
3: <title>15.3. program Idõbélyeg készítése az mktime()
függvénnyel </title>
4: </head>
5: <body>
6: <?php
7: // idõbélyeget készít 1999. 05. 01. 12 óra 30 perchez
8: $ido = mktime( 12, 30, 0, 5, 1, 1999 );
9: print date("Y.m.d. H:i:s<br>", $ido);
10: // 1999.05.01. 12:30:00
11: ?>
12: </body>
13: </html>

Az mktime() függvény néhány vagy akár az összes eleme elhagyható, ilyenkor


az aktuális idõnek megfelelõ értékeket használja. Az mktime() emellett azokat
az értékeket is kiigazítja, amelyek túl vannak a megfelelõ értéktartományon,
így ha 25-öt adunk meg óra paraméterként, akkor a meghatározott nap, hónap,
év paraméterek utáni nap reggeli 1.00-ként fogja kezelni azt. Az mktime()
függvény kimenete általában adatbázisban vagy fájlban való tároláshoz, illetve

15
dátumszámításokhoz lehet hasznos.

A dátum ellenõrzése a checkdate() függvénnyel


Elõfordulhat, hogy a felhasználó által bevitt dátummal kell dolgoznunk. Mielõtt
nekikezdenénk a munkának vagy tárolnánk a dátumot, meg kell bizonyosodnunk
róla, hogy az érvényes-e. A checkdate() függvény három egész számot,
a hónapot, a napot, és az évet kéri paraméterként (ebben a sorrendben) és true
(igaz) értéket ad vissza, ha a hónap 1 és 12 közt van, a nap elfogadható az adott
15_ora.qxd 8/3/2001 6:21 PM Page 290

290 15. óra

hónapban és évben (számításba véve a szökõéveket) és az év 0 és 32 767 közé


esik. Vigyázzunk azonban, mert elõfordulhat, hogy egy dátum ugyan érvényes, de
más dátumfüggvények számára mégsem elfogadható. Például a következõ sor
true (igaz) értéket ad vissza:

checkdate( 4, 4, 1066 )

Viszont ha ezekkel az értékekkel egy dátumot szeretnénk létrehozni, az mktime()


által visszaadott idõbélyeg –1 lenne. Általános szabályként fogadjuk el, hogy
az 1902 elõtti évekre nem használjuk az mktime() függvényt és az 1970 elõttiekre
is csak elõvigyázatosan.

Egy példa
Próbáljunk meg ezen függvények közül egyetlen példán belül minél többet
használni. Készítsünk naptárat, amely egy 1980 és 2010 közötti tetszõleges hónap
napjait mutatja. A felhasználó lenyíló menüvel választhatja ki a hónapot és az évet.
A program kimenetében az adott hónap dátumai a hét napjainak megfelelõen ke-
rülnek elrendezésre. Két globális változót használunk, a $honap és az $ev válto-
zókat, melyek adatait a felhasználó adja meg. A két változó segítségével elkészít-
jük a meghatározott hónap elsõ napjának idõbélyegét. Ha nem adtuk meg az évet
vagy a hónapot, vagy megadtuk, de a bevitt adat nem érvényes, a program beme-
netének alapbeállításként a folyó év aktuális hónapjának elsõ napját tekintjük.

A felhasználó által bevitt adatok ellenõrzése


Amikor egy felhasználó elõször látogat el weboldalunkra, valószínûleg nem fogja
megadni a bekért adatokat. Erre az isset() függvény segítségével készíthetjük
fel programunkat. Ez a függvény a false (hamis) értéket adja vissza, ha a neki
átadott változó nem meghatározott. (Használhatjuk helyette a checkdate()
függvényt is.) A 15.4. példa azt a kódrészletet tartalmazza, amely ellenõrzi
a $honap és az $ev változókat és egy idõbélyeget hoz létre belõlük.

15.4. program A felhasználó által bevitt adatok ellenõrzése


a naptárprogram számára
1: <?php
2: if ( ! checkdate( $honap, 1, $ev ) )
3: {
4: $mostTomb = getdate();
5: $honap = $mostTomb["mon"];
6: $ev = $mostTomb["year"];
7: }
15_ora.qxd 8/3/2001 6:21 PM Page 291

Dátumok kezelése 291

15.4. program (folytatás)


8: $kezdet = mktime ( 0, 0, 0, $honap, 1, $ev );
9: $elsoNapTombje = getdate($kezdet);
10: if ($elsoNapTombje["wday"] == 0)
{ $elsoNapTombje["wday"] = 6; }
11: else { $elsoNapTombje["wday"]--; }
12: ?>

A 15.4. program egy nagyobb program részlete, így önmagában nincs kimenete.
Az if utasításban a checkdate() függvényt használjuk a $honap és az $ev
változók ellenõrzésére. Ha ezek nem meghatározottak, a checkdate() false
(hamis) értéket ad vissza, mivel nem hozhatunk létre érvényes dátumot meghatá-
rozatlan hónap és év paraméterekbõl. E megközelítés további haszna, hogy
egyúttal a felhasználó által bevitt adat érvényességét is ellenõrizzük.

Ha a dátum nem érvényes, a getdate() függvénnyel létrehozunk egy, az aktu-


ális dátumon alapuló asszociatív tömböt. Ezután a tömb mon és year elemeivel
magunk állítjuk be a $honap és az $ev változók értékeit.

Most hogy megbizonyosodtunk, hogy a program bemenetét képezõ két változó ér-
vényes adatot tartalmaz, az mktime() függvényt használjuk a hónap elsõ napja
idõbélyegének létrehozására. A késõbbiek során még szükségünk lesz ennek
az idõbélyegnek a napjára és hónapjára, ezért létrehozunk egy $elsoNapTombje
nevû változót, amely a getdate() függvény által visszaadott és ezen az idõbélye-
gen alapuló asszociatív tömb lesz. Végül a magyar héthasználatnak megfelelõen
át kell alakítanunk a hét napjára vonatkozó értéket. A getdate() és más dátum-
függvények a hét elsõ napjának a vasárnapot tekintik. Ezért ha a hét elsõ napján
vagyunk (ez kapja a nullás számot), akkor hetedikre írjuk át, egyébként pedig
a nap számát eggyel csökkentjük. Így a vasárnap a hét végére kerül, a többi nap
pedig eggyel elõrébb, azaz a hétfõ az elsõ helyen szerepel.

A HTML ûrlap létrehozása


15
Olyan kezelõfelületet kell létrehoznunk, amellyel a felhasználók lekérdezhetik
egy hónap és év adatait. Ennek érdekében SELECT elemeket fogunk használni.
Bár ezeket módosíthatatlan elemekként, a HTML kódban is megadhatnánk,
azt is biztosítanunk kell, hogy a lenyíló menük alapbeállítása az adott hónap
legyen, ezért a menüket dinamikusan hozzuk létre és csak ott adjuk hozzá
a SELECTED tulajdonságot az OPTION elemhez, ahol szükséges. A 15.5. program-
ban a létrehozott ûrlapot láthatjuk.
15_ora.qxd 8/3/2001 6:21 PM Page 292

292 15. óra

15.5. program A naptárprogram HTML ûrlapja


1: <?php
2: if ( ! checkdate( $honap, 1, $ev ) )
3: {
4: $mostTomb = getdate();
5: $honap = $mostTomb["mon"];
6: $ev = $mostTomb["year"];
7: }
8: $kezdet = mktime ( 0, 0, 0, $honap, 1, $ev );
9: $elsoNapTombje = getdate($kezdet);
10: if ($elsoNapTombje["wday"] == 0)
{ $elsoNapTombje["wday"] = 6; }
11: else { $elsoNapTombje["wday"]--; }
12: ?>
13: <html>
14: <head>
15: <title><?php print "Naptár:" $elsoNapTombje["year"]
16: $elsoNapTombje["month"] ?></title>
17: <head>
18: <body>
19: <form method="post">
20: <select name="honap">
21: <?php
22: $honapok = Array ("január", "február", "március",
"április",
23: "május", "június", "július", "augusztus",
"szeptember",
24: "október", "november", "december");
25: for ( $x=1; $x <= count( $honapok ); $x++ )
26: {
27: print "\t<option value=\"$x\"";
28: print ($x == $honap)?" SELECTED":"";
29: print ">".$honapok[$x-1]."\n";
30: }
31: ?>
32: </select>
33: <select name="ev">
34: <?php
35: for ( $x=1980; $x<2010; $x++ )
36: {
37: print "\t<option";
38: print ($x == $ev)?" SELECTED":"";
15_ora.qxd 8/3/2001 6:21 PM Page 293

Dátumok kezelése 293

15.5. program (folytatás)


39: print ">$x\n";
40: }
41: ?>
42: </select>
43: <input type="submit" value="Megjelenítés!">
44: </form>
45: </body>
46: </html>

Miután létrehoztuk a $kezdet idõbélyeget és az $elsoNapTombje változót,


megírjuk az oldal HTML kódját. Vegyük észre, hogy az $elsoNapTombje válto-
zót arra használjuk, hogy az évet és a hónapot a TITLE (cím) elemhez adhassuk.
Az elõzõ példákban a FORM elemen belüli $PHP_SELF globális változót használ-
tuk arra, hogy biztosítsuk, az ûrlap az elküldés után újra megjeleníti magát,
e programban viszont azt a tényt használtuk ki, hogy ha egy FORM kódból kihagy-
juk az ACTION paramétert, alapbeállítás szerint ugyanez történik. A lenyíló menük
SELECT elemének létrehozásához visszalépünk PHP módba, hogy létrehozzuk
az egyes OPTION címkéket. Elõször létrehozunk egy $honapok nevû tömböt,
amely a 12 hónap nevét tartalmazza. Ezen aztán végiglépkedünk egy ciklussal,
mindegyikbõl készítve egy OPTION címkét. Ez az egyszerû SELECT elem létreho-
zásának túlbonyolított módja lenne, ha nem kellene közben figyelnünk az $x vál-
tozót (a for ciklusváltozóját). Ha az $x és a $honap megegyezik, a SELECTED
kifejezést hozzáadjuk az OPTION címkéhez, biztosítván ezzel, hogy a megfelelõ
hónap automatikusan kijelölõdik a lap betöltésekor. Hasonló módszerrel írjuk
meg az év menüjét is, végül HTML módba visszatérve létrehozzuk a Megjelenítés
gombot.

Így egy olyan ûrlapot kapunk, amely saját magának elküldi a hónap és év
paramétereket, és amelynek vagy az aktuális év és hónap, vagy pedig az elõzõleg
megadott év és hónap az alapbeállítása. A kész ûrlapot a 15.2. ábrán láthatjuk.

15
15_ora.qxd 8/3/2001 6:21 PM Page 294

294 15. óra

15.2. ábra
A naptár ûrlapja

A naptár táblázatának létrehozása


Most egy táblázatot kell létrehoznunk, amit a kiválasztott hónap napjaival kell
feltöltenünk. Ezt a 15.6. példában követhetjük nyomon, amely a teljes naptár-
programot tartalmazza.

15.6. program A teljes naptárprogram


1: <?php
2: define("EGYNAP", (60*60*24) );
3: if ( ! checkdate( $honap, 1, $ev ) )
4: {
5: $mostTomb = getdate();
6: $honap = $mostTomb["mon"];
7: $ev = $mostTomb["year"];
8: }
9: $kezdet = mktime ( 0, 0, 0, $honap, 1, $ev );
10: $elsoNapTombje = getdate($kezdet);
11: if ($elsoNapTombje["wday"] == 0)
{ $elsoNapTombje["wday"] = 6; }
12: else { $elsoNapTombje["wday"]--; }
13: ?>
14: <html>
15: <head>
16: <title><?php print "Naptár:" $elsoNapTombje["year"]
17: $elsoNapTombje["month"] ?></title>
18: <head>
19: <body>
15_ora.qxd 8/3/2001 6:21 PM Page 295

Dátumok kezelése 295

15.6. program (folytatás)


20: <form method="post">
21: <select name="honap">
22: <?php
23: $honapok = Array ("január", "február", "március",
"április",
24: "május", "június", "július", "augusztus",
"szeptember",
25: "október", "november", "december");
26: for ( $x=1; $x <= count( $honapok ); $x++ )
27: {
28: print "\t<option value=\"$x\"";
29: print ($x == $honap)?" SELECTED":"";
30: print ">".$honapok[$x-1]."\n";
31: }
32: ?>
33: </select>
34: <select name="ev">
35: <?php
36: for ( $x=1980; $x<2010; $x++ )
37: {
38: print "\t<option";
39: print ($x == $ev)?" SELECTED":"";
40: print ">$x\n";
41: }
42: ?>
43: </select>
44: <input type="submit" value="Megjelenítés!">
45: </form>
46: <p>
47: <?php
48: $napok = Array ("hétfõ", "kedd", "szerda",
"csütörtök”,
49: "péntek", "szombat", "vasárnap");
50:
51:
print "<TABLE BORDER=1 CELLPADDING=5>\n";
foreach ( $napok as $nap ) 15
52: print "\t<td><b>$nap</b></td>\n";
53: $kiirando = $kezdet;
54: for ( $szamlalo=0; $szamlalo < (6*7); $szamlalo++ )
55: {
56: $napTomb = getdate( $kiirando );
15_ora.qxd 8/3/2001 6:21 PM Page 296

296 15. óra

15.6. program (folytatás)


57: if ( (($szamlalo) % 7) == 0 )
58: {
59: if ( $napTomb["mon"] != $honap )
60: break;
61: print "</tr><tr>\n";
62: }
63: if ( $szamlalo < $elsoNapTombje["wday"] ||
$napTomb["mon"] != $honap )
64: {
65: print "\t<td><br></td>\n";
66: }
67: else
68: {
69: print "\t<td>" . $honapok[$napTomb["mon"]-1]
" $napTomb["mday"] "</td>\n";
70: $kiirando += EGYNAP;
71: }
72: }
73: print "</tr></table>";
74: ?>
75: </body>
76: </html>
77:

Mivel a táblázat fejlécébe a hét napjai kell, hogy kerüljenek, a programot végiglép-
tetjük a napok neveinek tömbjén és mindegyiket saját cellájába írjuk. A lényeg
a program utolsó for ciklusában történik.

Megadjuk a $szamlalo változó kezdeti értékét, majd biztosítjuk, hogy a ciklus 42


ismétlés után leáll. Erre azért van szükség, hogy a dátumoknak elegendõ cellát
hozzunk létre. A ciklusban a $kiirando változót a getdate() függvénnyel
egy dátumtömbbé alakítjuk és az eredményt a $napTomb változóba tesszük.
Bár a ciklus indításakor a $kiirando változó értéke a hónap elsõ napja lesz,
az idõbélyeget a ciklus minden lefutásakor 24 órával növeljük.

A maradékos osztás segítségével megnézzük, hogy a $szamlalo változó értéke


osztható-e 7-tel. Az ehhez az if utasításhoz tartozó kódrész csak akkor fut le,
ha a $szamlalo 0 vagy a 7 többszöröse. Így eldönthetjük, hogy befejezzük-e
a ciklust vagy új sort kezdjünk.
15_ora.qxd 8/3/2001 6:21 PM Page 297

Dátumok kezelése 297

Ha látjuk, hogy még a ciklus elsõ lefutásában vagy egy cellasor végénél vagyunk,
elvégzünk még egy ellenõrzést: megvizsgáljuk, hogy a $napTomb mon (hónap-
szám) eleme nem egyenlõ-e a $honap változóval. Ha nem egyenlõ, a ciklust befe-
jezhetjük. Emlékezzünk vissza, hogy a $napTomb-ben ugyanaz az idõpont van,
mint ami a $kezdet-ben, ami viszont a hónapnak pontosan az a része, amelyet
megjelenítünk. Ha a $kezdet túljut az aktuális hónapon, a $napTomb[mon] más
számot fog tartalmazni, mint a felhasználó által megadott $honap szám. A mara-
dékosztás igazolta, hogy éppen egy sor végén állunk: ha új hónapban járunk,
elhagyhatjuk a ciklust, ha viszont a sor végére értünk és még mindig ugyanabban
a hónapban vagyunk, befejezzük a sort és újat kezdünk.

A következõ if utasításban azt határozzuk meg, hogy írjunk-e szöveget a cellába.


Nem minden hónap kezdõdik hétfõvel, így könnyen meglehet, hogy egy-két üres
cellával indítunk. Emellett kevés hónap végzõdik sor végén, így az is valószínû,
hogy mielõtt lezárnánk a táblázatot, egy pár üres cellát is kell írnunk. A hónap
elsõ napjának adatait az $elsoNapTombje változóban találjuk. Ebbõl
az $elsoNapTombje["wday"] kifejezés segítségével kideríthetõ, hogy az adott
dátum hányadik nap a héten. Ha a $szamlalo kisebb, mint ez a szám, akkor
tudjuk, hogy még nem értük el azt a cellát, amelybe már írhatnánk. Ugyanezt fel-
használva ha a $honap változó már nem egyenlõ a $napTomb["mon"] változó-
val, tudhatjuk, hogy elértük a hónap végét (de a sor végét még nem). Mindkét
esetben egy üres cellát írunk ki a böngészõbe.

A végsõ else utasításnál jön a feladat érdekes része. Azzal már tisztában vagyunk,
hogy a kiírandó hónapban vagyunk és az aktuális nap oszlopa megegyezik
az $elsoNapTombje változóban tárolt számmal. Most kerül felhasználásra a ciklus
korábbi részében létrehozott $napTomb asszociatív tömb, valamint a hónapok
magyar neveit tartalmazó $honapok tömb, hogy kiírjuk a hónap nevét és napját
egy cellába.

Végül növeljük a $kiirando változót, amely az idõbélyeget tartalmazza. Egysze-


rûen hozzáadjuk egy nap másodperceinek számát (ezt az értéket a program elején
határoztuk meg) és már újra is kezdhetjük a ciklust a $kiirando változó egy új
értékével. A 15.3. ábrán a program egy lehetséges eredményét láthatjuk.

15
15_ora.qxd 8/3/2001 6:21 PM Page 298

298 15. óra

15.3. ábra
A naptárprogram

Összefoglalás
Ezen az órán megtanultuk, hogyan használjuk a time() függvényt az aktuális
idõbélyeg megszerzésére. Megtanultuk, hogyan használjuk az idõbélyegbõl
a dátum részeinek kinyerésére a getdate() függvényt és az idõbélyeget formá-
zott szöveggé alakító date() függvényt. Arról is tanultunk, hogyan hozzunk létre
idõbélyeget az mktime() függvénnyel. Megtanultuk ellenõrizni a dátum érvé-
nyességét a checkdate() függvénnyel, magyar elvárások szerint formáztunk
dátumokat, végül tanulmányoztunk egy példaprogramot, amely az említett
függvényeket alkalmazta.

Kérdések és válaszok
Vannak olyan függvények, amelyekkel a különbözõ naptárak között
váltogatni lehet?
Igen, a PHP naptárak teljes sorozatát biztosítja. Ezekrõl a hivatalos
PHP kézikönyvben olvashatunk,
a http://www.php.net/manual/ref.calendar.php címen.
15_ora.qxd 8/3/2001 6:21 PM Page 299

Dátumok kezelése 299

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. Hogyan kapunk meg egy UNIX idõbélyeget, amely a pontos dátumot és
idõt jelöli?

2. Melyik az a függvény, amelynek bemenete egy idõbélyeg és egy, az adott


dátumot jelképezõ asszociatív tömböt ad vissza?

3. Mely függvényt használnánk a dátum formázására?

4. Hogyan kapjuk meg egy tetszõleges dátum idõbélyegét?

5. Melyik függvényt használjuk egy dátum érvényességének ellenõrzésére?

Feladatok
1. Készítsünk egy születésnapig visszaszámláló programot. Ûrlappal lehessen
megadni az év, hó és nap értékeit, kimenete pedig egy üzenet legyen, amely
közli a felhasználóval, hogy hány nap, óra, perc, másodperc van még hátra
a nagy napig.

15
15_ora.qxd 8/3/2001 6:21 PM Page 300
16_ora.qxd 8/3/2001 6:21 PM Page 301

16. ÓRA
Az adatok kezelése
Ezen az órán az adatellenõrzésben és az adatmûveletekben fogunk egy kicsit
elmélyedni. Újra áttekintjük az adattípusokat. A PHP ugyan automatikusan kezeli
ezeket, de elengedhetetlen, hogy értsük az adatkezelést, ha nagy, megbízható
hálózati alkalmazásokat kell írnunk. Visszatérünk a tömbökhöz is és végül megis-
merkedünk a PHP fejlettebb adatkezelési, adatosztályozási eljárásaival.

Az óra folyamán a következõkrõl tanulunk:

• Hogyan alakítsuk át az egyes adattípusokat más adattípusokká?


• Hogyan alakítja át automatikusan a PHP az adattípusokat a kifejezésekben?
• Milyen további módjai vannak az adattípusok ellenõrzésének?
• Miért fontos megértenünk az adattípusokat?
• Hogyan ellenõrizzük, hogy egy változónak van-e értéke?
• Hogyan lehet másként bejárni egy tömböt?
• Hogyan deríthetjük ki, hogy egy tömb tartalmaz-e egy bizonyos elemet?
• Hogyan alakítsuk át egy tömb minden elemét?
• Hogyan lehet saját szempontok alapján tömbrendezést végezni?
16_ora.qxd 8/3/2001 6:21 PM Page 302

302 16. óra

Újra az adattípusokról
A negyedik órában már tanultunk néhány dolgot a PHP adattípusairól. Van azonban
még valami, ami eddig kimaradt. Ebben a részben a változók adattípusának ellenõr-
zésére használt függvények közül ismerkedünk meg néhánnyal, majd sorra vesszük
azokat a feltételeket, amelyek mellett a PHP automatikusan elvégzi helyettünk
az adattípus-átalakításokat.

Egy kis ismétlés


Azt már tudjuk, hogy a PHP változóinak értéke egész szám (integer), lebegõ-
pontos szám (double), karakterlánc (string), logikai érték (boolean), objektum
vagy tömb lehet. A gettype() függvénnyel bármelyik változótípust lekérdez-
hetjük. A függvény bemenete egy tetszõleges típusú változó, kimenete pedig
a változó adattípusát leíró szöveg:

$adat = 454;
print gettype( $adat );
// azt írja ki, hogy "integer", azaz egész szám

A változók adattípusát közvetlen típusátalakítással vagy a settype() függ-


vénnyel módosíthatjuk. Az adattípusok átalakításához a zárójelbe tett adattípust
a megváltoztatandó változó vagy érték elé írjuk. A folyamat közben a változó tar-
talmát a legcsekélyebb mértékben sem módosítjuk, ehelyett egy átalakított máso-
latot kapunk vissza. A következõ kódrészlet egy tizedestörtet alakít át egész szám-
má.

$adat = 4.333;
print ( integer ) $adat;
// "4"-et ír ki

Az $adat változó lebegõpontos szám típusú maradt, mi csupán a típusátalakítás


eredményét írattuk ki.

A változók adattípusának módosításához a settype() függvényt használhatjuk,


amelynek bemenete az átalakítandó változó és a céladattípus neve.

$adat = 4.333;
settype( $adat, "integer" );
print $adat;
// "4"-et ír ki

Az $adat változó most már egy egész számot tartalmaz.


16_ora.qxd 8/3/2001 6:21 PM Page 303

Az adatok kezelése 303

Összetett adattípusok átalakítása


Néhány egyszerû (skaláris és szöveges) adattípus közötti átváltást már láttuk rész-
leteiben is. Mi történik viszont akkor, ha egyszerû (egész és nem egész számok) és
összetett adattípusok (objektumok és tömbök) között kell típust váltani?

Amikor egy egyszerû adattípust tömbbé alakítunk, olyan tömb jön létre, melynek
elsõ eleme az eredeti érték lesz:

$szoveg = "ez az én szövegem"


$tomb_szoveg = (array) $szoveg;
print $tomb_szoveg[0];
// kiírja az "ez az én szövegem" karakterláncot

Amikor a skaláris vagy szöveges változókat objektumokká alakítjuk, egy egyetlen


scalar nevû tulajdonságot tartalmazó objektum jön létre, ez tartalmazza
az eredeti értéket:

$szoveg = "ez az én szövegem"


$obj_szoveg = (object) $szoveg;
print $obj_szoveg->scalar;
// kiírja az "ez az én szövegem" karakterláncot

A dolog a tömbök és objektumok közötti váltáskor válik igazán izgalmassá.


Amikor egy tömböt objektummá alakítunk, egy olyan új objektum jön létre,
amelyben a tömb egyes kulcsainak egy-egy tulajdonság felel meg.

$cimek = array ( "utca" => "Fõutca", "varos" => "Nagyfalva" );


$obj_cimek = ( object ) $cimek;
print $obj_cimek->utca;
// azt írja ki, hogy "Fõutca"

Fordított esetben, egy objektum tömbbé alakításakor, olyan tömb jön létre, amely-
ben minden objektum tulajdonságnak megfelel egy tömbelem. A metódusokat
az átalakítás figyelmen kívül hagyja.

class Pont
{
var $x;
var $y;
function Pont( $x, $y )
{
$this->x = $x; 16
$this->y = $y;
16_ora.qxd 8/3/2001 6:21 PM Page 304

304 16. óra

}
}
$pont = new Pont( 5, 7 );
$tomb_pont = (array) $pont;
print $tomb_pont["x"];
// azt írja ki, hogy "5"

Az adattípusok automatikus átalakítása


Ha olyan kifejezést hozunk létre, amelyben két különbözõ adattípus szerepel
operandusként, a PHP automatikusan átalakítja az egyiket a számíthatóság
kedvéért. Valószínûleg ezt már igénybe vettük, anélkül, hogy tudtunk volna róla.
Az ûrlapokból származó változók mindig karakterláncok, de ezeket használhattuk
igaz–hamis értékû kifejezésekben is vagy számolásoknál, ha éppen arra volt szük-
ségünk.

Tegyük fel, hogy egy felhasználót megkérdezünk, hány órát tölt a hálózaton
hetente, és a választ az $orak nevû változóban tároljuk. Ez kezdetben szövegként
kerül tárolásra.

$orak = "15"
if ($orak > 15)
print "Ilyen gyakori felhasználónak akár árengedmény
is járhatna";

Az $orak ellenõrzésekor a "15" karakterlánc egész számmá alakul, így a kifeje-


zés eredménye true (igaz) lesz.

Az automatikus átalakítás szabályai viszonylag egyszerûek. Egész számokból vagy


lebegõpontosakból álló környezetben a karakterláncok tartalmuknak megfelelõen
kerülnek átalakításra. Ha egy karakterlánc egész számmal kezdõdik, a szám
az annak megfelelõ érték. Így a következõ kifejezés eredménye 80:

4 * "20mb"

Ha a karakterlánc nem számmal kezdõdik, 0-vá alakul. Így a következõ sor 0-át ad
eredményül:

4 * "körülbelül 20mb"

Ha a karakterláncban a számot egy pont követi, akkor az lebegõpontos értékké


alakul. Ennek megfelelõen a következõ sor eredménye 4,8 lesz:

4 * "1.2"
16_ora.qxd 8/3/2001 6:21 PM Page 305

Az adatok kezelése 305

Az ++ és -- mûveletek karakterláncokra való alkalmazása különleges eset.


A karakterlánc növelése, mint ahogy azt elvártuk, 1-et ad a karakterlánc átalakított
értékéhez, de csak abban az esetben, ha a karakterlánc kizárólag számokból áll.
Maga az új érték azonban karakterlánc marad:

$szoveg = "4";
$szoveg++;
print $szoveg; // kiírja az 5-öt
print gettype( $szoveg ); // azt írja ki, hogy "string"

Ha egy betûket tartalmazó karakterláncot próbálunk növelni, egyedül az utolsó


karakter kódja fog megnõni:

$szoveg = "alszol";
$szoveg++;
print $szoveg; // azt írja ki, hogy "alszom"

Vessük össze ezt a karakterlánc növelésének egy másik megközelítésével:

$szoveg = "alszol";
$szoveg += 1;
print $szoveg; // 1-et ír ki
print gettype( $szoveg ); // azt írja ki, hogy "integer",
azaz egész szám

Az elõzõ példában a $szoveg változó elõször 0-vá (egész számmá) alakul, aztán
adjuk hozzá az 1-et. Ennek a mûveletnek az eredménye 1, amelyet újra a $szoveg
változóba helyezünk. A változó most már egy egész számot fog tartalmazni.

Az egész számok és a lebegõpontosak közötti automatikus átváltás még ennél is


egyszerûbb. Ha egy kifejezés bármelyik operandusa lebegõpontos, a PHP a másik
operandust is lebegõpontossá alakítja és az eredmény is lebegõpontos lesz:

$eredmeny = ( 1 + 20.0);
print gettype( $eredmeny );
// azt írja ki, hogy "double", azaz lebegõpontos

Fontos megjegyeznünk, hogy ha az automatikus átalakítás egy kifejezés kiértékelé-


séhez szükséges, a kifejezés egyik operandusa sem változik meg. Ha egy operan-
dust át kell alakítani, akkor annak átalakított másolata fog szerepelni a kifejezés
részeként.

16
16_ora.qxd 8/3/2001 6:21 PM Page 306

306 16. óra

Az adattípusok ellenõrzése
Már le tudunk kérdezni adattípusokat a gettype() függvénnyel, ami a hibakere-
sésnél jól jöhet, hiszen minden változóról meg tudjuk mondani, hogy milyen típusú.
Gyakran viszont csak azt szeretnénk megnézni, hogy a változó egy bizonyos adattí-
pusú értéket tartalmaz-e. A PHP ehhez az egyes adattípusoknak megfelelõ függvé-
nyeket biztosít, amelyek bemenete egy változó vagy egy érték, visszatérési értéke
pedig logikai. A függvények listáját a 16.1. táblázat tartalmazza.

16.1. táblázat Az adattípusok ellenõrzésének függvényei


Függvény Leírás
is_array() Igaz (true) értéket ad vissza, ha a paraméter tömb
is_bool() Igaz (true) értéket ad vissza, ha a paraméter logikai érték
is_double() Igaz (true) értéket ad vissza, ha a paraméter lebegõpontos szám
is_int() Igaz (true) értéket ad vissza, ha a paraméter egész szám
is_object() Igaz (true) értéket ad vissza, ha a paraméter objektum
is_string() Igaz (true) értéket ad vissza, ha a paraméter karakterlánc

Ezek a függvények egy kicsit megkönnyítik az adattípusok ellenõrzését. Az

if ( gettype( $valtozo ) == "array" )


print "ez egy tömb";

megegyezik a

if ( is_array( $valtozo ) )
print "ez egy tömb";

kóddal. (A $valtozo ellenõrzésének második módja egy kicsit tömörebb.)

Az adattípus-váltás további módjai


Eddig az adattípus-váltás két módjával ismerkedtünk meg: vagy egy értéket alakí-
tunk át meghatározott adattípussá, vagy a settype() függvényt használjuk. Ezek
mellett a PHP bizonyos függvényekkel lehetõvé teszi, hogy értékeket egész
számmá, lebegõpontos számmá vagy szöveggé alakítsunk át. E függvények beme-
nete tömbön és objektumon kívül bármilyen adattípus lehet, kimenetük pedig
az átalakított érték. Leírásukat a 16.2. táblázatban találhatjuk meg.
16_ora.qxd 8/3/2001 6:21 PM Page 307

Az adatok kezelése 307

16.2. táblázat Az adattípus-váltás függvényei


Függvény Leírás
doubleval() Bemenete egy érték, kimenete egy azonos értékû
lebegõpontos szám
intval() Bemenete egy érték, kimenete egy azonos értékû egész szám
strval() Bemenete egy érték, kimenete egy azonos értékû karakterlánc

Miért olyan fontosak az adattípusok?


A PHP nem követeli meg tõlünk, hogy egy változó létrehozásakor megadjuk
annak adattípusát, de elvégzi az adattípus átalakításokat helyettünk, ha a kifejezé-
sekben különbözõ adattípusú változókat használunk. Ha a PHP ennyire leegysze-
rûsíti az életünket, akkor miért van szükségünk mégis az adattípusok nyomon
követésére? Azért, hogy megelõzhessük a hibákat. Képzeljünk el egy olyan függ-
vényt, amely egy tömb kulcsait és értékeit írja ki egy böngészõbe. A PHP-ben
a függvényparaméterek típusát sem adhatjuk meg, így nem írhatjuk elõ, hogy
a meghívó kód egy tömböt adjon át nekünk, amikor a függvényt meghatározzuk.

function tombKiir( $tomb )


{
foreach ( $tomb as $kulcs => $ertek )
print "$kulcs: $ertek<P>";
}

A következõ függvény jól mûködik, ha tömb paraméterrel hívják meg.

tombKiir ( array(4, 4, 55) );

Ha figyelmetlenségünkben skaláris paramétert adunk át neki, az hibához vezet,


amint azt a következõ példa is mutatja:

tombKiir ( 4 );
// Warning: Non array argument supplied for foreach() in
// /home/httpd/htdocs/proba2.php on line 5
// azaz "Figyelmeztetés: a foreach() függvénynek nem tömb
å paramétert adtunk át
// a /home/httpd/htdocs/proba2.php program 5.
å sorában"

16
16_ora.qxd 8/3/2001 6:21 PM Page 308

308 16. óra

Azzal, hogy ellenõrizzük a kapott paraméter adattípusát, sokkal alkalmazkodóbbá


tesszük a függvényt. Azt is megtehetjük, hogy a függvény szép csöndben visszatér,
ha skaláris értéket kap:

function tombKiir( $tomb )


{
if ( ! is_array( $tomb ))
return false;
foreach ( $tomb as $kulcs => $ertek )
print "$kulcs: $ertek<P>";
return true;
}

Most már a hívó kód ellenõrizheti a függvény visszaadott értékeit, hogy megálla-
píthassa, végre tudta-e hajtani feladatát.

Adatátalakítást is használhatunk, hogy a skaláris adatot tömbként használhassuk fel:

function tombKiir( $tomb )


{
if ( ! is_array( $tomb ))
$tomb = (array) $tomb;
foreach ( $tomb as $kulcs => $ertek )
print "$kulcs: $ertek<P>";
return true;
}

A tombKiir() függvény nagyon rugalmassá vált, most már tetszõleges adattípust


képes feldolgozni, akár objektumot is.

Az adattípus ellenõrzése akkor is jól jöhet, ha a függvények visszaadott értékeit


szeretnénk ellenõrizni. Néhány nyelv, például a Java, minden metódusa mindig
egy elõre meghatározott adattípust ad vissza. A PHP-nak nincsenek ilyen megkö-
tései, viszont az ilyen rugalmasság alkalmanként kétértelmûségekhez vezethet.

Erre láttunk egy példát a tizedik órában. A readdir() függvény hamis (false)
értéket ad vissza, amikor eléri a beolvasott könyvtár végét, minden más esetben
viszont a könyvtár egyik elemének nevét tartalmazó karakterláncot. Hagyományo-
san a következõhöz hasonló szerkezetet használnánk, ha egy könyvtár elemeit
szeretnénk beolvastatni:

$kvt = opendir( "konyvtar" );


while ( $nev = readdir( $kvt ) )
print "$nev<br>";
closedir( $kvt );
16_ora.qxd 8/3/2001 6:21 PM Page 309

Az adatok kezelése 309

Ha azonban a readdir() által visszaadott egyik alkönyvtár neve "0", a while


utasítás kifejezése erre a karakterláncra false (hamis) értéket ad vissza és befe-
jezi a felsorolást. Ha ellenõrizzük a readdir() visszaadott értékének adattípusát,
elkerülhetjük ezt a problémát:

$kvt = opendir( "konyvtar" );


while ( is_string( $nev = readdir( $kvt ) ) )
print "$nev<br>";
closedir( $kvt );

A változók meglétének és ürességének ellenõrzése


Az adattípusok ellenõrzése hasznos lehet, ám elõzõleg meg kell bizonyosodnunk
róla, hogy a változó egyáltalán létezik-e, és meg kell néznünk, milyen értéket tartal-
maz. Ezt az isset() függvénnyel tehetjük meg, amelynek bemenete egy változó,
kimenete pedig true (igaz), ha a változó tartalmaz valamiféle értéket:

$nincsertek;
if ( isset( $nincsertek ) )
print "a \$nincsertek változónak van értéke";
else
print "a \$nincsertek változónak nincs értéke";
// kiírja, hogy "a $nincsertek változónak nincs értéke"

Azt a változót, amelyet már bevezettünk, de amelynek még nem adtunk értéket,
a függvény nem beállítottként, érték nélküliként fogja kezelni.

Egy veszélyre azonban hadd hívjuk fel a figyelmet: ha 0-át vagy üres karakterláncot
rendelünk egy változóhoz, a függvény azt már beállítottként, értékkel rendelke-
zõnek fogja tekinteni:

$nincsertek = "";
if ( isset( $nincsertek ) )
print "a \$nincsertek változónak van értéke";
else
print " a \$nincsertek változónak nincs értéke ";
// kiírja, hogy "a $nincsertek változónak van értéke"

Azok a változók, amelyeket a bejövõ ûrlapok töltenek fel értékkel, mindig beállí-
tottként fognak szerepelni, még akkor is, ha a felhasználó egyetlen mezõt sem
töltött ki adattal. Hogy az ilyen helyzetekkel megbirkózhassunk, elõször ellenõriz- 16
nünk kell, hogy üres-e a változó. Az empty() függvény bemenete egy változó,
16_ora.qxd 8/3/2001 6:21 PM Page 310

310 16. óra

kimenete pedig true (igaz), ha a változó nincs beállítva vagy olyan adatot tartal-
maz, mint a 0 vagy egy üres karakterlánc. Akkor is igaz értéket ad vissza,
ha a változó üres tömböt tartalmaz:

$nincsertek = "";
if ( empty( $nincsertek ) )
print "a \$nincsertek változó üres";
else
print " a \$nincsertek változó adatot tartalmaz";
// kiírja, hogy "a $nincsertek változó üres"

További tudnivalók a tömbökrõl


A hetedik órában már bemutattuk a tömböket és a tömbök kezeléséhez szükséges
függvényeket. Ebben a részben további függvényekkel és ötletekkel ismerked-
hetünk meg.

Tömbök bejárása más megközelítésben


A PHP 4 új eszköze a foreach utasítás, amellyel tömbök elemeit olvashatjuk be.
A könyvben lévõ példák legnagyobb részében ezt használjuk. A PHP 3 esetében
még egész másképpen kellett bejárni a tömböket. Ha a PHP 3-nak is megfelelõ
programokat szeretnénk írni vagy szeretnénk érteni a PHP 4 elõtti forráskódokat is,
ezzel tisztában kell lennünk.

Tömb létrehozásakor a PHP egy belsõ mutatót alkalmaz, amely a tömb elsõ
elemére mutat. Ennek az elemnek a kulcsához és értékéhez az each()
függvénnyel férhetünk hozzá. Az each() függvény bemenete egy tömbváltozó,
kimenete pedig egy négyelemû tömb. Ezek közül az elemek közül kettõ számmal
indexelt, kettõ pedig a "key" (kulcs) és az "value" (érték) címkét viseli.
A függvény meghívása után a belsõ mutató a vizsgált tömb következõ elemére fog
mutatni, kivéve, ha elérte a tömb végét, ilyenkor false (hamis) értéket ad vissza.
Hozzunk létre egy tömböt és próbáljuk ki az each() függvényt:

$reszletek = array( "iskola" => "Képzõmûvészeti", "tantargy"


å => "Térbeli ábrázolás" );
$elem = each( $reszletek );
print "$elem[0]<br>"; // azt írja ki, hogy "iskola"
print "$elem[1]<p>"; // azt írja ki, hogy "Képzõmûvészeti"
print "$elem["key"]<br>"; // azt írja ki, hogy "iskola"
print "$elem["value"]<br>"; // azt írja ki,
hogy "Képzõmûvészeti"
16_ora.qxd 8/3/2001 6:21 PM Page 311

Az adatok kezelése 311

A $reszletek nevû tömböt két elemmel hozzuk létre, ezután átadjuk az each()
függvénynek és a visszaadott értéket az $elem nevû tömbbe helyezzük. Az $elem
tartalmazza a $reszletek tömbváltozó elsõ elemének kulcsát és értékét.

Az each() által visszaadott tömböt kicsit nehézkes skaláris változókhoz rendelni,


de szerencsére a PHP list() függvénye megoldja ezt a problémát. A list()
függvény tetszõleges számú változót elfogad bemenetként és ezek mindegyikét
a jobb oldalán megadott tömbváltozó megfelelõ értékeivel tölti fel:

$tomb = array( 44, 55, 66, 77 );


list( $elso, $masodik ) = $tomb;
print "$elso"; // azt írja ki, hogy "44"
print "<BR>";
print "$masodik"; // azt írja ki, hogy "55"

Vegyük észre, hogy a list() függvénnyel könnyedén másolhatjuk át az elõzõ


példa tömbjének elemeit a külön változókba.

Használjuk arra a list() függvényt, hogy az each() minden egyes meghívá-


sakor két változónak adjon értéket.

$reszletek = array( "iskola" => "Képzõmûvészeti",


"tantargy" => "Térbeli ábrázolás" );
while ( list( $kulcs, $ertek ) = each( $reszletek ) )
print "$kulcs: $ertek<BR>";

Bár a kód mûködni fog, valójában még egy sor hiányzik. Ha tömbünkre már
használtuk a belsõ mutatót módosító függvények egyikét, az már nem a tömb
elejére mutat. A reset() függvénnyel visszaállíthatjuk a mutatót a tömb kezde-
tére. Ez a függvény paraméterként egy tömbváltozót vár.

Így az alábbi ismerõsebb szerkezet

foreach( $reszletek as $kulcs => $ertek );


print "$kulcs: $ertek<BR>";

egyenértékû a következõvel:

reset( $reszletek );
while ( list( $kulcs, $ertek ) = each( $reszletek ) )
print "$kulcs: $ertek<BR>";

16
16_ora.qxd 8/3/2001 6:21 PM Page 312

312 16. óra

Elem keresése tömbben


A PHP 4-et megelõzõleg ha azt szerettük volna megtudni, hogy egy elem elõfordul-
e egy tömbben, addig kellett bejárnunk a tömböt, míg megtaláltuk az elemet vagy
elértük a tömb végét. A PHP 4-ben azonban már rendelkezésünkre áll
az in_array() függvény. Két paramétere van, az egyik a keresett érték, a másik
az a tömb, amelyben keresni kívánunk. A függvény true (igaz) értéket ad vissza,
ha megtalálja a keresett értéket, egyébként false (hamis) értéket kapunk.

$reszletek = array( "iskola" => "Képzõmûvészeti", "tantargy"


å => "Térbeli ábrázolás" );
if ( in_array( "Térbeli ábrázolás", $reszletek ) )
print "A kurzus további intézkedésig
felfüggesztve<P>\n";

Elemek eltávolítása a tömbbõl


Az unset() függvénnyel elemeket is eltávolíthatunk egy tömbbõl. A függvény
bemenetéül egy változót vagy egy tömbelemet vár, majd azt minden teketória
nélkül megsemmisíti. Ha a paraméter egy tömb egy eleme, a tömböt automati-
kusan lerövidíti.

unset( $proba["cim"] );
unset( $szamok[1] );

Az unset() függvény egyetlen csapdája az lehet, hogy a tömb indexei


nem követik a tömb megváltozott méretét. Az elõzõ példa tömbje a $szamok[1]
elem eltávolítása után a következõképpen fest:

$szamok[0]
$szamok[2]
$szamok[3]

Szerencsére a foreach() függvénnyel ezen is gond nélkül végiglépkedhetünk.

Függvények alkalmazása a tömb összes elemére


A kifejezésekben szereplõ skaláris változókat könnyen módosíthatjuk, egy tömb
összes elemét megváltoztatni már egy kicsit nehezebb. Ha például a tömb összes
elemének értékéhez egy számot akarunk adni, azt úgy tehetnénk meg,
hogy a tömb összes elemén végiglépkedve frissítjük az értékeket. A PHP azonban
ennél elegánsabb megoldást kínál.
16_ora.qxd 8/3/2001 6:21 PM Page 313

Az adatok kezelése 313

Az array_walk() függvény egy tömb minden elemének kulcsát és értékét átadja


egy, a felhasználó által meghatározott függvénynek. A függvény bemenete egy
tömbváltozó, egy, a függvény nevét megadó karakterlánc érték, és egy elhagyható
harmadik paraméter, amelyet a választott függvénynek szeretnénk még átadni.

Vegyünk egy példát. Van egy adatbázisból kinyert ártömbünk, de mielõtt munkához
kezdenénk vele, az összes árhoz hozzá kell adnunk a forgalmi adót.
Elõször azt a függvényt hozzuk létre, amely hozzáadja az adót:

function ado_hozzaado( &$ertek, $kulcs, $adoszazalek )


{
$ertek +=( ($adoszazalek/100) * $ertek );
}

Az array_walk() számára készített összes függvénynek egyértéket, egy kulcsot


és egy elhagyható harmadik paramétert kell várnia.

Ha paraméterként nem értéket szeretnénk átadni, hanem egy változót, melyben


tükrözõdhetnek a függvény okozta változtatások a függvény hatókörén kívül is,
a függvény-meghatározásban egy ÉS jelet (&) kell az adott paraméter elé írni.
Ez fogja biztosítani, hogy ha a függvényen belül módosítjuk az értéket, az megje-
lenik a függvényen kívül a tömbben is. Ez az oka annak is, hogy példánkban
az ado_hozzaado() függvénynek nincs szokásos értelemben vett visszatérési
értéke.

Most hogy megvan a függvényünk, máris meghívhatjuk az array_walk() függ-


vényt a megfelelõ paraméterekkel:

function ado_hozzaado( &$ertek, $kulcs, $adoszazalek )


{
$ertek +=( ($adoszazalek/100) * $ertek );
}
$arak = array( 10, 17.25, 14.30 );
array_walk( $arak, "ado_hozzaado", 10 );
foreach( $arak as $ertek )
print "$ertek<BR>";
// kimenete:
// 11
// 18.975
// 15.73

A $arak tömbváltozót az ado_hozzaado() függvény nevével együtt átadjuk


az array_walk() függvénynek. Az ado_hozzaado() függvénynek tudnia kell az 16
érvényes adókulcsot. Az array_walk() harmadik, elhagyható paramétere átadódik
a megnevezett függvénynek és ezzel elérjük, hogy az értesüljön az adókulcsról.
16_ora.qxd 8/3/2001 6:21 PM Page 314

314 16. óra

Tömbök egyéni rendezése


A kulcs vagy érték alapján történõ rendezéssel már megismerkedtünk, nem mindig
szoktunk azonban ilyen egyszerûen rendezni tömböket. Elõfordulhat, hogy többdi-
menziós tömbbe beágyazott értékek alapján vagy a szokványos alfanumerikus
összehasonlítástól eltérõ szempont szerint szeretnénk rendezni.

A PHP lehetõvé teszi, hogy magunk határozzuk meg az összehasonlító tömbren-


dezõ függvényeket. Számmal indexelt tömbök esetében ilyenkor az usort()
függvényt kell meghívnunk, melynek bemenete a rendeznivaló tömb és annak
a függvénynek a neve, amely egy elempár összehasonlítását képes elvégzi.

Az általunk meghatározott függvénynek két paramétert kell elfogadnia, amelyek


az összehasonlítandó tömbértékeket tartalmazzák. Ha a feltételek alapján ezek
azonosak, a függvény a 0 értéket kell, hogy visszaadja, ha a tárgytömbben az elsõ
paraméternek a második elõtt kell jönnie, akkor –1-et, ha pedig ez elsõ paramé-
ternek kell a második után szerepelnie, akkor 1-et.

A 16.1. programban azt láthatjuk, hogyan használjuk az usort() függvényt egy


többdimenziós tömb rendezésére.

16.1. program Többdimenziós tömb rendezése mezõ alapján


az usort() függvénnyel
1: <?php
2: $termekek = array(
3: array( "nev"=>"HAL 2000", "ar"=>4500.5 ),
4: array( "nev"=>"Modem", "ar"=>55.5 ),
5: array( "nev"=>"Nyomtató", "ar"=>2200.5 ),
6: array( "nev"=>"Csavarhúzó", "ar"=>22.5 )
7: );
8: function arHasonlito( $a, $b )
9: {
10: if ( $a["ar"] == $b["ar"] )
11: return 0;
12: if ( $a["ar"] < $b["ar"] )
13: return -1;
14: return 1;
15: }
16: usort( $termekek, "arHasonlito" );
17: foreach ( $termekek as $ertek )
18: print $ertek["nev"] ":" $ertek["ar"] "<br>\n";
19: ?>
16_ora.qxd 8/3/2001 6:21 PM Page 315

Az adatok kezelése 315

Elõször létrehozzuk a $termekek tömböt, amelyet az egyes értékek ár mezõje


alapján szeretnénk rendezni. Ezután létrehozzuk az arHasonlito() függvényt,
amelynek két paramétere van, $a és $b. Ezek tartalmazzák azt a két tömböt,
amely a $termekek tömb második szintjét alkotja. Összehasonlítjuk az "ar" ele-
meiket és ha a két ár azonos, 0-át, ha az elsõ kevesebb, mint a másik, –1-et,
egyébként pedig 1-et adunk vissza.

Miután meghatároztuk a rendezõ függvényt és a tömböt is, meghívhatjuk


az usort() függvényt, amelynek átadjuk a $termekek tömböt és az összeha-
sonlító függvény nevét. Az usort() ismételten meghívja függvényünket, mindig
átadja annak a $termekek egy elemét és felcseréli az elemeket, a visszaadott
értékeknek megfelelõen. Végül végigléptetünk a tömbön, hogy megmutassuk
az új elrendezést.

Az usort() függvényt számmal indexelt tömbök esetében használjuk. Ha más


egyéni rendezést szeretnénk egy asszociatív tömbön végrehajtani, használjuk
az uasort() függvényt. Az uasort() úgy rendez, hogy megtartja a kulcsok és
az értékek közötti társítást is. A 16.2. program az uasort() használatát
egy asszociatív tömb rendezésén keresztül mutatja be.

16.2. program Többdimenziós tömb rendezése mezõ alapján


az uasort() függvénnyel
1: <?php
2: $termekek = array(
3: "HAL 2000" => array( "szin" =>"piros",
"ar"=>4500.5 ),
4: "Modem" => array( "szin" =>"kék",
"ar"=>55.5 ),
5: "Nyomtató" => array( "szin" =>"zöld",
"ar"=>2200.5 ),
6: "Csavarhúzó" => array( "szin" =>"piros",
"ar"=>22.5 )
7: );
8: function arHasonlito( $a, $b )
9: {
10: if ( $a["ar"] == $b["ar"] )
11: return 0;
12: if ( $a["ar"] < $b["ar"] )
13: return -1;
14: return 1;
15: }
16: uasort( $termekek, "arHasonlito" );
16
16_ora.qxd 8/3/2001 6:21 PM Page 316

316 16. óra

16.2. program (folytatás)


17: foreach ( $termekek as $kulcs => $ertek )
18: print "$kulcs: " $ertek["ar"] "<br>\n";
19: ?>

Az uksort() függvénnyel az asszociatív tömbökön a kulcsok alapján végezhe-


tünk egyéni rendezést. Az uksort() pontosan ugyanúgy mûködik, mint
az usort() és az uasort(), azzal a különbséggel, hogy az uksort() a tömb
kulcsait hasonlítja össze.

A 16.3. programban az uksort() függvénnyel az egyes kulcsok karakterszáma


alapján rendezünk egy tömböt. Megelõzve a következõ óra anyagát,
az strlen() függvénnyel állapítjuk meg a kulcsok hosszúságát. Az strlen()
függvény bemenete egy karakterlánc, visszaadott értéke pedig annak hosszúsága
karakterben mérve.

16.3. program Asszociatív tömb rendezése kulcshosszúság alapján


az uksort() függvénnyel
1: <?php
2: $ikszek = array(
3: "xxxx" => 4,
4: "xxx" => 5,
5: "xx" => 7,
6: "xxxxx" => 2,
7: "x" => 8
8: );
9: function hosszHasonlito( $a, $b )
10: {
11: if ( strlen( $a ) == strlen( $b ) )
12: return 0;
13: if ( strlen( $a ) < strlen( $b ) )
14: return -1;
15: return 1;
16: }
17: uksort( $ikszek, "hosszHasonlito" );
18: foreach ( $ikszek as $kulcs => $ertek )
19: print "$kulcs: $ertek <br>\n";
20:
21: // a kimenet:
16_ora.qxd 8/3/2001 6:21 PM Page 317

Az adatok kezelése 317

16.3. program (folytatás)


22: // x: 8
23: // xx: 7
24: // xxx: 5
25: // xxxx: 4
26: // xxxxx: 2
27:
28: ?>

Összefoglalás
Az óra során a tömbökkel és adattípusokkal kapcsolatos ismeretekben mélyedtünk
el. Megtanultuk, mi történik, ha összetett adattípust skalárissá alakítunk és fordítva.
Megtudtuk, hogyan kezeli a PHP a különbözõ adattípusokat egy kifejezésben,
hogyan határozza meg automatikusan az eredmény adattípusát helyettünk. Megis-
merkedtünk számos függvénnyel; például az is_array()-jel, amely különféle
adattípusokat ellenõriz, vagy az intval()-lal, amely az adatot egész értékûvé
alakítja át. Megtanultuk, hogyan lehet a PHP-ben hagyományos módon tömböt be-
járni, az each() és a list() függvénnyel. Az in_array() függvénnyel képe-
sek vagyunk ellenõrizni, hogy létezik-e egy adott érték egy tömbben, és el tudunk
távolítani egy elemet egy tömbbõl az unset() függvénnyel. Az array_walk()
függvénnyel már egy tömb összes elemén is végezhetünk mûveleteket, végül azt is
tudjuk, hogyan használjuk az usort(), az uasort() és az uksort() függvé-
nyeket arra, hogy a tömbök egyéni rendezését végezzük.

Kérdések és válaszok
A PHP minden tömbkezelõ függvényével megismerkedtünk?
Nem, az egész könyv sem lenne elég az összes tömbkezelõ függvény bemutatásához.
Teljes listájukat és leírásukat a http://www.php.net/manual/ref.array.php
weboldalon találhatjuk.

16
16_ora.qxd 8/3/2001 6:21 PM Page 318

318 16. óra

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 az a függvény, amellyel adattípusokat tetszõleges más adattípussá ala-
kíthatunk?

2. Sikerülhet ez függvény nélkül is?

3. Mit ír ki a következõ kód?


print "four" * 200;

4. Hogyan határoznánk meg, hogy egy adott változó tömb-e?

5. Melyik függvény adja vissza paraméterének értékét egész számként?

6. Hogyan ellenõrizzük, hogy egy változónak adtunk-e már értéket?

7. Hogyan ellenõrizzük, hogy egy változó üres értéket (például 0-át vagy üres
karakterláncot) tartalmaz?

8. Melyik függvénnyel törölnénk egy tömb egy elemét?

9. Melyik függvénnyel rendeznénk egy számmal indexelt tömböt?

Feladatok
1. Nézzük végig még egyszer a könyv során megoldott feladatokat. Alakítsunk
át minden foreach utasítást úgy, hogy az megfeleljen a PHP 3 követelményei-
nek is.

2. Hozzunk létre egy vegyes adattípusú tömböt. Rendeztessük a tömböt adattí-


pusok szerint.
17_ora.qxd 8/3/2001 6:21 PM Page 319

17. ÓRA
Karakterláncok kezelése
A Világháló valójában szöveges fájlokra épülõ környezet, és igazából nem számít,
mivel gazdagodik a jövõben a tartalma, a mélyén mindig szöveges állományokat
fogunk találni. Így nem meglepõ, hogy a PHP 4 sok olyan függvényt biztosít,
amellyel szövegmûveletek végezhetõk.

Az óra során a következõket tanuljuk meg:

• Hogyan formázzunk karakterláncokat?

• Hogyan határozzuk meg a karakterláncok hosszát?

• Hogyan találjunk meg egy karakterláncon belüli karakterláncot?

• Hogyan bontsuk szét a karakterláncot alkotóelemeire?

• Hogyan távolítsuk el a szóközöket a karakterláncok végérõl vagy elejérõl?

• Hogyan cseréljünk le karakterlánc-részleteket?

• Hogyan változtassuk egy karakterláncban a kisbetûket nagybetûre és fordítva?


17_ora.qxd 8/3/2001 6:21 PM Page 320

320 17. óra

Karakterláncok formázása
A megjeleníteni kívánt karakterláncot eddig egyszerûen kiírattuk a böngészõbe.
A PHP két olyan függvényt tartalmaz, amely lehetõvé teszi az elõzetes formázást,
függetlenül attól, hogy tizedestörteket kell valahány tizedes pontosságra kerekíte-
ni, egy mezõn belül kell jobbra vagy balra igazítani valamit, vagy egy számot kell
különbözõ számrendszerekben megjeleníteni. Ebben a részben a printf() és
az sprintf() függvények által biztosított formázási lehetõségekkel ismerkedünk
meg.

A printf() függvény használata


Ha már dolgoztunk C-vel, biztosan ismerõs lesz a printf() függvény, amelynek
PHP-s változata hasonló, de nem azonos azzal. A függvény bemenete egy karak-
terlánc, más néven a formátumvezérlõ karakterlánc (röviden formázó karakterlánc
vagy egyszerûen formázó), emellett további, különbözõ típusú paraméterek.
A formázó karakterlánc ezen további paraméterek megjelenítését határozza meg.
A következõ kódrészlet például a printf() függvényt használja, hogy egy egész
számot decimális értékként írjon ki:

printf("az én számom az %d", 55 );


// azt írja ki, hogy "az én számom az 55"

A formázó karakterláncban (ami az elsõ paraméter) egy különleges kódot helyez-


tünk el, amely átalakítási meghatározásként ismert.

Az átalakítási meghatározás százalékjellel (%) kezdõdik, és azt határozza


ÚJDONSÁG
meg, hogyan kell a printf() függvény neki megfelelõ paraméterét
kezelni. Egyetlen formátumvezérlõ karakterláncba annyi átalakítási meghatározást
írhatunk, amennyit csak akarunk, feltéve, hogy a printf() függvénynek ugyan-
ennyi paramétert adunk át a formázót követõen.

A következõ kódrészlet két számot ír ki a printf() használatával:

printf("Az elsõ szám: %d<br>\nA második szám: %d<br>\n",


55, 66 );
// A kiírt szöveg:
// Az elsõ szám: 55
// A második szám: 66

Az elsõ átalakítási meghatározás a printf() második paraméterének felel meg,


ami ebben az esetben az 55. A következõ átalakítási meghatározás a 66-nak felel
meg. A százalékjelet követõ d betû miatt a függvény az adatot decimális egészként
értelmezi. A meghatározásnak ez a része típusparaméterként ismeretes.
17_ora.qxd 8/3/2001 6:21 PM Page 321

Karakterláncok kezelése 321

A printf() és a típusparaméterek
Egy típusparaméterrel már találkoztunk, ez volt a d, amely az adatot decimális 17
formátumban jeleníti meg. A többi típusparamétert a 17.1. táblázatban láthatjuk.

17.1. táblázat Típusparaméterek


Paraméter Leírás
d A paramétert decimális számként jeleníti meg.
b Egész számokat bináris számként jelenít meg.
c Egy egész számot annak ASCII megfelelõjeként jelenít meg.
f A paramétert lebegõpontos számként ábrázolja.
o Egy egész számot oktális (8-as számrendszerû) számként
jelenít meg.
s A paramétert karakterlánc-állandónak tekinti.
x Egy egész számot kisbetûs hexadecimális (16-os számrend-
szerû) számként jelenít meg.
X Egy egész számot nagybetûs hexadecimális (16-os számrend-
szerû) számként jelenít meg

A 17.1. program a printf() függvénnyel egy számot a 17.1. táblázat típuspara-


méterei segítségével jelenít meg.

Vegyük észre, hogy a formázó karakterlánc nem egyszerûen csak átalakítási


meghatározásokat tartalmaz, minden további benne szereplõ szöveg kiírásra kerül.

17.1. program Néhány típusparaméter használatának bemutatása


1: <html>
2: <head>
3: <title>17.1. program Néhány típusparaméter
használatának bemutatása</title>
4: </head>
5: <body>
6: <?php
7: $szam = 543;
8: printf("Decimális: %d<br>", $szam );
9: printf("Bináris: %b<br>", $szam );
17_ora.qxd 8/3/2001 6:21 PM Page 322

322 17. óra

17.1. program (folytatás)


10: printf("Kétszeres pontosságú: %f<br>", $szam );
11: printf("Oktális: %o<br>", $szam );
12: printf("Karakterlánc: %s<br>", $szam );
13: printf("Hexa (kisbetûs): %x<br>", $szam );
14: printf("Hexa (nagybetûs): %X<br>", $szam );
15: ?>
16: </body>
17: </html>

A 17.1. program kimenetét a 17.1. ábrán láthatjuk. A printf() függvénnyel


gyorsan tudunk adatokat egyik számrendszerbõl a másikba átalakítani és az ered-
ményt megjeleníteni.

17.1. ábra
Néhány típusparamé-
ter használatának
bemutatása

Ha a HTML-ben hivatkoznunk kell egy színre, három 00 és FF közé esõ, a vörös,


zöld és kék színt képviselõ hexadecimális számot kell megadnunk. A printf()
függvényt használhatjuk arra, hogy a három 0 és 255 közé esõ decimális számot
azok hexadecimális megfelelõire alakítsuk át:

$piros = 204;
$zold = 204;
$kek = 204;
printf( "#%X%X%X", $piros, $zold, $kek );
// azt írja ki, hogy "#CCCCCC"
17_ora.qxd 8/3/2001 6:21 PM Page 323

Karakterláncok kezelése 323

Bár a típusparaméterrel a decimális számokat hexadecimálissá alakíthatjuk,


azt nem tudjuk meghatározni, hogy az egyes paraméterek kimenete hány karaktert
foglaljon el. A HTML színkódjában minden hexadecimális számot két karakteresre 17
kell kitölteni, ami problémát okoz, ha például az elõzõ kódrészlet $piros,
$zold, $kek változóit úgy módosítjuk, hogy 1-et tartalmazzanak. Kimenetül
"#111"-et kapnánk. A bevezetõ nullák használatát egy kitöltõ paraméter segítsé-
gével biztosíthatjuk.

A kitöltõ paraméter
Beállíthatjuk, hogy a kimenet bizonyos karakterekkel megfelelõ szélességûre
töltõdjön ki. A kitöltõ paraméter közvetlenül az átalakító paramétert kezdõ száza-
lékjelet követi. Ha a kimenetet bevezetõ nullákkal szeretnénk kitölteni, a kitöltõ
paraméterben a 0 karaktert az a szám követi, ahány karakteresre szeretnénk
a kimenetet bõvíteni. Ha a kimenet hossza ennél a számnál kisebb lenne, a különb-
ség nullákkal kerül kitöltésre, ha nagyobb, a kitöltõ paraméternek nincs hatása:

printf( "%04d", 36 )
// a kimenet "0036" lesz
printf( "%04d", 12345 )
// a kimenet "12345" lesz

Ha a kimenetet bevezetõ szóközökkel szeretnénk kitölteni, a kitöltõ paraméternek


tartalmaznia kell egy szóköz karaktert, amelyet a kimenet elvárt karakterszáma
követ:

printf( "% 4d", 36 )


// azt írja ki, hogy " 36"
17_ora.qxd 8/3/2001 6:21 PM Page 324

324 17. óra

Bár a HTML dokumentumokban egymás után szereplõ több


szóközt a böngészõk nem jelenítik meg, a megjelenítendõ szö-
veg elé és után helyezett <PRE> címkével mégis biztosíthatjuk
a szóközök és sortörések megjelenítését.
<pre>
<?php
print "A szóközök láthatóvá válnak."
?>
</pre>
Ha teljes dokumentumot szeretnénk szövegként megformázni,
a header() függvényt használhatjuk a dokumentumtípus
(Content-Type) fejlécének módosításához.
header("Content-type: text/plain");
Ne feledjük, hogy programunk nem küldhet semmilyen kimene-
tet a böngészõnek a header() függvényhívást megelõzõen, hogy
a megfelelõ módon mûködjön, mivel a kimenet megkezdésekor
a válasz fejrészét már elküldtük a böngészõnek.

Ha szóközön vagy nullán kívül más karaktert szeretnénk a kitöltéshez használni,


a kitöltõ paraméteren belül a kitöltõ karakter elé írjunk egyszeres idézõjelet:

printf( "%'x4d", 36 )
// azt írja ki "xx36"

Most már rendelkezésünkre állnak azok az eszközök, melyekkel a korábbi HTML


kódot kiegészíthetjük. Eddig ugyan már át tudtuk alakítani a három számot,
de nem tudtuk bevezetõ nullákkal kitölteni azokat:

$piros = 1;
$zold = 1;
$kek = 1;
printf( "#%02X%02X%02X", $piros, $zold, $kek );
// azt írja ki, hogy "#010101"

Most már minden változó hexadecimális számként fog megjelenni. Ha a kimenet


két karakternél rövidebb, a hiányt bevezetõ nullák pótolják.
17_ora.qxd 8/3/2001 6:21 PM Page 325

Karakterláncok kezelése 325

A mezõszélesség meghatározása
Meghatározhatjuk a kimenet által elfoglalt mezõ szélességét is. A mezõszélesség 17
paramétere egy olyan egész szám, amely a százalékjel után következik az átalakító
paraméterben (feltéve, hogy nem használunk helykitöltõ karaktereket). A követ-
kezõ kódrészlet kimenete egy négyelemû felsorolás, amelynek mezõszélessége
20 karakternyi. A szóközök láthatóvá tételéhez a kimenetet egy PRE elembe
ágyazzuk.

print "<pre>";
printf("%20s\n", "Könyvek");
printf("%20s\n", "CDk");
printf("%20s\n", "Játékok");
printf("%20s\n", "Magazinok");
print "</pre>";

A 17.2. ábrán a fenti kódrészlet eredményét láthatjuk.

17.2. ábra
Igazítás a mezõszé-
lességhez

A kimenet alapértelmezés szerint a mezõn belül jobbra igazodik. A balra igazítást


a mezõszélesség paramétere elé tett mínuszjellel (-) érhetjük el.

printf ("%-20s|<- eddig tart a balra zárás\n", "Balra zárt");

Fontos megjegyezni, hogy ha lebegõpontos számot írunk ki, az igazítás csak


a kimenetben levõ szám (ponttól jobbra levõ) tizedesrészére vonatkozik.
Más szóval jobbra igazításkor a lebegõpontos számnak a tizedesponttól balra esõ
része a mezõ bal oldali, túlsó végén marad.
17_ora.qxd 8/3/2001 6:21 PM Page 326

326 17. óra

A pontosság meghatározása
Ha az adatot lebegõpontos formában szeretnénk megjeleníteni, meghatározhatjuk
a kerekítés pontosságát. Ez fõleg a pénznem átváltásakor szokott fontos lenni.
A pontosságot meghatározó paraméter egy pontból és egy számból áll, és közvet-
lenül a típusparaméter elé kell írni. A megadott szám határozza meg, hány tize-
desre szeretnénk kerekíteni. Ez a paraméter csak akkor érvényes, ha a kimenet
f típusparaméterû:

printf ("%.2f\n", 5.333333);


// azt írja ki, hogy "5.33"

A C nyelv printf() függvényében akkor is lehetõségünk van


a pontosság megadására, ha decimális kimenet esetén kérünk
kitöltést. A PHP 4-ben a pontosság paraméterének nincs
semmilyen hatása a decimális kimenetre. Egész számok nullák-
kal való bevezetéséhez a kitöltõ paramétert kell használnunk.

Átalakító paraméterek (Ismétlés)


A 17.2. táblázatban az átalakító paramétereket foglaljuk össze. Megjegyzendõ,
hogy a két (kitöltõ és mezõszélesség) paraméter együttes használata bonyolult,
így azt tanácsoljuk, egyszerre csak az egyiket használjuk.

17.2. táblázat Az átalakítás lépései


Név Leírás Példa
Kitöltõ paraméter A kimenet által elfoglalandó karakter- ' 4'
számot és a kitöltésre használt karaktert
adja meg.
Mezõszélesség paraméter A formázandó karakterlánc méretét '20'
adja meg.
Pontosság paraméter Meghatározza, hogy a kétszeres '.4'
pontosságú számokat hány tizedesre
kell kerekíteni.
Típusparaméter Meghatározza az eredmény adattípusát. 'd'
17_ora.qxd 8/3/2001 6:21 PM Page 327

Karakterláncok kezelése 327

A 17.2. program a printf() használatával egy termékárlistát hoz létre.

17
17.2. program Termékárlista formázása a printf() függvénnyel
1: <html>
2: <head>
3: <title>17.2. program Termékárlista formázása
a printf() függvénnyel</title>
4: </head>
5: <body>
6: <?php
7: $termekek = Array("Zöld karosszék"=>"222.4",
8: "Gyertyatartó" => "4",
9: "Kávézóasztal" => "80.6"
10: );
11: print "<pre>";
12: printf("%-20s%23s\n", "Név", "Ár");
13: printf("%'-43s\n", "");
14: foreach ( $termekek as $kulcs=>$ertek )
15: printf( "%-20s%20.2f\n", $kulcs, $ertek );
16: print "</pre>";
17: ?>
18: </body>
19: </html>

Elõször a termékek nevét és árát tartalmazó tömböt adjuk meg. Egy PRE elemmel
jelezzük a böngészõnek, hogy a szóközöket és a soremeléseket értelmezze.
A printf() elsõ meghívása a következõ formázó karakterláncot adja meg:

"%-20s%23s\n"

Az elsõ átalakító meghatározás ("%-20s") a mezõszélességet balra zárt 20 karak-


teresre állítja. Ebben a mezõben egy karakterlánc típusú paramétert helyezünk el.
A második meghatározás ("%23s") egy jobbra zárt mezõszélességet ad meg.
A printf() függvénynek ez a meghívása hozza létre leendõ táblázatunk fejlécét.

A printf() második meghívásával egy 43 karakter hosszú, mínuszjelekbõl (-)


álló vonalat húzunk. Ezt úgy érjük el, hogy egy üres karakterláncot kitöltõ para-
méterrel jelenítünk meg.

A printf() legutolsó meghívása annak a foreach utasításnak a része, amely


végiglépked a termékek tömbjén. Két átalakító meghatározást használunk.
17_ora.qxd 8/3/2001 6:21 PM Page 328

328 17. óra

Az elsõ ("%-20s") a termék nevét írja ki egy 20 karakteres mezõbe, balra igazít-
va. A másik ("%20.2f") a mezõszélesség paraméterrel azt biztosítja, hogy
az eredmény egy 20 karakteres mezõben jobbra igazítva jelenjen meg, a pontossá-
gi paraméterrel pedig azt, hogy a megjelenített kétszeres pontosságú érték két
tizedesre legyen kerekítve.

A 17.3. ábrán a 17.2. program eredményét láthatjuk.

17.3. ábra
Termékárlista formá-
zása a printf() függ-
vénnyel

Formázott karakterlánc tárolása


A printf() az adatokat a böngészõben jeleníti meg, ami azzal jár, hogy eredmé-
nye programunk számára nem elérhetõ. Használhatjuk azonban a sprintf()
függvényt is, amelynek használata megegyezik a printf() függvényével,
viszont az eredményét egy karakterláncban adja vissza, amelyet aztán késõbbi
használatra egy változóba helyezhetünk. A következõ kódrészlet a sprintf()
függvény segítségével egy lebegõpontos értéket két tizedesre kerekít és az ered-
ményt a $kerek változóban tárolja:

$kerek = sprintf("%.2f", 23.34454);


print "Még $kerek forintot költhetsz";

A sprintf() függvény egy lehetséges felhasználása, hogy vele a megformázott


adatot fájlban lehet tárolni. Ennek az a módja, hogy elõször meghívjuk a sprintf()
függvényt, a visszaadott értékét egy változóban tároljuk, majd az fputs() függ-
vénnyel fájlba írjuk.
17_ora.qxd 8/3/2001 6:21 PM Page 329

Karakterláncok kezelése 329

Részletesebben a karakterláncokról
Nem minden esetben tudunk mindent azokról az adatokról, amelyekkel dolgo- 17
zunk. A karakterláncok többféle forrásból is érkezhetnek, beviheti a felhasználó,
érkezhetnek adatbázisokból, fájlokból és weboldalakról. A PHP 4 több függvénye
segítségünkre lehet abban, hogy ezekrõl a külsõ forrásból érkezõ adatokról többet
tudjunk meg.

Szövegek indexelése
A karakterláncokkal kapcsolatban gyakran használjuk az indexelés szót, de
a tömböknél még gyakrabban találkozhatunk vele. Valójában a karakterláncok és
a tömbök nem állnak olyan messze egymástól, mint azt gondolnánk. Egy karakter-
láncot elképzelhetünk egy karakterekbõl álló tömbként is. Ennek megfelelõen
a karakterláncok egyes karaktereihez ugyanúgy férhetünk hozzá, mint egy tömb
elemeihez:

$proba = "gazfickó";
print $proba[0]; // azt írja ki, hogy "g"
print $proba[2]; // azt írja ki, hogy "z"

Ne felejtsük el, hogy amikor egy karakterláncon belüli karakter indexérõl vagy
helyérõl beszélünk, akkor a karaktereket – ugyanúgy, mint a tömb elemeit – 0-tól
kezdve számozzuk. A tömbökkel kapcsolatos félreértések elkerülése érdekében
a PHP 4 bevezette a $proba{0} formát is erre a célra.

Szöveg hosszának megállapítása az strlen() függvénnyel


Az strlen() függvény segítségével megállapíthatjuk egy karakterlánc hosszát.
A függvény bemenete egy karakterlánc, visszatérési értéke pedig egy egész szám,
amely a függvénynek átadott változó karaktereinek száma. Ez a függvény például
kimondottan jól jöhet a felhasználó által megadott bemenet hosszának ellenõrzé-
sére. A következõ kódrészlettel ellenõrizhetjük, hogy a tagnyilvántartó azonosító
négykarakteres-e:

if ( strlen( $tagazonosito ) == 4)
print "Köszönöm!";
else
print "Az azonosítónak négykarakteresnek kell lennie<P>";

Ha a $tagazonosito globális változó értéke négykarakteres, megköszönjük


a felhasználónak, hogy rendelkezésünkre bocsátotta, más esetben hibaüzenetet
jelenítünk meg.
17_ora.qxd 8/3/2001 6:21 PM Page 330

330 17. óra

Szövegrész megkeresése az strstr() függvénnyel


Ezzel a függvénnyel azt állapíthatjuk meg, hogy egy karakterlánc megtalálható-e
beágyazva egy másik karakterláncban. Az strstr() függvény két paramétert
kap bemenetéül: a keresendõ szöveget és a forrásláncot, azaz azt a karakterláncot,
amelyben keresnie kell. Ha a keresett karakterlánc nem található a szövegben,
a visszatérési érték false (hamis) lesz, ellenkezõ esetben a függvény a forrás-
láncból a keresett karakterlánccal kezdõdõ részt adja vissza. A következõ példá-
ban megkülönböztetetten kezeljük azokat a tagazonosítókat, amelyekben
megtalálható az AB karakterlánc:

$tagazonosito = "pAB7";
if ( strstr( $tagazonosito, "AB" ) )
print "Köszönöm. Ne feledje, hogy tagsága hamarosan
lejár!";
else
print "Köszönöm!";

Mivel a $tagazonosito változó tartalmazza az AB karakterláncot, az strstr()


az AB7 karakterláncot adja vissza. Ez true (igaz) eredménynek számít, így
egy különleges üzenetet ír ki. Mi történik akkor, ha a felhasználó a "pab7" karak-
terláncot adja meg? Az strstr() megkülönbözteti a kis- és nagybetûket, így
nem találja meg az AB karakterláncot. Az if utasítás feltétele nem válik igazzá, így
a szokványos üzenet kerül a böngészõhöz. Ha vagy AB-t, vagy ab-t szeretnénk
kerestetni a szövegben, használjuk az stristr() függvényt, melynek mûködése
azonos az strstr()-ével, viszont nem különbözteti meg a kis- és nagybetûket.

Részlánc elhelyezkedésének meghatározása


az strpos() függvénnyel
Az strpos() függvény segítségével kideríthetjük, hogy egy szöveg megtalálható-e
egy másik szöveg részeként, és ha igen, hol. Bemenetét két paraméter képezi,
a forráslánc, amelyben keresünk, és a karakterlánc, amelyet keresünk. Ezek mellett
létezik még egy harmadik, nem kötelezõ paraméter, mégpedig azt az indexet
megadó egész szám, amelytõl kezdve keresni szeretnénk. Ha a keresett karakterlánc
nem található, a függvény a false (hamis) értéket adja vissza, ellenkezõ esetben
azt az egész számot, mely indextõl a keresett szöveg kezdõdik. A következõ prog-
ramrészletben az strpos() függvénnyel gyõzõdünk meg arról, hogy egy karakter-
lánc az mz karakterekkel kezdõdik-e:

$tagazonosito = "mz00xyz";
if ( strpos($tagazonosito, "mz") === 0 )
print "Üdv, mz.";
17_ora.qxd 8/3/2001 6:21 PM Page 331

Karakterláncok kezelése 331

Vegyük szemügyre azt a trükköt, amellyel a kívánt eredményt kaptuk. Az strpos()


megtalálja az mz karaktersort a lánc elején. Ez azt jelenti, hogy 0 értéket ad vissza,
ami viszont a kifejezés kiértékelése során hamis értéket eredményezne. Hogy ezt 17
elkerüljük, a PHP 4 új azonosság mûveleti jelét (===) alkalmazzuk, amely akkor
ad vissza true (igaz) értéket, ha bal és jobb oldali operandusa egyenlõ értékû és
azonos típusú is egyben.

Szövegrészlet kinyerése a substr() függvénnyel


A substr() függvény egy kezdõindextõl kezdve meghatározott hosszúságú
karakterláncot ad vissza. Bemenetét két paraméter képezi, az egyik a forráslánc,
a másik a kezdõindex. A függvény az összes karaktert visszaadja a kezdõindextõl
a forráslánc végéig. Harmadik, nem kötelezõ paramétere egy egész szám, amely
a visszaadandó szöveg hosszát jelenti. Ha ezt is megadjuk, a függvény csak
a meghatározott mennyiségû karaktert adja vissza a kezdõindextõl számítva.

$proba = "gazfickó";
print substr($proba,3); // azt írja ki "fickó"
print substr($proba,3,4); // azt írja ki "fick"

Ha kezdõindexként negatív számot adunk meg, a függvény nem a karakterlánc


elejétõl számolja a karaktereket, hanem a végétõl. A következõ kódrészlet megha-
tározott üzenetet ír ki azoknak, akiknek e-mail címe .hu-val végzõdik.

$cim = "felhasznalo@szolgaltato.hu"
if ( substr( $cim, -3 ) == ".hu" )
print "Ne felejtse el magyar vásárlóinknak járó
speciális ajánlatainkat!";
else
print "Üdvözöljük üzletünkben!";

Karakterlánc elemekre bontása az strtok() függvénnyel


Az strtok() függvénnyel karakterláncok szintaktikai elemzését végezhetjük.
A függvény legelsõ meghívásakor két paramétert vár, az elemzendõ karakterláncot
és egy határolójelet, amely alapján a karakterláncot felbontja. A határolójel tetszõ-
leges számú karakterbõl állhat. A függvény elsõ meghívásakor átmenetileg
a memóriába helyezi a teljes forrásláncot, így a további meghívások alkalmával
már csak a határolójelet kell megadnunk. Az strtok() minden meghívásakor
a következõ megtalált elemet adja vissza, a karakterlánc végére érkezést
a false (hamis) érték visszaadásával jelzi. Ezt a függvényt legtöbbször cikluson
belül használjuk. A 17.3. program egy URL-t bont elemeire: elõször leválasztja
a gazdagépet és az elérési útvonalat a karakterláncról, majd a változó–érték páro-
kat bontja szét. A 17.3. program eredményét a 17.3. ábrán láthatjuk.
17_ora.qxd 8/3/2001 6:21 PM Page 332

332 17. óra

17.3. program Karakterlánc elemekre bontása az strtok() függvénnyel


1: <html>
2: <head>
3: <title>17.3. program Karakterlánc elemekre bontása
4: az strtok() függvénnyel</title>
5: </head>
6: <body>
7: <?php
8: $proba = "http://www.deja.com/qs.xp?
9: OP=dnquery.xp&ST=MS&DBS=2&QRY=developer+php";
10: $hatarolo = "?&";
11: $szo = strtok( $proba, $hatarolo );
12: while ( is_string( $szo ) )
13: {
14: if ( $szo )
15: print "$szo<br>";
16: $szo = strtok( $hatarolo );
17: }
18: ?>
19: </body>
20: </html>

Az strtok() függvény önmagában nem sok mindent támogat, így csak különfé-
le trükkökkel bírhatjuk igazán hasznos munkára. Elõször a $hatarolo változó-
ban tároljuk a határolójelet. Meghívjuk az strtok() függvényt, átadjuk neki
az elemzendõ URL-t és a $hatarolo karakterláncot. Az elsõ eredményt a $szo
változóba helyezzük. A while ciklus feltételében azt ellenõrizzük, hogy a $szo
karakterlánc-e. Ha nem az, tudhatjuk, hogy elértük az URL végét és a feladat
befejezõdött.

Azért ellenõrizzük a visszaadott érték típusát, mert ha egy karakterlánc egy sorá-
ban két határolójel van, az strtok() az elsõ határolójel elérésekor üres karakter-
láncot ad vissza. Így, ha a $szo egy üres karakterlánc, az alábbi példában látható
szokványosabb próbálkozás sikertelen lesz, még akkor is, ha a függvény még
nem érte el a forráslánc végét, mivel a while feltétele hamissá válik:

while ( $szo )
{
$szo = strtok( $hatarolo );
}
17_ora.qxd 8/3/2001 6:21 PM Page 333

Karakterláncok kezelése 333

Ha meggyõzõdtünk róla, hogy a $szo változó karakterláncot tartalmaz, elkezdhe-


tünk dolgozni vele. Ha a $szo nem üres karakterlánc, megjelenítjük a böngészõ-
ben. Aztán újra meg kell hívnunk a strtok() függvényt, hogy a $szo változót 17
újabb karakterlánccal töltse fel a következõ kiértékeléshez. Vegyük észre, hogy
a második alkalommal nem adtuk át a függvénynek a forrásláncot. Ha ezt mégis
megtennénk, újra a forráslánc elsõ szavát találná meg, így végtelen ciklusba
kerülnénk.

A karakterláncok kezelése
A PHP 4 a karakterlánc paraméterek kisebb-nagyobb átalakításához számos
függvényt biztosít.

Szöveg tisztogatása a trim() típusú függvényekkel


Ha egy felhasználótól vagy fájlból kapunk információt, sohasem lehetünk biztosak
benne, hogy az adat elõtt vagy után nincs egy vagy több fölösleges elválasztó
karakter. A trim() függvény ezeket az elválasztó karaktereket (soremelés, tabu-
látorjel, szóköz stb.) hagyja el a karakterlánc elejérõl és végérõl. Bemenete
a megtisztítandó szöveg, kimenete pedig a megtisztított.

$szoveg = "\t\t\teléggé levegõs ez a szöveg ";


$szoveg = trim( $szoveg );
print $szoveg
// azt írja ki, hogy "eléggé levegõs ez a szöveg"

Persze lehet, hogy ez a túlbuzgó függvény nem a legmegfelelõbb számunkra.


Elképzelhetõ, hogy a szöveg elején levõ elválasztó karaktereket meg szeretnénk
tartani és csak a szöveg végérõl akarjuk eltávolítani azokat. Pontosan erre
a feladatra találták ki a chop() függvényt. Vigyázzunk, ha Perl ismeretekkel is
rendelkezünk, mivel ott a chop() függvény egy kicsit más jelentéssel bír. A prob-
léma áthidalására a PHP fejlesztõi ugyanezen szolgáltatás eléréséhez megadták
az rtim() függvénynevet is.

$szoveg = "\t\t\teléggé levegõs ez a szöveg ";


$szoveg = chop( $szoveg );
print $szoveg
// azt írja ki, hogy " eléggé levegõs ez a szöveg"

Lehetõségünk van az ltrim() függvény használatára is, amely az elválasztó


karaktereket csak a karakterlánc elejérõl távolítja el. Ahogy az elõzõeknél is,
bemenete az átalakítandó szöveg, kimenete pedig az elválasztó karakterektõl
csupán a bal oldalán mentes karakterlánc:
17_ora.qxd 8/3/2001 6:21 PM Page 334

334 17. óra

$szoveg = "\t\t\teléggé levegõs ez a szöveg ";


$szoveg = ltrim( $szoveg );
print $szoveg
// azt írja ki, hogy "eléggé levegõs ez a szöveg "

Karakterlánc részének lecserélése


a substr_replace() függvénnyel
A substr_replace() hasonlóan mûködik, mint a substr(), a különbség
abban rejlik, hogy itt lehetõség nyílik a kivonatolt karakterlánc-részlet lecserélésére
is. A függvény három paramétert vár: az átalakítandó karakterláncot, a csereszö-
veget és a kezdõindexet. Ezek mellett létezik egy nem kötelezõ, negyedik hosszú-
ság paraméter is. A substr_replace() függvény megtalálja a kezdõindex és
a hosszúság paraméter által meghatározott részláncot, lecseréli azt a csereszövegre,
és a teljes átalakított karakterláncot adja vissza.

A következõ kódrészletben egy felhasználó tagazonosítójának megújításához


le kell cserélnünk annak harmadik és negyedik karakterét:

<?
$tagazonosito = "mz99xyz";
$tagazonosito = substr_replace( $tagazonosito, "00", 2, 2 );
print "Az új tagnyilvántartó azonosító: $tagazonosito<p>";
// azt írja ki, hogy "Az új tagnyilvántartó azonosító:
mz00xyz"
?>

Az összes részlánc lecserélése


az str_replace() függvénnyel
Az str_replace() függvény a keresett karakterlánc-rész összes elõfordulását
lecseréli egy másik karakterláncra. Bemenetének három paramétere a lecserélen-
dõ karakterlánc, a csereszöveg és a forrásszöveg. A függvény kimenete az átalakí-
tott karakterlánc. A következõ példában egy karakterláncban az 1999 összes
elõfordulását 2000-re cseréljük:

$karakterlanc = "Ezt az oldal 1999-ben szerzõi jog által


védett";
$karakterlanc .= "Felsõoktatási tájékoztató 1999";
print str_replace("1999","2000",$karakterlanc);
17_ora.qxd 8/3/2001 6:21 PM Page 335

Karakterláncok kezelése 335

Kis- és nagybetûk közti váltás


A PHP több függvénnyel is segítségünkre van a kis- és nagybetûk cseréjében. 17
Amikor felhasználók által beírt adattal dolgozunk, fontos lehet mindent csupa
nagybetûsre vagy csupa kisbetûsre alakítani, hogy aztán könnyebben összehason-
líthatóak legyenek. Az strtoupper() függvény segítségével egy karakterláncot
csupa nagybetûsre alakíthatunk. A függvény egyetlen bemenete az átalakítandó
szöveg, visszatérési értéke pedig a csupa nagybetûs karakterlánc:

$tagazonosito = "mz00xyz";
$tagazonosito = strtoupper( $tagazonosito );
print "$tagazonosito<P>"; // azt írja ki, hogy "MZ00XYZ"

Karakterláncunk csupa kisbetûssé való alakításához használjuk az strtolower()


függvényt. Ennek egyetlen bemenete az átalakítandó szöveg és a csupa kisbetûs
karakterláncot adja vissza:

$honlap_url = "WWW.KISKAPU.HU";
$honlap_url = strtolower( $honlap_url );
if ( ! ( strpos ( $honlap_url, “http://” ) === 0 ) )
$honlap_url = "http://$honlap_url";
print $honlap_url; // azt írja ki, hogy
"http://www.kiskapu.hu"

A PHP-nek van egy nagyszerû, „tüneti kezelést” biztosító függvénye, az ucwords().


Ez a függvény egy karakterlánc minden szavának elsõ betûjét teszi nagybetûssé.
A következõ programrészletben a felhasználó által beírt karakterláncban a szavak
elsõ betûjét nagybetûre cseréljük:

$teljes_nev = "vitéz tinódi lantos sebestyén";


$teljes_nev = ucwords( $teljes_nev );
print $teljes_nev; // azt írja ki, hogy "Vitéz Tinódi
Lantos Sebestyén"

A függvény kizárólag a szavak elsõ betûjét cseréli le, így ha a felhasználónak


nehézségei vannak a SHIFT billentyûvel és azt írta be, hogy "ViTÉz tINóDi
laNtos sEBeSTyéN", ez a függvény nem sokban lesz segítségére, hiszen a tü-
neti kezelés eredménye "ViTÉz TINóDi LaNtos SEBeSTyéN" lesz. Ezen
úgy segíthetünk, hogy az ucwords() meghívása elõtt az strtolower() függ-
vénnyel elõször csupa kisbetûssé alakítjuk a karakterláncot:

$teljes_nev = "ViTÉz tINóDi laNtos sEBeSTyéN";


$teljes_nev = ucwords( strtolower($teljes_nev) );
print $teljes_nev; // azt írja ki, hogy "Vitéz Tinódi
Lantos Sebestyén"
17_ora.qxd 8/3/2001 6:21 PM Page 336

336 17. óra

Fel kell, hogy hívjuk a kedves olvasó figyelmét arra, hogy a magyar szövegekkel
az ékezetes betûk miatt alapbeállításban problémáink akadhatnak. A nemzeti be-
állítások testreszabására használható setlocale() függvényt kell alkalmaznunk,
hogy a kívánt eredményt elérjük.

Karakterláncok tömbbé alakítása


az explode() függvénnyel
A mókásan „robbantó”-nak nevezett függvény bizonyos mértékben hasonló
az strtok() függvényhez. Ez a függvény azonban egy karakterláncot tömbbé bont
fel, amit aztán tárolhatunk, rendezhetünk, vagy azt tehetünk vele, amit csak szeret-
nénk. Bemenetét két paraméter alkotja, ez egyik egy határolójel, ami alapján fel sze-
retnénk bontani a forrásláncot, a másik maga a forráslánc. A határolójel több karak-
terbõl is állhat, ezek együtt fogják alkotni a határolójelet. (Ez eltér az strtok()
függvény mûködésétõl, ahol a megadott karakterlánc minden karaktere egy-egy
önálló határolójel lesz.) A következõ kódrészlet egy dátumot bont fel részeire és az
eredményt egy tömbben tárolja:

$kezdet = "2000.12.01";
$datum_tomb = explode(".", $kezdet);
// $datum_tomb[0] == "2000"
// $datum_tomb[1] == "12"
// $datum_tomb[2] == "00"

Összefoglalás
A PHP külvilággal való kapcsolattartása és adattárolása leginkább karakterláncokon
keresztül valósul meg. Az órán a programjainkban levõ karakterláncok kezelésével
ismerkedtünk meg.

A printf() és az sprintf() függvények segítségével megtanultuk formázni


a karakterláncokat. Ezt a két függvényt olyan karakterláncok létrehozására hasz-
náljuk, amelyek egyrészt átalakítják, másrészt el is rendezik az adatokat. Tanultunk
olyan függvényekrõl, amelyek információt árulnak el a karakterláncokról.
Meg tudjuk állapítani egy karakterlánc hosszúságát az strlen(), egy részlánc
jelenlétét az strpos() függvénnyel, vagy kiszakíthatunk részláncokat az
strtok() segítségével.

Végül azokról a függvényekrõl tanultunk, amelyek karakterláncokat alakítanak át.


Most már el tudjuk tüntetni az elválasztó karaktereket a trim(), ltrim() vagy
a chop() függvénnyel, válthatunk a kis- és nagybetûk között az strtoupper(),
az strtolower() és az ucwords() függvényekkel, valamint egy karakterlánc
összes elõfordulását lecseréltethetjük az str_replace() segítségével.
17_ora.qxd 8/3/2001 6:21 PM Page 337

Karakterláncok kezelése 337

Ezek után nehéz elhinni, de még mindig nem végeztünk a karakterláncokkal.


A PHP ugyanis támogatja a szabályos kifejezéseket, amelyek a karakterlánc-
kezelés még hatékonyabb formáját biztosítják. A szabályos kifejezések alkotják 17
a következõ óra anyagát.

Kérdések és válaszok
Vannak még egyéb hasznos karakterlánc-függvények?
Vannak. A PHP több mint 60 ilyen függvénnyel rendelkezik! Ezekrõl a PHP 4
kézikönyvében olvashatunk, amelynek megfelelõ része
a http://php.net/manual/ref.strings.php címen található.

A printf() mûködését bemutató példában a formázást úgy jelenítettük


meg, hogy a kimenetet <PRE> elemek közé tettük. Ez a legjobb módja
a formázott szöveg megjelenítésének a böngészõben?
A <PRE> címkék akkor szükségesek, ha a sima szöveg (plain text) formázást
HTML-es környezetben is meg szeretnénk tartani. Ha viszont a teljes dokumentu-
mot így szeretnénk megjeleníteni, a legokosabb, ha közöljük a böngészõvel, hogy
sima szövegként formázza meg azt. Ez a header() függvénnyel érhetõ el:

Header("Content-type: text/plain");

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 átalakító paramétert használnánk a printf() függvényben
egy egész szám lebegõpontos számként való megformázására?

2. Hogyan egészítsük ki az 1. kérdésben átalakított számot nullákkal úgy, hogy


a tizedespont elõtti (attól balra esõ) rész 4 karakter hosszúságú legyen?

3. Hogyan kerekítenénk az elõzõ kérdés lebegõpontos számát


két tizedesjegyre?

4. Milyen függvényeket használnánk egy szöveg hosszának kiderítéséhez?

5. Milyen függvényeket használnánk egy részlánc más karakterláncon belüli


kezdetének meghatározására?
17_ora.qxd 8/3/2001 6:21 PM Page 338

338 17. óra

6. Milyen függvényeket használnánk arra, hogy egy szövegbõl kivonjuk annak


egy darabját?

7. Hogyan távolíthatjuk el az elválasztó karaktereket egy karakterlánc elejérõl?

8. Hogyan alakítanánk át egy karakterláncot csupa nagybetûsre?

9. Hogyan bontanánk fel egy határolójelekkel elválasztott karakterláncot


tömbökre?

Feladatok
1. Hozzunk létre egy olyan vélemény-visszajelzõ ûrlapot, amely a felhasználó
nevét és e-mail címét kéri be. Használjuk a kis- és nagybetûket átalakító
függvényeket a nevek elsõ betûjének nagybetûsítésére, majd jelenítsük meg
az eredményt a böngészõben. Ellenõrizzük, hogy a cím tartalmaz-e @-jelet,
ha nem, figyelmeztessük a felhasználót.

2. Hozzunk létre egy lebegõpontos és egész számokból álló tömböt. Léptessünk


végig a tömbön és kerekítsük az összes lebegõpontos számot két tizedesjegyre.
Igazítsuk jobbra a kimenetet egy 20 karakter szélességû mezõben.
18_ora.qxd 8/3/2001 6:22 PM Page 339

18. ÓRA
A szabályos kifejezések
használata
A szövegek vizsgálatának és elemzésének nagyszerû módja a szabályos kifejezések
(regular expressions) használata. Ezek lehetõvé teszik, hogy egy karakterláncon
belül mintákat keressünk, a találatokat pedig rugalmasan és pontosan kapjuk
vissza. Mivel hatékonyabbak az elõzõ órában tanult karakterlánc-kezelõ függvé-
nyeknél, lassabbak is azoknál. Így azt tanácsoljuk, hogy ha nincs különösebb
szükségünk a szabályos kifejezések által biztosított hatékonyságra, inkább hasz-
náljuk a hagyományos karakterlánc-kezelõ függvényeket.

A PHP a szabályos kifejezések két típusát támogatja. Egyrészt támogatja a Perl által
használtakat, az azoknak megfelelõ függvényekkel, másrészt a korlátozottabb
tudású POSIX szabályos kifejezés formát. Mindkettõvel meg fogunk ismerkedni.

Az óra során a következõkrõl tanulunk:

• Hogyan illesszünk mintát egy karakterláncra a szabályos kifejezések


segítségével?

• Mik a szabályos kifejezések formai követelményei?


18_ora.qxd 8/3/2001 6:22 PM Page 340

340 18. óra

• Hogyan cseréljünk le karakterláncokat szabályos kifejezésekkel?

• Hogyan keressünk és cseréljünk le mintákat egy szövegben a hatékony Perl


típusú szabályos kifejezésekkel?

A POSIX szabályos kifejezések függvényei


A POSIX szabályos kifejezéseket kezelõ függvények lehetõvé teszik, hogy egy szö-
vegben bonyolult mintákat keressünk és cseréljünk le. Ezeket általában egyszerû-
en szabályoskifejezés-függvényeknek szokták nevezni, mi azonban POSIX szabá-
lyoskifejezés-függvényekként utalunk rájuk, egyrészt azért, hogy
megkülönböztethessük õket a hasonló, ám hatékonyabb Perl típusú szabályos
kifejezésektõl, másrészt azért, mert a POSIX bõvített szabályos kifejezés (extended
regular expression) szabványát követik.

A szabályos kifejezések olyan jelegyüttesek, amelyek egy szövegben egy mintára


illeszkednek. Használatuk elsajátítása így jóval többet jelent annál, hogy megta-
nuljuk a PHP szabályoskifejezés-függvényeinek be- és kimeneti paramétereit.
Az ismerkedést a függvényekkel kezdjük és rajtuk keresztül vezetjük be az olvasót
a szabályos kifejezések formai követelményeibe.

Minta keresése karakterláncokban


az ereg() függvénnyel
Az ereg() bemenete egy mintát jelképezõ karakterlánc, egy karakterlánc, amiben
keresünk, és egy tömbváltozó, amelyben a keresés eredményét tároljuk. A függvény
egy egész számot ad vissza, amely a megtalált minta illeszkedõ karaktereinek számát
adja meg, illetve ha a függvény nem találja meg a mintát, a false (hamis) értéket
adja vissza. Keressük a "tt"-t az "ütõdött tánctanár" karakterláncban.

print ereg("tt", "ütõdött tánctanár", $tomb);


print "<br>$tomb[0]<br>";
// a kimenet:
// 2
// tt

A "tt" az "ütõdött" szóban megtalálható, ezért az ereg() 2-t ad vissza, ez


az illeszkedõ betûk száma. A $tomb változó elsõ elemében a megtalált karakter-
lánc lesz, amit aztán a böngészõben megjelenítünk. Felmerülhet a kérdés, milyen
esetben lehet ez hasznos, hiszen elõre tudjuk, hogy mi a keresett minta. Nem kell
azonban mindig elõre meghatározott karaktereket keresnünk. A pontot (.) hasz-
nálhatjuk tetszõleges karakter keresésekor:
18_ora.qxd 8/3/2001 6:22 PM Page 341

A szabályos kifejezések használata 341

print ereg("d.", "ütõdött tánctanár", $tomb);


print "<br>$tomb[0]<br>";
// a kimenet:
// 2
// dö

A d. minta illeszkedik minden olyan szövegre, amely megfelel annak a meghatá-


rozásnak, hogy „egy d betû és egy azt követõ tetszõleges karakter”. Ebben az eset-
ben nem tudjuk elõre, mi lesz a második karakter, így a $tomb[0] értéke máris
18
értelmet nyer.

Egynél többször elõforduló karakter keresése


mennyiségjelzõvel
Amikor egy karakterláncban egy karaktert keresünk, egy mennyiségjelzõvel
(kvantorral) határozhatjuk meg, hányszor forduljon elõ a karakter a mintában.
Az a+ minta például azt jelenti, hogy az "a"-nak legalább egyszer elõ kell fordul-
nia, amit 0 vagy több "a" betû követ. Próbáljuk ki:

if ( ereg("a+","aaaa", $tomb) )
print $tomb[0];
// azt írja ki, hogy "aaaa";

Vegyük észre, hogy ez a szabályos kifejezés annyi karakterre illeszkedik, amennyire


csak tud. A 18.1. táblázat az ismétlõdõ karakterek keresésére szolgáló mennyiségjel-
zõket ismerteti.

18.1. táblázat Az ismétlõdõ karakterek mennyiségjelzõi


Jel Leírás Példa Erre Erre nem
illeszkedik illeszkedik
* Nulla vagy több elõfordulás a* xxxx (Mindenre
illeszkedik)
+ Egy vagy több elõfordulás a+ xaax xxxx
? Nulla vagy egy elõfordulás a? xaxx xaax
{n} n elõfordulás a{3} xaaa aaaa
{n,} Legalább n elõfordulás a{3,} aaaa aaxx
{,n} Legfeljebb n elõfordulás a{,2} xaax aaax
{n1,n2} Legalább n1 és legfeljebb a{1,2} xaax xaaa
n2 elõfordulás
18_ora.qxd 8/3/2001 6:22 PM Page 342

342 18. óra

A kapcsos zárójelben levõ számok neve korlát. Segítségükkel határozhatjuk meg,


hányszor ismétlõdjön egy adott karakter, hogy a minta érvényes legyen rá.

A korlát határozza meg, hogy egy karakternek vagy karakterláncnak


ÚJDONSÁG
hányszor kell ismétlõdnie egy szabályos kifejezésben. Az alsó és felsõ
határt a kapcsos zárójelen belül határozzuk meg. Például az
a{4,5}
kifejezés az a négynél nem kevesebb és ötnél nem több elõfordulására
illeszkedik.

Vegyünk egy példát. Egy klub tagsági azonosítóval jelöli tagjait. Egy érvényes azo-
nosítóban egy és négy közötti alkalommal fordul elõ a "t", ezt tetszõleges számú
szám vagy betû karakter követi, majd a 99-es szám zárja. A klub arra kért fel
bennünket, hogy a tennivalókat tartalmazó naplóból emeljük ki a tagazonosítókat.

$proba = "A ttXGDH99 tagunk befizette már a tagsági


díjat?";
if ( ereg( "t{1,4}.*99 ", $proba, $tomb ) )
print "A megtalált azonosító: $tomb[0]";
// azt írja ki, hogy "A megtalált azonosító: ttXGDH99"

Az elõzõ kódrészletben a tagazonosító két t karakterrel kezdõdik, ezt négy


nagybetû követi, majd végül a 99 jön. A t{1,4} minta illeszkedik a két t-re,
a négy nagybetût pedig megtalálja a .*, amellyel tetszõleges számú, tetszõleges
típusú karakterláncot kereshetünk.

Úgy tûnik, ezzel megoldottuk a feladatot, pedig még attól meglehetõsen távol
állunk. A feltételek között a 99-cel való végzõdést azzal próbáltuk biztosítani,
hogy megadtuk, hogy egy szóköz legyen az utolsó karakter. Ezt aztán találat
esetén vissza is kaptuk. Még ennél is nagyobb baj, hogy ha a forráslánc

"Azonosítóm ttXGDH99 megkaptad már az 1999 -es tagsági díjat?"

akkor a fenti szabályos kifejezés a következõ karakterláncot találná meg:

"tóm ttXGDH99 megkaptad már az 1999"

Mit rontottunk el? A szabályos kifejezés megtalálta a t betût az azonosítóm


szóban, majd utána a tetszõleges számú karaktert egészen a szóközzel zárt 99-ig.
Jellemzõ a szabályos kifejezések „mohóságára”, hogy annyi karakterre illeszked-
nek, amennyire csak tudnak. Emiatt történt, hogy a minta egészen az 1999-ig
illeszkedett, a 99-re végzõdõ azonosító helyett. A hibát kijavíthatjuk, ha biztosan
tudjuk, hogy a t és a 99 közötti karakterek kizárólag betûk vagy számok és
egyikük sem szóköz. Az ilyen feladatokat egyszerûsítik le a karakterosztályok.
18_ora.qxd 8/3/2001 6:22 PM Page 343

A szabályos kifejezések használata 343

Karakterlánc keresése karakterosztályokkal


Az eddigi esetekben megadott karakterekkel vagy a . segítségével kerestünk
karaktereket. A karakterosztályok lehetõvé teszik, hogy karakterek meghatározott
csoportját keressük. A karakterosztály meghatározásához a keresendõ karaktere-
ket szögletes zárójelek közé írjuk. Az [ab] minta egyetlen betûre illeszkedik, ami
vagy a vagy b. A karakterosztályokat meghatározásuk után karakterként kezelhet-
jük, így az [ab]+ az aaa, bbb és ababab karakterláncokra egyaránt illeszkedik.
18
Karaktertartományokat is használhatunk karakterosztályok megadására: az [a-z]
tetszõleges kisbetûre, az [A-Z] tetszõleges nagybetûre, a [0-9] pedig tetszõ-
leges számjegyre illeszkedik. Ezeket a sorozatokat és az egyedi karaktereket
egyetlen karakterosztályba is gyúrhatjuk, így az [a-z5] minta tetszõleges kisbe-
tûre vagy az 5-ös számra illeszkedik.

A karakterosztályokat „tagadhatjuk” is, a csúcsos ékezet (^) kezdõ szögletes zárójel


után való írásával: az [^A-Z] mindenre illeszkedik, csak a nagybetûkre nem.

Térjünk vissza legutóbbi példánkra. Mintát kell illesztenünk egy 1 és 4 közötti


alkalommal elõforduló betûre, amelyet tetszõleges számú betû vagy számjegy
karakter követ, amit a 99 zár.

$proba = "Azonosítóm ttXGDH99 megkaptad már az 1999 -es


tagsági díjat?";
if ( ereg( "t{1,4}[a-zA-Z0-9]*99 ", $proba, $tomb ) )
print "A megtalált azonosító: $tomb[0]";
// azt írja ki, hogy "A megtalált azonosító: ttXGDH99 "

Szép lassan alakul. Az a karakterosztály, amit hozzáadtunk, már nem fog szóköz-
ökre illeszkedni, így végre az azonosítót kapjuk meg. Viszont ha az azonosító után
a próba-karakterlánc végére vesszõt írunk, a szabályos kifejezés megint nem il-
leszkedik:

$proba = "Azonosítóm ttXGDH99, megkaptad már az 1999 -es


tagsági díjat?";
if ( ereg( "t{1,4}[a-zA-Z0-9]*99 ", $proba, $tomb ) )
print "A megtalált azonosító: $tomb[0]";
// a szabályos kifejezés nem illeszkedik

Ez azért van, mert a minta végén egy szóközt várunk el, amely alapján meggyõ-
zõdhetünk, hogy elértük az azonosító végét. Így ha egy szövegben az azonosító
zárójelek közt van, kötõjel vagy vesszõ követi, a minta nem illeszkedik rá. Köze-
lebb visz a megoldáshoz, ha úgy javítunk a szabályos kifejezésen, hogy mindenre
illeszkedjék, csak szám és betû karakterekre nem:
18_ora.qxd 8/3/2001 6:22 PM Page 344

344 18. óra

$proba = "Azonosítóm ttXGDH99, megkaptad már az 1999 -es


tagsági díjat?";
if ( ereg( "t{1,4}[a-zA-Z0-9]*99[^a-zA-Z0-9]", $proba,
$tomb ) )
print "A megtalált azonosító: $tomb[0]";
// azt írja ki, hogy "A megtalált azonosító: ttXGDH99, "

Már majdnem kész is vagyunk, de még mindig van két probléma. Egyrészt
a vesszõt is visszakapjuk, másrészt a szabályos kifejezés nem illeszkedik, ha
az azonosító a karakterlánc legvégén van, hiszen megköveteltük, hogy utána
még egy karakter legyen. Más szóval a szóhatárt kellene megbízható módon
megtalálnunk. Erre a problémára késõbb még visszatérünk.

Az atomok kezelése
Az atom egy zárójelek közé írt minta (gyakran hivatkoznak rá részmin-
ÚJDONSÁG
taként is). Meghatározása után az atomot ugyanúgy kezelhetjük, mintha
maga is egy karakter vagy karakterosztály lenne. Más szóval ugyanazt a 18.1. táblá-
zatban bemutatott rendszer alapján felépített mintát annyiszor kereshetjük, ahány-
szor csak akarjuk.

A következõ kódrészletben meghatározunk egy mintát, zárójelezzük, és


az így kapott atomnak kétszer kell illeszkednie a keresendõ szövegre:

$proba = "abbaxaabaxabbax";
if ( ereg( "([ab]+x){2}", $proba, $tomb ) )
print "$tomb[0]";
// azt írja ki, hogy "abbaxaabax"

Az [ab]+x illeszkedik az "abbax" és az "aabax" karakterláncokra egyaránt,


így az ([ab]+x){2} illeszkedni fog az "abbaxaabax" karakterláncra.

Az ereg() függvénynek átadott tömbváltozó elsõ elemében kapjuk vissza


a teljes, megtalált, illeszkedõ karakterláncot. Az ezt követõ elemek az egyes
megtalált atomokat tartalmazzák. Ez azt jelenti, hogy a teljes találat mellett
a megtalált minta egyes részeihez is hozzáférhetünk.

A következõ kódrészletben egy IP címre illesztünk mintát, és nem csupán a teljes


címet tároljuk, hanem egyes alkotóelemeit is:
18_ora.qxd 8/3/2001 6:22 PM Page 345

A szabályos kifejezések használata 345

$ipcim = "158.152.55.35";
if ( ereg( "([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)", $ipcim,
$tomb ) )
{
foreach ( $tomb as $ertek )
print "$ertek<BR>";
}
// Az eredmény:
// 158.152.55.35
18
// 158
// 152
// 55
// 35

Vegyük észre, hogy a pontokat a szabályos kifejezésben fordított perjel elõzte


meg. Ezzel fejeztük ki, hogy a . karaktert itt minden különleges tulajdonsága
nélkül, egyszerû karakterként szeretnénk kezelni. Minden olyan karakternél ez
a követendõ eljárás, amely egyedi szereppel bír a szabályos kifejezésekben.

Elágazások
A szûrõkarakter (|) segítségével mintákat összekötve a szabályos kifejezéseken
belül elágazásokat hozhatunk létre. Egy kétágú szabályos kifejezés vagy az elsõ
mintára, vagy a második mintára illeszkedõ karakterláncokat keresi meg. Ettõl lesz
a szabályos kifejezések nyelvtana még rugalmasabb. A következõ kódrészletben
a .com, a .de vagy a .hu karakterláncot keressük:

$domain = "www.egydomain.hu";
if ( ereg( "\.com|\.de|\.hu", $domain, $tomb ) )
print "ez egy $tomb[0] tartomány<BR>";
// azt írja ki, hogy "ez egy .hu tartomány"

A szabályos kifejezés helye


Nemcsak a keresendõ mintát adhatjuk meg, hanem azt is, hol illeszkedjen egy ka-
rakterláncban. Ha a mintát a karakterlánc kezdetére szeretnénk illeszteni, a szabá-
lyos kifejezés elejére írjunk egy csúcsos ékezetet (^). A ^a illeszkedik az "alma",
de nem illeszkedik a "banán" szóra.

A karakterlánc végén úgy illeszthetjük a mintát, hogy dollárjelet ($) írunk a szabályos
kifejezés végére. Az a$ illeszkedik a "róka", de nem illeszkedik a "hal" szóra.
18_ora.qxd 8/3/2001 6:22 PM Page 346

346 18. óra

A tagazonosítót keresõ példa újragondolása


Most már rendelkezésünkre állnak azok az eszközök, melyekkel megoldhatjuk
a tagazonosítás problémáját. Emlékeztetõül, a feladat az volt, hogy szövegeket
elmezve kigyûjtsük azokat a tagazonosítókat, amelyekben a "t" egy és négy
közötti alkalommal fordul elõ, ezt tetszõleges számú szám vagy betû karakter
követi, amelyet a 99 zár. Jelenlegi problémánk az, hogyan határozzuk meg, hogy
illeszkedõ mintánknak szóhatárra kell esnie. Nem használhatjuk a szóközt, mivel
a szavakat írásjelekkel is el lehet választani. Az sem lehet feltétel, hogy egy nem
alfanumerikus karakter alkossa a határt, hiszen a tagazonosító lehet, hogy éppen
a szöveg elején vagy végén található.

Most, hogy képesek vagyunk elágazásokat megadni és helyhez kötni a szabályos


kifejezéseket, megadhatjuk feltételként, hogy a tagazonosítót vagy egy nem szám
vagy betû karakter kövesse, vagy pedig a karakterlánc vége. Ugyanezzel a gondo-
latmenettel adhatjuk meg a kód elején elõforduló szóhatárt is. A zárójelek haszná-
latával a tagazonosítót minden központozás és szóköz nélkül kaphatjuk vissza:

$proba = "Azonosítóm ttXGDH99, megkaptad már az 1999 -es


tagsági díjat?";
if ( ereg( "(^|[^a-zA-Z0-9])(t{1,4}[a-zA-Z0-9]*99)([^a-zA-
Z0-9]|$)", $proba, $tomb ) )
print "A megtalált azonosító: $tomb[2]";
// azt írja ki, hogy "A megtalált azonosító: ttXGDH99"

Amint láthatjuk, a szabályos kifejezések elsõre egy kicsit riasztók, de miután kisebb
egységekre bontjuk azokat, általában egész könnyen értelmezhetõk. Elértük, hogy
mintánk egy szóhatárra illeszkedjen (pontosan úgy, ahogy azt a feladat megköve-
telte). Mivel nem vagyunk kíváncsiak semmilyen, a mintát megelõzõ vagy követõ
szövegre, a minta számunkra hasznos részét zárójelek közé írjuk. Az eredményt
a $tomb tömb harmadik (2-es indexû) elemében találhatjuk meg.

Az ereg() megkülönbözteti a kis- és nagybetûket. Ha nem


szeretnénk megkülönböztetni õket, használjuk az eregi() függ-
vényt, amely egyébként minden más tekintetben megegyezik
az ereg() függvénnyel.
18_ora.qxd 8/3/2001 6:22 PM Page 347

A szabályos kifejezések használata 347

Minták lecserélése karakterláncokban


az ereg_replace() függvénnyel
Eddig csupán mintákat kerestünk a karakterláncokban, magát a karakterláncot
nem módosítottuk. Az ereg_replace() függvény lehetõvé teszi, hogy megke-
ressük és lecseréljük az adott szöveg egy mintára illeszkedõ részláncát. Bemenete
három karakterlánc: egy szabályos kifejezés, a csereszöveg, amivel felül szeret-
nénk írni a megtalált mintát és a forrásszöveg, amelyben keresünk. Találat esetén
a függvény a megváltoztatott karakterláncot adja vissza, ellenkezõ esetben az ere-
18
deti forrásszöveget kapjuk. A következõ kódrészletben egy klubtisztviselõ nevét
keressük ki, majd felülírjuk utódjának nevével:

$proba = "Titkárunk, Vilmos Sarolta, szeretettel


üdvözli önt.";
print ereg_replace ("Vilmos Sarolta", "László István",
$proba);
// azt írja ki, hogy " Titkárunk, László István,
szeretettel üdvözli önt."

Fontos megjegyezni, hogy míg az ereg() függvény csak a legelsõ megtalált min-
tára illeszkedik, az ereg_replace() a minta összes elõfordulását megtalálja és
lecseréli.

Visszautalás használata az ereg_replace() függvénnyel


A visszautalások azt teszik lehetõvé, hogy az illeszkedõ kifejezés egy részét
felhasználhassuk a felülíró karakterláncban. Ehhez szabályos kifejezésünk összes
felhasználandó elemét zárójelbe kell írnunk. Ezekre a részminták segítségével
megtalált karakterláncokra két fordított perjellel és az atom számával hivatkozha-
tunk (például \\1) a csereláncokban. Az atomok sorszámozottak, a sorszámozás
kívülrõl befelé, balról jobbra halad és \\1-tõl indul. A \\0 az egész illeszkedõ
karakterláncot jelenti.

A következõ kódrészlet a hh/nn/éééé formátumú dátumokat alakítja


éééé.hh.nn. formátumúvá:

$datumt = "12/25/2000";
print ereg_replace("([0-9]+)/([0-9]+)/([0-9]+)",
"\\3.\\1.\\2.", $datum);
// azt írja ki, hogy "2000.12.25"

Vegyük észre, hogy a fenti kód csereszövegében a pontok nem különleges értel-
mûek, így nem is kell \ jelet tenni eléjük. A . az elsõ paraméterben kapja a tetszõ-
leges karakterre illeszkedés különleges jelentését.
18_ora.qxd 8/3/2001 6:22 PM Page 348

348 18. óra

Az ereg_replace() függvény megkülönbözteti a kis- és nagybetû-


ket. Ha nem szeretnénk megkülönböztetni ezeket, használjuk
az eregi_replace() függvényt, amely minden más tekintetben
megegyezik az ereg_replace() függvénnyel.

Karakterláncok felbontása a split() függvénnyel


Az elõzõ órában már láttuk, hogy az explode() függvény segítségével
egy karakterláncot elemeire bontva tömbként kezelhetünk. Az említett függvény
hatékonyságát az csökkenti, hogy határolójelként csak egy karakterhalmazt
használhatunk. A PHP 4 split() függvénye a szabályos kifejezések hatékony-
ságát biztosítja, vele rugalmas határolójelet adhatunk meg. A függvény bemenete
a határolójelként használt minta és a forráslánc, amelyben a határolókat keressük,
kimenete pedig egy tömb. A függvény harmadik, nem kötelezõ paramétere
a visszaadandó elemek legnagyobb számát határozza meg.

A következõ példában egy elágazó szabályos kifejezéssel egy karakterláncot


bontunk fel, úgy, hogy a határolójel egy vesszõ és egy szóköz vagy egy szókö-
zökkel közrefogott és szó:

$szoveg = "almák, narancsok, körték és barackok";


$gyumolcsok = split(", | és ", $szoveg);
foreach ( $gyumolcsok as $gyumolcs )
print "$gyumolcs<BR>";
// a kimenet:
// almák
// narancsok
// körték
// barackok

Perl típusú szabályos kifejezések


Ha Perlös háttérrel közelítjük meg a PHP-t, akkor a POSIX szabályos kifejezések
függvényeit valamelyest nehézkesnek találhatjuk. A jó hír viszont az, hogy
a PHP 4 támogatja a Perlnek megfelelõ szabályos kifejezéseket is. Ezek formája
még az eddig tanultaknál is hatékonyabb. Ebben a részben a két szabályoskife-
jezés-forma közötti különbségekkel ismerkedünk meg.
18_ora.qxd 8/3/2001 6:22 PM Page 349

A szabályos kifejezések használata 349

Minták keresése a preg_match() függvénnyel


A preg_match() függvény három paramétert vár: egy szabályos kifejezést,
a forrásláncot és egy tömbváltozót, amelyben az illeszkedõ karakterláncokat adja
vissza. A true (igaz) értéket kapjuk vissza, ha illeszkedõ kifejezést talál és
false (hamis) értéket, ha nem. A preg_match() és az ereg_match() függ-
vények közötti különbség a szabályos kifejezést tartalmazó paraméterben van.
A Perl típusú szabályos kifejezéseket határolójelek közé kell helyezni. Általában
perjeleket használunk határolójelként, bár más, nem szám vagy betû karaktert is
18
használhatunk (kivétel persze a fordított perjel). A következõ példában
a preg_match() függvénnyel egy h-valami-z mintájú karakterláncot keresünk:

$szoveg = "üvegház";
if ( preg_match( "/h.*z/", $szoveg, $tomb ) )
print $tomb[0];
// azt írja ki, hogy "ház"

A Perl típusú szabályos kifejezések és a mohóság


Alapértelmezés szerint a szabályos kifejezések megkísérelnek a lehetõ legtöbb
karakterre illeszkedni. Így a

"/h.*z/"

minta a h-val kezdõdõ és z karakterre végzõdõ lehetõ legtöbb karaktert közrefogó


karakterláncra fog illeszkedni, a következõ példában a teljes szövegre:

$szoveg = "ház húz hülyéz hazardíroz";


if ( preg_match( "/h.*z/", $szoveg, $tomb ) )
print $tomb[0];
// azt írja ki, hogy "ház húz hülyéz hazardíroz"

Viszont ha kérdõjelet (?) írunk a mennyiséget kifejezõ jel után, rávehetjük


a Perl típusú szabályos kifejezést, hogy egy kicsit mértékletesebb legyen. Így míg a

"h.*z"

minta azt jelenti, hogy „h és z között a lehetõ legtöbb karakter”, a

"h.*?z"

minta jelentése a „h és z közötti lehetõ legkevesebb karakter”.


18_ora.qxd 8/3/2001 6:22 PM Page 350

350 18. óra

A következõ kódrészlet ezzel a módszerrel keresi meg a legrövidebb szót, amely


h-val kezdõdik és z-vel végzõdik:

$szoveg = "ház húz hülyéz hazardíroz";


if ( preg_match( "/h.*?z/", $szoveg, $tomb ) )
print $tomb[0];
// azt írja ki, hogy "ház"

A Perl típusú szabályos kifejezések és


a fordított perjeles karakterek
A Perl típusú szabályos kifejezésekben is vezérlõkarakterré változtathatunk bizonyos
karaktereket, ugyanúgy, mint ahogy azt karakterláncokkal tettük. A \t például
a tabulátor karaktert jelenti, az \n pedig a soremelést. Az ilyen típusú szabályos
kifejezések olyan karaktereket is leírhatnak, amelyek teljes karakterhalmazokra,
karaktertípusokra illeszkednek. A fordított perjeles karakterek listáját a 18.2. táblá-
zatban láthatjuk.

18.2. táblázat Karaktertípusokra illeszkedõ beépített karakterosztályok


Karakter Illeszkedik
\d Bármely számra
\D Mindenre, ami nem szám
\s Bármely elválasztó karakterre
\S Mindenre, ami nem elválasztó karakter
\w Bármely szóalkotó karakterre (aláhúzást is beleértve)
\W Mindenre, ami nem szóalkotó karakter

Ezek a karakterosztályok nagymértékben leegyszerûsíthetik a szabályos kifejezé-


seket. Nélkülük karaktersorozatok keresésekor saját karakterosztályokat kellene
használnunk. Vessük össze a szóalkotó karakterekre illeszkedõ mintát
az ereg() és a preg_match() függvényben:

ereg( "h[a-zA-Z0-9_]+z", $szoveg, $tomb );


preg_match( "/h\w+z", $szoveg, $tomb );

A Perl típusú szabályos kifejezések több váltókaraktert is támogatnak, melyek hivat-


kozási pontként mûködnek. A hivatkozási pontok a karakterláncon belül helyekre
illeszkednek, nem pedig karakterekre. Ismertetésüket a 18.3. táblázatban találhatjuk.
18_ora.qxd 8/3/2001 6:22 PM Page 351

A szabályos kifejezések használata 351

18.3. táblázat Hivatkozási pontként használt váltókarakterek


Karakter Illeszkedik
\A Karakterlánc kezdetére
\b Szóhatárra
\B Mindenre, ami nem szóhatár
\Z Karakterlánc végére (az utolsó soremelés vagy
a karakterlánc vége elõtt illeszkedik) 18
\z Karakterlánc végére (a karakterlánc legvégére
illeszkedik)

Emlékszünk még, milyen problémáink voltak a szóhatárra való illesztéssel a tagsági


azonosítást megvalósító példában? A Perl típusú szabályos kifejezések jelentõsen
leegyszerûsítik ezt a feladatot. Vessük össze, hogyan illeszt mintát szóalkotó karak-
terre és szóhatárra az ereg() és a preg_match():

ereg ( "(^|[^a-zA-Z0-9_])(y{1,4}[a-zA-Z0-9_]*99)
å ([^a-zA-Z0-9_]|$)", $szoveg, $tomb );
preg_match( "\bt{1,4}\w*99\b", $szoveg, $tomb );

Az elõzõ példában a preg_match() függvény meghívásakor a szóhatáron levõ


legalább egy, de legfeljebb négy t karakterre illeszkedik, amelyet bármennyi
szövegalkotó karakter követhet és amit a szóhatáron levõ 99 karaktersor zár.
A szóhatárt jelölõ váltókarakter igazából nem is egy karakterre illeszkedik, csupán
megerõsíti, hogy az illeszkedéshez szóhatár kell. Az ereg_match() meghívásá-
hoz elõször létre kell hoznunk egy nem szóalkotó karakterekbõl álló mintát, majd
vagy arra, vagy pedig szóhatárra kell illeszteni.

A váltókaraktereket arra is használhatjuk, hogy megszabaduljunk a karakterek


jelentésétõl. Ahhoz például, hogy egy . karakterre illeszthessünk, egy fordított
perjelet kell elé írnunk.

Teljeskörû keresés a preg_match_all() függvénnyel


A POSIX szabályos kifejezésekkel az az egyik probléma, hogy a minta karakterlán-
con belüli összes elõfordulását bonyolult megkeresni. Így ha az ereg() függ-
vénnyel keressük a b-vel kezdõdõ, t-vel végzõdõ szavakat, csak a legelsõ találatot
kapjuk vissza. Próbáljuk meg magunk is:
18_ora.qxd 8/3/2001 6:22 PM Page 352

352 18. óra

$szoveg = "barackot, banánt, bort, búzát és


békákat árulok";
if ( ereg( "(^|[^a-zA-Z0-9_])(b[a-zA-Z0-9_]+t)
å ([^a-zA-Z0-9_]|$)", $szoveg, $tomb ) )
{
for ( $x=0; $x< count( $tomb ); $x++ )
print "\$tomb[$x]: $tomb[$x]<br>\n";
}
// kimenete:
// $tomb[0]: barackot,
// $tomb[1]:
// $tomb[2]: barackot
// $tomb[3]: ,

Ahogy azt vártuk, a $tomb harmadik elemében találjuk az elsõ találatot,


a "barackot". A tömb elsõ eleme tartalmazza a teljes találatot, a második
a szóközt, a negyedik a vesszõt. Hogy megkapjuk az összes illeszkedõ kifejezést
a szövegben, az ereg_replace() függvényt kellene használnunk, ciklikusan,
hogy eltávolítsuk a találatokat a szövegbõl, mielõtt újra illesztenénk a mintát.

Fel kell, hogy hívjuk a kedves olvasó figyelmét arra, hogy a magyar szövegekre
az ékezetes betûk miatt alapbeállításban nem alkalmazható a fentihez hasonló
egyszerû szabályos kifejezés. A nemzeti beállítások testreszabására használható
setlocale() függvényt kell alkalmaznunk, hogy a kívánt eredményt elérjük.

A preg_match_all() függvényt használhatjuk arra, hogy egyetlen hívásból


a minta összes elõfordulását megkapjuk. A preg_match_all() bemenete
egy szabályos kifejezés, a forráslánc és egy tömbváltozó. Találat esetén true (igaz)
értéket ad vissza. A tömbváltozó egy többdimenziós tömb lesz, melynek elsõ eleme
a szabályos kifejezésben megadott mintára illeszkedõ összes találatot tartalmazza.

A 18.1. programban a preg_match_all() függvénnyel illesztettük mintánkat


egy szövegre. Két for ciklust használunk, hogy megjelenítsük a többdimenziós
eredménytömböt.

18.1. program Minta teljeskörû illesztése a preg_match_all() függvénnyel


1: <html>
2: <head>
3: <title>18.1. program Minta teljeskörû illesztése
a preg_match_all() függvénnyel</title>
4: </head>
5: <body>
18_ora.qxd 8/3/2001 6:22 PM Page 353

A szabályos kifejezések használata 353

18.1. program (folytatás)

6: <?php
7: $szoveg = "barackot, banánt, bort, búzát és
békákat árulok";
8: if ( preg_match_all( "/\bb\w+t\b/", $szoveg, $tomb ) )
9:
10:
{
for ( $x=0; $x< count( $tomb ); $x++ )
18
11: {
12: for ( $y=0; $y< count( $tomb[$x] ); $y++ )
13: print "\$tomb[$x][$y]:
".$tomb[$x][$y]."<br>\n";
14: }
15: }
16: // A kimenet:
17: // $tomb[0][0]: barackot
18: // $tomb[0][1]: banánt
19: // $tomb[0][2]: bort
20: // $tomb[0][3]: búzát
21: // $tomb[0][4]: békákat
22: ?>
23: </body>
24: </html>
A $tomb változónak a preg_match_all() függvénynek történõ átadáskor
csak az elsõ eleme létezik és ez karakterláncok egy tömbjébõl áll. Ez a tömb tartal-
mazza a szöveg minden olyan szavát, amely b-vel kezdõdik és t betûre végzõdik.

A preg_match_all() ebbõl a tömbbõl azért készít egy többdimenziósat, hogy


az atomok találatait is tárolhassa. A preg_match_all() függvénynek átadott
tömb elsõ eleme tartalmazza a teljes szabályos kifejezés minden egyes találatát.
Minden további elem a szabályos kifejezés egyes atomjainak (zárójeles részmintá-
inak) értékeit tartalmazza az egyes találatokban. Így a preg_match_all()
alábbi meghívásával

$szoveg = "01-05-99, 01-10-99, 01-03-00";


preg_match_all( "/(\d+)-(\d+)-(\d+)/", $szoveg, $tomb );
a $tomb[0] az összes találat tömbje:
$tomb[0][0]: 01-05-99
$tomb[0][1]: 01-10-99
$tomb[0][2]: 01-03-00
A $tomb[1] az elsõ részminta értékeinek tömbje:
$tomb[1][0]: 01
18_ora.qxd 8/3/2001 6:22 PM Page 354

354 18. óra

$tomb[1][1]: 01
$tomb[1][2]: 01
A $tomb[2] a második részminta értékeinek tömbjét tárolja:
$tomb[2][0]: 05
$tomb[2][1]: 10
$tomb[2][2]: 03

és így tovább.

Minták lecserélése a preg_replace() függvénnyel


A preg_replace() használata megegyezik az ereg_replace() használatával,
azzal a különbséggel, hogy hozzáférünk a Perl típusú szabályos kifejezések által
kínált kényelmi lehetõségekhez. A preg_replace() bemenete egy szabályos
kifejezés, egy csere-karakterlánc és egy forráslánc. Találat esetén a módosított karak-
terláncot, ellenkezõ esetben magát a forrásláncot kapjuk vissza változtatás nélkül.
A következõ kódrészlet a nn/hh/éé formátumú dátumokat alakítja át éé/hh/nn
formátumúvá:

$szoveg = "25/12/99, 14/5/00";


$szoveg = preg_replace( "|\b(\d+)/(\d+)/(\d+)\b|",
å "\\3/\\2/\\1", $szoveg );
print "$szoveg<br>";
// azt írja ki, hogy "99/12/25, 00/5/14"

Vegyük észre, hogy a szûrõkaraktert (|) használtuk határolójelként. Ezzel megta-


karítottuk a perjelek kikerülésére használandó váltókaraktereket az illesztendõ
mintában. A preg_replace() ugyanúgy támogatja a visszautalásokat a csere-
szövegben, mint az ereg_replace().

A preg_replace() függvénynek a forráslánc helyett karakterláncok egy tömbjét


is átadhatjuk, az ebben az esetben minden tömbelemet egyesével átalakít. Ilyenkor
a visszaadott érték az átalakított karakterláncok tömbje lesz.

Emellett a preg_replace() függvénynek szabályos kifejezések és csere-karak-


terláncok tömbjét is átadhatjuk. A szabályos kifejezéseket egyenként illeszti
a forrásláncra és a megfelelõ csereszöveggel helyettesíti. A következõ példában
az elõzõ példa formátumait alakítjuk át, de emellett a forráslánc szerzõi jogi
(copyright) információját is módosítjuk:

$szoveg = "25/12/99, 14/5/00. Copyright 1999";


$miket = array( "|\b(\d+)/(\d+)/(\d+)\b|",
å "/([Cc]opyright) 1999/" );
$mikre = array( "\\3/\\2/\\1", "\\1 2000" );
18_ora.qxd 8/3/2001 6:22 PM Page 355

A szabályos kifejezések használata 355

$szoveg = preg_replace( $miket, $mikre, $szoveg );


print "$szoveg<br>";
// azt írja ki, hogy "99/12/25, 00/5/14. Copyright 2000"

Két tömböt hozunk létre. A $miket tömb két szabályos kifejezést, a $mikre tömb
pedig csere-karakterláncokat tartalmaz. A $miket tömb elsõ eleme a $mikre
tömb elsõ elemével helyettesítõdik, a második a másodikkal, és így tovább.

Ha a csere-karakterláncok tömbje kevesebb elemet tartalmaz, mint a szabályos


18
kifejezéseké, a csere-karakterlánc nélkül maradó szabályos kifejezéseket a függ-
vény üres karakterláncra cseréli.

Ha a preg_replace() függvénynek szabályos kifejezések egy tömbjét adjuk át,


de csak egy csereláncot, akkor az a szabályos kifejezések tömbjének összes mintá-
ját ugyanazzal a csereszöveggel helyettesíti.

Módosító paraméterek
A Perl típusú szabályos kifejezések lehetõvé teszik, hogy módosító paraméterek
segítségével pontosítsuk a minta illesztési módját.

A módosító paraméter olyan betû, amelyet a Perl típusú szabályos kife-


ÚJDONSÁG
jezések utolsó határolójele után írunk, és amely tovább finomítja szabá-
lyos kifejezéseink jelentését.

A Perl típusú szabályos kifejezések módosító paramétereit a 18.4. táblázatban


találhatjuk.

18.4. táblázat A Perl típusú szabályos kifejezések módosító paraméterei


Minta Leírás
i Nem különbözteti meg a kis- és nagybetûket.
e A preg_replace() csereláncát PHP-kódként kezeli.
m A $ és a ^ az aktuális sor elejére és végére illeszkedik.
s A soremelésre is illeszkedik (a soremelések általában nem
illeszkednek a .-ra).
x A karakterosztályokon kívüli elválasztó karakterekre az olvasha-
tóság érdekében nem illeszkedik. Ha elválasztó karakterekre
szeretnénk mintát illeszteni, használjuk a \s, \t, vagy a \
(fordított perjel–szóköz) mintákat.
18_ora.qxd 8/3/2001 6:22 PM Page 356

356 18. óra

18.4. táblázat. (folytatás)


Minta Leírás
A Csak a karakterlánc elején illeszkedik (ilyen megszorítás
nincs a Perlben).
E Csak a karakterlánc végén illeszkedik (ilyen megszorítás
nincs a Perlben).
U Kikapcsolja a szabályos kifejezések „mohóságát”, azaz a lehetõ
legkevesebb karaktert tartalmazó találatokat adja vissza
(ez a módosító sem található meg Perlben).

Ahol ezek a megszorítások nem mondanak egymásnak ellent, egyszerre többet is


használhatunk belõlük. Az x megszorítást például arra használhatjuk, hogy
könnyebb legyen olvasni a szabályos kifejezéseket, az i megszorítást pedig arra,
hogy mintánk kis- és nagybetûktõl függetlenül illeszkedjék a szövegre.
A / k \S* r /ix kifejezés például illeszkedik a "kar" és "KAR" szavakra, de
a "K A R" szóra már nem. Az x-szel módosított szabályos kifejezések váltóka-
rakter nélküli szóközei nem fognak illeszkedni semmire sem a forrásláncban,
a különbség csupán esztétikai lesz.

Az m paraméter akkor jöhet jól, ha egy szöveg több sorában szeretnénk hivatkozási
pontos mintára illeszteni. A ^ és $ minták alapértelmezés szerint a teljes karakter-
lánc elejét és végét jelzik. A következõ kódrészletben az m paraméterrel módosítjuk
a $^ viselkedését:

$szoveg = "név: péter\nfoglalkozás: programozó\nszeme: kék\n";


preg_match_all( "/^\w+:\s+(.*)$/m", $szoveg, $tomb );
foreach ( $tomb[1] as $ertek )
print "$ertek<br>";
// kimenet:
// péter
// programozó
// kék

Egy olyan szabályos kifejezést hozunk létre, amely olyan mintára illeszkedik,
amelyben bármely szóalkotó karaktert vesszõ és tetszõleges számú szóköz követ.
Ezután tetszõleges számú karaktert követõ „karakterlánc vége” karakterre ($)
illesztünk. Az m paraméter miatt a $ az egyes sorok végére illeszkedik a teljes
karakterlánc vége helyett.
18_ora.qxd 8/3/2001 6:22 PM Page 357

A szabályos kifejezések használata 357

Az s paraméter akkor jön jól, ha a . karakterrel szeretnénk többsoros karakter-


láncban karakterekre illeszteni. A következõ példában megpróbálunk a karakter-
lánc elsõ és utolsó szavára keresni:

$szoveg = "kezdetként indítsunk ezzel a sorral\nés így


å egy következtetéshez\n érkezhetünk el végül\n";
preg_match( "/^(\w+).*?(\w+)$/", $szoveg, $tomb );
print "$tomb[1] $tomb[2]<br>";
18
Ez a kód semmit nem ír ki. Bár a szabályos kifejezés megtalálja a szóalkotó karak-
tereket a karakterlánc kezdeténél, a . nem illeszkedik a szövegben található
soremelésre. Az s paraméter ezen változtat:

$szoveg = "kezdetként indítsunk ezzel a sorral\nés így


å egy következtetéshez\n érkezhetünk el végül\n";
preg_match( "/^(\w+).*?(\w+)$/s", $szoveg, $tomb );
print "$tomb[1] $tomb[2]<br>";
// azt írja ki, hogy "kezdetként végül"

Az e paraméter különlegesen hasznos lehet számunkra, hiszen lehetõvé teszi,


hogy a preg_replace() függvény csereszövegét PHP kódként kezeljük.
A függvényeknek paraméterként visszautalásokat vagy számokból álló listákat
adhatunk át. A következõ példában az e paraméterrel adunk át illesztett számokat
egy függvénynek, amely ugyanazt a dátumot más formában adja vissza.

<?php
function datumAtalakito( $honap, $nap, $ev )
{
$ev = ($ev < 70 )?$ev+2000:$ev;
$ido = ( mktime( 0,0,0,$honap,$nap,$ev) );
return date("Y. m. j. ", $ido);
}

$datumok = "3/18/99<br>\n7/22/00";
$datumok = preg_replace( "/([0-9]+)\/([0-9]+)\/([0-9]+)/e",
"datumAtalakito(\\1,\\2,\\3)",
$datumok);
print $datumok;

// ezt írja ki:


// 1999. 03. 18.
// 2000. 07. 22.
?>
18_ora.qxd 8/3/2001 6:22 PM Page 358

358 18. óra

Három, perjelekkel elválasztott számhalmazt keresünk és a zárójelek használatával


rögzítjük a megtalált számokat. Mivel az e módosító paramétert használjuk,
a cserelánc paraméterbõl meghívhatjuk az általunk meghatározott
datumAtalakito() függvényt, úgy, hogy a három visszautalást adjuk át neki.
A datumAtalakito() csupán fogja a számbemenetet és egy jobban festõ
dátummá alakítja, amellyel aztán kicseréli az eredetit.

Összefoglalás
A szabályos kifejezések hatalmas témakört alkotnak, mi csak felületesen ismerked-
tünk meg velük ezen óra során. Arra viszont már biztosan képesek leszünk, hogy
bonyolult karakterláncokat találjunk meg és cseréljünk le egy szövegben.

Megismerkedtünk az ereg() szabályoskifejezés-függvénnyel, amellyel karakter-


láncokban mintákat kereshetünk, illetve az ereg_replace()-szel, amellyel
egy minta összes elõfordulását cserélhetjük le. A karakterosztályok használatával
karakterláncokat, a mennyiségjelzõk használatával több mintát, az elágazásokkal
mintákat vagylagosan kereshetünk. Részmintákat is kigyûjthetünk és rájuk vissza-
utalásokkal hivatkozhatunk. A Perl típusú szabályos kifejezésekben váltókarakte-
rekkel hivatkozási pontos illesztést kérhetünk, de karakterosztályok illesztésére is
rendelkezésre állnak váltókarakterek. Ezenkívül a módosító paraméterekkel
képesek vagyunk finomítani a Perl típusú szabályos kifejezések viselkedésén.

Kérdések és válaszok
A Perl típusú szabályos kifejezések nagyon hatékonynak tûnnek.
Hol található róluk bõvebb információ?
A szabályos kifejezésekrõl a PHP weboldalán (http://www.php.net) találha-
tunk némi felvilágosítást. Emellett még a http://www.perl.com oldalain talál-
hatunk információt, a Perl típusú szabályos kifejezésekhez pedig
a http://www.perl.com/pub/doc/manual/html/pod/perlre.htm
címen és Tom Christiansen cikkében,
a http://www.perl.com/pub/doc/manual/html/pod/perlfaq6.html
címen találhatunk bevezetést.
18_ora.qxd 8/3/2001 6:22 PM Page 359

A szabályos kifejezések használata 359

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ényt használnánk egy karakterláncban minta illesztésére,
ha POSIX szabályos kifejezéssel szeretnénk a mintát meghatározni?
18
2. Milyen szabályos kifejezést használnánk, ha a "b" betû legalább egyszeri,
de hatnál nem többszöri elõfordulására szeretnénk keresni?

3. Hogyan határoznánk meg a "d" és az "f" betûk közé esõ karakterek


karakterosztályát?

4. Hogyan tagadnánk a 3. kérdésben meghatározott karaktertartományt?

5. Milyen formában keresnénk tetszõleges számra vagy a "bokor" szóra?

6. Melyik POSIX szabályos kifejezés függvényt használnánk egy megtalált minta


lecserélésére?

7. A .bc* szabályos kifejezés mohón illeszkedik, azaz inkább


az "abc0000000bc" karakterláncra illeszkedik, mint az "abc"-re. A Perl
típusú szabályos kifejezésekkel hogyan alakítanánk át a fenti szabályos kife-
jezést úgy, hogy a megtalált minta legelsõ elõfordulását keresse meg?

8. A Perl típusú szabályos kifejezéseknél melyik fordított perjeles karakterrel


illesztünk elválasztó karakterre?

9. Melyik Perl típusú szabályos kifejezést használnánk, ha az a célunk, hogy


egy minta összes elõfordulását megtaláljuk?

10. Melyik módosító karaktert használnánk egy Perl típusú szabályoskifejezés-


függvényben, ha kis- és nagybetûtõl függetlenül szeretnénk egy mintára
illeszteni?

Feladatok
1. Gyûjtsük ki az e-mail címeket egy fájlból. A címeket tároljuk egy tömbben és
jelenítsük meg az eredményt a böngészõben. Nagy mennyiségû adattal fino-
mítsuk szabályos kifejezéseinket.
18_ora.qxd 8/3/2001 6:22 PM Page 360
19_ora.qxd 8/3/2001 6:22 PM Page 361

19. ÓRA
Á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ódsze-
rei 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õ olda-
lakon 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?


19_ora.qxd 8/3/2001 6:22 PM Page 362

362 19. óra

• Hogyan írjunk sütiket?

• Hogyan tároljuk adatbázisban a weboldalak lekérési statisztikáját sütik segít-


sé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


ÚJDONSÁG
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ó infor-
má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 felhasz-
ná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örnye-
zet 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û infor-
má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özvetle-
nü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
19_ora.qxd 8/3/2001 6:22 PM Page 363

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

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 tarto-
má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él-
dá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
19
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álto-


zó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<BR>"; // azt írja ki, hogy


å "zoldseg=articsoka"
print getenv("HTTP_COOKIE")."<br>"; // azt írja ki, hogy
å "zoldseg=articsoka"
print "$zoldseg<br>"; // azt írja ki, hogy "articsoka"
print "$HTTP_COOKIE_VARS["zoldseg"]<br>"; // 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 kime-
netként jelenik meg a böngészõben.
19_ora.qxd 8/3/2001 6:22 PM Page 364

364 19. óra

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 pon-
tosan 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ül-
dené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, vala-
mint 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ít-


sé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: <?php
2: setcookie( "zoldseg", "articsoka", time()+3600, "/",
3: "kiskapu.hu", 0 );
4: ?>
5: <html>
6: <head>
7: <title>19.1. program Süti értékének beállítása és
kiíratása</title>
8: </head>
9: <body>
10: <?php
11: if ( isset( $zoldseg ) )
12: print "<p>Üdv, az ön által kiválasztott zöldség a(z)
$zoldseg</p>";
13: else
14: print "<p>Üdvözöljük! Ez az ön elsõ látogatása.</p>";
15: ?>
16: </body>
17: </html>
19_ora.qxd 8/3/2001 6:22 PM Page 365

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

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átogat-
ja 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 érten-
dõ, 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 tarto-
má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 szeret-
né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
19
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 para-
mé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 bi-
zonyos böngészõk csak az útvonal megadása esetén képesek a sütik rendeltetés-
szerû 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.
19_ora.qxd 8/3/2001 6:22 PM Page 366

366 19. óra

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átoga-
tó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ít-
já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 megva-


ló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 felso-


rolt mezõkbõl áll.
19_ora.qxd 8/3/2001 6:22 PM Page 367

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

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.
19

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.
19_ora.qxd 8/3/2001 6:22 PM Page 368

368 19. óra

19.2 program A MySQL adatbázist új felhasználó adataival bõvítõ program


1: <?php
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<P>";
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: ?>
19_ora.qxd 8/3/2001 6:22 PM Page 369

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

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áziski-
szolgá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 bejegy-
zé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


19
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 eltekinthe-
tü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 megfe-
lelõ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.


19_ora.qxd 8/3/2001 6:22 PM Page 370

370 19. óra

19.3 program Felhasználókövetõ program sütik és MySQL adatbázis


felhasználásával
1: <?php
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<P>";
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();
19_ora.qxd 8/3/2001 6:22 PM Page 371

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

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:
46:
if ( ! mysql_num_rows( $eredmeny ) )
// süti van ugyan, de azonosító nincs — tehát
19
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: ?>
19_ora.qxd 8/3/2001 6:22 PM Page 372

372 19. óra

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 ol-
dal 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. En-
nek 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 komo-
lyabb megjelenésû, átfogóbb képet kell adnunk a látogatókról, de a lényeg megér-
té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á.
19_ora.qxd 8/3/2001 6:22 PM Page 373

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

19.4 program A 19.3-as program által begyûjtött letöltési statisztikák


megjelenítése
1: <?php
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:
10:
$idotartam = sprintf( "%.2f",
($vendeg_allapot["ossz_ido"]/ 19
/$vendeg_allapot["latogatas_szam"]) );
11: print "<p>Üdvözöljük! Az Ön azonosítója".
$vendeg_allapot["vendeg_azon"]."</p>\n\n";
12: print "<p>Az Ön látogatásainak száma
13: $vendeg_allapot["latogatas_szam"]."</p>\n\n";
14: print "<p>Letöltések átlagos száma
látogatásonként: $letoltesek</p>\n\n";
15: print "<p>Átlagos látogatási idõtartam: $idotartam
másodperc</p>\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 el-
osztva 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 megjele-
nítjük azokat a felhasználónak.
19_ora.qxd 8/3/2001 6:22 PM Page 374

374 19. óra

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ás-
hoz használt böngészõ típusát vagy a látogatók IP címeit is. Hogy mire lehet mind-
ezt 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.

19.1. kép
A használati statisz-
tika megjelenítése

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áto-
gatá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üld-
jük. Az értékek ekkor elérhetõk lesznek a kiszolgáló, illetve az általa futtatott prog-
ramok 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
19_ora.qxd 8/3/2001 6:22 PM Page 375

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

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.
19
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 át-
adni 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 karakter-
lá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:

<?php
$erdeklodes = "sport";
$honlap = "http://www.kiskapu.hu";
$lekerdezes = "honlap=".urlencode( $honlap );
$lekerdezes .= "&erdeklodes=".urlencode( $erdeklodes );
?>
<A HREF="masiklap.php?<?print $lekerdezes ?>">Gyerünk!</A>

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
19_ora.qxd 8/3/2001 6:22 PM Page 376

376 19. óra

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õ karakter-
láncokat tartalmazó hivatkozások készítését. Ez különösen fontos, ha meg szeret-
nénk tartani a PHP azon hasznos tulajdonságát, miszerint a nem kifejezetten prog-
ramozó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õ karak-
terláncot.

19.5. program Lekérdezõ karakterláncot készítõ függvény


1: <html>
2: <head>
3: <title>19.5 program Lekérdezõ karakterláncot készítõ
függvény</title>
4: </head>
5: <body>
6: <?php
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 );
19_ora.qxd 8/3/2001 6:22 PM Page 377

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

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: <p>
28: <a href="masiklap.php?<? print lsztring($lekerdezes)
?>">Gyerünk!</a>
29: </p>
30: </body>
31: </html>

Az lsztring() egy asszociatív tömböt vár paraméterként, amit jelen esetben


19
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.
19_ora.qxd 8/3/2001 6:22 PM Page 378

378 19. óra

Ö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ásai-
ró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ál-


tozókként válnak elérhetõvé. Létezik azonban egy tömb is, amely tartalmazza
õket. Mi ennek a tömbnek a neve?
19_ora.qxd 8/3/2001 6:22 PM Page 379

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

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õ karak-


terláncban tároljuk, ne sütikben.

19
19_ora.qxd 8/3/2001 6:22 PM Page 380
20_ora.qxd 8/3/2001 6:22 PM Page 381

20. ÓRA
Állapotok tárolása
munkamenet-függvényekkel
Az elõzõ órában áttekintettük, hogy hogyan lehet süti vagy lekérdezõ karaktersoro-
zat használatával menteni az oldalak állapotát. A PHP 4 ezeken kívül további lehetõ-
ségeket is nyújt, különbözõ függvényei vannak a felhasználó állapotának mentésére
is. Ezen függvények használata nagyon hasonló az elõzõ órában tanultakhoz, de
mivel közvetlenül a nyelvbe vannak építve, az állapot mentése egyszerû függvény-
hívásokkal végezhetõ el.

Ebben az órában a következõkrõl tanulunk:

• Mik azok a munkamenet-változók és hogyan használhatók?

• Hogyan indítsunk el és folytassunk egy munkamenetet?

• Hogyan tartsuk nyilván a munkamenetek változóit?

• Hogyan semmisítsünk meg egy munkamenetet?

• Hogyan töröljük egy munkamenet egyes változóit?


20_ora.qxd 8/3/2001 6:22 PM Page 382

382 20. óra

Mik azok a munkamenet-függvények?


A munkamenet-függvényekkel egyszerûen végezhetjük el azokat a mûveleteket,
amelyekrõl az elõzõ órában tanultunk. Ezek egy különleges felhasználói azonosí-
tót biztosítanak, amellyel oldalról oldalra különbözõ információkat vihetünk át,
hozzákapcsolva azokat ehhez az azonosítóhoz. Az elõzõekhez képest igen nagy
elõny, hogy a függvények használatával kevesebb munka hárul ránk. Amikor
a felhasználó lekér valamilyen munkamenetet támogató oldalt, kap egy azonosí-
tót, vagy a régebbi látogatásakor szerzett meglévõ azonosítója kerül felhasználás-
ra. Ezt követõen a munkamenethez kapcsolt összes globális változó elérhetõ lesz
a kódban.

A munkamenet-függvények mindkét, az elõzõ órában tanult módszert támogatják.


Alapértelmezés szerint a sütiket használják, ugyanakkor az azonosítókat minden,
a saját oldalunkra mutató kereszthivatkozásban elhelyezhetjük, így biztosítva,
hogy az oldal a sütiket nem támogató böngészõvel is használható legyen.

A munkamenet állapotát a rendszer általában egy ideiglenes fájlban tárolja, de


a megfelelõ modulok használatával az adatokat adatbázisba is tehetjük.

Munkamenet indítása a session_start() függvénnyel


Hacsak nem változtattuk meg a php.ini fájlt, a munkameneteket mindig saját
magunknak kell elindítanunk, alapállapotban azok nem indulnak el automati-
kusan. A php.ini fájlban található a következõ sor:

session.auto_start = 0

Változtassuk a session.auto_start értékét 1-re, így a PHP dokumentumok-


ban a munkamenetek rögtön elindulnak. Ha nem változtatjuk meg az értéket,
mindig meg kell hívnunk a session_start() függvényt.

Miután a munkamenet elindult, a session_id() függvénnyel rögtön hozzáfér-


hetünk a felhasználó munkamenet-azonosítójához. A session_id() függvénnyel
lekérdezhetjük vagy módosíthatjuk az azonosítót. A 20.1. példában található prog-
ram a munkamenet-azonosítót írja ki a böngészõbe.
20_ora.qxd 8/3/2001 6:22 PM Page 383

Állapotok tárolása munkamenet-függvényekkel 383

20.1. program Munkamenet indítása vagy folytatása


1: <?php
2: session_start();
3: ?>
4: <html>
5: <head>
6: <title>20.1. program Munkamenet indítása vagy
folytatása</title>
7: </head>
8: <body>
9: <?php
10: print "<p>Üdvözöljük! Az Ön munkamenet-azonosítója "
.session_id()."</p>\n\n";
11: ?>
12: </body>
13: </html>

A fenti program elsõ lefutása után létrehoz egy munkamenet-azonosítót. 20


Ha a felhasználó késõbb újratölti az oldalt, ugyanazt az azonosítót kapja meg.
Ehhez természetesen szükséges, hogy a felhasználó engedélyezze a sütiket
a böngészõjében. Vizsgáljuk meg a 20.1. példa kimenetének fejléceit. A süti
a következõkben lett beállítva:

HTTP/1.1 200 OK
Date: Sun, 07 Jan 2001 13:50:36 GMT
Server: Apache/1.3.9 (Unix) PHP/4.0.3
Set-cookie: PHPSESSID=2638864e9216fee10fcb8a61db382909; path=/
Connection: close
Content-Type: text/html

Mivel a session_start() megpróbálja beállítani a sütit, amikor munkamenetet


hoz létre, el kell indítani, mielõtt bármit kiíratnánk a böngészõvel. Vegyük észre,
hogy nincs lejárati idõ. Ez azt jelenti, hogy a munkamenet csak addig tarthat, amíg
a böngészõ aktív. Amikor a felhasználó leállítja a böngészõt, a sütit nem menti, de
ez a viselkedés a php.ini fájl session.cookie_lifetime beállításának
megváltoztatásával módosítható. Az alapértelmezett beállítás 0, itt kell a lejárati
idõt másodpercben megadni. Ezzel mindegyik munkamenetnek megadjuk
a mûködési határidõt.
20_ora.qxd 8/3/2001 6:22 PM Page 384

384 20. óra

Munkamenet-változók
A munkamenet-azonosító hozzárendelése a felhasználóhoz csak az elsõ lépés.
Egy munkamenet során tetszõleges számú globális változót vezethetünk be,
amelyeket késõbb bármelyik, a munkameneteket támogató oldalunkról elérhetünk.

A változó bejegyzéséhez, bevezetéséhez a session_register() függvényt kell


használnunk. A session_register() függvény paramétereiben karaktersoro-
zatokat kell megadni, így határozva meg egy vagy több bevezetendõ változó nevét.
A függvény visszatérési értéke true, ha a bejegyzés sikeres volt. A függvény para-
métereiben csak a változók nevét kell megadni, nem pedig a változók értékeit.

A 20.2. példában két változó bejegyzését láthatjuk.

20.2. program Változók bejegyzése


1: <?php
2: session_start();
3: ?>
4: <html>
5: <head>
6: <title>20.2. program Változók bejegyzése</title>
7: </head>
8: <body>
9: <?php
10: session_register( "termek1" );
11: session_register( "termek2" );
12: $termek1 = "Ultrahangos csavarhúzó";
13: $termek2 = "HAL 2000";
14: print session_encode();
15: print "A változókat bejegyeztük";
16: ?>
17: </body>
18: </html>

A 20.2. példában látható kódnak nincs túl sok értelme, amíg a felhasználó be nem
tölt egy új oldalt. A 20.3. példában egy olyan PHP program látható, amely a 20.2.
példában bejegyzett változókat használja.
20_ora.qxd 8/3/2001 6:22 PM Page 385

Állapotok tárolása munkamenet-függvényekkel 385

20.3. program Bejegyzett változók használata


1: <?php
2: session_start();
3: ?>
4: <html>
5: <head>
6: <title>20.3. program Bejegyzett változók
használata</title>
7: </head>
8: <body>
9: <?php
10: print "Az Ön által kiválasztott termékek:\n\n";
11: print "<ul><li>$termek1\n<li>$termek2\n</ul>\n";
12: ?>
13: </body>
14: </html>

A 20.3. program eredménye a 20.1. ábrán látható. Látjuk, hogy az oldalról hozzáfé- 20
rünk a másik programban bejegyzett $termek1 és $termek2 változókhoz.

20.1. ábra
Bejegyzett változók
használata

Hogyan mûködik mindez? A PHP 4 a háttérben folyamatosan fenntart egy ideigle-


nes fájlt a munkamenet számára. A session_save_path() függvény használa-
tával e fájl elérési útját deríthetjük ki, de a függvénynek egy könyvtár elérési útját
is megadhatjuk. Ha ezt meghatározzuk, az ideiglenes munkamenet-fájlok ezután
20_ora.qxd 8/3/2001 6:22 PM Page 386

386 20. óra

ide kerülnek. Ha a függvényt paraméter nélkül futtatjuk, visszatérési értéke annak


a könyvtárnak az elérési útja lesz, ahová a rendszer az ideiglenes munkamenet-
fájlokat menti. A szerzõ rendszerén a

print session_save_path();

visszatérési értéke /tmp. A /tmp könyvtár például a következõ fájlokat tartal-


mazhatja:

sess_2638864e9216fee10fcb8a61db382909
sess_76cae8ac1231b11afa2c69935c11dd95
sess_bb50771a769c605ab77424d59c784ea0

Amikor megnyitjuk azt a fájlt, melynek neve a 20.1. példában visszaadott munka-
menet-azonosítót tartalmazza, láthatjuk, hogyan tárolódnak a bejegyzett változók:

termek1|s:22:"Ultrahangos csavarhúzó";termek2|s:8:"HAL 2000";

Amikor meghívjuk a session_register() függvényt, a PHP beírja a fájlba


a változó nevét és értékét. Késõbb innen kapjuk meg a változó értékét.

Ha a session_register() függvénnyel bejegyeztünk egy változót, annak


a PHP program futása során módosított értéke a munkamenet-fájlban is
meg fog változni.

A 20.2. példa bemutatta a session_register() függvény használatát, de


a függvény mûködése nem tûnik túl rugalmasnak. Mit tehetünk, ha a felhasználó
többféle terméket tartalmazó változókat szeretne bevezetni? Szerencsére
a session_register() függvény paraméterében tömb típusú változót is
megadhatunk.

A 20.4. példában a felhasználó több termék közül választhat. Ezután munkamenet-


változókkal létrehozunk egy egyszerû „bevásárlókosarat”.

20.4. program Tömb típusú változó bejegyzése


1: <?php
2: session_start();
3: ?>
4: <html>
5: <head>
6: <title>20.4. program Tömb típusú változó
bejegyzése</title>
7: </head>
20_ora.qxd 8/3/2001 6:22 PM Page 387

Állapotok tárolása munkamenet-függvényekkel 387

20.4. program (folytatás)


8: <body>
9: <h1>Termékböngészõ lap</h1>
10: <?php
11: if ( isset( $termekek_urlap ) )
12: {
13: $termekek = $termekek_urlap;
14: session_register( "termekek" );
15: print "<p>A termékeit bejegyeztük!</p>;
16: }
17: ?><p>
18: <form method="POST">
19: <select name="termekek_urlap[]" multiple size=3>
20: <option> Ultrahangos csavarhúzó
21: <option> HAL 2000
22: <option> Kalapács
23: <option> TV
24:
25:
<option> Targonca
</select> 20
26: </p><p>
27: <input type="submit" value="Rendben">
28: </form>
29: </p>
30: <a href="20.5.program.php">Tartalom</a>
31: </body>
32: </html>

Elõször elindítjuk a munkamenetet a session_start() függvénnyel. Ezzel


hozzáférünk minden korábban beállított munkamenet-változóhoz. A HTML doku-
mentumon belül a FORM elem ACTION tulajdonságát beállítjuk a jelenlegi doku-
mentumra. Létrehozunk egy termekek_urlap[] nevû SELECT elemet, amely
a termékek számával megegyezõ OPTION összetevõt tartalmaz. Emlékezzünk rá,
hogy a HTML dokumentum azon elemeinek, amelyek engedélyezik több elem
kiválasztását, szögletes zárójellel együtt kell megadni a NAME paraméterét.
Így a felhasználó választása egy tömbbe kerül.

A PHP kód blokkjában megvizsgáljuk, hogy létezik-e a $termekek_urlap tömb.


Ha a változó létezik, feltehetjük, hogy a kérdõívet kitöltötték. Ezt a változót hozzá-
rendeljük a $termekek változóhoz, amit a session_register() függvénnyel
bejegyzünk. A $termekek_urlap tömböt közvetlenül nem jegyezzük be, mert
ez egy késõbbi kitöltés során ütközést okozhat az ugyanilyen nevû, POST eljárással
érkezett változóval.
20_ora.qxd 8/3/2001 6:22 PM Page 388

388 20. óra

A kód végén megadunk egy hivatkozást, ahol bemutatjuk, hogy valóban hozzáfé-
rünk a bejegyzett tömbhöz. Ez a kód a 20.5. példában található.

20.5. program Hozzáférés bejegyzett tömb típusú változóhoz


1:<?php
2:session_start();
3:print session_encode(); //kódolt karaktersorozat kiírása
4:?>
5:<html>
6:<head>
7:<title>20.5. program Hozzáférés bejegyzett
tömb típusú változóhoz</title>
8: </head>
9: <body>
10: <h1>Tartalom lap</h1>
11: <?php
12: if ( isset( $termekek ) )
13: {
14: print "<b>A bevásárlókocsi tartalma:</b><ol>\n";
15: foreach ( $termekek as $egytermek )
16: print "<li>$egytermek";
17: print "</ol>";
18: }
19: ?>
20: <a href="20.4.program.php">Vissza
a termékválasztáshoz</a>
21: </body>
22: </html>

A session_start() használatával folytatjuk a munkamenetet. Ellenõrizzük, hogy


létezik-e a $termekek változó. Ha létezik, elemeit egyenként kiírjuk a böngészõbe.

Természetesen egy igazi „bevásárlókosár-program” megírásakor a termékeket


érdemes adatbázisban, és nem a futtatandó kódban tárolni. A 20.4. és 20.5. példa
csak azt mutatta be, hogyan érhetõ el egy tömb típusú változó egy másik oldalról.
20_ora.qxd 8/3/2001 6:22 PM Page 389

Állapotok tárolása munkamenet-függvényekkel 389

A munkamenet és a változók bejegyzésének törlése


A munkameneteket és a bejegyzett változókat a session_destroy() függ-
vénnyel törölhetjük. A session_destroy() függvénynek nincsenek paraméterei,
futtatásához azonban szükséges egy folyamatban lévõ munkamenet. A következõ
kódrészlet létrehoz, majd rögtön megsemmisít egy munkamenetet:

session_start();
session_destroy();

Amikor olyan oldalt töltünk be, amely egy munkamenetet vár, az már nem látja
a korábban törölt munkamenetet, ezért létre kell hoznia egy újat. Minden koráb-
ban bejegyzett változó elvész.

Valójában a session_destroy() függvény nem semmisíti meg a bejegyzett válto-


zókat. Abban a kódban, amelyben a session_destroy() függvényt futtattuk,
a változók továbbra is elérhetõk. A következõ kódrészletben látható, hogy az 5-re
állított $proba változó a session_destroy() meghívása után is elérhetõ marad.
A munkamenet megszüntetése nem törli a bejegyzett változókat.
20
session_start();
session_register( "proba" );
$proba = 5;
session_destroy();
print $proba; // kiírja, hogy 5

A munkamenetbõl a bejegyzett változókat a session_unset() függvénnyel


távolíthatjuk el. A session_unset() a munkamenet-fájlból és a programból is
eltávolítja a változókat, ezért óvatosan használjuk.

session_start();
session_register( “proba” );
$proba = 5;
session_unset();
session_destroy();
print $proba; // nem ír ki semmit. a $proba változó
å már nem létezik.

A munkamenet megszüntetése elõtt meghívjuk a session_unset() függvényt,


amely eltávolítja a $proba, és minden más bejegyzett változót a memóriából.
20_ora.qxd 8/3/2001 6:22 PM Page 390

390 20. óra

Munkamenet-azonosítók a lekérdezõ karakterláncban


Áttekintettük a sütin alapuló munkamenetek kezelését. Tudnunk kell azonban,
hogy ez nem a legbiztosabb módszer. Nem feltételezhetjük ugyanis, hogy a láto-
gató böngészõje támogatja a sütik használatát. A probléma elkerülése végett épít-
sünk be programunkba egy, a munkamenet-azonosító továbbadására alkalmas
lekérdezõ karakterláncot. A PHP létrehozza a SID állandót, ha a böngészõ nem
küldött vissza azonosítót tartalmazó sütit. A SID név–érték alakú állandó karakter-
lánc, amelyet beágyazhatunk a munkamenetet támogató oldalra mutató HTML
hivatkozásokba:

<a href="masik_lap.php?<? print SID; ?>">Másik lap</a>


A böngészõben ez már így jelenik meg:
<a href="masik_lap.php?PHPSESSID=
å 08ecedf79fe34561fa82591401a01da1">Másik lap</a>

A munkamenet-azonosító automatikusan átvételre kerül, amikor a céloldalon


meghívjuk a session_start() függvényt, és az összes korábban bejegyzett
változó a szokásos módon elérhetõ lesz.

Ha a PHP 4-et az --enable-trans-sid kapcsolóval fordítottuk le a fenti lekér-


dezõ karakterlánc automatikusan hozzáadódik minden HTML hivatkozáshoz.
Ez a lehetõség alapállapotban kikapcsolt, de használatával kódjaink hordozha-
tóbbá válnak.

Munkamenet-változók kódolása és visszafejtése


Amikor megnéztük a munkamenet-fájl tartalmát, láttuk, hogyan menti és kódolja
a PHP a bejegyzett változókat. A kódolt karaktersorozathoz a session_encode()
függvény használatával bármikor hozzáférhetünk. Ez hasznos lehet a munkamene-
tek nyomkövetésénél. A következõ kódrészletben láthatjuk, hogyan mûködik
a session_encode() függvény.

session_start();
print session_encode()."<br>";
// minta eredmény: termekek|a:2:{i:0;s:8:
å "HAL 2000";i:1;s:8:"Targonca";}

Látható, hogy a függvény tárolási alakjukban adja vissza a bejegyzett változókat, így
ellenõrizhetjük, hogy a változó valóban be lett-e jegyezve és értéke megfelelõ-e.
A session_encode() függvény használatával bejegyzett változókat tartalmazó
adatbázisokat is készíthetünk.
20_ora.qxd 8/3/2001 6:22 PM Page 391

Állapotok tárolása munkamenet-függvényekkel 391

A session_decode() függvény használatával a változók kódolt formájából


visszanyerhetjük az értéküket. A következõ kódrészlet ezt mutatja be:

session_start();
session_unset(); // nem szabad, hogy létezzenek
å munkamenet-változók
session_decode( "termekek|a:2:{i:0;s:8:\”HAL 2000\";
å i:1;s:8:\"Targonca\";}" );
foreach ( $termekek as $egytermek )
{
print "$egytermek<br>\n";
}
// Kimenet:
// HAL 2000
// Targonca

A szokásos módon elindítjuk a munkamenetet. Hogy tiszta lappal induljunk,


a session_unset() függvénnyel töröljük az összes korábban bejegyzett változót.
Ezután átadjuk a session_decode() függvénynek a változók kódolt formáját. 20
A függvény párosítja a változóneveket a megfelelõ értékekkel. Ezt ellenõrizzük is:
a $termekek tömb minden elemét kiíratjuk.

Munkamenet-változó bejegyzésének ellenõrzése


Mint láttuk, a bejegyzett változó jelenlétét az isset() függvénnyel ellenõriz-
hetjük, de más módon is megvizsgálhatjuk a változó létezését. Erre való
a session_is_registered() függvény. A függvény paraméterében egy változó
nevét tartalmazó karakterláncot kell megadni, a visszatérési érték pedig true,
ha a változó bejegyzett.

if ( session_is_registered ( "termekek" ) )
print "A 'termekek' változó bejegyzett!";

Ez akkor lehet hasznos, ha biztosak akarunk lenni a változó forrásában, azaz, hogy
a változó tényleg a munkamenet bejegyzett változója vagy csak egy GET kérelem
eredményeként kaptuk.
20_ora.qxd 8/3/2001 6:22 PM Page 392

392 20. óra

Összefoglalás
Ebben és az elõzõ órában áttekintettük, hogyan menthetjük az állapotokat
egy állapot nélküli protokollban. Különféle módszereket alkalmaztunk: sütiket és
lekérdezõ karakterláncokat használtunk, néha ezeket fájlokkal és adatbázisokkal
ötvöztük. Mindegyik megközelítési módnak megvannak a maga elõnyei és
hátrányai.

A süti nem igazán megbízható és nem tárolhat sok információt. Ezzel szemben
hosszú ideig fennmaradhat.

Az adatok fájlban vagy adatbázisban való tárolása miatt a sebesség csökkenhet,


ami gondot okoz egy népszerû webhelyen. Ugyanakkor egy egyszerû azonosí-
tóval nagy mennyiségû adathoz férhetünk hozzá.

A lekérdezõ karakterlánc a süti ellentéte. Elég csúnyán néz ki, de viszonylag nagy
mennyiségû információt hordoz magában. Használatáról a körülmények mérlege-
lése után kell dönteni.

Ebben az órában megtanultuk, hogyan indítsunk el munkamenetet


a session_start() függvénnyel. Láttuk, hogyan jegyezhetünk be változókat
a session_register() függvénnyel, hogyan ellenõrizhetjük a bejegyzést
a session_is_registered() függvénnyel, valamint hogyan semmisíthetjük
meg a változókat a session_unset() függvénnyel. A munkamenet megsemmi-
sítésére a session_destroy() függvényt használtuk.

Hogy minél több felhasználó érhesse el a munkamenetet támogató környezetet,


lekérdezõ karakterláncainkban használjuk a SID állandót a munkamenet-azono-
sító átadására.

Kérdések és válaszok
Van valamilyen veszélye a munkamenet-függvények használatának,
amirõl még nem tudunk?
A munkamenet-függvények alapvetõen megbízhatók. De emlékezzünk rá, hogy
a sütik használata nem lehetséges több tartományon keresztül. Ezért, ha több tarto-
mánynevet használunk ugyanazon a kiszolgálón (elektronikus kereskedelemi alkal-
mazásoknál ez gyakori), tiltsuk le a sütik használatát a session.use_cookies 0-
ra állításával a php.ini fájlban.
20_ora.qxd 8/3/2001 6:22 PM Page 393

Állapotok tárolása munkamenet-függvényekkel 393

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ényt használjuk egy munkamenet elindítására?

2. Melyik függvény adja vissza a jelenlegi munkamenet azonosítóját?

3. Hogyan rendelhetünk változókat a munkamenethez?

4. Hogyan semmisíthetjük meg a munkamenetet és törölhetjük el minden nyomát?

5. Hogyan semmisíthetjük meg az összes munkamenet-változót a futó prog-


ramban és az egész munkamenetben?

6. Mi a SID állandó értéke?


20
7. Hogyan ellenõrizhetjük, hogy a $proba nevû változó be van-e jegyezve
egy munkameneten belül?

Feladatok
1. Az elõzõ óra Feladatok részében készítettünk egy programot, amely sütit
vagy lekérdezõ karakterláncot használ, hogy oldalról oldalra vigye tovább
a felhasználó válaszait. Ezután a környezet minden oldala a beállított háttér-
színnel indult és név szerint üdvözölte a felhasználót. Készítsük el ezt a prog-
ramot a PHP 4 munkamenet-függvényeivel.

2. Készítsünk programot, amely munkamenet-függvények használatával emlé-


kezik rá, hogy a felhasználó a környezet mely oldalait látogatta meg. Készítsük
el a felhasználó lépéseit tartalmazó hivatkozások sorozatát, hogy mozgása
nyomon követhetõ legyen.
20_ora.qxd 8/3/2001 6:22 PM Page 394
21_ora.qxd 8/3/2001 6:22 PM Page 395

21. ÓRA
Munka kiszolgálói környezetben
A korábbi fejezetekben áttekintettük, hogyan társaloghatunk távoli számítógépek-
kel és hogyan vehetünk át adatokat a felhasználótól. Ebben a fejezetben ismét ki-
tekintünk, olyan eljárásokat tanulunk meg, amelyek külsõ programok saját gépün-
kön való futtatására használhatók. A fejezet példái Linux operációs rendszerre
készültek, de a legtöbb alapelv felhasználható Microsoft Windows rendszerben is.

A fejezetben a következõket tekintjük át:

• Hogyan közvetítsünk adatokat a programok között?

• A héjparancsok végrehajtására és az eredmények megjelenítésére milyen le-


hetõségeink vannak?

• Hogyan írhatunk biztonságosabb PHP programokat?


21_ora.qxd 8/3/2001 6:22 PM Page 396

396 21. óra

Folyamatok összekötése a popen() függvénnyel


Ahogy a fájlokat nyitottuk meg írásra vagy olvasásra az fopen() segítségével,
ugyanúgy nyithatunk adatcsatornát két folyamat között a popen() paranccsal.
A popen() paramétereiben meg kell adni egy parancsot elérési úttal, és azt, hogy
írási vagy olvasási módban akarjuk használni a függvényt. A popen() visszatérési
értéke az fopen() visszatérési értékéhez hasonló fájlazonosító. A popen()-nek
a 'w' jelzõvel adhatjuk meg, hogy írási módban, az 'r' jelzõvel pedig azt, hogy
olvasási módban akarjuk használni a függvényt. Ugyanazzal az adatcsatornával
nem lehet egyszerre írni és olvasni is egy folyamatot. Amikor befejeztük a munkát
a popen() által megnyitott folyamattal, a pclose() paranccsal le kell zárnunk az
adatcsatornát. A pclose() függvény paraméterében egy érvényes fájlazonosítót
kell megadni.

A popen() használata akkor javasolt, amikor egy folyamat kimenetét sorról sorra
szeretnénk elemezni. A 21.1-es példában a GNU who parancs kimenetét elemezzük,
és a kapott felhasználóneveket mailto hivatkozásokban használjuk fel.

21.1. program A who UNIX parancs kimenetének olvasása


a popen() segítségével
1: <html>
2: <head>
3: <title>21.1. program A who UNIX parancs kimenetének
4: olvasása a popen() segítségével</title>
5: </head>
6: <body>
7: <h2>A rendszerbe bejelentkezett felhasználók</h1>
8: <?php
9: $ph = popen( "who", "r" )
10: or die( "A 'who' paranccsal nem vehetõ fel
kapcsolat" );
11: $kiszolgalo="www.kiskapu.hu";
12: while ( ! feof( $ph ) )
13: {
14: $sor = fgets( $ph, 1024 );
15: if ( strlen( $sor ) <= 1 )
16: continue;
17: $sor = ereg_replace( "^([a-zA-Z0-9_\-]+).*",
18: "<a
href=\"mailto:\\1@$kiszolgalo\">\\1</a><br>\n",
19: $sor );
20: print "$sor";
21: }
21_ora.qxd 8/3/2001 6:22 PM Page 397

Munka kiszolgálói környezetben 397

21.1. program (folytatás)


22: pclose( $ph );
23: ?>
24: </body>
25: </html>

A who parancs eredményének kiolvasásához szükségünk van egy fájlmutatóra


a popen() függvénytõl, így a while utasítás segítségével sorról sorra elemezhetjük
a kimenetet. Ha a sorban olvasható kimenet csupán egyetlen karakter, a while
ciklus következõ lépésére ugrunk, kihagyva az elemzést, különben
az ereg_replace() függvénnyel újabb HTML hivatkozással és soremeléssel
bõvítjük a végeredményt. Végül a pclose() függvénnyel lezárjuk az adatcsatornát.
A program egy lehetséges kimenete a 21.1. ábrán látható.

21.1. ábra
A who UNIX parancs
kimenetének olvasása

21

A popen() függvény használható parancsok bemenetének írására is. Ez akkor


hasznos, ha egy parancs a szabványos bemenetrõl vár parancssori kapcsolókat.
A 21.2. példában azt láthatjuk, hogyan használhatjuk a popen() függvényt
a column parancs bemenetének írására.
21_ora.qxd 8/3/2001 6:22 PM Page 398

398 21. óra

21.2. program A column parancs bemenetének írása


a popen() függvény segítségével
1: <html>
2: <head>
3: <title>21.2. program A column parancs bemenetének
írása
4: a popen() függvény segítségével</title>
5: </head>
6: <body>
7: <?php
8: $termekek = array(
9: array( "HAL 2000", 2, "piros" ),
10: array( "Modem", 3, "kék" ),
11: array( "Karóra", 1, "rózsaszín" ),
12: array( "Ultrahangos csavarhúzó", 1,
"narancssárga" )
13: );
14: $ph = popen( "column -tc 3 -s / >
fizetve/3as_felhasznalo.txt", "w" )
15: or die( "A 'column' paranccsal nem vehetõ fel
kapcsolat" );
16: foreach ( $termekek as $termek )
17: fputs( $ph, join(‘/’, $termek)."\n");
18: pclose( $ph );
19: ?>
20: </body>
21: </html>

A 21.2. példában megfigyelhetõ, hogyan érhetõk el és írhatók ASCII táblázatként


fájlba a többdimenziós tömbök elemei. A column parancs bemenetéhez adatcsa-
tornát kapcsolunk, amin keresztül parancssori kapcsolókat küldünk. A –t kapcso-
lóval megadjuk, hogy táblázattá formázza a kimenetet, a –c 3 megadja a szüksé-
ges oszlopok számát, a –s / a /-t állítja be mezõelválasztóként. Megadjuk, hogy
a végeredményt a 3as_felhasznalo.txt fájlba írja. A fizetve könyvtárnak
léteznie kell és a megfelelõ jogosultság szükséges, hogy a program írhasson bele.

Most egyetlen utasítással egyszerre több dolgot tettünk. Meghívtuk a column


programot és kimenetét fájlba írtuk. Valójában parancsokat adtunk ki a héjnak:
ez azt jelenti, hogy az adatcsatorna használatával, egy folyamat futtatásával más
feladatokat is elindíthatunk. A column kimenetét például a mail parancs segít-
ségével postázhatjuk valakinek:
21_ora.qxd 8/3/2001 6:22 PM Page 399

Munka kiszolgálói környezetben 399

popen( "column -tc 3 -s / | mail kiskapu@kiskapu.hu", "w" )

Így elérhetjük, hogy a felhasználó által beírt adatokkal rendszerparancsokat hajtsunk


végre PHP függvényekkel. Ennek néhány hátrányos tulajdonságát még áttekintjük
az óra további részében.

Miután rendelkezünk egy fájlazonosítóval, a $termekek tömb minden elemén


végiglépkedünk. Minden elem maga is egy tömb, amit a join() függvény segít-
ségével karakterlánccá alakítunk. Az üres karakter helyett mezõelválasztóként
a ’/’ karaktert választjuk. Ez azért szükséges, mert ha üres karakterek jelennének
meg a termékek tömbjében, az összezavarná a column parancsot. Az átalakítás
után a karakterláncot és egy újsor karaktert írunk ki az fputs() függvénnyel.

Végül lezárjuk az adatcsatornát. A 3as_felhasznalo.txt fájlban a következõk


szerepelnek:

HAL 2000 2 piros


Modem 3 kék
Karóra 1 rózsaszín
Ultrahangos csavarhúzó 1 narancssárga

A kódot hordozhatóbbá tehetjük, ha a szöveg formázására a sprintf() függ-


vényt használjuk.

21
Parancsok végrehajtása az exec() függvénnyel
Az exec() egyike azoknak a függvényeknek, amelyekkel parancsokat adhatunk ki
a héjnak. A függvény paraméterében meg kell adni a futtatandó program elérési
útját. Ezen kívül megadható még egy tömb, mely a parancs kimenetének sorait fogja
tartalmazni és egy változó, amelybõl a parancs visszatérési értéke tudható meg.

Ha az exec() függvénynek az 'ls –al .' parancsot adjuk meg, akkor az aktu-
ális könyvtár tartalmát jeleníti meg. Ez látható a 21.3. példában.

21.3. program Könyvtárlista betöltése a böngészõbe


1: <html>
2: <head>
3: <title>21.3. program Könyvtárlista betöltése
a böngészõbe </title>
4: </head>
5: <body>
21_ora.qxd 8/3/2001 6:22 PM Page 400

400 21. óra

21.3. program (folytatás)


6: <?php
7: exec( "ls -al .", $kimenet, $vissza );
8: print "<p>Visszatérési érték: $vissza</p>";
9: foreach ( $kimenet as $fajl )
10: print "$fajl<br>";
11: ?>
12: </body>
13: </html>

Ha az ls parancs sikeresen végrehajtódik, a visszatérési érték 0 lesz. Ha a program


a megadott könyvtárat nem találja vagy az nem olvasható, a visszatérési érték 1.

A végeredmény szempontjából nem tettünk semmi újat, hiszen az opendir() és


a readdir() függvényekkel ugyanezt elérhettük volna, de elképzelhetõ olyan
eset, amikor rendszerparancsokkal vagy korábban megírt Perl programokkal
sokkal gyorsabban megoldhatjuk a feladatot, mint PHP függvényekkel. Ha a PHP
program kifejlesztésének sebessége fontos szempont, esetleg érdemesebb
a korábban megírt Perl program meghívása mellett dönteni, mint átültetni azt
PHP-be, legalábbis rövid távon. Meg kell azonban jegyeznünk, hogy rendszer-
parancsok használatával programjaink több memóriát fogyasztanak és többnyire
futásuk is lassabb.

21.2. ábra
A könyvtárlista betöl-
tése a böngészõbe
az exec() függvény
segítségével
21_ora.qxd 8/3/2001 6:22 PM Page 401

Munka kiszolgálói környezetben 401

Külsõ programok futtatása a system() függvénnyel


vagy a ` mûveletjel segítségével
A system() függvény az exec() függvényhez hasonlóan külsõ programok
indítására használható. A függvénynek meg kell adni a futtatandó program elérési
útját, valamint megadható egy változó, amely a program visszatérési értékét tartal-
mazza majd. A system() függvény a kimenetet közvetlenül a böngészõbe írja.
A következõ kódrészlet a man parancs leírását adja meg:

<?php
print "<pre>";
system( "man man | col -b", $vissza );
print "</pre>";
?>

A PRE HTML elemet azért adtuk meg, hogy a böngészõ megtartsa a kimenet
eredeti formátumát. A system() függvényt használtuk, hogy meghívjuk a man
parancsot, ennek kimenetét hozzákapcsoltuk a col parancshoz, amely ASCII-ként
újraformázza a megjelenõ szöveget. A visszatérési értéket a $vissza változóba
mentjük. A system() közvetlenül a böngészõbe írja a kimenetet.

Ugyanezt az eredményt érhetjük el a ` mûveletjel használatával. A kiadandó


parancsot egyszerûen ilyen fordított irányú aposztrófok közé kell tennünk.
Az így megadott parancsot a rendszer végrehajtja és visszatérési értékként
a parancs kimenetét adja, amit kiírhatunk vagy változóban tárolhatunk.
21
Íme az elõzõ példa ilyetén megvalósítása:

print "<pre>";
print `man man | col -b`;
print "</pre>";

Vegyük észre, hogy ebben a megvalósításban rögtön kiírtuk a végeredményt.

Biztonsági rések megszüntetése


az escapeshellcmd() függvény használatával
Az escapeshellcmd() függvény ismertetése elõtt tekintsük át, mivel szemben
van szükségünk védelemre. A példa erejéig tegyük fel, hogy meg szeretnénk
engedni a látogatóknak, hogy különbözõ súgóoldalakat tekinthessenek meg.
Ha bekérjük egy oldal nevét, a felhasználó bármit beírhat oda. A 21.4. példában
található programot ne telepítsük, mert biztonsági rést tartalmaz!
21_ora.qxd 8/3/2001 6:22 PM Page 402

402 21. óra

21.4. program A man program meghívása


1: <html>
2: <head>
3: <title>21.4. program A man program meghívása.
4: Ez a kód nem biztonságos</title>
5: </head>
6: <body>
7: <form>
8: <input type="text" value="<?php print $manoldal;
?>" name="manoldal">
9: </form>
10: <pre>
11: <?php
12: if ( isset($manoldal) )
13: system( "man $manoldal | col -b" );
14: ?>
15: </pre>
16: </body>
17: </html>

Korábbi példánkat egy szöveges mezõvel és a system() függvénnyel egészí-


tettük ki. Megbízhatónak tûnik, UNIX rendszeren azonban a felhasználó
a manoldal mezõhöz hozzáadhatja saját parancsait, így hozzáférhet a kiszolgálón
számára tiltott részen lévõ adatokhoz is. Erre láthatunk példát a 21.3. ábrán.

21.3. ábra
A man program
meghívása
21_ora.qxd 8/3/2001 6:22 PM Page 403

Munka kiszolgálói környezetben 403

A felhasználó az oldalon keresztül kiadta az xxx; ls –al parancsot.


Ezt a $manoldal változóban tároljuk. A program futása közben a system()
függvénynek a következõ parancsot kell végrehajtania:

"man xxx; ls -al | col -b"

Vagyis meg kell jelenítenie az xxx parancshoz tartozó súgóoldalt, ami természe-
tesen nem létezik. Ebben az esetben a col parancs bemenete a teljes könyvtárlista
lesz. Ezzel a támadó kiírathatja a rendszer bármelyik olvasható könyvtárának tartal-
mát. A következõ utasítással például a /etc/passwd tartalmát kapja meg:

xxx; cat /etc/passwd

Bár a jelszavak egy titkosított fájlban, az /etc/shadow-ban vannak tárolva,


amely csak a rendszergazda (root) által olvasható, ez mégis egy igen veszélyes
biztonsági rés. A legegyszerûbben úgy védekezhetünk ellene, hogy soha nem
engedélyezzük, hogy a felhasználók közvetlenül adjanak parancsot a rendszernek.
Ennél kicsit több lehetõséget ad, ha az escapeshellcmd() függvénnyel
fordított perjel (\) karaktert adunk minden metakarakterhez, amit a felhasználó
kiadhat. Az escapeshellcmd() függvény paramétere egy karakterlánc,
végeredménye pedig egy átalakított másolat. A korábbi kód biztonságosabb
változata a 21.5. példában található.

21.5. program A felhasználói bemenet javítása


az escapeshellcmd() függvény használatával 21
1: <html>
2: <head>
3: <title>21.5. program A felhasználói bemenet javítása
4: az escapeshellcmd() függvény
használatával</title>
5: </head>
6: <body>
7: <form>
8: <input type="text" value="<?php print $manoldal; ?>"
name="manoldal">
9: </form>
10: <pre>
11: <?php
21_ora.qxd 8/3/2001 6:22 PM Page 404

404 21. óra

21.5. program (folytatás)


12: if ( isset($manoldal) )
13: {
14: $manoldal = escapeshellcmd( $manoldal );
15: system( "man $manoldal | col -b" );
16: }
17: ?>
18: </pre>
19: </body>
20: </html>

Ha a felhasználó most kiadja az xxx; cat etc/passwd parancsot, akkor


a system() függvény meghívása elõtt az escapeshellcmd() az xxx\; cat
/etc/passwd paranccsá alakítja azt, azaz a cat utasítás súgóját kapjuk a jelszófájl
helyett.

A rendszer biztonságát az escapeshellcmd() függvény segítségével tovább


növelhetjük. Lehetõség szerint kerüljük azokat a helyzeteket, ahol a felhasználók
közvetlenül a rendszernek adnak ki parancsokat. A programot még biztonságo-
sabbá tehetjük, ha listát készítünk az elérhetõ súgóoldalakról és még mielõtt meg-
hívnánk a system() függvényt, összevetjük a felhasználó által beírtakat ezzel
a listával.

Külsõ programok futtatása a passthru() függvénnyel


A passthru() függvény a system()-hez hasonló, azzal a különbséggel, hogy
a passthru()-ban kiadott parancs kimenete nem kerül átmeneti tárba. Így olyan
parancsok kiadására is lehetõség nyílik, amelyek kimenete nem szöveges, hanem
bináris formátumú. A passthru() függvény paramétere egy rendszerparancs és
egy elhagyható változó. A változóba kerül a kiadott parancs visszatérési értéke.

Lássunk egy példát! Készítsünk programot, amely a képeket kicsinyített mintaként


jeleníti meg és meghívható HTML vagy PHP oldalalakról is. A feladatot külsõ
alkalmazások használatával oldjuk meg, így a program nagyon egyszerû lesz.
A 21.6. példában látható, hogyan küldhetünk a képrõl mintát a böngészõnek.
21_ora.qxd 8/3/2001 6:22 PM Page 405

Munka kiszolgálói környezetben 405

21.6. program A passthru() függvény használata képek megjelenítésére


1: <?php
2: if ( isset($kep) && file_exists( $kep ) )
3: {
4: header( "Content-type: image/gif" );
5: passthru( "giftopnm $kep | pnmscale -xscale
.5 -yscale .5 | ppmtogif" );
6: }
7: else
8: print "A(z) $kep nevû kép nem található.";
9: ?>

Vegyük észre, hogy nem használtuk az escapeshellcmd() függvényt, ehelyett


a felhasználó által megadott fájl létezését ellenõriztük a file_exists()
függvénnyel. Ha a $kep változóban tárolt kép nem létezik, nem is próbáljuk
megjeleníteni. A program még biztonságosabbá tehetõ, ha csak bizonyos kiter-
jesztésû fájlokat engedélyezünk és korlátozzuk az elérhetõ könyvtárakat is.

A passthru() hívásakor három alkalmazást indítunk el. Ha ezt a programot


használni akarjuk, rendszerünkre telepítenünk kell ezen alkalmazásokat és meg
kell adni azok elérési útját. Elõször a giftopnm-nek átadjuk a $kep változó
értékét. Az beolvassa a GIF képet és hordozható formátumúra alakítja. Ezt a kime-
netet rákapcsoljuk a pnmscale bemenetére, amely 50 százalékkal lekicsinyíti
a képet. Ezt a kimenetet a ppmtogif bemenetére kapcsoljuk, amely visszaalakítja
21
GIF formátumúvá, majd a kapott képet megjelenítjük a böngészõben.

A programot a következõ utasítással bármelyik weboldalról meghívhatjuk:

<img src="21.6.program.php?kep=<?php
å print urlencode("/utvonal/kep.gif") ?>">

Külsõ CGI program meghívása


a virtual() függvénnyel
Ha egy oldalt HTML-rõl PHP-re alakítunk, azt vesszük észre, hogy a kiszolgálóol-
dali beillesztések nem mûködnek. Ha Apache modulként futtatjuk a PHP-t,
a virtual() függvénnyel külsõ CGI programokat hívhatunk meg, például Perl
vagy C nyelven írt számlálókat. Minden felhasznált CGI programnak érvényes
HTTP fejléccel kell kezdenie a kimenetét.
21_ora.qxd 8/3/2001 6:22 PM Page 406

406 21. óra

Írjunk egy Perl CGI programot! Ne aggódjunk, ha nem ismerjük a Perlt. Ez a prog-
ram egyszerûen egy HTTP fejlécet ír ki és minden rendelkezésre álló környezeti
változót felsorol:

#!/usr/bin/perl -w
print "Content-type: text/html\n\n";
foreach ( keys %ENV ){
print "$_: $ENV{$_}<br>\n";
}

Mentsük a programot a cgi-bin könyvtárba proba.pl néven.


Ezután a virtual() függvénnyel a következõképpen hívhatjuk meg:

<?php
virtual("/cgi-bin/proba.pl");
?>

Összefoglalás
Ebben a fejezetben áttekintettük, hogyan mûködhetünk együtt a héjjal és rajta
keresztül a külsõ alkalmazásokkal. A PHP sok mindenre használható, de lehet,
hogy külsõ programok használatával az adott probléma elegánsabb megoldá-
sához jutunk.

Megtanultuk, hogyan kapcsolhatunk össze alkalmazásokat a popen() függvény


segítségével. Ez akkor hasznos, amikor a programok a szabványos bemenetrõl
várnak adatokat, de mi egy alkalmazás kimenetébõl szeretnénk továbbítani azokat.

Megnéztük, hogyan használható az exec() és a system() függvény, valamint


a fordított irányú aposztróf mûveletjel a felhasználói utasítások közvetítésére
a rendszermag felé. Láttuk, hogyan védekezzünk a betörésre használható utasítá-
sok ellen az escapeshellcmd() függvény segítségével. Láttuk, hogyan fogad-
hatók bináris adatok rendszerparancsoktól a passthru() függvénnyel és hogy
hogyan valósíthatjuk meg a kiszolgálóoldali beillesztéseket (SSI) a virtual()
függvénnyel.
21_ora.qxd 8/3/2001 6:22 PM Page 407

Munka kiszolgálói környezetben 407

Kérdések és válaszok
Sokat emlegettük a biztonságot ebben a fejezetben. Honnan tudhatunk
meg többet a szükséges biztonsági óvintézkedésekrõl?
A legbõvebb számítógépes biztonsággal foglalkozó forrás Lincoln Stein (a híres
Perl modul, a CGI.pm szerzõje) által fenntartott FAQ. Megtalálható
a http://www.w3.org/Security/Faq/ címen. Érdemes a PHP kézikönyv
biztonságról szóló részét is tanulmányozni.

Mikor használjunk külsõ alkalmazásokat saját PHP kódok helyett?


Három szempontot kell megvizsgálnunk: a hordozhatóságot, a fejlesztési sebességet
és a hatékonyságot. Ha saját kódot használunk külsõ programok helyett, progra-
munk könnyebben átvihetõ lesz a különbözõ rendszerek között. Egyszerû felada-
toknál, például könyvtár tartalmának kiíratásakor, saját kóddal oldjuk meg a problé-
mát, így csökkenthetjük a futási idõt, mivel nem kell minden futás alkalmával egy
külsõ programot meghívnunk. Másrészrõl nagyobb feladatoknál sokat segíthetnek
a kész külsõ programok, mivel képességeiket nehéz lenne megvalósítani PHP-ben.
Ezekben az esetekben egy külön erre a célra készített külsõ alkalmazás használata
javasolt.

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.
21
Kvíz
1. Melyik függvényt használjuk alkalmazások összekapcsolására?

2. Hogyan olvasunk adatokat egy folyamat kimenetérõl, miután elindítottuk?

3. Hogyan írunk adatokat egy folyamat bemenetére, miután elindítottuk?

4. Az exec() függvény közvetlenül a böngészõbe írja a végeredményét?

5. Mit csinál a system() függvény a végrehajtott külsõ parancs kimenetével?

6. Mi a fordított irányú aposztróf visszatérési értéke?

7. Hogyan adhat ki biztonságosan a felhasználó parancsokat a rendszerhéjnak?

8. Hogyan hajthatunk végre külsõ CGI programot a PHP programokból?


21_ora.qxd 8/3/2001 6:22 PM Page 408

408 21. óra

Feladatok
1. Írjunk programot, amely a UNIX ps parancsának segítségével megjeleníti
a böngészõben a futó folyamatokat! (Megjegyezzük, hogy nem biztonságos,
ha a felhasználók futtathatják a programot!).

2. Nézzük meg a ps parancs súgójában a lehetséges parancssori kapcsolókat!


Módosítsuk az elõzõ programot, hogy a felhasználó a kapcsolók egy részét
használhassa. Ne küldjünk ellenõrizetlen utasításokat a rendszermagnak!
22_ora.qxd 8/3/2001 6:22 PM Page 409

22. ÓRA
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 hiba-
keresõ 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


22_ora.qxd 8/3/2001 6:22 PM Page 410

410 22. óra

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.

22.1. ábra
PHP információk
megjelenítése

Az oldal tetején a használt PHP-változatról, a webkiszolgáló típusáról, a rendszer-


rõ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ál-
lításokra:

track_vars On
register_globals Off
22_ora.qxd 8/3/2001 6:22 PM Page 411

Hibakeresés 411

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 $felhasznalo-
ké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 hiba-
kereséséhez. Tegyük fel például, hogy olyan munkameneteket szeretnénk létre-
hozni, 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


22
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.
22_ora.qxd 8/3/2001 6:22 PM Page 412

412 22. óra

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: <?php
2: setcookie( "azonosito", "2344353463433",
time()+3600, "/" );
3: ?>
4: <html>
5: <head>
6: <title>22.1. program A phpinfo() függvény
kipróbálása</title>
7: </head>
8: <body>
9: <form action="<?php print "$PHP_SELF" ?>"
METHOD="get"">
10: <input type="text" name="felhasznalo">
11: <br>
12: <select name="termekek[]" multiple>
13: <option>Krumpli
14: <option>Sajt
15: <option>Kenyér
16: <option>Csirke
17: </select>
18: <br>
19: <input type="submit" value="Lássuk!">
20: </form>
21: <p></p>
22: <hr>
23: <p></p>
24: <?php
25: phpinfo();
26: ?>
27: </body>
28: </html>

Ha a „Lássuk!” gombra kattintunk, a program megkapja a felhasználó által meg-


adott 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.
22_ora.qxd 8/3/2001 6:22 PM Page 413

Hibakeresés 413

22.2. ábra
Globális változók
elérése

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.
22
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.
22_ora.qxd 8/3/2001 6:22 PM Page 414

414 22. óra

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: <html>
2: <head>
3: <title>22.2. program Dokumentum forrásának
megjelenítése</title>
4: </head>
5: <body>
6: <form action="<?php print "$PHP_SELF" ?>"
method="get">
7: Kérem a fájl nevét:
8: <input type="text" name="file" value="<?php print
$file; ?>">
9: <p></p><hr><p></p>
10: <?php
11: if ( isset( $file ) )
12: show_source( $file ) or print "nem lehet
megnyitni a következõ fájlt: \"$file\"";
13: ?>
14: </body>
15: </html>
A 22.3. ábra a 22.2. példaprogramot mutatja mûködés közben.

22.3. ábra
Színkiemelés
használata

Miért hasznos ez a lehetõség? Hiszen megnézhetnénk a kódot megszokott szöveg-


szerkesztõ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.
22_ora.qxd 8/3/2001 6:22 PM Page 415

Hibakeresés 415

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õ.

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!

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 22
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 elfelejtet-
tünk zárójelbe tenni egy kifejezést vagy elgépeltük egy függvény nevét. A hibaüze-
netek 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ít-
sé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
22_ora.qxd 8/3/2001 6:22 PM Page 416

416 22. óra

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
22_ora.qxd 8/3/2001 6:22 PM Page 417

Hibakeresés 417

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ügg-
vé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: <?php
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:
8: };
print "Tudom, hogy a \$flag változó értéke NEM 45";
22
9: ?>

Mint látható, a $flag változó értékét akarjuk vizsgálni, de elgépeltük. Nincs végze-
tes 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 üze-
netet 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é:
22_ora.qxd 8/3/2001 6:22 PM Page 418

418 22. óra

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:

<INPUT TYPE="text" NAME="felhasznalo" VALUE="<?


å print $felhasznalo; ?>">

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ít-
mé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 hibakere-


sõ 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.
22_ora.qxd 8/3/2001 6:22 PM Page 419

Hibakeresés 419

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 ); 22
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ül-
jö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:
22_ora.qxd 8/3/2001 6:22 PM Page 420

420 22. óra

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óbejegy-


zé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
22_ora.qxd 8/3/2001 6:22 PM Page 421

Hibakeresés 421

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 "<p>\$valtozo: $valtozo</p>";

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 "<p>".__LINE__.": \$teszt értéke: $teszt</p>";

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 fejlesz-
té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: <?php
2: function debug( $sor, $uzenet)
3: { 22
4: static $hivasok = 1;
5: print "<P><HR>\n";
6: print "DEBUG $hivasok: $sor. sor: $uzenet<br>";
7: $argumentumok = func_get_args();
8: if ( count( $argumentumok ) % 2 )
9: print "Páratlan számú paraméter!<BR>";
10: else
11: {
12: for ( $x=2; $x< count($argumentumok); $x += 2 )
13: {
14: print "&nbsp;&nbsp; \$$argumentumok[$x]: "
.$argumentumok[$x+1];
22_ora.qxd 8/3/2001 6:22 PM Page 422

422 22. óra

22.4. program (folytatás)

15: print " .... (".gettype(


$argumentumok[$x+1] ).")<BR>\n";
16: }
17: }
18: print "<hr><p></p>\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 vissza-
adott 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üze-
netet kell adnunk, ha páratlan számú elem érkezik a tömbben. Egyébként végig-
lé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.

22.4. ábra
A debug() függvény
használata
22_ora.qxd 8/3/2001 6:22 PM Page 423

Hibakeresés 423

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 progra-
mozó beleesik.

Észrevesszük a hibát a következõ kódrészletben?

$valtozo=0;
while ( $valtozo < 42 );
{
print "$valtozo<BR>";
$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
22
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övet-
kezni, 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 "<P>A \$proba értéke 4</P>\n";
}
22_ora.qxd 8/3/2001 6:22 PM Page 424

424 22. óra

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ön-
leges 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.


22_ora.qxd 8/3/2001 6:22 PM Page 425

Hibakeresés 425

Összefoglalás
A fejlesztés talán egyik leghálátlanabb része a hibakeresés. A megfelelõ módsze-
rekkel 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álto-
zókról. Az error_log() függvénnyel hibaüzeneteket írtunk ki fájlba és küld-
tünk el elektronikus levélben. Tanultunk a kézi hibakeresésrõl a fontosabb válto-
zó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éleg-
zetû programot létrehozni, amely elsõre tökéletesen mûködik. Használjunk modu-
lá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ál-
junk „bolondbiztos” kódot készíteni és ellenõrizzük mûködését szélsõséges körül-
mé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 22
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 rend-
szerünkrõl?

2. Melyik függvénnyel jeleníthetjük meg a színekkel kiemelt forráskódot


a böngészõablakban?
22_ora.qxd 8/3/2001 6:22 PM Page 426

426 22. óra

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.
23_ora.qxd 8/3/2001 6:23 PM Page 427

IV. RÉSZ
Összefoglaló példa
23. óra Teljes példa (elsõ rész)
24. óra Teljes példa (második rész)
23_ora.qxd 8/3/2001 6:23 PM Page 428
23_ora.qxd 8/3/2001 6:23 PM Page 429

23. ÓRA
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önyv-


tá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?


23_ora.qxd 8/3/2001 6:23 PM Page 430

430 23. óra

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írathat-
já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ése-
ket kell majd végrehajtani.

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.

A 23.1. ábra az alkalmazás felépítését mutatja.

23.1. ábra
Az alkalmazás
felépítése
23_ora.qxd 8/3/2001 6:23 PM Page 431

Teljes példa (elsõ rész) 431

Az új tagok a csatlakozas.php oldalon csatlakozhatnak a rendszerhez (itt je-


gyeztethetik 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 kiala-
kí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 (

23
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)
);
23_ora.qxd 8/3/2001 6:23 PM Page 432

432 23. óra

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 rendez-
vényét a déli városrészben tartja. Egy társadalmi csoport tarthat oktatási szeminári-
umot, 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ér-
jü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.


23_ora.qxd 8/3/2001 6:23 PM Page 433

Teljes példa (elsõ rész) 433

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ül-
mé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 23


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.
23_ora.qxd 8/3/2001 6:23 PM Page 434

434 23. óra

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 olda-
lakat 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.
23_ora.qxd 8/3/2001 6:23 PM Page 435

Teljes példa (elsõ rész) 435

A munkamenetek követése és az azonosítással kapcsolatos feladatokat ellátó függ-


vények számára egy újabb külsõ állományt használunk. A munkamenet-függvénye-
ket 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õ (<?php) és záró (?>) 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: <?php
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

13:
mezõt!<br>\n";
23
14: if ( $urlap["jelszo"] != $urlap["jelszo2"] )
15: $uzenet .= "A jelszavak nem
egyeznek!<br>\n";
16:
23_ora.qxd 8/3/2001 6:23 PM Page 436

436 23. óra

23.3. program (folytatás)


17: if ( strlen( $urlap["jelszo"] ) > 8 )
18: $uzenet .= "A jelszó hossza legfeljebb
19: 8 karakter lehet!<br>\n";
20:
21: if ( strlen( $urlap["nev"] ) > 8 )
22: $uzenet .= "A tagsági név hossza
legfeljebb
23: 8 karakter lehet!<br>\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!<br>\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: <html>
42: <head>
43: <title>Csatlakozás</title>
44: </head>
45:
46: <body>
47: <?php
48: include("kozosnav.inc");
49: ?>
50: <p>
51: <h1>Csatlakozás</h1>
23_ora.qxd 8/3/2001 6:23 PM Page 437

Teljes példa (elsõ rész) 437

23.3. program (folytatás)


52:
53: <?php
54: if ( $uzenet != "" )
55: {
56: print "<b>$uzenet</b><p>";
57: }
58: ?>
59:
60: <p>
61: <form action="<?php print $PHP_SELF;?>">
62: <input type="hidden" name="mitkelltenni"
value="csatlakozas">
63: <input type="hidden" name="<?php print
session_name() ?>"
64: value="<?php print session_id() ?>">
65: Tagsági név: <br>
66: <input type="text" name="urlap[nev]"
67: value="<?php print $urlap["nev"] ?>"
maxlength=8>
68: </p>
69: <p>
70: Jelszó: <br>
71: <input type="password" name="urlap[jelszo]"
value="" maxlength=8>
72: </p>
73: <p>
74: Jelszó megerõsítés: <br>
75: <input type="password" name="urlap[jelszo2]"
value="" maxlength=8>
76: </p>
77: <p>
78: <input type="submit" value="Rendben">
79: </p>
80:
81:
</form>
23
82: </body>
83: </html>

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
23_ora.qxd 8/3/2001 6:23 PM Page 438

438 23. óra

számos más oldalon találkozni fogunk. Az $uzenet célja egyrészt, hogy tartal-
mazza a hibaüzenetet, amit késõbb kiírhatunk a böngészõ számára, másrészt hasz-
ná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ál-
tatá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 ûr-
lapot 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ó hivatko-
zásokat tartalmazza.

23.4. program Részlet a kozosnav.inc fájlból


1: <p>
2: <a href="klubokinfo.php?<?php print SID
?>">Klubinformációk</a> |
3: <a href="esemenyekinfo.php?<?php print SID
?>">Eseményinformációk</a> |
4: <a href="csatlakozas.php?<?php print SID
?>">Csatlakozás</a> |
5: <a href="belepes.php?<?php print SID ?>">Belépés</a> |
6: <a href="index.php?<?php print SID ?>">Honlap</a>
7: </p>

Azzal, hogy a navigációs elemeket külön állományba helyezzük, egyetlen mozdu-


lattal módosíthatjuk a hivatkozásokat, illetve az elemek kinézetét a teljes alkalma-
zásra vonatkozóan.
23_ora.qxd 8/3/2001 6:23 PM Page 439

Teljes példa (elsõ rész) 439

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. Program-
jainkban í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 munkamenet-
azonosítót, mivel nem kívánjuk elveszteni azokat a látogatókat, akik nem tudnak
vagy nem akarnak sütiket fogadni.

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.

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õ

23
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.
23_ora.qxd 8/3/2001 6:23 PM Page 440

440 23. óra

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.
23_ora.qxd 8/3/2001 6:23 PM Page 441

Teljes példa (elsõ rész) 441

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õ olda-
lunk 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 munkame-
nethez 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 tag-
nak be kell majd állítania az újonnan bejegyzett klub részletes adatait.

A csatlakozas.php kimenetét a 23.2. ábrán láthatjuk.

23.2. ábra
A csatlakozas.php
kimenete

23
23_ora.qxd 8/3/2001 6:23 PM Page 442

442 23. óra

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: <?php
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!<br>\n";
13:
14: if ( ! sorLekeres( “teruletek”, “azonosito”,
$urlap["terulet"] ) )
15: $uzenet .= "KRITIKUS HIBA: A terület kód-
ja nem található!<br>";
16:
17: if ( ! sorLekeres( "tipusok", "azonosito",
$urlap["tipus"] ) )
18: $uzenet .= "KRITIKUS HIBA: A típus kódja
nem található!<br>";
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: }
23_ora.qxd 8/3/2001 6:23 PM Page 443

Teljes példa (elsõ rész) 443

23.8. program (folytatás)


28: else
29: {
30: $urlap = $klub_sor;
31: }
32: ?>
33:
34: <html>
35: <head>
36: <title>Klubinformációk frissítése</title>
37: </head>
38:
39: <body>
40: <?php
41: include("kozosnav.inc");
42: ?>
43: <h1>Klubinformációk frissítése</h1>
44: <?php
45: if ( $uzenet != "" )
46: {
47: print "<b>$uzenet</b><p>";
48: }
49: ?>
50:
51: <form action="<?php print $PHP_SELF;?>">
52: <input type="hidden" name="mitkelltenni"
value="frissites">
53: <input type="hidden" name="<?php print
session_name() ?>"
54: value="<?php print session_id() ?>">
55:
56: <p>
57: Klub neve: <br>
58: <input type="text" name="urlap[klubnev]"
59: value="<?php print
stripslashes($urlap["klubnev"]) ?>"> 23
60: </p>
61: <p>
62: Klub helye: <br>
63: <select name="urlap[terulet]">
64: <?php optionLista( "teruletek", $urlap["terulet"] ) ?>
23_ora.qxd 8/3/2001 6:23 PM Page 444

444 23. óra

23.8. program (folytatás)


65: </select>
66: </p>
67: <p>
68: Klub típusa: <br>
69: <select name="urlap[tipus]">
70: <?php optionLista( "tipusok", $urlap["tipus"])?>
71: </select>
72: </p>
73: <p>
74: Kapcsolattartó e-mail címe: <br>
75: <input type="text" name="urlap[email]"
76: value="<?php print
stripslashes($urlap["email"]) ?>">
77: </p>
78: <p>
79: Klub ismertetõje: <br>
80: <textarea name="urlap[ismerteto]" rows=5 cols=30
wrap="virtual">
81: <?php print stripslashes($urlap["ismerteto"]) ?>
82: </textarea>
83: </p>
84: <p>
85: <input type="submit" value="Rendben">
86: </p>
87: </form>
88:
89: </body>
90: </html>

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;
23_ora.qxd 8/3/2001 6:23 PM Page 445

Teljes példa (elsõ rész) 445

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"] ele-


mét használjuk arra, hogy a sorLekeres() függvény segítségével lekérjük a klub-
hoz 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ömb-
elemeivel. 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ések-
nek 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úljut-
hatna. 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õ egye-
zé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 23


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ügg-
vé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 szerepel-
tetjük a tagok menüjét is:
23_ora.qxd 8/3/2001 6:23 PM Page 446

446 23. óra

23.10. program kozosnav.inc


1: <p>
2: <a href="klubokinfo.php?<?php print SID ?>">
Klubinformációk</a> |
3: <a href="esemenyekinfo.php?<?php print SID ?>">
Eseményinformációk</a> |
4: <a href="csatlakozas.php?<?php print SID ?>">
Csatlakozás</a> |
5: <a href="belepes.php?<?php print SID ?>">Belépés</a> |
6: <a href="index.php?<?php print SID ?>">Honlap</a>
7: </p>
8: <?php
9: if ( $munkamenet["belepett"] )
10: {
11: ?>
12: <p>
13: <A HREF="klubfrissites.php?<?php print SID ?>”>
Klub részletei</A> |
14: <A HREF="esemenylista.php?<?php print SID ?>">
Bejegyzett események</A> |
15: <A HREF="esemenyfrissites.php?<?php print SID ?>">
Új esemény</A> |
16: <A HREF="tagmenu.php?<?php print SID ?>">
Tagok honlapja</A>
17: </p>
18: <?
19: }
20: ?>
21: <hr>

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ás-
ban 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.
23_ora.qxd 8/3/2001 6:23 PM Page 447

Teljes példa (elsõ rész) 447

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<p>";
8: return false;
9: }
10: while ( $egy_sor = mysql_fetch_row( $eredmeny ) ){
11: print "<option value=\"$egy_sor[0]\"";
12: if ( $azon == $egy_sor[0] )
13: print "SELECTED";
14: print ">$egy_sor[1]\n";
15: }
16: }

A függvény a $tabla paramétert használja, hogy kiválasszon minden sort


a teruletek vagy tipusok táblából. Ezután végiglépked minden soron az ered-
ménytáblában, kiírva egy HTML option elemet a böngészõ számára.
Ha a mysql_fetch_array() által visszaadott tömb elsõ eleme egyezik az $azon
paraméterben megadott azonosítóval, a SELECTED karakterláncot is kiírja. Ezzel
biztosítjuk, hogy a megfelelõ elem kerül alapbeállításban kiválasztásra az ûrlapon.

A PHP kódban, ahol ellenõrizzük a bevitt adatokat, elsõ feltételünk


az urlap["klubnev"] kitöltöttségének tényét vizsgálja. Ezután
az urlap["terulet"] és urlap["tipus"] értékek helyességét ellenõrizzük.
Ha az $uzenet változó ezeket követõen üres marad, tudjuk, hogy az adatok
a meghatározott feltételeknek eleget tesznek, ezért átadjuk azokat egy új függvény-
nek, a klubFrissites()-nek, amely végrehajtja a szükséges módosítást az adat-
bázisban. A függvény egy klubazonosítót, egy klubnevet, egy területet, egy típust,

23
egy e-mail címet és egy ismertetõt vár a klubok tábla számára.
23_ora.qxd 8/3/2001 6:23 PM Page 448

448 23. óra

23.12. program Részlet az adatbazis.inc fájlból


1: function klubFrissites( $azonosito, $klubnev,
$terulet, $tipus, $email,
$ismerteto )
2: {
3: global $kapcsolat;
4: $lekeres = "UPDATE klubok set klubnev='$klubnev',
terulet='$terulet', tipus='$tipus',
5: email='$email', ismerteto='$ismerteto' WHERE
azonosito='$azonosito'";
6: $eredmeny = mysql_query( $lekeres, $kapcsolat );
7: if ( ! $eredmeny )
8: die ( "klubFrissites hiba: ".mysql_error() );
9: }

Miután a sort frissítettük, a tagot a tagmenu.php oldalra küldhetjük.

Ha a tag az oldalt egy hivatkozásra kattintva vagy a böngészõjében lévõ könyvjelzõ-


vel érte el, a $mitkelltenni változó nem kerül beállításra és az ellenõrzést és
frissítést végzõ kód nem hajtódik végre. Még mindig van azonban egy feladatunk.
A $klub_sor asszociatív tömb tartalmazza a klub adatait, amit az azonositas()
függvénnyel töltöttünk fel. Ebben találhatók az adott klubhoz tartozó mezõnevek és
értékek az adatbázisból. Ezt a tömböt adjuk értékül az $urlap tömbnek, így bizto-
sítva, hogy az ûrlap alapbeállításban az adatbázisban található érvényes információ-
kat tartalmazza.

A 23.3. ábra a klubfrissites.php kimenetét mutatja.

23.3. ábra
A klubfrissites.php
kimenete
23_ora.qxd 8/3/2001 6:23 PM Page 449

Teljes példa (elsõ rész) 449

tagmenu.php
A tagmenu.php a tagok területének központja. Alapvetõen hivatkozások listájából
áll, de a tagok számára fontos hírek és ajánlatok is helyet foglalhatnak az oldalon.

23.13. program tagmenu.php


1: <?php
2: include("adatbazis.inc");
3: include("kozosfv.inc");
4:
5: $klub_sor = azonositas();
6: klubAdatEllenorzes( $klub_sor );
7: ?>
8:
9: <html>
10: <head>
11: <title>Üdvözlet!</title>
12: </head>
13:
14: <body>
15: <?php
16: include("kozosnav.inc");
17: ?>
18:
19: <h1>Tagok honlapja</h1>
20:
21: <a href="klubfrissites.php?<?php print SID ?>">
Klub részletei</a><br>
22: <a href="esemenylista.php?<?php print SID ?>">
Bejegyzett események</a><br>
23: <a href="esemenyfrissites.php?<?php print SID ?>">
Új esemény</a><br>
24:

23
25: </body>
26: </html>

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 rendez-
vényeket a rendszerhez.
23_ora.qxd 8/3/2001 6:23 PM Page 450

450 23. óra

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: <?php
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!<br>\n";
11:
12: if ( ! ( $sor_tomb =
13: jelszoEllenorzes( $urlap["nev"],
$urlap["jelszo"] ) ) )
14: $uzenet .= "Hibás név vagy jelszó, próbál-
kozzon újra!<br>\n";
15:
23_ora.qxd 8/3/2001 6:23 PM Page 451

Teljes példa (elsõ rész) 451

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: <html>
26: <head>
27: <title>Belépés</title>
28: </head>
29:
30: <body>
31:
32: <?php
33: include("kozosnav.inc");
34: ?>
35:
36: <h1>Belépés</h1>
37:
38: <?php
39: if ( $uzenet != "" )
40: {
41: print "<p><b>$uzenet</b></P>";
42: }
43: ?>
44:
45: <p>
46: <form action="<?php print $PHP_SELF;?>">
47: <input type="hidden" name="mitkelltenni"

48:
value="belepes">
<input type="hidden" name="<?php
23
print session_name() ?>"
49: value="<?php print session_id() ?>">
50: </p><p>
51: Tagsági név: <br>
52: <input type="text" name="urlap[nev]"
53: value="<?php print $urlap["nev"] ?>">
23_ora.qxd 8/3/2001 6:23 PM Page 452

452 23. óra

23.15. program (folytatás)


54: </p><p>
55: Jelszó: <br>
56: <input type="password" name="urlap[jelszo]"
value="">
57: </p><p>
58: <input type="submit" value="Rendben">
59: </form>
60:
61: </body>
62: </html>

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: }
23_ora.qxd 8/3/2001 6:23 PM Page 453

Teljes példa (elsõ rész) 453

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: <?php
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" )
23
18: {
19: if ( empty( $urlap["enev"] ) )
20: $uzenet .="Az eseménynek névvel kell
rendelkeznie!<br>\n";
21:
23_ora.qxd 8/3/2001 6:23 PM Page 454

454 23. óra

23.17. program (folytatás)


22: if ( ! sorLekeres( "teruletek", "azonosito",
$urlap["eterulet"] ) )
23: $uzenet .= "KRITIKUS HIBA: A terület
kódja nem található!<br>";
24:
25: if ( ! sorLekeres( "tipusok", "azonosito",
$urlap["etipus"] ) )
26: $uzenet .= "KRITIKUS HIBA: A típus
kódja nem található!<br>";
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: }
23_ora.qxd 8/3/2001 6:23 PM Page 455

Teljes példa (elsõ rész) 455

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: <html>
67: <head>
68: <title>Esemény hozzáadása/frissítése</title>
69: </head>
70: <body>
71:
72: <?php
73: include("kozosnav.inc");
74: ?>
75:
76: <h1>Esemény hozzáadása/frissítése</h1>
77:
78: <?php
79: if ( $uzenet != "" )
80: {
81: print "<b>$uzenet</b>";
82: }
83: ?>
84:
85:
<p>
<form action="<?php print $PHP_SELF;?>">
23
86: <input type="hidden" name="mitkelltenni"
value="esemenyFrissites">
87: <input type="hidden" name="<?php
print session_name() ?>"
88: value="<?php print session_id() ?>">
23_ora.qxd 8/3/2001 6:23 PM Page 456

456 23. óra

23.17. program (folytatás)


89: <input type="hidden" name="eazonosito"
90: value="<?php print $eazonosito ?>">
91: Esemény neve: <br>
92: <input type="text" name="urlap[enev]"
93: value="<?php print
stripslashes($urlap["enev"]) ?>">
94: </p>
95: <p>
96: Dátum és idõ: <br>
97: <select name="urlap[ehonap]">
98: <?php honapLehetosegek( $edatum ) ?>
99: </select>
100:
101: <select name="urlap[enap]">
102: <?php napLehetosegek( $edatum ) ?>
103: </select>
104:
105: <select name="urlap[eev]">
106: <?php evLehetosegek( $edatum ) ?>
107: </select>
108:
109: <select name="urlap[eora]">
110: <? oraLehetosegek( $edatum ) ?>
111: </select>
112:
113: <select name="urlap[eperc]">
114: <? percLehetosegek( $edatum ) ?>
115: </select>
116: </p>
117: <p>
118: Esemény helye: <br>
119: <select name="urlap[eterulet]">
120: <?php optionLista( "teruletek",
$urlap["eterulet"] ) ?>
121: </select>
122: </p>
123: <p>
124: Esemény típusa: <br>
125: <select name="urlap[etipus]">
126: <?php optionLista( "tipusok", $urlap["etipus"])?>
127: </select>
23_ora.qxd 8/3/2001 6:23 PM Page 457

Teljes példa (elsõ rész) 457

23.17. program (folytatás)


128: </p>
129: <p>
130: Esemény ismertetõje: <br>
131: <textarea name="urlap[eismerteto]" wrap="virtual"
rows=5 cols=30>
132: <?php print stripslashes($urlap["eismerteto"]) ?>
133: </textarea>
134: </p>
135: <p>
136: Helyszín: <br>
137: <input type="text" name="urlap[ehelyszin]"
138: value="<?php print
stripslashes($urlap["ehelyszin"])?>">
139: </p>
140: <p>
141: Helyszín címe: <br>
142: <textarea name="urlap[ecim]" wrap="virtual"
rows=5 cols=30>
143: <?php print stripslashes($urlap["ecim"]) ?>
144: </textarea>
145: </p>
146: <p>
147: Helyszín irányítószáma: <br>
148: <input type="text" name="urlap[eirsz]"
149: value="<?php print
stripslashes($urlap["eirsz"]) ?>">
150: </p>
151: <p>
152: <input type="submit" value="Rendben">
153: </p>
154: </form>
155:
156: </body>
157: </html>
23
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,
23_ora.qxd 8/3/2001 6:23 PM Page 458

458 23. óra

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últ-
beli é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: {
23_ora.qxd 8/3/2001 6:23 PM Page 459

Teljes példa (elsõ rész) 459

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 tehet-
jü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 megfele-
lõ adatokat adjuk értékül a $klub_sor tömbbõl. Ezzel a megfelelõ lenyíló me-
nü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 23
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 jelez-
zék. Az alapbeállításban kiválasztandó értéket már elhelyeztük az $edatum válto-
zó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.
23_ora.qxd 8/3/2001 6:23 PM Page 460

460 23. óra

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 "<OPTION
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 "<OPTION VALUE=\"$x\"";
19: print ( ( $datum_tomb["mday"] ==
$x )?"SELECTED":"" );
20: print ">$x\n";
21: }
22: }
23:
24: function evLehetosegek( $datum )
25: {
26: $datum_tomb = getDate( $datum );
27: $most_tomb = getDate(time());
28: for ( $x = $most_tomb["year"];
$x <= ($most_tomb["year"]+5); $x++ )
29: {
30: print "<OPTION VALUE=\"$x\"";
23_ora.qxd 8/3/2001 6:23 PM Page 461

Teljes példa (elsõ rész) 461

23.19. program (folytatás)


31: print ( ( $datum_tomb["year"] ==
$x )?"SELECTED":"" );
32: print ">$x\n";
33: }
34: }
35:
36: function oraLehetosegek( $datum )
37: {
38: $datum_tomb = getDate( $datum );
39: for ( $x = 0; $x< 24; $x++ )
40: {
41: print "<OPTION VALUE=\"$x\";
42: print ( ( $datum_tomb["hours"] ==
$x)?"SELECTED”:"" );
43: print ">".sprintf("%'02d",$x)."\n";
44: }
45: }
46:
47: function percLehetosegek( $datum )
48: {
49: $datum_tomb = getDate( $datum );
50: for ( $x = 0; $x<= 59; $x++ )
51: {
52: print "<OPTION VALUE=\"$x\"";
53: print ( ( $datum_tomb["minutes"] ==
$x )?"SELECTED":"" );
54: print ">".sprintf("%'02d",$x)."\n";
55: }
56: }

Minden függvény egy idõbélyeget vár és HTML OPTION elemek listáját írja ki.
A getDate() PHP függvényt használják arra, hogy az idõbélyeg megfelelõ

23
elemének indexét megállapítsák (év, hónap, hónap napja, óra, perc). Ezután
a kapott számot összehasonlítják az alkalmazott tartomány értékeivel (a tartomány
a hónap napjainál 1-tõl 31-ig, a perceknél 0-tól 59-ig terjed). Ha egyezést észlel-
nek, a SELECTED jelzõt adják az OPTION elemhez, így választják ki a megfelelõ
sort.

A 23.4. ábra az esemenyfrissites.php kimenetét mutatja.


23_ora.qxd 8/3/2001 6:23 PM Page 462

462 23. óra

23.4. ábra
Az esemenyfrissites.php
kimenete

esemenylista.php
Végül biztosítanunk kell a tagoknak egy oldalt, ahol minden általuk bevitt ese-
ményt végigtekinthetnek. Ennek az oldalnak lehetõséget kell adnia arra is, hogy
a tagok az eseményeket szerkeszthessék vagy törölhessenek egyet.
Az esemenylista.php az eddigiek ismeretében egyszerû program.

23.20. program esemenylista.php


1: <?php
2: include("adatbazis.inc");
3: include("kozosfv.inc");
4: $klub_sor = azonositas();
5: klubAdatEllenorzes( $klub_sor );
6:
7: function esemenyKiiras()
8: {
9: global $klub_sor;
10: $esemenyek = esemenyekLekeres
( $klub_sor["azonosito"] );
11: if ( ! $esemenyek )
12: {
13: print "Nincs esemény a listában<P>";
14: return;
15: }
23_ora.qxd 8/3/2001 6:23 PM Page 463

Teljes példa (elsõ rész) 463

23.20. program (folytatás)


16: print "<table border=1>\n";
17: print "<td><b>Dátum</b></td>\n<td>
<b>Név</b></td>\n
18: <td><b>&nbsp;</b></td>\n";
19: foreach ( $esemenyek as $sor )
20: {
21: print "<tr>\n";
22: print "<td>".date("j M Y H.i",
$sor["edatum"])."</td>\n";
23: print "<td><a href=
\"esemenyfrissites.php?eazonosito=".
$sor["eazonosito"]."&".SID."\">".
24: html($sor["enev"])."</a></td>\n";
25: print "<td><a href=\"".
$GLOBALS["PHP_SELF"]."?eazonosito=".
$sor["eazonosito"];
26: print "&mitkelltenni=
esemenyTorles&".SID."\" ";
27: print "onClick=\"return
window.confirm('Biztos benne, hogy
törli ezt az eseményt?')\">";
28: print "törlés</a><br></td>\n";
29: print "</tr>\n";
30: }
31: print "</table>\n";
32: }
33: $uzenet="";
34:
35: if ( isset( $mitkelltenni ) &&
36: $mitkelltenni == "esemenyTorles" &&
isset( $eazonosito ) )
37: {
38: esemenyTorles( $eazonosito );
39: $uzenet .= "Az esemény törlése

40: }
megtörtént!<br>";
23
41:
42: ?>
43: <html>
44: <head>
45: <title>Események listája</title>
46: </head>
23_ora.qxd 8/3/2001 6:23 PM Page 464

464 23. óra

23.20. program (folytatás)


47: <body>
48: <?php
49: include("kozosnav.inc");
50: ?>
51: <h1>Események listája</h1>
52: <?php
53: if ( $uzenet != "" )
54: {
55: print "<b>$uzenet</b>";
56: }
57: ?>
58:
59: <?php
60: esemenyKiiras();
61: ?>
62:
63: </body>
64: </html>

Szokás szerint az adatbazis.inc fájlt használjuk, hogy kész adatbáziskapcsolat-


tal kezdjük az oldalt és a kozosfv.inc fájlt, hogy aktív munkamenetünk legyen.
Úgyszintén a megszokott módon ellenõrizzük, hogy érvényes tag kérte-e le
az oldalt. Ezután létrehozunk egy új esemenyKiiras() nevû függvényt, amely
közvetlenül a böngészõbe írja az eseményrõl elérhetõ információkat. Emlékez-
zünk rá, hogy az azonositas() függvény által visszaadott $klub_sor tömb
tartalmazza a klubadatokat. A $klub_sor["azonosito"] értéket használhat-
juk arra, hogy a klubhoz tartozó összes rendezvényt listába írjuk. Ehhez
az adatbazis.inc esemenyekLekeres() függvényét használjuk. Ezt a függ-
vényt alaposabban a következõ órában tárgyaljuk, egyelõre elegendõ annyit tud-
nunk, hogy egy klubazonosítót vár elsõ paraméteréül, így egy kétdimenziós tömb-
ben adja vissza a klubhoz tartozó összes esemény minden adatát.

A függvény visszatérési értékét az $esemenyek tömbben tároljuk. Valójában több


adatot kérünk le, mint amennyire szükségünk van, de az esemenyekLekeres()
függvény olyan rugalmas, hogy nyugodtan használhatjuk, hacsak nem érzékelünk
teljesítménybeli problémákat a program futása során. Ha az $esemenyek hamis
értékû, figyelmeztetõ üzenetet küldünk a kimenetre és befejezzük a függvény futá-
sát. Egyéb esetben egy HTML táblázatot építünk fel: végiglépkedve az $esemenyek
tömbön kiírunk minden eseményre vonatkozóan néhány információt.
23_ora.qxd 8/3/2001 6:23 PM Page 465

Teljes példa (elsõ rész) 465

A date() PHP függvénynek átadva minden tömb edatum elemét, formázott dátu-
mokat írunk ki. A dátum mellett minden esemény számára egy hivatkozást hozunk
létre, felhasználva az esemény azonosítóját és az enev értéket. Az átadandó
eazonosito változó mellett szerepeltetjük a SID állandót, így biztosítva, hogy
a munkamenet érvényes marad az új oldalon is. A hivatkozás
az esemenyfrissites.php oldalra mutat, amely így meg tudja jeleníteni az ese-
mény adatait a szerkesztés számára. Végül minden rendezvény sorában egy erre
az oldalra visszamutató hivatkozást is szerepeltetünk. Ehhez az eazonosito mellett
egy esemenyTorles értékû mitkelltenni paramétert is meghatározunk.
Ez az adott esemény törlésére szolgál majd, ezért egy JavaScript eseménykezelõt is
adunk a hivatkozáshoz, hogy ne lehessen véletlenül törölni egy rendezvényt sem.

Miután elkészítettük az esemenyKiiras() függvényt, kezelnünk kell azt


az esetet is, amikor a tag törölni kíván egy eseményt. Ezt a $mitkelltenni és
az $eazonosito változók ellenõrzésével tehetjük meg. Ha rendben megkaptuk
ezeket, egy új adatbazis.inc függvényt, az esemenyTorles()-t hívjuk meg,
átadva az $eazonosito értéket.

23.21. program Részlet az adatbazis.inc fájlból


1: function esemenyTorles( $eazonosito )
2: {
3: global $kapcsolat;
4: $lekeres = "DELETE FROM esemenyek WHERE
eazonosito='$eazonosito'";
5: $eredmeny = mysql_query( $lekeres, $kapcsolat );
6: if ( ! $eredmeny )
7: die ( "esemenyTorles hiba: ".mysql_error() );
8: return ( mysql_affected_rows($kapcsolat) );
9: }

Az esemenylista.php egy lehetséges kimenetét a 23.5. ábra mutatja.

23
23_ora.qxd 8/3/2001 6:23 PM Page 466

466 23. óra

23.5. ábra
Az esemenylista.php
kimenete

Összefoglalás
Az óra végére elkészültünk a teljesen mûködõ, tagok számára készült környezettel
a rendezvényeket nyilvántartó rendszerhez. Lehetõséget teremtettünk grafikusa-
inknak az oldalak jó kialakítására, azzal, hogy a lehetõ legtöbb kódot külsõ állo-
mányokban helyeztük el. Gyakran használtuk a header() függvényt, hogy
új oldalra irányítsuk a tagot, ha adatokat várunk tõle. A belépési információk táro-
lásához munkamenet-kezelõ függvényeket, a tagok azonosításához adatbázis-
lekérdezéseket használtunk minden oldalon.

A következõ órában hasonló megoldásokat fogunk használni a program nyilvános


felületének kialakításához.

Kérdések és válaszok
A több oldalból álló alkalmazások megtervezése és karbantartása bonyo-
lultnak tûnik. Van valami titok emögött?
A példaalkalmazás elkészítése során majdnem minden oldalon egyszerû mintát
követtünk. Ahogy alkalmazásaink nagyobbá válnak, a teljes környezetrõl egyetlen
programként kell gondolkodnunk. A különálló oldalak csak a látogató csatlakozá-
si pontjai az egész alkalmazáshoz. Tartsuk az összes egynél több oldalon ismétlõ-
dõ kódot külön állományban!
23_ora.qxd 8/3/2001 6:23 PM Page 467

Teljes példa (elsõ rész) 467

Ha esetleg úgy döntünk, hogy egyetlen központi programot készítünk a teljes alkal-
mazás számára, egy egyszerû, alapvetõ HTML elemeket tartalmazó oldalt kell készí-
tenünk. Minden más tartalom dinamikusan áll majd elõ a program futása során.
Szükségünk lesz egy mitkelltenni típusú változóra, amely mindig a megfelelõ
szolgáltatást választja ki a teljes alkalmazásból. Ez sokkal formásabbá teheti a kódot
és segít elkerülni a nem túl elegáns Location fejléctrükköt. Másrészt ez azzal jár,
hogy sokkal több HTML-t kell beépítenünk a PHP kódok közé.

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 PHP függvényt használjuk arra, hogy MySQL adatbázishoz
csatlakozzunk?

2. Melyik függvényt alkalmazzuk a munkamenet elkezdésére vagy folytatására?

3. Melyik függvény alkalmas arra, hogy külsõ állományokat illesszünk a PHP


kódba?

4. Melyik PHP függvénnyel küldünk SQL kéréseket egy MySQL adatbázis


számára?

5. Melyik állandót alkalmazhatjuk arra, hogy a munkafolyamat-azonosítót


eljuttassuk egyik oldalról a másikra egy HTML hivatkozásban?

6. Hogyan küldhetjük tovább a látogatót egy másik oldalra?

7. Melyik függvény alkalmas dátumok formázására?

Feladatok
1. Tekintsünk végig az órában tárgyalt forráskódokon. Találunk olyan megoldá- 23
sokat, amelyeket saját programjainkban is tudunk majd hasznosítani?
23_ora.qxd 8/3/2001 6:23 PM Page 468
24_ora.qxd 8/3/2001 6:23 PM Page 469

24. ÓRA
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 munkamenet-


függvényekkel?

• Hogyan kell átalakítanunk az egyszerû szöveges adatokat, hogy


a HTML kódba írhassuk azokat?
24_ora.qxd 8/3/2001 6:23 PM Page 470

470 24. óra

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: <?php
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"] );
24_ora.qxd 8/3/2001 6:23 PM Page 471

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

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<p>";
30: return;
31: }
32: print "<table border=1>\n";
33: print "<td><b>Dátum</b></td>\n";
34: print "<td><b>Esemény</b></td>\n";
35: print "<td><b>Klub</b></td>\n";
36: print "<td><b>Terület</b></td>\n";
37: print "<td><b>Típus</b></td>\n";
38: foreach ( $esemenyek as $sor )
39: {
40: print "<tr>\n";
41: print "<td>".date("j M Y H.i",
$sor["edatum"])."</td>\n";
42: print "<td><a
href=\"esemenyinfo.php?eazonosito=".
$sor["eazonosito"]."&".SID."\">".
43: html($sor["enev"])."</a></td>\n";
44: print "<td><a href=\"klubinfo.php?kazonosito=".
$sor["eklub"]."&".SID."\">".
45: html($sor["klubnev"])."</a></td>\n";
46: print "<td>".$sor["teruletnev"]."</td>\n";
47: print "<td>".$sor["tipusnev"]."</td>\n";
48: print "</tr>\n";
49: }
50: print "</table>\n";
51: }
52: ?>
53:
54: <html>
55:
56:
<head>
<title>Esemény információk</title>
24
24_ora.qxd 8/3/2001 6:23 PM Page 472

472 24. óra

24.1. program (folytatás)


57: </head>
58: <body>
59: <?php
60: include("kozosnav.inc");
61: ?>
62: <h1>Esemény információk</h1>
63: <p>
64: <form action="<?php print $PHP_SELF;?>">
65: <input type="hidden" name="mitkelltenni"
value="esemenyLista">
66: <input type="hidden"
name="<?php print session_name() ?>"
67: value="<?php print session_id() ?>">
68: <select name=urlap[honap]>
69: <?php honapLehetosegek( $idoszak[0] ); ?>
70: </select>
71:
72: <select name=urlap[ev]>
73: <?php evLehetosegek( $idoszak[0] ); ?>
74: </select>
75:
76: <select name=urlap[terulet]>
77: <option value="BÁRMELY">Bármely terület
78: <?php optionLista( "teruletek", $urlap["terulet"]) ?>
79: </select>
80:
81: <select name=urlap[tipus]>
82: <option value="BÁRMELY">Bármely típus
83: <?php optionLista( "tipusok", $urlap["tipus"] ) ?>
84: </select>
85:
86: <input type = "submit" value="Listázás">
87: </form>
88: </p>
89:
90: <?php
91: esemenyLista( );
92: ?>
93:
94: </body>
95: </html>
24_ora.qxd 8/3/2001 6:23 PM Page 473

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

Szokás szerint az adatbazis.inc és a kozosfv.inc külsõ állományok beil-


leszté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 asszoci-
atí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 munkame-


nethez (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 eset-
ben 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 tartal-
maznak, akár ûrlapértékekbõl, akár korábbi beállításból, akár az aktuális dátum-
bó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éte-
reket vár és két idõbélyeggel tér vissza, megjelölve a hónap kezdetét és végét. 24
24_ora.qxd 8/3/2001 6:23 PM Page 474

474 24. óra

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ó tulaj-
donsá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) )
24_ora.qxd 8/3/2001 6:23 PM Page 475

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

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áb-
lá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 24
figyelmen kívül maradnak, ha a "BÁRMELY" karakterláncot tartalmazzák.
24_ora.qxd 8/3/2001 6:23 PM Page 476

476 24. óra

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 para-
mé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 felhasz-
ná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 infor-
máció érhetõ el egy rendezvényrõl. Ehhez az esemény azonosítóját és a SID állan-
dó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ény-
ben, ahogy az események információin végiglépkedünk, ismét a html() függ-
vényt hívjuk meg. Ez az általunk írt függvény a kozosfv.inc állományban talál-
ható. 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é alakul-
nak, az újsor karakterek például <br>-é.

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:
24_ora.qxd 8/3/2001 6:23 PM Page 477

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

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 karak-
terlá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 <br> 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.

24.1. ábra
Az esemenyekinfo.php
kimenete

24
24_ora.qxd 8/3/2001 6:23 PM Page 478

478 24. óra

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: <?php
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<p>\n";
22: return;
23: }
24: print "<table border=1>\n";
25: print "<td><b>Klub</b></td>\n";
26: print "<td><b>Terület</b></td>\n";
27: print "<td><b>Típus</b></td>\n";
28: foreach ( $klubok as $sor )
29: {
30: print "<tr>\n";
24_ora.qxd 8/3/2001 6:23 PM Page 479

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

24.5. program (folytatás)


31: print "<td><a
href=\"klubinfo.php?[kazonosito]=".
$sor["azonosito"]."&".SID."\">".
32: html($sor["klubnev"])."</a></td>\n";
33: print "<td>$sor["teruletnev"]</td>\n";
34: print "<td>$sor["tipusnev"]</td>\n";
35: print "</tr>\n";
36: }
37: print "</table>\n";
38: }
39: ?>
40: <html>
41: <head>
42: <title>Klub információk</title>
43: </head>
44: <body>
45: <?php
46: include("kozosnav.inc");
47: ?>
48: <P>
49: <h1>Klub információk</h1>
50: <p>
51: <form action="<?php print $PHP_SELF;?>">
52: <input type="hidden" name="mitkelltenni"
value="klubLista">
53: <input type="hidden" name="<?php print
session_name() ?>"
54: value="<?php print session_id() ?>">
55: <select name=urlap["terulet"]>
56: <option value="BÁRMELY">Bármely terület
57: <?php optionLista( "teruletek",
$urlap[terulet] ) ?>
58: </select>
59: <select name=urlap[tipus]>
60: <option value="BÁRMELY">Bármely típus
61: <?php optionLista( "tipusok", $urlap["tipus"] ) ?>
62: </select>
63: <input type = "submit" value="Rendben">
64: </form>
24
24_ora.qxd 8/3/2001 6:23 PM Page 480

480 24. óra

24.5. program (folytatás)


65: </p>
66: <?php
67: klubLista( );
68: ?>
69: </body>
70: </html>

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() );
24_ora.qxd 8/3/2001 6:23 PM Page 481

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

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étdi-
menzió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 megte-
kinté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: <?php
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"] != "" )

24
10: $klub["email"] = "<A HREF=\"mailto:$klub[email]\
">".$klub["email"]."</A>";
24_ora.qxd 8/3/2001 6:23 PM Page 482

482 24. óra

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<P>";
18: return;
19: }
20: print "<table border=1>\n";
21: print "<td><b>Dátum</b></td>\n";
22: print "<td><b>Esemény</b></td>\n";
23: print "<td><b>Terület</b></td>\n";
24: print "<td><b>Típus</b></td>\n";
25: foreach ( $esemenyek as $sor )
26: {
27: print "<tr>\n";
28: print "<td>".date("j M Y H.i",
$sor["edatum"])."</td>\n";
29: print "<td><a
href=\"esemenyinfo.php?eazonosito=".
$sor["eazonosito"]."&".SID."\">".htm
l($sor["enev"])."</a></td>\n";
30: print "<td>".$sor["teruletnev"]."</td>\n";
31: print "<td>".$sor["tipusnev"]."</td>\n";
32: print "</tr>\n";
33: }
34: print "</table>\n";
35: }
36: ?>
37: <html>
38: <head>
39: <title>Klub részletek</title>
40: </head>
41: <body>
42: <?php
43: include("kozosnav.inc");
44: ?>
45: <p>
46: <h1>Klub részletek</h1>
47: <h4><?php print $klub["klubnev"] ?></h4>
24_ora.qxd 8/3/2001 6:23 PM Page 483

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

24.7. program (folytatás)


48: <p>
49: Terület: <b><?php print $klub["teruletnev"] ?></b>
50: <br>
51: Típus: <b><?php print $klub["tipusnev"] ?></b>
52: <br>
53: Email: <b><?php print $klub["email"] ?></b>
54: </p>
55: Ismertetõ:<br>
56: <b><?php print $klub["ismerteto"] ?></b>
57: <hr>
58: <?php
59: klubEsemenyei();
60: ?>
61: </body>
62: </html>

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:
13:
return mysql_fetch_array( $eredmeny );
}
24
24_ora.qxd 8/3/2001 6:23 PM Page 484

484 24. óra

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.

24.2. ábra
A klubinfo.php kime-
nete

esemenyinfo.php
Az esemenyinfo.php az utolsó oldal, amit az alkalmazáshoz el kell készíte-
nü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.
24_ora.qxd 8/3/2001 6:23 PM Page 485

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

24.9. program esemenyinfo.php


1: <?php
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: <html>
10: <head>
11: <title>Esemény részletei</title>
12: </head>
13: <body>
14: <?php
15: include("kozosnav.inc");
16: ?>
17: <P>
18: <h1>Esemény részletei</h1>
19: <h4><?php print $esemeny["enev"] ?></h4>
20: <p>
21: Klub:
22: <b>
23: <?php print "<a href=\"klubinfo.php?kazonosito=".
$esemeny["eklub"]."&".SID."\">
24: $esemeny["klubnev"]</a>"
25: ?>
26: </b>
27: <br>
28: Terület: <b><?php print $esemeny["teruletnev"]?></b>
29: <br>
30: Típus: <b><?php print $esemeny["tipusnev"] ?></b>
31: </p>
32: Ismertetõ:<br>
33: <?php print $esemeny["eismerteto"] ?>
34: </body>
35: </html>

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észle- 24
teit. Miután ezek egy tömbben rendelkezésre állnak, már csak ki kell írnunk azokat
a böngészõbe.
24_ora.qxd 8/3/2001 6:23 PM Page 486

486 24. óra

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 munkamenet-
függvények nélkül feltehetõen sokkal több információt kellett volna kérésrõl-
kérésre átadnunk oldalainknak az URL-ekben.
24_ora.qxd 8/3/2001 6:23 PM Page 487

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

Bár az eseménynaptár bizonyos megközelítésbõl teljesnek tekinthetõ, mindazo-


ná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áto-
gató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 rendez-


vé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 karban-


tartó felületre, amely alkalmas arra, hogy egy technikailag képzetlen adminiszt-
rá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 grafi-
ká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 oldot-
tunk 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.

24
24_ora.qxd 8/3/2001 6:23 PM Page 488

488 24. óra

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 HTML-


kiírás céljából?

4. Melyik függvény alakítja át az újsor karaktereket <br> elemekké?

5. A SID állandó a munkamenet-azonosító oldalról-oldalra küldéséhez hivat-


kozá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.

You might also like