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:
<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.....".
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>
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 ? ";
print $x->checkbox_group(-name=>leben,-values=>[super,phantastisch,irre]);
print " ";
print "Sie können hier was reinschreiben ";
print $x->textfield(-name=>'beitrag');
print " ";
print "Sind Sie männlich oder weiblich ? ";
print $x->radio_group(-name=>geschlecht,-value=>['männlich','weiblich']);
print " ";
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 ";
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{$_} ";
}
}
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.
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:
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:
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.
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:
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]);
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.
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:
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.)
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.
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 ";
}
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ä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:
-----------------------------
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 ü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.