Home

News

Software
  - HTML
  - DHTML
  - Javascript
  - CGI
  - VRML
  - Linux
  - Dirty-Progs
    - CSS-DIV-Slicer
    - Sprite-Painter
    - FLV-CCC
    - CPU-Eater
    - Pixel-Evolution
    - MediaPanelyzer
    - OpenGL ISS
    - OpenGL Planets
    - PicOfPics
    - OpenGL Henrys
    - VidSplitt

  - PHP
    - Src2Textarea
    - Volltext-Suche
    - Hilfsfunktionen

Bilder

Texte

Alles fliesst

Comics

Musik

Leben

Links

Sitemap

Admin


Zahlreiche Auktionen bei
Henrys Auktionshaus

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

command:=paramstr(1);


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 ...

c:=pos('&',s);


... 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.


| Home | News | Software | HTML | DHTML | Javascript | CGI | VRML | Linux | Dirty-Progs | CSS-DIV-Slicer | Sprite-Painter | FLV-CCC | CPU-Eater | Pixel-Evolution | MediaPanelyzer | OpenGL ISS | OpenGL Planets | PicOfPics | OpenGL Henrys | VidSplitt | PHP | Src2Textarea | Volltext-Suche | Hilfsfunktionen | Bilder | Texte | Alles fliesst | Comics | Musik | Leben | Links | Sitemap | Admin |

© by DanPHPEd - Letzte Änderung: 08. Mai 2009