Werbung einblenden Werbung ausblenden


Home / Tutorials / Perl Handbuch / Das CGI.pm Modul

mit dem CGI Modul:

HTML Seiten erstellen
Formulare generieren
Formulare auslesen
komplexere HTML Seiten aufbauen
Cookies setzen
Cookies einrichten
Cookies auslesen
persistente und temporäre Cookies anlegen
Dateien auf einem Fremdrechner bearbeiten

HTML Seiten erstellen

Das CGI Modul ist wohl das am meisten benutzte und das am besten dokumentierte Perl Modul.
Zu beginn wird der Ansatz des CGI Moduls kurz beschrieben. Eine ausführliche Erläuterung findet man in der Dokumentation der Distribution von Activestate (c:/perl/docs).
Darüber hinaus werden Probleme beschrieben, die sich ohne das CGI.pm Modul nicht, oder nur mit enormen Aufwand lösen lassen.
Es ist hilfreich, sich die HTML Grundlagen, die die Forms betreffen, genauer anzusehen, siehe Formulareingaben auswerten.

Der HTML Quellcode lässt sich problemlos in ein Perl Skript integrieren. Dies zeigt das folgende Beispiel:

#!usr/bin/perl

print "Content-type:text/html\n\n";

print "
<html><head><title>Hello Globus</title></head>
<body>
<font color=blue size=5>
Masturbation is a way to have sex with someone
</font>
you really love.
</body>
</html>

Das Problem bei dieser Vorgehensweise ist, dass das Perl Skript in der Regel gewaltig aufgeschwemmt wird.
Das gleiche sieht mit dem CGI.pm Modul so aus:

use CGI qw/:standard/;
$mein_html=CGI->new;
print $mein_html->header(),
$mein_html->start_html("Hello Globus"),
$mein_html->font({color=>'red',size=>'5'},'Masturbation is a way to have sex with someone you really love'),
$mein_html->end_html;

Es ist an dieser Stelle hilfreich, sich die Kapitel: Referenzen, Objektorientierte Programmierung, Arbeiten mit Modulen noch mal zu vergegenwärtigen. Das Skript wird dann im cgi-bin Verzeichnis des HTTP -Servers abgespeichert und mit http://127.0.0.1/cgi-bin/mein_name.pl ausgelöst. Mit use CGI qw/:standard/; binden wird das CGI.pm Modul in das Hautprogramm ein. Beim Aufruf geben wir noch an, welche Werte importiert werden sollen, in diesem Fall also :standard
Dies bewirkt, dass alle HTML Elemente über $name_des_Zeigers->html_tag aufrufbar sind.
Auch folgende Schreibweise ist möglich:

use CGI::Carp "fatalsToBrowser";
use CGI qw/:standard/;

$mein_html=CGI->new;
print $mein_html->header(),
$mein_html->start_html("Hello Globus"),
$mein_html->font({color=>'red',size=>'5'},'Masturbation is a way to have sex with someone you really love'),
$mein_html->end_html;

Alle Fehler, die das Skript produziert, werden im Browser angezeigt. Dies ist im CGI Umfeld nicht der Default. Hier erscheint als Fehlermeldung, die der HTTP Server produziert (z. B. This server has encountered an internal error, which prevents it from fullfilling your request......).
Auffällig ist noch, dass im ersten Beispiel nur ein package aufgerufen wird, im zweiten Beispiel aber ein kompletter Pfad. Das ist nicht weiter erstaunlich, da cgi.pm in c:/perl/lib liegt, also keinen Pfad braucht. carp.pm dagegen liegt im Ordner c:/perl/lib/CGI und braucht einen Pfad.
Um das zu verdeutlichen, machen wir jetzt einen Fehler:

use CGI::Carp "fatalsToBrowser";. 
use CGI qw/:standard/;
$mein_html=CGI->new;
print $mein_html->header(),
$mein_html->start_html("Hello Globus"),
$mein_html->font({color=>'red',size=>'5','Masturbation is a way to have sex with someone you really love'),
$mein_html->end_html;

Da in dem Skript der anonymous hash nicht geschlossen wird, erhalten wir folgende Fehlermeldung:
Software error: syntax error at C:\sambar\cgi-bin\testcgi.pl line 1, near ";." Execution of C:\sambar\cgi-bin\testcgi.pl aborted due to compilation errors. For help, please send mail to this site's webmaster, giving this error message and the time and date of the error.

Das CGI.pm Modul kann genutzt werden, indem man Subroutinen des packages direkt aufruft oder objektorientiert. Hier wird allerdings nur der objektorientierte Ansatz vorgestellt.
Mit $mein_html=CGI->new; bilden wir ein Instanz der Klasse CGI. (Also ein Objekt, das weiß, dass es zum package CGI gehört und folglich all das kann, was das package CGI.pm kann). Mit diesem Objekt werden wir dann im folgenden arbeiten.

Was im Detail passiert, kann schematisch dargestellt werden:

Subroutinen des CGI.pm Moduls

und was sie bewirken

print

alles was jetzt produziert wird, wird gedruckt

$mein_html->header

"Content-type:text/html\n\n";

$mein_html->start_html

<html><head><title>hello Globus</title></head><body>

$mein_html->font({-Name_Attribut=>'Wert_Attribut},'Text')

<font color=red size=5>Masturbation is a way to have...</font>

$mein_html->end_html

</body></html>

Damit ist prinzipiell klar, was passiert. Jeder HTML tag kann nach diesem Schema aufgerufen werden. Es können dann jeweils zwei Parameter übergeben werden.

  • Erstens ein anonymous Hash, siehe Referenzen. Der anomymous Hash steht zwischen den beiden geschweiften Klammern ({}).
    Wiederholung: Ein anonymous Hash ist ein Hash ohne Namen, der nur über einen Zeiger angesprochen werden kann. In dem Hash stehen die Attribute des dazugehörigen HTML tags.

  • Zweitens wird das angegeben, was zwischen dem öffnenden und dem schließenden Tag tatsächlich stehen soll, in diesem Falle also "Masturbation is a way to have sex.....".

Formulare generieren

Nach einem ähnlichen Schema wie oben lassen sich auch Formulare generieren:

use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Mein Formular, mein Stolz');
print $x->start_form;
print "Was denken Sie vom Leben ?
"; print $x->checkbox_group(-name=>leben,-values=>['toll','super','berauschend'],-default=>'toll'); print $x->submit; print $x->end_form; print $x->end_html;

Auffallend ist hier der Teil, der die Checkbox Liste auf den Schirm setzt. Da wir es mit dem Spezialfall zu tun haben, dass es Checkboxen mit gleichem Namen gibt, rufen wir nicht einfach checkbox auf, sondern checkbox_group.
Der anonymous Hash, der übergeben wird, hat dann drei Werte: den Namen der Box (für alle drei Boxen der gleiche, nämlich leben), die Werte für diese Boxen und eine Eingabe, welche Boxen von vorneherein angeklickt sein sollen.
Was start_form macht ist im Prinzip klar, man kann sich allerdings anschauen, welche default Werte das CGI.pm Modul einsetzt, weil hier kein Hash mitgeliefert wird, der das genauer spezifiziert.

Die HTML Seite, die das Perl Skript generiert, sieht dann so aus:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML Basic 1.0//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head><title>Mein Formular, mein Stolz</title></head>
<body>
<form method="post" action="../../cgi-bin/testcgi.pl" enctype="application/x-www-form-urlencoded">
Was denken Sie vom Leben ?<br>
<input type="checkbox" name="leben" value="toll" checked />toll
<input type="checkbox" name="leben" value="super" />super
<input type="checkbox" name="leben" value="berauschend" />berauschend
<input type="submit" name=".submit" /><input type="hidden" name=".cgifields" value="leben" />
</form>
</body>
</html>

Formulare auslesen

Der praktisch relevantere Teil des CGI Moduls ist nicht, HTML Seiten mit Formularen aufzubauen.
Spannend ist es, wie die Werte aus dem Formular wieder rausgefischt werden. Das heißt, wie findet man raus, ob der User das Leben toll, super oder berauschend findet?

Wir erweitern einfach das obige Skript und wissen, wie es geht:

use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Mein Formular, mein Stolz');
print $x->start_form;
print "Was denken Sie vom Leben ?
"; print $x->checkbox_group(-name=>leben,-values=>['toll','super','berauschend'],-default=>'toll'); print $x->submit; print $x->end_form; print $x->end_html; if(param) { print "Prima ! Du findest das Leben also ".param('leben'); }

Mit der Funktion param('name_der_box') können wir den Wert, den der User angeklickt hat wieder rausfischen. Prinzipiell funktioniert das so einfach.
Wer aber mit dem Beispiel ein bisschen rumspielt, wird ein Problem erkennen. Werden mehrere Boxen angeklickt, zeigt das Programm immer nur den Wert der letzten Box, also nur einen Wert.
Was ist aber, wenn der User das Leben sowohl toll als auch berauschend findet?
In diesem Fall müssen die Werte, die die Funktion param liefert, an einen Array übergeben werden:

use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Mein Formular, mein Stolz');
print $x->start_form;
print "Was denken Sie vom Leben ?
"; print $x->checkbox_group(-name=>leben,-values=>['toll','super','berauschend'],-default=>'toll'); print $x->submit; print $x->end_form; print $x->end_html; if(param) { @leben=param('leben'); print "Prima ! Du findest das Leben also @leben"; }

Das gleiche Beispiel in einer objektorientierten Schreibweise:

use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Mein Formular, mein Stolz');
print $x->start_form;
print "Was denken Sie vom Leben ?
"; print $x->checkbox_group(-name=>leben,-values=>['toll','super','berauschend'],-default=>'toll'); print $x->submit; print $x->end_form; print $x->end_html; if(param) { @leben=param('leben'); $query = new CGI; print $query; @names = $query->param('leben'); print "Prima ! Du findest das Leben also @names"; }

Es sind Anwendungen denkbar, bei denen nicht bekannt ist, wie das Formular aussieht.
Das ist zum Beispiel der Fall, wenn man eine Routine schreibt, die es der Menschheit ermöglichen soll, jedes x-beliebige Formular über Email zu verschicken.
Aber auch in Anwendungen, bei denen die Art des Formulars davon abhängt, welche Eingaben der User vorher gemacht hat. Es entsteht also das Problem, dass auf einzelne Elemente des Formulars (nach dem Schema $banane=param('himbeere')) nicht zugegriffen werden kann, da nicht bekannt ist, ob es überhaupt eine himbeere gibt.
Gesucht wird also eine Routine, die einfach alle Namen eines Formulars und die dazugehörigen Werte in einen Hash einliest und zwar unabhängig von der Frage, wie viele Formularelemente das Formular hat und unabhängig davon, wie diese heißen.
Das folgende kleine Programm zeigt, wie es geht:


use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Mein Formular, mein Stolz');
print $x->start_form;
print "Was denken Sie vom Leben ?<br>";
print $x->checkbox_group(-name=>leben,-values=>[super,phantastisch,irre]);
print "<br>";
print "Sie k&ouml;nnen hier was reinschreiben <br>";
print $x->textfield(-name=>'beitrag');
print "<br>";
print "Sind Sie m&auml;nnlich oder weiblich ? <br>";
print $x->radio_group(-name=>geschlecht,-value=>['m&auml;nnlich','weiblich']);
print "<br>";
print $x->submit;
print $x->end_form;
print $x->end_html;
if(param)
{
$leben=$x->Vars;
print "Das ist der Zeiger auf einen Hash, der alle name/value Paare des Formulars hat<br>";
print $leben;
print "<br>";
print "Diesen hash kann man jetzt auslesen<br>";
foreach (keys(%$leben))
{
    print "Es gibt einen Schl&uuml;ssel $_ und zu diesem geh&ouml;rt der Wert $$leben{$_} <br>";

}
}

Um zu verstehen, was hier passiert, sollte das Kaspitel Referenzen noch mal verinnerlicht werden.
Entscheidend ist die Zeile $leben=$x->Vars;.
Diese Zeile bildet einen Zeiger $leben auf einen Hash, der den Query_String in Hash Format von den Formularelementen zeigt, die zu dem Objekt $x gehören. Dieser Hash kann dann mit den üblichen Funktionen, siehe Funktionen zur Bearbeitung von Hashs, ausgelesen werden.

Unter Perl Routine zum Auslesen des QUERY_STRING, werden wir in einer Routine alle Formularelemente mit "der Hand" auslesen, unabhängig davon welche und wie viele Formularelemente vorkommen.

Komplexere HTML Seiten aufbauen

Werden mit dem CGI.pm Modul komplexere HTML Dokumente aufgebaut, wird die Sache schwieriger. HTML Dokumente sind so strukturiert, dass das die verschiedenen Elemente ineinander verschachtelt sind (aus SGML Sicht ist es eher eine hierarchische Struktur, aber das hilft uns im Moment nicht weiter). Das heißt, in den body Tags sitzen die table Tags, in den table Tags die tr Tags, in den tr Tags die td Tags, in den td Tags die font Tags etc. Beim Aufbau komplexerer HTML Seiten, muss also die innere Abhängigkeit der Tags zum Ausdruck gebracht werden. Das sieht dann so aus:

use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Mein Formular, mein Stolz');
print $x->start_form;
print $x->table(
{-bgcolor=>'yellow',-border=>'1'},
Tr(td({-align=>'center'},'Was denken Sie vom Leben')),
Tr(td({-align=>'center'},checkbox_group(-name=>leben,-values=>[super,phantastisch,irre]))),
Tr(td({-align=>'center'},font({-color=>'red',-size=>5},'Sie können hier was reinschreiben'))),
Tr(td({-align=>'center'},textarea(-name=>'beitrag',-rows=>'5',-cols=>'40'))),
Tr(td({-align=>'center'},font({-color=>'red',-size=>5},'Sind Sie männlich oder weiblich'))),
Tr(td({-align=>'center'},radio_group(-name=>geschlecht,-value=>['männlich','weiblich'] ))),
Tr(td({-align=>'center'},submit)),
),
$x->end_form,
$x->end_html;
if(param)
{
$leben=$x->Vars;
print "Das ist der Zeiger auf einen Hash, der alle name/value Paare des Formulars hat
"; print $leben; print "
"; print "Diesen hash kann man jetzt auslesen
"; foreach (keys(%$leben)) { print "Es gibt einen Schlüssel $_ und zu diesem gehört der Wert $$leben{$_}
"; } }

Dieses Programm produziert dann folgende HTML Seite:

Was denken Sie vom Leben
super phantastisch irre
Sie können hier was reinschreiben
Sind Sie männlich oder weiblich
männlich weiblich

Dieser Code ist zwar ausgesprochen kompakt, aber wesentlich komplexer als der "normale" HTML Quellcode.
Das CGI.pm Modul baut HTML Tags nach folgendem Schema zusammen:
Name_des_Tags({Attribute_des_Tags},'der eigentliche Inhalt des Tags');
Wenn jetzt aber "der_eigentliche Inhalt des Tags" selber wieder ein Tag ist, erhalten wir folgendes Schema:

Name_des_Tags_eins ( {Attribute_des_Tags}, Name_des_Tags({Attribute_des_Tags},'der eigentliche Inhalt des Tags'), Name_des_Tags({Attribute_des_Tags},'der eigentliche Inhalt des Tags'), Name_des_Tags({Attribute_des_Tags},'der eigentliche Inhalt des Tags'), );

Der Tag Name_des_Tags_eins hat also eine Attributliste, die in einem anonymous Hash übergeben wird und einen Inhalt, der selbst wieder aus drei Tags besteht, die wiederum Attribute und Inhalte haben.
Das Skript kann mit folgender Schreibweise noch komprimiert werden:

use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Mein Formular, mein Stolz');
print $x->start_form;
print $x->table
(
		{-bgcolor=>'yellow',-border=>'1'},
  Tr(
	[
  	td({-align=>'center'},'Was denken Sie vom Leben'),
	td({-align=>'center'},checkbox_group(-name=>leben,-values=>[super,phantastisch,irre])),
	td({-align=>'center'},font({-color=>'red',-size=>5},'Sie können hier was reinschreiben')),
	td({-align=>'center'},textarea(-name=>'beitrag',-rows=>'5',-cols=>'40')),
	td({-align=>'center'},font({-color=>'red',-size=>5},'Sind Sie männlich oder weiblich')),
	td({-align=>'center'},radio_group(-name=>geschlecht,-value=>['männlich','weiblich'] )),
	td({-align=>'center'},submit)
	]
    )
),
$x->end_form,
$x->end_html;
if(param)
{
$leben=$x->Vars;
print "Das ist der Zeiger auf einen Hash, der alle name/value Paare des Formulars hat
"; print $leben; print "
"; print "Diesen hash kann man jetzt auslesen
"; foreach (keys(%$leben)) { print "Es gibt einen Schlüssel $_ und zu diesem gehört der Wert $$leben{$_}
"; } }

Wir sehen, dass dem Tag Tr als Inhalt ein anonymous Hash übergeben wird. Für jedes Element dieses Arrays wird der dazugehörige Tag einmal aufgebaut. (im obigen Beispiel wird der objektorientierte Ansatz und der Ansatz, über einen Funktionsaufruf die HTML Tags zusammenzubauen, vermischt.)
Für die Attributliste des Tags sind unterschiedliche Schreibweisen möglich:

I.   name_des_tags({Attribute_des_Tags},'Erster_Inhalt_des_Tags');
     name_des_tags({Attribute_des_Tags},'Zweiter_Inhalt_des_Tags');
     name_des_tags({Attribute_des_Tags},'Dritter_Inhalt_des_Tags');
II.  name_des_tags({Attribute_des_Tags},
     ['Erster_Inhalt_des_Tags','Zweiter_Inhalt_des_Tags','Dritter_Inhalt_des_Tags']);

Komplexere HTML Dokumente vollständig mit dem CGI.pm Modul aufzubauen, ist schwierig, deshalb schauen wir uns noch ein Beispiel an.
Versuchen wir, folgendes Formular mit dem CGI.pm Modul zu bauen. Es enthält alle existierenden HTML Formularelemente:

Hallo mein Schnuckel !
Wie heisst du denn, mein Schatz ?
Wie bist du denn so drauf ?
Bist du ein männlicher oder weiblicher Schnuckel ?m w
Erzähl mir doch mal was von Dir kleine Knusperstange
Hey Zuckerstange, passen wir zusammen ? Was hast du denn für Hobbys ?
SchwimmenSaufen
Mädchen ärgernJungs ärgern
Bild gefällig

Das Programm ist für Schüchterne. Perl startet eine ganz charmante Anmache, ganz professionell, ganz ohne Herzklopfen.
Das Programm sieht dann so aus:

use CGI qw/:standard/;
 
$x=new CGI;

print $x->header('text/html');
print $x->start_html(-title=>'Flirtomat');
print $x->start_form;
print $x->start_table({-border=>'1'}),
$x->Tr($x->td({-bgcolor=>'cococo',-colspan=>'2',-align=>'center'},
font({-color=>'red',-size=>'4'},'Hallo mein Schnuckel'))),
$x->Tr($x->td('Wie heisst du denn mein Schatz'),$x->td(textfield({-name=>'Name'}))),
$x->Tr($x->td('Wie bist du denn so drauf'),$x->td(popup_menu({-name=>'Name', -values=>
['gut','solala','weniger'],-labels=>{'gut'=>'Mir geht es gut'}}))),
$x->Tr($x->td('Bist du ein männlicher oder weiblicher Schnuckel'),
$x->td(radio_group({-name=>'geschlecht', -values=>['m','w'] }))),
$x->Tr($x->td({-colspan=>'2',-align=>'middle'},
'Erzähl mir doch mal was von dir, kleine Knusperstange')),
$x->Tr($x->td({-colspan=>'2',-align=>'middle'},textarea({-rows=>'5',-cols=>'40'}))),
$x->Tr($x->td({-colspan=>'2',-align=>'middle'},
'Hey Zuckerstange, passen wir zusammen ? Was hast du denn für hobbys ?')),
$x->Tr
(
  $x->td
  (
       {-align=>'middle',-colspan=>'2'},
		$x->table
	(
		{-border=>'1'},
   		$x->Tr($x->td(checkbox_group(-name=>hobby,values=>['schwimmen','saufen']))),
		$x->Tr($x->td(checkbox_group(-name=>hobby,values=>['Mädchen','Jungs']))),
	)
  )
),
$x->Tr($x->td({-colspan=>'2',-align=>middle},filefield({-name=>'bild'}))),
$x->Tr($x->td({-colspan=>'2',-align=>'middle'},
submit({-value=>'Ui, Ui my honeymoon, da bin ich aber gespannt'}))),
$x->end_table;

In diesem Beispiel ist es einfacher, auch den schließenden Tag des tables gleich mitgenerieren zu lassen. Dann müssen alle folgenden Tags in Abhängigkeit vom table definiert werden, was in diesem Fall, aufgrund der tieferen Schachtelung, sehr kompliziert ist. Danach werden die einzelnen Zeilen der Tabelle aufgebaut. Neu sind nur einige Formularelemente, die aber nach dem selben Schema aufgebaut werden.
Kompliziert wird es erst an der Stelle, an der wir einen "genesteten" table generieren müssen, das heißt, einen table der sich in einer Zelle befindet.

Die Struktur sieht so aus:

Zeile ({keine_Eigenschaften}, Inhalt=> Zelle ({mit_Eigenschaften}, Inhalt=>table({mit_Eigenschaften}, Inhalt=> tr({keine_Eigenschaften},Inhalt=>zwei Zellen tr({keine_Eigenschaften},Inhalt=>zwei Zellen

Danach werden die restlichen Zeilen aufgebaut. Am Schluss wird der table mit $x->end_table geschlossen.

Cookies setzen

Cookies sind Dateien, die im aufrufenden Rechner gespeichert werden, wo und wie werden wir noch sehen. Sie enthalten Informationen über den User.
Sollen die Informationen nur für die Dauer einer Sitzung gespeichert werden, dann gibt es Alternativen zu den Cookies. Die Werte können mit einem input type=hidden von einer Seite auf die nächste mitgeführt werden, siehe Formulareingaben auswerten, oder sie können in einen unsichtbaren Frame geschossen werden. Hier werden sie dann von einem JavaScript aufgenommen.
Keine Alternativen gibt es, wenn Informationen über mehrere Sitzungen gespeichert werden sollen. Wenn zum Beispiel registriert werden soll, ob der User schon einmal auf der Seite war oder nicht. Die Syntax, die verwendet wird, um mit dem CGI.pm Modul Cookies zu setzen, ist teilweise eigenartig. Vorab sollten wir uns folgendes klar machen:

sub wat_den_dat
{
  %det_isses=@_;
  foreach (keys(%det_isses))
  {
      print "Schlüssel: $_ Wert:$det_isses{$_} \n";
   }
}

wat_den_dat("name"=>"Ehmann","Vorname"=>"Andres","telefon"=>"03047301386");

Das funktioniert! Werden als Parameter einer Funktion Werte in Hash Schreibweise übergeben, dann wird ein Hash übergeben, der normal ausgelesen werden kann.

In objektorientierter Schreibweise, sieht das dann so aus:

package toll;

sub new
{
   $zeiger={};
   bless($zeiger);
}


sub wat_den_dat
{
$nirvana=shift;
  %det_isses=@_;
  foreach (keys(%det_isses))
  {
      print "Schlüssel: $_ Wert:$det_isses{$_} \n";
   }
}

$objekt=toll->new;
$objekt->wat_den_dat("name"=>"Ehmann","Vorname"=>"Andres","telefon"=>"03047301386");

Zum besseren Verständnis siehe Objektorientierte Programmierung. Theoretisch könnte das CGI.pm Modul, die Werte entgegennehmen und mit diesen einen Cookie anlegen. Dieses Verfahren führt zu Problemen, wenn mehrere Cookies aufeinmal angelegt werden sollen. Die nächste Idee ist, nicht den Hash selbst zu übergeben, sondern einen Zeiger auf diesen Hash. Es können beliebig viele Zeiger auf Hashs übergeben werden.

Wird nur ein Hash übergeben, funktioniert das auch und sieht so aus:

package toll;

sub new
{
   $zeiger={};
   bless($zeiger);
}
sub wat_den_dat
{
$nirvana=shift;
  %det_isses=@_;
  %$nirvana=%det_isses; 
  $fertig=\%$nirvana;
}

sub hash_auslesen
{
$nirvana=shift;
$zeiger_auf_hash=shift;

    foreach $himbeere(keys(%$zeiger_auf_hash))
   {
      print "Schlüssel ist $himbeere und Wert ist $$zeiger_auf_hash{$himbeere} \n";
   }
}
$objekt=toll->new;
$der_hash=$objekt->wat_den_dat("name"=>"Ehmann","Vorname"=>"Andres","telefon"=>"03047301386");
$objekt->hash_auslesen($der_hash);

Das ist allerdings nur dann eine Möglichkeit, wenn garantiert nur ein Hash an das CGI.pm Modul übergeben wird. Es können aber mehrere Hashs übergeben werden, dann funktioniert dieser Ansatz nicht mehr, wie folgendes Beispiel zeigt:

package toll;

sub new
{
   $zeiger={};
   bless($zeiger);
}
sub wat_den_dat
{
$nirvana=shift;
  %det_isses=@_;
  %$nirvana=%det_isses; 
  $fertig=\%$nirvana;
}

sub hash_auslesen
{
$nirvana=shift;
$zeiger_auf_array=shift;
foreach $erdbeere(@$zeiger_auf_array)
{
    foreach $himbeere(keys(%$erdbeere))
   {
      print "Schlüssel ist $himbeere und Wert ist $$erdbeere{$himbeere} \n";
   }
}
}
$objekt=toll->new;
$der_hash1=$objekt->wat_den_dat("name"=>"Ehmann","Vorname"=>"Andres","telefon"=>"03047301386");
$der_hash2=$objekt->wat_den_dat("Bolivien"=>"La Paz","Kolumbien"=>"Bogotá","Venezuela"=>"Caracas");
$objekt->hash_auslesen([$der_hash1,$der_hash2]);

Was passiert jetzt? Das Objekt hat nur einen einzigen Hash. Folglich überschreibt der zweite Aufruf die Werte des ersten.
$der_hash1 und $der_hash2 sind also identisch.
Wir erhalten also die Name/Werte Paare: Bolivien mit La Paz, Kolumbien mit Bogotá und Venezuela mit Caracas. Wie die Lösung aussieht, lässt sich nur durch eine genaue Analyse des CGI.pm Modul erreichen.
Um sich klar zu machen, wie dies funktioniert, reicht es, ein Programm zu schreiben, bei dem der Aufruf der Parameter auf die gleiche Art und Weise erfolgt:

package toll;

sub new
	{
  		 $zeiger={};
   		bless($zeiger);
	}

sub wat_den_dat
	{
		$nirvana=shift;
		my($zeigerle);
		$zeigerle={@_}; 

		push(@{$nirvana->{'-test'}},$zeigerle);
		$ende=$zeigerle;
	}

sub hash_auslesen
		{
		$nirvana=shift;
		%erdbeere=@_;
		($schluessel,$wert)=(each(%erdbeere));
		$werte=join(" ",@$wert);

			foreach $gurke(@{$nirvana->{$schluessel}})
			{
			$tomate=~s/\(/\(/g;
			$tomate=~s/\)/\)/g;

				if($werte=~m/$tomate/)
				{
   					  foreach(keys(%$gurke)) 
    					 {
         				   print "Der Schlüssel ist $_ und der Wert ist $$gurke{$_} \n";
     				}

		}

	}

}

$objekt=toll->new;
$der_hash1=$objekt->wat_den_dat("name"=>"Ehmann","Vorname"=>"Andres","telefon"=>"03047301386");
$der_hash2=$objekt->wat_den_dat("Bolivien"=>"La Paz","Kolumbien"=>"Bogotá","Venezuela"=>"Caracas");
$der_hash3=$objekt->wat_den_dat("Hemd"=>"Hose","Schuhe"=>"Socken","Kopf"=>"Name");
$objekt->hash_auslesen(-test=>[$der_hash1,$der_hash2,$der_hash3]);

$der_hash1=$objekt->wat_den_dat("name"=>"Ehmann","Vorname" =>"Andres","telefon"=>"03047301386");

Die Subroutine wat_den_dat weist dem Hash des Objektes $nirvana ein neues Name/Wert Paar zu. Der Wert hierbei ist -test und der Wert ist ein anonymous Array, der mit jedem Aufruf einen neuen Zeiger auf einen anonymous Hash bekommt.

Wir haben also folgende Struktur:

$nirvana

das berühmte referenzierte Dingsda, das weiß zu wem es gehört. (Ein anonymous Hash, der zum package toll gehört.)

$nirvana{-test}

ist ein Zeiger auf einen anonymous Array. [Zeiger auf den ersten Hash, Zeiger auf den zweiten Hash, Zeiger auf den dritten Hash]. Jedesmal, wenn wat_den_dat aufgerufen wird, wird ein Element hinzugefügt

$zeigerle

ist der Zeiger auf den ersten Hash, der Zeiger auf den zweiten Hash etc. (was in den anonymous hash, auf den $nirvana{-test} zeigt, eingefügt wird.) $nirvana{-test} sieht also nach 3maligem Aufruf so aus: [HASH(4235X455),HASH(344rf444),HASH(454444Xfo)], wobei der Inhalt der eckigen Klammern auch wieder über einen Zeiger auf einen anonyomous Array angesprochen wird.

Das Beispiel oben ist objektorientiert programmiert, da der Zeiger, der auf den anonymous Array zeigt, der die Zeiger auf die anonymous Hashes listet, vollständig objektorientiert angesprochen wird.
Daher die sind die HASH, die dann die Name/Werte Paare aufrufen, objektorientiert gekapselt. Das heißt, es können nicht nur beliebig viele Name/Werte Paare übergeben werden, sondern es können auch mehrere Objekte angelegt werden:

package toll;

sub new
	{
  		 $zeiger={};
   		bless($zeiger);
	}

sub wat_den_dat
	{
		$nirvana=shift;
		my($zeigerle);
		$zeigerle={@_}; 

		push(@{$nirvana->{'-test'}},$zeigerle);
		$ende=$zeigerle;
	}

sub hash_auslesen
		{
		$nirvana=shift;
		%erdbeere=@_;
		($schluessel,$wert)=(each(%erdbeere));
		$werte=join(" ",@$wert);

			foreach $gurke(@{$nirvana->{$schluessel}})
			{
			$tomate=~s/\(/\(/g;
			$tomate=~s/\)/\)/g;

				if($werte=~m/$tomate/)
				{
   					  foreach(keys(%$gurke)) 
      			    {
         			  print "Der Schlüssel ist $_ und der Wert ist $$gurke{$_} \n";
     				}

		}

	}

}

$objekt_a=toll->new;
$der_hash1=$objekt_a->wat_den_dat("name"=>"Coca Cola","Konsument"
=>"Andrew the tiger","Bedarf"=>"2 Liter");
$der_hash2=$objekt_a->wat_den_dat("name"=>"Kaffe","Konsument"
=>"Andrés Ehmann","Bedarf"=>"2 Liter");
$der_hash3=$objekt_a->wat_den_dat("name"=>"Schokolade","Konsument"
=>"Andrew the tiger","Bedarf"=>"1 kg");
$objekt_a->hash_auslesen(-test=>[$der_hash1,$der_hash2,$der_hash3]);

$objekt_b=toll->new;
$der_hash1=$objekt_b->wat_den_dat("name"=>"Ehmann","Vorname"
=>"Andres","telefon"=>"03047301386");
$der_hash2=$objekt_b->wat_den_dat("Bolivien"=>"La Paz","Kolumbien"
=>"Bogotá","Venezuela"=>"Caracas");
$der_hash3=$objekt_b->wat_den_dat("Hemd"=>"Hose","Schuhe"
=>"Socken","Kopf"=>"Nase");
$objekt_b->hash_auslesen(-test=>[$der_hash1,$der_hash2,$der_hash3]);

Wird das Programm ausgelöst, erscheinen alle Werte auf dem Schirm. Das heißt, die Hashs sind in den Objekten gekapselt.

Cookies einrichten

Einrichten kann man einen Cookie mit folgendem Perl Skript:

use CGI;

$mein_keks=new CGI;

$mein_hash = $mein_keks->cookie(-name=>'mein_user',
                             -value=>'Informationen über meinen User',
                             -expires=>'+1h',
 #                           -path=>'/cgi-bin',
                             -domain=>'.infos24.de',
                             -secure=>"");
    print $mein_keks->header(-cookie=>$mein_hash);

print "hallo";

Dieses Skript wird dann im cgi-bin Verzeichnis des HTTP Servers gespeichert, oder in einen anderen Ordner des HTTP Servers, der das Ausführen von Perl Skripten ermöglicht.
Der Aufruf erfolgt dann über http://www.meine-domain.de/cgi-bin/mein_skript.pl. Die Syntax ist identisch mit den Beispielen oben. Übergeben wird also ein anonymous Hash mit folgenden Werten:

name

irgendein Name ohne Leerzeichen

value

die eigentlichen Werte des Cookies, das, was abgespeichert erden soll

expires

eine Zeitangabe, wann der Cokie verfällt

path

zusätzlich zu der Domain, kann man auch noch einschränken, wo der Skript liegen soll, der den Cookie lesen oder überschreiben darf.

domain

die Domain, die den Cookie beschreibt. Beim Ausführen des Skriptes auf einem lokalen Rechner ergibt sich hier folgendes Problem. Angenommen man hat in die hosts Datei etwas eingetragen z. B. www.infos24.de, dann lässt sich der Cookie natürlich nicht mit http://127.0.0.1/cgi-bin/mein_skript.pl auslösen, weil dann ja die Domain, die den Cookie startet nicht identisch ist mit der Domain, die aufgerufen wird. In diesem Fall wird der Cookie nur eingerichtet, wenn man das Skript mit http://www.infos24.de/cgi-bin/mein_skript.pl aufruft.

Beim Aufruf der Funktion, die den Header produziert, werden die Werte, die gebraucht werden, um den Cookie zu generieren, gleich mitgeliefert. Beim Aufruf des Skriptes mit dem Explorer, erhält man eine Datei im Ordner c:\windows mit dem Namen:
Name_des_Rechners@Name_der_Domain[1].txt.
Die Datei enthält alle übergebenen Daten. Sonderzeichen werden, wie auch beim Query_String, in hexadezimal Schreibweise dargestellt.
Man beachte den Punkt vor infos24.de. Ohne den Punkt schreibt Netscape keine Cookies. Darüber hinaus werden sie von Netscape gepuffert. Tatsächlich geschrieben werden sie erst, wenn man den Browser schließt.
Netscape speichert die Cookies in einer Datei mit dem sinnvollen Namen cookies.txt (in ......./Netscape/users/default/cookies.txt ).
Das Beispiel von oben mit Netscape:

.infos24.de TRUE /   FALSE 1036947382 mein_user Informationen%20%FCber%20meinen%20User
Will man die Stelle zeigen, an der genau definiert wird, aus welchem Ordner das Skript stammen muss, damit der Cookie eingerichtet wird, dann ensteht:
.infos24.de TRUE / cgi-bin FALSE 1036948075 mein_user Informationen%20%FCber%20meinen%20User

.infos24

Domain

TRUE

keine Ahnung, was das soll?

/cgi-bin

Ordner, in dem das Skript sein muss, damit es funktioniert.

FALSE

das heißt, dass keine SSL Verbingung besteht, soll eine bestehen, dann muss secure="1" da stehen.

mein_User

ist sozusagen der Name des Cookies

Informationen%20%
FCber%20meinen%20User

der eigentliche Wert des Cookies

Was der Internet Explorer 6.0 produziert, sieht schon ein bisschen "wilder" aus. Es wurde mit Wordpad geöffnet:

mein_user
Informationen%20%FCber%20meinen%20User
infos24.de/
1025
2131054848
29526237
497793216
29526229
*

Wird das Skript ausgelöst und ein Verzeichnis angegeben, dann entsteht:

mein_user
Informationen%20%FCber%20meinen%20User
infos24.de/cgi-bin	
1024			
3221185664
29526241
1583424032
29526233
*

infos24.de/cgi-bin zeigt den Pfad zu dem Ordner, in dem sich das Skript befinden muss.
Die Datei heißt bei dieser Variante allerdings name_des_rechners@cgi-bin[1].txt
1024 ist zuständig für die SSL Verbindung.(1024 wenn vorhanden 1025 wenn nicht vorhanden.)

Cookies auslesen

Jetzt stellt sich noch die Frage, wie werden die Werte aus dem Cookie wieder ausgelesen?
Das veranschaulicht das folgende kleine Skript:

use CGI;

$mein_keks=new CGI;

$mein_hash = $mein_keks->cookie(-name=>'mein_user',
                             -value=>'Begriffen ? Die Cookies sieht man erst, wenn man die Seite nochmal lädt',
                             -expires=>'+24h',
                             -path=>'/cgi-bin',
                             -domain=>'.infos24.de',
                             -secure=>"");

print $mein_keks->header(-cookie=>$mein_hash);

$ergebnis = $mein_keks->cookie('mein_user');
print $ergebnis;
print "
Mach mal reload, sonst wird das nix";

Dieses Skript müsste schon bei einem einmaligen Aufruf den Cookie schreiben und ihn anschließend wieder auslesen. Tatsächlich funktioniert das aber nicht. Das geht den Browsern wohl zu schnell. Sie brauchen offensichtlich eine Weile, um den Cookie einzurichten.
Ruft man das Skript zum zweiten Mal auf, wird der Cookie ausgelesen. Bei Anwendungen wie Shops ist dies nicht sehr hilfreich, da zu jedem Produkt, das der User bestellt, eine ganze Reihe von Werten gehören, Preis, Menge, Produktname, Bestellnummer etc. Hier bedarf es einer komplexeren Möglichkeit, die Daten in einem Cookie abzuspeichern. Das ist mit dem CGI.pm Modul möglich. Hier kann als Wert ein vollständiger Hash abgespeichert werden. Das sieht dann so aus:

use CGI;

$mein_keks=new CGI;

$zeigerle={"Ehmann"=>"Andres","Maria"=>"Kanntstein"};

$mein_hash = $mein_keks->cookie(-name=>'mein_user',
                             -value=>$zeigerle,
                             -expires=>'+24h',
                             -path=>'/cgi-bin',
                             -domain=>'.infos24.de',
                             -secure=>"");

print $mein_keks->header(-cookie=>$mein_hash);

%ergebnis = $mein_keks->cookie('mein_user');

foreach $himbeere(keys(%ergebnis))
{
   print "Nachname: $himbeere , Vorname:$ergebnis{$himbeere} 
"; } print "
Mach mal reload, sonst wird das nix";

Ein Ansatz, mit dem sich auch komplexere Strukturen abspeichern lassen, sieht so aus:

use CGI;

$mein_keks=new CGI;

$zeigerle={"ISBN-453344"=>"Hanna Schygulla|Der Mann der aussah wie ein Seelöwe|Suhrkamp|16.80",
"ISBN-4484884"=>"Wladimir Putin|Helle Nächte|Diogenes|23.60"};

$mein_hash = $mein_keks->cookie(-name=>'mein_user',
                             -value=>$zeigerle,
                             -expires=>'+24h',
                             -path=>'/cgi-bin',
                             -domain=>'.infos24.de',
                             -secure=>"");

print $mein_keks->header(-cookie=>$mein_hash);

%ergebnis = $mein_keks->cookie('mein_user');

while(($isbn_nummer,$buch)=each(%ergebnis))
{
   ($Autor,$Titel,$Verlag,$Preis)=split(/\|/,$buch);
   print "ISBN-Nummer: $isbn_nummer , Autor:$Autor, Titel:$Titel, Verlag;$Verlag, Preis:$Preis 
"; } print "
Mach mal reload, sonst wird das nix";

Auf diese Art und Weise, könnte der Warenkorb in einem Cookie gehalten werden. Das Problem bei Shops ist aber komplizierter, da es ganz verschiedene Typen von Daten gibt. Notwendig sind hier alle Informationen zu den Produkten (ein homogen strukturierter Informationsblock) und die Daten, die den User betreffen, wie Name, Adresse, Telefon, Liefertermine etc.
In diesem Fall bietet es sich an, für diesen Informationsblock einen neuen Cookie anzulegen. Das sieht dann so aus:

use CGI qw/:standard/;

$mein_keks=new CGI;

$modul=param('modul');

if($modul == 1)
{
$zeigerle={"ISBN-453344"=>"Hanna Schygulla|Der Mann der aussah wie ein Seelöwe|Suhrkamp|16.80",
"ISBN-4484884"=>"Wladimir Putin|Helle Nächte|Diogenes|23.60"};

$mein_hash1= $mein_keks->cookie(-name=>'mein_user',
                             -value=>$zeigerle,
                             -expires=>'+24h',
                             -path=>'/cgi-bin',
                             -domain=>'.infos24.de',
                             -secure=>"");
$mein_hash2= $mein_keks->cookie(-name=>'mein_user2',
                             -value=>'it seems very hard to have just one girl, when there are a million in the world',
                             -expires=>'+24h',
                             -path=>'/cgi-bin',
                             -domain=>'.infos24.de',
                             -secure=>"");

print $mein_keks->header(-cookie=>[$mein_hash1,$mein_hash2]);
%ergebnis = $mein_keks->cookie('mein_user');

while(($isbn_nummer,$buch)=each(%ergebnis))
{
   ($Autor,$Titel,$Verlag,$Preis)=split(/\|/,$buch);
   print "ISBN-Nummer: $isbn_nummer , Autor:$Autor, Titel:$Titel, Verlag;$Verlag, Preis:$Preis 
"; } $ergebnis2 = $mein_keks->cookie('mein_user2'); print "$ergebnis2"; print "
Mach mal reload, sonst wird das nix"; } if ($modul == 2) { $zeigerle={"ISBN-11111"=>"Johannes Maria Schimmer|Und es flogen die Fetzen|Kiepenheuer und Witsch |32.80","ISBN-4484884"=>"Wladimir Putin|Helle Nächte|Diogenes|23.60"}; $mein_hash1= $mein_keks->cookie(-name=>'mein_user', -value=>$zeigerle, -expires=>'+24h', -path=>'/cgi-bin', -domain=>'.infos24.de', -secure=>""); print $mein_keks->header(-cookie=>$mein_hash1); $ergebnis2 = $mein_keks->cookie('mein_user2'); %ergebnis = $mein_keks->cookie('mein_user'); while(($isbn_nummer,$buch)=each(%ergebnis)) { ($Autor,$Titel,$Verlag,$Preis)=split(/\|/,$buch); print "ISBN-Nummer: $isbn_nummer , Autor:$Autor, Titel:$Titel, Verlag;$Verlag, Preis:$Preis
"; } $ergebnis2 = $mein_keks->cookie('mein_user2'); print "$ergebnis2"; print "$ergebnis2"; }

Das Skript besteht aus zwei Bereichen, die jeweils in einem Modul gekapselt sind.

Der erste Teil wird aufgerufen mit:
http://www.infos24.de/cgi-bin/mein_skript.pl?modul=1

Den zweiten Teil ruft man auf mit:
http://www.infos24.de/cgi-bin/mein_skript.pl?modul=2

In diesem zweiten Teil wird der "Warenkorb" geändert, das heißt, er wird vollkommen neu geschrieben. Die beiden Bücher mit der ISBN Nummer ISBN-453344 und ISBN-4484884 fliegen raus und werden durch das Buch mit der ISBN Nummer ISBN-11111 ersetzt. Man hätte auch, das erste Buch wieder übernehmen und nur das zweite ersetzen können. Der zweite Cookie (it seems very hard......) wird nicht ersetzt. Damit das funktioniert, muss nach dem Aufruf des jeweiligen Skriptbereiches noch mal "reloaded" werden.

persistente und temporäre Cookies anlegen

Es werden zwei Typen von Cookies unterschieden: Persistente und temporäre.
Persistente Cookies sind solange gültig, wie der Wert, der bei expires=>"der Wert" angegeben ist, noch nicht abgelaufen ist. Gibt es keinen Wert, oder ist die Zeile nicht vorhanden, dann ist der Cookie solange gültig bis der Browser geschlossen wird.
Das folgende kleine Programm verdeutlicht dies:

use CGI qw/:standard/;

$mein_keks=new CGI;

if(!defined ($id=$mein_keks->cookie('mein_user'))) 
{
$mein_hash1= $mein_keks->cookie(-name=>'mein_user',
                             -value=>'Wir sind nur Mund, wer singt das stille Herz, das heil in allen Dingen weilt, Rilke',
                             -expires=>'',
                             -path=>'/cgi-bin',
                             -domain=>'.infos24.de',
                             -secure=>"");
print $mein_keks->header(-cookie=>$mein_hash1);
print "Mach mal reload, sonst wird das nix 
"; } else { $ergebnis = $mein_keks->cookie('mein_user'); print $ergebnis; }

Wird dieses Programm zum ersten mal aufgerufen, ist kein Cookie vorhanden (vielleicht sollte man mal alle Cookies vorher löschen).
Die Zeile if(!defined ($id=$mein_keks->cookie('mein_user'))) gibt also true aus, wenn der Cookie nicht da ist, da der Wert der zurückgegeben wird durch das Ausrufezeichen negiert wird. Folglich erscheint bei erstmaligem Aufruf des Skriptes der Satz: "Mach mal reload, sonst wird das nix". Allerdings hat expires keinen Wert, so dass kein Cookie auf die Festplatte geschrieben wird. Wenn man jetzt reload macht, dann erscheint:"Wir sind nur Mund, wer singt das stille Herz, das heil in allen Dingen weilt, Rilke". Wird allerdings der Browser geschlossen und das Skript wieder geladen, erscheint: "Mach mal reload, sonst wird das nix". Der Cookie wurde nur temporär gespeichert, war also nur solange gültig, wie der Browser nicht geschlossen wurde.
Alle bislang diskutierten Probleme hätten auch anders, ohne Cookies gelöst werden können. Die einfachste Methode wäre gewesen, eine User Identifikation von Seite zu Seite mitzunehmen, über einen 

<input type=hidden name=user2 value=irgendwas>

Will man allerdings wissen, ob der User schon mal auf der Seite war, wie oft oder wann er zuletzt auf der Seite war, lässt sich nur mit dem Einsatz von Cookies ermitteln. Die einzige Alternative wäre hier, dass der User vor Betreten der Seite immer ein Password eingibt.
Ein Skript, das erfasst, ob der User schon mal auf der Seite war, wie oft und wann das letzte Mal, ist unten abgebildet:

use CGI qw/:standard/;

($sec,$min,$hour,$mday,$mon,$year,$wday,$ydat,$isdst)=localtime();
             $jahr=$year;
             $monat=$mon+1;
             $tag=$mday;
             $jahr=$year;
if (length($year) ==  2)
{
  $jahr="20$year";
}
if (length($year) == 3)
{
  $jahr="2$year"-100;
}
if (length($monat) == 1)
{
    $monat="0$monat";
}
if(length($tag) == 1)
{
   $tag="0$tag";
}
if(length($hour) == 1)
{
   $hour="0$hour";
}
if(length($min) == 1)
{
   $min="0$min";
}
if(length($sec) == 1)
{
   $sec="0$sec";
}

$datum=$tag.".".$monat.".".$jahr;
$zeit=$hour.":".$min.":".$sec;

$mein_keks=new CGI;

$ergebnis_alt = $mein_keks->cookie(-name=>'mein_user');
$ergebnis2_alt = $mein_keks->cookie(-name=>'mein_user2');

$wie_oft=$ergebnis_alt+1;


$mein_hash1= $mein_keks->cookie(-name=>'mein_user',
                             -value=>"$wie_oft",
                             -expires=>'+5y',
                             -path=>'',
                             -domain=>'.infos24.de',
                             -secure=>"");

$mein_hash2= $mein_keks->cookie(-name=>'mein_user2',
                             -value=>"$datum um  $zeit",
                             -expires=>'+5y',
                             -path=>'',
                             -domain=>'.infos24.de',
                             -secure=>"");

print $mein_keks->header(-cookie=>[$mein_hash1,$mein_hash2]);

if($ergebnis_alt ne "")
{
print "Du warst bis jetzt  insgesamt $ergebnis_alt hier 
"; print "Das letzte Mal am $ergebnis2_alt "; } else { print " Du warst noch nie da. Mach mal reload "; }
Dateien auf einem Fremdrechner bearbeiten

Es gibt aber auch Probleme, die ohne das CGI.pm Modul, zumindest wenn mit Perl programmiert wird, kaum lösbar sind. Zu dieser Gruppe von Problemen gehört auch das Verarbeiten einer Datei, die auf einen Fremdrechner hochgeladen wird und zwar über:

<input type=file name=datei2>

.

Das HTML Formular, mit dem dies gestartet wird, sieht so aus:
<html>
<head>
<title> Bild upload direkt aus dem Browser </title>
</head>
<form action=http://127.0.0.1/cgi-bin/upload2.pl
enctype=multipart/form-data method=post>
W&auml;hlen Sie eine Datei
<input type=file name=datei>
<input type=submit value=hochladen>
</form>
</body>

Dieses Formular produziert keinen Query_String vom Typ?name1=wert1&name2=wert2, sondern etwas wesentlich komplizierteres, was ja auch klar ist, da zu einer Datei wesentlich mehr Informationen gehören, als zu einer simplen Zeichenkette. Notwendig ist der eigentliche Inhalt der Datei.
Wer sich den Query_String anschauen will, den das Formular oben produziert, der braucht ein Skript in dieser Art:

#!/usr/local/bin/perl
read (STDIN,$frage,$ENV{'CONTENT_LENGTH'});
print $frage;

Auf dem Schirm erscheint:

-----------------------------
7d235c36c0
Content-Disposition: form-data; name="datei";
filename="C:\Eigene Dateien\Eigene Bilder\bildung\bkein.jpg"
Content-Type: image/pjpeg
>die bits und byte die das Bild sind in Hyroglyphen Form<

Wir sehen, dass dies nicht mehr das Format ist, dass wir aus der Diskussion Formulareingaben auswerten kennen und das wir es auch nicht so auswerten können, wie wir das in Perl Routine zum Auslesen des QUERY_STRING tun.
Will man das Bild an den Fremdrechner übertragen und dort speichern, brauchen wir ein Skript, das so aussieht:

#!/usr/local/bin/perl
use CGI qw/:standard/;
print "Content-type:text/html\n\n";
$wurz="../perltest/bilder";
$bild=param('datei');
if ($bild ne / /)
{
$bild=~m!^.*\\(.*)!;
open(bildchen, ">$wurz/$1");
binmode(bildchen);
print bildchen <$bild> ;
close($bildchen);
}
print " <html><head><title>Feedback</title></head><body>
Das Bild das Du hochgeladen hast sieht so aus <br>
<img src=http://www.netzinfos.de/perltest/bilder/$datei1><br>
Das Bild wurde hochgeladen und wird jetzt &uuml;ber einen Hyperlink aufgerufen.
</body></html>";

Damit das funktioniert, braucht "form" das Attribut enctype=mulitpart/form-data. Die method muss post sein.
Wie oben, in der Darstellung des Query_String, deutlich sichtbar, wird der gesamte Pfad des Bildes übertragen (filename="C:\Eigene Dateien\Eigene Bilder\bildung\bkein.jpg"). Wir wollen nur den eigentlichen Namen des Bildes, also bkein.jpg. Folglich schneiden wir uns mit einer regular expression, siehe regular expressions , den Namen des Bildes aus.
Bei der Anwendung des CGI.pm Moduls liegt der eigentliche Inhalt des Bildes in der Variablen $bild vor, in Verbindung mit dem diamond operator (<$bild>). (die Bits und Bytes, die tatsächlich das Bild darstellen.)
Diesen kann man dann auf die Platte drucken. Vorher muss nicht in den binary mode gewechselt werden.

Das zweite Problem, das einen gewissen Aufwand darstellt, entsteht, wenn die Form Elemente beinhaltet, die alle den gleichen Namen haben. Dies kommt oft im Zusammenhang mit Checkboxen vor. Mit dem CGI.pm Modul ist es kein Problem, mehrere Variablen mit einem Namen im Formular abzuspeichern. Man speichert die Werte einfach in einem Array:
@banane=param('banane');

Für ein grundsätzliches Verständnis des CGI.pm Modul und seiner Möglichkeiten sollte das erst mal reichen. Mehr Informationen zum CGI.pm Modul finden sich in den Tutorials von Activestate.

vorhergehendes Kapitel