Zahlreiche Auktionen bei
|
CGI - Ein Tutorial
CGI-Tutorial von Daniel Schwamm (28.03.1998)
Aus "Heimat des Dilettantismus"
http://www.henrys.de/daniel/index.php?cmd=software_cgi_index.htm
Im Gegensatz zu HTML, VRML und Jacascript kommt man bei CGI
i.d.R. nicht nur mit einem ASCI-Editor aus; man benötigt
eine Programmiersprache, die entweder CGI-Scripts interpretieren
oder EXEs bzw. DLLs kompilieren kann. CGI-Skripte sind im
Zusammenhang mit Perl unter UNIX sehr beliebt. Auch für NT findet
man kostenlose Perl-Interpreter, jedoch wollen wir diese hier
nicht betrachten. Unter NT scheinen mir EXEs bzw. DLLs sinnvoller
zu sein, zumal sie auch ein deutlich schnelleres Antwortverhalten
an den Tag legen. Der Einfachheithalber betrachten wir hier zunächst
nur EXEs, obwohl DLLs sicherlich die bessere Alternative darstellen
(DLLs werden nur einmal in den Speicher geladen und verbleiben dann
dort resistent, d.h., sie müssen im Ggs. zu EXEs nicht bei jeder CGI-Anfrage
neu geladen und gestartet werden).
Als begeisterter Delphi-Programmierer werden die im folgenden vorgestellten
CGI-EXEs in dieser Sprache programmiert sein.
CGI-Anwendungen bestehen i.d.R. aus zwei Teilen: Aus dem HTML-File,
welches die CGI-Applikation aufruft, und aus der CGI-Applikation selbst.
Sehen wir uns ersteinmal das aufrufende HTML-File an:
Man nehme einen x-beliebigen ASCII-Editor, z.B. Notepad in Windows,
und tippe folgendes ein:
<html>
<body>
<center>
<a href='/cgi-bin/cgikurs/cgikurs1.cgi'>
Klick mich, um CGI aufzurufen
</a>
</center>
</body>
</html>
|
(=>
cgikurs1.html)
Man sieht hier eine typische Referenz, die im Gegensatz zu sonst
meist üblich kein HTML-File addressiert, sondern ein ausführbares
Programm namens cgikurs1.cgi im /cgi-bin/cgikurs-Verzeichnis.
Mit etwas Fantasie und Programmier-Knowhow kann man sich vielleicht
bereits vorstellen, was CGI-Programme eigentlich tun: Sie
liefern unserem freundlichen Webserver eine HTML-Seite zurück. Eine
HTML-Seite wohlgemerkt, die i.d.R. zum Zeitpunkt des Aufrufs noch nicht
existiert, sondern vom CGI-Programm erst erzeugt und nach Standardoutput
geschrieben wird.
Und wie sieht nun der Source-Code von CGIKURS1.cgi in DELPHI 2.0
aus? Take a look!
program cgikurs;
{$apptype console}
uses
windows,sysutils,classes;
begin
writeln('Content-type: text/html');
writeln;
writeln;
writeln('<html><body>');
writeln('Hello, world!');
writeln('</body></HTML>');
end.
|
Na, ist das einfach? {$apptype console} sorgt dafür, daß unser
Programm eine Konsolenapplikation ist - wie oben erwähnt müssen wir
nämlich unsere dynamisch erzeugte HTML-Datei nach Standardoutput
schreiben (und nicht in ein Formular oder sonstwohin). Dann kommen
jene drei magischen Zeilen
writeln('Content-type: text/html');
writeln;
writeln;
|
ohne die gar nix geht. Mein lieber Schwan, haben die mich bei meinen
ersten CGI-Versuchen Nerven gekostet; nur ein writeln weniger,
und der Browser meldet Bullshit zurück. Naja, der Rest ist eigentlich
klar. Über
writeln('<html><body>');
writeln('Hello, world!');
writeln('</body></HTML>');
|
produzieren wir das klassische HTML-File
<html><body>;
Hello, world!;
</body></HTML>
|
welches - abgespeichert z.B. als tst.htm - mit jedem Webbrowser
betrachtet werden kann.
Klar, das ist alles noch wenig beeindruckend. Aber das Potential dahinter
ist bereits zu ersehen: Statt dem klassischen Hello, world-File
kann hier jedes x-beliebige HTML-File generiert werden. HTML-Files
z.B., die ihrerseits wieder CGI-Apps refrenzieren können. Es ist auch das
einfachste der Welt, auf herkömmliche Weise HTML-Seiten zu entwicklen
und diese dann in obige Delphi-Applikation einzubinden. Ihr wollt
Beweise? Sollt ihr bekommen. Hier das aufrufende HTML-File:
<html>
<body>
<center>
<a href='/cgi-bin/cgikurs/cgikurs2.cgi?tst1.htm'>
Klick mich, um HTML-Datei 'tst1.htm' anzuzeigen
</a>
<br>
<a href='/cgi-bin/cgikurs/cgikurs2.cgi?tst2.htm'>
Klick mich, um HTML-Datei 'tst2.htm' anzuzeigen
</a>
</center>
</body>
</html>
|
(=>
cgikurs2.html)
Hier das anzuzeigende HTML-File namens tst1.htm
<html>
<body bgcolor='#000000' text='#6060ff' link='#ffff00' vlink='#c0c000'>
<center>
<font size='6'>
Ich bin die Datei <b>'TST1.HTM'</b>
</font>
<br>
<a href='/cgi-bin/cgikurs/cgikurs2.cgi?tst2.htm'>
Klick mich, um HTML-Datei 'tst2.htm' anzuzeigen
</a>
</center>
</body>
</html>
|
Hier das anzuzeigende HTML-File namens tst2.htm
<html>
<body bgcolor='#6060ff' text='#000000' link='#ffff00' vlink='#c0c000'>
<center>
<font size='6'>
Ich bin die Datei <b>'TST2.HTM'</b>
</font>
<br>
<a href='/cgi-bin/cgikurs/cgikurs2.cgi?tst1.htm'>
Klick mich, um HTML-Datei 'tst1.htm' anzuzeigen
</a>
</center>
</body>
</html>
|
Und hier das Delphi-Programm:
program cgikurs2;
{$apptype console}
uses
forms,windows,sysutils,classes;
VAR
homedir,command,s:string;
tf:textfile;
begin
command:=paramstr(1);
homedir:=extractfilepath(application.exename);
writeln('Content-type: text/html');
writeln;
writeln;
assignfile(tf,homedir+command);
reset(tf);
while not eof(tf) do begin
readln(tf,s);
writeln(s);
end;
closefile(tf);
end.
|
In cgikurs2.html sehen wir, wie durch ?[parameter]
einem CGI-Programm ein Parameter übergeben werden kann.
In unserem Falls sind dies die Parameter tst1.htm und
tst2.htm. Durch
holt sich das Delphi-Programm diesen Parameter. Anschliessend wird
das Laufverzeichnis ermittelt, die gewünschte Datei im Textmodus
geöffnet, zeilenweise eingelesen, nach StdOut geschrieben, und so an
den Web-Client übermittelt.
Im nächsten Beispiel wollen wir mehrere Parameter an's CGI.cgi übergeben.
Außerdem sollen diese Parameter vom User vorgegeben werden können.
Zu diesem Zweck eigenen sich FORMS. Da hätten wir z.B.:
<html>
<body>
<center>
<form action='/cgi-bin/cgikurs/cgikurs3.cgi' method='post'>
Vorname <input type='text' name='Vorname' value='D.'><br>
Nachname <input type='text' name='Nachname' value='S.'><br>
<input type='submit' value='Sende zu CGIKURS3.cgi'><br>
</form>
</center>
</body>
</html>
|
(=>
cgikurs3.html)
Man beachte das Attribut method="post" im FORM-Tag.
Dadurch werden alle Usereingaben als StdInput an das CGI-EXE gesendet,
statt sie in die auf 255 Zeichen beschränkten Parameterliste abzulegen
(dies ließe sich durch das GET-Attribut erreichen). Das zugehörige
Delphi-Programm ist folgendermaßen aufgebaut:
program cgikurs3;
{$apptype console}
uses
forms,windows,sysutils,classes;
VAR
s,p:string;
cl,c:integer;
ch:char;
pc:array[0..10]of char;
procedure GetInput(var s:string);
begin
getenvironmentvariable('CONTENT_LENGTH',pc,255);
cl:=strtoint(strpas(pc));
for c:=1 to cl do begin
read(ch);
s:=s+ch;
end;
end;
begin
GetInput(s);
c:=pos('&',s);
writeln('Content-type: text/html');
writeln;
writeln;
writeln('<html><body><center>');
writeln(copy(s,1,c-1)+'<br>');
writeln(copy(s,c+1,length(s)-c)+'<br>');
writeln('</center></body></html>');
end.
|
Das ist schon etwas anspruchsvoller. Zunächst wird die Länge des
StdInput-Streams über eine WWW-Umgebungsvariable ermittelt. Dies
geschieht über
getenvironmentvariable('CONTENT_LENGTH',pc,255);
cl:=strtoint(strpas(pc));
|
Danach wird der Eingabestrom Zeichen für Zeichen nach s
eingelesen. Die einzelnen Usereingaben sind im Eingabestrom jeweils
durch ein &-Zeichen voneinander getrennt. Die Position von
& zwischen unseren beiden Eingabefeldern wird mit ...
... ermittelt. Anschließend werden beide Inputs über ...
writeln(copy(s,1,c-1)+'<br>');
writeln(copy(s,c+1,length(s)-c)+'<br>');
|
... getrennt voneinander ausgegeben und an den Web-Client zurückgesandt.
Gut, kommen wir nun zu einem Beispiel mit praktischerem Nutzen: Eine
Suchmaschine! Naja, eine Minisuchmaschine zumindestens. Gehen
wir von folgender Datenbank namens db.txt aus:
C
10
C++
12
COBOL
4
Delphi
15
FORTRAN
6
|
Unsere Suchformular sieht so aus:
<html>
<body>
<center>
<b>Programmiersprachen</b><br>
<form action='/cgi-bin/cgikurs/cgikurs4.cgi' method='post'>
Sprachname enthält <input type='text' name='Name' value='c'><br>
Sprache hat mehr Punkte als
<SELECT NAME='Mindestpunkte'>
<OPTION>0</OPTION>
<OPTION>5</OPTION>
<OPTION>10</OPTION>
<OPTION>15</OPTION>
</SELECT>
<br>
<input type='submit' value='Selektiere aus DB.TXT'><br>
</form>
</center>
</body>
</html>
|
(=>
cgikurs4.html)
Und unser Delphi-Programm so:
program cgikurs4;
{$apptype console}
uses
forms,windows,sysutils,classes;
const
_dbfn='db.txt';
VAR
homedir,s,pname,mpunkte,dbname,dbpunkte:string;
cl,c:integer;
ch:char;
pc:array[0..10]of char;
tf:textfile;
procedure GetInput(var s:string);
begin
getenvironmentvariable('CONTENT_LENGTH',pc,255);
cl:=strtoint(strpas(pc));
for c:=1 to cl do begin
read(ch);
s:=s+ch;
end;
end;
begin
homedir:=extractfilepath(application.exename);
GetInput(s);
c:=pos('&',s);
pname:=copy(s,1,c-1);
mpunkte:=copy(s,c+1,length(s)-c);
writeln('Content-type: text/html');
writeln;
writeln;
writeln('<html><body><center>');
writeln(
'Suche nach: <b>'+pname+' '+mpunkte+
'</b> Gefunden wurden:<br>'
);
writeln('<table border=1 cellpadding=5 cellspacing=0>');
writeln(
'<tr bgcolor=a0a0a0><th>Sprache</th><th>Punkte</th><tr>'
);
pname:=uppercase(copy(pname,pos('=',pname)+1,length(pname)));
mpunkte:=copy(mpunkte,pos('=',mpunkte)+1,length(mpunkte));
assignfile(tf,homedir+_dbfn);
reset(tf);
while not eof(tf) do begin
readln(tf,dbname);
readln(tf,dbpunkte);
if
((pos(pname,uppercase(dbname))<>0)or(pname=''))and
(strtoint(dbpunkte)>=strtoint(mpunkte))
then
writeln(
'<tr bgcolor=d0d0d0><th>'+dbname+'</th>'+
'<th>'+dbpunkte+'</th></tr>'
);
end;
closefile(tf);
writeln('</Table></center></body></html>');
end.
|
Ja, das ist schon ein etwas dickerer Brocken. Zunächst filtern wir
wieder zwei Eingabevariablen aus dem Eingabestrom.
GetInput(s);
c:=pos('&',s);
pname:=copy(s,1,c-1);
mpunkte:=copy(s,c+1,length(s)-c);
|
Etwas später isolieren wir aus diesen Strings die Teilstrings, die
nach dem =-Zeichen beginnen.
pname:=uppercase(copy(pname,pos('=',pname)+1,length(pname)));
mpunkte:=copy(mpunkte,pos('=',mpunkte)+1,length(mpunkte));
|
Anschließend öffnen wir die Datenbank und prüfen, ob die Kriterien
mit den Usereingaben übereinstimmen.
((pos(pname,uppercase(dbname))<>0)or(pname=''))and
(strtoint(dbpunkte)>=strtoint(mpunkte))
|
Wenn ja, wird der Eintrag ausgegeben, ansonsten ignoriert. Und um
das ganze optisch etwas ansprechender zu machen, wird noch eine
Table um die Ausgabe verpackt. That's it.
|