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
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 megtudhatunk
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 kulcsok
és értékek elérhetõvé kell, hogy váljanak programunk
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:
2:
3: 13.1. program Néhány környezeti változó<br />felsorolása
4:
5:
6: 7: $korny_valtozok = array( "HTTP_REFERER",
"HTTP_USER_AGENT", "REMOTE_ADDR", "REMOTE_HOST",
"QUERY_STRING", "PATH_INFO" );
238 13. óra
13.1. program (folytatás)
8: foreach ( $korny_valtozok as $valtozo )
9: {
10: if ( isset( $$valtozo ) )
11: print "$valtozo: ${$valtozo}
";
12: }
13: ?>
14:
15:
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:
gyerünk
Amint láthatjuk, a hivatkozás relatív útvonalat használ a 13.1.program.php
meghívására.
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.
Kapcsolat a külvilággal 239
13 13.1. ábra
Néhány környezeti
változó kiíratása
a böngészõben
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árokb
ó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 megengedett
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 lehet
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 fejleszt
õ 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 adatokat
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
240 13. óra
a hatékonyság kedvéért gyakran letiltják. Ha nem létezne ilyen változó, az inform
á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önyv
ü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
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 kiszolg
áló információt szolgáltat magáról és a küldött adatokról. Ezen információk legt
ö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 legfeljebb
három részbõl állhat:
• A kérés sora
• 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áírjuk
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öbbsz
ör HTML ûrlapok esetében használatos.
ÚJDONSÁG
Kapcsolat a külvilággal 241
13
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 tartalmazza
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.
242 13. óra
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
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.
Kapcsolat a külvilággal 243
13
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.
244 13. óra
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:
8:
9: 13.3. lista A kiszolgáló válasza
10:
11:
12: Üdvözlet!
13:
14:
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
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:
2:
3: 13.4. program Weboldal letöltése és megjelen<br />ítése az fopen()-nel
4:
5:
6: 7: $weboldal = "http://www.php.net/index.php";
8: $fajlmutato = fopen( $weboldal, "r" ) or
die("A $weboldal nem nyitható meg");
Kapcsolat a külvilággal 245
13
13.4. program (folytatás)
9: while ( ! feof( $fajlmutato ))
10: print fgets( $fajlmutato, 1024 );
11: ?>
12:
13:
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álhat
ó 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:

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ájuthatunk
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-
246 13. óra
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:
2:
3: 13.5. program Gépnév lekérdezése<br />a gethostbyaddr() segédletével
4:
5:
6: 7: if ( isset( $REMOTE_HOST ) )
8: print "Üdvözöljük $REMOTE_HOST
";
9: elseif ( isset ( $REMOTE_ADDR ) )
10: print " Üdvözöljük
".gethostbyaddr( $REMOTE_ADDR )."
";
11: else
12: print " Üdvözöljük, akárki is Ön.
";
13: ?>
14:
15:
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, által
á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.
Kapcsolat a külvilággal 247
13
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áltoz
ó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ájlmutat
ó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 hibak
ó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íthess
ünk egy webkiszolgálóval. A 13.6-os programban megnyitunk egy HTTP kapcsolatot,
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:
2:
3: 13.6. program Weboldal lekérése az fsockopen()<br />használatával
4:
5:
6: 7: $kiszolgalo = "www.kiskapu.hu";
8: $lap = "/index.html";
9: $fajlmutato = fsockopen( "$kiszolgalo", 80,
&$hibaszam, &$hibaszoveg);
10: if ( ! $fajlmutato )
248 13. óra
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:
25:
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
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 meghozniuk.
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.
Kapcsolat a külvilággal 249
13
13.7. program Az állapotsor megjelenítése webkiszolgálók válaszaiból
1:
2:
3: 13.7. program Az állapotsor megjelenítése<br />webkiszolgálók válaszaiból
4:
5:
6: 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
...
\n";
14: $fajlmutato = fsockopen( "$kiszolgalo", 80,
&$hibaszam, &$hibaszoveg, 10);
15: if ( ! $fajlmutato )
16: {
17: print "A $kiszolgalo géphez nem sikerült
csatlakozni:\n
A hiba kódja:
$hibaszam\n
Szövege: $hibaszoveg\n";
18: print "



\n";
19: continue;
20: }
21: print "A $lap oldal fejlécének letöltése ...
\n";
22: fputs( $fajlmutato, “HEAD $lap HTTP/1.0\r\n\r\n" );
23: print fgets( $fajlmutato, 1024 );
24: print "


\n";
25: fclose( $fajlmutato );
26: }
27: ?>
28:
29:
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,
250 13. óra
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ó.
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:
2:
3: 13.8. program Egyszerû NNTP kapcsolat az<br />fsockopen() használatával
4:
5:
6: 7: $kiszolgalo = "news"; // ezt saját hírkiszolgálónk
címére kell beállítanunk
Kapcsolat a külvilággal 251
13
13.2. ábra
Kiszolgálók válaszát
megjelenítõ program
13.8. program (folytatás)
8: $csoport = "alt.test";
9: $sor = "";
10: print "
\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: }
252 13. óra
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 "
";
51: ?>
52:
53:
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étl
é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ó ért
é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 csatlakozunk,
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 kiszolg
á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üggv
é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 tov
ábblépünk, egyébként pedig befejezzük a programot.
Ha minden az elvárásoknak megfelelõen haladt, akkor a "group" paranccsal kiv
álasztjuk a kívánt hírcsoportot. Ha ez is sikerült, a kiszolgálónak egy 211-es állapotk
óddal kezdõdõ szöveget kell válaszul küldenie. Ezt is ellenõrizzük és sikertelens
ég esetén kilépünk a programból.
Kapcsolat a külvilággal 253
13
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 esetben
is elõször egy nyugta érkezik, mely a 211-es állapotkódot kell, hogy tartalmazza.
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.
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üggv
é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";
254 13. óra
13.3. ábra
NNTP kapcsolat
megteremtése
Ha a PHP-t UNIX rendszeren futtatjuk, a Sendmailt fogja használni, más rendszereken
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écsorokat
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.
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 ismeret
é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 ismerete
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.
Kapcsolat a külvilággal 255
13
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 foglalkoznunk
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élprogramt
ó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?
256 13. óra
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.