CGI - Common Gateway Interface
# Dieses CGI-Skript erzeugt ein Formular
# und gibt die eingegebenen Werte zurück.
use CGI qw/:standard/;
print header,
start_html('Ein einfaches Beispiel'),
h1('Ein einfaches Beispiel'),
start_form,
"Wie lautet Ihr Name? ",textfield('name'),p,
"Wie lautet die Kombination?", p,
checkbox_group(-name=>'words',
-values=>['eenie','meenie','minie','moe'],
-defaults=>['eenie','minie']), p,
"Ihre Lieblingsfarbe? ",
popup_menu(-name=>'color',
-values=>['rot','grün','blau','zartrosa']),p,
submit,
end_form,
hr;
if (param()) {
print "Ihr Name lautet",em(param('name')),p,
"Die Schlüsselwörter sind: ",em(join(", ",param('words'))),p,
"Ihre Lieblingsfarbe ist",em(param('color')),
hr;
}
Diese Perl-Bibliothek verwendet Perl5-Objekte, um die Generierung von Web-Formularen und das Parsing der entsprechenden Inhalte zu vereinfachen. Dieses Paket definiert CGI-Objekte, Entitäten, die Werte des aktuellen Query-Strings enthalten, sowie weitere Zustandsvariablen. Durch die Verwendung der Methoden eines CGI-Objekts können Sie die an Ihr Skript übergebenen Schlüsselwörter und Parameter untersuchen. Sie können auch Formulare erzeugen, deren Anfangswerte aus der aktuellen Query stammen (d.h., Zustandsinformationen bleiben erhalten). Das Modul stellt eine Reihe abkürzender Funktionen zur Verfügung, die reines HTML erzeugen und Eingabe- sowie Codierungsfehler reduzieren. Es stellt auch Funktionen für einige der fortgeschritteneren Features der CGI-Programmierung bereit, wie etwa das Upload von Dateien, Cookies, die Kaskadierung von Stylesheets, Server-Push und Frames.
CGI.pm erlaubt auch einen einfachen, funktionsorientierten Programmierstil, falls die objektorientierten Features nicht benötigt werden sollten.
Die aktuelle Version von CGI.pm finden Sie unter
http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html ftp://ftp-genome.wi.mit.edu/pub/software/WWW/
Für die Programmierung mit CGI.pm gibt es zwei verschiedene Ansätze: einen objektorientierten sowie einen funktionsorientierten Ansatz. Beim objektorientierten Ansatz erzeugen Sie ein oder mehrere CGI-Objekte und nutzen dann die Objektmethoden, um die verschiedenen Elemente der Seite zu generieren. Jedes CGI-Objekt beginnt mit einer Liste benannter Parameter, die Ihrem CGI-Skript vom Server übergeben wurden. Sie können diese Objekte verändern, in einer Datei oder einer Datenbank abspeichern und regenerieren. Weil jedes Objekt dem "Zustand" des CGI-Skripts entspricht, und weil die Parameterliste jedes Objekts unabhängig von den anderen existiert, ist es Ihnen möglich, den Zustand des Skripts zu sichern und später wiederherzustellen.
Mit dem objektorientierten Ansatz können Sie eine einfache "Hallo Welt"-HTML-Seite wie folgt erzeugen:
#!/usr/local/bin/perl
use CGI; # CGI-Routinen laden.
$q = new CGI; # Neues CGI-Objekt erzeugen.
print $q->header, # HTTP-Header generieren.
$q->start_html('Hallo Welt'), # HTML einleiten.
$q->h1('Hallo Welt'), # Level-1-Header
$q->end_html; # HTML abschließen.
Beim funktionsorientierten Ansatz gibt es ein Standard-CGI-Objekt, mit dem Sie aber nur selten direkt arbeiten. Statt dessen rufen Sie einfach Funktionen auf, um CGI-Parameter zu ermitteln, HTML-Tags zu erzeugen, Cookies zu verwalten und so weiter. Mit diesem Ansatz steht Ihnen eine klarere Programmierschnittstelle zur Verfügung, allerdings sind Sie dabei auf nur jeweils ein Objekt beschränkt. Das nachfolgende Beispiel gibt die gleiche Seite aus wie oben, verwendet dabei aber die funktionsorientierte Schnittstelle. Die Hauptunterschiede liegen darin, daß wir nun eine Reihe von Funktionen in unseren Namensraum importieren (üblicherweise die "standard"-Funktionen) und kein CGI-Objekt erzeugen müssen.
#!/usr/local/bin/perl
use CGI qw/:standard/; # Standard-CGI-Routinen laden.
print header, # HTTP-Header generieren.
start_html('Hallo Welt'), # HTML einleiten.
h1('Hallo Welt'), # Level-1-Header
end_html; # HTML abschließen.
Die Beispiele in diesem Dokument verwenden den objektorientierten Ansatz. Wichtige Informationen zur funktionsorientierten Programmierung mit CGI.pm finden Sie unter "HOW TO IMPORT FUNCTIONS".
Die meisten Routinen von CGI.pm akzeptieren mehrere, manchmal bis zu 20 optionale Argumente! Um diese Schnittstelle zu vereinfachen, verwenden alle Routinen beim Aufruf ein benanntes Argument, das wie folgt aussieht:
print $q->header(-type=>'image/gif',-expires=>'+3d');
Jedem Argumentnamen steht ein Bindestrich voran. Weder die Schreibweise noch die Reihenfolge spielen in der Argumentliste eine Rolle. -type, -Type und -TYPE sind alle erlaubt. Tatsächlich muß nur das erste Argument mit einem Bindestrich beginnen. Besitzt das erste Argument einen Bindestrich, übernimmt CGI.pm den Bindestrich für alle nachfolgenden Argumente automatisch.
Wenn Sie möchten, können Sie auf den Bindestrich sogar ganz verzichten. Nachdem Sie ein CGI-Objekt erzeugt haben, rufen Sie die Methode use_named_parameters() mit einem Wert ungleich null auf. Damit teilen Sie CGI.pm mit, daß Sie ausschließlich benannte Parameter verwenden wollen:
$query = new CGI;
$query->use_named_parameters(1);
$field = $query->radio_group('name'=>'OS',
'values'=>['Unix','Windows','Macintosh'],
'default'=>'Unix');
Verschiedene Routinen werden häufig mit nur einem Argument aufgerufen. Bei diesen Routinen können Sie das einzelne Argument ohne den Argumentnamen angeben. header() ist eine dieser Routinen, wobei hier das einzelne Argument den Typ des Dokuments bestimmt.
print $q->header('text/html');
Weitere gleichgelagerte Routinen werden nachfolgend noch dokumentiert.
Manchmal erwarten benannte Argumente einen Skalar, manchmal eine Referenz auf ein Array und manchmal eine Referenz auf einen Hash. Häufig können Sie einen beliebigen Argumenttyp übergeben, und die Routine sucht sich das passendste Argument aus. Zum Beispiel wird die Routine param() dazu benutzt, um einzelne oder mehrere Werte festzulegen. Diese beiden Fälle sind nachfolgend aufgeführt:
$q->param(-name=>'veggie',-value=>'tomato'); $q->param(-name=>'veggie',-value=>'[tomato','tomahto','potato','potahto']);
Viele Routinen in CGI.pm sind im Modul nicht explizit definiert, sondern werden nach Bedarf generiert. Dabei handelt es sich um die "HTML-Kurzformen", die HTML-Tags erzeugen, die dann in dynamisch generierten Seiten verwendet werden. HTML-Tags besitzen sowohl Attribute (die attribut="wert"-Paare innerhalb des Tags selbst) als auch einen Inhalt (der Teil zwischen den öffnenden und schließenden Paaren). Um zwischen Attribut und Inhalt zu unterscheiden, verwendet CGI.pm eine Konvention, bei der HTML-Argumente als erstes Argument in Form einer Hashreferenz übergeben werden, während die Inhalte, falls es welche gibt, in den nachfolgenden Argumenten übergeben werden. Das sieht dann so aus:
Code HTML
---- --------------
h1() <H1>
h1('irgendein','Inhalt'); <H1>irgendein Inhalt</H1>
h1({-align=>left}); <H1 ALIGN="LEFT">
h1({-align=>left},'Inhalt'); <H1 ALIGN="LEFT">Inhalt</H1>
HTML-Tags werden später noch ausführlich beschrieben.
Viele CGI.pm-Neulinge sind verwirrt durch die Aufrufkonventionen für HTML-Kurzformen (bei denen die HTML-Tag-Attribute von geschweiften Klammern umschlossen sein müssen) und für normale Routinen (bei denen die Attribute auch ohne geschweifte Klammern verarbeitet werden). Lassen Sie sich nicht irritieren. Der Bequemlichkeit halber sind geschweifte Klammern überall optional, die Ausnahme bilden nur die HTML-Kurzformen. Wenn Sie wollen, können Sie jede Routine, die benannte Argumente verwendet, mit geschweiften Klammern aufrufen:
print $q->header( {-type=>'image/gif',-expires=>'+3d'} );
Wenn Sie den Switch -w verwenden, erhalten Sie eine Warnung, daß einige Argumentnamen von CGI.pm mit in Perl integrierten Funktionen kollidieren. Am häufigsten betroffen ist hiervon das Argument -values, mit dem aus mehreren Werten bestehende Menüs, Gruppen von Radiobuttons und ähnliches erzeugt werden. Um diese Warnung zu vermeiden, haben Sie mehrere Möglichkeiten:
Viele Routinen stellen etwas mehr oder weniger Sinnvolles mit einem unbekannten benannten Argument an. Zum Beispiel können Sie vom Standard abweichende HTTP-Header-Felder erzeugen, indem Sie diese als benannte Argumente übergeben:
print $q->header(-type => 'text/html',
-cost => 'Three smackers',
-annoyance_level => 'high',
-complaints_to => 'bit bucket');
Damit wird der folgende, vom Standard abweichende HTTP-Header erzeugt:
HTTP/1.0 200 OK Cost: Three smackers Annoyance-level: high Complaints-to: bit bucket Content-type: text/html
Beachten Sie die Art, wie Unterstriche automatisch in Bindestriche umgewandelt werden. HTML-generierende Routinen führen eine andere Form der Umwandlung durch.
Dieses Feature ermöglicht es Ihnen, mit den sich schnell ändernden HTTP- und HTML-"Standards" Schritt zu halten.
$query = new CGI;
Analysiert ("parst") die Eingabe (über POST sowie über GET) und speichert sie in einem Perl5-Objekt namens $query.
$query = new CGI(INPUTFILE);
Übergeben Sie ein Dateihandle an die new()-Methode, werden die Parameter aus der Datei (oder STDIN, oder was auch immer) gelesen. Diese Datei kann jede der beim Thema Debugging beschriebenen Formen besitzen (beispielsweise würde eine Reihe von TAG=WERT-Paaren - durch Zeilenvorschübe getrennt - funktionieren). Üblicherweise wird diese Art von Datei mit der save()-Methode (siehe unten) erzeugt. Mehrere Datensätze können gesichert und wiederhergestellt werden.
Perl-Puristen werden gerne hören, daß diese Syntax Referenzen auf Dateihandles - ja sogar Referenzen auf Dateihandle-Globs - erlaubt, die den "offiziellen" Weg für die Übergabe eines Dateihandles darstellen:
$query = new CGI(\*STDIN);
Sie können das CGI-Objekt auch mit einem FileHandle- oder IO::File-Objekt initialisieren.
Wenn Sie mit der funktionsorientierten Schnittstelle arbeiten und den CGI-Zustand über ein Dateihandle initialisieren wollen, müssen Sie das mit restore_parameters() erledigen. Damit wird das Standard-CGI-Objekt über das angegebene Dateihandle (re)initialisiert.
open (IN,"test.in") || die; restore_parameters(IN); close IN;
Sie können das Query-Objekt auch über eine Hashreferenz initialisieren:
$query = new CGI( {'dinosaur'=>'barney',
'song'=>'I love you',
'friends'=>[qw/Jessica George Nancy/]}
);
oder über einen richtig formatierten, URL-geschützten c:
$query = new CGI('dinosaur=barney&color=purple');
oder über ein bereits existierendes CGI-Objekt (momentan wird damit die Parameterliste kopiert, nicht aber die objektspezifischen Felder wie etwa Autoescaping):
$old_query = new CGI; $new_query = new CGI($old_query);
Um eine leere Query zu erzeugen, initialisieren Sie sie über einen leeren String oder Hash:
$empty_query = new CGI("");
- oder -
$empty_query = new CGI({});
@keywords = $query->keywords
Wenn das Skript als Ergebnis einer <ISINDEX>-Suche ausgeführt wird, können die erkannten Schlüsselwörter mit der Methode keywords() ermittelt werden. Zurückgeliefert wird eine entsprechende Liste.
@names = $query->param
Wurde das Skript mit einer Parameterliste aufgerufen (z.B. "name1=wert1&name2=wert2&name3=wert3"), gibt die Methode param() eine Liste aller Parameternamen zurück. Wurde das Skript als <ISINDEX>-Skript aufgerufen, erhalten Sie nur einen einzelnen Parameter namens 'keywords'.
HINWEIS: Seit der Version 1.5 enthält das Array die Parameternamen in der gleichen Reihenfolge, wie sie vom Browser übergeben wurden. Üblicherweise entspricht das der gleichen Reihenfolge, in der die Parameter im Formular definiert sind (was aber nicht Teil der Specs ist und daher nicht garantiert wird).
@values = $query->param('foo');
- oder -
$value = $query->param('foo');
Übergeben Sie der param()-Methode ein einzelnes Argument, um den Wert des benannten Parameters zu bestimmen. Besitzt der Parameter mehrere Werte (z.B. mehrere aktive Einträge einer Scroll-Liste), können Sie auch ein Array anfordern. Anderenfalls gibt die Methode einen einzelnen Wert zurück.
$query->param('foo','ein','array','mit','werten');
Damit setzen Sie den Wert des benannten Parameters 'foo' auf ein Wertearray. Dies ist eine Möglichkeit, den Wert eines Feldes zu ändern, NACHDEM das Skript bereits einmal aufgerufen wurde. (Eine andere Möglichkeit besteht darin, den Parameter -override zu verwenden, der von allen Methoden akzeptiert wird, die Formularelemente generieren.)
param()
erkennt auch einen an benannten Parametern orientierten Aufrufstil, der später noch im Detail erläutert wird:
$query->param(-name=>'foo',-values=>['ein','array','mit','werten']);
- oder -
$query->param(-name=>'foo',-value=>'der wert');
$query->append(-name=>'foo',-values=>['noch','mehr','werte']);
Damit wird ein Wert oder eine Werteliste an den benannten Parameter angehängt. Die Werte werden an das Ende des Parameters angehängt, wenn dieser bereits existiert. Anderenfalls wird der Parameter erzeugt. Beachten Sie, daß diese Methode nur die Aufrufsyntax für benannte Argumente erkennt.
$query->import_names('R');
Dies erzeugt eine Reihe von Variablen im Namensraum 'R', also beispielsweise $R::foo, @R:foo. Für Schlüsselwortlisten erscheint eine Variable @R::keywords. Wird kein Namensraum angegeben, geht die Methode von 'Q' aus. WARNUNG: Importieren Sie nichts nach 'main' - das ist ein ernsthaftes Sicherheitsrisiko!!!!
Bei älteren Versionen hieß diese Methode import(). Seit der Version 2.20 wurde dieser Name vollständig entfernt, um einen Konflikt mit dem Perl-Moduloperator import zu vermeiden.
$query->delete('foo');
Diese Routine löscht einen Parameter vollständig. Ist manchmal nützlich für das Zurücksetzen einzelner Parameter, die Sie zwischen Skriptaufrufen nicht weitergeben wollen.
Falls Sie die funktionsorientierte Schnittstelle verwenden, benutzen Sie statt dessen "Delete()", um einen Konflikt mit dem in Perl integrierten delete-Operator zu verhindern.
$query->delete_all();
Damit wird das CGI-Objekt vollständig gelöscht. Nützlich, um sicherzustellen, daß beim Erzeugen eines Formulars alle Standardwerte verwendet werden.
Verwenden Sie bei der funktionsorientierten Schnittstelle die Funktion Delete_all().
$q->param_fetch('address')->[1] = '1313 Mockingbird Lane';
unshift @{$q->param_fetch(-name=>'address')},'George Munster';
Wenn Sie auf die Parameterliste in einer Weise zugreifen müssen, die durch die obigen Methoden nicht abgedeckt wird, können Sie eine direkte Referenz ermitteln, indem Sie die Methode param_fetch() mit dem Namen des Parameters aufrufen. Auf diese Weise erhalten Sie eine Arrayreferenz auf die benannten Parameter zurück, die Sie auf jede gewünschte Weise manipulieren können.
Sie können auch mit benannten Argumenten arbeiten, indem Sie das Argument -name verwenden.
$query->save(FILEHANDLE)
Schreibt den aktuellen Zustand des Formulars an das übergebene Dateihandle. Diesen Zustand können Sie wiederherstellen, indem Sie ein Filehandle an die new()-Methode übergeben. Beachten Sie, daß es sich bei diesem Dateihandle um eine Datei, eine Pipe oder was auch immer handeln kann!
Das Format der gesicherten Datei ist wie folgt:
NAME1=WERT1 NAME1=WERT1' NAME2=WERT2 NAME3=WERT3 =
Sowohl der Name als auch der Wert sind URL-geschützt. CGI-Parameter mit mehreren Werten werden mit sich wiederholenden Namen angegeben. Datensätze einer Session werden durch ein einzelnes Gleichheitszeichen getrennt. Sie können mehrere Datensätze sichern und mit wiederholten Aufrufen von new wieder einlesen. Sie können das auch über mehrere Sessions hinweg machen, indem Sie die Datei im Anhänge-Modus öffnen. Auf diese Weise können Sie ein einfaches Gästebuch aufbauen oder eine Liste der Benutzerabfragen führen. Hier ein kurzes Beispiel für die Erzeugung von Datensätzen über mehrere Sessions hinweg:
use CGI;
open (OUT,">>test.out") || die;
$records = 5;
foreach (0..$records) {
my $q = new CGI;
$q->param(-name=>'counter',-value=>$_);
$q->save(OUT);
}
close OUT;
# Erneut öffnen (lesen)
open (IN,"test.out") || die;
while (!eof(IN)) {
my $q = new CGI(IN);
print $q->param('counter'),"\n";
}
Das zum Sichern/Wiederherstellen verwendete Format entspricht dem vom Whitehead Genome Center verwendeten Format zum Datenaustausch ("Boulderio") und kann mit Boulderio-Utilities verändert, ja sogar in Datenbanken übernommen werden. Details hierzu finden Sie unter http://www.genome.wi.mit.edu/genome_software/other/boulder.html.
Sie können diese Methode auch mit der funktionsorientierten Schnittstelle verwenden. Der exportierte Name dieser Methode lautet save_parameters().
Um die funktionsorientierte Schnittstelle verwenden zu können, müssen Sie angeben, welche CGI.pm-Routinen bzw. welcher Satz von Routinen in den Namensraum Ihres Skripts zu importieren ist. Mit diesem Import ist ein kleiner Overhead verbunden, aber er ist nicht sehr groß.
use CGI <Liste der Methoden>;
Die aufgeführten Methoden werden in das aktuelle Paket importiert. Sie können sie direkt aufrufen, ohne vorher ein CGI-Objekt erzeugen zu müssen. Das folgende Beispiel zeigt, wie die Methoden param() und header() importiert und dann direkt genutzt werden können:
use CGI 'param','header';
print header('text/plain');
$zipcode = param('zipcode');
Weitaus häufiger werden Sie einen oft verwendeten Satz von Funktionen importieren, indem Sie diese Gruppe über den Namen ansprechen. Allen Funktionsgruppen wird ein Doppelpunkt vorangestellt, also beispielsweise ":html3" (für im HTML3-Standard definierte Tags).
Hier ist eine Liste der importierbaren Funktionsgruppen:
%TAGS definiert ist. Importieren Sie einen Funktionsnamen, der kein Bestandteil von CGI.pm ist, betrachtet das Modul ihn als neuen HTML-Tag und generiert die entsprechende Unterroutine. Diese können Sie dann wie jeden anderen HTML-Tag verwenden. Auf diese Weise sind Sie dem sich schnell ändernden HTML-"Standard" gewachsen. Nehmen wir beispielsweise einmal an, Microsoft kommt mit einem neuen Tag namens <GRADIENT> heraus (der den Bildschirmhintergrund des Benutzers mit einem ständig rotierenden Farbspektrum füllt, bis seine Maschine neu gebootet wird). Sie müssen nicht auf eine neue Version von CGI.pm warten, um den neuen Tag direkt nutzen zu können:
use CGI qw/:standard :html3 gradient/;
print gradient({-start=>'red',-end=>'blue'});
Beachten Sie, daß CGI.pm im Interesse der Ausführungsgeschwindigkeit nicht die Standard-Exporter-Syntax zur Angabe von Ladesymbolen verwendet. Dies könnte sich in Zukunft ändern.
Wenn Sie irgendeine der zustandsverarbeitenden CGI-Methoden oder formulargenerierende Methoden verwenden, wird beim ersten Aufruf einer Methode, die ein Objekt benötigt, automatisch ein Standard-CGI-Objekt erzeugt und initialisiert. Hierzu gehören param(), textfield(), submit() und so weiter. (Falls Sie direkt auf das CGI-Objekt zugreifen müssen, finden Sie es in der globalen Variable $CGI::Q.) Durch den Import von CGI.pm-Methoden können Sie rein optisch sehr elegante Skripten erzeugen:
use CGI qw/:standard/;
print
header,
start_html('Einfaches Skript'),
h1('Einfaches Skript'),
start_form,
"Wie lautet Ihr Name? ",textfield('name'),p,
"Wie lautet die Kombination?",
checkbox_group(-name=>'words',
-values=>['eenie','meenie','minie','moe'],
-defaults=>['eenie','moe']),p,
"Ihre Lieblingsfarbe?",
popup_menu(-name=>'color',
-values=>['rot','grün','blau','zartrosa']),p,
submit,
end_form,
hr,"\n";
if (param) {
print
"Ihr Name ist ",em(param('name')),p,
"Die Schlüsselwörter sind: ",em(join(", ",param('words'))),p,
"Ihre Lieblingsfarbe ist",em(param('color')),".\n";
}
print end_html;
Zusätzlich zu den Funktionsgruppen gibt es eine Reihe von Pragmas, die importiert werden können. Pragmas, denen immer ein Bindestrich vorsteht, ändern auf verschiedene Arten die Funktionsweise der CGI.pm-Funktionen. Pragmas, Funktionsgruppen und einzelne Funktionen können alle in der gleichen use()-Zeile importiert werden. Zum Beispiel importiert die folgende use-Anweisung die Gruppe der Standardfunktionen und deaktiviert den Debugging-Modus (Pragma -no_debug):
use CGI qw/:standard -no_debug/;
Nachfolgend die aktuelle Liste der Pragmas:
use CGI qw(-any);
$q=new CGI;
print $q->gradient({speed=>'fast',start=>'red',end=>'blue'});
use CGI qw(-compile :standard :html3);
use CGI qw(-compile :all);
compile() (siehe unten). ?name=fred;age=24;favorite_color=3
self_url() und query_string() nicht emittiert, solange das Pragma -newstyle_urls nicht angegeben ist. use CGI qw(-no_debug :standard);
use CGI qw(-no_debug :standard);
restore_parameters(join('&',@ARGV));
Jede dieser Funktionen erzeugt ein HTML- oder HTTP-Fragment, das direkt im Browser erscheint, an einen String angehängt oder zur späteren Verwendung in einer Datei abgelegt werden kann.
print $query->header;
- oder -
print $query->header('image/gif');
- oder -
print $query->header('text/html','204 No response');
- oder -
print $query->header(-type=>'image/gif',
-nph=>1,
-status=>'402 Payment required',
-expires=>'+3d',
-cookie=>$cookie,
-Cost=>'$2.00');
header() gibt den Content-type:-Header zurück. Sie können einen eigenen MIME-Typ angeben, anderenfalls wird text/html genommen. Als optionalen zweiten Parameter können Sie den Statuscode zusammen mit einer für Menschen verständlichen Nachricht übergeben. Zum Beispiel können Sie 204, "No response" angeben, um ein Skript zu erzeugen, das den Browser anweist, nichts zu tun.
Das letzte Beispiel zeigt die Verwendung benannter Argumente zur Übergabe von Argumenten an CGI-Methoden, die mit benannten Parametern arbeiten. Bekannte Parameter sind -type, -status, -expires und -cookie. Bei allen anderen Parametern wird der führende Bindestrich entfernt, und die Parameter werden in Header-Felder umgewandelt, was es Ihnen erlaubt, jeden von Ihnen gewünschten HTTP-Header anzugeben. Enthaltene Unterstriche werden dabei in Bindestriche umgewandelt:
print $query->header(-Content_length=>3002);
Die meisten Browser legen die Ausgaben von CGI-Skripten nicht im Cache ab. Jedesmal lädt der Browser die Seite erneut, und das Skript wird erneut aufgerufen. Sie können dieses Verhalten mit dem Parameter -expires ändern. Geben Sie diesem Parameter ein absolutes oder relatives Ablaufintervall mit, legen einige Browser und Proxy-Server die Ausgabe des Skripts im Cache ab, bis die angegebene Ablaufzeit vorbei ist. Die folgenden Formen sind für das -expires-Feld gültig:
+30s 30 Sekunden von nun an +10m 10 Minuten von nun an +1h eine Stunde von nun an -1d gestern (d.h. so schnell wie möglich) now jetzt +3M in drei Monaten +10y in 10 Jahren Thursday, 25-Apr-1999 00:40:33 GMT zum angegebenen Zeitpunkt (Zeit & Datum)
Der Parameter -cookie generiert einen Header, der den Browser anweist, bei allen nachfolgenden Transaktionen mit dem Skript ein sogenanntes "Magic Cookie" bereitzustellen. Netscape-Cookies besitzen ein spezielles Format, das interessante Attribute wie etwa das Ablaufdatum umfaßt. Verwenden Sie die Methode cookie() zur Erzeugung und Bestimmung von Session-Cookies.
Wird der Parameter -nph auf wahr gesetzt, werden die für ein NPH-Skript ("no-parse-header") benötigten Header generiert. Das ist in Verbindung mit bestimmten Servern besonders wichtig, etwa dem Microsoft Internet Explorer, weil diese erwarten, daß alle Skripten NPH-Skripten sind.
print $query->redirect('http://somewhere.else/in/movie/land');
Manchmal wollen Sie kein eigenes Dokument erzeugen, sondern den Browser einfach irgendwo anders hin "umleiten" (redirect), wobei möglicherweise eine URL gewählt wird, die von der Tageszeit oder der Identität des Benutzers abhängt.
Die redirect()-Funktion leitet den Browser an eine andere URL um. Wenn Sie Redirection auf diese Weise verwenden, dürfen Sie zusätzlich nicht noch einen Header mit ausgeben. Seit der Version 2.0 wird sowohl der inoffizielle Location:-Header als auch der offizielle URI:-Header erzeugt. Das sollte den meisten Servern und Browsern genügen.
Ein Hinweis, den ich hier noch anbringen möchte, ist, daß relative Links möglicherweise nicht richtig funktionieren, wenn Redirection auf ein anderes Dokument Ihrer Site verweist. Das liegt an einer gutgemeinten Optimierung, die von einigen Servern durchgeführt wird. Die Lösung liegt darin, die vollständige URL (einschließlich des http:-Teils) des gewünschten Dokuments anzugeben.
Sie können auch benannte Argumente verwenden:
print $query->redirect(-uri=>'http://somewhere.else/in/movie/land',
-nph=>1);
Wird der Parameter -nph auf wahr gesetzt, werden die für ein NPH-Skript ("no-parse-header") benötigten Header generiert. Das ist in Verbindung mit bestimmten Servern besonders wichtig, etwa dem Microsoft Internet Explorer, weil diese erwarten, daß alle Skripten NPH-Skripten sind.
print $query->start_html(-title=>'Secrets of the Pyramids',
-author=>'fred@capricorn.org',
-base=>'true',
-target=>'_blank',
-meta=>{'keywords'=>'pharaoh secret mummy',
'copyright'=>'copyright 1996 King Tut'},
-style=>{'src'=>'/styles/style1.css'},
-BGCOLOR=>'blue');
Nachdem der HTTP-Header erzeugt wurde, beginnen die meisten CGI-Skripten mit dem Absetzen eines HTML-Dokuments. Die Routine start_html() erzeugt den Anfang der Seite, zusammen mit vielen optionalen Informationen, die das Erscheinungsbild und das Verhalten der Seite bestimmen.
Die Methode liefert einen konservierten HTML-Header und den öffnenden <BODY>-Tag zurück. Alle Parameter sind optional. Als benannte Parameter werden -title, -author, -base, -xbase und -target (eine Erklärung finden Sie weiter unten) akzeptiert. Jeder zusätzliche Parameter, etwa das inoffizielle Netscape-Attribut BGCOLOR, wird dem <BODY>-Tag hinzugefügt. Zusätzlichen Parametern muß ein Bindestrich voranstehen.
Das Argument -xbase ermöglicht einen HREF für den <BASE>-Tag, der sich von der aktuellen Position unterscheidet:
-xbase=>"http://home.mcom.com/";
Alle relativen Links werden relativ zu diesem Tag interpretiert.
Das Argument -target erlaubt ein Standard-Ziel-Frame für alle Links und Formulare der Seite. Wie damit umzugehen ist, erläutert die Netscape-Dokumentation zu Frames.
-target=>"answer_window"
Alle relativen Links werden relativ zu diesem Tag interpretiert. Sie können willkürliche Metainformationen an den Header anhängen, indem Sie das Argument -meta verwenden. Dieses Argument erwartet einen Hash mit Name/Wert-Paaren, die die entsprechenden Metainformationen enthalten. Der Hash wird dann in eine Reihe von Header-<META>-Tags umgewandelt, die wie folgt aussehen:
<META NAME="keywords" CONTENT="pharaoh secret mummy"> <META NAME="description" CONTENT="copyright 1996 King Tut">
Der HTTP-EQUIV-Typ des <META>-Tags wird nicht unterstützt. Das liegt daran, daß Sie den HTTP-Header mit der header()-Methode direkt verändern können. Wenn Sie also beispielsweise den Refresh:-Header senden wollen, machen Sie das direkt mit der header()-Methode:
print $q->header(-Refresh=>'10; URL=http://www.capricorn.com');
Mit dem -style-Tag können Sie kaskadierende Stylesheets in Ihren Code einbinden. Weitere Informationen finden Sie im Abschnitt Eingeschränkte Unterstützung zur Kaskadierung von Stylesheets.
Sie können andere willkürliche HTML-Elemente in den <HEAD>-Abschnitt aufnehmen, indem Sie den -head-Tag benutzen. Um beispielsweise das recht selten verwendete <LINK>-Element in den Head-Abschnitt aufzunehmen, geben Sie folgendes ein:
print $q->start_html(-head=>Link({-rel=>'next',
-href=>'http://www.capricorn.com/s2.html'}));
Um mehrere HTML-Elemente in den <HEAD>-Abschnitt einzufügen, übergeben Sie einfach eine Arrayreferenz:
print $q->start_html(-head=>[
Link({-rel=>'next',
-href=>'http://www.capricorn.com/s2.html'}),
Link({-rel=>'previous',
-href=>'http://www.capricorn.com/s1.html'})
]
);
JAVASCRIPTING: Die Parameter -script, -noScript, -onLoad, -onMouseOver, -onMouseOut und -onUnload werden verwendet, um Aufrufe von Netscapes JavaScript in Ihre Seiten einzufügen. -script muß auf einen Textblock verweisen, der JavaScript-Funktionsdefinitionen enthält. Dieser Block wird in einem <SCRIPT>-Block innerhalb des HTML-(nicht HTTP-)Headers plaziert. Der Block wird innerhalb des Headers plaziert, um Ihrer Seite eine reale Chance zu geben, alle JavaScript-Funktionen griffbereit zu haben, selbst wenn der Benutzer den Stop-Button drückt, bevor die Seite vollständig geladen wurde. CGI.pm versucht, das Skript so zu formatieren, daß selbst Browser, die JavaScript eher unbedarft gegenüberstehen, nicht über den Code stolpern. Unglücklicherweise gibt es einige Browser, etwa Chimera für Unix, die sich dennoch verwirren lassen.
Die Parameter -onLoad und -onUnload verweisen auf Fragmente mit JavaScript-Code, der ausgeführt werden soll, wenn der Browser die Seite öffnet bzw. schließt. Üblicherweise handelt es sich bei diesen Parametern um Aufrufe von Funktionen, die im -script-Feld definiert wurden:
$query = new CGI;
print $query->header;
$JSCRIPT=<<END;
// Alberne Frage fragen.
function riddle_me_this() {
var r = prompt("Was geht morgens auf vier," +
"tagsüber auf zwei " +
"und abends auf drei Füßen?");
response(r);
}
// Alberne Antwort einlesen.
function response(answer) {
if (answer == "Mann")
alert("Richtig!");
else
alert("Falsch! Versuchen Sie es erneut.");
}
END
print $query->start_html(-title=>'Das Rätsel der Sphinx',
-script=>$JSCRIPT);
Verwenden Sie den Parameter -noScript, um einen HTML-Text zu übergeben, der von Browsern ausgegeben wird, die kein JavaScript unterstützen (oder bei denen es deaktiviert ist).
Netscape 3.0 erkennt verschiedene Attribute im <SCRIPT>-Tag, darunter LANGUAGE und SRC. Letzteres ist besonders interessant, weil dieses Attribut es uns möglich macht, den JavaScript-Code in einer Datei bzw. einem CGI-Skript zu halten, statt jede Seite mit dem Quelltext belasten zu müssen. Um diese Attribute nutzen zu können, übergeben Sie eine HASH-Referenz an den -script-Parameter, die einen oder mehrere -language-, -src- oder -code-Einträge enthält:
print $q->start_html(-title=>'Das Rätsel der Sphinx',
-script=>{-language=>'JAVASCRIPT',
-src=>'/javascript/sphinx.js'}
);
print $q->(-title=>'Das Rätsel der Sphinx',
-script=>{-language=>'PERLSCRIPT'},
-code=>'print "Hallo Welt!\n;"'
);
Ein letztes Feature ermöglicht es Ihnen, mehrere <SCRIPT>-Abschnitte in den Header aufzunehmen. Übergeben Sie die Liste der Skriptabschnitte einfach als Arrayreferenz. Damit können Sie unterschiedliche Quelldateien für verschiedene JavaScript-Dialekte festlegen:
print $q->start_html(-title=>'Das Rätsel der Sphinx',
-script=>[
{ -language => 'JavaScript1.0',
-src => '/javascript/utilities10.js'
},
{ -language => 'JavaScript1.1',
-src => '/javascript/utilities11.js'
},
{ -language => 'JavaScript1.2',
-src => '/javascript/utilities12.js'
},
{ -language => 'JavaScript28.2',
-src => '/javascript/utilities219.js'
}
]
);
Wenn Ihnen das etwas zu extrem erscheint, nehmen Sie einen Rat von mir an und bleiben Sie bei reinen CGI-Skripten.
Weitere Informationen zu JavaScript finden Sie unter:
http://home.netscape.com/eng/mozilla/2.0/handbook/javascript/
Die althergebrachten Parameter sind wie folgt:
print $query->end_html
Beendet ein HTML-Dokument durch Ausgabe des </BODY></HTML>-Tags.
$myself = $query->self_url; print "<A HREF=$myself>Ich rede mit mir selbst.</A>";
self_url() gibt eine URL zurück, die, wenn sie aktiviert wird, dieses Skript erneut aufruft. Alle Zustandsinformationen bleiben dabei erhalten. Dies ist am nützlichsten, wenn Sie innerhalb des Dokuments mit Hilfe interner Anker herumspringen wollen, ohne den aktuellen Inhalt von Formular(en) verlieren zu wollen. Der dazu nötige Trick ist im folgenden Beispiel zu sehen:
$myself = $query->self_url; print "<A HREF=$myself#table1>Siehe Tabelle 1</A>"; print "<A HREF=$myself#table2>Siehe Tabelle 2</A>"; print "<A HREF=$myself#yourself>Siehe selbst</A>";
Wenn Sie eine größere Kontrolle über die Rückgabe besitzen wollen, verwenden Sie statt dessen die url()-Methode.
Sie können auch einen unverarbeiteten Query-String mit query_string() empfangen:
$the_string = $query->query_string;
$full_url = $query->url(); $full_url = $query->url(-full=>1); #alternative Syntax $relative_url = $query->url(-relative=>1); $absolute_url = $query->url(-absolute=>1); $url_with_path = $query->url(-path_info=>1); $url_with_path_and_query = $query->url(-path_info=>1,-query=>1);
url()
liefert die URL des Skripts in unterschiedlichen Formaten zurück. Ohne irgendwelche Argumente wird die vollständige URL, inklusive Host-Namen und Port-Nummer, zurückgegeben.http://your.host.com/path/to/script.cgi
Sie können dieses Format mit den folgenden benannten Argumenten ändern:
/path/to/script.cgi
script.cgi
$color = $query->url_param('color');
Die param()-Methode wird immer den Inhalt des POSTing-Formulars zurückgeben und den Query-String von URL ignorieren. Um URL-Parameter zu erhalten, rufen Sie die Methode url_param() auf. Sie wird auf dieselbe Weise verwendet wie param(). Der Hauptunterschied besteht darin, daß sie das Lesen, aber nicht das Setzen der Parameter ermöglicht.
CGI.pm definiert allgemeine HTML-Kurzformmethoden für die meisten, wenn nicht für alle Tags von HTML 3 und HTML 4. HTML-Kurzformen sind nach einem einzelnen HTML-Element benannt und liefern ein HTML-Fragment zurück, das Sie ausgeben oder in jeder gewünschten Weise manipulieren können. Jede Kurzform gibt ein HTML-Codefragment zurück, das Sie an einen String anhängen, in einer Datei sichern oder einfach so ausgeben können, daß es direkt im Browser erscheint (der häufigste Fall).
Das nachfolgende Beispiel zeigt die Verwendung der HTML-Methoden:
$q = new CGI;
print $q->blockquote(
"Vor vielen, vielen Jahren lebte auf der Insel",
$q->a({href=>"http://crete.org/";},"Kreta"),
"ein Minotaurus namens ",
$q->strong("Fred."),
),
$q->hr;
Das führt zu folgendem HTML-Code (zur besseren Lesbarkeit wurden zusätzliche Zeilenvorschübe eingefügt):
<blockquote> Vor vielen, vielen Jahren lebte auf der Insel <a HREF="http://crete.org/";>Kreta</a> ein Minotaurus namens <strong>Fred.</strong> </blockquote> <hr>
Wenn Ihnen die Syntax zum Aufruf der HTML-Kurzformen nicht behagt, können Sie sie in Ihren Namensraum importieren und auf die Objektsyntax vollständig verzichten (mehr dazu im nächsten Abschnitt):
use CGI ':standard';
print blockquote(
"Vor vielen, vielen Jahren lebte auf der Insel",
a({href=>"http://crete.org/";},"Kreta"),
"ein Minotaurus namens",
strong("Fred."),
),
hr;
Die HTML-Methoden akzeptieren null, ein oder mehrere Argumente. Ohne Angabe von Argumenten erhalten Sie einen einzelnen Tag:
print hr; # <HR>
Geben Sie ein oder mehrere String-Argument(e) an, werden diese durch Leerzeichen miteinander verkettet und zwischen dem öffnenden und dem schließenden Tag plaziert:
print h1("Kapitel","1"); # <H1>Kapitel 1</H1>"
Handelt es sich beim ersten Argument um eine Hashreferenz, werden die Schlüssel und Werte des assoziativen Arrays zu den Attributen des HTML-Tags:
print a({-href=>'fred.html',-target=>'_new'},
"Neuen Frame öffnen");
<A HREF="fred.html",TARGET="_new">Neuen Frame öffnen</A>
Wenn Sie es vorziehen, können Sie die Bindestriche vor den Attributnamen auch weglassen:
print img {src=>'fred.gif',align=>'LEFT'};
<IMG ALIGN="LEFT" SRC="fred.gif">
Manchmal besitzt ein HTML-Tag-Attribut kein Argument. Zum Beispiel können geordnete Listen als COMPACT markiert werden. In diesem Fall sieht die Syntax vor, daß das Argument auf einen undefinierten String zeigt:
print ol({compact=>undef},li('one'),li('two'),li('three'));
Vor der CGI.pm-Version 2.41 war die Angabe eines leeren Strings (") als Attributargument gleichwertig mit der Angabe von undef. Das wurde geändert, um auch diejenigen zufriedenzustellen, die Tags der Form <IMG ALT=""> erzeugen wollen. Die beiden folgenden Codezeilen machen den Unterschied deutlich: img({alt=undef}) <IMG ALT> img({alt="}) <IMG ALT="">
Eine der starken Eigenschaften der HTML-Kurzformen ist ihr distributives Verhalten. Wenn Sie eine Referenz auf eine Liste als Argument übergeben, wird der Tag über jedes Element der Liste verteilt. Als Beispiel sei hier eine Möglichkeit aufgeführt, eine geordnete Liste zu generieren:
print ul(
li({-type=>'disc'},['Sneezy','Doc','Sleepy','Happy']);
);
Dieses Beispiel führt zu folgender HTML-Ausgabe:
<UL> <LI TYPE="disc">Sneezy</LI> <LI TYPE="disc">Doc</LI> <LI TYPE="disc">Sleepy</LI> <LI TYPE="disc">Happy</LI> </UL>
Das ist für die Generierung von Tabellen besonders nützlich:
print table({-border=>undef},
caption('Wann sollten Sie Gemüse essen?'),
Tr({-align=>CENTER,-valign=>TOP},
[
th(['Gemüse', 'Frühstück','Mittagessen','Abendessen']),
td(['Tomaten' , 'nein', 'ja', 'ja']),
td(['Broccoli' , 'nein', 'nein', 'ja']),
td(['Zwiebeln' , 'ja','ja', 'ja'])
]
)
);
Betrachten Sie das nachfolgende Codefragment:
print blockquote(em('Hi'),'mom!'));
Üblicherweise erhalten Sie den String zurück, den Sie wohl auch erwarten, nämlich:
<BLOCKQUOTE><EM>Hi</EM> mom!</BLOCKQUOTE>
Beachten Sie das Leerzeichen zwischen dem Element "Hi" und dem Element "mom!". CGI.pm fügt dieses zusätzliche Leerzeichen mit Hilfe der Array-Interpolation ein, die über die magische Variable $" kontrolliert wird. Manchmal wollen Sie dieses zusätzliche Leerzeichen aber nicht, beispielsweise wenn Sie eine Reihe von Grafiken ausrichten. In diesem Fall setzen Sie den Wert von $" einfach auf den Leer-String:
{
local($") = '';
print blockquote(em('Hi'),'mom!'));
}
Ich empfehle Ihnen, den Code, wie hier gezeigt, in einen Block zu setzen. Anderenfalls gilt die Änderung von $" für den gesamten nachfolgenden Code, bis die Variable explizit zurückgesetzt wird.
Einige wenige HTML-Tags folgen aus verschiedenen Gründen nicht dem Standardmuster.
comment()
generiert einen HTML-Kommentar (<!-- kommentar -->). Der Aufruf erfolgt auf folgende Weise:
print comment('Hier ist mein Kommentar');
Aufgrund von Konflikten mit in Perl integrierten Funktionen beginnen die folgenden Funktionen mit einem Großbuchstaben:
Select Tr Link Delete
Darüber hinaus haben start_html(), end_html(), start_form(), end_form(), start_multipart_form() und alle Formular-Tags ihre Besonderheiten. Beachten Sie hierzu die entsprechenden Abschnitte.
Allgemeiner Hinweis
: Die verschiedenen Methoden zur Formulargenerierung liefern alle einen String an den Aufrufer zurück. Dieser String enthält den Tag oder die Tags, die das angeforderte Formularelement erzeugen. Sie sind dafür verantwortlich, daß diese Strings auch tatsächlich ausgegeben werden. Dieser Weg wurde gewählt, damit Sie formatierende Tags um die Formularelemente plazieren können.Noch ein Hinweis
: Die für das Formular möglicherweise festgelegten Standardwerte werden nur beim ersten Aufruf des Skripts (wenn kein Query-String vorliegt) verwendet. Bei nachfolgenden Aufrufen des Skripts (wenn ein Query-String existiert) werden die vorangegangenen Werte verwendet, auch wenn die entsprechenden Felder leer sind.Wenn Sie den vorherigen Wert eines Feldes ändern wollen, haben Sie zwei Möglichkeiten:
(1) Setzen Sie den Wert mit der param()-Methode.
(2) Verwenden Sie den Parameter -override (Alias -force), ein neues Feature ab Version 2.15. Damit erzwingen Sie, daß der Standardwert benutzt wird, unabhängig davon, welcher Wert vorher verwendet wurde:
print $query->textfield(-name=>'feldname',
-default=>'startwert',
-override=>1,
-size=>50,
-maxlength=>80);
Und noch ein Hinweis
: Standardmäßig werden die Texte und Label von Formularelementen entsprechend den HTML-Regeln geschützt ("Escaping"). Das bedeutet, Sie können unbesorgt "<HIER KLICKEN>" als Label für einen Button verwenden. Andererseits behindert das die Fähigkeit, spezielle HTML-Zeichensequenzen wie Á, in Ihre Felder aufzunehmen. Wenn Sie das automatische Escaping ausschalten wollen, müssen Sie unmittelbar nach Erzeugung eines CGI-Objekts die MethodeautoEscape() mit einem "falsch"-Wert aufrufen:
$query = new CGI;
$query->autoEscape(undef);
print $query->isindex(-action=>$action);
- oder -
print $query->isindex($action);
Gibt einen <ISINDEX>-Tag aus. Nicht gerade aufregend. Der Parameter -action gibt die URL des Skripts an, das die Query verarbeiten soll. Per Voreinstellung wird die Query mit dem aktuellen Skript verarbeitet.
print $query->startform(-method=>$method,
-action=>$action,
-encodingtype=>$encoding);
<... verschiedene Formularelemente ...>
print $query->endform;
- oder -
print $query->startform($method,$action,$encoding); <... verschiedene Formularelemente ...> print $query->endform;
startform()
gibt einen <FORM>-Tag zurück, der optional zu der von Ihnen übergebenen Methode, Aktion und Formularcodierung ist. Voreingestellt sind:endform()
liefert den schließenden </FORM>-Tag zurück.
Der Codierungstyp von startform() teilt dem Browser mit, wie die verschiedenen Felder des Formulars zu packen sind, bevor das Formular an den Server geschickt wird. Zwei Werte sind möglich:
Aus Kompatibilitätsgründen verwendet startform() per Voreinstellung die ältere Codierung. Wollen Sie standardmäßig mit der neueren Codierung arbeiten, können Sie start_multipart_form() anstelle von startform() aufrufen.
JAVASCRIPTING: Die Parameter -name und -onSubmit stehen für die Arbeit mit JavaScript bereit. Der Parameter -name gibt dem Formular einen Namen, so daß es identifiziert und von JavaScript-Funktionen bearbeitet werden kann. -onSubmit muß auf eine JavaScript-Funktion zeigen, die ausgeführt wird, unmittelbar bevor das Formular an Ihren Server übertragen wird. Sie können diese Gelegenheit nutzen, um den Inhalt des Formulars auf Konsistenz und Vollständigkeit zu überprüfen. Falls Sie fehlerhafte Angaben entdecken, können Sie entweder eine Alarm-Box ausgeben oder die Dinge selbst korrigieren. Sie können die Übertragung abbrechen, indem Sie diese Funktion "falsch" zurückgeben lassen.
Üblicherweise ist der Großteil der JavaScript-Funktionen in einem <SCRIPT>-Block des HTML-Headers definiert, und -onSubmit zeigt auf eine dieser Funktionen. Details finden Sie unter start_html().
print $query->textfield(-name=>'feldname',
-default=>'startwert',
-size=>50,
-maxlength=>80);
- oder -
print $query->textfield('feldname','startwert',50,80);
textfield()
gibt ein Texteingabefeld zurück.
Wie bei all diesen Methoden wird das Feld mit dem Inhalt vorangegangener Aufrufe dieses Skripts initialisiert. Wird das Formular verarbeitet, kann der Wert des Textfeldes wie folgt ermittelt werden:
$value = $query->param('foo');
Soll nach dem Aufruf des Skripts der Standardwert wiederhergestellt werden, können Sie wie folgt vorgehen:
$query->param('foo',"Ich verwende diesen Wert!");
NEU SEIT VERSION 2.15: Soll das Feld nicht den vorherigen Wert annehmen, können Sie mit dem Parameter -override (Alias -force) die Verwendung des aktuellen Werts erzwingen:
print $query->textfield(-name=>'feldname',
-default=>'startwert',
-override=>1,
-size=>50,
-maxlength=>80);
JAVASCRIPTING: Sie können auch die Parameter -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut und -onSelect angeben, um JavaScript-Event-Handler einzurichten. Der Handler onChange wird immer dann aufgerufen, wenn der Benutzer den Inhalt des Textfeldes ändert. Bei Bedarf können Sie also die Validität des Textes prüfen. onFocus und onBlur werden aufgerufen, wenn der Zeiger in das bzw. aus dem Textfeld fährt. onSelect wird aufgerufen, wenn der Benutzer den markierten Textbereich ändert.
print $query->textarea(-name=>'foo',
-default=>'startwert',
-rows=>10,
-columns=>50);
-oder
print $query->textarea('foo','startwert',10,50);
textarea()
ist wie textfield, erlaubt aber die Angabe von Spalten und Zeilen für ein mehrzeiliges Texteingabefeld. Sie können auch einen Standardwert für dieses Feld definieren, das lang sein und mehrere Zeilen einnehmen kann.
JAVASCRIPTING: Die Parameter -onChange, -onFocus, -onBlur , -onMouseOver, -onMouseOut und -onSelect werden erkannt. Siehe textfield().
print $query->password_field(-name=>'secret',
-value=>'startwert',
-size=>50,
-maxlength=>80);
- oder -
print $query->password_field('secret','startwert',50,80);
password_field()
entspricht textfield(), nur daß die Zeichen auf der Web-Seite als Sternchen erscheinen.
JAVASCRIPTING: Die Parameter -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut und -onSelect werden erkannt. Siehe textfield().
print $query->filefield(-name=>'uploaded_file',
-default=>'startwert',
-size=>50,
-maxlength=>80);
- oder -
print $query->filefield('uploaded_file','startwert',50,80);
filefield()
gibt ein Datei-Upload-Feld für Netscape-2.0-Browser zurück. Um diese Fähigkeit vollständig nutzen zu können, müssen Sie die neue Multipart-Codierung für das Formular verwenden. Hierzu rufen Sie startform() entweder mit dem Codierungstyp $CGI::MULTIPART auf, oder Sie verwenden die neue Methode start_multipart_form() anstelle des üblichen startform()-Aufrufs.
Bei der Verarbeitung des Formulars können Sie den eingegebenen Dateinamen wie folgt mit param() ermitteln:
$filename = $query->param('uploaded_file');
Beim Netscape Navigator 2.0 entspricht der zurückgelieferte Dateiname dem lokalen Dateinamen auf der Maschine des Benutzers. Sitzt der entfernte Benutzer an einer Unix-Maschine, folgt der Dateiname den Unix-Konventionen:
/path/to/the/file
Bei MS-DOS/Windows- und OS/2-Maschinen folgt der Dateiname den DOS-Konventionen:
C:\PATH\TO\THE\FILE.MSW
Auf einem Macintosh-Rechner folgt der Dateiname den Mac-Konventionen:
HD 40:Desktop Folder:Sort Through:Reminders
Der zurückgegebene Dateiname ist gleichzeitig ein Dateihandle. Sie können den Inhalt der Datei mit gewöhnlichen Perl-Dateioperationen verarbeiten:
# Textdatei lesen und ausgeben.
while (<$filename>) {
print;
}
# Binärdatei an einen sicheren Ort kopieren.
open (OUTFILE,">>/usr/local/web/users/feedback");
while ($bytesread=read($filename,$buffer,1024)) {
print OUTFILE $buffer;
}
Findet ein Datei-Upload statt, sendet der Browser üblicherweise einige Informationen in Form von Headern mit. Diese Informationen umfassen üblicherweise den MIME-Inhaltstyp. Zukünftige Browser könnten noch zusätzliche Informationen (etwa das Modifikationsdatum) übergeben. Um an diese Informationen zu gelangen, rufen Sie uploadInfo() auf. Dies liefert eine Referenz auf ein assoziatives Array zurück, in dem alle Dokument-Header enthalten sind.
$filename = $query->param('uploaded_file');
$type = $query->uploadInfo($filename)->{'Content-Type'};
unless ($type eq 'text/html') {
die "NUR HTML-DATEIEN!";
}
Wenn Sie mit einer Maschine arbeiten, die "Text"- und "Binär"-Modi unterscheidet, sollten Sie ganz genau verstehen, wann und wie sie zu verwenden sind (schauen Sie im Kamel-Buch nach). Anderenfalls könnten Binärdateien bei Uploads beschädigt werden.
JAVASCRIPTING: Die Parameter -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut und -onSelect werden erkannt. Siehe textfield().
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie');
- oder -
%labels = ('eenie'=>'erste Wahl',
'meenie'=>'zweite Wahl',
'minie'=>'dritte Wahl');
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie',\%labels);
- oder (mit benannten Parametern) -
print $query->popup_menu(-name=>'menu_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-labels=>\%labels);
popup_menu() erzeugt ein Menü.
Bei der Verarbeitung des Formulars kann der im Popup-Menü gewählte Wert wie folgt ermittelt werden:
$popup_menu_value = $query->param('menu_name');
JAVASCRIPTING: popup_menu() erkennt die folgenden Event-Handler: -onChange, -onFocus, -onMouseOver, -onMouseOut und -onBlur. Details zum Aufruf dieser Handler finden Sie im Abschnitt über textfield().
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true');
- oder -
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true',
\%labels);
- oder -
print $query->scrolling_list(-name=>'list_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-size=>5,
-multiple=>'true',
-labels=>\%labels);
scrolling_list()
erzeugt eine Scroll-Liste.
@selected = $query->param('list_name');
scrolling_list() erkennt die folgenden Event-Handler: -onChange, -onFocus, -onMouseOver, -onMouseOut und -onBlur. Wann diese Handler aufgerufen werden, wird im Abschnitt zu textfield() erklärt.
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-linebreak=>'true',
-labels=>\%labels);
print $query->checkbox_group('group_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],'true',\%labels);
NUR BEI HTML3-KOMPATIBLEN BROWSERN:
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-rows=2,-columns=>2);
checkbox_group()
erzeugt eine Liste von Kontrollkästchen, die unter dem gleichen Namen zusammengefaßt sind.
checkbox_group() eine HTML3-kompatible Tabelle zurück, in der die Gruppe der Kontrollkästchen mit der angegebenen Anzahl von Zeilen und Spalten aufbereitet ist. Wenn Sie wollen, können Sie auch nur den Parameter -columns angeben; checkbox_group berechnet dann die entsprechende Anzahl Zeilen für Sie.Um Zeilen- und Spaltenüberschriften in die zurückgelieferte Tabelle aufzunehmen, können Sie die Parameter -rowheaders und -colheaders verwenden. Beide erwarten einen Zeiger auf ein Array der zu verwendenden Überschriften. Diese Überschriften dienen nur der Dekoration. Eine Reorganisation der Kontrollkästchen findet nicht statt--sie bilden immer noch eine einzelne benannte Einheit.
Bei der Verarbeitung des Formulars werden alle aktivierten Kontrollkästchen in Form einer Liste unter dem Parameternamen 'group_name' zurückgegeben. Die Werte der aktiven Kontrollkästchen können wie folgt ermittelt werden:
@turned_on = $query->param('group_name');
Der von checkbox_group() zurückgegebene Wert ist tatsächlich ein Array von Button-Elementen. Sie können diese Elemente abfangen und in Tabellen, Listen oder auf andere kreative Weise einsetzen:
@h = $query->checkbox_group(-name=>'group_name',-values=>\@values); &was_bin_ich_kreativ(@h);
JAVASCRIPTING: checkbox_group() erkennt den Parameter -onClick. Dieser legt den JavaScript-Code bzw. die -Funktion fest, die aufgerufen wird, wenn der Benutzer einen Button der Gruppe anklickt. Sie können die Identität des jeweils angeklickten Buttons über die Variable "this" bestimmen.
print $query->checkbox(-name=>'checkbox_name',
-checked=>'checked',
-value=>'AN',
-label=>'KLICK MICH AN');
- oder -
print $query->checkbox('checkbox_name','checked','AN','KLICK MICH AN');
checkbox()
wird verwendet, um ein isoliertes Kontrollkästchen zu erzeugen, das nicht mit anderen verknüpft ist.
Der Wert des Kontrollkästchens kann wie folgt ermittelt werden:
$turned_on = $query->param('checkbox_name');
JAVASCRIPTING: checkbox() erkennt den Parameter -onClick. Details hierzu finden Sie unter checkbox_group().
print $query->radio_group(-name=>'group_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-linebreak=>'true',
-labels=>\%labels);
- oder -
print $query->radio_group('group_name',['eenie','meenie','minie'],
'meenie','true',\%labels);
NUR HTML3-KOMPATIBLE BROWSER:
print $query->radio_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-rows=2,-columns=>2);
radio_group()
erzeugt einen Satz logisch zusammengehöriger Radio-Buttons. (Die Aktivierung eines Mitglieds der Gruppe deaktiviert alle anderen.)
radio_group() eine HTML3-kompatible Tabelle zurück, in der die Gruppe der Radio-Buttons mit der angegebenen Anzahl von Zeilen und Spalten aufbereitet ist. Wenn Sie wollen, können Sie auch nur den Parameter -columns angeben; radio_group berechnet dann die entsprechende Anzahl Zeilen für Sie.Um Zeilen- und Spaltenüberschriften in die zurückgelieferte Tabelle aufzunehmen, können Sie die Parameter -rowheaders und -colheaders verwenden. Beide erwarten einen Zeiger auf ein Array der zu verwendenden Überschriften. Diese Überschriften dienen nur der Dekoration. Eine Reorganisation der Radio-Buttons findet nicht statt--sie bilden immer noch eine einzelne benannte Einheit.
Bei der Verarbeitung des Formulars kann der gewählte Radion-Button wie folgt ermittelt werden:
$which_radio_button = $query->param('group_name');
Der von radio_group() zurückgelieferte Wert ist tatsächlich ein Array mit Button-Elementen. Sie können diese Elemente abfangen und in Tabellen, Listen oder auf andere kreative Weise einsetzen:
@h = $query->radio_group(-name=>'group_name',-values=>\@values); &was_bin_ich_kreativ(@h);
print $query->submit(-name=>'button_name',
-value=>'value');
- oder -
print $query->submit('button_name','value');
submit()
erzeugt einen sogenannten Submit-Button zum Absenden einer Query. Jedes Formular muß einen solchen Button besitzen.
Sie können ermitteln, welcher Button gedrückt wurde, indem Sie jedem Button einen anderen Wert zuweisen:
$which_one = $query->param('button_name');
JAVASCRIPTING: radio_group() erkennt den Parameter -onClick. Details hierzu finden Sie unter checkbox_group().
print $query->reset
reset()
erzeugt den "Reset"-Button. Beachten Sie, daß das Formular auf die Werte zurückgesetzt wird, die beim letzten Aufruf des Skripts verwendet wurden, NICHT notwendigerweise auf die Standardwerte.
print $query->defaults('button_label')
defaults()
erzeugt einen Button, der beim Aufruf das gesamte Formular auf seine Standardwerte zurücksetzt und so alle bislang durchgeführten Änderungen verwirft.
print $query->hidden(-name=>'hidden_name',
-default=>['value1','value2'...]);
- oder -
print $query->hidden('hidden_name','value1','value2'...);
hidden()
erzeugt ein Textfeld, das für den Benutzer unsichtbar ist. Es ist nützlich für die Übergabe von Zustandsinformationen von einem Aufruf des Skripts zum nächsten.
Den Wert eines versteckten Feldes bestimmen Sie wie folgt:
$hidden_value = $query->param('hidden_name');
Beachten Sie, daß, genau wie bei allen anderen Formularelementen, der Wert eines versteckten Feldes sehr "anhänglich" ("sticky") ist. Möchten Sie den Wert eines versteckten Feldes ändern, nachdem das Skript einmal aufgerufen wurde, müssen Sie das manuell erledigen.
$query->param('hidden_name','new','values','here');
print $query->image_button(-name=>'button_name',
-src=>'/source/URL',
-align=>'MIDDLE');
- oder -
print $query->image_button('button_name','/source/URL','MIDDLE');
image_button()
erzeugt ein sogenanntes "clickable Image". Beim Anklicken des Images wird die Position des Klicks im Format "button_name.x" und "button_name.y" an Ihr Skript zurückgeliefert. "button_name" ist dabei der von Ihnen zugewiesene Name.
JAVASCRIPTING: image_button() erkennt den Parameter -onClick. Details finden Sie unter checkbox_group().
Die Koordinaten bestimmen Sie wie folgt: $x = $query->param('button_name.x'); $y = $query->param('button_name.y');
print $query->button(-name=>'button_name',
-value=>'Label_fuer_Benutzer',
-onClick=>"tu_was()");
- oder -
print $query->button('button_name',"tu_was()");
button()
erzeugt einen Button, der zum Netscape-2.0-JavaScript kompatibel ist. Beim Anklicken wird der JavaScript-Code ausgeführt, auf den der Parameter -onClick verweist. Bei Nicht-Netscape-Browsern erscheint dieses Formularelement möglicherweise gar nicht erst.
Netscape-Browser unterstützen seit der Version 1.1 sogenannte "Cookies", die den Zustand innerhalb einer Browser-Session verwalten helfen. CGI.pm besitzt verschiedene Methoden zur Unterstützung von Cookies.
Ein Cookie ist ein Name/Wert-Paar, das den benannten Parametern in einem CGI-Query-String sehr ähnlich ist. CGI-Skripten erzeugen ein oder mehrere Cookies und senden diese im HTTP-Header an den Browser. Der Browser pflegt eine Liste von Cookies, getrennt nach Web-Servern, und liefert sie während nachfolgender Interaktionen an das CGI-Skript zurück.
Neben dem notwendigen Name/Wert-Paar besitzt jedes Cookie verschiedene optionale Attribute:
Die Schnittstelle zu Netscape-Cookies bildet die cookie()-Methode:
$cookie = $query->cookie(-name=>'sessionID',
-value=>'xyzzy',
-expires=>'+1h',
-path=>'/cgi-bin/database',
-domain=>'.capricorn.org',
-secure=>1);
print $query->header(-cookie=>$cookie);
cookie()
erzeugt ein neues Cookie. Die Parameter sind:
$cookie=$query->cookie(-name=>'family information',
-value=>\%childrens_ages);
"+1h" in einer Stunde von nun an
Das von cookie() erzeugte Cookie muß innerhalb des durch die header()-Methode zurückgelieferten Strings in den HTTP-Header eingebunden werden:
print $query->header(-cookie=>$my_cookie);
Um mehrere Cookies zu erzeugen, übergeben Sie header() eine Arrayreferenz:
$cookie1 = $query->cookie(-name=>'riddle_name',
-value=>"Die Frage der Sphinx");
$cookie2 = $query->cookie(-name=>'answers',
-value=>\%answers);
print $query->header(-cookie=>[$cookie1,$cookie2]);
Um ein Cookie zu ermitteln, rufen Sie cookie() mit dem entsprechenden Namen, aber ohne den -value-Parameter, auf:
use CGI;
$query = new CGI;
%answers = $query->cookie(-name=>'answers');
# $query->cookie('answers') funktioniert auch!
Cookies und CGI besitzen getrennte Namensräume. Besitzen Sie einen Parameter namens 'answers' und ein Cookie namens 'answers', sind die durch param() und cookie() zurückgelieferten Werte völlig unabhängig voneinander. Dennoch ist es einfach, einen CGI-Parameter in ein Cookie (und umgekehrt) umzuwandeln:
# CGI-Parameter in Cookie umwandeln.
$c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]);
# Cookie in CGI-Parameter umwandeln.
$q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
Einige Ideen zur effektiven Nutzung von Cookies finden Sie im Beispielskript cookie.cgi.
Hinweis:
Für Netscape-Cookies seien einige (undokumentierte) Einschränkungen genannt. Zumindest unter Netscape 2.01 ist es mir nicht gelungen, mehr als drei Cookies gleichzeitig zu setzen. Auch was die Länge der Cookies angeht, könnte es Beschränkungen geben. Wenn Sie viele Informationen speichern müssen, ist es wahrscheinlich besser, eine eindeutige Session-ID zu erzeugen, diese in einem Cookie abzulegen und dann die ID zu benutzen, um auf eine externe Datei/Datenbank zuzugreifen, die direkt auf dem Server liegt.Es ist CGI.pm-Skripten mit Hilfe des Frame-Mechanismus von Netscape möglich, in verschiedene Browser-Panels und -Fenster zu schreiben. Drei verschiedene Techniken stehen zur Definition neuer Frames zur Verfügung:
start_html() ein Standard-HTML-Dokument zu generieren, ein <FRAMESET>-Dokument, das die Frames der Seite definiert. Geben Sie Ihr(e) Skript(en) (mit den entsprechenden Parametern) im SRC-Tag jedes Frames an. Es gibt bei CGI.pm keine besondere Unterstützung für die Erzeugung von <FRAMESET>-Abschnitten, der notwendige HTML-Code ist aber sehr einfach zu schreiben. Details finden Sie in der Frame-Dokumentation auf der Netscape-Homepage:
http://home.netscape.com/assist/net_sites/frames.html
header()-Methode übergeben:
print $q->header(-target=>'Ergebnisfenster');Damit weisen Sie Netscape an, die Ausgabe Ihres Skripts an den Frame namens "Ergebnisfenster" zu schicken. Wenn ein Frame dieses Namens noch nicht existiert, öffnet Netscape ein neues Fenster und gibt das von Ihrem Skript erzeugte Dokument in diesem Fenster aus. Es gibt eine Reihe "magischer" Namen, die Sie als Ziel angeben können. Auch hierzu finden Sie die genauen Details in den Frame-Dokumenten auf den Netscape-Homepages.
print $q->startform(-target=>'Ergebnisfenster');Wird Ihr Skript vom Formular erneut aufgerufen, geht die Ausgabe an den Frame namens "Ergebnisfenster". Existiert der Frame noch nicht, wird ein neues Fenster erzeugt.
Das Skript "frameset.cgi" im Beispielverzeichnis zeigt eine Möglichkeit, bei der ein Formular und die Antwort in nebeneinanderliegenden Frames existieren.
CGI.pm unterstützt eingeschränkt Cascading Style Sheets (CSS, kaskadenartige Formatvorlagen) von HTML 3. Um ein Stylesheet in Ihr Dokument einzubinden, übergeben Sie der start_html()-Methode den Parameter -style. Der Wert dieses Parameters kann ein Skalar sein, was zu einer direkten Einbettung in einen <STYLE>-Abschnitt führt, es kann aber auch eine Hashreferenz übergeben werden. In letzterem Fall müssen Sie den Hash mit einer oder mehreren -src- oder -code-Angaben versehen. -src zeigt auf eine URL, auf der ein extern definiertes Stylesheet zu finden ist. -code verweist auf einen Skalarwert, der im <STYLE>-Bereich einzubetten ist. Style-Definitionen in -code überschreiben gleichnamige Definitionen in -src, daher auch der Begriff "kaskadieren".
Sie können auch den Typ des Stylesheets festlegen, indem Sie den optionalen -type-Parameter zum durch -style referenzierten Hash hinzufügen. Geben Sie den Typ nicht an, wird standardmäßig 'text/css' angenommen.
Um auf einen Style innerhalb des Bodies Ihres Dokuments zu verweisen, fügen Sie jedem HTML-Element den Parameter -class hinzu:
print h1({-class=>'Fancy'},'Willkommen zur Party');
Oder definieren Sie Styles mit dem Parameter -style so nebenbei:
print h1({-style=>'Color: red;'},'Willkommen in der Hölle');
Sie können auch das neue span()-Element verwenden, um einen Style auf einen Textabschnitt anzuwenden:
print span({-style=>'Color: red;'},
h1('Willkommen in der Hölle'),
"Wer ist jetzt dran?"
);
Beachten Sie, daß Sie die ":html3"-Definitionen importieren müssen, um die span()-Methode nutzen zu können. Hier folgt ein kleines Beispiel für die Verwendung von CSS. Weitere Informationen finden Sie in der CSS-Spezifikation unter http://www.w3.org.
use CGI qw/:standard :html3/;
#Ein direkt in die Seite eingebundenes Stylesheet
$newStyle=<<END;
<!--
P.Tip {
margin-right: 50pt;
margin-left: 50pt;
color: red;
}
P.Alert {
font-size: 30pt;
font-family: sans-serif;
color: red;
}
-->
END
print header();
print start_html( -title=>'CGI mit Stil',
-style=>{-src=>'http://www.capricorn.com/style/st1.css',
-code=>$newStyle}
);
print h1('CGI mit Stil'),
p({-class=>'Tip'},
"Lesen Sie zuerst die CSS-Specs, bevor Sie hiermit rumspielen!"),
span({-style=>'color: magenta'},
"Schau mal Mutti, freihändig!",
p(),
"JuuHuuu!"
);
print end_html;
Wenn Sie das Skript über die Kommandozeile oder mit dem Perl-Debugger ausführen, können Sie dem Skript in der Kommandozeile oder über die Standardeingabe eine Liste mit Schlüsselwörtern oder Parameter/Wert-Paaren übergeben. (Sie müssen also nicht mit Umgebungsvariablen tricksen.) Schlüsselwörter werden wie folgt übergeben:
ihr_skript.pl schlüsselwort1 schlüsselwort2 schlüsselwort3
oder so:
ihr_skript.pl schlüsselwort1+schlüsselwort2+schlüsselwort3
oder so:
ihr_skript.pl name1=wert1 name2=wert2
oder so:
ihr_skript.pl name1=wert1&name2=wert2
Sie können sogar durch Zeilenvorschübe getrennte Parameter über die Standardeingabe einlesen.
Während des Debuggens können Sie in der für Shells üblichen Weise Quoting-Zeichen und Backslashes zum Schutz einzelner Zeichen verwenden. Damit können Sie Leerzeichen und andere Sonderzeichen in Ihre Parameter/Wert-Paare einfügen:
ihr_skript.pl "name1='Ein sehr langer Wert'" "name2=zwei\ Worte"
Die dump()-Methode erzeugt einen String, der alle Name/Wert-Paare der Query enthält. Diese Werte sind in Form einer verschachtelten Liste aufbereitet, was für Debugging-Zwecke sehr nützlich ist:
print $query->dump
Dies erzeugt so etwas wie:
<UL>
<LI>name1
<UL>
<LI>wert1
<LI>wert2
</UL>
<LI>name2
<UL>
<LI>wert1
</UL>
</UL>
Sie können dump() den Wert 'wahr' übergeben, was dazu führt, daß das Ergebnis als reiner Text zurückgegeben wird, der in einem <PRE>-Abschnitt eingebettet werden kann.
Seit der Version 1.56 können Sie das gesamte CGI-Objekt in einen String interpolieren, der dann durch den oben gezeigten HTML-Dump ersetzt wird:
$query=new CGI; print "<H2>Aktuelle Werte</H2> $query\n";
Einige der sinnvolleren Umgebungsvariablen können durch diese Schnittstelle abgefragt werden. Folgende Methoden stehen zur Verfügung:
cookie(). raw_cookie() die gepackte Cookie-Struktur zurück. Eine Aufteilung in einzelne Cookies ist über eine Split-Operation mit der Zeichensequenz "; " möglich. Erfolgt der Aufruf mit dem Namen eines Cookies, wird die unverfälschte Form des Cookies zurückgegeben. Sie gelangen an die Namen mit der normalen cookie()-Methode oder mit Hilfe der raw_fetch()-Methode des CGI::Cookie-Moduls. path_info(), wandelt die Pfadinformationen aber in einen physikalischen Pfad um, z.B. "/usr/local/etc/httpd/htdocs/additional/stuff". NPH-Skripten ("no-parsed-header") umgehen den Server und senden den vollständigen HTTP-Header direkt an den Browser. Das bringt eine leichte Verbesserung im Durchsatz, ist aber am nützlichsten, um HTTP-Erweiterungen zu verwenden, die von Ihrem Server nicht direkt unterstützt werden (etwa Server-Push und PICS-Header).
Server verwenden eine Reihe von Konventionen, um CGI-Skripten als NPH-Skripten zu kennzeichnen. Viele Unix-Server untersuchen den Anfang des Dateinamens auf das Präfix "nph-". Der WebSTAR-Server für den Macintosh und der Microsoft Internet Information Server hingegen versuchen anhand der ersten Zeile der Ausgabe zu entscheiden, ob es sich um ein NPH-Skript handelt.
CGI.pm unterstützt NPH-Skripten durch einen speziellen NPH-Modus. In diesem Modus gibt CGI.pm beim Aufruf der header()- und redirect()-Methoden alle zusätzlich benötigten Header-Informationen aus.
Der Microsoft Internet Information Server verlangt den NPH-Modus. Seit der Version 2.30 erkennt CGI.pm automatisch, ob ein Skript unter IIS läuft, und schaltet sich von selbst in diesen Modus. Sie müssen dies also nicht von Hand ausführen, auch wenn Sie damit keinen Schaden anrichten können.
Es gibt eine Reihe von Möglichkeiten, CGI.pm in den NPH-Modus zu schalten:
use CGI qw(:standard -nph)
CGI->nph(1)
print $q->header(-nph=>1);
CGI.pm stellt drei einfache Funktionen zur Verfügung, mit denen Multipart-Dokumente erzeugt werden können, die zur Implementierung eines Server-Pushes notwendig sind. Diese Funktionen wurden großzügigerweise von Ed Jordan ."<ed@fidalgo.net bereitgestellt. Um sie in Ihren Namensraum einzubinden, müssen Sie den ":push"-Satz importieren. Gleichzeitig ist es ratsam, das Skript in den NPH-Modus zu schalten und $| auf 1 zu setzen, um Probleme mit der Pufferung zu vermeiden.
Hier ein einfaches Beispiel, das den Server-Push demonstriert:
#!/usr/local/bin/perl
use CGI qw/:push -nph/;
$| = 1;
print multipart_init(-boundary=>'----------------und los!');
while (1) {
print multipart_start(-type=>'text/plain'),
"Die aktuelle Zeit ist ",scalar(localtime),"\n",
multipart_end;
sleep 1;
}
Das Skript initialisiert den Server-Push durch den Aufruf von multipart_init(). Danach tritt es in eine Endlosschleife ein, in der mit multipart_start() ein neuer Multipart-Abschnitt eingeleitet, die lokale Zeit ausgegeben und mit multipart_end() der Multipart-Abschnitt beendet wird. Danach wird eine Sekunde gewartet, bevor das Ganze von neuem beginnt.
multipart_start(-type=>$type)
multipart_end()
multipart_end() für jedes multipart_start() einmal aufrufen. An Server-Push-Anwendungen interessierte Benutzer sollten sich auch das CGI::Push-Modul ansehen.
Ein mögliches Problem von CGI.pm besteht darin, daß es standardmäßig versucht, Formular-POSTings unabhängig von ihrer Länge zu verarbeiten. Ein böser Hacker könnte Ihre Site angreifen, indem er einem CGI-Skript ein mehrere Megabyte großes POSTing schickt. CGI.pm wird versuchen, das gesamte POSTing in eine Variable einzulesen, die daraufhin sehr groß wird, bis möglicherweise sogar der Speicher aufgebraucht ist. Während das Skript versucht, den benötigten Speicher anzufordern, kann die Geschwindigkeit Ihres Systems dramatisch sinken. Das ist eine Form der sogenannten "Denial of Service"-Attacken.
Eine andere Möglichkeit des Angriffs besteht darin, daß der entfernte Benutzer CGI.pm dazu bringt, einen sehr großen Datei-Upload zu akzeptieren. CGI.pm wird den Upload akzeptieren und ihn in einem temporären Verzeichnis unterbringen, selbst wenn das Skript eigentlich keinen Upload erwartet. CGI.pm löscht diese Datei beim Beenden zwar automatisch, aber in der Zwischenzeit könnte der entfernte Benutzer die Platte des Servers aufgefüllt haben und so bei anderen Programmen Probleme verursachen.
Die beste Möglichkeit, Denial-of-Service-Angriffe zu vermeiden, besteht darin, den Speicher, die CPU-Zeit und den Plattenplatz für CGI-Skripten zu beschränken. Einige Web-Server besitzen Möglichkeiten, um so etwas zu erreichen. In anderen Fällen können Sie die Shell-Befehle limit oder ulimit verwenden, um Obergrenzen für CGI-Ressourcen festzulegen.
CGI.pm besitzt auch einige einfache, fest integrierte Schutzmechanismen gegen solche Angriffe - diese müssen aber von Ihnen aktiviert werden, bevor sie genutzt werden können. Verwendet werden hierzu zwei globale Variablen im CGI-Namensraum:
Sie können diese Variablen auf zwei unterschiedliche Arten verwenden.
use CGI qw/:standard/; use CGI::Carp 'fataler Browser-Fehler'; $CGI::POST_MAX=1024 * 100; # maximal 100K POSTings $CGI::DISABLE_UPLOADS = 1; # keine Uploads
$POST_MAX und $DISABLE_UPLOADS, und setzen Sie sie auf die gewünschten Werte. Sie finden sie am Anfang der Datei in einer Unterroutine namens initialize_globals(). Weil der Versuch, ein POSTing mit mehr als $POST_MAX Bytes durchzuführen, zu einem fatalen Fehler führt, können Sie CGI::Carp verwenden, um den fatalen Fehler im Browser-Fenster auszugeben (siehe oben). Anderenfalls erhält der Benutzer nur die generische Fehlermeldung "Internal Server Error". Weitere Details finden Sie in der CGI-Manpage.
Um die Portierung von Programmen einfacher zu machen, die auf der cgi-lib.pl basieren, steht die Routine "ReadParse" zur Verfügung. Die Portierung ist einfach:
ALTE VERSION
require "cgi-lib.pl";
&ReadParse;
print "Der Wert der Antiquität liegt bei $in{antique}.\n";
NEUE VERSION
use CGI;
CGI::ReadParse
print "Der Wert der Antiquität liegt bei $in{antique}.\n";
Die ReadParse()-Routine von CGI.pm erzeugt eine gebundene Variable namens %in, auf die Sie zugreifen können, um die Query-Variablen zu ermitteln. Wie bei ReadParse können Sie auch Ihre eigene Variable angeben. Selten verwendete Features von ReadParse, wie etwa die Erzeugung von @in- und $in-Variablen, werden nicht unterstützt.
Sobald Sie ReadParse verwendet haben, gelangen Sie folgendermaßen an das Query-Objekt selbst:
$q = $in{CGI};
print $q->textfield(-name=>'wow',
-value=>'funktioniert das wirklich?');
Auf diese Weise können Sie die interessanteren Merkmale von CGI.pm nutzen, ohne Ihre alten Skripten völlig neu schreiben zu müssen.
Diese Manpage dokumentiert "CGI.pm" in der Version CGI.pm-2.43.
Copyright 1995-1997, Lincoln D. Stein. All rights reserved. It may be used and modified freely, but I do request that this copyright notice remain attached to the file. You may modify this module as you wish, but if you redistribute a modified version, please attach a note listing the modifications you have made.
Bug-Reports und Kommentare richten Sie bitte an: lstein@genome.wi.mit.edu
Deutsche Übersetzung von Peter Klicman,
© 1998 by O'Reilly Verlag, Köln
Vielen Dank an:
#!/usr/local/bin/perl
use CGI;
$query = new CGI;
print $query->header;
print $query->start_html("Beispiel eines CGI.pm-Formulars");
print "<H1> Beispiel eines CGI.pm-Formulars</H1>\n";
&print_prompt($query);
&do_work($query);
&print_tail;
print $query->end_html;
sub print_prompt {
my($query) = @_;
print $query->startform;
print "<EM>Wie lautet Ihr Name?</EM><BR>";
print $query->textfield('name');
print $query->checkbox('Nicht mein wirklicher Name');
print "<P><EM>Wo findet man englische Spatzen?</EM><BR>";
print $query->checkbox_group(
-name=>'Sparrow locations',
-values=>[England,Frankreich,Spanien,Asien,Hoboken],
-linebreak=>'yes',
-defaults=>[England,Asien]);
print "<P><EM>Wie weit können sie fliegen?</EM><BR>",
$query->radio_group(
-name=>'how far',
-values=>['10 Meter','1 Kilometer','10 Kilometer','wirklich weit'],
-default=>'1 Kilometer');
print "<P><EM>Ihre Lieblingsfarbe?</EM> ";
print $query->popup_menu(-name=>'Color',
-values=>['Schwarz','Braun','Rot','Gelb'],
-default=>'Rot');
print $query->hidden('Reference','Monty Python und der Heilige Gral');
print "<P><EM>Was haben Sie da?</EM><BR>";
print $query->scrolling_list(
-name=>'possessions',
-values=>['Eine Kokosnuß','Einen Gral','Ein Icon',
'Ein Schwert','Ein Ticket'],
-size=>5,
-multiple=>'true');
print "<P><EM>Irgendwelche Kommentare?</EM><BR>";
print $query->textarea(-name=>'Comments',
-rows=>10,
-columns=>50);
print "<P>",$query->reset;
print $query->submit('Action',Rufen');
print $query->submit('Action','Schreien');
print $query->endform;
print "<HR>\n";
}
sub do_work {
my($query) = @_;
my(@values,$key);
print "<H2>Hier die aktuellen Werte des Formulars</H2>";
foreach $key ($query->param) {
print "<STRONG>$key</STRONG> -> ";
@values = $query->param($key);
print join(", ",@values),"<BR>\n";
}
}
sub print_tail {
print <<END;
<HR>
<ADDRESS>Lincoln D. Stein</ADDRESS><BR>
<A HREF="/">Homepage</A>
END
}
Dieses Modul ist groß und monolithisch. Außerdem macht es viele Dinge, etwa die Verarbeitung von URLs, das Parsing von CGI-Eingaben, das Schreiben von HTML-Code etc., die auch von den LWP-Modulen erledigt werden. Eigentlich sollte es zugunsten der CGI::*-Module aufgegeben werden, aber irgendwie arbeite ich immer weiter daran.
Beachten Sie, daß der Code wirklich verdreht ist, um Warnungen zu vermeiden, die bei der Ausführung mit dem -w-Switch auftreten könnten.
CGI
, URI, CGI, CGI, CGI, CGI, CGI, CGI, CGI, CGI