SELFHTML

CGI-typische Aufgaben in Perl

Informationsseite

nach unten CGI-typische Lösungen in Perl
nach unten Counter (Zugriffszähler)
nach unten Form-Mailer
nach unten Gästebuch
nach unten Datenbank-Frontend

 nach unten 

CGI-typische Lösungen in Perl

Perl ist anders als etwa Seite PHP oder Seite ASP nicht speziell für Web-Anwendungen konzipiert, sondern eine offene Programmiersprache für scriptbasierte Lösungen aller Art. Es hat jedoch Eigenschaften, die es als Sprache für CGI-Scripts qualifizieren: dazu gehören die mächtigen Funktionen für Zeichenkettenverarbeitung und Datei-Handling, aber auch die vielen Unix-spezifischen Funktionen, von denen auch in Perl geschriebene CGI-Scripts, die auf typischen Web-Server-Umgebungen wie Linux und Apache zum Einsatz kommen, profitieren können. Durch das Modulkonzept von Perl gibt es mittlerweile außerdem Module, die sich speziell für die Verwendung in CGI-Scripts anbieten - allen voran das Seite CGI-Modul, das bei jeder Standard-Installation von Perl zur Verfügung steht. Mit den Möglichkeiten dieses Moduls sollten Sie sich auf jeden Fall näher befassen, wenn Sie CGI-Scripts schreiben.

Wenn Sie noch unsicher sind in Perl und sich nicht in der Lage sehen, eine CGI-Anwendung von Grund auf nach eigenen Vorstellungen zu programmieren, dann können Sie auf zahlreiche Scripts zurückgreifen, die im Web verfügbar sind. Es gibt viele Anbieter, die Freeware-Scripts oder Shareware-Scripts anbieten. Um ein solches Script auf Ihrem Server oder in Ihrer lokalen HTTP-Umgebung zum Laufen zu bekommen und die Anwendung so zu gestalten, dass sie Ihren Vorstellungen entspricht, müssen Sie allerdings sich mit dem Quelltext des Scripts auseinandersetzen und die angewendete Programmierlogik des fremden Script-Entwicklers nachvollziehen können. Wenn Sie Glück haben, ist das Script Ihrer Wahl sauber dokumentiert, und es ist nicht schwer, es für eigene Zwecke anzupassen. Im Linkverzeichnis des Online-Angebots von SELFHTML aktuell finden Sie eine Übersicht mit Anbietern fertiger CGI-Scripts in Perl und anderen Sprachen:

Online-Seite SELFHTML Linkverzeichnis: CGI/Perl

Im folgenden werden einige typische Anwendungsgebiete von CGI-Scripts angeschnitten. Es wird beschrieben, wie der prinzipielle Programmablauf eines entsprechenden Scripts aussieht, und welche Perl-Bestandteile dazu erforderlich sind. Die Beschreibungen enthalten Verweise zu den Stellen, an denen Sie weitere Details finden.

 nach obennach unten 

Counter (Zugriffszähler)

Ein Counter ist entweder grafisch oder textbasiert. Bei einem grafischen Counter wird das CGI-Script aus HTML heraus mittels eines <img>-Tags aufgerufen - Beispiel (HTML):

<img src="/cgi-bin/counter.pl" alt="Counter">

Bei einem textbasierten Counter geschieht der Aufruf meistens mit Hilfe von Seite Server Side Includes - Beispiel (HTML):

<!--#exec cgi="/cgi-bin/counter.pl"-->

Das aufgerufene Script muss dann zuerst die Datei mit dem aktuellen Zählerstand auslesen, den Zählerstand um 1 erhöhen und den neuen Zählerstand wieder in die Datei zurückschreiben. Dafür gibt es in Perl die Seite Funktionen für Ein-/Ausgabe und Lesen/Schreiben von Daten. Wenn es ein textbasierter Counter ist, kann das Script den Zählerstand z.B. mit einem HTTP-Header mit dem Seite Mime-Type text/html an den Browser senden, der die Zahl an der Stelle der Server-Side-Include-Anweisung einfügt. Bei einem grafischen Counter muss das Script eine Grafik vom Typ GIF, PNG oder JPEG zurückgeben, da der Browser im <img>-Tag etwas Entsprechendes erwartet. PNG-Grafiken lassen sich dynamisch mit Perl beispielsweise mit dem Seite CPAN-Modul namens GD erzeugen.

 nach obennach unten 

Form-Mailer

Ein Form-Mailer löst das leidige mailto-Problem bei HTML-Formularen. Ein solches Script kann ein beliebiges HTML-Formular verarbeiten und sendet die Daten per E-Mail an einen vorgesehenen Empfänger, in der Regel den Anbieter des Web-Projekts. In HTML wird das Form-Mail-Script einfach als action-Attribut im HTML-Formular angegeben - Beispiel:

<form action="/cgi-bin/formmail.pl" method="post">

Das Script wird aufgerufen, wenn ein Anwender das Formular absendet. Das Script sollte die Seite Formularverarbeitung mit dem CGI-Modul nutzen, um die übergebenen Formulardaten einzulesen. Anschließend muss es aus den Daten des Formulars eine E-Mail zusammenbauen. Dazu sind vor allem der Seite Operator für Zeichenkettenverknüpfung und Seite Funktionen für Zeichenketten von Bedeutung, ferner aber auch Wissen über den Aufbau einer E-Mail und darüber, wie eine Mail zu versenden ist. Die typische Anweisungsfolge dazu lautet:

my $Sendmail_Prog = "/usr/lib/sendmail";
open(MAIL,"|$Sendmail_Prog -t") || print "Mailprogramm konnte nicht gestartet werden\n";
print MAIL "To: $mailto\n";
print MAIL "Subject: $subject\n\n";
print MAIL "$mailtext\n";
close(MAIL) || print "Fehler beim Mailversenden!";

Wichtig ist bei Anwendung der Seite open-Funktion, dass das Programm sendmail, das E-Mails versenden kann, auch tatsächlich verfügbar ist, und zwar unter dem angegebenen Pfad. Der Pfad im Beispiel und die Verfügbarkeit von sendmail beziehen sich auf typische Unix-Rechner. Fragen Sie Ihren Provider gegebenenfalls danach! Die E-Mail selbst wird dann, wie Sie dem Beispiel entnehmen können, mit print-Anweisungen in den bei open benannten Einausgabekanal des sendmail-Programms geschrieben - im Beispiel der Kanal mit dem Namen MAIL. Wichtig ist, dass eine E-Mail eine erste Zeile mit To: beginnend und eine weitere mit Subject: beginnend enthält. Vor der Ausgabe des Mailtextes, also der zuvor für die Ausgabe vorbereiteten Formulardaten, müssen zwei Steuerzeichen \n\n stehen, also eine Leerzeile. Die Art und Weise der Datenübergabe kann variieren. Schauen Sie auf jeden Fall in die Anleitungen und FAQs Ihrers Providers und ggf. in die Anleitung des Mailprogramms!

Neben dem Mailversand muss das Script natürlich auch noch eine Seite CGI-notwendige Ausgabe an den Browser senden. Bei einem Form-Mailer ist das sinnvollerweise eine Dank-Seite, die dem Anwender bestätigt, dass sein Formular verarbeitet wurde.

Im Online-Angebot von SELFHTML aktuell finden Sie einen Online-Seite SELFHTML Feature-Artikel: Einfacher Form-Mailer, der ein vollständiges Beispiel eines Form-Mailers beschreibt.

 nach obennach unten 

Gästebuch

Es gibt mehrere Wege, ein Gästebuch zu programmieren. Einer davon ist, die Gästebucheinträge in eine statische HTML-Datei zu schreiben, die angezeigt wird, wenn der Anwender das Gästebuch aufruft. Die Datei könnte ein Formular enthalten, in dem der Anwender seinen eigenen Eintrag schreiben kann, sowie die bereits vorhandenen Einträge. Das Script, das das Gästebuch verwaltet, wird dann aufgerufen, wenn der Anwender das Formular mit einem eigenen Eintrag absendet. Dazu ist im einleitenden <form>-Tag ein entsprechender Aufruf notiert - Beispiel:

<form action="/cgi-bin/guestbook.pl" method="post">

Das Script sollte die Seite Formularverarbeitung mit dem CGI-Modul nutzen, um die übergebenen Formulardaten einzulesen. Angenommen, das Formular hat zwei Felder: eines für den Namen des Gästebuchschreibers (name="Username"), und eines für den Text (name="Usertext"). Dann wäre nach dem Einlesen mit dem CGI-Modul in Perl beispielsweise mit einem Konstrukt wie $cgi->param($Username) auf den Inhalt des Feldes Username möglich.

Weiterhin muss das Script die HTML-Datei mit den bisherigen Einträgen einlesen. Mit der Seite open-Funktion beispielsweise lässt sich die Datei dann öffnen und kann danach etwa in einen Seite Array eingelesen werden. Jedes Element des Arrays ist dann eine Zeile der HTML-Datei.

Damit das Script sich im eingelesenen HTML-Code zurechtfindet und weiß, wo es die neuen Daten einfügen muss, sollte die Datei an der betreffenden Stelle in einer eigenen Zeile eine "geheime Marke" enthalten, was mit einem HTML-Kommentar lösbar ist - Beispiel:

<!-- NEU -->

Es macht aber auch Sinn, wenn die HTML-Datei vor jedem vorhandenen Eintrag in einer eigenen Zeile noch eine interne Notiz für das Script bereithält. Auch das ist mit Kommentaren möglich. Beispiel eines Eintrags in der HTML-Datei:

<!-- EINTRAG [Winfried Wachtelmann] [27.07.2001]-->
<table border="1"><tr>
<th>von:</th><td>Winfried Wachtelmann</td>
<th>am:</th><td>27.07.2001</td>
</tr><tr>
<td colspan="2">Diese wunderbare Seite hat mein Leben ver&auml;ndert usw.</td>
</tr></table>

Das Script tut sich dann leichter mit eventuellem Suchen in der Datei. Um die Formulardaten, die das Script übergeben bekommen und eingelesen hat, einzufügen, muss es aus den Formulardaten erst einmal den für einen Gästebucheintrag üblichen HTML-Code zusammenbauen und die Formulardaten darin einfügen. Im Beispiel würde das Script also eine HTML-Tabelle zusammenbauen und in den dafür vorgesehenen Zellen die Werte aus den Formulardaten einbauen. Am sinnvollsten ist es, wenn das Script dazu einen Array deklariert und diesem für jede Zeile des HTML-Codes ein Element zuweist mit dem entsprechenden HTML-Code. Am Ende jedes Eintrags im Array sollte ein \n für "neue Zeile" stehen. Dazu benötigen Sie die Funktion Seite push und den Seite Operator für Zeichenkettenverknüpfung - Beispiel:

my @NeuerEintrag;
push(@NeuerEintrag, "<!-- EINTRAG [".$cgi->param($Username)."] [".$Datum."]-->\n");
push(@NeuerEintrag, "<table border=\"1\"><tr>\n");
push(@NeuerEintrag, "<th>von:</th><td>".$cgi->param($Username)."</td>\n");
push(@NeuerEintrag, "<th>am:</th><td>".$Datum."</td>\n");
push(@NeuerEintrag, "</tr><tr>\n");
push(@NeuerEintrag, "<td colspan=\"2\">".$cgi->param($Usertext)."</td>\n");
push(@NeuerEintrag, "</tr></table>\n");

Das in $Datum gespeicherte Tagesdatum muss das Script natürlich zuvor ermitteln. Dazu gibt es die Seite Funktionen für Datum und Uhrzeit.

Nun muss das Script den neuen Eintrag einfach an der Stelle in der bisherigen Datei einfügen, wo mit <!-- NEU --> die Marke zum Einfügen steht. Eine mögliche Variante ist es, einen neuen Array zu bauen, der aus den Zeilen der alten Datei und den Zeilen des neuen Eintrags besteht. Dazu kann das Script in einer Seite foreach-Schleife den Array mit den Zeilen der eingelesenen Datei abarbeiten und mit Hilfe eines Seite regulären Ausdrucks nach /^<!-- NEU -->$/ suchen und an der betreffenden Stelle den Array mit dem neuen Eintrag einfügen. Der Code könnte etwa so aussehen:

my @NeueZeilen;
my $Zeile;
foreach $Zeile (@Zeilen) {               # @Zeilen = zuvor eingelesene Zeilen der Datei
  if(/^<!-- NEU -->/) {                  # Aha, Eintrag hier einfügen
    foreach(@NeuerEintrag) {             # @NeuerEintrag = zuvor zusammengebaute HTML-Zeilen
      push(@NeueZeilen,$_);              # Zeile für Zeile hinzufügen
    }
    push(@NeueZeilen,"<!-- NEU -->\n");  # fürs nächste mal ...
  }
  else {                                 # jede alte Zeile, die nicht /^<!-- NEU -->/ enthält
    push(@NeueZeilen,$Zeile);            # einfach in den neuen Array kopieren
  }
}

Der neue Array @NeueZeilen enthält dann also die Zeilen der neuen Fassung der Gästebuch-HTML-Datei. Dieser Array muss nun einfach noch in die gleiche Datei zurückgeschrieben werden, die zuvor eingelesen wurde. Das geht mit schreibendem Öffnen mit Seite open und Beschreiben mit Seite print ins Datei-Handle der geöffneten Datei.

Am Ende darf das Script natürlich nicht vergessen, Seite CGI-notwendige Ausgaben an den Browser zu senden. Am einfachsten ist es wohl, einfach einen HTTP-Kopf und @NeueZeilen auszugeben. Das sind zwei print-Befehle, und schon sieht der Anwender, der das Formular abgesendet hat, das Gästebuch mit seinem eigenen neuen Eintrag.

Natürlich gibt es noch viele weitere wichtige Dinge, die das Gästebuch erledigen sollte. Beispielsweise sollten Dateien, die ein CGI-Script öffnet, grundsätzlich gegen versehentlichen Mehrfachzugriff geschützt werden - denn es könnten ja zwei Anwender geichzeitig ein Formular mit einem neuen Eintrag absenden. Dann würden sich zwei Prozesse mit dem gleichen Script in die Quere kommen. Das so genannte File-Locking für den Zugriffsschutz geht mit der Funktion Seite flock. Weiterhin sollte das Script reagieren, wenn die HTML-Datei mit den Gästebucheinträgen zu groß wird. In diesem Fall könnte das Script einen Teil des Arrays mit älteren Einträgen in eine zweite Datei schreiben und diese in der Datei mit den aktuellen Einträgen verlinken, d.h. also in die erste Datei einen HTML-Link auf die zweite mit einbauen.

 nach obennach unten 

Datenbank-Frontend

Sie brauchen nicht für jede Anwendung, bei der ein Webseitenbesucher dynamisch Daten abfragen kann, eine Datenbank. Datenbestände von bis zu ein paar Megabyte Größe, die nicht zu intensiv genutzt werden, lassen sich durchaus auch in Textdateien (z.B. kommasepariert oder in einer Seite XML-Struktur) halten, die dann mit CGI-Scripts in Perl verwaltet werden können. Ein öffentliches "Frontend" (also eine Web-Anwendung) zum Abfragen des Datenbestandes sowie ein nur intern zugängliches Frontend zum Verwalten des Datenbestandes (auch eine Web-Anwendung, die das Hinzufügen, Ändern und Löschen von Datensätzen mittels Formular möglich macht) brauchen Sie sowieso in jedem Fall. Eine richtige Datenbank sollten Sie dann wählen, wenn der Datenbestand sehr intensiv gepflegt wird (sehr viele Änderungen im Datenbestand - ein Fall für "Table-Locking"), oder wenn die Datenstruktur sehr stark relational ist und mit vielen Lookups arbeitet, oder wenn der Datenbestand wirklich sehr groß ist und die Pi-mal-Daumen-Größe von ein paar Megabyte übersteigt. Auf dem Server muss dann natürlich eine entsprechende Datenbank-Software installiert sein - z.B. das beliebte Freeware-Produkt MySQL. Letzteres ist mittlerweile so dominant im Web, dass es für relationale Datenbanken bis zu mittlerer Größe praktisch konkurrenzlos ist. Fragen Sie gegebenenfalls Ihren Provider, ob Ihnen MySQL dort, wo Sie Speicherplatz im WWW gemietet haben, zur Verfügung steht, bzw. berücksichtigen Sie dies bei der Wahl des Providers, wenn Sie eine Datenbankanbindung brauchen. MySQL wird zwar vorwiegend gemeinsam mit Seite PHP genutzt, aber über Perl ist es genauso möglich, Datenbank-Frontends zu schreiben, die mit MySQL kommunizieren können.

Bevor Sie ein Datenbank-Frontend in Perl schreiben, müssen Sie sich zuerst intensiv mit MySQL, Datenbankschnittstellen und der Abfragesprache SQL auseinandersetzen. Dazu gibt es Dokumentationen und Bücher. Im Linkverzeichnis des Online-Angebots von SELFHTML aktuell finden Sie entsprechende Links:

Online-Seite SELFHTML Linkverzeichnis: Datenbankanbindung

Dieser kurze Abschnitt hier kann nur einige allgemeine Details aus Sicht von Perl behandeln. In einem Perl-CGI-Script, das mit einer MySQL-Datenbank kommunizieren möchte, müssen zu Beginn Zeilen wie die folgenden stehen:

use CGI;
use DBI;

my $DB_NAME = "Produkte";
my $DB_DSN = "DBI:mysql:database=$DB_NAME";
my $DB_USER = "";
my $DB_PASSWD = "";

my $dbh = DBI->connect($DB_DSN, $DB_USER, $DB_PASSWD) or die "Fehler bei Datenbankverbindung: $!";

DBI ist ein Seite CPAN-Modul, das Sie in der Regel benötigen, um mit Perl auf Datenbanken zugreifen zu können. Es stellt eine datenbankunabhängige Schnittstelle zu verschiedenen datenbankabhängigen Treibern dar. Ihr Perl-Script kommuniziert also mit der Datenbank in der Form, dass es die Funktionen bzw. Methoden des DBI-Moduls nutzt.

Im Beispielcode deklariert das Script einige Skalare, die für das Modul und den Aufbau mit der Datenbank erforderlich sind. $DB_NAME ist der Name der Datenbank. DB_DSN ist eine Information für das DBI-Modul, welcher Treiber zum Verbindungsaufbau mit der Datenbank benutzt werden soll (im Beispiel: mysql), und welche Datenbank geöffnet werden soll (im Beispiel die Datenbank, die in $DB_NAME gespeichert ist). Da der SQL-Server von MySQL, der die Datenbankzugriffe und die Ausgabe an extern aufrufende Prozesse überwacht, Daten aus Datenbanken nur gegen Anmeldung mit Benuterkennwort und Passwort herausrückt, sind diese ebenfalls bei der Datenbankverbindung mit anzugeben. Im Beispiel erhalten die entsprechenden Skalare $DB_USER und $DB_PASSWD einen leeren Inhalt zugewiesen. Bei autorisierter Nutzung einer Datenbank müssen Sie dort jedoch die Kenndaten eingeben.

Mit DBI->connect(...) wird die Verbindung zur Datenbank aufgebaut. Der Rückgabewert wird in einer Datenbank-Handle-Variablen gespeichert, im Beispiel $dbh. Über dieses Handle können Sie im weiteren Verlauf des Scripts die Funktionen bzw. Methoden des DBI-Moduls ansprechen wie in diesem Beispiel:

my @DB_Felder = $dbh->list_fields('produktdaten');
$dbh->disconnect;

list_fields ermittelt die Feldnamen einer bestimmten Tabelle der Datenbank, im Beispiel die der Tabelle produktdaten. Mit $dbh->disconnect wird eine Datenbankverbindung am Ende wieder geschlossen. Die eigentliche Kommunikation mit der Datenbank erfolgt jedoch über entsprechende SQL-Befehle. Das folgende Beispiel zeigt, wie Sie in einem Perl-Script einen solchen Befehl notieren können und eine anschließende Datenbankabfrage starten:

my $SQL_Statement = "SELECT nummer, name, beschreibung FROM produktdaten ".
                    "WHERE produktdaten.nummer >= ".$cgi->param($von_Nummer).
                    " AND produktdaten.nummer <= ".$cgi->param($bis_Nummer).
                    " ORDER BY ".$cgi->param($sortier_feld);

my $Abfrage = $dbh->prepare($SQL_Statement);
$Abfrage->execute();

my @Datensatz;
while(@Datensatz = $Abfrage->fetchrow_array()) {
  DatensatzVerarbeiten(@Datensatz);
}

Für die Datenbankabfrage müssen Sie einen SQL-Befehl zusammenstellen und in einem Skalar speichern. Dazu müssen Sie die Syntax von SQL kennen. Normalerweise wird es so sein, dass Ihr CGI-Script wie im Beispiel die Parameter der Abfrage aus einem HTML-Formular bezieht, das der Anwender, der das Script mit dem Absenden des Formulars aufgerufen hat, ausgefüllt hat. Dazu sollte das Script die Seite Formularverarbeitung mit dem CGI-Modul nutzen, um die übergebenen Formulardaten einzulesen. Eine dynamische Konstruktion eines SQL-Befehls aus Formulardaten ist dann wie gezeigt mit dem Seite Operator für Zeichenkettenverknüpfung möglich. Anschließend wird mit $Abfrage = $dbh->prepare($SQL_Statement) dem DBI-Modul der Abfragewunsch mitgeteilt. Und danach kann dann mit $Abfrage->execute() der Abfragebefehl gestartet werden. Die Datenbank gibt nun der Reihe nach alle gefundenen Datensätze zurück. Jeder Datensatz besteht aus mehreren Feldern. Jeder Datensatz wird einzeln als Seite Array zurückgegeben. In einer Seite while-Schleife, die so lange läuft, wie der Aufruf von $Abfrage->fetchrow_array() einen neuen Datensatz liefert, wird im Beispiel eine Seite Subroutine namens DatensatzVerarbeiten aufgerufen, die als Parameter den aktuellen Datensatz-Array übergeben bekommt. Diese Subroutine könnte beispielsweise den HTML-Code für die Ausgabe eines Datensatzes vorbereiten. Denn abschließend muss das Script natürlich Seite CGI-notwendige Ausgaben an den Browser senden.

Bei der Verwaltung der Datenbank über ein HTML-Formular/Perl-Script-Frontend ist der Vorgang ganz ähnlich, nur mit zusätzlichen SQL-Befehlen zum Hinzufügen oder Zurückschreiben geänderter Datensätze in die Datenbank. Wichtig ist, dass ein solches Front-End für die interne Datenbankpflege gegen öffentliche Zugriffe geschützt ist. Dies kann zweistufig geschehen: zum einen sollte ein solches Front-End-Formular nur in einem Seite htaccess-geschützten Verzeichnis liegen, und zum anderen sollte das Formular auch Eingabefelder für Benutzernamen und Passwort zum schreibenden Zugriff auf die Datenbank enthalten.

 nach oben
weiter Seite Funktionen für Zeichenketten
zurück Seite Objektorientiertes Programmieren
 

© 2001 E-Mail selfhtml@teamone.de