# Ein- und Ausgabe

Das Unsympathische an Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
Brigitte Bardot, franz. Filmschauspielerin

# Parameterübergabe

Die wichtigste Aufgabe eines CGI-Scripts ist sicherlich die Entgegennahme von Parametern. Während in anderen Scriptsprachen, wie z. B. PHP, in der URL übergebene Parameter als Variablen zur Verfügung stehen, müssen Sie in Perl selbst dafür sorfen, da Sie die Parameter lediglich als zusammenhängende Zeichenkette zur Verfügung gestellt bekommen. Diese Zeichenkette ist in dem Hash %ENV hinterlegt, in dem der Server alle Umgebungsvariablen ablegt. Der Schlüssel für die Zeichenkette lautet QUERY_STRING.

Die Anweisung

print $ENV{'QUERY_STRING'};

würde nun die entsprechende Zeichenkette ausgeben.

Wichtig ist jedoch, dass die Parameter in einer bestimmten Notation übergeben werden müssen. Der eigentliche Pfad- und Dateiname und die Parameter werden durch ein Fragezeichen in der URL getrennt.

http://server/cgi-bin/script.pl?hier-folgen-die-parameter

Alles, was in der URL nach dem Fragezeichen folgt, sind die übergebenen Parameter, in diesem Fall also hier-folgen-die-parameter. Damit Sie sowohl einen Parameter als auch einen entsprechenden Wert übergeben können, müssen Sie den Parameter und den Wert durch ein Gleichheitszeichen = voneinander trennen.

parameter=wert

Mehrere Wertepaare (Parameter und Wert) werden durch das kaufmännische Und & voneinander abgetrennt.

parameter1=wert1&parameter2=wert2&parameterN=wertN

Das folgende Listing 6.1 hat einzig und allein die Aufgabe, den Wert des QUERY_STRING-Elements auszugeben.

#!/usr/bin/perl -w
use CGI qw(:standard);

print header();

print $ENV{'QUERY_STRING'};

Listing 6.1: Perl-Script zum Ausgeben der übergebenen Parameter

Ein Beispielaufruf für dieses Script könnte folgendermaßen aussehen:

http://localhost/cgi-bin/list6.1.pl?farbe=336699

Das Script würde dann dementsprechend die folgende Ausgabe erzeugen:

farbe=336699

Das Problem, vor dem Sie nun stehen, ist, dass Sie sowohl den Parameterbezeichner als auch den Wert als eine zusammenhängende Zeichenkette vorliegen haben. Dies ist jedoch ungünstig, wenn Sie den übergebenen Wert im Script verarbeiten bzw. verwenden möchten, z. B. um dem HTML-Dokument den als Parameter übergebenen Wert als Hintergrundfarbe zuzuweisen. Zwar könnten Sie mit der Funktion index die Position des Gleichheitszeichens ermitteln und die Zeichenkette dann dementsprechend zerlegen, würden Sie aber mehr als ein Wertepaar übergeben, wird dies schnell unübersichtlich – vor allem, da Sie sowohl nach dem Gleichheitszeichen als auch nach dem kaufmännischen Und suchen müssten. Ein Beispielaufruf mit zwei Wertepaaren sieht so aus:

http://localhost/cgi-bin/list6.1.pl?bg=336699&font=EEEEEE

Im Perl-Script steht Ihnen dann die Zeichenkette

bg=336699&font=EEEEEE

zur Verfügung.

In Perl gibt es allerdings eine Funktion, mit der man Zeichenketten anhand eines bestimmten Zeichens zerlegen kann: die split-Funktion. Der Funktion wird dabei zuerst das Zeichen übergeben, nach dem die Zeichenkette zerlegt werden soll, und anschließend die zu zerlegende Zeichenkette. Der Rückgabewert der Funktion ist dann eine Liste.

Wichtig ist, dass das Trennzeichen als regulärer Ausdruck übergeben werden muss. Da Sie erst später in diesem Buch mit regulären Ausdrücken in Kontakt kommen werden, sei an dieser Stelle lediglich gesagt, dass Sie das Zeichen innerhalb von Schrägstrichen in der Form /\[Zeichen]/ notieren müssen. Für das kaufmännische Und lautet die Schreibweise dann

/\&/

und für das Gleichheitszeichen:

/\=/

In Listing 6.2 zerlegen Sie die Zeichenkette $ENV{'QUERY_STRING'} erst einmal in die entsprechenden Wertepaare und geben diese anschließend im Browser aus.

#!/usr/bin/perl -w
use CGI qw(:standard);

print header();

my @wertepaare = split(/\&/,$ENV{'QUERY_STRING'});

print "Wertepaar 1: ",$wertepaare[0],"<br>";
print "Wertepaar 2: ",$wertepaare[1];

Listing 6.2: Perl-Script, das die übergebene Zeichenkette in Wertepaare zerlegt

Würden Sie das Listing 6.2 mit der URL http://localhost/cgi-bin/list6.2.pl? bg=336699&font=EEEEEE aufrufen, würden Sie die folgende Ausgabe erhalten:

Wertepaar 1: bg=336699
Wertepaar 2: font=EEEEEE

Nun müssen Sie nur noch die einzelnen Elemente der Liste @wertepaare in die Parameter und Werte zerlegen. Auch dafür verwenden Sie wieder die split-Funktion, diesmal jedoch in Verbindung mit einer foreach-Anweisung.

#!/usr/bin/perl -w
use CGI qw(:standard);

print header();

my @wertepaare = split(/\&/,$ENV{'QUERY_STRING'});

foreach(@wertepaare)
{
  ($param,$wert) = split(/\=/,$_);
  print $param,"<br>";
  print $wert,"<br>";
}

Listing 6.3: Erweiterung des Listing 6.2 – Trennen der Wertepaare in Parameter und Wert

Der interessante Teil des Listing 6.3 ist die foreach-Anweisung. Mit dieser Anweisung werden alle Elemente der @wertepaare-Liste einzeln abgearbeitet. Das gerade aktuelle Element wird im Skalar $_ gespeichert. Die Zeichenkette, die im $_-Skalar gespeichert ist, wird dann erneut zerlegt. Diesmal wird jedoch anhand des Gleichheitszeichens getrennt. Die beiden daraus resultierenden Zeichenketten werden in den Skalaren $param und $wert gespeichert. Diese werden dann anschließend einzeln im Browser ausgegeben.

Würden Sie das Listing 6.3 ebenfalls mit der URL http://localhost/cgi-bin/list6.2.pl?bg=336699&font=EEEEEE aufrufen, würden Sie die folgende Ausgabe erhalten:

bg
336699
font
EEEEEE

Anstatt diese einzelnen Zeichenketten nun im Browser auszugeben, können Sie sie natürlich auch weiterverarbeiten. In Listing 6.4 werden die einzelnen Parameter überprüft und die Werte dann entsprechenden Variablen zugewiesen. Anschließend werden sie mit der bereits bekannten crypt-Funktion verschlüsselt.

#!/usr/bin/perl -w
use CGI qw(:standard);

print header();

my @params = split(/\&/,$ENV{'QUERY_STRING'});

foreach(@params)
{
  ($param,$value) = split(/\=/,$_);
  if($param eq "name") { $soup = $value; }
  if($param eq "pw") { $salt = $value; }
}

print crypt($soup,$salt);

Listing 6.4: Perl-Script, das zwei übergebene Wertepaare verschlüsselt

Im Anweisungsblock der foreach-Anweisung wird zuerst überprüft, welchen Bezeichner die einzelnen Parameter erhalten haben, und entsprechend werden dann den beiden Skalaren $soup und $salt die Werte zugewiesen. Zum Schluss werden diese beiden Werte verwendet, um eine kodierte Zeichenkette zu erhalten.

# Modularisierung

Da Sie nun sicherlich nicht jedes Mal eine Lösung schreiben wollen, die es Ihnen ermöglicht, die einzelnen Parameter und Werte aus der QUERY_STRING-Zeichenkette zu filtern, sollten Sie eine Subroutine erstellen, die Ihnen diese Zeichenkette zerlegt. Die Routine könnte folgendermaßen aussehen:

sub splitCGIParams  
{  
  local @pairs = split(/\&/,$ENV{'QUERY_STRING'});  
  local %paramHash;  
  foreach(@pairs)  
  {  
    ($param,$value) = split(/\=/,$_);  
    $paramHash{$param} = $value;  
  }  
  return %paramHash;  
}

Innerhalb der Subroutine werden zwei lokale Variablen definiert. Der Liste @pairs werden die einzelnen Wertepaare zugewiesen, und es wird anschließend der Hash %paramHash definiert. In der nachfolgenden foreach-Schleife werden die Wertepaare in Parameterbezeichner und Werte aufgeteilt. Die Parameterbezeichner werden dann als Elementbezeichner bzw. assoziativer Index und die Werte als Elementwerte verwendet. Schlussendlich wird der in der Subroutine erzeugte Hash mit der return-Anweisung zurückgegeben.

Ein Beispielaufruf für diese Subroutine wäre:

my %params = splitCGIParams();

Achten Sie darauf, dass Sie die runden Klammern trotzdem notieren müssen, auch wenn Sie keine Parameter an die Subroutine übergeben. Andernfalls kann es zu Fehlern kommen.

Im Hash %params stehen Ihnen nun alle übergebenen Wertepaare zur Verfügung.

# Formulare

Bei der Verwendung von HTML-Formularen gibt es zwei Arten der Datenübertragung: GET und POST, wobei sich letztere mittlerweile als die effektivste erwiesen hat. Sobald Sie größere Datenmengen an den Server übertragen möchten, bleibt Ihnen auch keine andere Möglichkeit. Vorteilhaft ist auch, dass die übermittelten Daten nicht in der Adressleiste des Browsers wiederzufinden sind, wie es bei der GET-Methode der Fall ist. Die Verwendung der POST-Methode ist also ein – wenn auch geringer – Sicherheitsaspekt.

Das Problem ist wiederum die Art, wie Perl die übermittelten Daten zur Verfügung stellt. Weil die Daten bei Verwendung der POST-Methode über einen eigenen Datenkanal an den Server übertragen werden, müssen Sie diesmal direkt auf diesen Datenkanal zugreifen. Man nennt dies auch einen Datenstrom, was bedeutet, dass alle Daten, die mit dem HTML-Formular übertragen wurden, aneinander gereiht ankommen. Bei der GET-Methode werden die Daten über die URL übergeben.

Generell werden sowohl bei der POST- als auch bei der GET-Methode nicht nur die Namen der Formularfelder, sondern auch die Werte übertragen. Damit die einzelnen Informationen im Script nun weiterverarbeitet werden können, müssen sie gekennzeichnet bzw. kodiert werden. Keine Sorge, dies klingt schlimmer, als es ist. Kodierung bedeutet in diesem Fall, dass spezielle Sonderzeichen den Anfang und das Ende der einzelnen Datenfelder kennzeichnen.

  • Alle Wertepaare (dies sind die Bezeichner der Formularfelder und der entsprechende Wert) werden durch ein kaufmännisches Und & voneinander getrennt.
  • Bezeichner und Wert wiederum werden durch das Gleichheitszeichen = voneinander getrennt.
  • Alle Leerzeichen bei den Werten werden durch das Pluszeichen + ersetzt.
  • Die Buchstaben von a bis z, von A bis Z und die Zahlen von 0 bis 9 werden normal übertragen.
  • Alle Sonderzeichen (deren Wert in der ASCII-Tabelle höher als 128 ist) hingegen werden durch einen ASCII-Code ersetzt, der in hexadezimaler Form angegeben und durch das Prozentzeichen % eingeleitet wird.
  • Alle Zeichen, die eigentlich als Sonderzeichen verwendet werden (&, =, + und %) und in den Formularfeldern verwendet wurden, werden ebenfalls nach der ASCII-Norm kodiert.

Einen Teil dieser Regeln haben Sie bereits im vorangegangenen Kapitel kennen gelernt. Die restlichen Regeln finden dort jedoch auch Anwendung. Aus diesem Grund wurden die Hex-Tripel-Werte in den vorigen Beispielen ohne das führende Rautezeichen übergeben. Denn dieses müsste ebenfalls kodiert werden. Das bedeutet, dass, egal ob Sie die Daten per HTML-Formular oder direkt über die URL übergeben, diese Regeln beachtet werden müssen, da es ansonsten zu fehlerhaften Ergebnissen kommen kann.

Ich werde Ihnen ein konkretes Beispiel geben. Während Sie bei einer einfachen Übergabe der Parameter das Element QUERY_STRING aus dem %ENV-Hash ausgelesen haben, müssen Sie bei einer Datenübergabe mittels HTML-Formular den bereits erwähnten Datenstrom einlesen. Die dafür zu verwendende Funktion lautet read.

read(handle, string destination, integer length)

Als handle wird der Standard-Eingabekanal übergeben, der sich STDIN nennt. Die Daten, die aus dem Datenstrom eingelesen wurden, liegen als Zeichenkette vor. Daher müssen Sie anstelle von destination einen Skalar notieren, der die empfangenen Daten aufnehmen bzw. speichern soll. Leider wird bei einem Datenstrom kein Steuerzeichen gesendet, das das Ende des Datenstroms markiert. Aus diesem Grund müssen Sie der Funktion read noch mitteilen, wie viele Zeichen sie aus dem Datenstrom auslesen soll. Die Anzahl der Zeichen wird jedoch im %ENV-Hash hinterlegt, und zwar im Element CONTENT_LENGTH. Ein Beispielaufruf der Funktion read könnte lauten:

read(STDIN, my $datenstrom, $ENV{'CONTENT_LENGTH'}`;`

Diese Anweisung würde nun alle Zeichen aus dem Datenstrom auslesen und sie im Skalar $datenstrom speichern.

Wichtig ist, dass Sie den Datenstrom auslesen müssen, noch bevor Sie irgendeine Ausgabe mit der print-Anweisung veranlassen. Die Anweisung print header() gehört ebenfalls dazu und darf erst nach dem Auslesen des Datenstroms notiert werden.

Das nun folgende Listing 6.5 ist ein HTML-Dokument, das ein Formular bereitstellt. Die Daten des Formulars werden mit der POST-Methode an das Perl-Script list6.6.pl Der Einfachheit halber wurden einige HTML-Tags weggelassen, wie z. B. das !DOCTYPE-Element bzw. der Kommentar.gesendet.

<html>
  <head>
    <title>Listing 6.5</title>
  </head>
  <body>
    <form method="post" action="/cgi-bin/list6.6.pl">
      Vorname:<br><input type="text" name="vorname"><br>
      Nachname:<br><input type="text" name="nachname"><br>
      Email:<br><input type="text" name="email"><br>
      Kommentar:<br><textarea name="kommentar" cols="40" rows="10"></textarea><br>
      <input type="submit">
    </form>
  </body>
</html>

Listing 6.5: HTML-Dokument, das die eingegebenen Daten mit der POST-Methode an das Perl-Script list6.6.pl versendet

Dieses HTML-Dokument stellt insgesamt fünf Formularelemente zur Verfügung. Die ersten drei Elemente sind vom Typ input und ermöglichen eine einzeilige Texteingabe. Das vierte Element ist vom Typ textarea und ermöglicht die Eingabe eines längeren Textes, und das fünfte Element erzeugt eine Schaltfläche zum Versand der Formulardaten.

Das Perl-Script, das die Daten empfängt, sieht folgendermaßen aus:

#!/usr/bin/perl -w
use CGI qw(:standard);

read(STDIN, my $datenstrom, $ENV{'CONTENT_LENGTH'});

print header();
print $datenstrom;

Listing 6.6: Perl-Script, das Daten aus einem HTML-Formular entgegennimmt und im Browser ausgibt

Mit der read-Funktion werden die an das Script übermittelten Daten im Skalar $datenstrom gespeichert. Anschließend wird nach der Ausgabe des HTML-Headers der Inhalt des Skalars $datenstrom im Browser ausgegeben.

Gehen Sie einmal davon aus, dass folgende Daten im HTML-Formular eingegeben wurden:

Formularfeld Eingabe
Vorname Max
Nachname Mustermann
Email max@mustermann.de
Kommentar Das ist ein einfacher Kommentartext.

Tabelle 6.1: Beispieleingaben im HTML-Formular aus Listing 6.5

Nach dem Klick auf die Absenden-Schaltfläche würde das Perl-Script aus Listing 6.6 die folgende Ausgabe erzeugen:

vorname=Max&nachname=Mustermann&email=max@mustermann.de&kommentar=Das+ist+ein+einfacher+Kommentartext.

Mehrere Dinge sind deutlich zu erkennen: Alle Wertepaare werden durch das kaufmännische Und & aneinander gehängt, und alle Leerzeichen wurden durch Pluszeichen + ersetzt. Zu guter Letzt ist zu erkennen, dass als Parameterbezeichner der Wertepaare der Name übergeben wurde, der dem Formularelement über das name-Attribut zugewiesen worden ist. Dies ergibt also immer folgende Konstruktion:

elementname=eingegebener_wert

Nur dadurch ist es möglich, die einzelnen Informationen aus dem Datenstrom den entsprechenden Formularelementen zuordnen zu können. Das bedeutet auch, dass der Wert des name-Attributs (bis auf eine Ausnahme) immer unterschiedlich sein sollte. Welche Ausnahme das genau ist, werden Sie etwas später erfahren.

# Daten dekodieren

In der Form, wie die Formulardaten übergeben wurden, sind diese kaum zu gebrauchen. Nun könnten Sie eine Subroutine programmieren, die alle Pluszeichen durch Leerzeichen ersetzt, die einzelnen Wertepaare in Bezeichner und Wert zerlegt und auch die Dekodierung der einzelnen Sonderzeichen vornimmt. Einfacher und besser wäre es aber, die Funktion param aus dem CGI-Modul zu verwenden, die diese Arbeiten übernimmt. Seien Sie mir nicht böse, dass ich Sie zuvor mit der ganzen Theorie gequält habe und vielleicht das eine oder andere graue Haar bei Ihnen gewachsen ist. Für die Fehlersuche wird Ihnen dies später aber hilfreich sein. Außerdem erkennen Sie dadurch sehr gut, welche Arbeitserleichterung Ihnen das CGI-Modul bietet. Es beschränkt sich halt nicht nur auf die Ausgabe eines HTML-Headers.

Je nachdem, in welchem Kontext die Funktion aufgerufen wird, können Sie unterschiedliche Informationen auslesen, z. B. die Schlüsselnamen, einen einzelnen Wert oder die Anzahl der gesamten Wertepaare.

Aufrufkontext Rückgabetyp Erläuterung
@schluessel = param() Liste Speichert alle Schlüssel in der angegebenen Liste.
$anzahl = param() Skalar (Integer) Ermittelt die Anzahl aller Felder.
if(param()) Boolean Überprüft, ob überhaupt Daten übermittelt wurden.
$name = param('vorname') Skalar (String) Liefert den Wert des angegebenen Felds zurück.

Tabelle 6.2: Verschiedene Aufrufarten für die Funktion param

Im folgenden Listing 6.7 kommen alle Aufrufkontexte aus Tabelle 6.2 zum Einsatz.

#!/usr/bin/perl -w
use CGI qw(:standard);

if(param())
{
  my $anz = param();
  my @felder = param();
  
  print header();
  print "Insgesamt wurden $anz Wertepaare übergeben.<br>";
  foreach(@felder)
  {
    print $_," = ",param($_),"<br>";
  }
}
else
{
  print header();
  print "<html>
    <head>
      <title>Listing 6.7</title>
    </head>
    <body>
      <form method=\"post\" action=\"/cgi-bin/list6.7.pl\">
        Vorname:<br><input type=\"text\" name=\"vorname\"><br>
        Nachname:<br><input type=\"text\" name=\"nachname\"><br>
        Email:<br><input type=\"text\" name=\"email\"><br>
        Kommentar:<br><textarea name=\"kommentar\" cols=\"40\" rows=\"10\"></textarea><br>
        <input type=\"submit\">
      </form>
    </body>
  </html>";
}

Listing 6.7: Perl-Script, das überprüft, ob Daten an das Script übergeben wurden, und das entweder die Daten ausgibt oder ein HTML-Formular anzeigt

Zu Beginn des Scripts aus Listing 6.7 wird überprüft, ob das Script Daten übergeben bekommen hat. Dafür wird die Funktion param in einem logischen Kontext aufgerufen. Wenn Daten übermittelt wurden, liefert die Funktion TRUE zurück, andernfalls FALSE.

Wurden Daten übermittelt, wird der if-Anweisungsblock ausgeführt. In diesem werden zuerst die Anzahl der Wertepaare im Skalar $anz und die Schlüsselnamen in der Liste @felder gespeichert. Es werden der HTML-Header und die Anzahl der Wertepaare ausgegeben. Danach wird in der foreach-Schleife jeder Schlüsselname einzeln abgearbeitet und sowohl der Schlüsselname als auch der entsprechende Wert ausgegeben.

Wenn keine Daten übermittelt wurden, wird der else-Anweisungsblock ausgeführt. Dieser gibt lediglich den HTML-Header und ein HTML-Dokument aus, das ein Formular enthält. Als Datenempfänger wurde in dem HTML-Formular das eigene Script angegeben. Der Name des Scripts ist in der globalen Variable $PROGRAM_NAME2 gespeichert.

Diese Art von Perl-Scripts ist immer dann sinnvoll, wenn ein Script aus verschiedenen Kontexten heraus aufgerufen werden kann. Dadurch reicht es aus, einfach das Script als Ziel eines Verweises zu notieren, und es überprüft selbstständig, ob bzw. welche Daten es noch benötigt.

# Cookies

Wie auch schon in JavaScript ist es auch in Perl möglich, Cookies zu schreiben und zu lesen. Alles, was Sie dazu benötigen, ist bereits im CGI-Modul vorhanden. Dadurch können Sie individuelle Informationen zu einem Benutzer Ihrer Webseite zwischenspeichern und bei Bedarf darauf zurückgreifen. Während Sie in JavaScript jedoch eine Funktion nutzen konnten, um ein Cookie zu schreiben oder zu lesen, müssen Sie in Perl eine Hash-Funktion verwenden.

Dies klingt vielleicht ungewohnt, ist aber gar nicht so undurchsichtig, wie es klingt. Die Funktion, die Sie verwenden müssen, heißt cookie. Die Funktion kapselt jedoch nur den Zugriff auf einen Hash. Als Parameter übergeben Sie an die Funktion den Schlüsselnamen eines Elements und den entsprechenden Wert. Die Schreibweise entspricht dabei derjenigen, die Sie auch bei der Definition eines Hashs verwenden.

Ein Beispiel:

my $ein_cookie = cookie(-name=>'das erste cookie');

Dieses Beispiel definiert ein Cookie, das dem Skalar $ein_cookie zugewiesen wird. Dem Element name des Cookies wird der Wert das erste cookie zugewiesen. Die Funktion cookie liefert nun anhand der übergebenen Parameter eine kodierte Zeichenkette. Diese Arbeitsweise ist sehr einfach und auch gut anzuwenden, leider können Sie die Parameter nicht nachträglich erweitern. Sie müssen also alle Parameter zugleich übergeben. Die folgende Tabelle 35.3 bietet eine Übersicht über diese Parameter.

Parameter Beispiel Erläuterung
-name -name=>'last_visit' Definiert einen Namen für das Cookie.
-value -value=>'01.10.2002' Definiert den Wert, der im Cookie gespeichert werden soll.
-expires -expires=>'+6M' Legt die Haltbarkeitsdauer des Cookies fest. +6M bedeutet sechs Monate.
-path -path=>'/' Definiert das Verzeichnis, in dem das Cookie gültig ist (gilt auch für die Unterverzeichnisse). / entspricht dem root-Verzeichnis.

Tabelle 7.3: Die wichtigsten Parameter für die Funktion cookie

Bei der Namensgebung des Cookies sind Sie in Ihrer Entscheidungsfreiheit nicht eingeschränkt. Sie sollten jedoch auf Sonderzeichen verzichten, da dies sonst zu Problemen führen wird. Verwenden Sie außerdem eindeutige Namen, damit sich, falls Sie mehrere Cookies erzeugen wollen, diese nicht überschneiden oder gar überschreiben.

Auch der zu speichernde Wert ist egal. Sie können sowohl einen festen Wert speichern als auch eine Variable übergeben. Achten Sie jedoch darauf, dass Sie maximal 1024 Bytes speichern können.

-value=>$ein_skalar

Jedes Cookie verfügt über eine Haltbarkeitszeit bzw. über einen Zeitraum, in dem es gültig ist. Diesen Zeitraum können Sie entweder relativ oder absolut angeben. Eine relative Angabe wäre z. B. +3M. Dies bedeutet, dass das Cookie ab dem Zeitpunkt, an dem es erstellt wurde, genau drei Monate lang gültig bleibt. Weitere Einheiten wären y für Jahre, d für Tage, h für Stunden, m für Minuten und s für Sekunden. Dass Sie anstelle des Pluszeichens kein Minuszeichen notieren dürfen, versteht sich von selbst, denn es hätte keinen Sinn, die Gültigkeitsdauer eines Cookies auf einen bereits vergangenen Zeitpunkt festzulegen.

Bei der Angabe eines absoluten Zeitpunkts müssen Sie diesen im UTC-Format (Universal TimeCode) übergeben, z. B. Tuesday, 31-Dec-2002 23:59:59 GMT+0100.

Wenn Sie einen Pfad angeben, bedeutet das, dass das Cookie nur in diesem Verzeichniszweig gültig ist, also in dem angegebenen Verzeichnis und allen Unterverzeichnissen. Geben Sie das root-Verzeichnis an (/), ist das Cookie in allen Verzeichnissen gültig. Geben Sie hingegen keinen Pfad an, ist das Cookie nur in dem Verzeichnis und den Unterverzeichnissen gültig, in denen auch das erstellende Perl-Script liegt.

Nachdem Sie sich nun mit den einzelnen Parametern befasst haben, werde ich Ihnen jetzt aufzeigen, wie Sie das Cookie überhaupt schreiben können. Noch bevor Sie den HTML-Header an den Browser senden, müssen Sie das Cookie definieren, da Sie den Skalar, dem Sie das Cookie zugewiesen haben, beim Senden des HTML-Headers mit übergeben müssen.

Das Cookie definieren Sie durch die Anweisung:

my $ein_cookie = cookie([Parameter]);

Und durch die Anweisung

print header(-cookie=$ein_cookie);

können Sie dann das Cookie schreiben.

Das folgende Listing soll dies noch einmal verdeutlichen.

#!/usr/bin/perl -w
use CGI qw(:standard);

my $jetzt = localtime(time);
my $ein_cookie = cookie(-name=>'Letzter Besuch',
                        -value=>$jetzt,
                        -expires=>'+7d');

print header(-cookie=>$ein_cookie);
print "<h1>Zeitpunkt: $jetzt</h1>";

Listing 6.8: Perl-Script, das ein Cookie schreibt

Zuerst wird der aktuelle Zeitpunkt ermittelt und dem Skalar $jetzt zugewiesen. Anschließend erzeugen Sie das Cookie mit dem Namen »Letzter Besuch« und dem in $jetzt gespeicherten Zeitpunkt als Wert. Außerdem wird dem Cookie eine Haltbarkeitsdauer von 7 Tagen zugewiesen. Danach wird das Cookie zusammen mit dem HTML-Header an den Browser gesendet.

Wenn während des Ausführens des Scripts keine Fehler aufgetreten sind, wurde das Cookie auf dem Rechner des Benutzers erzeugt. Dieses Cookie können Sie nun, abhängig davon, wie lange es gültig ist, beliebig abrufen.

Das Schreiben eines Cookies hat natürlich keinen Sinn, wenn Sie auf dieses Cookie nicht auch lesend zugreifen. Dabei unterscheidet sich das Lesen des Cookies vom Schreiben nur durch die Anzahl der Parameter, die an cookie übergeben wird. Es wird nämlich nur der Name des Cookies übergeben.

#!/usr/bin/perl -w
use CGI qw(:standard);

my $jetzt = localtime(time);
my $cookie_alt = cookie(-name=>'Letzter Besuch');
my $cookie_neu = cookie(-name=>'Letzter Besuch',
                        -value=>$jetzt,
                        -expires=>'+7d');

print header(-cookie=>$cookie_neu);
print "<h1>Letzter Besuch: $cookie_alt</h1>";
print "<h1>Jetziger Zeitpunkt: $jetzt</h1>";

Listing 6.9: Perl-Script, das das alte Cookie liest und durch ein neues überschreibt

Auch in diesem Listing wird zuerst der aktuelle Zeitpunkt ermittelt und im Skalar $jetzt gespeichert. Anschließend wird das alte Cookie ausgelesen, im Skalar $cookie_alt gespeichert und ein neues Cookie erzeugt, das dem Skalar $cookie_neu zugewiesen wird. Nach dem Senden des HTML-Headers inklusive des neuen Cookies werden der Wert des alten Cookies und der aktuelle Zeitpunkt (der Wert, der dem neuen Cookie zugewiesen wurde) im Browser ausgegeben.

Natürlich ist die Verwendung von Cookies nicht auf das Speichern und Lesen eines Zeitpunkts beschränkt. Sie könnten z. B. Einstellungen speichern, die der Benutzer mit einem anderen Perl-Scripts vorgenommen hat, und diese bei Bedarf wieder abrufen.

# Zusammenfassung

  • Parameter, welche die über die URL übergeben wurden, können aus dem Element QUERY_STRING des %ENV-Hashs ausgelesen werden.
  • Die einfachste Variante, Formulardaten eines HTML-Dokuments zu erhalten, ist die Verwendung der Funktion param. Die übermittelten Daten stehen dann in einem Hash zur Verfügung.
  • Cookies werden über die Funktion cookie und spezielle Parameter erstellt. Um ein Cookie zu lesen, genügt die Zuweisung an einen Skalar. Um ein Cookie zu schreiben, müssen Sie es zusammen mit dem HTML-Header an den Browser senden.

# Fragen und Übungen

  1. Welche Funktion müssen Sie verwenden, wenn Sie Parameter und Werte der Zeichenkette $ENV{'QUERY_STRING'} ermitteln möchten?
  2. Mit welcher Zeichenfolge müssen Sie & und = bei Verwendung nach der eben gefragten Funktion ersetzen?
  3. Wie können Sie im Perl-Script überprüfen, ob Daten mit einem HTML-Formular an das Script gesendet wurden?
  4. Schreiben Sie eine Subroutine, die sowohl den Parameterbezeichner als auch den Wert der übermittelten Formulardaten ausgibt. Beachten Sie, dass diese Routine in verschiedenen Scripts Verwendung finden soll, die unterschiedliche Formulardaten erhalten.
  5. Schreiben Sie ein Script, das die Anzahl der persönlichen Besuche eines Benutzers mittels Cookies zählt.