Lássunk néhány érdekesebb, vagy fontosabb modult. A lista távolról sem teljes, csak ízelítőt akar adni a 2003 februári állapotról.
Név | Állapot | Leírás |
---|---|---|
Archive::Tar | alfa | Tar állományok létrehozására, és manipulálására szolgál. Lehet egy archív fájlhoz hozzáadni új fájlokat, törölni belőle régieket, listázni vagy kibontani külön-külön a fájlokat, vagy egyben az egészet. 32 bites Windows környezetben nem működik, de a függvényeit automatikusan helyettesítik az Archive::Tar::Win32 modul függvényei, így ilyen környezetben is használható. |
Archive::Zip | Kibocsátott | Minden amit egy zip fájllal megtehető. Önkicsomagoló állományokat is létre tud hozni, de nem használható gzip fájlokhoz, azokhoz külön modul van. Sok példaprogramot adnak hozzá. |
Compress::Bzip2 | Kibocsátott | BZip2 tömörítés |
Név | Állapot | Leírás |
---|---|---|
Math::BigIntFast | Kibocsátott | Gyors műveletek tetszőlegesen nagy egész számokon. Hibrid modul, azaz C kódot is tartalmaz a sebesség miatt. (A tisztán Perl változat, azaz a Math::BigInt standard modul) |
Math::BigRat | Kibocsátott | Tetszőlegesen nagy racionális számok, és műveleteik |
Math::Matrix | alfa | Mátrixok, és műveleteik. Alapműveletek, determináns-számítás, lineáris egyenletrendszer megoldása. |
Math::Logic | Kibocsátott | 2, 3 és többértékű logikai függvények |
Math::Polynomial | Kibocsátott | Polinomok, öszeadás, kivonás, szorzás, maradékos osztás |
Math::Polynomial::Solve | Kibocsátott | Legfeljebb negyedfokú polinomok gyökeinek meghatározása |
Math::Spline | Kibocsátott | Négyzetes spline interpoláció |
Math::Bezier | Kibocsátott | Bezier görbék megoldása Robert D. Miller algoritmusával. |
Math::FFT | alfa | Gyors Fourier Transzformáció |
Név | Állapot | Leírás |
---|---|---|
GD | alfa | Interfész a Gd grafikus könyvtárhoz. Jpg, png, xbm, bmp és más formátumú fájlokat tud írni és olvasni. Lehet vele primitíveket rajzolni (pont, vonal, poligon, ellipszis-ív stb), feliratokat tenni a képre, képeket összehasonlítani, egymásra másolni. C kódot is tartalmaz. |
GD::Graph | Kibocsátott | Két dimenziós grafikonokat rajzol a GD modul segítségével. Vonal-, oszlop-, terület-, tortadiagramokat készíthetünk vele. Utóbbiból 3d változatot is tud. |
Chart::Graph | Kibocsátott | Szintén grafikonok készítésére alkalmas, de a kimenete nem egy kép, hanem egy gnuplot, XRT, vagy Xmgrace által értelmezhető fájl. Így a modul használatához ezek valamelyike is szükséges, viszont kihasználhatjuk azok minden funkcióját. |
GIMP | Kibocsátott | Interfész az egyik(?) legnépszerűbb nyílt forrású rajzolóprogramhoz. |
Image::Thumbnail | Kibocsátott | A Gd modult használva előnézeti képek generálásra alkalmas. |
Image::WorldMap | Kibocsátott | Világtérképet rajzol, bejelöli rajta a megadott koordinátájú pontokat, és feliratozza őket, úgy, hogy a címkék lehetőleg ne fedjék egymást. |
Név | Állapot | Leírás |
---|---|---|
Convert::Translit | 8-bites karakterkonverziók az RFC 1345-nek megfelelően: ASCII, EBCDIC, latin1-2, IBM karakterkódolások, cirill kódolások stb, de csak egyet-egyre átalakításokat végez. | |
Date::* | Naptár átváltások Gregorián, kínai, egyiptomi, etióp, hindu, japán, hobbit stb. naptárak között. | |
Date::Calc | Kibocsátott | Gregorián naptárral végezhető rengeteg művelet |
AI::* | Kibocsátott | Mesterséges intelligencia: modulok Fuzzy logikához, genetikus algoritmusokhoz, mesterséges neuronhálókhoz. |
Astro::* | Asztronómiai számításokat végző modulok. Napkelte, napnyugta, holdfázisok, koordináta transzformációk | |
GSM::SMS | Kibocsátott | Sms küldés, és fogadás |
LEGO::RCX | LEGO-robot vezérlés infraporton keresztül | |
MP3::* | MP3 készítés, MP3-tag-ek lekérdezése, megváltoztatása, playlist generálás | |
Hook::PrePostCall | Ezzel a modullal egy Perl program normális futásába avatkozhatunk bele a kód módosítása nélkül. A modul lehetőséget ad arra, hogy megadjunk kódrészleteket, amik egy bizonyos szubrutin meghívása előtt, illetve lefutása után közvetlenül végrehajtódnak. | |
Hook::Scope | Az előzőhöz hasonló célú modul, ez arra ad lehetőséget, hogy egy névtelen szubrutin akkor fusson le, amikor a vezérlés elhagyja az a blokkot, amiben a szubrutin definiálva lett. A megadott kód akkor is lefut, ha a blokkot egy die() hatására hagyjuk el. |
Unix alatt, a rendszer által támogatott adatbázis eszköz a DBM, amely alkalmas kulcs-érték párokba szervezett információ tárolására két háttérállomány felhasználásával. Ehhez hasheken keresztül lehet hozzáférni, majd módosítani. Vagyis a hash egy fajta közvetítő az adatbázis rendszer és a programozó között.
DBM megnyitása:
dbmopen(%hash, "dbm", $mode); ahol
%hash: DBM-el összekötendő hash neve
"dbm": az adatbázis neve
$mode: a megnyitandó állomány hozzáférési
módja (írás/olvasás/futtatás)
DBM bezárása:
dbmclose(%hash) #elég, ha csak a
"közvetítőt" töröljük
DBM módosítása:
1.törlés: delete $emp{id};
2.módosítás: $emp{id} = "Robert"; #simán felülírjuk a régi bejegyzést
Fontos megjegyezni, hogy a DBM-et csak kulcs-érték
párok tárolása esetén tudjuk használni. Komplexebb problémáknál (ha
relációs adatbázis használata nem lehetséges) közvetlen hozzáférésű állományokat
kell használnunk.
Közvetlen hozzáférésű állományok
Fix hosszúságú, közvetlen hozzáférésű állományokat tudunk használni összetettebb adatbázis kezelésére. Adatokat egyforma hosszúságú rekordokban tároljuk. A "seek" paranccsal közvetlenül hozzá tudunk férni a rekordokhoz (nem vagyunk rákényszerítve a szekvenciális olvasásra).
Függvény --------> Szerepe
open ------------->Állomány megnyitása
binmode --------->Állománymutatót bináris módra állítja
seek-------------->A rekordmutató pozicionálása
pack ------------->Adatok méretre szabása íráshoz és olvasáshoz
unpack----------->Adatok feldarabolása alkotó részeire
print-------------->Adatok írása az állományba
read-------------->Adatok olvasása az állományból
Adatbázis-programozás Windows környezetben
Microsoft ActiveX Data Objects (ADO) és az ODBC
(Open Database Connectivity) felületeken keresztül létre tudunk hozni a
Perlből relációs adatbázist. Az ADO külső adatforrásokhoz való kapcsolódásnál
nyújt hozzáférési lehetőséget bizonyos objektumokhoz. Ezek a külső
adatforrások lehetnek Access vagy SQL szerverek. (ODBC adatelérési
technika a Win32::ABDC modulban van).
ActiveX Data Objects (ADO)
Az ADO egy könnyen használható adatbázis hozzáférési
réteget biztosít a felhasználó számára, amelyet a Perl használhat.
Az ADO lényegében az ODBC API egy leegyszerűsített változata, amely kevés
beállítható tulajdonsággal és az objektumokat vezérlő metódusokkal rendelkezik.
ADO modell
A modell egy hierachikusan felépített rendszer. Ennek külső objektumai a következők:
A második szinten vannak:
Ez alatt már csak egy réteg van, ahol a felette levő rétegben összegyűjtött egyéni objektumok jelennek meg.
Mivel objektumoknak elég sok metódusakkal illetve tulajdonságokkal rendelkeznek, ezért most csak a legfontosabbakat sorolom fel, amelyekre általában szükség van az adatbázis programozásához.
Tulajdonság/Metódus Funkció
Open ------------> Létrehozza a kapcsolatot az adatforrással
Close ------------>Megszűnteti a kapcsolatot az adatforrással
Execute ----------> Egy SQL utasítás végrehajtása
EOF() ----------->Állomány vége jel
MoveNext() ----->Rekordhalmaz következő rekordjára
ugrik
Value ------------>Egy mező objektumértékét tárolja
ADO használatához szükséges rendszer beállítások
Első dolgunk az OLE-DB SDK installálása a rendszerünkön. Ezt a https://www.microsoft.com/ado weblapról lehet letölteni. Ennek telepítése után, az ODBC Data Source Administrator-al létrehozunk egy adatforrást, amelyre csatlakozhatunk a későbbiekben. A további lépéseket nem részletezem, mivel ezek adatbázis típusától függnek. Általánosságban a következőket kell tenni:
A DBI/DBD keretrendszer – az ODBC- és JDBC- technológiákhoz hasonlóan – adatbázis-kezelő és platform-független módon, egységes programozási felületet biztosít relációs adatbázis-kezelő rendszerekhez.
Az architektúra kétrétegű: a DBI- modulból, és az ún. meghajtó (driver) DBD- modulból épül fel. A DBI- modul definiálja a programozói felületet (API-t), és továbbítja a metódushívásokat az adatbázis-specifikus meghajtónak.
A DBD- modulok (meghajtók) felelősek a DBI- specifikációnak egy adott adatbázisrendszerre való implementálásáért: az adatbázis-kezelő és az alkalmazás (DBI- modul) közötti kommunikációt valósítják meg. A CPAN-ból ingyen letölthető a megfelelő DBD- meghajtó bármelyik, széles körben elterjedt adatbázisrendszerhez (lásd DBD::Oracle, DBD::MySQL stb.).
KezelőobjektumokAz adatbázis és a program közötti kommunikáció ún. kezelőobjektumokon keresztül történik, amelyeket típusaik szerint három kategóriába sorolhatunk:
A meghajtó-kezelő objektumok a DBD- modulok betöltésekor jönnek létre. Az adatbáziskapcsolat-kezelő a connect osztálymetódus meghívására keletkezik. Az utasításkezelők az adatbáziskapcsolat-kezelőkből származnak, és az SQL-parancsok végrehajtásáért felelősek.
Műveletek
Az adatbázis-programozás alapvető lépései a következők:
Kapcsolódás az adatbázishoz,
Lekérdezés vagy egyéb SQL-művelet előkészítése,
A művelet végrehajtása,
A lekérdezés esetén a kiválasztott rekordok további feldolgozása,
A kapcsolat bontása, lezárás.
>Kapcsolódás, előkészítés, végrehajtás
>1. Példa
A példaprogram első lépése: kapcsolódás az „alkalmazott.db” SQLite típusú adatbázishoz. Amennyiben a kapcsolat létrehozása sikertelen volt, a program hibaüzenettel leáll. A hibaüzenetet a DBI--> errstr paranccsal kérdezhetjük le. A kapcsolat létrehozásához szükséges információk a következők:
· az adatforrás „elérési útvonala”, azonosítója,
· felhasználói név,
· >jelszó,
· >egyéb beállítások (lásd később).
A továbbiakban létrehozzuk az „Alkalmazott” táblát a do metódus meghívásával, amelynek egyetlen paramétere maga a táblakészítő SQL- utasítás. A tábla feltöltéséhez a prepar metódussal „előkészítjük” a végrehajtandó SQL-utasítást, amely jelen esetben helyőrzőket (pozicionálás paramétereket, placeholders) tartalmaz. A helyőrzők a végrehajtás során kapnak értéket.
A prepare utasítás lehetővé teszi, hogy az adatbázis kielemezze, majd lefordítsa az SQL utasítást, aminek következtében futási időt lehet megspórolni az utasítás ismételt végrehajtása esetén.
A továbbiakban a „data.csv” állományból beolvassuk az adatokat, a split fügvény segítségével felbontjuk az egyes sorokat a vesszők mentén, az értékeket pedig eltároljuk a @data tömbben.
Az előkészített utasítást az execute metódussal hajtjuk végre, paraméterként átadva a @data tömböt. A helyőrzők fölveszik a @data tömbben tárolt értékeket, majd megtörténik az utasítás tényleges végrehajtása az adatbázis-kezelőben.
2. példa
A második példaprogramban a connect metódust a RaiseError 1-re állításával hívtuk meg, és a kódot standard kivétel-kezelési (eval{} if ($@) {}) blokkokban helyeztük el. A RaiseError bekapcsolásával, bármilyen hiba bekövetkeztekor automatikusan meghívódik a die függvény a megfelelő hibaüzenettel. Ezt követően már nincs szükség a lépésenkénti hibaellenőrzésre, így a kód jelentősen leegyszerűsödik, és áttekinthetővé válik.
A prepare metódus meghívásával előkészítjük a lekérdező utasítást, majd végrehajtjuk az execute meghívásával. Az execute visszatérési értéke – skaláris kontextusban – megegyezik az eredménytábla sorainak, vagyis a kiválasztott sorok számával.
Az eredménytáblát egy while-ciklussal dolgozzuk fel. A sorokat egyenként kérjük le a fetchrow_array metódussal, amelynek visszatérési értéke egy olyan tömb, amelyben az utasításnak megfelelő sorrendben és számban találhatók a feltételnek megfelelő rekordok adatai. Az adatfeldolgozás befejeztével lezárjuk az utasításkezelőt, és bontjuk az adatbázis-kapcsolatot.
Eredménytábla feldolgozása
Az ismertetett fetchrow_array mellett a következő metódusok használhatók adatok beolvasására egy eredménytáblából:
Fetchrow_arrayref:az eredménytábla egy sorát adja vissza tömbreferencia formájában (ami megegyezik egy fetchrow_array hívás tömbjével),
Fetchrow_hashref:az aktuális rekordot egy hash-referenciában adja át, amelynek kulcsai megegyeznek az utasításban szereplő oszlopnevekkel,
Fetchall_arrayref:a teljes eredménytáblát mátrix (tömbreferencia, melynek elemei tömbreferenciák) formában adja vissza.
A bind_col és bind_columns metódusok segítségével előírhatjuk, hogy a lekérdezés eredményei automatikusan egy változóba vagy változókba kerüljenek:
A $nev és $fizetes változók a cikluson belül fölveszik az eredménytábla első és második oszlopához tartozó soronkénti értékeit.
Tranzakció-kezelésA tranzakció-kezelés a commit és a rollback metódusokkal valósítható meg:
A kapcsolat létrehozásakor az Autocommit paraméter értékének 1-re állításával bekapcsolható az automatikus tranzakció-kezelés: minden sikeres utasítás végrehajtását követően automatikusan lefut a commit parancs.
MetaadatokA DBI- specifikáció lehetőséget biztosít az adatbázisra, valamint a táblákra vonatkozó metaadatok lekérdezésére. A tables metódus meghívásával megkaphatjuk egy adatbázisban létrehozotttáblák neveit:
@tables = $dbh-->tables;
Az utasításkezelő (azonosító) objektum NAME, TYPE és NUM_OFF_FIELDS attributumai az utasításban szereplő oszlopok neveiről, típusáról és számáról tárolnak információkat:
Az adatbázisok szerkezetének ismerete fontos szerepet játszhat grafikus kezelőfelületek automatikus kialakításában, vagy minden olyan esetben, amikor szükség van az egyes táblákat alkotó oszlopok pontos nevének, típusának pontos ismeretére.
A DBI-modul legújabb változatai – a fentebb ismertetett metódusokon túl – több metódust is biztosítanak az adatbázisok metaadatainak lekérdezésére, de ezek implementálását az adatbázis-meghajtókra bízzák, így nincs garancia működésükre.
A teljes hordozhatóság érdekében a DBI API-ját megkerülve oldható meg az adatbázistáblák felderítése.
ImplementációAz adatbázistábla szerkezetének térképezését a DBI::Introspector::Table és DBI::Introspector::Field osztályok végzik, a metaadatokat a DBI::Meta::Table és DBI::Introspector::Table objectumok tárolják.
A DBI::Introspctor::Table table metódusa az alábi algoritmussal dolgozik: végighalad a tábla oszlopain, és a DBI::Introspector::Field közreműködésével begyűjti a metaadatokat:mező neve, típusa, értéktartománya, numerikus típusok esetén a minimum és maximum érték, diszkrét típusoknál az értékek listája (lásd az SQL-kifejezéseket a DBI::Introspector::Field osztály _prep_sql metódusában).
A DBI::Introspector::Table metódusaival megállapítható, hogy létezik-e egy adott nevű tábla az adatbázisban (has_table), hogy a tábla üres vagy sem (is_table_epty), hogy van-e a táblában adott nevű mező/oszlop (has_field).
Az SQL-típusok helyett a mezőknek négy fajtáját különböztetjük meg.
·Egész (’Int’),
·Valós (’REAL’),
·Karakterlánc, max. 40 karakterhosszig (’STRING’)
·Szövegek (40 karakter fölött, ’TEXT’).
Ez a négy típus – a dátum, idő és bináris típusok kivételével lefedi az SQL szabvány típusait. Korlátai és „egyszerűsége” ellenére is elegendő lehet több alkalmazás számára.
DBI::Introspector::TableA modul segítségével szétválaszthatjuk az SQL-utasításokat és a Perl-kódot. Mivel minden egyes SQL-utasítás megfeleltethető egy eljárásnak/függvénynek, az egyes SQL-lekérdezéseket elnevezzük, és letároljuk egy hash-változóban, a modul pedig szimbólumtábla módosításával a befogadó osztályban szubrutinokat (metódusokat) készít belőlük.
ImplementációA modul bemenő adatként egy utasításból álló „könyvet” vár. Az egyes utasítások névből és műveletekből (SQL-lekérdezés, törlés, frissítés stb.) állnak. A műveletek típussal rendelkeznek. A típusok a következők:
·Plain:„egyszerű” SQL, egy SQL-utasítás (például „SELECT * from Documents;”) tárolására szolgál, nem hajtódik végre.
·Sql:preparált SQL-utasítás, végrehajtása elött paraméter-behelyettesítés történik.
(„SELECT FROM Document WHERE Title = ?”)
·Mxsql:preparált SQL-utasítás, amelynek a végső formája változók behelyettesítése után áll elő:
„SELECT * FROM {$table} WHERE {attrib} = ?”.
Mivel a DBIx::OpcodeBook osztály közvetlenül nem példányosítható, az utasításkönyvet regisztráltatni kell a befogadó osztállyal: a modult elhelyezzük a „befogadó” osztály öröklési hierarchiájában, és az osztály konstruktorában meghívjuk a register_opcodebook metódust.
Az implementáció részletezése elött, egy példán keresztül bemutatjuk a modul használatát.
Package Bank;
A DBIx::OpcodeBook modul, az implementáció szempontjából a következő egységekre tagolható:
- modulok betöltése,
- a műveletek szétosztásáért felelős diszpécsertábla elkészítése,
- lekérdező/beállító metódusok (automatikus) generálása,
- inicializáció – utasítások regisztrálásáért felelős metódusok elkészítése,
- adatbázis-műveletekért felelős kód,
- segédszubrutinok,
- az utasításkönyv szerializálásáért felelős metódus.
Az osztály, a modulok betöltésével és verziószám beállításával kezdődik:
Package DBIx::OpcodeBook
A Text::Template (CPAN) modult, a változók sztring interpolációjának kiváltására használjuk az ’mxsql’ típusú utasítások feldolgozásánál. A modul szubrutinjai közül csak a fill_in_string-et importáljuk saját névterünkbe. A fill_in_string két paraméterű függvény, az első paramétere a sablonszöveg, a második a behelyettesítendő értékeket tároló adatszerkezet:
Az utasítástípusokhoz egy diszpécsertáblát rendelünk, amely nem más, mint egy hash-referencia, amelynek kulcsai a típusnevek, értékei pedig a DBIx::OpcodeBook metódusaira mutató szubrutin-referenciák:
A lekérdező/beállító metódusokat a CLASS::MethodMaker segítségével állítjuk elő:
Az utasításkönyv regisztrálásáért az alábbi kód felelős:
A _set_book metódusnak egyetlen paramétere van, amely kétféle típusú lehet:
Hash-referencia esetén a memóriában levő, az utasításkönyvet tartalmazó adatszerkezet, vagy egy YAML-dokumentumot tároló állomány neve.
Ennek köszönhetően az SQL utasításainkat elhelyezhetjük egy vagy több külső állományban, az egyes SQL-dialektusoknak megfeleleően, és futáskor az adatbázisrendszernek megfelelőt „töltjük be”.
A _set_ops metódus sorban feldolgozza az utasításokat: az ’sql’ típusúakból preparált és tárolt SQL-utasítást készít, a ’mxsql’ és ’plain’ típusúakat változatlan formában hagyva eltárolja egy hash-ben, az utasítás nevét használva kulcsként. Az utasítások típusát és nevét egy másik hash-ben szintén eltároljuk.
A _create_subs az utasítás nevével megegyező metódusokat hoz létre a szimbólumtábla módosításával. A típusnak megfelelő metódushívásokat beburkoljuk egy névtelen szubrutinba, majd bejegyezzük a szimbólumtáblába az utasítás nevének megfelelő kulccsal.
Az SQL-utasítások végrehajtásában a következő metódusok vesznek részt:
Az _exec_sql metódusba koncentrálódik az adatbázis-műveletekkel kapcsolatos logika 99%-a. A metódus első lépésben lekérdezi a behelyettesítendő paramétereket (placeholderek) számát, és összehasonlítja a ’dat’ paraméterben átadott tömb hosszával. (Ebben a tömbben adjuk át a behelyettesítendő paramétereket a metódusnak.) Ha a paraméterek száma és a tömbméret eltér, a metódus kivételdobással megszakítja futását. Ily módon megakadályozza, hogy az adatbáziskezelő-rendszer szintjéig terjedjen a hiba, és az olyan utasítást hajtson végre, ami biztosan hibás. Amennyiben az átadott paraméterek száma megfelelő, a korábban előkészített SQL-utasítás végrehajtására kerül sor (execute). Ha a végrehajtott SQL-utasítás egy DSL-művelet, a (NUM_OF_FIELDS) attributum értéke megegyezik az eredménytábla oszlopainak számával, minden más esetben (create, insert) pedig 0 lesz.
Az _exec_sql által visszaadott eredménytábla méretét és a tárolásához használt adatszerkezet típusát a metódusnak átadott paraméterekkel befolyásolhatjuk. A szabályok a következők:
Ha definiálva van egy ’bind’ paraméter, akkor a visszatérési érték egy hash-referencia és egy iterátor lesz. Az iterátorral előre lépve, a hash-referencia felveszi az eredménytábla aktuális sorának értékeit. (A hash-referencia kulcsai az oszlopneveknek felelnek meg.) Ez a leggyorsabb és legalacsonyabb memóriafogyasztással járó módja az eredménytábla bejárásának.
Ha definiálva van egy ’sth’ paraméter (’sth’ => 1), akkor a metódus visszatérési értéke egy lekérdezéskezelő objektum lesz.
Ha a paraméterlista tartalmaz egy ’slice’ nevű paramétert, akkor az eredménytábla bizonyos oszlopait tartalmazó mátrix lesz a visszatérési érték. Ha a ’slice’ paraméter típusa hash-referencia, akkor a hash kulcsaivalmegegyező nevű oszlopok kerülnek bele a mátrixba, tömbreferencia esetén, a tömbben található sorszámok jelölik ki az oszlopokat.
Ha sem az 1. sem a 2. szabály nem teljesül, akkor a teljes eredménytábla lesz a metódus visszatérési értéke.
A segédszubrutinok a következők:
# „SQL-injekciós” támadásokban használt SQL-kifejezések
# detektálására szolgáló szubrutin
A Perl egyik leggyakoribb alkalmazási területe a világhálóra szánt CGIprogramok írása. A CGI-programok on-line tranzakciók feldolgozását végzik, animációkat végeznek, és más dinamikus elemeket visznek az amúgy statikus weboldalakba, egyszerűsítik a rendszeradminisztrációs feladatokat, és még lehetne sorolni. A CGI-programoknak van legalább egy közös vonása: a módszer, amellyel a kliens webböngészőkkel információt cserélnek. Ismerve, hogy a CGI-adatcsere nem áll másból, mint szögeges bemenet feldolgozásából és formattált szöveg kimenetre küldéséből (HTML-kód), nem okozhat túl nagy meglepetést, hogy a Perl vált az első számú nyelvvé ehhez a feladathoz.
A Common Gateway Interface (CGI) főbb tulajdonságainak rövid áttekintésével kezdjük a fejezetet. Elsősorban azt vizsgáljuk meg, hogyan kerülnek átadásra az adatok a webböngészőből a CGI-programba, és milyen elvárásoknak kell megfelelnie a program kimenetének. Ezután megnézünk néhány CGI-program példát, amelyek kiválóan demonstrálják a Perl hatékony alkalmazhatóságát a CGI-adatok kezelése terén. Majd bemutatjuk a Perl CGI-modulját, amely most már része a standard Perl terjesztésnek. Használatával elegánsabbá és egyszerűbbé válik a CGI-programok írása. A fejezet végén a CGI-programozás biztonságossági vonatkozásáról ejtünk néhány szót.
A következő részek feltételezik a hálózati dokumentumok készítésére használt HTML-nyelv alkalmazásszintű ismeretét. Ha az olvasó eljutott arra a szintre, hogy a CGI-programozást szeretné tanulmányozni, akkor már bizonyára volt dolga a HTML-lel. Amennyiben soha nem volt alkalma HTML-kód készítésére vagy olvasására, akkor javaslom, hogy vegyen a kezébe egy ezzel a témával foglalkozó könyvet, mielőtt belevetné magát a CGIprogramozás rejtelmeibe.
Még itt az elején felhívjuk a figyelmet, hogy ennek a fejezetrésznek nem célja a CGI teljes körű tárgyalása, csak arra vállalkozik, hogy a CGI főbb tulajdonságait megvilágítsa, a súlypontot a fejezetben alkalmazásra kerülő lehetőségekre helyezve. A fejezet feldolgozásával képesek leszünk egyedül átgondolni azokat a megoldásokat, amelyekkel a különböző formátumú bemeneti adatokat kezelni tudjuk a Perl használatával. Éppen ezért az ismertetést szándékosan fogtuk ilyen rövidre. A következő alfejezetben láthatunk majd példákat.
A Common Gateway Interface vagy CGI, egy módszert definiál, amellyel adatokat cserélhetünk a webkliensek (böngészők) és a webszerveren futó programok, az ún. CGI-programok között. A CGI-programok szerepe a statikus HTML-oldalakban rejlő lehetőségek kiterjesztése. Ez történhet kicsiben - például animációk hozzáadásával vagy dokumentumainkat intelligenssé tevő dinamikus oldalgenerálással - valamint lehet olyan jelentős mértékű, mint egy felület létrehozása más nem webalapú, a host gépen működő szolgáltatás számára. Az tény, hogy a CGI-programok a szerveren futnak és nem a kliensen, megkülönbözteti őket más webprogramoktól (mint pl. Java appletek) és hatékonyabb eszközzé teszi őket olyan feladatokra, amelyek megkövetelik a kölcsönhatást a szerverrel.
A CGI működésének alapja az, hogy a webböngésző bemeneti adatokat fogad el egy HTML dokumentumtól (általában egy munkalaptól), vagy egy URL-hez rendelt speciális szövegtől. A böngésző az adatokat egy sztringbe kódolja és elküldi ezt az adatsztringet ("query string") a webszervernek, amely ennek hatására lefuttatja a CGI-programot. A szerver a query stringet elérhetővé teszi a CGI-program számára. Az adatok átadása a szerveren kétféleképpen történhet attól függően, hogy a böngésző hogyan hívja meg a CGI-programot. A CGI-program élvégzi a feladatát és kimenetként HTMLkódot szolgáltat, amit a szerver visszajuttat a böngészőhöz.
A további tárgyalás érdekében egy egyszerű HTML-form meglétét feltételezzük, amely két adatot kér be: a felhasználó bejelentkezési nevét és a teljes nevét, majd ezeket az add name.cgi nevű programnak adja át. A HTMLkód számunkra lényeges része valami ilyesmi lehet:
Miután a böngésző előtt ülő személy begépeli a kívánt adatokat az űrlapon és rákattintott a Submit gombra, a böngésző becsomagolja az adatokat egy query stringbe és elküldi a szervernek. Általában az adatsztring kulcs=érték séma szerinti párok sorozatából van elkészítve. Az egymás utáni adatpórok & jellel vannak elválasztva egymástól. A mi konkrét példánkban két névvel ellátott adatelem szerepel a "login" és a "name". Mielőtt a böngésző elküldené az adatokat a szervernek, el kell végeznie bizonyos karakterek kódolását, nehogy a webszerver félreértelmezze őket.
Annak ellenére, hogy a CGI-bemenet mindig szöveges, bizonyos karakterekhez speciális jelentéssel bírhat attól függően, hogy a kliens milyen módon adja át az információt a szervernek. Ezek közé a karakterek közé tartoznak azok is, amelyeknek a HTML-kódolásban van sajátos jelentésük, úgymint a szóközök, perjelek (/) és sokan mások. Ezek mind veszélyt jelenthetnek, mert nem tudni, hogy milyen jelentést tulajdonít nekik a szerver parancsértelmezője. Megakadályozandó az esetleges félreértelmezését a szerveroldalon mind a parancs-shell, mind pedig a CGI-program által, a böngésző az alábbi módon kódolja a karaktereket: minden problematikus karaktert helyettesít egy százalékjel prefixszel és egy hexadecimális számmal, amely a karakter helyét jelöli ki az ASCII karakterhalmazban. Például a kérdőjel (?) ASCII kódja Ox3f (decimális 63). Így HTML kódolt formában a kérdőjelnek a %3F felel meg. Egy kivétel az általános kódolási szabály alól: a szóközök pluszjelként is írhatók.
Ha példa formunkban a felhasználó "tomo"-t ad meg bejelentkezési névként, és "Tom O'Brien"-t teljes névként, a böngésző a következő adatsztringet generálja:
Login=tomo&name=Tom+O%27Brian
Vegyük észre, hogy a szóköz és az aposztróf is kódolva szerepel. A CGIprogram feladata ezen karakterek kibogozása; a webszerver ezt nem csinálja meg helyettünk. A kódolandó karakterek listáját bármilyen HTML referenciából megtudhatjuk. Fontos azonban tudnunk, hogy bármilyen ASCII-karakter kódolható ily módon, még a normális alfabetikus karakterek is. Ennek megfelelően alapkövetelmény, hogy a CGI-programunk képes legyen bármilyen kódolt adatot felismerni.
Az, hogy a kódolt adatsztring a két lehetséges módszer közül melyikkel kerül átadásra, a HTML-form kulcsszavából derül ki. A két lehetőség a get és a post. A webszerver automatikusan beállítja a request method rendszerváltozót ezen értékek egyikére, amelyből a CGI-program megtudhatja a meghívás módját.
A Get az alapértelmezett átadási mód, amellyel form adatokat küldhetünk a CGI-programoknak. Ennél a módszernél az adatsztring CGI URL hivatkozásához fűződik hozzá, egy kérdőjel közbeiktatásával. Az előző példában, mivel nem jelöltünk meg semmilyen módszert a form kulcsszóban, a get a feltételezett rnód. A szervernek átadott URL így fog kinézni:
http: //server.company.com/cgiin/add_name.pl?login=tomo&name=Tom+O % 27Brien .
A webszerver az input adatokat a query_string rendszerváltozón keresztül teszi elérhetővé a CGI-program számára. Ha a CGI-program a FREF kulcsszóból lett meghíva (és nem a HTML FORM-ból), vagy a felhasználó maga adja meg a program URL-jét a böngészőben, az adatsztringet explicit módon "hozzá kell ragasztanunk" az URL végéhez. Ebben az esetben a felhasználónak vagy a HTML programozónak kell gondoskodnia az adatsztring helyes kódolásáról.
Ha a CGI-program a post módszerrel lett meghíva a formból, akkor a query string a program szabványos bemenetén fog megjelenni. Továbbá a beme
neti (kódolt) adatsztring hossza (karaktereinek száma) a content length r rendszerváltozóba másolódik. A post módszer használatához a példa for
munk FORM kulcsszavát a következőképpen kell módosítanunk:
A CGI-programoknak történő adatátadás egy másik alkalmazható módszere az, amikor kiegészítő elérési út információkat fűzünk az CGI URLjéhez. Ez a módszer a webszerver azon tulajdonságára támaszkodik, hogy képes felismerni a tényleges elérési út végét, így biztosítva a CGI-program végrehajtását. A többletinformáció a path_data környezeti változón keresztül válik elérhetővé a CGI-program számára. Például az add name.cgi szkriptet meghívhatjuk a következő URL-lel:
http://server.company.com/ cgi-bin/add_name.cgi/update?login=tomo&name=Tom+O%27Brien.
Ebben az esetben a webszerver lefuttatja az add name.cgi-t, miközben a path_data környezeti változó a "/update" értéket tartalmazza, a queri_string változó pedig a kódolt adatsztringet, mint korábban.
Mint azt tapasztalhattuk, a webszerver bizonyos információkat környezeti változókon keresztül juttat el a CGI-programhoz. Láthattuk, ahogyan a szerver az átadási móddal, a request sztringgel és sztring hosszával bánik. Valójában a szerver ennél jóval több információt raktároz a környezeti változókban: a kliens böngészővel kapcsolatos adatokat, a kliens gép címét és néhány részletet magáról a szerverről. A következő fejezetrészben egy olyan CGI-programot mutatunk be, amelyen keresztül a környezeti változók teljes készletével megismerkedhetünk.
A végső mozzanatot egy CGI-programban a kliens böngészőn megjelenítendő HTML-kód generálása jelenti. Ami magát a CGI-programot illeti, nincs nehéz dolga: csupán szöveget kell kiküldenie a szabványos kimenetre; a webszerver feladata a HTML-kód eljuttatása a böngészőhöz. Idézzük fel, hogy egy HTML-dokumentum egy fejrészből (header), és egy törzsből (body) áll, a kettőt egy üres sor választja el egymástól. Amikor statikus HTML-kódot készítünk, csak a törzsrésszel kell foglalkoznunk, a fejinformációt a szerver küldi meg, amikor a dokumentumot elküldi a böngészőnek. Egy CGI-programnak viszont kötelessége fejinformációval is ellátni a kódot, amely általában legalább egy "Content-type" sor hozzáadását jelenti. A szerver ezt szükség esetén saját információkkal egészíti ki.
A HTTP fejlécek kezelése két esetben érdekes. Az egyik a HTTP kérés fejlécei, míg a másik a HTTP válasz fejlécei. A HTTP kérés fejléceihez a CGI program direkt módon nem fér hozzá, azokat a Webszerver nem adja át. Ez talán érthető is, ha arra gondolunk, hogy a HTTP fejlécben szerepelhetnek olyan információk, mint a felhasználó jelszava, amelyet a Webszerver esetleg maga értelmez, és ellenőriz, és semmi dolga vele magának az alkalmazásnak. Azokat az információkat, amelyeket a böngésző a http fejlécben küld el a webszervernek, és amelyekre a CGI programnak szüksége lehet a webszerver a CGI processz környezeti változóiban helyezi el. Alaphelyzetben a CGI programnak nem kell semmilyen fejlécet előállítania. A minimálisan szükséges fejléceket a html szöveg elé odateszi a webszerver, elegendő, ha a CGI program magát a HTML szöveget visszaküldi. Megtehetjük, hogy a teljes általunk küldendő fejlécet a program a HTML kód előtt kiírja, pontosan úgy, ahogy annak a http válaszban szerepelnie kell. Létezik a fejlécekkel kapcsolatban az NPH fogalma is, amely a No Parsed Header angol kifejezés rövidítése, amely azt jelenti, hogy a webszerver a CGI alkalmazás által visszaküldött http választ teljesnek tekinti, nem vizsgálja, hogy van-e benne Status vagy bármilyen más olyan fejléc, amellyel kezdeni tud valamit, nem tesz a CGI program által generált fejlácek elé, vagy mögé semmit, hanem leküldi egy az egyben a böngészőknek. Az nph scriptek írására a CGI szabvány azt mondja, hogy ezek a futtatandó fájlok nph- karakterekkel kell, hogy kezdődjenek. Térjünk tehát rá arra, hogy milyen fejléceket érdemes a programnak a HTML szöveg előtt küldenie. Nem fogunk minden fejlécet áttekinteni, csak a legfontosabbakat.
A legfontosabb, és a Status után az első amit minden programnak küldenie kell, az a Content-type fejlécsor, amelyben a böngészővel közöljük, hogy a küldendő információ, amelyik a fejlécsorok után jön, milyen MIME típusú. Ez általában text/html de ha nem HTML szöveget küldünk vissza, csak sima szöveget akkor text/plain, de előfordulhat, hogy egy bináris állományt küldünk vissza, ami mondjuk egy GIF kép, akkor image/gif az érték, így a programsor, amelyik ezt az információs mint fejlécsort kinyomtatja:
vagy
vagy
A következő példaprogram CGI scripten keresztül küld a felhasználónak egy GIF képet:
Ez egy olyan fejléc, amellyel azt mondhatjuk aböngészőnek, hogy az információ, amit ő kér nem is ott van, ahol ő keresi, hanem valahol máshol. Ilyenkor általában a Status sorban sem a 200 OK üzenetet adja vissza a program, hanem valamilyen más hibakódot, általában a 301 Moved Permanently értéket. Ez azt jelenti a böngészőnek, hogy a kért információ nem ott található, ahol ő keresi, hanem valahol máshol, nevezetesen a Location fejlécsorban megadott helyen. Egy egyszerű példaként álljon itt egy kis script, amelyik a felhasználót az AltaVizsla keresőhöz küldi:
Mire jó ez? Nos a leggyakrabban a hirdetési bannereket megjelenítő programok használják ezt a technikát. Amikor megjelenik egy hirdetési kép, és valaki rákattint, akkor nem lehet azonnal a hirdető Web oldalaira küldeni, mert előtte a hirdetést megjelenítő szolgáltató még rögzíteni akarja egy naplófájlba, hogy egy rákattintás történt, és csak ezután küldi el a felhasználót a keresett oldalra. Például az Internetto is ezt a technikát használja. Ha valaki Apache webszervert használ, és valamilyen oknál fogva egy weboldalba a képeket CGI scripten keresztül akarja küldeni, például azért, mert ellenőrizni akarja, hogy aki le akarja tölteni az oldalt az kifzette-e a havi díjat és így jogosult a képek megnézésére, akkor is használhatja ezt a technikát. Sokkal hatékonyabb lesz, mint beolvasni az egész fájlt, majd a CGI processzen keresztül elküldeni a webszervernek, amelyik azt továbbküldi. Az Apache van annyira intelligens, hogy észreveszi, hogy a cgi script az elérendő információ helyeként egy olyan URL-t adott meg, amelyet szintén ő kezel, és ahelyett, hogy a hibakódot leküldené a böngészőnek, rögtön az új URL-en levő információt küldi le. Ami persze lehet kép, szöveg, hang vagy akár egy újabb CGI script, vagy valamilyen más információ, amelyet például egy Apache modul kezel. Ha pedig nem fizetett, akkor a visszatérési státusz kód lehet 402.
Az egyes munkamenetek elkülönítése, az állapotok tárolása (session sate management) Session objektumokkal. A session objektumot a szerver tárolja, az adott felhasználóhoz kötődik, egyedi azonosító szükséges a URL-hez illesztve, így az a programozó adatokat tárolhat benne.
Elérkeztünk a fejezet központi témájához - nevezetesen, annak bemutatásához, hogy mitől is olyan alkalmas a Perl a CGI-programozásra. Itt most nem arra helyezzük a hangsúlyt, hogy demonstráljuk, mire képes a CGI, hanem inkább arra, hogy rámutassunk, hogyan lehet a Perl segítségünkre ezen a téren. Már tapasztalhattuk, hogy érdemes a Perlt választani általános rendszerprogramozási feladatokhoz, ebben a fejezetrészben a Periben rejtőző újabb lehetőségekre derül fény, amely megmagyarázza, hogy a Perl miért olyan népszerű a CGI-programozásban.
Kezdjük vizsgálódásainkat egy nagyon egyszerű Periben írt CGI-szkripttel. Ez a példaprogram nem fogad el bemenetet a böngészőtől. Meghíváskor nem csinál mást, mint meghívja a szerver who parancsát és a kimenetet elküldi a böngészőnek HTML formátumú dokumentumként. (A who parancs a bejelentkezett felhasználókat listázza.)
A program egy Content-type" sor generálásával kezdődik, amelyet egy üres sor választ el a dokumentum törzsrészétől. Ezek együtt egy részleges fejet alkotnak, amelyet a szerver kiegészít, még mielőtt a dokumentumot elküldené a böngészőnek. A kód nagy részét a HTML-kód generálása teszi ki. Erre a célra a helyben tárolt dokumentumos (here) megoldást használjuk. Egy kis időt nyertünk azáltal, hogy a who parancs kimenete előre van formattálva (a <PRE> </PRE> kulcsszavakkal), és a backtick operátor kimenetét egy skalár változóban tároljuk. A program által generált mintakimenetet egy másik példa kapcsán közöljük a 8.3. ábrán.
Íme egy másik programocska, amely a CGI-program környezet változóit jeleníti meg:
Tanulságos lehet a programot több különböző módon meghívni, hogy lássuk, hogyan kerülnek az adatok átadásra a CGI-programnak a környezeti változókon keresztül. Például próbáljuk meg a programot a "-showenv.cgi?up&down=down" hivatkozással elindítani vagy írjunk egy egyszerűbb formot, amely a POST-tal küldi el az adatokat. A CGI-program meghívása az alábbi módon történik:
/cgi-bin/showenv.cgi/extra/path/info?name=this+tune
Vegyük sorra a fontosabb kulcs-értél párokat:SERVER_SOFTWARE | A szerver-program neve, és verziója. |
GATEWAY_INTERFACE | A gateway (a webszerver és a program közötti felület) neve és verziója, általában "CGI/1.1". |
DOCUMENT_ROOT | Az a könyvtár, amit a kliens a gyökérkönyvtárnak lát. |
REMOTE_ADDR | A kliens, vagy az általa használt proxy szerver IP címe. |
REMOTE_HOST | A kliens host neve, általában nem áll rendelkezésre (a szerver nem határozza meg, vagy egyáltalán nincs). |
SERVER_PROTOCOL | A használt protokoll, és annak verziója. |
REQUEST_METHOD | A HTTP kérés típusa (ld. később). |
QUERY_STRING | GET típusú hívás esetén ebből nyerhetők ki az adatok. |
CONTENT_LENGTH | POST típusú hívás esetén az elküldött bájtok száma (ld. később). |
HTTP_USER_AGENT | A kliens böngészőprogramjának a neve és verziója, általában az operációs rendszerrel kiegészítve. |
HTTP_ACCEPT | A kliens által elfogadott mime típusok listája, általában szerepel benne a */*, mivel így a szerver minden típust elküld, és a böngésző dönti el, hogy mit kezd vele. |
HTTP_ACCEPT_LANGUAGE | Azokat a nyelveket találjuk itt, amelyeket a böngésző tulajdonosa beállított, hogy elfogad, el tud olvasni. |
SCRIPT_NAME | Programunk virtuális helye (azért virtuális, mert itt az a könyvtár számít a gyökérkönyvtárnak, amelyet a kliens is annak lát). |
SCRIPT_FILENAME | Programunk helye a szerveren (a valódi gyökérkönyvtárból számolva) |
SERVER_NAME | A szerver neve, vagy IP címe. |
REQUEST_URI | Ezt az URI-t kérte a kliens. |
SERVER_PORT | A port száma, ahol a kérés érkezett. |
HTTP_HOST | A szerver host neve. |
PATH_INFO | A CGI program virtuális könyvtárként is használható, ebben a változóban a programnév utáni, további alkönyvtárak találhatók. |
PATH_TRANSLATED | Az előző teljes változata. |
CONTENT_TYPE | A kéréshez csatolt információ mime típusa (ld. később) |
Most, hogy az olvasó túl van a CGI áttekintésén és fel van vértezve programozói szintű Perl ismeretekkel, bizonyára megfogalmazódott a fejében egy Perl program, amely egy CGI-bemenetet dolgoz fel. Mivel a bemeneti CGIadatok értelmezése a legtöbb CGI-programban felmerül, érdemes kifejlesztenünk néhány újra hasznosítható függvényt ehhez a feladathoz. Alább két rutint közlünk, amelyekkel CGI paraméterek nyerhetők ki egy alkalmas Perl szerkezetbe, függetlenül a meghívás módjától.
A split függvény oldja meg a különböző adatpór elemek kinyerését a query sztringből. A kulcsokat és az értékeket egy ötletes reguláris kifejezés dekódolja, amely százalékjel után álló kétjegyű hexadecimális számokat keres. Ha ilyet talál, akkor a hex függvény segítségével átalakítja decimálissá, a konvertálás rögtön a pack argumentumában történik. A pack függvény kimenete végül helyettesíti a sztring kódolt karakterét. Az eszközök, amelyekkel a Perl a kódolt adatsztringet kezeli, azok közül is legfőképpen a bármely HTML-kódolt karakter visszaállítását végző, elegáns reguláris kifejezés, egy a sok ok közül, amely a Perl népszerűségét magyarázza CGI-programozás terén.
A parseQuery függvény egy hash-ra mutató referenciát ad vissza. A hash tartalmazza a query sztring kulcs/érték párjait. Figyelem, a rutin egy kulcshoz rendelt több értéket is kezel, az értékeket a nullkarakter (\0) választja el egymástól. Az alább közölt egyszerű program a fenti rutinokat használja. A példa nem csinál mást, mint egy szépen formatált listába szedi a query stringbe csomagolt adatokat. Ez hasznos lehet HTML-formok teszteléséhez, később pedig egy másik példában vesszük hasznát:
A HTML-kód generálása a CGI-programból viszonylag egyszerű, mechanikus eljárás, ahogy azt az olvasó is minden kétséget kizáróan felfedezte az előző példákban. A helyben tárolt dokumentumos technika alkalmazásával lehetővé válik a programozó számára, hogy közvetlenül a CGI-program forráskódjába ágyazza a HTML-kódot, míg a print utasítások rövidebb kódok kiíratására használhatók.
A HTML-fejek készítése további figyelmet érdemel. Az idáig bemutatott példákban a CGI-program által készített fejek kiterjedése egyetlen sor volt, amely a tartalomtípust tüntette fel (content-type), ami a legtöbb esetben elegendő is. Amellett, hogy a webszerver HTML-fej iránti igényeit kielé
gítjük, függetleníteni tudjuk programjainkat a szerver alapértelmezett tartalomtípus választásától. Léteznek azonban más elemek is, amelyeket adott esetben fel szeretnénk tüntetni a CGI-fejben. Ilyen lehet a "Status" sor. Például a "Status: 204 No Response" sorral közölhetjük a böngészővel, hogy a program futás alatt áll, de nem fog kimenetet generálni. Hasonló módon értelmes "Status" kód generálás beépítésével a CGI-szkriptet különböző hibakezelőkkel is felszerelhetjük a futtatás során jelentkező hibák esetére (pl. "Status: 500 Internal Server Error"). Az olvasó biztosan megtalálja a HTML-állapotkódok (status codes) teljes listáját a kedvenc HTML-dokumentációjában.
Két másik említésre méltó, a fejrészben használható sor az "Expires" és a "Location". Az előbbi a böngészőnek jelzi, hogy az oldallal kiküldött adatok érvényessége lejár a megadott idő után és kéri az újbóli letöltését. Az utóbbi utasítja a szervert egy másik dokumentum átadására. Például a következő rendkívül egyszerű CGI-program a szervert az "under-construction.html" dokumentumhoz irányítja át:
print "Location: under-construction.html\n\n";
exit;
A "Location" és a "Content-type" sorok nem szerepelhetnek ugyanabban a fejrészben.
Az itt közölt néhány példából hibás lenne azt a következtetést levonni, hogy a CGI-programok csak szöveges adatokat generálhatnak kimenetként. Például, teljesen helyes az alábbi kód is, amelyben a CGI-program bináris képi információt küldhet (feltéve, hogy a kliens böngésző fogadja):
my $file="picture.jpg" my $length = (stat($file))[6]; open(FILE, "<$file") or die "A $file nem nyitható meg: $!" @data = <FILE>; print "Content-type: image/jpeg\n" print "Content-length: $length\n\n"; #a fejrészt záró extra sor print @data;Az alap HTML-nyelv egy népszerű kiterjesztésében a keretek (frame) is. A CGI-programok alkalmasak kereteket tartalmazó dokumentumok generálására. A fődokumentum keretekre bontása két lépésből áll. Először a kerethalmazt definiáljuk, majd a kereteket megtöltjük dokumentumokkal vagy CGI-kimenetekkel a kerethalmaz definíciójától függően. A kiegészítő elérési utas technika kényelmes megoldást kínál, amellyel egyetlen CGI-programban megvalósítható a kerethalmaz generálása és a keretek benépesítése. Tekintsük az alábbi CGI-kódot, amely bemenetként (a get-en keresztül) egy hivatkozást kap egy másik CGI-programra (cél), amelynek kimenetét megjeleníti egy keretben, a forráskódját pedig egy másikban listázza ki. A program nevét a cél CGI query sztringje kell hogy kövesse. Továbbá feltétel, hogy a cél ugyanabban a könyvtárban legyen, mint az eredeti szkript. Meghívására példa:
/cgi-bin/showcgi.cgi?testparse.cgi/extra/path/info?up=up
És a tényleges kód:
A program valójában kétszer kerül meghívásra, először böngésző kérésére, amikor a buildFrames függvény végrehajtódik, másodszor saját kérésre a showCGI hívás alkalmával, amikor az alsó keret a célszkript szövegével töltődik fel. Az extra elérési út információk az URL után fűződnek, amikor a program meghívja önmagát, ez különbözteti meg a program példányait.
Néhány megjegyzés a példával kapcsolatban: figyeljük meg, hogyan választja szét a főprogram egy elegáns reguláris kifejezése a cél CGI-szkript nevét és query sztringjét (és az extra elérési út információkat, ha vannak). Ismét megcsillantak a Perl képességei. A showCGI-függvény kiír egy "Content-type" sort, amelyben a tartalomtípusnak text/plain-t jelöl meg.
Ezt látva a böngésző nem fogja értelmezni a HTML-kódokat, amelyek jelen lehetnek a cél CGI-forrásában.
Egy érdekes kérdés: Mit gondol az olvasó, mi fog történni, ha a showcgi.cgi-t önmagával hívjuk meg a következőképpen: "/cgi-bin/showcgi.cgi? showcgi.cgi"?
print "Content-type: text/html\n\n";
my $who_cmd = '/bin/who';
my $who = '$who_cmd';
print <EOM;
<HTML>
<HEAD>
<TILE>Ki van a szerveren</TITLE>
</HEAD>
<BODY>
<H1>Ki van a szerveren?<H2>
<PRE>
Ismerve, hogy a CGI-programozók nagy része Perl párti, nem okozhat meglepetést, hogy kimondottan CGI-kódokhoz kifejlesztettek egy Perl modult. A modult - amely egyszerűen a CGLpm nevet kapta - Lincoln Stein készítette és az 5.004-es Perl változattól kezdve része a standard Perl könyvtárnak. (Külön is elérhető a CPAN-ról.) A CGI-modul sok olyan szolgáltatást kínál, amely nagyban leegyszerűsíti a CGI-kódok megírását. Ezek közé tartozik a query adatok automatikus tagolása, HTML-kódsorozatok előállítását végző függvények és hibakezelő rutinok, amelyek a böngésző számára generálnak hasznos információkat.
Ismerkedésünket a CGLpm modullal kezdjük egy rövid CGI-programmal. Ez bizonyos tekintetben hasonlít a korábban látott showwho.cgi szkriptre, de ez a szerver traceroute parancsát futtatja. Célállomásként vagy a megadott IP-címet használja, vagy ha nem jelölünk meg semmit, akkor a kliens gép IP-címét.
>Megjegyzés: A traceroute egy olyan program, amely ügyesen felhasználva az ICMP-csomagok "time to live" mezőjét, felfedi azon útválasztók sorozatát, amelyeket a hálózati csomagok érintenek
a megadott hosthoz vezető útjuk során. A program elérhető sok Unix verzió, valamint Windows NT alatt, ahol a tracert nevet viseli.
Mielőtt a CGI traceroute programot közölnénk, nézzük meg a HTMLmunkalapot, amelyről elindíthatjuk:
Lássuk most a CGI-programot:
# nph-trace.cgi
use CGI;
use CGI::Carp qw(fatalsToBrowser);
$I = 1; #Pufferolás nélküli input
my $query = new CGI;
my $host addr = $query->server_name;
my $dest addr = $query->param('host') ? $query->param('host') : $query->remote_addr;
die "Rossz karakter ($1) a hostnévben"
if $dest_addr =~/({\\;*><'Il)/;
die "Cél cím hiányzik" unless $dest addr; print $query->header(-type=>'text/html', -status=>'200 OK';
-nph=>1, );
print $query->start html('Traceroute demo');
print $query->h1('Traceroute demo');
print $query->h2($host addr,'-tól a(z)', $dest addr,'-ig');
print $query-.>hr;
print "<PRE><TT>\n";
open (TRACE, "/usr/sbin/traceroute $dest addr I");
while (<TRACE>){
print;
}
print "</PRE></TT>\n";
print $query->hr;
print $query->end_html; exit;
A kód elején a $query-t egy új CGI-objektumként deklaráljuk, ez egyben megoldja a bemeneti adatsztring feldolgozását is, függetlenül a kérelem módjától. A bemeneti adatok ezek után a $query objektum param metódusa által lesznek elérhetők a programozók számára. Általában a `name' nevű adatelem értéke a következőképpen kérdezhető le:
$value = $query->param('name');
A paraméterek neveihez így férhetünk hozzá:
@names = $query->param;
A szerver környezeti, változói közvetlenül elérhetők a CGI-objektum metódusai segítségével. Erre két példát láthatunk is a kódban: remote_addr és server name metódusok alkalmazását. A hasznos metódusok közé sorolandó még a path_info, a query_string, a request method, accept és a user_agent. A showenv.cgi szkript kimenetéből a többi kitalálható.
A kód print utasításait megvizsgálva látható, hogyan kímélhetjük meg magunkat a fáradságos gépeléstől, amikor a HTML-kód generálására kerül sor. Az argumentumok nélküli header függvény elkészíti a "Content-type: text/html" és a fejrészt a dokumentumtörzstől elválasztó üres sort. További argumentumok megjelölésével létrehozhatunk "Status" sort is vagy - mint a példa kódban - "Expire" sort, vagy akármilyen számunkra szükséges fejinformációt. A start html függvény a <HTML>, a <HEAD> valamint a <TITLE> </TITLE> és a nyitó <BODY> kulcsszavakat adja vissza. A hl függvény az argumentumait szóközökkel tölti ki és a kapott sztringet a <H1> és a </H1> kulcsszavak közé helyezi. Ennek alapján várható, hogy hasonló
módon más címsorokat (h2-h6) is lehet készíteni. Jó néhány más argumentum nélküli függvény is van, ilyen a példabeli "hr" is (amely a <HR> HTMLkulcsszót készíti el).
Az előző példának van még egy szokatlan tulajdonsága: az, hogy ez egy "no-parse-header" vagy NPH-program. Rendes körülmények között a webszerver megvárja, amíg a CGI-program befejezi futását, mielőtt a kimenetet a böngészőhöz továbbítaná. Egy NPH-program esetében azonban a CGIprogram által generált kimenet késedelem nélkül továbbítódik a kliensnek. A traceroute példában ez a kívánatos megoldás, mert elképzelhető, hogy a traceroute parancs végrehajtása akár egy percet is igénybe vesz. Ha a kimenet azonnal a böngészőbe jut, akkor van lehetősége a felhasználónak, hogy félbeszakítsa a szkriptet, ha valami miatt úgy kívánja. Az automatikus puffer ürítés változót ($I) igazra állítottuk, amely azt biztosítja, hogy a parancs futása közben - állapotától függően - készüljön a kimenet. A módszer, amely által egy CGI-programot NPH-programmá tehetünk, szerverfüggő. Néhány, mint pl. az NCSA és az Apache megköveteli, hogy a program neve "nph-"-val kezdődjön. Mások a fejrészben keresnek valamilyen kérelmet, amit az előző példában az nph igazra állításával tettünk meg a header függvényben.
Észrevehető, hogy fenti CGLpm-re támaszkodó programban egy másik modult is felhasználtunk, nevezetesen a CGI::Carp-ot. Ez a modul az alapvető hibakezelési függvényeknek - úgymint a warn és a die, továbbá a croak, confess és a carp - megfelelő modulbarát hibarutinokat definiálja. Ezek a helyettesítő függvények további információkat fűznek az általuk megjelentetett hibaüzenetekhez, úgymint a hiba időpontját, amely a webszerver hibanapló állományában követhetőbb bejegyzéseket eredményez. A qw(fatalsToBrowser) használata arra kéri a modult, hogy a fatális hibákat (amelyeket a die, a croak vagy a confess generál) küldje el mind a szerver naplóba, mind a böngészőnek.
Egy másik hibakeresési technika, amely a CGLpm-et használja, a kód hálózat nélküli futtatása. A CGI-modul ugyanis elfogadja a kulcs=érték formában megadott bemenetet a parancssorból (a program meghívásakor) és interaktív módon a szabványos bemenetről is. A bemeneti adatot a modul először megfelelő query sztringgé alakít, majd azt a megszokott módon
(a param metódus segítségével) elérhetővé teszi a program számára. Ez a kód hibamentesítésének egy tiszta és kényelmes módja, valamint sokkal hatékonyabb, mint a szerver naplóállományok átfésülése a hibák felderítéséhez.
Az nph-trace.cgi kódban használt függvények csak egy töredéke, annak a készletnek, amelyet a CGLpm nyújt. A HTML-oldalak létrehozása az, amelyben a CGI-modul haszna leginkább megnyilvánul. Tekintsük az alábbi példát, amely a 8.6. ábrán látható formot hozza létre:
Szöveg bemenet: | ", textfield(-name=>'input')," |
---|---|
Jelszó bemenet: | ",password field(-name=>'password'), " |
Rádiógombok: | ", radio-group(-name=>'radio', -value=>/@radioValues, -labels=>\~radioLabels), " |
Lenyíló lista: | ", popup_menu(-name=>'popup', -value=>\@popupList)," |
Gördülő lista: | ", scrolling_list(-name=>'scroll', -value=>\@scrollList, -multiple=>'true', -size=>3)," |
Szövegmező: | ", textarea(-name=>'textl', -rows=>2, -cols=>20)," |
Szövegmező (szöveggel): | ",textarea(-name=>'text2', -rows=>2, -cols=>20, -value=>$default)," |
Egy kicsit elidőzünk a példaszkript elemzésével, mert jó néhányat illusztrál a CGI-modul lehetőségei közül. Mindjárt az első sorban a CGI-modul usezal történő importálásakor a atandard címkét használjuk, amely a leghasznosabb szimbólumokat helyezi a főprogram névterébe. Ez azt jelenti, hogy írhatunk olyat is, mint "print start html" ahelyett, hogy fel kellene
tüntetnünk a minősítőt is a függvénynévvel, mint a korábbi példákban: "print $query->start html". Egy ilyen rövid programban nem áll fenn a veszélye, hogy beszennyezzük a névteret. A CGI-modul számos hasonló címkét definiál, ilyenek például a :form, :htm12, :html3 és a :netscape. A CGLpm forrásában a teljes ilyen címkelistát megtaláljuk a hozzájuk tartozó szimbólumokkal együtt.
Sok más említésre méltó momentum található az előző példában. Először is vegyük észre, hogy szabadon kevertük a CGLpm függvényhívásokat amelyek HTML-kimenetet produkálnak - az explicit HTML-kóddal. A példában egy táblázatot hoztunk létre a formátum kezeléséhez, és a CGLpm függvényhívások köré HTML-táblázatsor és táblázatadat kulcsszavakat helyeztünk a print utasításokba. Másodszor figyeljük meg a radio_group, a popup_fist és a scrolling list függvényeket: ezek argumentuma lehet tömbre mutató referencia - a listaelemek értékei számára -, vagy hash-re mutató referencia - a listaelem címkék számára, mint pl. a radio-buttons hívásban). Sőt még az is megengedett, hogy kifejtett tömb adatokat adjunk át, miként a következő kódban:
print popup_list(-name=>'hal', -value=>['egy', 'kettő', 'piros', 'kék']);
Ezek a függvények jól mutatják, hogyan rejtheti el a CGI-modul a programozó elől a HTML bőbeszédűségét. Például egyetlen popup list hívás a fenti sorban az alábbi HTML-kódot generálja:
<SELECT NAME="hal">
<OPTION VALUE="one">egy
<OPTION VALUE="two">kettő
<OPTION VALUE="red">piros
<OPTION VALUE="blue">kék
</SELECT>
Megjegyzés: Nem árt tudnunk, hogy az előző példában is használt jelszó típusú inputmező nem teljesen biztonságos. Igaz ugyan, hogy a beütött karakterek nem jelennek meg a képernyőn, de a há
lózaton titkosítás nélkül utaznak. Ha az adatokat a GET-módszerrel küldjük át, akkor a jelszó megjelenik az URL-ben. A lényeg az, hogy ne használjunk jelszó típusú inputmezőt, ha biztonságosságra törekszünk.
Amennyiben hálózaton keresztül történő biztonságos adatcserét kívánunk megvalósítani CGI-programokkal, akkor egy biztonságos szerver konfigurációra van szükségünk. Ez a témakör azonban jócskán túlmutat a könyv keretein.
A CGLpm teljes függvénykészletének és az azok nyújtotta lehetőségek megismeréséhez, futtassuk a perldocCGI-t a rendszerünkön, vagy tanulmányozzuk át a forráskódban található dokumentációt.
Egy végső megjegyzés a CGI biztonságosságával kapcsolatban
A CGI-programozás tárgyalásából nem maradhat el - ha csak egy-két szó erejéig is - a biztonságosság kérdése. Csakugyan a CGI-programokkal kapcsolatosan nem lehet eleget hangsúlyozni a biztonságosság fontosságát. Elegendő arra gondolnunk, hogy a CGI egy olyan módszer, amely majdnem mindenki számára lehetővé teszi, hogy egy programot hajtson végre a gépünkön. Ha a CGI-programok nem elég elővigyázatosan vannak elkészítve, rosszindulatú felhasználók igyekezni fognak saját céljuk elérésére felhasználni azt és nem arra, amire eredetileg szántuk. Ez nem azt jelenti, hogy nem szabad CGI-programokat írni. Ha tudatában vagyunk a felmerülő veszélyeknek, akkor azokat el is tudjuk kerülni.
A biztonságosságra vonatkozó első szabály így szól: kerüljük az olyan CGI-kódot, amely rendszerparancsok hívásakor a query sztringből kinyert adatokat adja át argumentumként. Ha semmiképpen sem tudunk más módszert alkalmazni, akkor előzetesen végezzünk a sztringen vizsgálatot, hogy kiszűrjük a potenciális veszélyt jelentő karaktereket, amelyek speciális jelentéstartalommal rendelkezhetnek a parancsértelmező számára. Az nph-trace.cgi példában láthattuk, hogy lehet egy ilyen szűrést elvégezni. Igénybe vehetjük a Perl egy hasznos szolgáltatását is - mindössze a -T kapcsolóval kell meghívni -, amely abban áll, hogy a fordító ellenőrzi néhány alapvető biztonságossági feltétel meglétét a program környezetébe. Például a fordító fatális hibát jelez, ha egy rendszer parancsot a teljes elérési út feltüntetése nélkül próbálunk meghívni, kivéve, ha beállítottuk az elérési utat a %ENV hash-ben. A -T kapcsoló használatára a dokumentációkban "taint checking" néven van utalás. A -T kapcsoló a szkript első sorában is megadható:
#!/usr/local/bin/perl -T
Célszerű engedélyezni a biztonsági ellenőrzést, ha olyan CGI-programot fejlesztünk, amely rendszer parancsokat futtat vagy lokális állományokba ír.
Egy másik fontos dolog, amelyet jó, ha szem előtt tartunk, az, hogy a CGI-szkript a webszervert futtató effektív felhasználó hozzáférési jogosultságaival rendelkezik. Ezek az engedélyek jellemzően nagyon korlátozottak, ami gyakran meghiúsítja a program elkészítésével kapcsolatos elképzeléseinket. Például akadályba ütközhetünk, ha el akarjuk érni, hogy CGI-programunk egy korlátozott elérést engedélyező adatbázishoz férjen hozzá. Ilyen esetekben meggondolatlan lépésekre is elszánhatjuk magunkat: pl. a CGI-programunkból setuid-t próbálunk alkalmazni, vagy a webszerver konfigurálásával igyekszünk jogosultsági körét kibővíteni. Az ilyen próbálkozások nem nevezhetők józannak. Általában mindig található valamilyen biztonságosabb út terveink kivitelezésére. Szerencsére sok webszerver nem engedélyezi olyan CGI-programok futását, amelyeknek be van kapcsolva a setuid bitjük, legalábbis nem speciális konfiguráció nélkül. Csak abban az esetben futassunk beállított setuiddel rendelkező CGI-programokat, ha teljesen biztosak vagyunk a dolgunkban.
Végezetül még valami, amire fel kell hívnunk a figyelmet. Lehetőség van arra, hogy CGI-programjainkba magunk is beépítsünk bizonyos fokú hozzáférési kontrollt. Ez különböző információkra támaszkodhat, mint pl. a kliens gép IP-címe (amely a remote_addr környezeti változóból olvasható ki), vagy a távoli felhasználó azonosítója (a remote_user környezeti változóban, ha elérhető), a CGI-program eldöntheti, hogy bizonyos adatokhoz és funkcionalitáshoz engedélyezzen-e hozzáférést. Azonban ne nagyon bízzunk a kliens gépről nyert információkban, hacsak nem egy biztonságos webszervert futtatunk, mert vannak módszerek, amelyekkel ezek hamisíthatók. Általánosan elmondható a számítógépek biztonságosságáról, hogy minél többet tudunk működéséről, annál biztonságosabbá tudjuk tenni környezetünket. Az ellenkezője még inkább igaz: Amennyiben nem teljesen vagyunk tisztában a dolgok természetével, jobb, ha a legnagyobb óvatossággal járunk el.
Semmi kétség, hogy a Perl a szerveroldali webprogramozásra használt legelterjedtebb szkript nyelv. Körülbelül az összes dinamikus weboldalt Perl szkriptek generálják. De mi a helyzet a kliensoldali szkriptekkel, amelyek dinamikus tartalmat adhatnak olyan weboldalak számára, ahol nincsen szükség szerveroldali feldolgozásra: azaz állományok írására és olvasására, illetve valamely adatbázis adatainak felhasználására?
A kliensoldali webprogramozáshoz a Perl egy szkript változatát kínálja az alapnyelvnek, ezt nevezik PerlScriptnek. A PerlScript egy ActivX szkript motor, amely lehetővé teszi a felhasználó számára, hogy kódot írhasson webszerverek és webböngészők számára egyaránt. A PerlScript az ActiveState terméke, ugyanazé a cégé, amely a közkedvelt Win32-es Perl változatot is kifejlesztette. Az aktuális PerlScript változatot Windows NT-re vagy Windows 95-re az ActiveState honlapjáról tölthetjük le, vagyis a http://www.activestate.com címről.
Miért használjunk PerlScriptet?
Egy olyan nyelv használatával, mint például a PerlScript, lehetővé válik a weboldalaink tartalmának programszintű vezérlése. A PerlScript segítségével magához a webböngészőhöz is hozzáférhetünk. Az alábbi fejezetrészekben bemutatjuk, hogyan aknázhatók ki a PerlScript lehetőségei weboldalaink és tartalmuk "feldobásához". Előrebocsátjuk, hogy a könyv elkészültekor a PerlScript kizárólag a Microsoft Internet Explorer böngészőcsaláddal működik együtt, így a fejezet példái valószínűleg nem működnek a Netscape-ben és más böngészőkben.
HTML-objektumoknak a tipikus vizuális weboldal komponenseket (úgymint bemeneti ablak) nevezzük. A HTML-objektumok egy gyakori alkalmazási területe a bemeneti formok. A bemeneti formok legtöbbet látható megjelenési formája a vendégkönyv. Ezek a formfajták tisztán HTMLkulcsszavakkal is elkészíthetők, de ha arra vágyunk, hogy a HTML-alapú (ormon információk is megjelenjenek, akkor valamilyen kód beépítése is szükséges a munkalapba.
A PerlScript valós idejű adatok megjelenítésére is alkalmas a HTMLobjektumokban. Néha találkozhatunk olyan weboldallal, amely képes megjeleníti IP-címünket. A PerlScript használható a felhasználó Environment Address változójának lekérdezésére, amelyben az IP-cím van tárolva. Természetesen egy ilyen alkalmazás a szerveroldalon is megvalósítható, de a feldolgozás egy részének a kliensre terhelése segíthet a terhek kiegyenlített elosztásában és így a lestrapált webszerver egy kis "levegőhöz juthat".
A PerlScript segítségével a Browser (böngésző) objektum és nagyszámú tulajdonsága elérhetővé válik. Ez azt jelenti, hogy a böngésző jellemzőinek nagy része, úgymint a címsor és az előzmények listája vezérelhetővé válik a PerlScript használatával. Megváltoztathatjuk a böngésző ablakának megjelenését az ablak jellemzőinek módosításával, az eljárás hasonlít a keretek kezeléséhez.
A böngésző, mint objektum, maga is számos objektumból tevődik össze. Ezt fontos szem előtt tartanunk, amikor saját PerlScript szkriptjeinket készítjük. A következő fejezetrészekben áttekintjük a PerlScriptben található jelentősebb objektumokat.
A Window objektum
A Window objektum a webböngésző fő komponense. A Window-ból származik az összes többi objektum. Az objektum egy eseménnyel is rendelkezik, az OnLoad-dal, amely lehetővé teszi a szkriptek futtatását a szkriptet tartalmazó weboldal böngészőbe töltése után.
A Windowobjektum három hívható metódussal rendelkezik: . Alert: Egy üzenetablakot jelenít meg egy OK gombbal
.Status: Szöveges sztringet jelenít meg a böngésző aljában található állapotsorban
. Open: Egy új Window objektumot nyit meg
A következő példában a Window objektumot a $window nevű változó hordozza. A példa az alert metódus használatát mutatja be:
<html>
<head>
<script language = "PerlScript">
$window->alert("PerlScript veszély!");
</script>
</head>
</html>
objektum lehetővé teszi, hogy keretekkel dolgozhassunk az ablakon belül. Mivel egyszerre egy ablak több keretet is tartalmazhat, a Frame objektum tulajdonképpen egy objektumtömb. Szkriptjeinkben az egyes keretekre a keret nevével vagy a Frame objektum tömb referenciáján keresztül hivatkozhatunk. Például két keretet feltételezve, a topFrame-et és a botI~ rame-et, akkor hivatkozhatunk rájuk egyszerűen a nevükkel, vagy úgy is, mint Frames(0) illetve Frames(1) a létrehozás sorrendjének megfelelően.
A Document objektumon keresztül az aktuális weboldalt (amelyikkel éppen dolgozunk) érhetjük el. Amikor szkriptet használva valamilyen szöveget jelenítünk meg a weboldalon, a Document objektumra kell hivatkoznunk. Például egy olyan PerlScript sor, amely egy üdvözlő üzenetet jelenít meg, a weboldalunkon így néz ki (később ezt a példát tüzetesebben megvizsgáljuk):
$window->document->write("Helló Világ");
A Document objektum segítségével egy létező alapoldalba beágyazott weboldalakat hozhatunk létre. _
objektum szintén egy objektumtömb, mivel egy oldalon több form (más néven munkalap) is elképzelhető. Ahogyan a Frames objektumnál is, a Form objektum tömbjének az indexelése is 0-val kezdődik. Ezt az objektumot használjuk felhasználói bemeneti formok és olyan szkriptek készítéséhez, amelyek automatikus ellenőrzést végeznek a formon, mielőtt az elküldésre kerülne a szervernek.
Az element objektum tulajdonképpen nem más, mint a munkalapokban alkalmazható különböző vezérlő elemek, vagy vizuális komponensek gyűjteménye, amelybe többek között a szövegmezők, parancsgombok, lenyíló listaablakok tartoznak. Az Element objektum is egy tömb. Minden komponensre hivatkozhatunk egyszerűen az elem tömbbeli helyének megfelelő index megadásával. Minden komponens - mint ahogy később látni fogjuk rondelkezik egy névvel is, és így a sokkal könnyebb névszerinti hivatkozás is használható.
A PerlScripttel lehetséges, hogy egy betöltött dokumentumból egy másik betöltött dokumentum értékeire hivatkozzunk. Ilyen szituációval gyakran szembe kell néznünk például kétkeretes weboldalak esetén, ahol is az egyik keretbe az A dokumentumot töltöttük be, a másikba pedig a B-t. A PerlScriptre akkor van szükség, amikor az A dokumentum adatait a B dokumentumban kívánjuk felhasználni, vagy ha olyan komponenseket szeretnénk az A dokumentumba helyezni, amelyekkel a B dokumentum objektumai vezérelhetők.
A PerlScript egyik legnagyobb erénye, hogy segítségével új weboldalakat állíthatunk elő futási időben, miközben a felhasználó kölcsönhatásban áll a weboldallal. Például ha a felhasználó a szükséges adatokat megadta, az adatok alapján testre szabott formot hozhatunk létre kizárólag a tartalmat előállító PerlScript szkript segítségével. _
Csakúgy mint bármely hagyományos programozási nyelv, a PerlScript is lehetővé teszi változók definiálását és azokban a felhasználótól begyűjtött adatok tárolását. Ennek a jellemzőnek egy gyakori alkalmazása a felhasználói bement ellenőrzése, mely által biztosíthatjuk, hogy a dokumentum megfeleljen bizonyos kritériumoknak. A felhasználói bemenet jóváhagyása mellett a PerlScriptben matematikai függvények és műveletek teljes skáláját is igénybe vehetjük a felhasználói adatokon végzendő számításokhoz. Ez tisztán a HTML-lel nem tehető meg.
Mivel a PerlScript egy ActiveX szkriptmotor, használható ActiveX komponensek elkészítésére weboldalakon, illetve az oldalakra helyezett más ActivcX komponensekkel való kölcsönhatásra. Ennek a tulajdonságának köszi)nhetően a PerlSripttel "Windowsos" megjelenésű weboldalakat hozhatunk létre.
Mielőtt beleásnánk magunkat a PerlScript példákba, érdemes feleleveníteni azt a folyamatot, amelynek hatására kliensoldali szkript beágyazódik a weboldalba. Emlékezzünk, hogy mikor szerveroldali szkripteket készítettünk Perlben, a weboldalon egy kulcsszó gondoskodott a szerveren található Perl szkript meghívásáról; amikor a dinamikus webtartalmat a kliensoldalon akarjuk létrehozni, a szkriptet be kell ágyaznunk a weboldalak HTML-kódjába.
Az alábbi példa egy olyan weboldalt készít el, amely a klasszikus "Helló Világ!" üzenetet jeleníti meg. A példa a fent leírtak működését is illusztrálja. Íme a kód, amelyet majd működésének leírása követi:
<html>
<head>
<title> PerlScript "He11Ó Világ!" példa</title>
<script language = "PerlScript">
sub DisplayMessage {
$window->document->write("Helló Világ!");
}
</script>
</head>
<body>
<script>
DisplayMessage();
</script>
<p>Az oldalt PerlScript generálta. <p>
</body>
</html>
A szkript első három sora szabványos HTML-kód. A negyedik sor jelzi a böngészőnek, hogy a PerlScript az alkalmazott szkriptnyelv. A következő három sorban egy PerlScript függvénydefiníció található, a DisplayMessage függvényé. A függvény középső sora végzi a munkát a WindowDocument objektum write metódusának meghívásával, amely a "Helló
Világ!" üzenetet jeleníti meg. A függvénydefiníciót követő két sor lezárj<z a SCRIPT és a HEAD utasításokat.
A HEAD lezárása után a BODY kulcsszó nyitja meg a törzset. Az öss-r_es PerlScript függvény a weboldal fejrészében kerül deklarálásra, és a dokumentumtörzsből hívjuk meg őket. A <SCRIPT> kulcsszó jelzi a böngészőnek, hogy feldolgozandó kód következik. Majd a függvényhívás következik, amely nem különbözik egy szokásos Perl függvény meghívásától. Mivel több dolgunk nincs, az egyetlen függvény meghívása után következhet a </SCRIPT>, amely lezárja a szkriptet. Végül egy egyszerű HTML-sort írunk ki ("Az oldalt PerlScript generálta") és végül a weblapot a </BODY> és </HTML> utasítások zárják.
Szöveg generálása nem nevezhető éppen tudományos bravúrnak mí~~ akkor sem, ha kliensoldali PerlScript függvény által végeztük. Tcrmuszetesen nem vethetjük bele magunkat csak úgy, mindenféle elv>tanalmányok nélkül a hálózati megrendelő formok készítésébe. A kövotkurí~ példából megtudhatjuk, hogyan adhatunk gombokat és szövegmezi>I<ut weboldalainkhoz.
Képernyő elemek (widgets) - úgymint szövegmezők, beviteli gombok - elhelyezése egy weboldalon standard HTML használatával történik, és nem igényel semmilyen szkriptnyelv alkalmazást. Azok számára, akik nem jártasak a HTML-nyelvben, itt megtudhatják a komponensek hozzáadásának módját HTML segítségével.
A komponenseket és más weboldal objektumokat nem csak úgy rápakoljuk a weboldalra. Ki kell számukra jelölni egy helyet, ahová formként beilleszthetők a weblapra. Ezt a FORM HTML kulcsszóval lehet kivitelezni. A kulcsszó által definiált blokkmeghatározott blokk tartalmazza az összes megjelenítendő komponenst. Használata:
<form action = " " name = "Widgets">
Az acton tulajdonságnak általában üres sztringet adunk meg, mert a form nem végez valódi tevékenységet. A name tulajdonságnak ad unk értéket, mert a szkriptjeinknek képesnek kell lennie hivatkozni a forrnra, hogy hozzáférhessenek a tulajdonságaihoz.
A komponensek, függetlenül attól, hogy szövegmezőkről vagy parancsgombról van-e szó, "input" objektumoknak tekintendők a HTML-ben. Ez azért van így, mert általában ezeket az objektumokat használj uk a felhasználói bemenet begyűjtésére. Egy komponens megjelenítéséhez a dokumentumon meg kell adnunk a típusát, nevét, és más, az elem típusától függő jellemzőket. Az alábbi kód egy szövegablak komponenst definiál:
<input type = "text" size = "70" name = "InputString">
Ezt a HTML-sort input tagnak (címkének) nevezzük. Az első beállított tulajdonság a type, amely a "text" értéket kapta, ez jelöli a szőve-Bablakot. A második jellemzőnek, a size-nak "70"-et adtunk értékül, amivel a szövegmező hosszát határoztuk meg.
Az utolsó tulajdonság a name. Ezzel adhatunk nevet a bemeneti ablaknak, amellyel a szkriptben majd a komponensre hivatkozhatunk. Ha ezt a sort beillesztjük egy minimális HTML-kódba, amely oldal létrehozásához feltétlenül szükséges, az alábbi sorokhoz jutunk. Ezek eredményeként az üres weboldalunkon egy szövegmező jelenik meg:
<html>
<head>
<title>szövegmező és bemeneti gomb készítése</tile>
<body>
<form action = " " name = "Widgets">
<input type = "text" size = "70" name = "InputString">
<p>Szövegmező felhasználói adatok bekérésére<p>
</form>
</body>
</html>
A következő lépés egy parancsgomb készítése. A gomb esetében is az előző típusú HTML kulcsszót kell használnunk, az objektum típusának most azonban "button"-t kell megadnunk a "text" helyett és meg kell jelölnünk a gomb szövegét is. Ennek megfelelően a gomb készítését végző HTML-sor így néz ki:
<input type = "button" name = "DisplayText" value = "Szöveg megjelenítése lejjebb">
Ez hozzáadható a fenti kódhoz úgy, hogy a gomb a szövegmező alá kerülji)n:
<html>
<head>
<title>Szövegmezők és parancsgombok létrehozása</title>
<body>
<form action = " " name = "Widgets">
<input type = "text" size = "70" name = "InputString">
<p>
<input type = "button" name = "DisplayText" value = . "Szöveg megjelenítése lejjebb">
</form>
</body>
</html>
Most, hogy elsajátítottuk, hogyan helyezhetünk komponenseket a weboldalra felhasználói munkalapok készítéséhez, bizonyára szeretnénk, ha formjaink valamit csinálnának. Bevezetőként kezdjük egy egyszerű feladattal. Azt szeretnénk megvalósítani, hogy a gomb lenyomásával a szövegmezőbe beírt szöveg még egy példányban megjelenne.
A weboldal komponensek képesek a felhasználó által kiváltott eseményekre reagálni. Például, ha egy parancsgombbal csináltatni akarunk valamit, egy olyan szkriptet kell írnunk, amely akkor kerül végrehajtásra, amikor a gomb onClick esemény bekövetkezik. Minden komponenshez tartoznak bizonyos események, amelyekhez kódot tudunk rendelni. A fejezet utolsó részében felsoroljuk a különböző PerlScríptben lekezelhető eseményeket.
Ahhoz, hogy az egyszerű példánk parancsgombja kiírja a szövegmező tartalmát, egy olyan függvényt kell definiálnunk, amely ezt a feladatot ,elvégzi a gomb lenyomására. A függvény kiolvassa a felhasználó által begépelt szöveget a mezőből, és egy másik szövegmezőben kiírja a gomb alá. Az alábbi PerlScript szubrutin ezt valósítja meg:
sub Widgets::DisplayText_onClick() {
$text = $Widgets->InputString->('Value');
$Widgets->OutputString->{'Value'}= $text;
A függvénydefiníció első sorában a nevét adjuk meg, amely a gomb és a függvényt meghívó esemény nevének kombinációjából kell hogy álljon.
A következő sor olvassa ki az InputString nevű szövegmező tartalmát és a kapott sztringet a $text skalárba másolja be. Az utolsó sor fogja ezt a skalárt, és értékül adja a másik szövegmező value tulajdonságának, aminek eredményeként a $text tartalma megjelenik benne.
Az előző HTML-kódot a függvénnyel kiegészítve a következőt kapjuk:
Természetesen a Perl majdnem minden funkcionalitása használható a PerlScriptben is. Az alábbi példaszkript a korábbi példára támaszkodva, a felhasználó által az első mezőbe beírt szöveget átalakítja úgy, hogy az a második szövegmezőben csupa nagybetűs formában jelenjen meg.
Egy másik input formokon gyakran előforduló komponens a lenyíló listaablak vagy más néven kombóablak.
Lenyíló listaablakokat a HTML-ben is készíthetünk a select kulcsszó segítségével, amellyel magát a kombót hozhatjuk létre, és a választható elemek listáját is megadhatjuk. A HTML SELECT kulcsszó használatát alább láthatjuk:
A munka oroszlánrészét a Mailer::Convert_onClick függvény végzi, amely egyszerűen a kombóablak kiválasztott elemének értékét olvassa ki, eltávolítja belőle a szóközöket, majd az eredményt egy szövegmezőben joleníti meg. Az egész eljárás kulcsa az, ahogyan a kombóablak választott. elemét kinyerjük. Ilyen programozási szituációkban, mivel PerlScript dokumentáció gyakorlatilag nem létezik, más referenciákhoz kell fordulnunk, úgymint a Microsoft VBScript dokumentációja. A VBScript által használt objektumok és metódusok közel állnak a PerlScript objektumaihoz, illetve metódusaihoz; a lényegi különbséget a szintaxisbeli eltérések adják a két nyelv között.
Most, hogy az olvasó elsajátította a PerlScript használatának alapjait weboldalak kezeléséhez, bizonyára kíváncsi, hogyan használható ez a nyelv új weboldalak dinamikus előállítására. Ez anélkül is megtehető, hogy a szerverre bármiféle feladatot hárítanánk. Mielőtt megismerhetjük, hogyan építhetünk weboldalakat magából a böngészőből, szükséges megértenünk, hogyan változtathatjuk meg a weboldal tartalmát, amikor az letöltc~dik a böngészőbe.
Tartalom hozzáadása letöltési időben
A PerlScript segítségével megváltoztathatjuk a weboldalak tartalmát a böngészőbe történő letöltődésük közben. Egy gyakori példája ennek a dinamikus dokumentum lábrész (footer). A lábrészben különböző információkat tárolhatunk, mint pl. dátum és idő, a lapot letöltő böngészőt azonosító adatok és más értékes információk.
A következő szkript azt illusztrálja, hogyan lehet minden weboldalra egy lábrészt helyezni. A lábrész számos PerlScript változót használ olyan információk közléséhez, mint a weboldal megtekintésének dátuma és a használt webböngésző típusa. Íme a szkript:
A fenti kód szkript részében két változó játszik fontos szerepet az aktuális dátum és a felhasználó által használt böngésző típusának tárolásában. A dátumhoz a szkript a PerlScript localtime függvényének meghívásával jut hozzá, amely hónapra, napra és évre van tagolva. A felhasználó webböngészőjének típusát a Navigator objektumot használva tudhatjuk meg, amelynek userAgent tulajdonsága a felhasználói ágens sztringet tartalmazza, mint pl. "Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)".
Webdokumentumok valós idejű készítéséhez a kulcsot a Document objektum open metódus jelenti. Ez a metódus létrehoz egy új dokumentumot és lehetővé teszi számunkra, hogy azt tartalommal töltsük fel. Az open használata rendkívül egyszerű:
$document->open;
Nyilvánvalóan szeretnénk az oldalt szöveggel is ellátni. Ehhez a write metódust használjuk a következő formában:
$document->write("Ez egy új weboldal");
Ezzel a két metódussal a böngészőből készíthetünk új webdokumentumokat, esetleg válaszként valamilyen felhasználói bemenetre. Fontos azonban szem előtt tartanunk azt a tényt, hogy az open metódus meghívásának eredményeként a jelenleg látható dokumentumot az új felül fogja írni.
A PerlSctipt megoldást kínál olyan helyzetekben, amikor valamilyen kliensoldali tevékenységre van szükségünk. Két olyan szituáció, amikor célszerű ezt a technikát alkalmazni: a felhasználói bemenet ellenőrzése és jóváhagyása, valamint új weboldalak valós idejű létrehozása. Más szkriptnyelvek - úgymint a JavaScript és VBScript - szintén használhatók kliensoldali szkriptként. A PerlScript a megfelelő választás, ha a Perl nyelv képességeit szeretnénk felhasználni a szkriptekben. A PerlScript letölthető az ActiveSate cég weboldaláról (http://www.activestate.com). Ott mindig megtalálhatjuk a PerlScript legfrissebb változatát és mellette néhány PerlScript példát. Látogatásunkat összeköthetjük a Perl for Win32 legújabb változatának letöltésével.