Software-Engineering Martin Fabiani

Sitemap (Navigation ohne JavaScript)

Impressum: Martin Fabiani, Röderbergweg 104, D-60485 Frankfurt, Tel: +49 (69) 49084808, E-Mail: info (at) fabiani.net, USt-IdNr: DE217298609

Tips und Tricks zu Perl

Diverses zu CGI


Einführung in Perl/CGI

Ich werde in dieser Einführung nicht in alle Details gehen, sondern versuchen, einen kleinen Überblick zu geben, damit jemand mit Perl-Kenntnissen, der CGI-Scripte schreiben will, so grundsätzlich versteht, wie das funktioniert.

Was ist CGI?

Die CGI-Schnittstelle eines Webservers erlaubt es, anstelle von statischen Webseiten wie z.B. html-Seiten oder Bildern irgendwelche Programme auszuführen, deren Output dann an den Browser zurückgeliefert wird. Dieser Output kann eine ganz normale HTML-Seite sein, aber auch ein Bild oder irgendwas anderes. Damit der Webserver und der Webbrowser zwischen den verschiedenen Arten von Dokumenten unterscheiden kann, muß man dem Webserver jedoch sagen, was man zurück gibt. Dies macht man mit einem Content-Type, der z.B. für HTML-Seiten text/html lautet.

Um die CGI-Schnittstelle ansprechen zu können, kann man fast jede Sprache verwenden (sogar Unix-Shellscripte). In der dunklen Frühzeit des Webs wurde z.B. häufig die Sprache C verwendet. Mittlerweile ist die gebräuchlichste Sprache dafür Perl geworden, vor allem wahrscheinlich deshalb, weil man damit sehr einfach die CGI-Schnittstelle ansprechen kann.

Was benötige ich, um mit Perl CGI-Scripte zu schreiben?

  1. Webserver, der die Ausführung von CGI-Scripten gestattet. Häufig werden der Webserver Apache und unter Windows auch der Microsoft Internet Information Server verwendet. Ich beziehe mich jedoch nur auf den Apache Webserver.
  2. Programmier- oder Scriptsprache wie z.B. Perl. Perl für Windows kann man von http://www.activestate.com/ downloaden, für andere Betriebssysteme von http://www.perl.com/

Für die Installation einer Scriptsprache in einem Webserver muß man jedoch häufig den Webserver recht gut kennen, d.h. es ist häufig eine etwas größere Einarbeitungszeit nötig. Um diese Einarbeitungszeit zu reduzieren, haben einige wunderbare Leute schon so gut wie fertig konfigurierte Kombinationen von Apache und Perl erstellt und eine gute, einfach verständliche Installationsanleitung hinzugefügt. Und zum Entwickeln von Scripten genügt das leicht. Einige solche Kombinationen für Windows oder Linux können von http://www.apachefriends.org/ downloaden. Für Windows gibt es z.B. den WAMPP, eine Kombination von Apache, MySql (=Datenbank), PHP und Perl und einige zusätzliche Hilfen wie z.B. phpMyAdmin (Administration der Datenbank MySql), etc. Ebenso LAMPP für Linux. Dabei sollte man ein Package downloaden, das in etwa zu dem vom Webprovider passt; also wenn der Webprovider Apache 1.3 verwendet, sollte man zu einem wampp_0.13.x oder lampp_0.13.x greifen, oder wenn der Webprovider Apache 2.0 verwendet, dann besser zu wampp_0.2.x oder lampp_0.2.x. Ebenso sollte die Perl-Version in etwa identisch sein, damit man beim Upload keine bösen Überraschungen erlebt, wenn irgendwelche Befehle nicht laufen. Die meisten Provider haben leider noch nicht perl5.8 laufen, sondern leider 5.6 oder 5.6.1 (die leider sehr viele Bugs enthalten) oder noch die recht alte, aber grundsolide Version 5.005_03, die jedoch leider das Compilerpragma use warnings noch nicht unterstützt.

Tips zur Konfiguration von Apache 1.3 für Windows:

Bei CGI-Scripten wird ebenso wie bei "normalen" Perl-Scripten ein Shebang benötigt (häufig #! /usr/bin/perl ), über den der Webserver ein Script einem Programm zuordnen kann. Bei Windows gibt es jedoch in der Konfigurationsdatei des Apache namens httpd.conf (meistens unter \wampp....\apache\conf\httpd.conf ). Dort suche man nach der Zeile

# ScriptInterpreterSource registry

und entferne die Raute # davor und starte danach Apache neu. Als nächste muß man der Registry noch sagen, daß Scripte mit der Endung .cgi und .pl noch mit perl ausgeführt werden sollen. Dazu öffne man sich eine Dos-Shell (unter WinNT/2k/XP cmd.exe) und gebe dort die folgenden Befehle ein:

assoc .pl=Perl-Script
assoc .cgi=Perl-Script
ftype Perl-Script=E:\wampp13a\perl\bin\perl.exe "%1" %*

(Achtung: die Anführungszeichen um %1 herum sind wichtig; in der Hilfe zu ftype steht zwar auch ein ähnliches Beispiel mit Perl, aber leider fehlen dort die Anführungszeichen, was Probleme bereitet, wenn im Skript oder einem Verzeichnis dorthin Leerzeichen vorkommen)

Wenn Perl in einem anderen Pfad als E:\wampp13a\perl\bin\perl.exe installiert ist, muß man den Pfad demensprechend anpassen. Dann ist der Shebang egal, und man kann schon den des Providers (meistens #! /usr/bin/perl ) verwenden.

Das erste CGI-Script

Man erstelle eine neue Datei unter \wampXXX\cgi-bin\ namens hello.cgi und schreibe da folgenden Code hinein:

#! /usr/bin/perl
use warnings;
use strict;

use CGI;

# die folgende Zeile sorgt dafuer, dass Fehler und Warnungen
# nicht im error.log verschwinden, sondern - wenn moeglich -
# im Webbrowser ausgegeben werden. Dies ist fuer die Entwicklung
# von Perl/CGI-Scripten sehr hilfreich, sollte dann aber, wenn
# ein Script produktiv geht, deaktiviert werden, weil dadurch
# ein potentieller Hacker zu viele Informationen bekommen koennte:

use CGI::Carp qw(fatalsToBrowser warningsToBrowser);


my $cgi = CGI::->new(); # neues CGI-Objekt erzeugen

# HTTP-Header mit dem Content-type text/html erzeugen. Man koennte auch
# print $cgi->header() schreiben, weil dann standardmaessig text/html
# verwendet wird.
print $cgi->header( -type=>'text/html' );

# Erzeuge einen HTML-Header, setze den Titel der Webseite auf Hello World 
# und verwende als Hintergrundfarbe Blau
print $cgi->start_html( -title => 'Hello World', -BGCOLOR => 'blue' );

# Schreibe einen zentrierte Überschrift erster Ordnung
print $cgi->h1( {-align => 'center'}, 'Meine Hello-World-Page');

# und beende die ausgegebene HTML-Seite
print $cgi->end_html();

Was für Methoden liefert das Modul CGI?

Siehe perldoc CGI

Was ist HTML? Was bedeuten <h1> <body> ...?

Siehe Selfhtml -> HTML/XHTML

Was tut der Webserver für mich? Umgebungsvariablen

Der Webserver liefert einige Umgebungsvariablen, die sehr interessant sein können. Man kann sie sich mit folgendem Script (nennen wir es mal printenv.cgi)anzeigen lassen:

#! /usr/bin/perl
use warnings;
use strict;

use CGI;
my $cgi = CGI->new();
print $cgi->header();
print $cgi->start_html( -title => 'Meine Umgebungsvariablen' );

print $cgi->start_table();

foreach (sort keys %ENV) {
  print "<tr><td>$_</td><td>$ENV{$_}</td></tr>\n"; # man kann auch html pur ausgeben
} # foreach

print $cgi->end_table();

print $cgi->end_html();

Wenn man dieses Script folgendermaßen aufruft, kommen auf meinem Rechner unter anderem folgende Umgebungsvariablen:

http://localhost/cgi-bin/printenv.cgi?param1=value1&param2=value2&param3=value3

DOCUMENT_ROOT e:/wampp13a/htdocs
HTTP_ACCEPT_LANGUAGEde
HTTP_HOST localhost
HTTP_USER_AGENTMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
QUERY_STRING param1=value1&param2=value2&param3=value3
REMOTE_ADDR 127.0.0.1
REMOTE_PORT1196
REQUEST_METHODGET
REQUEST_URI /cgi-bin/printenv.cgi?param1=value1&param2=value2&param3=value3
SCRIPT_FILENAME e:/wampp13a/cgi-bin/printenv.cgi
SCRIPT_NAME/cgi-bin/printenv.cgi
SERVER_ADDR 127.0.0.1
SERVER_NAME localhost
SERVER_PORT 80
SERVER_SOFTWAREApache/1.3.26 (Win32) mod_ssl/2.8.10 OpenSSL/0.9.6d mod_perl/1.27_01-dev PHP/4.2.1

Es können jedoch auch mehr oder weniger Umgebungsvariablen vorbelegt sein. Sehr nützlich sind manchmal die folgenden:

DOCUMENT_ROOT Wo befindet sich die Document-Root (vom Dateisystem aus gesehen)
HTTP_ACCEPT_LANGUAGE In welcher Sprache möchte der Webbrowser idealerweise eine Antwort erhalten?
HTTP_USER_AGENT Informationen über den Webbrowser des Benutzers
QUERY_STRING Die dem Script übergebenen Parameter (wenn GET)
REMOTE_ADDR Die IP-Adresse des Besuchers
REQUEST_METHOD GET oder POST? Auf welche Art werden Daten übergeben?
REQUEST_URI Welche Uri mit welchen Parametern wurde aufgerufen?
SCRIPT_FILENAME Dateiname und Pfad des Scriptes (vom Dateisystem aus gesehen)
SCRIPT_NAME Dateiname und Pfad des Scriptes (vom Web aus gesehen)
HTTP_REFERER Von woher kam der Browser? (Von welcher Seite?)

 

Wird irgendwann fortgesetzt...


Datei-Upload mit Perl/CGI

Auf vielen Mailinglisten und Diskussionsforen wird häufig die Frage gestellt, wie man mit Hilfe von Perl und CGI eine Datei auf einen Webserver hochladen kann. Also bringe ich eine von vielen Lösungen hier in dieser Rubrik. Darkmage von www.perl-community.de hat dazu ein sehr gutes Tutorial geschrieben, welches ich für ältere CGI-Module sehr empfehlen kann. Dies ist auch der Grund, wieso ich das alte Fileupload-Rezept von meiner Homepage entfernt habe.

Ab der Version 2.47 von CGI.pm gibt es jedoch einen einfacheren Weg als den in dem Tutorial gezeigten. Gehen wir davon aus, daß das Upload-Field in der aufrufenden Form den Namen uploaded_file hat. Dann kann man folgenden Code benützen:

#! /usr/bin/perl
use warnings; # ab Perl5.6
use strict;
use CGI;
	   
my $query = CGI->new();

# Maximalgroesse der Datei auf 100 Kb setzen
$CGI::POST_MAX = 100 * 1024;

# HTML-Output
print $q->header,
$q->start_html(
-title => 'Datei hochladen',
),
$q->h1('Datei hochladen'); # ueber diesen Filehandle wird die hochzuladende Datei empfangen my $fh = $query->upload('uploaded_file'); unless (defined $fh) { print "Fehler: keine Datei augewaehlt?"; exit 0; } # unless else { my $filename = $query->param('uploaded_file'); my $contentType = $query->UploadInfo($filename)->{'Content-Type'}; print "Filename: $filename", $query->br(); print "Content-type: $contentType", $query->br(); # wenn es sich um eine Binaerdatei handelt und das Betriebssystem # zwischen Binaer- und ASCII-Dateien unterscheidet, wie z.B. Windows binmode($fh); # nicht ganz sauber; was passiert, wenn bei Unix ein \ im Dateinamen # vorkommt? Besser vielleicht File::Basename verwenden. my ($localFilename) = ( $filename =~ /[\\\/]([^\\\/]+)$/ ) || $filename; unless (open (FILE, ">", $localFilename)) { print "Fehler: konnte Datei '$localFilename' nicht anlegen: $!\n"; exit 0; } # unless else { binmode (FILE); # wenn es sich um Binaerdatei handelt (siehe oben) local $/ = undef; # Datei auf einmal lesen; nicht bei grossen Dateien # machen!!! while (<$fh>) { # lese eine Zeile der upgeloadeten Datei print (FILE $_); # und schreibe sie in die lokale Datei } # while # schliesse die lokale Datei unless (close (FILE)) { print "Fehler beim schliessen von $localFilename: Festplatte voll? $!"; exit 0; } # unless print "Datei $localFilename hochgeladen", $query->br(); } # else } # else

Genauere Infos zu diesem Thema gibt die Dokumentation zum Modul CGI.


Perl-Konfiguration auslesen

Hiermit kann man einiges ueber den Webserver, auf dem man das seine CGI-Scripte laufen läßt, herausfinden.

Voraussetzungen:


#! /usr/bin/perl -w
use strict;
use CGI ();
use File::Find;


my $cgi = CGI->new();
print $cgi->header();
print $cgi->start_html('Perl-Konfiguration');
  
# Betriebssystem und Perl-Informationen herausfinden
print "Operating system: ", $^O, "<br/>\n";
print "Perl-Location: ", `which perl`, "<br/>\n";
print "Perl-Version: " , `perl -v`, "<br/>\n";
print "Sendmail-Location: ", `which sendmail`, "<br/>\n";
print "Date-Location: ", `which date`, "<br/>\n"; print "<hr/>"; print "PATH: @INC\n"; print "<hr/>"; # installierte Module auflisten foreach my $dir (@INC){ find sub { print "$File::Find::name<br/>\n" if /\.pm$/; }, $dir; } print "<hr/>"; # Environment-Variablen auslesen foreach (keys %ENV){ print ("$_ => $ENV{$_}<br/>\n"); } print "<hr/>"; # HTML-Footer schreiben print $cgi->end_html();

Letztes Update dieser Seite: Tuesday, 27-Jun-2006 20:37:01 CEST