Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
Vorwort des Gutachters
1 Einstieg in C
2 Das erste Programm
3 Grundlagen
4 Formatierte Ein-/Ausgabe mit »scanf()« und »printf()«
5 Basisdatentypen
6 Operatoren
7 Typumwandlung
8 Kontrollstrukturen
9 Funktionen
10 Präprozessor-Direktiven
11 Arrays
12 Zeiger (Pointer)
13 Kommandozeilenargumente
14 Dynamische Speicherverwaltung
15 Strukturen
16 Ein-/Ausgabe-Funktionen
17 Attribute von Dateien und das Arbeiten mit Verzeichnissen (nicht ANSI C)
18 Arbeiten mit variabel langen Argumentlisten – <stdarg.h>
19 Zeitroutinen
20 Weitere Headerdateien und ihre Funktionen (ANSI C)
21 Dynamische Datenstrukturen
22 Algorithmen
23 CGI mit C
24 MySQL und C
25 Netzwerkprogrammierung und Cross–Plattform-Entwicklung
26 Paralleles Rechnen
27 Sicheres Programmieren
28 Wie geht’s jetzt weiter?
A Operatoren
B Die C-Standard-Bibliothek
Stichwort

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch
Buch: C von A bis Z

C von A bis Z
3., aktualisierte und erweiterte Auflage, geb., mit CD und Referenzkarte
1.190 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1411-7
Pfeil 23 CGI mit C
Pfeil 23.1 Was ist CGI?
Pfeil 23.2 Vorteile von CGIs in C
Pfeil 23.3 Andere Techniken der Webprogrammierung
Pfeil 23.4 Das dreistufige Webanwendungsdesign
Pfeil 23.4.1 Darstellungsschicht
Pfeil 23.4.2 Verarbeitungsschicht
Pfeil 23.4.3 Speicherschicht
Pfeil 23.5 Clientseitige Programmierung
Pfeil 23.5.1 JavaScript
Pfeil 23.5.2 Java-Applets
Pfeil 23.6 Serverseitige Programmierung
Pfeil 23.7 Der Webserver
Pfeil 23.7.1 Das Client/Server-Modell des Internets
Pfeil 23.7.2 Serverimplementierung
Pfeil 23.7.3 Hosting-Services
Pfeil 23.7.4 Schlüsselfertige Lösung
Pfeil 23.7.5 Weitere Möglichkeiten
Pfeil 23.7.6 Apache
Pfeil 23.8 Das HTTP-Protokoll
Pfeil 23.8.1 Web-Protokolle
Pfeil 23.8.2 Wozu dienen Protokolle?
Pfeil 23.8.3 Was ist ein Protokoll?
Pfeil 23.8.4 Normen für die Netzwerktechnik
Pfeil 23.8.5 Das OSI-Schichtenmodell
Pfeil 23.8.6 Die Elemente einer URL
Pfeil 23.8.7 Client-Anfrage – HTTP-Request (Browser-Request)
Pfeil 23.8.8 Serverantwort (Server-Response)
Pfeil 23.8.9 Zusammenfassung
Pfeil 23.9 Das Common Gateway Interface (CGI)
Pfeil 23.9.1 Filehandles
Pfeil 23.9.2 CGI-Umgebungsvariablen
Pfeil 23.9.3 CGI-Ausgabe
Pfeil 23.10 HTML-Formulare
Pfeil 23.10.1 Die Tags und ihre Bedeutung
Pfeil 23.11 CGI-Eingabe
Pfeil 23.11.1 Die Anfrage des Clients an den Server
Pfeil 23.11.2 Eingabe parsen
Pfeil 23.12 Ein Gästebuch
Pfeil 23.12.1 Das HTML-Formular (»guestbook.html«)
Pfeil 23.12.2 Das CGI-Programm (»auswert.cgi«)
Pfeil 23.12.3 Das HTML-Gästebuch (»gaeste.html«)
Pfeil 23.13 Ausblick


Rheinwerk Computing - Zum Seitenanfang

23.11 CGI-Eingabe Zur nächsten ÜberschriftZur vorigen Überschrift


Rheinwerk Computing - Zum Seitenanfang

23.11.1 Die Anfrage des Clients an den Server Zur nächsten ÜberschriftZur vorigen Überschrift

In den Abschnitten zur Client-Anfrage und zu den Formular-Tags habe ich die zwei vorwiegend in der Praxis eingesetzten Methoden zum Empfangen von Daten schon erwähnt (POST, GET). Diese Methoden werde ich jetzt anhand des folgenden HTML-Formulars genauer erläutern:

<html>
<head>
<title>Eine einfache Auswertung</title>
</head>
<body>
<h1><center>
<b><u>Formular</u></b></center></h1><br><br>
<form action=http://localhost/cgi-bin/auswert.cgi method=get>
   <center><b>Bitte geben Sie Ihren Namen ein :</b><br>
   <input name="Textfeld" size="20"> </input>
   <input type=submit value="abschicken"></center>
</form>
</body>
</html>

So sieht es aus:

Abbildung 23.20 Eingabeformular

Von ganz besonderem Interesse ist hier das <form>-Tag. Sobald Sie auf den Button abschicken klicken, wird mit dem Attribut action ein Prozess, nämlich die CGI-Anwendung auswert.cgi, auf dem Webserver gestartet. Darin unterscheiden sich beide Methoden nicht. Da im HTML-Beispiel hier die Methode GET (method=get) verwendet wurde, soll diese auch als Erste behandelt werden.

Arbeitsweise von GET

Bei der GET-Methode hängt der Browser die Zeichenkette am Ende der URL an. Bei einer Eingabe der Zeichenkette "hallo" hat die URL folgendes Aussehen:

Der Webserver ist jetzt dafür verantwortlich, diese Zeichenkette wieder zu entfernen, und übergibt diese an die Umgebungsvariable QUERY_STRING:

QUERY_STRING = Textfeld=hallo

Jetzt sind Sie an der Reihe, mit dem CGI-Programm die Umgebungsvariable QUERY_STRING auszuwerten. Die GET-Möglichkeit stellt dabei die einfachste Art dar. Es herrscht hierbei immer noch der Irrglaube, dass mit der GET-Methode nur 255 bzw. 1024 Bytes verarbeitet werden können. Diese Größe wird aber vom Webserver vorgegeben und beträgt mindestens 255 Bytes bis zu 8192 Bytes.

Arbeitsweise von POST

Wollen Sie statt der Methode GET die Methode POST verwenden, müssen Sie nur im HTML-Formular die Zeile

<form action="http://... /cgi-bin/auswert.cgi" method=get>

umändern in:

<form action="http://.. /cgi-bin/auswert.cgi" method=post >

Bei der POST-Methode werden die Daten nicht in einer der Umgebungsvariablen abgelegt, sondern in der Standardeingabe (stdin). Sie können somit die CGI-Anwendung so schreiben, als würde die Eingabe von der Tastatur gemacht. Die Länge des kodierten Strings befindet sich in der Umgebungsvariablen CONTENT_LENGTH.

Außerdem wird noch die Umgebungsvariable CONTENT_TYPE verwendet, damit die CGI-Anwendung weiß, um was für eine Art Dokument es sich handelt.

POST- oder GET-Methode programmtechnisch auswerten

Damit die CGI-Anwendung jetzt weiß, ob die Daten mit der Methode GET oder POST gesendet wurden, benötigen Sie eine Funktion, die die Umgebungsvariable REQUEST_METHOD auswertet und den Inhalt (String), sei es nun vom QUERY_STRING oder von der Standardeingabe, an den Aufrufer zurückgibt.

/*  Funktion liest Daten in der POST- oder GET-Methode ein.
 *  Rückgabewert: String puffer mit den Daten

 *  bei Fehler  : NULL
*/
char *getdata(void) {
   unsigned long size;
   char *puffer = NULL;
   char *request = getenv("REQUEST_METHOD");
   char *cont_len;
   char *cgi_string;

   /* zuerst die Request-Methode überprüfen */
   if(  NULL == request )
      return NULL;
   else if( strcmp(request, "GET") == 0 ) {
      /* die Methode GET -> Query String abholen */
      cgi_string = getenv("QUERY_STRING");
      if( NULL == cgi_string )
         return NULL;
      else {
         puffer =(char *) Strdup(cgi_string);
         return puffer; /* Rückgabewert an den Aufrufer */
      }
   }
   else if( strcmp(request, "POST") == 0 ) {
      /* die Methode POST -> Länge des Strings
       * ermitteln (CONTENT_LENGTH) */
      cont_len = getenv("CONTENT_LENGTH");
      if( NULL == cont_len)
         return NULL;
      else {
         /* String CONTENT_LENGTH in
          * unsigned long umwandeln */
         size = (unsigned long) atoi(cont_len);
         if(size <= 0)
            return NULL; /* Keine Eingabe!?!? */
      }
      /* jetzt lesen wir die Daten von stdin ein */
      puffer = (char *) malloc(size+1);
      if( NULL == puffer )
         return NULL;
      else {
         if( NULL == fgets(puffer, size+1, stdin) ) {
            free(puffer);
            return NULL;
         }
         else  /* Rückgabewerte an den Ausrufer */
            return puffer;
      }
   }
   else /*  Weder die GET- noch die POST-Methode
         *  wurden verwendet. */
      return NULL;
}

/*  Da die Funktion strdup() in der Headerdatei <string.h> keine
 *  ANSI-C-Funktion ist, schreiben wir eine eigene.
 */
char *Strdup(const char *str) {
   char *p;

   if(NULL == str)
      return NULL;
   else {
      p = malloc(strlen(str)+1);
      if(NULL == p)
         return NULL;
      else
         strcpy(p, str);
   }
   return p;
}

Es wurde außerdem eine extra Funktion für Strdup() geschrieben, da die vorhandene strdup() in der Headerdatei <string.h> nicht zum ANSI-C-Standard gehört. Sie können diese eben erstellten Funktionen gern in einer CGI-Anwendung testen und ausführen. Falls Sie die CGI-Anwendung getestet und etwa folgende Eingabe in einem Webformular gemacht haben:

Jürgen "pronix" Wolf

erscheint anschließend im Webbrowser folgende Zeile:

Textfeld=J%FCrgen+%22pronix%22+Wolf

Wir sind also noch ein wenig vom gewünschten Ergebnis entfernt.


Rheinwerk Computing - Zum Seitenanfang

23.11.2 Eingabe parsen topZur vorigen Überschrift

Sie können zwar jetzt die Eingabe vom Client empfangen, aber Sie müssen den String noch lesefreundlich dekodieren. Hier folgt ein Überblick zu den Zeichen, die eine besondere Bedeutung haben und die Sie als Programmierer von CGI-Anwendungen berücksichtigen müssen.

  • & – Die einzelnen Formularelemente (sofern es mehrere sind) werden mit diesem Zeichen getrennt.
  • = – Mit diesem Zeichen werden die Variable/Wert-Paare voneinander getrennt.
Textfeld J%FCrgen+%22pronix%22+Wolf
  • + – Damit werden die Leerzeichen der eingegebenen Daten getrennt.
Textfeld J%Fcrgen %22pronix%22 Wolf
  • %XX – Bei einem Prozentzeichen, auf das zwei hexadezimale Ziffern folgen, handelt es sich um ASCII-Zeichen mit dem dezimalen Wert von 128 bis 255. Diese hexadezimalen Ziffern müssen in ASCII-Zeichen dekodiert werden.
Textfeld Jürgen pronix Wolf

In Tabelle 23.18 finden Sie Steuerzeichen und weitere Zeichen sowie ihre hexadezimale Darstellung im Überblick:


Tabelle 23.18 Kodierte Zeichen und ihre Bedeutung

Zeichen Hexadezimale Darstellung

Tab

%09

Space

%20

"

%22

#

%23

%

%25

&

%26

(

%28

)

%29

'

%2C

.

%2E

/

%2F

:

%3A

;

%3B

<

%3C

=

%3D

>

%3E

?

%3F

@

%40

[

%5B

\

%5C

]

%5D

^

%5E

,

%60

{

%7B

|

%7C

}

%7D

~

%7E


Jetzt wollen Sie natürlich auch wissen, wie Sie dies in der Praxis dekodieren können. Folgende Funktionen sind dazu zunächst nötig:

  • kodierte Zeichen (Prozentzeichen, gefolgt von zwei Hexzahlen) dekodieren
  • alle Leerzeichen, die mit + angegeben sind, in ein echtes Leerzeichen konvertieren

Alle anderen Schritte folgen in den nächsten Funktionen. Betrachten wir zunächst die Funktionen, mit denen die hexadezimalen Zahlen in ASCII-Werte und die +-Zeichen in echte Leerzeichen konvertiert werden:

/* Wandelt einzelne Hexzeichen (%xx) in ASCII-Zeichen
 * und kodierte Leerzeichen (+) in echte Leerzeichen um. */
void hex2ascii(char *str)  {
   int x, y;


   for(x=0,y=0; str[y] != '\0'; ++x,++y) {
      str[x] = str[y];
      /* Ein hexadezimales Zeichen? */
      if(str[x] == '%')  {
         str[x] = convert(&str[y+1]);
         y += 2;
      }
      /* Ein Leerzeichen? */
      else if( str[x] == '+')
         str[x]=' ';
   }
   /* geparsten String sauber terminieren */
   str[x] = '\0';
}

/* Funktion konvertiert einen String von zwei hexadezimalen
 * Zeichen und gibt das einzelne dafür stehende Zeichen zurück. */
char convert(char *hex) {
   char ascii;

   /* erster Hexawert */
   ascii =
   (hex[0] >= 'A' ? ((hex[0] & 0xdf) - 'A')+10 : (hex[0] - '0'));

   ascii <<= 4; /* Bitverschiebung schneller als ascii*=16 */
   /* zweiter Hexawert */
   ascii +=
   (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A')+10 : (hex[1] - '0'));
   return ascii;
}

Sollten Sie die Funktionen wieder in der Praxis testen wollen, können Sie dies tun. Jetzt bekommen Sie die Eingabe des Formulars im Klartext ausgegeben:

Textfeld=Jürgen "pronix" Wolf

Im nächsten Schritt benötigen Sie eine Funktion, die diese beiden Werte auseinanderhält und zwischenspeichert. In diesem Beispiel wurde nur eine Variable (Textfeld) mit dem Wert (Jürgen "pronix" Wolf) verwendet. Die nun folgende Funktion sollte in diesem Zusammenhang allgemeingültig und auch später wiederverwendbar sein. Daher kommen Sie nicht um die Programmierung einer dynamischen Liste herum. Folgende Struktur soll hierfür verwendet werden:

struct CGI_DATEN {
   char *variable;
   char *wert;
   struct CGI_DATEN *next;
};

struct CGI_DATEN *ende = NULL;

Die Daten einer einzelnen CGI-Eingabe werden anhand des '='-Zeichens getrennt (variable=wert). Somit muss dieses Zeichen auch geparst werden. Und für den Fall (so ist es meistens), dass mehrere Variablen/Werte-Paare übermittelt werden, müssen Sie auch das Zeichen '&' parsen, das die Paare voneinander trennt (variable1=wert&variable2=wert). Eine Menge Arbeit liegt damit vor Ihnen. Hier sehen Sie die komplette Funktion:

struct CGI_DATEN *erstellen(char *str) {
   char* s;
   char* res;
   /* Irgendwo gibt es auch eine Grenze, hier sind
    * MAX_PAARE erlaubt. */
   char *paare[MAX_PAARE];
   struct CGI_DATEN *ptr_daten = NULL;
   struct CGI_DATEN *ptr_anfang = NULL;
   int i=0, j=0;

   /* Zuerst werden die Variablen/Werte-Paare anhand
    * des Zeichens '&' getrennt, sofern es mehrere sind. */
   s=str;
   res=strtok(s,"&");
   while( res != NULL && i < MAX_PAARE) {
      /* Wert von res dynamisch in char **pair speichern. */
      paare[i] = (char *)malloc(strlen(res)+1);
      if(paare[i] == NULL)
         return NULL;
      paare[i] = res;
      res=strtok(NULL,"&");
      i++;
   }

   /* Jetzt werden die Variablen von den Werten getrennt und
    * an die Struktur CGI_DATEN übergeben. */
   while ( i > j ) { /* Das erste Element? */
      if(ptr_anfang == NULL) {
         ptr_anfang =(struct CGI_DATEN *)
           malloc(sizeof (struct CGI_DATEN *));
         if( ptr_anfang == NULL )
            return NULL;
         res = strtok( paare[j], "=");
         ptr_anfang->variable = malloc(strlen(res)+1);
         if( ptr_anfang->variable == NULL )
            return NULL;
         ptr_anfang->variable = res;
         res = strtok(NULL, "\0");
         ptr_anfang->wert = malloc(strlen(res)+1);
         if( ptr_anfang->wert == NULL )
            return NULL;
         ptr_anfang->wert = res;
         /* printf("%s %s<br>",
          * ptr_anfang->variable, ptr_anfang->wert); */
         ptr_anfang->next = malloc(sizeof (struct CGI_DATEN *));
         if(ptr_anfang->next == NULL)
            return NULL;
         ptr_daten = ptr_anfang->next;
         j++;
      }
      else { /* die restlichen Elemente */
         res = strtok( paare[j], "=");
         ptr_daten->variable = malloc(strlen(res)+1);
         if(ptr_daten->variable == NULL)
            return NULL;
         ptr_daten->variable = res;
         res = strtok(NULL, "\0");
         ptr_daten->wert = malloc(strlen(res)+1);
         if(ptr_daten->wert == NULL)
            return NULL;
         ptr_daten->wert = res;
         /* printf("%s %s<br>",
          * ptr_daten->variable, ptr_daten->wert); */
         ptr_daten->next = malloc(sizeof (struct CGI_DATEN *));
         if( ptr_daten->next == NULL )
            return NULL;
         ptr_daten = ptr_daten->next;
         j++;
      }
   }
   ende = ptr_daten;
   /* Anfangsadresse der Liste struct CGI_DATEN zurückgeben */
   return ptr_anfang;
}

Hiermit haben Sie eine Funktion erstellt, die für alle Fälle gerüstet ist. Jetzt benötigen Sie nur noch eine Funktion, die den Speicherplatz der dynamischen Liste wieder freigibt. Diese finden Sie im folgenden Programmbeispiel.



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: C von A bis Z

 C von A bis Z
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: C/C++






 C/C++


Zum Rheinwerk-Shop: Einstieg in C






 Einstieg in C


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern