CGI's (Common Gateway Interface) ist einfach Ausgedrückt eine Schnittstelle, womit man Anwendungen für das Internet schreiben kann. Diese CGI-Anwendung laufen dabei auf einem (Web)Server (wie Beispielsweise dem Apache) und wird von einer HTML-Webseite angesteuert. Die Daten erhält diese CGI-Anwendung entweder von der HTML-Seite selbst (POST-Verfahren) oder direkt über die URL (GET-Verfahren). C C++ C/C++ CGI mit C CGI Skripte in C CGI mit C- CGI Skripte in C Kapitel 28: MySQL und C

28.5. MySQL und C mit CGI            zurück  Ein Kapitel tiefer  zum Inhaltsverzeichnis

Zum Abschluss soll wie versprochen ein Beispiel erstellt werden, bei dem Sie mithilfe eines CGI-Webformulars eine Datenbank mit E-Mail-Adressen füttern. Auf diese Weise erstellen Sie quasi eine grafische Oberfläche zum Bedienen einer Datenbank mithilfe des Webbrowsers.

Erzeugen Sie eine neue Datenbank mit dem Namen mail_archiv. Geben Sie dazu im mysql-Client Folgendes ein:

CREATE DATABASE mail_archiv;

Wechseln Sie in diese Datenbank mit USE und erstellen Sie eine Tabelle mit folgendem SQL-Kommando:

CREATE TABLE daten (adresse CHAR(255), name CHAR(255)); 

28.5.1 HTML-Eingabeformular
Als Nächstes sollten Sie die HTML-Datei erstellen, mit der Sie die Daten eingeben können. Hier die Datei:

<html>
<head>
<title>Datenbank</title>
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#FF0000" alink="#FF0000" vlink="#FF0000">
<h3>Datenbank (E-Mail-Adressen)</h3>

<hr><br>
<form action="http://localhost/cgi-bin/add_db.cgi" method=post>
Neuen Datensatz hinzufügen:
<pre>Name  : <input value="IhrName" name="Name" size="20">
E-Mail : <input value="adr@mail" name="E-Mail" size="20"></pre>
<input type=submit value="Hinzufügen">
</form>
<hr><br>
<form action=http://localhost/cgi-bin/search_db.cgi
      method=post>
In der Datenbank suchen:
<pre>Name   : <input value="IhrName" name="Name" size="20"></pre>
<input type=submit value="Suchen">
</form>
<hr>
</body>
</html>

Bei diesem HTML-Formular können zwei CGI-Anwendungen gestartet werden: zum einen das Einfügen neuer Daten in die Datenbank (add_db.cgi) und zum anderen das Suchen darin (search_db.cgi).

Abbildung 28.xx: HTML-Formular zur Eingabe oder Suche von Datensätzen
Abbildung 28.xx: HTML-Formular zur Eingabe oder Suche von Datensätzen

28.5.2 CGI-Anwendung add_db.cgi
Zuerst wird die CGI-Anwendung zum Hinzufügen neuer Datensätze in die Datenbank geschrieben. Dabei finden Sie wieder alte bekannte Funktionen aus den Abschnitten zu CGI und C. Ich habe mich entschlossen, das Listing hier vollständig zu schreiben, da ich es auch nicht mag, ständig in einem Buch hin- und her zu blättern.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined __WIN32__ || _MSC_VER
    #include <windows.h>
#endif
#include <mysql.h>
// Für VC++:
//#include "c:\mysql\include\mysql.h"

#define MAX_PAARE 255
#define BUF 255

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

struct CGI_DATEN *ende = NULL;

MYSQL *mysql;

void print_html();
char *getdata();
char *Strdup(const char *);
void hex2ascii(char *);
char convert(char *);
void loeschen(struct CGI_DATEN *);
struct CGI_DATEN *erstellen(char *);
void check_error();
void verbinden();
void verbindung_schliessen();

/* Weiterleitung zu einer URL
 * url ist die URL, wo Sie den User weiterleiten
 */
void print_html()
{
   printf("<html><head>\n");
   printf("<title>Eintragsbestätigung</title>\n");
   printf("</head><body>\n");
   printf("Eintragung erfolgreich. Zurück gehts"
          " <a href=\"javascript:history.back()\">hier</a>");
   printf("</body></html>\n");
}

/*
 *  Funktion liest Daten in der POST oder GET-Methode ein.
 *  Rückgabewert: Stringpuffer mit den Daten
 *  bei Fehler  : NULL
*/
char *getdata()
{
   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;
            }
      }
   /* Weder GET-Methode noch die POST-Methode wurden verwendet */
   else
      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 =(char *) malloc(strlen(str)+1);
         if(NULL == p)
            return NULL;
         else
            strcpy(p, str);
      }
   return p;
}

/* 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;
}

/* Liste aus Variable/Wert-Paaren erstellen
 * Rückgabewert: Anfangsadresse der Liste
 * Bei Fehler: NULL
 */
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], "=");
              if(res == NULL)
                 return NULL;
              ptr_anfang->variable =(char *)
                                    malloc(strlen(res)+1);
              if( ptr_anfang->variable == NULL )
                 return NULL;
              ptr_anfang->variable = res;
              res = strtok(NULL, "\0");
              if(res == NULL)
                 return NULL;
              ptr_anfang->wert =(char *) malloc(strlen(res)+1);
              if( ptr_anfang->wert == NULL )
                 return NULL;
              ptr_anfang->wert = res;
              /* printf("%s %s<br>",ptr_daten->variable,
                                   ptr_daten->wert); */
              ptr_anfang->next = (struct CGI_DATEN *)
                        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], "=");
              if(res == NULL)
                 return NULL;
              ptr_daten->variable =(char *)
                                   malloc(strlen(res)+1);
              if(ptr_daten->variable == NULL)
                 return NULL;
              ptr_daten->variable = res;
              res = strtok(NULL, "\0");
              if(res == NULL)
                 return NULL;
              ptr_daten->wert =(char *) 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 = (struct CGI_DATEN *)
                       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;
}


/* Bricht bei Fehler (mysql_error != 0) das Programm ab */
void check_error()
{
   if (mysql_errno(mysql) != 0)
      {
         fprintf(stderr, "Fehler: %s\n", mysql_error(mysql));
         exit(1);
      }
}

/* Baut eine Verbindung zum Datenbankserver auf.
 * Passen Sie ggf. Usernamen und Passwort und, sofern
 * andere Parameter benötigt werden, diese Ihren Umständen
 * selbst an
*/
void verbinden()
{
   mysql= mysql_init(mysql);
   check_error();
   mysql_real_connect(mysql, "localhost", "root", NULL, NULL, 0, NULL, 0);
   check_error();
}

/* Serververbindung wieder schließen und den Speicher für die
   Struktur MYSQL wieder freigeben */
void verbindung_schliessen()
{
   mysql_close(mysql);
}

/* Falls Datenbank bei der Funktion verbinden() nicht angegeben
   wurde oder Sie die Datenbank wechseln wollen, dann verwenden
   Sie diese Funktion */
void db_waehlen(char *db)
{
   mysql_select_db(mysql, db);
   check_error();
}

/* Daten mit mysql_query() in die Datenbank schreiben */
void daten_anfuegen(struct CGI_DATEN *daten)
{
   char buf[BUF] = "INSERT INTO daten (name, adresse) VALUES ('";
   strcat(buf, daten->wert);
   strcat(buf, "', '");
   daten = daten->next;
   strcat(buf, daten->wert);
   strcat(buf, "');");

   /* Jetzt die Anfrage an den Datenbankserver */
   mysql_query(mysql, buf);
   check_error();
}

int main()
{
   char *str;
   struct CGI_DATEN *cgi;
   struct CGI_DATEN *free_cgi;
   /* Für Fehlermeldungen */
   printf("Content-Type: text/html\n\n");

   /* Eingabe einlesen */
   str = getdata();
   if(str == NULL)
      {
         printf("Fehler beim Einlesen von der Formulareingabe");
         return 0;
      }
   /* Hexzeichen in ASCII-Zeichen konvertieren und aus '+'
      Leerzeichen machen */
   hex2ascii(str);
   /* Liste der Formualar-Daten erstellen */
   cgi = erstellen(str);
   free_cgi = cgi;
   if (cgi == NULL)
      {
          printf("Fehler beim Erstellen der "
                 "Variablen/Werte-Liste!!\n");
          return 0;
      }
   verbinden();
   db_waehlen("mail_archiv");
   daten_anfuegen(cgi);

   verbindung_schliessen();
   print_html();
   return 0;
}

Übersetzen Sie den Quellcode wieder wie gewohnt, ändern Sie die Extension (*.cgi) und speichern Sie die ausführbare Datei im cgi-bin-Verzeichnis des (Apache-) Webservers. Unter Linux werden dafür teilweise root-Rechte benötigt. Ändern Sie außerdem unter Linux die Zugriffsrechte für diese Datei (chmod go+rx add_db.cgi). Weiteres finden Sie in Kapitel 27, CGI mit C, welches Sie bereits durchgenommen haben sollten, bevor Sie sich an dieses Programm wagen.

28.5.3 CGI-Anwendung search_db.cgi
Als Nächstes folgt die CGI-Anwendung zur Suche in der Datenbank mail_archiv, welche im Großen und Ganzen ebenfalls nichts Neues mehr enthält, was nicht bereits besprochen wurde.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined __WIN32__ || _MSC_VER
    #include <windows.h>
#endif
#include <mysql.h>
// Für VC++:
//#include "c:\mysql\include\mysql.h"

#define MAX_PAARE 255
#define BUF 255

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

struct CGI_DATEN *ende = NULL;

MYSQL *mysql;

void print_html();
char *getdata();
char *Strdup(const char *);
void hex2ascii(char *);
char convert(char *);
void loeschen(struct CGI_DATEN *);
struct CGI_DATEN *erstellen(char *);
void check_error();
void verbinden();
void verbindung_schliessen();

/* Weiterleitung zu einer URL
 * url ist die URL, wo Sie den User weiterleiten
 */
void print_html()
{
   printf("<html><head>\n");
   printf("<title>Suchergebniss</title>\n");
   printf("</head><body>\n");
   printf("<br><br>Zurück gehts "
          "<a href=\"javascript:history.back()\">hier</a>");
   printf("</body></html>\n");
}

/*
 *  Funktion liest Daten in der POST oder GET-Methode ein.
 *  Rückgabewert: Stringpuffer mit den Daten
 *  bei Fehler  : NULL
*/
char *getdata()
{
   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;
         /* String CONTENT_LENGTH in unsigned long umwandeln */
         else
            {
               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;
            }
      }
   /* Weder GET-Methode noch die POST-Methode wurden verwendet */
   else
      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 = (char *)malloc(strlen(str)+1);
         if(NULL == p)
            return NULL;
         else
            strcpy(p, str);
      }
   return p;
}

/* 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;
}

/* Liste aus Variable/Wert-Paaren erstellen
 * Rückgabewert: Anfangsadresse der Liste
 * Bei Fehler: NULL
 */
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], "=");
               if(res == NULL)
                  return NULL;
               ptr_anfang->variable = (char *)
                                 malloc(strlen(res)+1);
               if( ptr_anfang->variable == NULL )
                  return NULL;
               ptr_anfang->variable = res;
               res = strtok(NULL, "\0");
               if(res == NULL)
                  return NULL;
               ptr_anfang->wert = (char *)
                                      malloc(strlen(res)+1);
               if( ptr_anfang->wert == NULL )
                  return NULL;
               ptr_anfang->wert = res;
               /* printf("%s %s<br>",ptr_daten->variable,
                                    ptr_daten->wert); */
               ptr_anfang->next = (struct CGI_DATEN *)
                        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], "=");
               if(res == NULL)
                  return NULL;
               ptr_daten->variable =(char *)
                                malloc(strlen(res)+1);
               if(ptr_daten->variable == NULL)
                  return NULL;
               ptr_daten->variable = res;
               res = strtok(NULL, "\0");
               if(res == NULL)
                  return NULL;
               ptr_daten->wert = (char *)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 = (struct CGI_DATEN *)
                        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;
}


/* Bricht bei Fehler (mysql_error != 0) das Programm ab */
void check_error()
{
   if (mysql_errno(mysql) != 0)
      {
         fprintf(stderr, "Fehler: %s\n", mysql_error(mysql));
         exit(1);
      }
}

/* Baut eine Verbindung zum Datenbankserver auf.
 * Passen Sie ggf. Usernamen und Passwort und, sofern
 * andere Parameter benötigt werde, diese Ihren Umständen
 * selbst an
*/
void verbinden()
{
   mysql= mysql_init(mysql);
   check_error();
   mysql_real_connect(mysql, "localhost", "root",
                      NULL, NULL, 0, NULL, 0);
   check_error();
}

/* Serververbindung wieder schließen und den Speicher für die
   Struktur MYSQL wieder freigeben */
void verbindung_schliessen()
{
   mysql_close(mysql);
}

/* Falls Datenbank bei der Funktion verbinden() nicht angegeben
   wurde oder Sie die Datenbank wechseln wollen, dann verwenden
   Sie diese Funktion */
void db_waehlen(char *db)
{
   mysql_select_db(mysql, db);
   check_error();
}

/* Daten mit mysql_query() in die Datenbank schreiben */
void daten_suchen(struct CGI_DATEN *daten)
{
   MYSQL_ROW  row;
   MYSQL_RES  *mysql_res;
   unsigned long  anzahl_reihen;
   unsigned int i;
   char buf[BUF] = "SELECT adresse FROM daten WHERE name='";
   strcat(buf, daten->wert);
   strcat(buf, "';");

   mysql_query(mysql, buf);
   check_error();
   /* Daten der Anfrage abholen */
   mysql_res = mysql_store_result(mysql);
   check_error();
   /* Anzahl der gefundenen Datensätze ermitteln */
   anzahl_reihen = (unsigned long) mysql_num_rows (mysql_res);
   printf ("Anzahl gefunden: %lu\n\n<br><br>", anzahl_reihen);
   /* Gefundenen Datensatz bzw. Datensätze ausgeben */
   while ((row = mysql_fetch_row (mysql_res)) != NULL)
      { /* Einzelne Spalten der Zeile ausgeben */
         for (i = 0;  i < mysql_num_fields(mysql_res);  i ++)
            printf ("Addresse zu %s lautet %s<br> ",
                                         daten->wert,row[i]);
         printf("\n");
      }
   /* Speicherplatz wieder freigeben */
   mysql_free_result(mysql_res);
}

int main()
{
   char *str;
   struct CGI_DATEN *cgi;
   struct CGI_DATEN *free_cgi;
   /* Für Fehlermeldungen */
   printf("Content-Type: text/html\n\n");

   /* Eingabe einlesen */
   str = getdata();
   if(str == NULL)
      {
         printf("Fehler beim Einlesen von der Formulareingabe");
         return 0;
      }
   /* Hexzeichen in ASCII-Zeichen konvertieren und aus '+'
      Leerzeichen machen */
   hex2ascii(str);
   /* Liste der Formualar-Daten erstellen */
   cgi = erstellen(str);
   free_cgi = cgi;
   if (cgi == NULL)
      {
         printf("Fehler beim Erstellen der "
                "Variablen/Werte-Liste!!\n");
         return 0;
      }
   verbinden();
   db_waehlen("mail_archiv");
   daten_suchen(cgi);

   verbindung_schliessen();
   print_html();
   return 0;
}

Natürlich gilt auch hier: Übersetzen Sie den Quellcode wie gewohnt, ändern Sie die Extension (*.cgi) und speichern Sie die ausführbare Datei im cgi-bin-Verzeichnis des (Apache-) Webservers. Unter Linux werden dafür teilweise root-Rechte benötigt. Ändern Sie außerdem unter Linux die Zugriffsrechte für diese Datei (chmod go+rx search_db.cgi).

Das war es. Wenn Sie jetzt wollen, können Sie die CGI-Anwendungen mit MySQL in der Praxis testen. Öffnen Sie dazu mit Ihrem Webrowser das erstellte HTML-Formular. Jetzt können Sie munter Datensätze in die Datenbank einfügen oder in den Datensätzen suchen. Voraussetzung dafür, dass dies auch funktioniert, ist, dass der (Apache-) Webserver und der Datenbankserver MySQL gestartet wurden.

Mit diesem Beispiel haben Sie jetzt die Grundlagen für komplexere Aufgaben mit der MySQL-Datenbank geschaffen.

28.6. Funktionsübersicht            zurück  Ein Kapitel tiefer  Ein Kapitel höher  zum Inhaltsverzeichnis

Zum Abschluss dieses Kapitels werden hier nochmals die wichtigsten Funktionen der MySQL C-API für Referenzzwecke zusammengefasst.

Funktion Bedeutung
mysql_affected_rows() Gibt die Anzahl von Zeilen zurück, die durch die letzte UPDATE-, DELETE- oder INSERT-Anfrage geändert, gelöscht bzw. hinzugefügt wurden.
mysql_close() Schließt eine Serververbindung
mysql_connect() Stellt die Verbindung mit einem MySQL-Server her. Diese Funktion ist veraltet, benutzen Sie dafür mysql_real_connect().
mysql_change_user() Ändert Benutzer und Datenbank bei einer geöffneten Verbindung.
mysql_character_set_name() Gibt den Namen des vorgabemäßigen Zeichensatzes für die Verbindung zurück.
mysql_create_db() Erzeugt eine Datenbank. Diese Funktion ist veraltet, benutzen Sie stattdessen den SQL-Befehl CREATE DATABASE.
mysql_data_seek() Sucht bis zu einer beliebigen Zeile in einer Anfrage-Ergebnismenge.
mysql_debug() Macht ein DBUG_PUSH mit der angegebenen Zeichenkette.
mysql_drop_db() Löscht eine Datenbank. Diese Funktion ist veraltet, benutzen Sie stattdessen den SQL-Befehl DROP DATABASE.
mysql_dump_debug_info() Veranlasst den Server, Debug-Informationen in die Log-Datei zu schreiben.
mysql_eof() Stellt fest, ob die letzte Zeile der Ergebnismenge gelesen wurde oder nicht. Diese Funktion ist veraltet, benutzen Sie stattdessen mysql_errno() oder mysql_error().
mysql_errno() Gibt die Fehlernummer der zuletzt aufgerufenen MySQL-Funktion zurück.
mysql_error() Gibt die Fehlermeldung der zuletzt aufgerufenen MySQL-Funktion zurück.
mysql_real_escape_string() Escape-Sonderzeichen in einer Zeichenkette, die für ein SQL-Statement benutzt wird, wobei der aktuelle Zeichensatz der Verbindung berücksichtigt wird.
mysql_escape_string() Escape-Sonderzeichen in einer Zeichenkette, die für ein SQL-Statement benutzt wird.
mysql_fetch_field() Gibt den Typ des nächsten Tabellenfelds zurück.
mysql_fetch_field_direct() Gibt den Typ eines Tabellenfelds zurück, angegeben durch eine Feldnummer.
mysql_fetch_fields() Gibt ein Array aller Feldstrukturen zurück.
mysql_fetch_lengths() Gibt die Länge aller Spalten in der aktuellen Zeile zurück.
mysql_fetch_row() Holt die nächste Zeile aus der Ergebnismenge.
mysql_field_seek() Setzt den Spaltencursor auf eine bestimmte Spalte.
mysql_field_count() Gibt die Anzahl der Ergebnisspalten für die letzte Anfrage zurück.
mysql_field_tell() Gibt die Position des Feldcursors zurück, der für das letzte mysql_fetch_field() benutzt wurde.
mysql_free_result() Gibt Speicher frei, der von einer Ergebnismenge benutzt wird.
mysql_get_client_info() Gibt Client-Versionsinformationen zurück.
mysql_get_host_info() Gibt eine Zeichenkette zurück, welche die Verbindung beschreibt.
mysql_get_proto_info() Gibt die Protokollversion zurück, die von der Verbindung benutzt wird.
mysql_get_server_info() Gibt die Server-Versionsnummer zurück.
mysql_info() Gibt Informationen über die zuletzt ausgeführte Anfrage zurück.
mysql_init() Holt oder initialisiert eine MYSQL-Struktur.
mysql_insert_id() Gibt die Kennung zurück, die für eine AUTO_INCREMENT-Spalte durch die letzte Anfrage erzeugt wurde.
mysql_kill() Tötet einen angegebenen Thread.
mysql_list_dbs() Gibt die Datenbanknamen zurück, die mit einem einfachen regulären Ausdruck übereinstimmen.
mysql_list_fields() Gibt die Feldnamen zurück, die mit einem einfachen regulären Ausdruck übereinstimmen.
mysql_list_processes() Gibt eine Liste der aktuellen Server-Threads zurück.
mysql_list_tables() Gibt Tabellenamen zurück, die mit einem einfachen regulären Ausdruck übereinstimmen.
mysql_num_fields() Gibt die Anzahl von Spalten in einer Ergebnismenge zurück.
mysql_num_rows() Gibt die Anzahl von Zeilen in einer Ergebnismenge zurück.
mysql_options() Setzt Verbindungsoptionen für mysql_connect().
mysql_ping() Prüft, ob die Verbindung zum Server funktioniert oder nicht, und verbindet sich erneut, falls notwendig.
mysql_query() Führt eine SQL-Anfrage aus, die als NULL-begrenzte Zeichenkette angegeben wird.
mysql_real_connect() Verbindet sich mit einem MySQL-Server.
mysql_real_query() Führt eine SQL-Anfrage aus, die als gezählte Zeichenkette angegeben wird.
mysql_reload() Weist den Server an, die Berechtigungstabellen erneut zu laden.
mysql_row_seek() Sucht bis zu einer Zeile in einer Ergebnismenge, indem sie den Wert benutzt, der von mysql_row_tell() zurückgegeben wird.
mysql_row_tell() Gibt die Zeilencursorposition zurück.
mysql_select_db() Wählt eine Datenbank aus.
mysql_shutdown() Fährt den Datenbankserver herunter.
mysql_stat() Gibt den Serverstatus als Zeichenkette zurück.
mysql_store_result() Ruft eine vollständige Ergebnismenge zum Client ab.
mysql_thread_id() Gibt die aktuelle Thread-Kennung zurück.
mysql_thread_safe() Gibt 1 zurück, wenn die Clients Thread-sicher kompiliert sind.
mysql_use_result() Initialisiert den zeilenweisen Abruf einer Ergebnismenge.

Tabelle 28.11: Funktionsübersicht der MySQL-C-API

28.7. Datentypenübersicht der C API            zurück  Ein Kapitel höher  zum Inhaltsverzeichnis

Auch zu den eigenen Datentypen von MySQL und der C-API erfolgt hier ein kurzer Überblick.

Datentyp Bedeutung
MYSQL Handle einer Datenbankverbindung. Wird für fast alle MySQL-Funktionen verwendet.
MYSQL_RES Ergebnis einer Anfrage, welche Zeilen zurückgibt (SELECT, SHOW, DESCRIBE, EXPLAIN).
MYSQL_ROW Eine typensichere Darstellung eines Datensatzes (Zeile). Zeilen werden gewöhnlich mit der Funktion mysql_fetch_row() eingelesen.
MYSQL_FIELD Eine Struktur mit Informationen über ein Feld, Feldnamen, Feldtyp und Feldgröße. Die einzelnen Werte dieser Struktur erhalten Sie durch die Funktion mysql_fetch_field().
MYSQL_FIELD_OFFSET Eine typensichere Darstellung eines Offsets in einer MySQL-Feldliste. Offsets sind Feldnummern innerhalb einer Zeile.
my_ulonglong Der Typ, der für die Anzahl von Zeilen und für mysql_affected_rows(), mysql_num_rows() und mysql_insert_id() benutzt wird.

Tabelle 28.12: Datentypenübersicht der MySQL-C-API

Weiter mit Kapitel 29: Wie geht's jetzt weiter?            zum Inhaltsverzeichnis