Tutorial : CGI-Programmierung für Einsteiger
      
Shopsoftware Shopsystem
  Home     Download     News     Kontakt     Impressum     Sitemap  

Demo-Version   
Häufige Fragen   
Module und Preise   
Wie bestellen   
Support   
AnfrageAnfrage   
TutorialsTutorials
Partnerprogramm   
Über interaktiv.net   
Leistungen   
Referenzen   
Sie sind hier  :  Startseite Support Tutorials
CGI-Programmierung für Einsteiger


Entwicklungsumgebung
Aufgabenstellung
Script Header schreiben
Libraries verwenden und Script strukturieren
Unterfunktionen schreiben
CGI auf Webserver installieren
Ausblick



Entwicklungsumgebung

PERL CGI's welche auf einem LINUX Server laufen sollen in einer Win32 Umgebung entwickeln? Jawohl das geht! Und wer Wert darauf legt, dass seine Scripte ohne Änderung gleichermassen auf Win32 und LINUX laufen müssen, sollte zumindest die im Folgenden beschriebenen Besonderheiten kennen:
  • Unter LINUX gibt es keine Laufwerksbuchstaben! Bei der Entwicklung eines CGI's in einer Win32 Umgebung kann die Laufwerksangabe entfallen sofern sich HTTP Root, CGI-BIN und andere lokale Pfade auf ein und demselben Laufwerk befinden.
  • Unter LINUX gibt es den Slash! Für PERL kein Problem in einer Win32 Umgebung, einfach den Slash verwenden (lediglich mit einigen Win32 Modulen muss der Backslash verwendet werden, dann jedoch bitte maskieren).
  • Sollen Systembefehle eingesetzt werden, ist zu beachten, dass diese selbstverständlich von System zu System unterschiedlich sind. Mit dem geschickten Einsatz von diversen PERL Modulen lassen sich jedoch manche Systembefehle durch reines PERL ersetzen und das Script erhält somit eine Plattformunabhängigkeit.
  • Soll ein Script auch mit verschiedenen Systembefehlen plattformunabhängig gemacht werden, kann die Version des Betriebssystems über die Variable $^O in Kontrollstrukturen aufgearbeitet werden.
Voraussetzung für das lokale Testen von PERL CGI's ist ein installierter lokaler Webserver Webserver möglichst mit virtuellen Hosts die beim Offline Testen von URL übergreifenden Scripts sehr von Vorteil sind. Bei der Auswahl der Serversofware ist u.a. der Gedanke interessant inwieweit der Pfad zum PERL Interpreter (1. Zeile eines jeden Scripts) angegeben werden muss, weil dieser mit Sicherheit in einer Win32 Umgebung anders ist als unter LINUX. Soll ein Script also nicht jedesmal vor dem Hochladen in dieser Zeile geändert werden müssen, sollte ein für lokale Tests ein Webserver genommen werden der die 1. Zeile ignoriert wie z.B. der OmniHTTPd OmniHTTPd. Der PERL Interpreter ist erhältlich bei Activestate Activestate. Schließlich ist auch noch die Wahl eines geeigneten Editors zu treffen, z.B. Ultraedit Ultraedit.


Aufgabenstellung

Zu Scripten ist ein CGI welches einmal die HTML Seite aufbaut und zum Anderen die Verarbeitung der Eingaben übernimmt. Die Eingaben sollen zeilenweise in eine Datei geschrieben werden mit dem folgenden Aufbau:

datum und zeit;name;geschlecht;alter

Während das Geschlecht aus einer Option Bar ausgewählt werden kann und demzufolge immer ein Wert gegeben ist, müssen Name und Alter stets vom Benutzer ausgefüllt werden. Bei fehlenden Eingaben soll das Script eine Fehlermeldung ausgeben.


Script Header schreiben

Die allererste Zeile eines jeden PERL Scripts enthält den Pfad zum PERL Interpreter (es sei denn der Webserver ignoriert Diese). Syntax:

#!/usr/bin/perl

Die nächsten Zeilen sollten in keinem Script fehlen und werden als Kommentar notiert:

# Verwendungszweck
# Autor
# Erstellungsdatum
# Version

Der nächste Block beinhaltet globale Variablen welche vom Benutzer zu setzen sind, da dieses Script eine Datei beschreibt muss der Benutzer den lokalen Pfad und Dateinamen angeben

# Pfad und Name der Benutzerdatei
$ben_dat = "/temp/benutzer.txt";




Libraries verwenden und Script strukturieren

Lesen und Parsen von HTML Form's lassen sich erheblich vereinfachen mit Modulen oder Libraries. Im Vorliegenden Fall soll die cgi-lib.pl cgi-lib.pl für diesen Zweck verwendet werden. Ohne die Funktionen jetzt gleich mit Quelltext zu definieren, kann nun die komplette Struktur der CGI's locker aufgegliedert notiert werden:

require "cgi-lib.pl";
print &PrintHeader; # der Content-type...

if ( &ReadParse ) { # Wenn eine Eingabe erfolgte...
 &einprf; # Eingabe prüfen
 &a_html; # Seite bis Body
 &write_file; # Datei anlegen und Einträge in Datei schreiben
 &quit; # erfolgreiche Eingaben im Browser anzeigen
 &z_html; # Seite schließen
}
else{ # keine Eingabe, Seite aufbauen mit Formular
 &a_html; # Seite bis Body
 &form; # Eingabeformular
 &z_html; # Seite schließen
}
exit;

Kleine Erläuterung zu diesem Script bisher

Mit require "cgi-lib.pl"; wird Selbige eingebunden. Die nächste Zeile schickt den Content-Type:text/html zum Browser gefolgt von einer Leerzeile (wichtig).

Die nachfolgende Kontrollstruktur beinhaltet den Ablauf des CGI's in 2 Blöcken, einmal im Falle einer Benutzereingabe und zum Anderen im Falle dass noch keine Eingabe erfolgte. Diese Kontrollstruktur ist wichtig, weil ja mit einem einzigen CGI Script das Formular gezeigt und die Eingaben verarbeitet werden sollen. Mit ähnlichen Kontrollstrukturen lassen sich später auch kompliziertere Aufgaben lösen, beispielsweise die Verarbeitung unterschiedlicher Formulare oder unterschiedlicher Submit Buttons in einem einzigen CGI!

Dieser Teil der Strukturierung ist entscheidend für das sichere Funktionieren eines CGI's und der Hauptteil des Programmierens eines CGI's überhaupt. Natürlich können die Unterfunktionen noch einiges an Arbeitsaufwand erfordern, aber im Wesentlichen ist das Script an dieser Stelle hier schon fertig.




Unterfunktionen schreiben

#---Subfunctions---#

# Datei anlegen und Einträge in Datei schreiben
sub write_file{
 my $zeit = localtime(time);
 open FH, ">>$ben_dat" or CgiDie("Fehler beim Anlegen oder Schreiben der Benutzerdatei","$!");
 print FH "$zeit;$in{'name'};$in{'sex'};$in{'alter'}\n";
 close FH;
}

# erfolgreiche Eingaben im Browser anzeigen
sub quit{
my $zeit = localtime(time);
print<<QUIT;
<h3>Benutzereingaben erfolgreich gespeichert!</h3>
<pre>
Datum und Zeit: $zeit
Name: $in{'name'}
Geschlecht: $in{'sex'}
Alter: $in{'alter'}
</pre>
QUIT
}

# Eingaben prüfen
sub einprf{
 if( !$in{'name'} or !$in{'alter'} or $in{'alter'} =~ /[^0-9]/ ){
 CgiDie("Fehlerhafte Eingabe","Backbutton klicken und Eingabe wiederholen, Name, Geschlecht und Alter muss angegeben werden. Das Alter bitte als einen ganzzahligen Wert eingeben.");
 }
}

# Formular aufbauen
sub form{
print<<FORM;
<h3>CGI 4 Beginner, Benutzereingaben in Datei speichern</h3>
<pre>
<form action="$ENV{SCRIPT_NAME}" method="post">
Bitte Füllen Sie alle Eingabefelder aus

Name: <input type="Text" name="name" size="45" >
Geschlecht männlich: <input type="Radio" name="sex"
value="Maennlich" checked> Weiblich: <input type="Radio" name="sex" value="Weiblich">
Alter: <input type="Text" name="alter" size="3" maxlength="3">
<input type="Submit" name="ok" value="Eingaben speichern"><input type="reset" value="Eingaben verwerfen">
</form>
</pre>
FORM
}

# Seite aufbauen bis zum Body
sub a_html{
print<<AHTML;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE>CGI 4 Beginner</TITLE>
</HEAD>
<BODY>
AHTML
}

# Seite schließen
sub z_html{
print<<ZHTML;
</BODY>
</HTML>
ZHTML
}

Erläuterungen zu den Unterfunktionen

Die Funktion write_file weist keine Besonderheiten auf und ist auch für den Anfänger durchschaubar. Wichtig ist es immer beim Anwenden der Funktion open den Rückgabewert abzufragen ob es einen Fehler gab, hilfreich dazu ist die Variable $!. Im vorliegenden Fall wird das Script bei einem Fehler bei open FH,... abgebrochen.

In den Funktionen a_html, z_html, form wird die gesamte Ausgabe per Here is... Konstrukt auf den print Befehl umgeleitet - mit einem einzigen print Befehl wird ein komplettes Dokument an den Browser geschickt. Von Vorteil ist dabei die Möglichkeit einer vereinfachten Schreibweise, so müssen z.B. eingefügte " " nicht maskiert werden.

Interessant ist vielleicht auch die Notifikation form action="$ENV{SCRIPT_NAME}" im einleitenden Form Tag, damit wird dieses CGI vom Namen des Scripts unhängig (falls der Script Name irgendwann mal geändert werden sollte).

Die Funktion einprf prüft in einer oder Verknüpfung ob die Eingabefelder ausgefüllt wurden. Recht einfach wird hier auch geprüft ob das Alter auch wirklich nur Ziffern enthält. Bei fehlerhafter Eingabe wird die weitere Verarbeitung des CGI's abgebrochen mit der Funktion CgiDie und einer selbst definierten Fehlermeldung im Argument dieser Funktion.


CGI auf Webserver installieren

Sofern lokal alles funktioniert kommt der große Moment des Ausprobierens, seitens des Providers steht ein cgi-bin zur Verfügung und dort soll natürlich auch dieses Script installiert werden und laufen. Also stellen wir die Verbindung zum Provider her über Modem oder ISDN und starten mit unseren FTP-Zugangsdaten ein geeignetes FTP Programm. Ist das Script im ASCII Mode hochgeladen muss es auf dem Server auf ausführen gesetzt werden, viele Provider reden dabei von chmod 755 file ... aber auch das ist zu schaffen!

Eine Besonderheit gibt es jedoch auch bei diesem Script zu beachten: Es soll eine Datei angelegt bzw. mit Benutzereingaben gefüllt werden, was heißt das? Nun, je nach Providervorgaben läuft ein CGI unter einem bestimmten Benutzer Account, das ist meistens die Gruppe (seltener "Alle"). Soll mit einem solchen CGI also eine Datei in einem bestimmten Verzeichnis angelegt werden, muss für die Gruppe auf dieses Verzeichnis ein Schreibrecht bestehen! Die Vergabe des Schreibrechtes auf ein ganzes Verzeichnis kann umgangen werden wenn es die Datei bereits gibt, in diesem Fall muss das Schreibrecht (chmod 666 datei) lediglich auf die Datei gesetzt werden. Siehe auch: UNIX Dateirechte


Ausblick

Dieser Artikel zeigt wie mit einem guten Lösungsansatz eine bestimmte Aufgabenstellung als CGI gelöst werden kann. Mit dem gezielten Einsatz von Modulen oder Libraries (hier cgi-lib.pl) kann ein Script wesentlich vereinfacht werden und der Programmierer kann sich auf das Wesentliche beschränken. Strukturierte Programmierung konsequent angewandt heißt: Übersicht behalten über den gesamten Ablauf eines Scripts. Hilfreich sind in jedem Falle Kommentare - so wird ein etwaiger Umzug auf eine andere Plattform oder die Programmpflege schlechthin vereinfacht.

Das Problem File Locking ist im aufgezeigten Beispiel nicht berücksichtigt, sollte jedoch in jedem Falle Beachtung finden. Unter LINUX/UNIX kann dazu die Funktion flock() verwendet werden, für anderen Plattformen gibt es dazu auch andere Lösungen wie z.B. das Verfahren der Umbenennung, so wird erreicht, dass eine Datei tatsächlich nur von einem Prozess beschrieben werden kann.

Um stets die Übersichtlichkeit zu wahren gibt es auch die Möglichkeit, Unterfunktionen in externe Dateien auszulagern. Siehe dazu auch die entsprechenden Abschnitte im Perl Tutorial von Eike Grote wie Code von externen Dateien eingebunden wird. Tipp: die Funktionen &a_html und &z_html in eine eigene Library auslagern und im Argument zum Beispiel übergeben ("Titel","CSS Datei","Hintergrund")... externe Dateien einzubinden macht i.d.R. immer dann einen Sinn, wenn diese nur einmal pro Prozess aufgerufen werden, also zum Beispiel im Falle des Seitenaufbaues beim Aufruf des CGI's.
interAKTIVnet GmbH
Otto-Lilienthal-Str. 36
71034 Böblingen
Tel. 07031-714740
Fax 07031-714744
info@interaktiv.net