In den letzten Jahren hat sich die Erstellung von CGI-Skripten zu einem der Hauptanwendungsbereiche von Perl entwickelt. CGI ist das Akronym für »Common Gateway Interface« und bezieht sich auf Programme und Skripts, die auf einem Webserver stehen und ausgeführt werden als Antwort auf entsprechende Eingaben eines Webbrowsers. Diese Eingaben können die Form von Formularen, komplexen Links oder bestimmten Arten von Image-Maps annehmen - ja eigentlich bedarf alles, was als Antwort nicht gerade eine ganz gewöhnliche Datei ist, einer Art von CGI- Skript.
Aufgrund der Popularität von Perl als CGI-Sprache möchte ich nicht darauf verzichten, Ihnen im Zusammenhang mit Perl eine kurze Einführung in CGI zu geben. Heute werden wird das bisher Erlernte anwenden, um CGI-Skripts für das Web zu erstellen. Im einzelnen erfahren Sie
CGI.pm
,
Um in Perl ein CGI-Skript zu schreiben, benötigen Sie drei Dinge:
CGI.pm
, das Teil Ihrer Perl-Version sein sollte (mehr dazu später)
Sie benötigen nicht unbedingt das Modul
CGI.pm
, um CGI-Skripts mit Perl zu erstellen. Es gibt auch andere Hilfsskripte, mit denen Sie CGI programmieren können, oder Sie schreiben den ganzen zugrundeliegenden Code gleich selbst. Dies würde jedoch einen erheblich größeren Programmieraufwand bedeuten; es ist viel, viel einfacher, statt dessenCGI.pm
einzusetzen. Wir tun es alle. Warum schließen Sie sich uns nicht an?
Aufgrund der großen Bandbreite an Webservern für verschiedene Plattformen und den Unterschieden zwischen ihnen, möchte ich der Diskussion, wie Sie Ihren Webserver für CGI fit machen, nicht allzuviel Platz einräumen. Umfangreiche Hilfe finden Sie in den zahlreichen Hilfedateien im Web:
http://hoohoo.ncsa.uiuc.edu./cgi/
).
http://www.perl.com/CPAN-local/doc/FAQs/cgi/perl-cgi-faq.html
).
http://www.perl.com/CPAN-local/doc/FAQs/cgi/idiots-guide.html
).
http:/www.activestate.com/support/faqs/win32/
). Hier finden
Sie eine Fülle von Informationen zur Programmierung, dem Aufsetzen und dem
Einsatz von Perl für CGI. Aber auch zu Ihrem Webserver kann es spezielle
Webserver-bezogene Informationen zur Erstellung und Konfiguration von CGI-
Skripten mit Perl geben.
Sie können auch jederzeit die Dokumentation, die mit Ihrem Webserver ausgeliefert wurde, zu Rate ziehen. Und wenn Sie vorhaben, wirklich viel mit CGI zu arbeiten, sollten Sie vielleicht die Anschaffung von Sams Teach Yourself CGI Programming in a Week von Rafe Colburn in Erwägung ziehen. Das Buch wird Ihnen eine größere Hilfe sein und mehr Beispiele bieten, als ich es im Rahmen dieses Buches kann.
Um mit dem Rest dieser Lektion nicht allzu viele Schwierigkeiten zu haben, sollten Sie zumindest einige flüchtige Kenntnisse in HTML haben. Auch hier möchte ich Ihnen empfehlen, sich durch die Vielzahl der HTML-Tutorien im Web zu kämpfen oder das Buch Sams Teach Yourself Web Publishing with HTML 4 in 21 Days von Laura Lemay (das bin übrigens ich) durchzuarbeiten.
Beginnen wir diesen Abschnitt damit, dass ich Ihnen etwas Hintergrundwissen zu CGI vermittle und Ihnen erkläre, wo CGI in der Beziehung zwischen Webbrowser und Webserver einzuordnen ist.
CGI steht, wie bereits erwähnt, für Common Gateway Interface. Common (»gemeinsam, allgemein«) bedeutet, dass der gleiche Prozeß für viele verschiedene Arten von Webservern verwendet wird, und Gateway (»Tor«) resultiert daher, dass die Skripts früher einmal in der Regel als Tor zwischen dem Webserver und einem größeren Programm fungierten - zum Beispiel einer Datenbank oder einer Suchmaschine. Heutzutage hat CGI viel von seiner ursprünglichen Bedeutung verloren und bezieht sich einfach auf ein Skript oder Programm, das als Antwort auf eine Eingabe eines Webbrowsers ausgeführt wird.
Es gibt viele Probleme, die sich mit einem CGI-Skript lösen lassen, und es gibt für jedes Problem unzählige Möglichkeiten, das zugehörige Skript zu schreiben. Im Rahmen dieser Lektion konzentrieren wir uns auf einen typischen Anwendungsbereich von CGI-Skripten: die Bearbeitung von Daten, die als Teil eines HTML-Formulars empfangen wurden. In Abbildung 16.1 sehen Sie ein typisches Ablaufdiagramm, das zeigt, was passiert, wenn ein Benutzer über seinen Webbrowser ein Formular anfordert, es ausfüllt und wieder zurückschickt.
Abbildung 16.1: Der CGI-Prozeß
Und so sehen die Schritte im einzelnen aus:
Das scheint nicht allzu kompliziert. Wichtig ist, dass Sie verstanden haben, wo das CGI-Skript in dem Datenfluß eingreift, woher die Daten für das CGI-Skript kommen und wohin sie gehen. Später wird dies noch von Bedeutung sein.
Am besten erlernt man die CGI-Programmierung, indem man einfach loslegt - also,
auf geht's! In diesem Abschnitt erstellen wir ein ganz einfaches CGI-Skript - das
Gegenstück zu »Hallo Welt«. Dazu benötigen wir ein einfaches HTML-Formular, Perl
für das CGI-Skript und das Modul CGI.pm
, um alles zusammenzubinden. Das HTML-
Formular gebe ich Ihnen vor, das Skript werden wir Zeile für Zeile erarbeiten.
In Listing 16.1 finden Sie den HTML-Code für ein einfaches HTML-Formular, das Sie nach Ihrem Namen fragt. In Abbildung 16.2 können Sie dann sehen, wie das Ganze auf dem Webbrowser ausgegeben wird.
Listing 16.1: Die Datei name.html
1: <HTML>
2: <HEAD>
3: <TITLE>Tell Me Your Name</TITLE>
4: </HEAD>
5: <BODY>
6: <FORM ACTION="/cgi-bin/name.pl">
7: <P>Geben Sie Ihren Namen ein: <INPUT NAME="name">
8: <P><INPUT TYPE="SUBMIT" VALUE="Abschicken!">
9: </FORM>
10: </BODY>
11: </HTML>
Zwei wichtige Dinge möchte ich zu diesem HTML-Code anmerken:
ACTION
auf das CGI-Skript, das dieses Formular
verarbeiten wird, wenn es an den Server geschickt wird. In unserem Beispiel heißt
das Skript name.pl und steht auf dem Server im Verzeichnis cgi-bin (dem
regulären Speicherort für CGI-Skripts; das Verzeichnis muss jedoch nicht bei allen
Servern gleich lauten; es kann auch erforderlich sein, dass Sie erst die Erlaubnis
einholen müssen, bevor Sie Ihre Skripts dort ablegen). Passen Sie den Pfad
gegebenenfalls an.
Einige Webserver verlangen, dass Sie Ihre Skripts mit der Extension
.cgi
versehen, damit sie als CGI-Skripts erkannt werden. Da dies von Server zu Server unterschiedlich gehandhabt wird, sollten Sie vorsichtshalber Ihre Server-Dokumentation konsultieren.
<INPUT>
-Tag). Mit Hilfe des
Attributs NAME
geben Sie diesem Element einen Namen. Dies wird von Bedeutung
sein, wenn Sie das CGI-Skript für das Formular erstellen.
Kommen wir jetzt zu dem Perl-Skript, das die Daten verarbeitet. Ein CGI-Skript wird in Perl grundsätzlich in der gleichen Weise aufgesetzt wie ein normales Perl-Skript, das von der Befehlszeile aus ausgeführt wird. Es gibt jedoch einige wesentliche Unterschiede, die darauf beruhen, dass Ihr Skript vom Webserver aufgerufen wird und nicht von Ihnen. So erhalten Sie zum Beispiel keine Optionen oder Dateinamen- Argumente über die Befehlszeile. Alle Daten, die Sie im Skript erhalten, kommen vom Webserver (oder werden von Ihnen selbst aus Dateien auf der Festplatte eingelesen). Die Ausgabe Ihres Skripts muss in einem bestimmten Format vorliegen - normalerweise HTML.
Zum Glück gibt es das Modul CGI.pm
, geschrieben von Lincoln Stein, das mit der
aktuellen Perl-Version ausgeliefert wird, Ihnen die CGI-Skripterstellung leichter macht
und einen großen Teil der Probleme abfängt.
Lassen Sie uns mit den obersten Zeilen unseres CGI-Skripts anfangen:
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard);
Die shebang-Zeile und use strict
kennen Sie bereits, und die dritte Zeile use CGI
sollte Sie auch nicht allzusehr überraschen. Das Tag :standard
importiert, wie Sie
sich vielleicht aus Kapitel 13, »Gültigkeitsbereiche, Module und das Importieren von
Code«, erinnern, nur einen Teilbereich des CGI-Moduls und nicht das ganze Modul.
Dieses Tag werden Sie wahrscheinlich im Zusammenhang mit CGI.pm
häufig
verwenden.
Die meisten CGI-Skripts bestehen aus zwei Teilen: Der erste Teil liest die Daten ein, die Sie von einem Formular oder dem Webbrowser erhalten haben, und verarbeitet sie. Der zweite Teil gibt eine Antwort aus, die in der Regel im HTML-Format erzeugt wird. Da es in unserem Beispiel kaum etwas zu verarbeiten gibt, gehen wir gleich zum Ausgabeteil über.
Das erste, was wir ausgeben müssen, ist ein besonderer Header an den Webserver,
der ihm mitteilt, welche Art von Datei Sie zurücksenden. Senden Sie eine HTML-
Datei zurück, lautet der Typ text/html
. Ist es eine einfache Textdatei, lautet der Typ
text/plain
. Für eine Grafik ist es image/gif
. Diese Dateitypen sind alle als Teil der
MIME-Spezifikation standardisiert, und wenn Sie tiefer in die CGI-Skripterstellung
einsteigen, werden Sie sich mit zumindest einigen dieser Formate näher vertraut
machen müssen. Das geläufigste Format ist zweifelsohne text/html
. CGI.pm
stellt
Ihnen eine grundlegende Subroutine namens print_header()
zur Verfügung, die den
entprechenden Header für diesen Formattyp ausgibt.
print header();
Alle weiteren Ausgaben, die auf den Header folgen, müssen jetzt im HTML-Format
sein. Sie können entweder reine HTML-Tags ausgeben, die Perl-Subroutinen von
CGI.pm
verwenden, um den HTML-Code zu erzeugen, oder beide Methoden
miteinander kombinieren. Da ich mit HTML vertraut bin, ziehe ich die Subroutinen
von CGI.pm
nur dort vor, wo es mir Tipparbeit erspart, und verwende ansonsten
normale print
-Anweisungen. Sehen Sie hier den Rest unseres einfachen CGI-Skripts:
print start_html('Hallo!');
print "<H1>Hallo, ", param('name'), "!</H1>\n";
print end_html;
Die erste Zeile ruft die CGI.pm
-Subroutine start_html()
auf, die den ersten Teil einer
jeden HTML-Datei ausgibt (die Tags <HTML>
, <HEAD>
, <TITLE>
und <BODY>
). Das
String-Argument für start_html()
ist der Titel der Seite. Sie können dieser
Subroutine aber auch andere Argumente übergeben, um zum Beispiel
Hintergrundfarbe, Schlüsselwörter und andere Besonderheiten des Headers zu setzen
(mehr dazu im nächsten Abschnitt).
Die zweite Zeile ist eine reguläre print
-Anweisung, die eine HTML-Überschrift (<H1>
-
Tag) zum Hallo-Sagen ausgibt. Zwischen dem öffnenden und dem schließenden Tag
befindet sich der interessante Teil. Die Subroutine param()
ist ebenfalls Teil von
CGI.pm
und dient dazu, an die Informationen zu gelangen, die Ihr Benutzer in das
Formular eingegeben hat. Rufen Sie dazu param()
mit dem Namen des
Formularelements (aus dem NAME
-Attribut des HTML-Tags des Formularelements) auf,
und die Routine liefert den Wert zurück, den der Benutzer für das Element eingegeben
hat. Mit dem Aufruf von param('name')
erhalten wir den String, den der Benutzer in
das Textfeld unseres Formulars eingegeben hat. Mit diesem Wert können wir dann die
Antwort erzeugen.
Die dritte Zeile ist eine weitere Subroutine von CGI.pm
, die lediglich die
abschließenden HTML-Elemente (</BODY>
und </HTML>
) ausgibt und damit die
Antwort komplettiert. Sehen Sie im folgenden das komplette Skript:
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard);
print header;
print start_html('Hallo!');
print "<H1>Hallo, ", param('name'), "!</H1>\n";
print end_html;
Vielleicht ist Ihnen aufgefallen, dass wir für die Ausgabe eigentlich keine besonderen
Schritte unternommen haben. Wir haben lediglich einfache print
-Anweisungen
verwendet. Und doch geht die Ausgabe nicht an den Bildschirm, sondern zurück an
den Browser. Damit ist ein CGI-Skript ein Paradebeispiel dafür, dass die
Standardeingabe und -ausgabe nicht unbedingt die Tastatur oder der Bildschirm sein
müssen. CGI-Skripts lesen Ihre Eingaben von der Standardeingabe und schreiben ihre
Ausgabe in die Standardausgabe, nur das in diesem Falle die Standardeingabe und -
ausgabe der Webserver ist. Sie müssen keine besonderen Vorkehrungen treffen, um
mit dem Server zu kommunizieren; über die Standardwege klappt das reibungslos.
Was aber ist unsere Ausgabe? Wenn der Benutzer in das Formular Fred
eingegeben
hätte, würde die Ausgabe des CGI-Skripts samt Header und HTML-Daten wie folgt
aussehen:
Content-type: text/html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML><HEAD><TITLE>Hallo!</TITLE>
</HEAD><BODY><H1>Hallo, Fred!</H1>
</BODY></HTML>
Diese Daten werden über die Standardausgabe an den Webserver übergeben, der sie wiederum an den Webbrowser von Fred zurückgibt.
Bevor Sie ein Skript auf Ihren Webserver installieren, ist es angebracht, das Skript zu
testen, um sicherzustellen, dass Sie keine groben Fehler gemacht haben. Mit Hilfe von
CGI.pm
können Sie das CGI-Skript zum Test von der Befehlszeile aus starten:
%name.pl
(offline mode: enter name=value pairs on standard input)
Nach dieser Zeile können Sie die Formulareingabe in Form von Name/Werte-Paaren
simulieren. So müßten Sie zum Beispiel für das Hallo-Formular als Name name
angeben, und der Wert wäre dann irgendein Name (zum Beispiel Fred
). Ihre Eingabe
sähe dann wie folgt aus:
name=Fred
Solange Ihre Eingabe keine Leerzeichen enthält, müssen Sie keine Anführungszeichen
setzen. Nachdem Sie Ihre Name/Werte-Paare eingegeben haben, drücken Sie
[Strg]
+[D
] ([Strg]
+[Z
] für Windows), um die Standardeingabe zu beenden. Das Skript
wird dann ausgeführt, als ob es die Eingabe vom Formular erhalten hätte, und das
Ergebnis wird auf dem Bildschirm ausgegeben.
Alternativ können Sie die Namen und Werte auch als Argumente in der Befehlszeile des Skripts eingeben:
%name.pl name=Fred
Das Skript wird dann diese Name/Werte-Paare als Eingabe betrachten und Sie nicht nach weiteren Eingaben fragen.
Nachdem Sie sich davon überzeugt haben, dass Ihr CGI-Skript so funktioniert, wie Sie
es erwarten, besteht der letzte Schritt darin, das Skript auf dem Webserver zu
installieren. Installation kann bedeuten, dass Sie Ihr Skript in einem besonderen
Verzeichnis namens cgi-bin
ablegen, die Skriptextension in .cgi
umbenennen oder
auf anderweitige Art und Weise dem Webserver signalisieren, dass es sich bei Ihrem
Skript um ein CGI-Skript handelt. (Auch hier gilt, dass sich diese Anforderungen von
Server zu Server unterscheiden können, so dass Sie auf alle Fälle in Ihrer Server-
Dokumentation über Einzelheiten informieren sollten). Eventuell müssen Sie auch
sicherstellen, dass Ihr Skript eine ausführbare Datei ist, oder spezielle
Zugriffsberechtigungen vergeben. Und abschließend werden Sie noch die Original-
HTML-Datei ändern müssen, so dass sie auf die aktuelle Position des Skripts zeigt.
Haben Sie all diese Probleme gelöst, sollte es Ihnen möglich sein, in die HTML-Datei mit dem Formular einen Namen einzugeben, den Abschicken-Schalter anzuklicken und vom CGI-Skript eine Antwort zu erhalten. In Abbildung 16.3 sehen Sie die Antwort als Webseite.
Abbildung 16.3: Hallo, die Antwort
Das Kernstück eines jeden CGI-Skripts ist das Modul CGI.pm
. Sie können CGI-Skripts
zwar auch in reinem Perl schreiben oder andere im Web verfügbare CGI-Programme
verwenden, doch CGI.pm
wird als Teil von Perl mit ausgeliefert, findet breite
Unterstützung, ist robust, läuft plattformübergreifend und bietet Ihnen alles, was Sie
bei Ihrer Arbeit mit CGI gebrauchen könnten. Auf CGI.pm
zu verzichten, heißt sich das
Leben als Entwickler von CGI-Skripten unnötig schwer zu machen.
Im vorangehenden Abschnitt habe ich Ihnen ein wirklich einfaches Beispiel für den
Einsatz von CGI.pm
gezeigt. In diesem Abschnitt möchte ich Sie mit dem Inhalt dieses
Moduls näher vertraut machen, so dass Sie hinterher wissen, was Sie alles damit
anfangen können.
Wenn Sie eine aktuelle Version von Perl haben, stehen die Chancen gut, dass CGI.pm
dabei ist. Sind Sie sich nicht sicher, können Sie in dem lib
-Verzeichnis Ihrer Perl-
Installation nachschauen, ob das Modul dort abgelegt wurde. Ist es nicht vorhanden,
können Sie es von der Website unter http://www.genome.wi.mit.edu/ftp/pub/
software/WWW/cgi_docs.html
herunterladen; es ist aber auch als Teil von CPAN
verfügbar. Auf der CGI.pm
-Seite finden Sie genau erklärt, wie Sie bei der Installation
dieser Datei vorzugehen haben, aber kurz gesagt, müssen Sie dazu lediglich die Datei
CGI.pm
in Ihr Perl-Verzeichnis lib
kopieren.
Das CGI.pm
-Paket enthält neben CGI.pm
noch ein weiteres Modul namens Carp
. Carp
gehört in das CGI-Verzeichnis unter dem lib-Verzeichnis von Perl (falls es noch nicht
dort abgelegt wurde). Carp
wird verwendet, um hilfreiche Fehlermeldungen in Ihren
Webserver-Protokollen oder dem Webbrowser auszugeben. Für das Debuggen von
CGI-Skripten ist das Modul von unschätzbarem Wert, was Sie schnell feststellen
werden, wenn Sie später einmal intensiver in die Arbeit mit CGI einsteigen (weiter
unten erfahren Sie gleich noch etwas mehr über Carp
).
Sowohl zu CGI.pm
als auch zu Carp.pm
gibt es eine Dokumentation im POD-Format.
Um sich diese anzuschauen, brauchen Sie nur perldoc CGI
einzutippen (MacPerl-
Benutzer können die shuck-Anwendung nutzen). Sie finden die aktuelle
Dokumentation aber auch im Web unter http://www.genome.wi.mit.edu/ftp/pub/
software/WWW/cgi_docs.html.
Um CGI.pm
in Ihren Perl-Skripten zu verwenden, importieren Sie es wie jedes andere
Modul. CGI.pm
weist mehrere Import-Tags auf, die Sie verwenden können, unter
anderem:
:cgi
- importiert Unterstützung für das CGI-Protokolls selbst, beispielsweise
param()
.
:html2
- importiert Unterstützung für die Erzeugung von HTML2-Tags,
beispielsweise start_html()
und end_html()
:form
- importiert Unterstützung zur Erzeugung von Formularelementen
:standar
d - importiert alle Elemente von :cgi
, :html2
and :form
:html3
- importiert Unterstützung für HTML 3.0
:netscape
- importiert Unterstützung für die Netscape-Version von HTML
:html
- importiert alle Elemente von :html2
, :html3
und :netscape
:all
- importiert alles
CGI.pm
ist so implementiert, dass Sie es sowohl objektorientiert verwenden können
(unter Verwendung eines CGI-Objekts dessen Methoden man aufruft) als auch durch
Aufruf einfacher Subroutinen. Wenn Sie einen der oben angeführten Import-Tags
verwenden, stehen Ihnen die Subroutinennamen in Ihrem Skript zur Verfügung.
Wenn Sie keine Import-Tags verwenden, wird davon ausgegangen, dass Sie die
objektorientierte Version von CGI.pm
nutzen möchten.
Der vielleicht größte Nutzen, den Ihnen CGI.pm
bietet, besteht darin, dass dieses
Modul Formulareingaben verarbeitet, die der Webbrowser an den Webserver schickt
und der Server an das Skript weiterleitet. Diese Eingaben kommen vom Browser in
einer ganz besonderen codierten Form, manchmal über die Standardeingabe und
manchmal als Schlüsselargumente mit nichtalphanumerischen Zeichen im Hex-Code.
Wenn Sie Ihren eigenen CGI-Prozessor von Grund auf selbst schreiben wollten,
müßten Sie sich um die Decodierung selbst kümmern (und, glauben Sie mir, das
macht keinen allzu großen Spaß). Mit CGI.pm
bleibt Ihnen all das erspart, und Sie
müssen sich lediglich um die tatsächlichen Eingabewerte kümmern, um die es ja auch
eigentlich geht.
Die Eingabe, die Sie von einem Formular erhalten, besteht aus Schlüssel/Wert-
Paaren. Der Schlüssel ist der Name des Formularelements (im HTML-Code durch das
NAME
-Attribut definiert), der Wert ist das, was der Benutzer letztendlich eingegeben,
ausgewählt oder im Formular markiert hat. Der Wert, den Sie erhalten, hängt vom
Typ des Formularelements ab. Einige Formularelemente - wie zum Beispiel Textfelder
- liefern einfache Strings, andere - zum Beispiel Markierungsfelder - liefern nur Ja
oder Nein. Popup-Menüs und scrollbare Listen, die mit dem HTML-Tag <SELECT
>
erzeugt wurden, können sogar mehrere Werte enthalten.
Das CGI.pm
-Modul speichert diese Schlüssel und Werte in einem Parameter-Array. Mit
der Subroutine param()
können Sie auf die Elemente im Array zugreifen. Ohne
irgendwelche Argumente liefert param()
nur eine Liste der Schlüssel im Parameter-
Array zurück (die Namen der Formularelemente). Wenn das CGI-Skript sowohl die
ursprüngliche HTML-Seite mit dem Formular als auch das Ergebnis erzeugt, kann
man anhand dieser Liste feststellen, ob das Formular vollständig ausgefüllt wurde.
Auch beim Debuggen lohnt es sich param()
ohne Argumente aufzurufen, um die
Schlüssel und Werte des Formulars auszugeben. Der Code dazu würde
folgendermaßen lauten:
foreach $key (param()) {
print "$key hat den Wert ", param($key), "\n";
}
Beachten Sie, dass die Parameter im Array in der gleichen Reihenfolge stehen, wie sie vom Browser ursprünglich gesendet wurden. In den meisten Fällen entspricht das der Reihenfolge, in der sie auf der Seite erscheinen. Da es jedoch dafür keine Garantie gibt, sind Sie am besten beraten, wenn Sie auf jedes Formularelement explizit Bezug nehmen - falls Ihnen die Reihenfolge wichtig ist.
Wird die Subroutine param()
mit dem Namen eines Formularelements als Argument
aufgerufen, liefert Sie entweder den Wert dieses Formularelements zurück oder undef
,
wenn zu diesem Formularelement kein Wert geschickt wurde. Auf diese Art und
Weise werden Sie param()
wahrscheinlich am häufigsten in Ihren CGI-Skripten
aufrufen. Der Schlüssel, den Sie als Argument für param()
verwenden, muss mit dem
Namen des Formularelements in der HTML-Datei genau übereinstimmen. Um zum
Beispiel den Wert eines Textfeldes zu erhalten, das als <INPUT NAME="foozle"
>
definiert wurde, müssen Sie param('foozle')
eingeben. Meistens erhalten Sie einen
einfachen skalaren Wert als Antwort. Manche Formularelemente, bei denen
Mehrfachauswahl möglich ist, geben jedoch eine Liste der gewählten Optionen
zurück. Es ist Ihre Aufgabe, die verschiedenen Werte, die Sie aus einem Formular
zurückerhalten, in dem CGI-Skript zu verarbeiten.
Ein Großteil des CGI-Skripts besteht in der Regel aus dem HTML-Code, der für die
Antwort erzeugt wird. Die Skripts, die wir für CGI schreiben, enthalten wahrscheinlich
mehr print
-Anweisungen als alle anderen Skripts, die wir bisher geschrieben haben.
Um eine HTML-Ausgabe zu erzeugen, geben Sie einfach, wie bei jedem anderen Skript, die auszugebenden Zeilen weiter an die Standardausgabe. Sie können dazu mehrere Wege einschlagen:
Für den ersten Weg rufen Sie print
einfach mit dem auszugebenden HTML-Code auf
- so wie Sie es bereits die ganze Zeit gemacht haben:
print "<HTML><HEAD><TITLE>Dies ist eine Webseite</TITLE></HEAD>\n";
print "<BODY BGCOLOR=\"white\">\n";
# und so weiter
print
-Anweisungen bereiten zwar keine Probleme, können aber manchmal recht
unhandlich sein, besonders wenn die Ausgabe recht umfangreich ist oder Sie es mit
verschachtelten Anführungszeichen zu tun haben (wie bei dem Wert »white
« im
obigen Beispiel). Wenn Sie einen größeren HTML-Block auszugeben haben, können
Sie von einer speziellen Perl-Option, den sogenannten »Hier-Dokumenten«, Gebrauch
machen. Der Name mutet seltsam an, besagt aber einfach: »Gib alles bis hier aus.« Ein
Hier-Dokument könnte zum Beispiel folgendermaßen aussehen:
print <<EOF;
Diese Zeilen werden so ausgegeben
wie sie hier erscheinen; Sie benötigen keine zusätzlichen
print-Anweisungen, "Anführungszeichen mit Escape-Zeichen"
oder besonderen Neue-Zeile-Zeichen. So wie Sie es hier sehen.
EOF
Dieser kurze Perl-Code würde folgendes Ergebnis erzeugen:
Diese Zeilen werden so ausgegeben
wie sie hier erscheinen; Sie benötigen keine zusätzlichen
print-Anweisungen, "Anführungszeichen mit Escape-Zeichen"
oder besonderen Neue-Zeile-Zeichen. So wie Sie es hier sehen.
Mit anderen Worten, der ausgegebene Text entspricht fast genau dem Text in dem
Skript. Die am Anfang stehende print
-Anweisung im Hier-Dokument legt fest, wie
weit gelesen und ausgegeben werden soll. Zur Kennzeichnung des Endes des Hier-
Dokuments wird ein Endemarker definiert, bei dem es sich entweder um ein Wort, das
in der Sprache keine anderweitige Bedeutung hat, oder um einen String in
Anführungszeichen handeln kann. Ich habe in obigem Beispiel EOF
(End of File für
»Ende der Datei«) gewählt, da dies eine nette, kurze und allgemein übliche Abkürzung
ist, die sich gut vom Rest des Skripts abhebt.
Wenn Sie den Endemarker in Anführungszeichen setzen, legt die Art der
Anführungszeichen fest, wie der Text innerhalb des Hier-Dokuments bearbeitet wird.
Ein einfaches Wort, wie das von mir oben verwendete EOF
, erlaubt
Variableninterpolation - so als ob der Text innerhalb des Hier-Dokuments in
doppelten Anführungszeichen stehen würde. Den gleichen Effekt erzielen Sie, wenn
Sie das Wort in doppelte Anführungszeichen setzen. Ein in einfache
Anführungszeichen geklammerter Endemarker unterdrückt die Variableninterpolation
wie bei allen Strings in einfachen Anführungszeichen.
Das Ende eines Hier-Dokuments wird von dem Endemarker (Wort oder String)
angezeigt, mit dem das Hier-Dokument gestartet wurde, allerdings ohne die
Anführungszeichen. Der Endemarker steht allein auf einer Zeile ohne irgendwelche
führenden oder angehängten Zeichen oder Whitespaces. Nach dem Endemarkierer
können Sie ein weiteres Hier-Dokument starten, wieder auf print
-Anweisungen
zurückgreifen oder beliebige anderen Zeilen in Perl-Code schreiben.
Weitere Informationen zu den Hier-Dokumenten finden Sie in der perldata-Manpage.
Die dritte Möglichkeit, HTML-Code in einem CGI-Skript zu erzeugen, ist die
Verwendung der dafür vorgesehenen CGI.pm
-Subroutinen. Für die meisten HTML-
Tags gibt es in CGI.pm
äquivalente Perl-Subroutinen. Diese CGI.pm
-Subroutinen haben
den Vorteil, dass Sie auf diese Weise Variablenreferenzen einfügen (mittels Strings in
doppelten Anführungszeichen) und schnell bestimmte HTML-Elemente, wie zum
Beispiel Formularelemente, erzeugen können. Außerdem verfügt CGI.pm
über die
Subroutinen start_html()
und end_html()
, mit denen Anfang und Ende einer
HTML-Datei ausgegeben werden. Alle Subroutinen zur Erzeugung von HTML-Code
liefern Strings zurück. Um diese Strings tatsächlich auszugeben, müssen Sie sie einer
print
-Anweisung übergeben.
Manche Subroutinen erzeugen einzelne Tags, die keine Argumente übernehmen (zum
Beispiel p()
und hr()
, die <P>
und <HR>
erzeugen). Andere wiederum erzeugen
paarweise öffnende und schließende Tags. Tags dieser Art übernehmen ein oder
mehrere String-Argumente für den Text zwischen das öffnende und das schließende
Tag.
Subroutinen können ineinander verschachtelt werden:
h1('Dies ist eine Überschrift'); # <H1>Dies ist eine Überschrift</H1>
b('Bold'); # <B>Bold</B>
b('mal fett mal ', i('kursiv')); # <B>mal fett mal <I>kursiv</I></B>
ol(
li('erstes Element'),
li('zweites Element'),
li('drittes Element'),
);
Wenn das auszugebende HTML-Tag selbst Attribute enthält, stellen Sie diese in
geschweifte Klammern {}
und trennen Sie Name und Wert des Attributs durch die
Zeichen =>
(wie bei einem Hash):
a({href=>"index.html", name=>"foo"}, "Homepage");
# <A HREF="index.html" NAME="foo">Homepage</A>
Fast alle HTML-Tags, die Sie in einer HTML-Datei finden können, sind als Subroutine
verfügbar. Für welche Tags Ihnen Subroutinen zur Verfügung stehen, hängt allerdings
davon ab, welche Gruppe von Subroutinen Sie in die use CGI
-Zeile importieren.
CGI.pm
enthält außerdem einen besonders robusten Satz an Subroutinen zur
Erzeugung von weiteren Formularelementen. Ich kann hier leider nicht auf alle einzeln
eingehen, deshalb möchte ich Sie auf die CGI.pm
-Dokumentation verweisen.
Im Verlauf unseres Hallo-Beispiels haben Sie bereits eine Möglichkeit kennengelernt, wie man Skripts vor der Installation auf dem Server debuggt. Dabei haben wir die CGI-Eingabe als Name/Wert-Paar entweder über die Skript-Befehlszeile oder über die Standardeingabe eingegeben. Dieser Mechanismus ist unschätzbar, wenn es darum geht, kleinere Fehler aufzudecken, die sich beim Schreiben der CGI-Skripts eingeschlichen haben. Wenn Sie das Skript von der Befehlszeile ausführen, können Sie auch den Perl-Debugger verwenden, um sicherzustellen, dass Ihr Skript ordnungsgemäß läuft, bevor es installiert wird.
Irgendwann ist es jedoch soweit, dass Sie das CGI-Skript installieren und vor Ort
ausführen müssen, um seine ordnungsgemäße Funktionsweise sicherzustellen. Wenn
das Skript erst einmal installiert ist, kann das Debuggen allerdings Schwierigkeiten
bereiten, da Fehler normalerweise in wenig hilfreichen Meldungen (wie Server Error
500
) dem Browser mitgeteilt werden oder in Fehlerprotokollen landen, die weder
Identifizierer noch Zeitmarkierungen haben, anhand derer man sehen könnte, welcher
Fehler auf Sie zurückgeht.
An dieser Stelle kommt das Modul CGI::Carp
ins Spiel. CGI::Carp
ist Bestandteil von
CGI.pm
und sollte deshalb wie letzteres Modul auch Teil Ihrer Standard-Perl-Version
sein. (Überprüfen Sie das, indem Sie in dem CGI-Unterverzeichnis des Perl-
Verzeichnisses lib danach suchen. Es gibt auch noch ein reguläres Carp
-Modul, das
verwandt, aber nicht dasselbe ist.) Carp
wird verwendet, um Fehlermeldungen für CGI-
Skripts zu erzeugen, die Ihnen dann beim Debuggen dieser Skripts sehr dienlich sein
können. Vor allem das Schlüsselwort fatalsToBrowser
kann für das Debuggen sehr
nützlich sein, da es alle Perl-Fehler in dem CGI-Skript als HTML-Code ausgibt, der als
Antwort auf das abgeschickte Formular in dem Browser angezeigt wird, der wiederum
das Formular angefordert hat. Um diese Fehler als Echo an den Browser zu schicken,
fügen Sie folgende use
-Zeile in den Anfang Ihres Skripts auf:
use CGI::Carp qw(fatalsToBrowser);
Abgesehen von fatalsToBrowser
enthält das CGI::Carp
-Modul neue Definitionen für
die Funktionen warn()
und die()
(und fügt die Subroutinen croak()
, carp()
und
confess()
hinzu), so dass Fehler mit vernünftigen Identifizierern ausgegeben werden
und im dem Fehlerprotokoll Ihres Webservers erscheinen. (Näheres zu croak()
,
carp()
und confess()
finden Sie in der Dokumentation zum Standard-Carp
-Modul.)
Zusammengefaßt läßt sich sagen, dass CGI::Carp
besonders nützlich zum Debuggen
Ihrer CGI-Skripts auf dem Server ist.
Unser »Hallo Welt«-Beispiel zu Beginn hat Ihnen vielleicht einen Vorgeschmack darauf gegeben, wie sich CGI-Skripts einsetzen lassen. Um wirklich von Nutzen zu sein, ist es aber zu einfach. Deshalb wollen wir im folgenden ein wesentlich komplexeres Skript betrachten, das eine webbasierte Umfrage verarbeitet. Das Skript zeichnet alle aus der Umfrage stammenden Daten auf, indem es die Eingabe des aktuellen Formulars verarbeitet und daraus Ergebnistabellen erzeugt, die auf allen bis dato eingesandten Daten basieren. In Abbildung 16.4 sehen Sie das Formular unserer kleinen Umfrage.
Abbildung 16.4: Eine einfache Web-Umfrage
Nachdem alle Fragen der Umfrage beantwortet wurden, verarbeitet das CGI-Skript diese Eingaben, fügt sie zu den bereits erhaltenen Daten hinzu und erzeugt eine Reihe von Tabellen, wie in Abbildung 16.5 zu sehen.
Abbildung 16.5: Die Ergebnisse der Web-Umfrage
Alle Daten der Umfrage werden in einer separaten Datei auf dem Webserver gespeichert. Über das CGI-Skript werden Sie diese Datendatei öffnen, lesen und in die Datei schreiben.
Beginnen wir mit dem HTML-Code für das Formular, damit Sie lernen, mit welchen Werten Sie es in dem CGI-Skript zu tun bekommen. In Listing 16.2 sehen Sie diesen HTML-Code:
<HTML>
<HEAD>
<TITLE>Kurze Umfage</TITLE>
</HEAD>
<BODY>
<H1>Nehmen Sie doch bitte an unserer Umfrage teil!</H1>
<FORM ACTION="/cgi-bin/survey.pl">
<P><STRONG>Alter: </STRONG><BR>
<INPUT TYPE="radio" NAME="age" VALUE="under18">Unter 18<BR>
<INPUT TYPE="radio" NAME="age" VALUE="18to34">18-34<BR>
<INPUT TYPE="radio" NAME="age" VALUE="35to50">35-50<BR>
<INPUT TYPE="radio" NAME="age" VALUE="50plus">50+
<P><STRONG>Geschlecht: </STRONG><BR>
<INPUT TYPE="radio" NAME="sex" VALUE="male">männlich<BR>
<INPUT TYPE="radio" NAME="sex" VALUE="female">weiblich
<P><STRONG>Sind Sie Perl-Programmierer? </STRONG><BR>
<INPUT TYPE="radio" NAME="perl" VALUE="yes">Ja<BR>
<INPUT TYPE="radio" NAME="perl" VALUE="no">Nein
<P><INPUT TYPE="submit" VALUE="Daten abschicken">
</FORM>
</BODY>
</HTML>
Einige wenige, aber wichtige Punkte möchte ich zu diesem HTML-Code anmerken.
Im Gegensatz zum vorangehenden Beispiel finden Sie hier keine Textfelder, sondern
Gruppen von Optionsfeldern (englisch: »radio buttons«). Beachten Sie, dass alle
Optionsfelder einer Gruppe den gleichen Namen haben (so heißen zum Beispiel alle
vier Optionsfelder in der Gruppe Alter »age
«). Damit wird verhindert, dass mehr als ein
Schalter in einer Gruppe zur Zeit ausgewählt werden kann. Das bedeutet wiederum,
dass in der Eingabe für Ihr Skript nur ein Wert pro Gruppe erscheint. Sie müssen die
Eingabe mit allen möglichen Werten vergleichen, um herauszufinden, welche Option
gewählt wurde.
Das CGI-Skript, das dieses Formular verarbeitet, hat vier Hauptaufgaben zu erledigen:
Listing 16.3 zeigt den Code für unser CGI-Skript mit Namen umfrage.pl
.
Listing 16.3: Das Skript umfrage.pl
1: #!/usr/bin/perl -w
2: use strict;
3: use CGI qw(:standard);
4:
5: my $results = 'umfrage_ergebnisse.txt';
6: my %data = ();
7: my $thing = '';
8: my $val = 0;
9:
10: open(RESULTS, $results) or
die "Ergebnisdatei konnte nicht geoeffnet werden: $!";
11: while (<RESULTS>) {
12: ($thing, $val) = split(' ');
13: $data{$thing} = $val;
14: }
15: close(RESULTS);
16:
17: # Gesamtsumme
18: $data{total}++;
19:
20: # Alter
21: if (!param('age')) { $data{age_na}++ }
22: else {
23: if (param('age') eq 'under18') { $data{age_under18}++; }
24: elsif (param('age') eq '18to34') { $data{age_18to34}++; }
25: elsif (param('age') eq '35to50') { $data{age_35to50}++; }
26: elsif (param('age') eq '50plus') { $data{age_50plus}++; }
27: }
28:
29: # Geschlecht
30: if (!param('sex')) { $data{sex_na}++ }
31: else {
32: if (param('sex') eq 'male') { $data{sex_m}++; }
33: elsif (param('sex') eq 'female') { $data{sex_f}++; }
34: }
35:
36: # Perl
37: if (!param('perl')) { $data{perl_na}++ }
38: else {
39: if (param('perl') eq 'yes') { $data{perl_y}++; }
40: elsif (param('perl') eq 'no') { $data{perl_n}++; }
41: }
42:
43: open(RESULTS, ">$results") or
die "In Ergebnisdatei kann nicht geschrieben werden: $!";
44: foreach $thing (keys %data) {
45: print RESULTS "$thing $data{$thing}\n";
46: }
47: close(RESULTS);
48:
49: print header;
50: print start_html('Danke');
51: print <<EOF;
52: <H1>Danke, dass Sie das Umfrageformular ausgefüllt haben!</H1>
53: <P>Die bisherigen Ergebnisse:
54: <P>Geschlecht:
55: <TABLE BORDER><TR><TH>Männlich</TH><TD>
56: EOF
57:
58: print &percent('sex_m'), "</TD></TR>\n";
59: print "<TR><TH>Weiblich</TH><TD>\n";
60: print &percent('sex_f'), "</TD></TR>\n";
61: print "<TR><TH>Keine Antwort</TH><TD>\n";
62: print &percent('sex_na'), "</TD></TR>\n";
63: print "</TABLE>\n";
64:
65: print "<P>Alter:\n";
66: print "<TABLE BORDER><TR><TH>Unter 18</TH><TD>\n";
67: print &percent('age_under18'), "</TD></TR>\n";
68: print "<TR><TH>18 bis 34</TH><TD>\n";
69: print &percent('age_18to34'), "</TD></TR>\n";
70: print "<TR><TH>35 bis 50</TH><TD>\n";
71: print &percent('age_35to50'), "</TD></TR>\n";
72: print "<TR><TH>Über 50</TH><TD>\n";
73: print &percent('age_50plus'), "</TD></TR>\n";
74: print "<TR><TH>Keine Antwort</TH><TD>\n";
75: print &percent('age_na'), "</TD></TR>\n";
76: print "</TABLE>\n";
77:
78: print "<P>Perl-Programmierer?\n";
79: print "<TABLE BORDER><TR><TH>Ja</TH><TD>\n";
80: print &percent('perl_y'), "</TD></TR>\n";
81: print "<TR><TH>Nein</TH><TD>\n";
82: print &percent('perl_n'), "</TD></TR>\n";
83: print "<TR><TH>Keine Antwort</TH><TD>\n";
84: print &percent('perl_na'), "</TD></TR>\n";
85: print "</TABLE>\n";
86:
87: print end_html;
88:
89: sub percent {
90: if (defined $data{$_[0]}) {
91: return sprintf("%.1f%%", $data{$_[0]} / $data{total} * 100);
92: }
93: else { return '0%'; }
94: }
Ich möchte dieses Skript nicht Zeile für Zeile durchgehen, da Sie einen großen Teil
davon schon in irgendeiner Form gesehen haben (und viele Zeilen nur aus print
-
Anweisungen bestehen). Statt dessen möchte ich Sie auf einige der wichtigeren Teile
dieses Skripts aufmerksam machen:
Zeile 5 speichert den Namen der Datei mit den Umfragedaten in der Variablen
$results
. Dabei wird davon ausgegangen, dass sich die Datei in dem gleichen
Verzeichnis befindet wie das CGI-Skript. Gegebenenfalls müssen Sie den Pfadnamen
in Ihrem Skript ändern. Die Datendatei besteht aus einem Satz von Datenschlüsseln
für die einzelnen Optionen in der Umfrage und »na«-Schlüsseln für den Fall, dass in
einer Gruppe keine Option ausgewählt wurde. Jeder Schlüssel hat einen Wert für die
Anzahl der »Stimmen«, die eingereicht wurden. In den Zeilen 10 bis 15 wird die
Datendatei geöffnet und die Daten in den Hash %data
eingelesen. Anschließend wird
die Datei direkt wieder geschlossen.
Die Datendatei - die hier im gleichen Verzeichnis steht wie das CGI-Skript - muss dem Webserver den Schreibzugriff erlauben. Für Unix-Systeme bedeutet dies, dass die Datei mit den entsprechenden Zugriffsberechtigungen versehen sein muss, so dass der Webserver mit seiner Benutzer- oder Gruppen-ID (in der Regel
nobody
) darauf zugreifen kann. Aber auch unter Windows müssen Sie Ihre Sicherheitseinstellungen entsprechend setzen. Wenn Sie das Skript auf einem Webserver ausführen und dabei Fehler erhalten, die besagen, dass in die Datei nicht geschrieben werden konnte (und die bei der Ausführung von der Befehlszeile aus nicht aufgetreten sind), sollten Sie die Zugriffsberechtigungen für die Datei prüfen.
Die Zeilen 17 bis 41 verarbeiten die Eingabe des Formulars in Gruppen, die mit den
Gruppen der Optionsschalter in der HTML-Datei (Alter, Geschlecht und Perl)
übereinstimmen. Beachten Sie, dass Sie für jede Gruppe testen müssen, ob eventuell
keine Antwort gegeben wurde (in diesem Falle wird nämlich für diese Gruppe kein
Schlüssel in dem param()
-Array, das Sie von CGI.pm
erhalten, eingerichtet.) Wurde
eine Auswahl getroffen, inkrementieren wir den Wert dieses Schlüssels in dem Daten-
Hash. Dabei verfolgen wir die Gesamtsumme (Zeile 17), die wir benötigen, um die
Prozentwerte für die Ausgabe zu berechnen.
Nachdem wir die Daten verarbeitet haben, können wir die neue Datendatei in die
gleiche Datei schreiben, je einen Datenschlüssel und -wert pro Zeile, getrennt durch
ein Leerzeichen. Die eigentliche Reihenfolge der Schlüssel ist nicht von Belang, da sie
vom Skript nur wieder aus der Datei in einen Hash gelesen werden. Eine einfache
foreach
-Schleife in den Zeilen 44 und 45 schreibt die neuen Werte in die Datendatei
(die wir in Zeile 43 zum Schreiben neu geöffnet haben).
Die zweite Hälfte des Skripts erzeugt als Ausgabe das aktuelle Ergebnis der Umfrage, die der Benutzer als Antwort erhält. Ab Zeile 49 erfolgt die Ausgabe, die mit dem Header beginnt (Zeile 49). Anschließend werden der Titel (Zeile 50) und mit Hilfe eines Hier-Dokuments (Zeile 51 bis 56) die ersten Zeilen HTML-Text ausgegeben.
Ab Zeile 58 wird das Ganze dann erst richtig interessant. Die restliche HTML-Datei
besteht aus Tabellen, in denen die aktuellen Ergebnisse der Umfrage präsentiert
werden. Ein Großteil der folgenden print
-Ausgabe wird für den HTML-Code für die
Tabellen benötigt. Die endgültigen Prozentzahlen werden mit einer von uns
definierten Hilfsroutine namens &percent()
berechnet. Die in den Zeilen 89 bis 94
definierte &percent()
-Routine erzeugt einen Prozent-String, der sich auf der Basis des
ihr übergebenen Werts geteilt durch die Gesamtzahl der Antworten errechnet. Diese
Routine stellt auch sicher, dass der gegebene Datenschlüssel tatsächlich einen Wert
hat (ist er gleich Null, erscheint er nicht im Hash %data
). Und zum Schluß formatiert
sie mit Hilfe der Funktion sprintf
die Prozentangaben mit einem Dezimalpunkt und
einem Prozentzeichen (beachten Sie, dass Sie aufgrund des sprintf
-Formatiercodes
nicht ohne weiteres ein einfaches Prozentzeichen ausgeben können; Sie müssen es als
%%
eingeben).
Wie ich bereits zu Beginn dieser Lektion erwähnt habe, könnte ich problemlos Seite
um Seite und Kapitel um Kapitel mit all den verschiedenen Aspekten von CGI füllen.
Eine genaue Beschreibung von CGI.pm
allein wäre schon wesentlich umfangreicher als
mein bescheidenes Kapitel hier. Dennoch gibt es einige Besonderheiten von CGI.pm
,
auf die ich noch näher eingehen möchte. Alle diese Besonderheiten finden Sie
natürlich in der Dokumentation zu CGI.pm
(perldoc CGI
weist Ihnen den Weg) und auf
der Webseite http://www.genome.wi.mit.edu/ftp/pub/software/WWW/
cgi_docs.html
.
Wenn Sie an weitergehenden Informationen zu CGI selbst interessiert sind, scheuen
Sie sich nicht, die Webseiten zu besuchen, die ich eingangs dieser Lektion erwähnt
habe, oder lesen Sie das Buch, das ich Ihnen dort empfohlen habe. Wenn Sie
Unterstützung brauchen, um Ihre CGI-Skripts auf verschiedenen Plattformen zum
Laufen zu bringen, schauen Sie doch mal in der Usenet-Newsgroup
comp.infosystems.www.authoring.cgi
nach.
Wenn Ihr CGI-Skript mit den Daten vom Browser aufgerufen wird, hält der Webserver
in seiner Umgebung einige interessante Werte bereit, die sich auf das Skript selbst, auf
den Webserver und auf das System, auf dem der Browser läuft, der das Formular
abgeschickt hat, beziehen. Auf Unix-Systemen werden diese Werte auch
Umgebungsvariablen genannt, auf die man innerhalb des Perl-Skripts mit dem Hash
%ENV zugreifen kann. Auf anderen Webservern erfolgt die Übergabe dieser Variablen
unter Umständen anders. In CGI.pm
jedoch finden Sie Subroutinen, um auf diese
Variablen in einer Art und Weise zuzugreifen, die plattform- und Webserver-
unabhängig ist. Sie müssen diese Subroutinen nicht unbedingt in Ihren CGI-Skripten
verwenden, aber vielleicht finden Sie die Daten ganz nützlich.
Tabelle 16.1 enthält die CGI.pm
-Subroutinen zu den CGI-Variablen.
Tabelle 16.1: Die Subroutinen zu den CGI-Variablen
Ein Browser kann CGI-Skripts auf zwei Wegen aufrufen: via POST
oder via GET
. GET
kodiert die Formularelemente direkt in den URL, während POST
die Formularelemente über die Standardeingabe sendet. Darüber hinaus kann GET
dazu verwendet werden, um ein Formular abzuschicken, das eigentlich nicht vorhanden ist - Sie könnten zum Beispiel einen Link haben, bei dem der URL die hartkodierten Formularelemente zum Abschicken enthält.
CGI.pm
verarbeitet beide Wege und speichert sie in dem Parameter-Array Ihres CGI-
Skripts, so dass Sie sich keine Gedanken darüber machen müssen, welche Methode
zum Abschicken des Skripts verwendet wurde. Wenn Sie wirklich daran interessiert
sind, die Parameter aus dem URL herauszulesen, verwenden Sie statt param()
die
Funktion url_param()
.
Manchmal ist das Ergebnis eines CGI-Skripts keine HTML-Datei, sondern statt dessen
ein Verweis auf eine existierende HTML-Datei auf dem eigenen oder einem beliebigen
Server. CGI.pm
unterstützt diese Art von Ergebnis durch die Subroutine redirect()
:
print redirect('http://www.andererserver.com/anderedatei.html');
Mit redirect
teilen Sie dem Browser des Benutzers mit, dass er nicht irgendeinen
HTML-Code auf dem Bildschirm anzeigen, sondern eine bestimmte Datei im Web
suchen soll. Da ein CGI-Skript, das redirect
aufruft, keine neue Webseite erzeugt,
sollten Sie in der Ausgabe eines CGI-Skripts redirect
nicht mit irgendeinem HTML-
Code kombinieren.
Mit CGI.pm
können Sie sogar Cookie-Werte verwalten und Dateien bearbeiten, die
über den Upload-Mechanismus der HTML-Formulare hochgeladen werden. Zur
Verwaltung von Cookies dient die Subroutine cookie()
aus CGI.pm
. Das Hochladen
von Dateien verläuft ähnlich wie die Bearbeitung normaler Formularelemente. Die
Subroutine param()
wird verwendet, um den Dateinamen zurückzuliefern, der in dem
Formular eingegeben wurde. Dieser Dateiname ist gleichzeitig auch ein Datei-Handle,
der offen ist und aus dem Sie Zeilen mit den Standard-Perl-Mechanismen auslesen
können.
Zu beiden Themen finden Sie weitere Informationen in der CGI.pm
-Dokumentation.
Jedes CGI-Skript stellt ein potentielles Sicherheitsloch auf Ihrem Webserver dar. Jede beliebige Person, die durch das Web streift, kann CGI-Skripts auf Ihrem Server mit irgendwelchen Eingaben ausführen lassen. Je nachdem wie sorglos Sie Ihre Skripts schreiben und wie entschlossen die Gegenpartei ist, kann Ihr CGI-Skript für böswillige Nutzer Schlupflöcher aufweisen, die diese nutzen können, um in Ihr System einzubrechen und schlimmstenfalls unwiderruflichen Schaden anzurichten.
Der beste Weg, ein Problem zu beseitigen, besteht darin, es zu erkennen und Schritte
zu seiner Vermeidung zu unternehmen. Ein empfehlenswerter Ansatzpunkt sind die
häufig gestellten Fragen zur Sicherheit im WWW unter http://www.genome.wi.mit.edu/
WWW/faqs/www-security-faq.html
. Perl verfügt außerdem über eine besondere Option,
den sogenannten Taint-Modus, der Sie daran hindert, unsichere Daten so zu
verwenden, dass Ihr System Schaden erleiden könnte. Im Kapitel 20, »Was noch
bleibt«, erfahren Sie mehr über den Taint-Modus.
Jedesmal, wenn ein in Perl geschriebenes CGI-Skript von einem Webserver aufgerufen wird, erfolgt ein Aufruf an Perl, um das Skript auszuführen. Für sehr stark frequentierte Webserver, auf denen eine Unmenge von CGI-Skripten ausgeführt wird, kann das bedeuten, dass viele Kopien von Perl gleichzeitig aufgerufen werden, was eine beträchtliche Last für die Maschine darstellt, die als Webserver fungiert. Um ihre Leistungsfähigkeit zu verbessern, verfügen viele Webserver über einen Mechanismus, mit dem der Perl-Interpreter in dem Webserver selbst eingebettet wird, so dass Skripts, die auf dem Webserver aufgerufen werden, nicht länger als CGI-Skripts ausgeführt werden. Statt dessen werden sie als Teile der Webserver-Bibliothek ausgeführt, wodurch der Overhead und die Anlaufzeit für die Skripts reduziert werden. Oftmals muss man die CGI-Skripts nicht einmal anpassen, um sie auf diese Weise ausführen zu lassen.
Unterschiedliche Webserver auf unterschiedlichen Plattformen verwenden unterschiedliche Mechanismen zur Einbettung von Perl. Sie müssen in der Dokumentation zu Ihrem Webserver nachlesen, ob mit Perl verfaßte CGI-Skripts eingebettet werden können und welche Tools und Module man dafür benötigt.
Wenn Sie einen ISAPI-Webserver unter Windows (beispielsweise den IIS) verwenden,
benötigen Sie das »Perl für ISAPI«-Paket (manchmal auch PerlIIS genannt). Dieses
Paket ist Teil der ActiveState-Version von Perl für Windows und wird automatisch
zusammen mit diesem Paket installiert. Sie können es aber auch separat von der
ActiveState-Web-Site unter http://www.activestate.com
herunterladen.
Wenn Sie einen Open-Source Apache-Webserver verwenden, finden Sie in mod_perl
ein Apache-Modul, das den Perl-Interpreter in den Apache-Webserver einbettet.
Damit erreichen Sie, dass Ihre in Perl geschriebenen CGI-Skripts schneller und
effizienter ausgeführt werden. Doch obwohl dies sicherlich das wichtigste Ergebnis ist,
ist es nicht das einzige. Darüber hinaus gestattet Ihnen die Einbettung fortan, mit Perl
auf alle internationalen Erweiterungs-APIs von Apache zuzugreifen, so dass Sie Ihren
Webserver mit Hilfe von Perl in nahezu unbegrenzter Weise anpassen können.
Weitere Informationen zum Apache-Webserver finden Sie unter http://
www.apache.org
und beim Apache/Perl-Integrationsprojekt, den Entwicklern von
mod_perl
, und zwar unter http://perl.apache.org
.
Nicht alles in Perl ist gleichbedeutend mit langen, komplizierten Skripten und vielen,
vielen Subroutinen. Manchmal sind es gerade die nützlichsten und interessantesten
Dinge, die man mit Hilfe von Modulen und ein wenig eigenem Code, der das Skript
zusammenhält, implementieren kann. CGI ist dafür ein hervorragendes Beispiel. Das
Modul CGI.pm
übernimmt den Großteil der harten Arbeit bei der CGI-Programmierung
und macht es leicht, die Werte aus einem Formular oder einer anderen CGI-Quelle
auszulesen und eine HTML-Datei als Ergebnis zurückzusenden.
Heute haben Sie ein wenig darüber gelernt, wie Perl für CGI eingesetzt werden kann.
Sie wissen jetzt, wie CGI abläuft - vom Browser zum Server zum Skript und wieder
zurück -, wie CGI.pm
in Ihr Skript importiert und dort genutzt werden kann und wie die
zahlreichen Möglichkeiten dieses Moduls Ihr Leben mit CGI angenehmer machen.
Wir haben ein umfangreicheres CGI-Beispiel gesehen: ein Umfrageformular, das die
Umfragedaten in einer externen Datei abspeichert. Ich kann zwar nicht garantieren,
dass diese Lektion Ihnen genügend Wissen vermittelt hat, um CGI-Skripts für
beliebige Aufgaben zu erstellen (weil ich dazu zuviel in dieser Lektion auslassen
mußte), aber ich hoffe, dass sich die Lektion als eine gute Ausgangsbasis erweist, auf
der Sie aufbauen können.
Die in dieser Lektion vorgestellten Subroutinen sind alle Teil der CGI.pm
-Moduls und
umfassen:
param()
- liest die Parameter, die dem CGI-Skript, normalerweise als Teil des
übersendeten Formulars, übergeben wurden. param()
ohne Argumente liefert eine
Liste der verfügbaren Schlüssel (Namen der Formularelemente) zurück. param()
mit einem Schlüsselargument liefert den Wert für diesen Schlüssel zurück.
print_header()
- gibt den CGI-Header für die Ausgabe aus. print_header()
ohne
Argumente geht davon aus, dass die Ausgabe im HTML-Format erfolgt.
start_html()
- erzeugt den obersten Teil einer HTML-Seite einschließlich der
Tags <HTML>
, <HEAD>
, <TITLE>
und <BODY>
. Unterschiedliche Argumente für
start_html()
erzeugen unterschiedliche Werte für den HTML-Code (so setzt zum
Beispiel ein einzelnes String-Argument den Titel der Seite).
end_html()
- erzeugt die schließenden Tags (</BODY>
und </HTML>
) für die Ausgabe.
Frage:
Ich habe eine Reihe von CGI-Skripten gesehen, die in Perl geschrieben waren und
trotzdem keinen Gebrauch von CGI.pm
gemacht haben. Statt dessen verwenden
diese Skripts andere Bibliotheken wie z.B. cgi-lib.pl
. Sind diese Skripts schlecht
und sollten korrigiert werden?
Antwort:
Nicht unbedingt. Es gibt im Web etliche Bibliotheken zur Erstellung von CGI-
Skripten mit Perl, und cgi-lib.pl
ist eine der bekanntesten. Sie können
bedenkenlos diese anderen Bibliotheken verwenden. Ich habe mich in diesem
Kapitel für CGI.pm
entschieden, da es inzwischen der Standard für Perl im
Zusammenspiel mit CGI geworden ist. Es ist ein unproblematisches Modul,
das den Standard-Modul-Konventionen folgt, bei Bedarf objektorientiert
genutzt werden kann und, was am wichtigsten ist, Teil der Standard-Perl-
Version ist. Damit hat es einen unschlagbaren Vorteil gegenüber anderen
Bibliotheken.
Frage:
Meine CGI-Skripts lassen sich von der Befehlszeile aus ausführen, nicht jedoch
von einer Webseite. Was mache ich falsch?
Antwort:
In Anbetracht der vielen verschiedenen Plattformen und Webserver, die es
gibt, läßt sich diese Frage nicht so einfach beantworten. Ist das Skript eine
ausführbare Datei? Ist das Skript in einem »offizielles« CGI-Verzeichnis Ihres
Servers abgelegt (normalerweise ein spezielles cgi-bin
-Verzeichnis oder etwas
Ähnliches)? Sind die Zugriffsberechtigungen für Ihr Skript korrekt gesetzt
(Webserver führen CGI-Skripts als einen besonderen Benutzer mit begrenzten
Zugriffsrechten aus)? Sind Sie sicher, dass auf Ihrer Maschine überhaupt ein
Webserver installiert ist? Auf den Web-Sites, die ich Ihnen im Laufe dieser
Lektion genannt habe, finden Sie Tipps und Vorschläge zum Debuggen Ihrer
CGI-Skripts.
Frage:
Meine Website befindet sich auf einer Unix-Maschine. Dort kann ich CGI-Skripts
ausführen. Aber ich möchte meine CGI-Skripts lieber auf meinem Windows-NT-
PC zuhause schreiben und debuggen, so dass ich nicht die ganze Zeit eingeloggt
sein muss. Ist dies möglich?
Antwort:
Dank des Wunders der Plattformunabhängigkeit von Perl und des Moduls
CGI.pm
ist das selbstverständlich möglich. Sie müssen dazu einen Webserver
auf Ihrem NT-System installieren - am besten einer der ähnlich oder gleich
dem auf der Unix-Maschine ist. Danach können Sie lokal CGI-Skripts
installieren, debuggen und ausführen. Sie sollten allerdings auf Unterschiede
in den Pfadangaben der Dateien achten und auf die Art, in der verschiedene
Server mit CGI umgehen. Halten Sie Ihr Skript so einfach wie möglich und
Sie sollten wenig Arbeit damit haben, es auf Unix zu übertragen.
Frage:
Ich habe die Umfragedatei modifiziert, so dass sie jetzt mit einem Gästebuch-
ähnlichen Skript verwendet wird und es den Besuchern erlaubt, Kommentare zu
einer Webseite abzugeben. Allerdings habe ich Probleme damit, wenn mehrere
Besucher zur selben Zeit ihren Kommentar an die Webseite schicken. Manchmal
wird von mehreren Besuchern gleichzeitig in die Datei geschrieben, und
Kommentare gehen dadurch verloren, oder seltsame Dinge passieren. Was
mache ich falsch?
Antwort:
Das Umfragebeispiel in diesem Kapitel zeigt nur die Grundlagen der CGI-
Skripterstellung. Um kommerzielle Web-Sites zu unterstützen, müssen Sie
schon etwas tiefer einsteigen (ich empfehle, die von mir bereits genannten
Websites zu konsultieren und ein weiterführendes Buch anzuschaffen).
Besonders, wenn Sie mit einer externen Datei arbeiten, die potentiell von
mehreren Benutzern gleichzeitig beschrieben werden kann - wie das mit
jedem CGI-Skript möglich ist -, werden Sie diese Datei »sperren« müssen,
bevor in die Datei geschrieben wird, und anschließend die Sperre wieder
aufheben. Das könnte so einfach sein, wie eine weitere temporäre Datei
namens umfrage.lock
anzulegen. In Ihrem Skript würden Sie also, bevor Sie in
die Datei mit den Umfrageergebnissen schreiben, Folgendes tun:
sleep
-
Funktion) und erneut versuchen.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie zur Lektion des nächsten Tages übergehen.
CGI.pm
? Wo finden Sie es, und wie
nutzen Sie es?
param()
ein?
print
-Anweisungen?
<UL>
<LI>Ein Element
<LI>Zwei Elemente
<LI>Drei Elemente
</UL>
param()
ohne Argumente gibt Ihnen eine Liste der Namen
aller Formularelemente aus, die an das Skript geschickt wurden.
if (!param()) { $data{sex_na}++ }
else {
if (param() eq 'male') { $data{sex_m}++; }
elsif (param() eq 'female') { $data{sex_f}++; }
}
Hier die Antworten auf die Workshop-Fragen aus dem vorigen Abschnitt.
CGI.pm
hilft beim Schreiben, Ausführen und Debuggen von CGI-
Skripten. Es definiert eine Reihe von Subroutinen, mit denen die Ein- und
Ausgaben der CGI-Skripts bearbeitet werden können, sowie etliche Hilfsroutinen
zu fast jedem erdenklichen Aspekt der CGI-Skripterstellung.
CGI.pm
ist Teil der meisten aktuellen Perl-Versionen. Wenn Sie nicht
schon bereits darüber verfügen, können Sie es von dem weiter vorn in dieser
Lektion genannten URL herunterladen und auf Ihrem Computer installieren.
CGI.pm
-Modul zu nutzen, müssen Sie es, wie jedes andere Modul auch,
erst einmal importieren. Dazu verwenden Sie use
und ein Import-Tag wie
:standard
oder :all
.
param()
dient dazu, die Werte aller Formularelemente auf der
Webseite, die das Skript aufgerufen hat, zu ermitteln. Ohne Argumente
aufzurufen, liefert param()
eine Liste der Schlüssel zurück, die sich auf die Namen
der Formularelemente beziehen. Mit einem Schlüsselargument (einem String)
aufgerufen, liefert param()
den Wert zurück, der mit diesem Formularelement
verbunden ist.
print
-Anweisungen; beachten Sie eingebettete
Anführungszeichen!
CGI.pm
-Modul
print
-Anweisungen sowie Anführungszeichen mit Escape-Zeichen zu vermeiden.
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard);
my @keys = param();
print header;
print start_html('Hallo!');
print "<H1>Schlüssel/Wert-Paare</H1>\n";
print "<UL>\n";
foreach my $name (@keys) {
print "<LI>$name = ", param($name), "\n";
}
print "</UL>\n";
print end_html;
param()
wird ohne irgendwelche Argumente aufgerufen. In
einigen Fällen - wie zum Beispiel in Übung 1 - entspricht dies genau Ihren
Wünschen. In diesem Fall jedoch, in dem die Tests einen String-Wert erwarten,
sollte param()
besser mit einer Art von String-Argument aufgerufen werden, um
einen Wert aus den Formularparametern zu erhalten.
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard);
my $countfile = 'zaehler.txt';
my $count = '';
open(COUNT, $countfile) or
die "Zählerdatei konnte nicht geöffnet werden: $!";
while (<COUNT>) {
$count = $_;
}
close(COUNT);
$count++;
open(COUNT, ">$countfile") or
die "In Zählerdatei kann nicht geschrieben werden: $!";
print COUNT $count;
close(COUNT);
print header;
print start_html('Hallo!');
print "<H1>Hallo Welt</H1>\n";
print "<P>Diese Seite wurde bereits $count Mal besucht.\n";
print end_html;
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard);
my $guestbook = 'gaeste.txt';
my $mail = ''; # EMail-Adresse
my $comment = ''; # Kommentare
open(GUEST, $guestbook) or
die "Gästebuch konnte nicht geöffnet werden: $!";
print header;
print start_html('Kommentare');
print "<H1>Kommentare</H1>\n";
print "<P>Kommentare zu dieser Website!\n";
print "<HR>\n";
while (<GUEST>) {
($mail, $comment) = split(' ',$_,2);
if ($mail) {
if (!$comment) { $comment = "nichts\n"; }
else { print "<P><B>$mail sagt:</B> $comment"; }
}
}
$mail = param('mail');
$comment = param('comment');
print "<P><B>$mail sagt:</B> $comment\n";
open(GUEST, ">>$guestbook") or
die "Gästebuch konnte nicht geöffnet werden: $!";
print GUEST "$mail $comment\n";
print end_html;