Hacker mögen Sport (Linux-Magazin, Februar 2001)

Mit HTML::Mason entstehen hochperformante dynamische Webseiten einfach durch in HTML eingebettetes Perl.

Auf dem Netscape-Campus in Mountain View wird nicht nur hart gearbeitet, sondern auch viel Sport getrieben. Es gibt Basketball-Courts, Beach-Volleyballfelder und eine Rollerhockey-Anlage. In den Gebäuden sind Pool-Billiard und Kicker (amerikanisch: ``Foosball'') Standard. Neulich kam in unserer Abteilung eine Tischtennisplatte hinzu und eine neue Sportmodewelle nahm ihren Lauf.

So kam mir die Idee, schnell eine Online-Rangliste zu implementieren. Nach bestimmten Regeln sollten niedriger eingestufte Leute höher rangierende herausfordern, und, falls der Herausforderer gewänne, mit dem Verlierer den Platz in der Rangliste tauschen. Ein CGI sollte es jedem erlauben, Listenplätze zu verändern und neue Mitspieler am Ende der Liste einzufügen.

Da meine künstlerischen Fähigkeiten sich in Grenzen halten, wollte ich mit vorbehalten, vielleicht später die Grafikabteilung um ein nettes Layout zu bitten. Reines CGI kam also nicht in Frage, da die Damen und Herren Künstler mit Perl nichts anzufangen wissen.

Nun gibt es mehrere Möglichkeiten, Perl in HTML einzubetten und so dynamische Abläufe in Webseiten zu steuern, Gerald Richters HTML::Embperl zum Beispiel. So können Grafiker wie gewohnt HTML-Code editieren, der versteckten Perl-Code enthält. Seit neuestem geistert ein neues derartiges System durch die Gegend: HTML::Mason.

Was ist HTML::Mason?

HTML::Mason ist ein Perl-Modul von Jonathan Swartz, das einen mit mod_perl beschleunigten Apache-Server dazu überredet, sogenannte Mason-Komponenten zu verarbeiten -- in HTML eingebettetes Perl.

Diese Komponenten dürfen wiederum weitere Komponenten hinzuziehen und Parameter an sie übergeben. Besonders gekennzeichnete Initialisierungsbereiche durchläuft HTML::Mason nur einmal und nicht bei jedem Aufruf, sogenannte Autohandler schnappen sich alle Seiten eines Verzeichnisses -- kurzum, ein äußerst mächtiges System zur Steuerung dynamisch generierter Webseiten.

Statt nun beispielsweise eine statische HTML-Seite zu erzeugen, deren Submit-Knopf einen in Perl geschriebenen und als CGI implementieren Formular-Handler aufruft, kann man mit HTML::Mason Formularerzeugung und -verarbeitung in einer Komponente verbinden.

Liegen so beispielsweise keine Eingabeparameter vor, stellt die Komponente ein Eingabeformular vor, dessen Submit-Knopf wiederum zurück auf die Komponente zeigt. Füllt der Benutzer die Formularfelder aus, wirft die Komponente den Code zur Formularverarbeitung an und gibt vielleicht eine weitere Komponente als Antwort zurück. Diese Vorgänge spielen sich alle in Perl-erweitertem HTML ab. Intelligentes Caching und ein permanent aktiver Perl-Interpreter beschleunigen die Abarbeitung dieser Komponenten dramatisch, bei Seiten mittlerer Komplexität ist kaum ein Unterschied zu statischen Seiten feststellbar.

Wie soll nun die Pingpongliste funktionieren? Ruft der Benutzer die Seite pingpong.html auf, kommt die aktuelle Tabelle nach Abbildung 1 hoch.

Abbildung 1: Die Hauptseite zur Anzeige der Liste.

Klickt man auf den Knopf ``Edit Table'', erscheint, wie in Abbildung 2 dargestellt, eine Eingabemaske zur Manipulation der Tabelle. Jeder Tabellenplatz ist mit einer Checkbox hinterlegt. Wählt der Benutzer so zwei Plätze an und drückt den Knopf ``Switch Selected Entries'', tauscht die Komponente beide Plätze und gibt wiederum die editierbare Tabelle zurück. Füllt der Benutzer andererseits die Eingabebox weiter unten mit einem neuen Spielernamen und drückt den Knopf ``Add Name'', fügt die Komponente den neuen Namen unten in die Tabelle ein. Ein Mausklick auf den Knopf ``Back to List'' hingegen lässt die Komponente wieder zurück zur ursprünglichen Anzeige nach Abbildung 1 springen, die selbstverständlich auch die durchgeführten Änderungen reflektiert.

Abbildung 2: Die Seite zum Editieren der Liste.

Die Logik dieser drei Komponenten steht in den Listings pingpong.html, display.html und edit.html.

Listing pingpong.html zeigt die Hauptkomponente, die die Logik des Ablaufs implementiert. Die mit <%args>...</%args> ausgezeichnete erste Sektion in pingpong.html definiert die Parameter, die die Komponente entgegennimmt. Ruft der Webserver die Komponente auf, stehen dort die vom Benutzer nach der GET oder der POST-Methode gesetzten CGI-Parameter zur Verfügung. Voraussetzung hierfür ist allerdings, dass in der <%args>-Sektion eine gleichnamige Variable definiert wurde. Nach einem =>-Pfeil steht dort neben jedem Parameter auch noch ein Default-Wert, auf den die Variable gesetzt wird, falls kein entsprechender Eingabeparameter vorliegt.

Ruft also beispielsweise ein Browser den URL

    http://server/mason/\
        pingpong.html?edit=1

auf, erhält der CGI-Parameter edit nach der GET-Methode den Wert 1 und HTML::Mason setzt wegen der ersten Zeile der <%args>-Sektion den Wert der Variablen $edit auf 1. Verlangt der Browser hingegen schlicht nach

    http://server/mason/pingpong.html

ist die CGI-Variable edit nicht gesetzt und dementsprechend steht $edit für den Rest der Komponente auf dem in der <%args>-Sektion gesetzten Defaultwert 0 .

Perl einbetten

HTML::Mason bettet Perl auf verschiedene Arten in HTML ein:

(1)
Zwischen <%...%> stehender Perl-Code wird ausgeführt und der Ausdruck durch das Ergebnis des Perl-Codes ersetzt (<% $edit %> liefert beispielsweise den Wert der Variablen $edit ins HTML der Seite zurück).

(2)
Zwischen <%perl>...</%perl> stehender Perl-Code wird bei jedem Aufruf der Komponente ausgeführt und der Rückgabewert ignoriert.

(3)
Zwischen <%once>...</%once> stehender Perl-Code wird genau einmal ausgeführt, wenn nämlich der Apache die Komponente lädt -- und dann nie wieder, obwohl alles weiterhin im Speicher residiert. So bleiben etwa definierte Konstantenwerte oder Funktionen erhalten.

(4)
Statt Perl-Code zwischen <%perl>...</%perl> einzubetten, kann man auch an den Anfang (ohne Leerzeichen!) jeder Perl-Zeile ein %-Zeichen schreiben.

Listing 1: pingpong.html

    01 <%args>
    02 $edit     => 0
    03 $view     => 0
    04 $switch   => 0
    05 $userlist => []
    06 </%args>
    07 
    08 <HTML>
    09 
    10 <HEAD> <TITLE> <% $TITLE %> </TITLE> </HEAD>
    11 <BODY BGCOLOR="<% $BGCOLOR %>">
    12 
    13 <CENTER>
    14 
    15 <H1><FONT FACE=ARIAL> <% $TITLE %> </FONT></H1>
    16 
    17 <%perl>
    18 my @users = users_read(); 
    19 if($edit and !$view) {
    20   $m->comp("/edit.html", 
    21            users => \@users, %ARGS);
    22 } else {
    23   $m->comp("/display.html", users => \@users);
    24 }
    25 close DATA;
    26 </%perl>
    27 
    28 </CENTER>
    29 </BODY>
    30 </HTML>
    31 
    32 <%once>
    33 my $BGCOLOR   = "#ddddff";
    34 my $TITLE     = 'Ping Pong Ranking List';
    35 my $DATA_FILE = '/home/mschilli/DEV/ix/68/eg/tt.dat';
    36 
    37 ##################################################
    38 sub users_read {
    39 ##################################################
    40 
    41     use Fcntl qw(:DEFAULT :flock);
    42 
    43         # Read in data file
    44     sysopen(DATA, $DATA_FILE, O_RDWR | O_CREAT) or 
    45         die "Cannot open $DATA_FILE: $!";
    46  
    47         # Lock it. Move back to beginning
    48     flock(DATA, LOCK_EX);
    49     seek(DATA, 0, 0);
    50 
    51         # Read out existing records
    52     my @users = <DATA>;
    53     
    54     return @users;
    55 }
    56 </%once>

Zeile 10 in pingpong.html übernimmt beispielsweise den Wert einer Variablen $TITLE nach Strategie (1) in den HTML-Code. $TITLE selbst wurde nach Strategie (3) in Zeile 34 festgesetzt. Da <%once>-Sektionen vor allen anderen ausgeführt werden, ist dies zulässig. So wird aus

    <HEAD> <TITLE> <% $TITLE %> 
           </TITLE> </HEAD>

schnell

    <HEAD> <TITLE> Ping Pong 
     Ranking List </TITLE> </HEAD>

Übrigens gelten überall in HTML::Mason die strengen Anforderungen von use strict -- keine undeklarierten Variablen, weiche Referenzen oder Barewords sind erlaubt.

Die <%once>-Sektion ab Zeile 32 in pingpong.html definiert außer einigen Variablen auch noch eine Funktion users_read(), die unsere Tabellendatei ausliest. Deren Format ist einfach ein Spieler pro Zeile und nachdem alle Zeilen in @users eingelesen wurden, gibt users_read() dessen Elemente als Liste zurück. Findet pingpong.html die Datei nicht vor, legt sie eine neue an.

Dieser Luxus erfordert überlegtes Handeln, um das Programm gegen sogenannte Race-Conditions zu schützen: Mit einem normalen Dateitest, einem anschließenden open und nachfolgendem flock wäre es nicht getan. Da der Webserver Anfragen quasi gleichzeitig abarbeitet, könnten sich verschiedene Instanzen des Skripts zwischen den Einzelanweisungen gegenseitig in die Quere kommen und Datensalat erzeugen.

Die Logik zwischen den Zeilen 44 und 49 ist hingegen narrensicher: Der sysopen-Befehl kann eine Datei gleichzeitig zum Lesen und Schreiben öffnen und sie auch noch erzeugen, falls sie noch nicht existiert -- und das ganze atomar, also ohne dass jemand dazwischenfunken kann. Das normale open könnte das nicht. Die Konstanten O_RDWR und O_CREAT definiert das Modul Fcntl, das Zeile 41 hereinzieht. Zeile 48 setzt einen exklusiven Lock auf die Datei und 49 fährt zurück zum Anfang, falls jemand mit der Datei jongliert hat, bevor der Lock den Daumen draufhielt.

Aufgabe von pingpong.html ist es, die aktuelle Spieler-Datei einzulesen (Zeile 18) und anschließend zur Anzeigekomponente display.html oder zur Editierkomponente edit.html zu verzweigen, je nachdem, ob die CGI-Parameter edit oder view gesetzt sind.

Am Ende schließt pingpong.html in Zeile 25 die mit DATA verknüpfte Datei wieder. Dieses Datei-Handle nutzt die aufgerufene Komponente edit.html weiter unten, um eventuell Manipulationen an der Datei und damit der persistenten Tabelle vorzunehmen.

Kinder von Komponenten rufen

In Perl-Sektionen erfolgt der Aufruf anderer Komponenten über die comp-Methode des Mason-Objekts, dessen Referenz immer in $m vorliegt. Bekommt die Komponente außerdem auch noch eine Reihe von Parametern mit, werden diese einfach als Name/Value-Paare angehängt:

    $m->comp("/edit.html", 
             "users" => \@users, 
             %ARGS);

ruft edit.html auf und gibt unter dem Parameternamen users eine Referenz auf den @users-Array mit. Ausserdem soll auch edit.html alle Eingangs-Parameter von pingpong.html mitbekommen -- im Spezial-Hash %ARGS sind alle versammelt. Auch außerhalb einer Perl-Sektion kann eine Mason-Komponente übrigens eine Unterkomponente aufrufen:

    <& /edit.html, 
       users => \@users, %ARGS &>

lautet die Syntax für den oben beschriebenen Aufruf aus regulärem HTML heraus.

Listing display.html zeigt die Komponente, die pingpong.html aufruft, falls die Spielertabelle erscheinen soll. Als Parameter übergibt pingpong.html eine Referenz auf die Spielerliste @users, die display.html in der Argumentsektion entgegennimmt.

Einzelwerte und Listen übergeben

Listen an Komponenten zu übergeben funktioniert in Mason übrigens nicht nur mit Aufrufen an Unterkomponenten -- auch CGI-Parameter können nicht nur als Einzelwerte, sondern auch als Listen daherkommen. Dies ist der Fall, falls der Browser einen Eingabeparameter mehrfach setzt:

    http://server/mason/\
        pingpong.html?p=1&p=2

Hier stehen in Mason etwa nach

    <%args>
    $p => []
    @p => ()
    </%args>

in @p die Werte (1,2) und $p enthält [1,2]. Mit [] (Referenz auf leere Liste) und () (leere Liste) führen die Variablen auch dann sinnvolle Werte, falls die Übergabe nicht klappt. Ohne Defaultwerte besteht Mason auf den Parametern und löst einen Fehler aus, falls der Browser sie nicht liefert.

Abbildung 3 zeigt, was passiert, wenn der Browser display.html testhalber mit folgendem URL aufruft:

    http://localhost/mason/display.html\
        ?users=Hugo&users=Bernie

Ruckzuck steht dann $users auf ["Hugo", "Bernie"] und display.html formt eine Tabelle daraus.

Abbildung 3: display.html testhalber aufgerufen

Die wechselnden Farben in den Tabellenzeilen nach Abbildung 1 erzeugt display.html über den in Zeile 6 definierten Array @COLORS, in den Zeile 13 mit einem alternierenden Index $i hineingreift.

Zwischen den Zeilen 11 und 22 befindet sich eine foreach-Schleife, die als Körper sowohl Perl-Code als auch reguläres HTML mit wiederum eingebautem Perl-Code enthält -- Alltag in Mason.

Listing 2: display.html

    01 <%args>
    02 $users => []
    03 </%args>
    04 
    05 <%perl>
    06    my @COLORS = ("#eeeeff", "#ffffff");
    07    my $i      = 0;
    08 </%perl>
    09 
    10 <TABLE>
    11 %   foreach my $user (@$users) {
    12 %       $i++;
    13 %       my $color = $COLORS[$i % 2];
    14 
    15         <TR BGCOLOR="<% $color %>">
    16         <TD> <FONT FACE=ARIAL SIZE=+2> 
    17              <B> <% $i %>. </B> </FONT>
    18         <TD> <FONT FACE=ARIAL SIZE=+2> 
    19              <B> <% $user %> </B> </FONT>
    20         </TR>
    21 
    22 %   }
    23 </TABLE>
    24 
    25 <FORM METHOD="POST">
    26 <FONT FACE=ARIAL>
    27 <INPUT TYPE=SUBMIT NAME=edit VALUE="Edit Table">
    28 </FONT>
    29 </FORM>

display.html zeigt ab Zeile 25 ein Formular, dessen Submit-Knopf zur editierbaren Version der Tabelle verzweigt. Das FORM-Tag setzt als METHOD-Attribut POST, gibt aber keine ACTION an -- also wird der Browser nach dem Drücken des Submit-Knopfes nach pingpong.html zurückspringen und dort die CGI-Variable edit nach der POST-Methode auf 1 setzen. Übrigens erscheint der URL zu display.html bei aktivem pingpong.html niemals im Browser -- es handelt sich lediglich um eine Komponente, die pingpong.html bei Bedarf ansaugt.

Editieren geht über Studieren

Listing edit.html zeigt die Komponente, die das editierbare Formular ausgibt. Sie erhält als Parameter nicht nur eine Referenz auf den Spielerarray ($user), sondern auch die Werte von $switch und $new, die anzeigen, ob der Benutzer bei einem vorhergehenden Aufruf von edit.html Spielerränge vertauschen oder neue Spieler einfügen wollte.

Im ersten Fall steht in $switchlist eine Referenz auf einen Array, der die beiden Indexpositionen der zu vertauschenden Tabellenplätze enthält. Im zweiten Fall steht in $newname der Name des einzufügenden Spielers. Die Werte dieser Parameter steuert das weiter unten definierte HTML-Formular. Die verschiedenen Submit-Knöpfe setzen die Parameter $new bzw. $switch.

Der Perl-Code zwischen den Zeilen 12 und 31 manipuliert das Array, auf das $users zeigt und schreibt es zurück in die noch mit DATA geöffnete Tabellendatei. Hierzu fährt seek an den Dateianfang zurück, dann löscht truncate den bestehenden Inhalt und print schreibt neue Daten hinein. Warum der Aufwand? Auf DATA steht noch ein flock, um bei parallelen Zugriffen keinen Datensalat zu generieren. Um den flock zu behalten, darf mit DATA zwischen dem Lesen und Wieder-Beschreiben kein close() erfolgen.

Listing 3: edit.html

    01 <%args>
    02 $users      => []
    03 $switch     => 0
    04 $switchlist => []
    05 $new        => ""
    06 $newname    => ""
    07 </%args>
    08 
    09 <FORM METHOD="POST">
    10 <INPUT TYPE=HIDDEN NAME=edit VALUE=1>
    11 
    12 <%perl>
    13 ##################################################
    14 # Data manipulation
    15 ##################################################
    16     # Switch ranks if requested
    17 if($switch) {
    18     my($from, $to) = @$switchlist;
    19     ($users->[$from], $users->[$to]) = 
    20         ($users->[$to], $users->[$from]);
    21 }
    22     # Add new user if requested
    23 if($new) {
    24     push(@$users, $newname);
    25 }
    26     # Daten zurückschreiben
    27 seek DATA, 0, 0;
    28 truncate DATA, 0;
    29 print DATA join("\n", @$users);
    30 ##################################################
    31 </%perl>
    32 
    33 <TABLE>
    34 
    35 % ################################################
    36 % # Display Edit Table
    37 % ################################################
    38 % my $count = 0;
    39 % foreach my $user (@$users) {
    40 %   $count++;
    41 
    42     <TR><TD>
    43     <FONT FACE=ARIAL> <% $count %>. </FONT>
    44     </TD><TD>
    45     <INPUT TYPE="checkbox" NAME="switchlist" 
    46                            VALUE="<% $count-1 %>">
    47     <FONT FACE=ARIAL> <B> <% $user %> </B> </FONT>
    48     </TD></TR>
    49     </FONT>
    50 
    51 % }
    52 
    53 </TABLE>
    54 
    55 <FONT FACE=ARIAL>
    56 <INPUT TYPE="SUBMIT" NAME=switch 
    57        VALUE="Switch Selected Entries">
    58 
    59 <HR>
    60 <INPUT TYPE="TEXT"   NAME=newname VALUE="">
    61 <INPUT TYPE="SUBMIT" NAME=new VALUE="Add Name">
    62 
    63 <HR>
    64 <INPUT TYPE="SUBMIT" NAME=view 
    65                      VALUE="Back to List">
    66 </FONT>
    67 
    68 </FORM>

Zwischen Zeile 35 und 51 stellt edit.html die Tabelle mit eingebauten Checkbox-Knöpfen dar, die alle switchlist heissen und als Werte die Indexpositionen 0 bis @$users - 1 aufweisen. Klickt der Benutzer zwei davon an und drückt den ``Switch Selected Entries''-Knopf, geht der Browser zurück nach pingpong.html, welches wegen des in Zeile 10 von edit.html gesetzten edit-Parameters wieder edit.html hereinholt. $switchlist zeigt dann auf ein Array, das als Elemente die beiden Indexpositionen von @$users enthält, die es zu vertauschen gilt. Die Zeilen 19 und 20 tun genau dies.

Ist hingegen $new gesetzt, will der Benutzer einen neuen Spieler einfügen, dessen Name in $newname steht. Zeile 24 schiebt ihn ans Ende der Tabelle.

Drückt der Benutzer hingegen den Knopf ``Back to List'', setzt das Formular in Zeile 64 von edit.html den CGI-Parameter view und das kurz darauf vom Browser kontaktierte pingpong.html zeigt wegen seiner Zeile 19 trotz gesetztem edit wieder die nicht-editierbare Tabelle an.

Installation

HTML::Mason läuft üblicherweise in einem mit mod_perl-beschleunigten Apache-Server. Wer hierzu zu faul ist, lese sich den nächsten Abschnitt ``Installation für Faule'' durch. Aber mod_perl ist schnell installiert, hierzu holt man es sich unter

    http://perl.apache.org/dist/\
        mod_perl-1.24_01.tar.gz

ab (nicht die Version 1.24 vom CPAN, die enthält nämlich einen Fehler), den Apache 1.3.14 von www.apache.org und entpackt beide:

    gzip -dc apache_1.3.14.tar.gz \
        | tar xfv -
    gzip -dc mod_perl-1.24_01.tar.gz \
        | tar xfv -

Man sollte sich überlegen, wo der Apache landen soll, wir nehmen einfach einmal /www/apache an. Dort legen wir ein zusätzliches mason-Verzeichnis an, mit einem comp- und einem data-Unterverzeichnis:

    mkdir /www/apache/mason
    mkdir /www/apache/mason/comp
    mkdir /www/apache/mason/data
    chown nobody /www/apache/mason/data

Das data-Verzeichnis muss vom Benutzer des Webservers beschreibbar sein, üblicherweise nobody. Dann wechselt man ins mod_perl-Verzeichnis und konfiguriert sowohl mod_perl als auch den Apache auf einen Rutsch. Soll der Apache nach /www/apache, geht das so:

    cd mod_perl-1.24_01
    perl Makefile.PL \
           APACHE_PREFIX=/www/apache \
           DO_HTTPD=1 \
           USE_APACI=1 \
           EVERYTHING=1
    make
    make install

Dies konfiguriert, compiliert, linkt und installiert sowohl mod_perl als auch den Apache. make install erfordert die notwendigen Benutzerrechte zum Beschreiben der Perl-Installation und der Webserver-Verzeichnisse. In die Datei conf/httpd.conf der Apache-Installation (im Beispiel unter /www/apache/conf/http.conf) muss dann noch folgende Sequenz:

    # Additions to your httpd.conf
    PerlRequire \
        /www/apache/mason/handler.pl
    Alias /mason /www/apache/mason/comp
    <Location /mason>
        SetHandler perl-script
        PerlHandler HTML::Mason
    </Location>

Nun kommt HTML::Mason an die Reihe. Hierzu eignet sich am besten die CPAN-Shell:

    perl -MCPAN -eshell
    cpan> install MLDBM
    cpan> install HTML::Mason

HTML::Mason setzt MLDBM voraus, was der obige Aufruf gleich mitinstalliert. Die HTML::Mason-Distribution enthält noch einen Handler, den der Apache braucht, deswegen kopieren wir ihn von dort ins Webserververzeichnis:

    cd ~/.cpan/build/HTML::Mason
    cp eg/handler.pl \
        /www/apache/mason/handler.pl

Das Verzeichnis hierfür ist beliebig wählbar, muss aber dem vorher in httpd.conf gesetzten entsprechen.

Angepasst wird der Initialisierungshandler in /www/apache/mason/handler.pl hernach, indem mit einem Editor die beiden dort enthaltenen Platzhalter <component root> und <data directory> auf die vorher angelegte Mason-Dokumentwurzel umgebogen werden, also beispielsweise /www/apache/mason/comp und /www/apache/mason/data.

Anschließend wird der Apache mit

    /www/apache/bin/apachectl start

hochgefahren. In der Standardeinstellung lauscht er auf Port 8080, wer auf dem Standardport 80 fahren will, muss dies in conf/httpd.conf unter Port einstellen (und ihn anschließend unter root hochfahren).

Anschließend müssen die drei Skripts pingpong.html, display.html und edit.html nach /www/apache/mason/comp wandern. Die in Zeile 35 in pingpong.html eingestellte Datei (im Beispiel tt.dat) muss vom Benutzer des Webservers (nobody) beschreibbar sein. Der Pingpong-Administrator darf sie übrigens auch manuell mit einem Editor verändern, um Funktionen auszuführen, die das Browser-Interface nicht anbietet, wie zum Beispiel das Löschen von Spielern aus der Tabelle.

Stellt man dann den Browser auf

    http://localhost:8080/\
        mason/pingpong.html

ein (falls als Port 80 gewählt wurde, darf die Portangabe entfallen), sollte sich eine erste Tabelle gemäß des Inhalts der Spielerdatei tt.dat zeigen.

Installation für Faule

Wer den ganzen Aufwand mit mod_perl scheut und nur mit HTML::Mason herumspielen will, kann ein CGI-Skript nach Listing ttm.pl nutzen und den Browser darauf zeigen:

    http://localhost/cgi-bin/ttm.pl

So läuft die Pingpong-Tabelle zwar langsam aber unabhängig vom verwendeten Webserver. Spielt fleißig Pingpong!

Listing 4: ttm.pl

    01 #!/usr/bin/perl -w
    02 
    03 my $ROOT      = "/www/apache/mason";
    04 my $COMP_PATH = "$ROOT/comp";
    05 my $DOC_PATH  = "$ROOT/data";
    06 
    07 use CGI qw(:all);
    08 use HTML::Mason;
    09 
    10 print header();
    11 my $outbuf;
    12 my $parser = HTML::Mason::Parser->new();
    13 my $interp = HTML::Mason::Interp->new( 
    14                  parser     => $parser,
    15                  comp_root  => $COMP_PATH,
    16                  data_dir   => $DOC_PATH,
    17                  out_method => \$outbuf );
    18 
    19 %params = CGI::Vars();
    20 
    21 # Multi-Werte in Arrays transformieren
    22 foreach $param (keys %params) {
    23     my @values = split /\0/, $params{$param};
    24     if(@values > 1) {
    25         $params{$param} = \@values;
    26     }
    27 }
    28 
    29 my $retval = $interp->exec("/pingpong.html", %params);
    30 
    31 print $outbuf;

Referenzen

[1]
``Building Sites with Mason'', Reuven M. Lerner, Linux-Journal 06/00, http://www2.linuxjournal.com/cgi-bin/frames.pl/index.html

[2]
HTML::Mason Home Page, http://masonhq.com

Michael Schilli

arbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com.