Wer CGI-Skripts mit use CGI
anfängt, hat es leichter, denn
CGI.pm
, Lincoln Steins praktisches Modul,
holt Query-Parameter ab, verkürzt HTML-Ausgaben,
hilft beim Debuggen - ein Tausendsassa in Modulform!
CGI.pm
liegt der aktuellen Perl-Distribution perl-5.004_04
bei - ein
weiterer Grund, aufzurüsten! Sonst liegt es auf dem CPAN unter
CPAN/modules/by-module/CGI/CGI.pm-2.37b12.tar.gz
CGI.pm
arbeitet eigentlich mit einem CGI-Objekt:
<include file=eg/cgiobj.pl filter=eg/usenew.sed>
Über die Objektreferenz $q
stehen anschließend die
Dienste als Methoden zur Verfügung:
<include file=eg/cgiobj.pl filter=eg/print.sed>
gibt den Server-Header und eine H1
-Überschrift etwa als
Content-Type: text/html <H1>Überschrift</H1>
aus. Im harten Alltagsgeschäft verkompliziert das Objekt $q
aber nur
unnötig die HTML-Ausgaben. Mit einer Tag-Liste hinter dem use
-Befehl
läßt CGI.pm
fünf gerade sein und importiert
die Methoden als Funktionen in den Namensraum des Skripts:
<include file=eg/cgistd.pl filter=eg/cut2.sed>
Für CGI-Parameter, Formulare und Basis-HTML reicht :standard
, kommen
Tabellen mit ins Spiel, muß auch noch :html3
'ran.
Doch noch einmal zuurrrrück zum Anfang: Richtiges HTML mit Titel,
Body und allem, was dazugehört, schafft
<include file=eg/startend.pl filter=eg/printgo.sed>
Das setzt den Titel des zurückgelieferten HTML-Dokuments auf Titel
und die Hintergrundfarbe auf ein neutrales Weiß.
Zwar kommt ab Perl 5.003 der vordere Teil einer Key/Value-Kombination wie
z.B. -title => 'abc'
auch ohne sichernde Anführungszeichen aus,
da aber CGI.pm
eine Unmenge
von Funktionen exportiert, kann es zu
Verwirrungen kommen: -title
könnte der Perl-Interpreter auch als negativen
Rückgabewert der von CGI.pm
exportierten Funktion title()
verstehen.
Bei angeschalteter -w
-Option mault perl
entsprechend, '-title'
schafft hier Klarheit und Ruhe.
So gibt's für jeden HTML-Tag eine Funktion aus CGI.pm
.
Listing basehtml.pl
zeigt ein CGI-Skript, das die wichtigsten Tags
aus dem HTML-Standard-Fundus verwendet: Listen, verschiedene
Schriftarten, Hyperlinks.
Ins cgi-bin
-Verzeichnis des Webservers verfrachtet, bringt ein Aufruf von
http://server/cgi-bin/basehtml.pl
im Browser die Ausgabe aus Abbildung
1 zum Vorschein.
basehtml.pl
01 #!/usr/bin/perl -w 02 ###################################################################### 03 # Michael Schilli, 1998 (mschilli@perlmeister.com) 04 ###################################################################### 05 06 use CGI qw/:standard/; 07 08 print header, 09 start_html('-title' => 'HTML-Tags', 10 '-BGCOLOR' => 'white'), 11 12 h2("Bullet-Liste"), 13 ul( 14 li( i("kursiv") ), 15 li( b("fett") ), 16 li( tt("getippt") ) 17 ), 18 19 hr, # Querstrich 20 p, # Absatz 21 22 h2("Glossar-Liste"), 23 dl( 24 dt("Hyperlink"), 25 dd( 26 a( {href => 'http://www.com'}, "Hier klicken!") 27 ), 28 dt("Hyperlink als Image"), 29 dd( 30 a( {href => 'http://www.com'}, 31 img({src => "/pic.gif"})) 32 ) 33 ), 34 35 end_html;
Abb.1: HTML-Tags aus dem Standard-Fundus |
Die Funktionen aus CGI.pm
, die Texte HTML-formatiert zurückgeben, heißen wie
die zugehörigen HTML-Tags: Aus <P>
wird p()
, aus <UL>
(Bullet-Liste) wird ul()
, mit dem Unterschied, daß HTML einen Ausdruck
mit einem öffnenden und einem schließenden Tag umrahmt, während
<CGI.pm> verschachtelte Funktionenaufrufe erfordert, um die gewünschte
Struktur zu erzeugen. So liefert dl(ul('a'), ul('b'))
etwa
<DL><UL>a</UL><UL>b</UL></DL>
Um Attribute für ein HTML-Tag zu setzen, also z. B. mit dem
SRC
-Attribut die Quelldatei für ein Image-Tag festzulegen,
erhält die entsprechende CGI.pm
-Funktion einfach einen
anonymen Hash als ersten Parameter, der Wertepaare der Form
Attributname/Wert enthält, für einen Hyperlink also
beispielsweise
a({href => 'http://anywhere.com'}, "Hier klicken!");
was
<A HREF=http://anywhere.com>Hier klicken!</A>
zurückliefert.
Tabellen enstehen mit den Funktionen table
, TR
, th
und td
, die
den HTML-Tags TABLE
, TR
, TH
und TD
entprechen (daß die
TR
-Funktion großgeschrieben wird, liegt nur daran, daß es schon eine
Perl-Funktion namens tr
gibt).
<include file=eg/tabman.pl filter=eg/cut2.sed>
Die Newlines wären zwar aus HTML-Sicht nicht notwendig, erleichtern aber das Lesen der Ausgabe:
<TABLE BORDER="1" BGCOLOR="beige"> <TR><TH>Spalte1</TH> <TH>Spalte2</TH></TR> <TR><TD>Feld 1/1</TD> <TD>Feld 1/2</TD></TR> <TR><TD>Feld 2/1</TD> <TD>Feld 2/2</TD></TR> </TABLE>
Stellt Perl-Code den Tabelleninhalt dynamisch zusammen, ergibt sich
öfter das Problem, daß man eigentlich alle Tabellendaten innerhalb
eines table(...)
-Aufrufs sammeln möchte, aber es geht nicht,
weil deren Erzeugung so kompliziert ist! Teilen wir die
Arbeit doch auf:
<include file=eg/tabloop.pl filter=eg/cut2.sed>
Perls map
-Funktion bewältigt schleifen-typische Aufgaben
auch ohne Schleife.
Das nachfolgende Snippet macht
aus einer Liste von Spaltenüberschriften (@head
) und
einer LoL (List of Lists, enthält die Tabellenzeilen als
Unter-Listen) ohne viel Federlesens eine Tabelle:
<include file=eg/tablol.pl filter=eg/cut2.sed>
Die erste Zeile im table()
-Aufruf umschließt jeden Eintrag in
@head
mit <TH>...</TH>
und rahmt das Ganze
mit <TR>...</TR>
ein - fertig ist der Tabellenkopf.
Der map
-Befehl liefert ja bekanntlich eine neue Liste zurück, indem
er jedes Element der ihm überreichten Liste durch den
in geschweiften Klammern entstehenden Ausdruck ersetzt.
Bei der Zeile mit den zwei map
-Befehlen, die direkt darunter steht,
wäre mir fast der Hirnkasten
zersprungen, so angestrengt mußte ich nachdenken. Der Trick ist der:
Der äußere map
-Befehl ackert @lol
durch, läßt die gefundenen
Unter-Listen (@$_
) vom inneren map
-Befehl verarbeiten, schreibt sein
<TR>...</TR>
drumherum und gibt's zurück. Der innere
map
-Befehl rahmt jeden Unter-Listen-Eintrag mit
<TD>...</TD>
ein. Alles klar?
CGI.pm
beherrscht alle HTML-Tags, auch wenn sie nicht unbedingt in der
mitgelieferten Dokumentation (erscheint mittels perldoc CGI
) stehen.
Der HTML-Tag in Kleinbuchstaben
ergibt meist die entsprechende Funktion aus CGI.pm
.
Attribute (wie z.B. das SRC
-Attribut im IMG
-Tag) setzt ein
anonymer Hash als erstes Argument. Da diese Funktionen meist
nicht mit dem :standard
-Tag exportiert werden, hilft ein
vorangestellter Modul-Bestimmer wie CGI::
. So ändert
<include file=eg/font.pl filter=eg/cut2.sed>
die Fontgröße und -farbe in HTML mit
<FONT SIZE="+1" COLOR="red">Achtung, Rot!</FONT>
Tritt bei einem CGI-Skript ein schwerwiegender Fehler auf, so schwer, daß
man am liebsten alles hinwerfen würde und das Skript abbrechen, stellt sich
das Problem, daß vor der eigentlichen Fehlermeldung ein CGI-Header
kommen muß, sonst zeigt der Browser ein unschönes
Internal Server Error
an und das heißt: Amateur am Werk!
Steht die Header-Ausgabe am Anfang und der kritische Teil des Skripts
inmitten eines eval
-Konstrukts, kann nichts schiefgehen: Läuft
das Skript auf eine die
-Anweisung, springt es aus dem eval
-Block
heraus und hinein! in die nachfolgende if
-Bedingung, denn $@
führt in diesem Fall den Wortlaut der Fehlermeldung:
<include file=eg/erroreval.pl filter=eg/cut2.sed>
Um den eval
-Block zu sparen, kann man auch die Pseudo-Signale __DIE__
und __WARN__
abfangen, und einen Handler für den Fehlerfall definieren:
<include file=eg/errorsig.pl filter=eg/cut2.sed>
Alle Ausgaben schleust dieser Code durch cgiprint
, einer print
-Funktion,
die lediglich beim ersten Aufruf der Ausgabe den Header voranstellt.
cgiprint
'merkt' sich diesen Zustand in der globalen Variablen
header_printed
.
Bevor ein CGI-Skript im cgi-bin
-Verzeichnis irgendwelchen Unsinn
treibt, sollte es zumindest einmal fehlerfrei auf dem Trockenen laufen:
Ein Perl-Skript mit eingebundenem CGI.pm
'weiß', ob es von der
Kommandozeile oder vom Server aufgerufen wurde.
Falls es im ersten Fall irgendwo CGI-Eingabe-Parameter verarbeitet,
stoppt es vorher und nimmt Wertepaare der Form Key=Value
entgegen:
(offline mode: enter name=value pairs on standard input) a=b c=d CTRL-D
Anschließend fährt es normal mit der Bearbeitung fort, nur daß
die Query-Parameter a
und c
die Werte b
bzw. d
enthalten.
Um in cgi-bin
schnell mal auszuprobieren, welche Parameter ein Skript
zugespielt bekommt, eignet sich das Skript
<include file=eg/dump.pl filter=eg/cut2.sed>
Die as_string()
-Funktion gibt alle empfangenen Query-Parameter als
Glossar-Liste in HTML aus,
egal ob sie per GET- oder POST-Methode angelangten. Kritische
Zeichen, die der Browser zur eindeutigen Übermittlung im Format %xx
maskierte, entpackt CGI.pm
dabei wieder vorschriftsmäßig.
Die Zeile mit dem map
-Befehl schreibt noch sämtliche Umgebungsvariablen
aus dem
ENV
-Hash schön formatiert in die Ausgabe. Der Server nutzt
die Environment-Variablen als
Schnittstelle, um dem Skript bestimmte Variablen zu übermitteln
(z.B. den Original-Querystring, die IP-Adresse des Absenders, eventuell
vorhandene Request-Header etc.).
Ins cgi-bin
-Verzeichnis des Web-Servers gestellt und mit
http://localhost/cgi-bin/dump.pl?a=b&c=d
aufgerufen, zeigt dump.pl
im Browser etwa ein Bild nach Abbildung 2.
Abb.2: Ausgabe von dump.pl |
Wie gelangen die Eingabedaten normalerweise zum CGI-Skript? Formulare,
Formulare, Formulare heißt die Antwort.
Wie man sie (natürlich mit CGI.pm
) erstellt und
Benutzer-Eingaben auswertet (natürlich auch mit CGI.pm
),
zeige ich in der nächste Folge. Habe die Ehre, Freunde!
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |