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

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 12 MySQL und PostgreSQL
  gp 12.1 Relationales Datenbanksystem
  gp 12.2 Relationaler Datenbankserver
  gp 12.3 SQL-Server im Überblick
  gp 12.4 MySQL
    gp 12.4.1 Anwendungsgebiete von MySQL
    gp 12.4.2 Schnittstellen von MySQL
    gp 12.4.3 Installation von MySQL
    gp 12.4.4 MySQL-Server starten und stoppen
    gp 12.4.5 Konfigurationsdatei my.cnf
    gp 12.4.6 Kommandozeilenwerkzeuge für und von mysql
    gp 12.4.7 Grafische Clients
    gp 12.4.8 MySQL-Crashkurs
    gp 12.4.9 Datentypen
    gp 12.4.10 Datenbank anlegen, verwenden und löschen
    gp 12.4.11 Tabelle anlegen
    gp 12.4.12 Schlüsselfelder (Tabellen anlegen)
    gp 12.4.13 Indizes
    gp 12.4.14 Tabellentypen (Tabellen anlegen)
    gp 12.4.15 Autowerte definieren
    gp 12.4.16 Tabellen umbenennen und ändern
    gp 12.4.17 Daten einfügen, ändern und löschen
    gp 12.4.18 Daten importieren
    gp 12.4.19 Datenausgabe
    gp 12.4.20 NULL ist 0 oder undefiniert?
    gp 12.4.21 Unscharfe Suche
  gp 12.5 MySQL C-API
    gp 12.5.1 Verbindung mit dem MySQL-Server aufbauen
    gp 12.5.2 Aufgetretene Fehler ermitteln – mysql_errno() und mysql_error()
    gp 12.5.3 Schließt die Verbindung zum Server – mysql_close()
    gp 12.5.4 Erstes Beispiel
    gp 12.5.5 Verschiedene Informationen ermitteln
    gp 12.5.6 Datenbanken, Tabellen und Felder ausgeben (MYSQL_RES)
    gp 12.5.7 Ergebnismenge zeilenweise bearbeiten (MYSQL_ROW)
    gp 12.5.8 Ergebnismenge spaltenweise einlesen (und ausgeben) (MYSQL_FIELD)
    gp 12.5.9 Ein Beispiel
    gp 12.5.10 Ergebnismenge – weitere Funktionen
    gp 12.5.11 Befehle an den Server – mysql_query() und mysql_real_query()
    gp 12.5.12 Weitere Funktionen
    gp 12.5.13 Veraltete Funktionen
    gp 12.5.14 Neue Funktionen ab Version 4.1.x
  gp 12.6 Beispiel eines Newssystems mit MySQL
    gp 12.6.1 Die Headerdatei my_cgi.h
    gp 12.6.2 (Pseudo-)Planung
    gp 12.6.3 Datenbank und Tabellen anlegen
    gp 12.6.4 MySQL-Clients mit GUI
    gp 12.6.5 Randnotiz
  gp 12.7 Neue SQL-Funktionen für die Shell – MySQL erweitern
  gp 12.8 MySQL-Funktionen mit der UDF-Schnittstelle entwerfen
    gp 12.8.1 UDF-Sequenzen
    gp 12.8.2 UDF_INIT-Struktur
    gp 12.8.3 UDF_ARGS-Struktur
    gp 12.8.4 Rückgabewert
    gp 12.8.5 Benutzerdefinierte Funktionen erstellen
    gp 12.8.6 Benutzerdefinierte Funktion kompilieren, installieren und ausführen
  gp 12.9 PostgreSQL – objektrelationales Datenbankverwaltungssystem
    gp 12.9.1 PostgreSQL im Vergleich zu MySQL
    gp 12.9.2 Unterschiede in der Syntax zwischen MySQL und PostgreSQL
    gp 12.9.3 PostgreSQL installieren
    gp 12.9.4 Konfigurationsdateien bei PostgreSQL – (postgresql.conf, pg_hba_conf)
    gp 12.9.5 CRASHKURS PostgreSQL
    gp 12.9.6 PostgreSQL C-API – libpg
    gp 12.9.7 Umgebungsvariablen und Passwortdatei
    gp 12.9.8 PostgreSQL und Threads
    gp 12.9.9 Ausblick


Rheinwerk Computing

12.6 Beispiel eines Newssystems mit MySQL  downtop

Um ein solches Beispiel zu realisieren, sollten hierzu gleich einige Sicherheitsaspekte zu Beginn angesprochen werden.

Um ein Login zu verwirklichen, sollte man möglichst nicht die Zugangsdaten für MySQL nutzen, da diese sonst immer per Plaintext (Klartext = für jedermann lesbar) ins Netz übertragen werden. Im folgenden Beispiel werden die Login-Daten nur der Einfachheit halber jedes Mal im Admin-Bereich weiter übergeben!

Diese Login-Daten für den öffentlichen Bereich sollten aber nach Möglichkeit nicht hartcodiert im Programm liegen. Falls es jemand schafft, das Programm herunterzuladen, kommt er per Hexeditor an die Zugangsdaten. Hier sollte man eine Textdatei bevorzugen, die außerhalb des DOKUMENT_ROOT des Apaches liegt (also nicht per http erreichbar ist, aber vom Programm aus lesbar), und die Daten dann vom Programm aus einlesen. Den Pfad zu der Datei kann man dem Programm beim Kompilieren angeben (-D_PATH_="/pfad/zum/logindatei").


Hinweis   Auf der Buch-CD finden Sie eine solche Funktion (connect_db.c) zum Auslesen von Login-Daten – die auch schon praxiserprobt eingesetzt wurde. Diese können Sie gerne in dem anschließenden Beispiel einsetzen (in der Praxis – also auf einem öffentlichen Server – sollten Sie diese unbedingt einsetzen).


Um Ihnen jetzt das ganze Thema praxisnäher zu demonstrieren, soll ein einfaches Newssystem, das Sie bei allen größeren Webseiten finden, erstellt werden, ein eigenes kleines CMS (Content Management System), wenn Sie so wollen. Für den Laien: Ein Newssystem können Sie sich wie eine Tageszeitung vorstellen. Der Websurfer kommt auf Ihrer Seite vorbei und sieht von oben nach unten Schlagzeilen und einen kurzen Text über irgendwelche Neuigkeiten. Will dieser mehr dazu lesen, kann er, wie auch bei einer Zeitung, auf einen Link klicken, um den ganzen Artikel zu lesen. Der Reporter in dem Newssystem sind Sie oder irgendwelche Personen, denen Sie die Rechte dazu erteilt haben.

Ich werde Ihnen das Beispiel so erklären, dass Sie es selbst an Ihrem heimischen Rechner ausführen können. Sofern Sie vorhaben, dass Beispiel auszubauen und auf Ihrer Webseite zu veröffentlichen, müssen Sie sicherstellen, ob Sie bei dem Webhoster (dem Server, wo Ihre Webseite liegt – vielleicht haben Sie ja auch einen eigenen Server) CGI-Anwendungen in C ausführen können – sprich, Sie müssen Ihre Anwendung auf dem Server kompilieren dürfen. Dazu gehört auch, dass Sie Zugriff auf Ihren Webspace via SSH haben. Aber wie und ob Sie das Ganze publizieren, steht hier jetzt nicht zur Diskussion, und darüber müssen Sie sich selbst einen Überblick verschaffen.

Das Beispiel, das hier zur Anwendung kommt, verwendet den Apache als Webserver und CGI als Kommunikationsschnittstelle zwischen dem Webserver und Ihrer Clientanwendung. Die Sprache, mit der sich der Webserver und Ihre Clientanwendung über die CGI-Schnittstelle unterhalten, ist HTTP. Die Anforderungen im Beispiel sind also recht hoch. Sofern Sie sich einen besseren Überblick zur CGI-Programmierung verschaffen wollen, kann ich Ihnen das Buch C von A bis Z aus meiner Feder empfehlen. Sie finden das Buch C von A bis Z im Buchhandel, aber auch auf meiner Webseite unter http://pronix.de als Online-Version zum Lesen. Da ich aber nicht erwarten kann, dass Sie extra auf die Webseite kommen, um sich Wissen anzueignen, finden Sie das komplette Buch auch auf der beiliegenden Buch-CD.


Hinweis   Sofern Sie wirklich absoluter Laie bezüglich der Webprogrammierung mit CGI und dem Webserver Apache sind, dann sollten Sie z. B. auf der Buch-CD das Kapitel 27 des Buchs C von A bis Z lesen.



Rheinwerk Computing

12.6.1 Die Headerdatei my_cgi.downtop

Bevor Sie das kleine Projekt beginnen, soll hierzu eine Headerdatei my_cgi.h erstellt werden, die den ganzen CGI-Kram für uns erledigt. Somit können Sie theoretisch auch ohne Kenntnisse zur CGI-Schnittstelle die anschließenden Beispiele ausführen (falls Sie keine Lust haben, sich mit dieser zu befassen). Diese Headerdatei wird in allen folgenden Listings verwendet.

/* my_cgi.h */
#define MAX_PAARE 255
#define BUF 255
char *getdata( void );
char *Strdup(const char *);
void hex2ascii(char *);
char convert(char *);
struct CGI_DATEN *erstellen(char *);
struct CGI_DATEN {
  char *variable;
  char *wert;
  struct CGI_DATEN *next;
};
struct CGI_DATEN *ende = NULL;
/*
 *  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 Hexwert */
  ascii =
  (hex[0] >= 'A' ? ((hex[0] & 0xdf) - 'A')+10 : (hex[0] - '0'));
  /* Bitverschiebung schneller als ascii*=16 */
  ascii <<= 4; 
  /* zweiter Hexwert */
  ascii +=
  (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A')+10 : (hex[1] - '0'));
  return ascii;
}
/* Liste aus Variablen/Wertpaaren 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/Wertpaare 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;
}

Rheinwerk Computing

12.6.2 (Pseudo-)Planundowntop

Anhand der folgenden Grafik können Sie die einzelnen Listings erkennen und auch, welche Bedeutung bzw. Arbeit diesen in dem anschließenden Beispiel zukommt (siehe Abbildung 12.3).


Hinweis   Bei diesem Beispiel handelt es sich um ein kurz gehaltenes Newssystem ohne viele Extras (auch ohne besonders die Sicherheitsaspekte zu berücksichtigen; siehe 11.6, Anfang). Es ließen sich noch viele Dinge verändern bzw. verbessern und hinzufügen – was Sie hoffentlich auch machen.



Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 12.3    Die einzelnen Listings im Überblick



Rheinwerk Computing

12.6.3 Datenbank und Tabellen anlegedowntop

Zuerst sollten Sie die MySQL-Shell öffnen, um eine neue Datenbank und entsprechende Tabellen anzulegen:

# rcmysql start
Starting service MySQL                                                        done
# exit
exit
$ mysql -hlocalhost -uroot -pk4p6m3o3
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 3.23.55-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> CREATE DATABASE news;
mysql> USE news;
mysql> CREATE TABLE DATA( datum TIMESTAMP, autor VARCHAR(200),
    -> suche VARCHAR(200), title VARCHAR(150),
    -> beschreibung BLOB, inhalt BLOB);

Hinweis   Diesen Arbeitsschritt können (sollten) Sie in der Praxis auch mit einer CGI-Anwendung (z. B. install.cgi) ausführen lassen. Hierfür müssten Sie sich lediglich einloggen, eine Verbindung initialisieren, aufbauen und entsprechende SQL-Statements mit der Funktion mysql_real_query() ausführen lassen.

Hinweis zu BLOB   Auch wenn hier BLOBs verwendet wurden, sollte man sie in der Praxis nicht verwenden, weil dies die Performance der gesamten Datenbank erheblich bremsen kann.


Login.html

Zuerst soll hier die HTML-Datei zum Einloggen in die Datenbank news erstellt werden.

<html>
<head>
  <title>Login zum Admin-Bereich</title>
</head>
<body bgcolor="white">
<h1>Login in den Admin-Bereich</h1>
<pre>
<form action="http://localhost/cgi-bin/login" method="POST"><br>
Host      :
<input type="text" name="host" value="localhost" size=25><br>
User      :
<input type="text" name="user" value="root" size=25><br>
Passwort  :
<input type="password" name="passwort" size=25><br>
Datenbank :
<input type="text" name="datenbank" value="Name Datenbank" size=25><br>
<input type="submit" value="Bestätigen">
<input type="reset" value="Reset">
</pre>
</form>
</body>
</html>

Speichern Sie die Datei in Ihrem Heimverzeichnis, oder kopieren Sie diese als Superuser in das htdocs-Verzeichnis des Servers (im Beispiel unter SUSE ist dies das Verzeichnis /srv/www/htdocs) und passen ggf. die Zugriffsrechte an. Anschließend sollten Sie den Apache-Webserver und den MySQL-Server starten:

$ su
Password:*******
# cp login.html /srv/www/htdocs
# chmod a+rx /srv/www/htdocs/login.html
# rcapache start
Starting httpd [ PHP4 ]                               done

Öffnen Sie Ihren Lieblingsbrowser (hier Mozilla), und geben Sie entsprechende Login-Daten ein, die Sie zuvor auch bei der MySQL-Shell verwendet haben (siehe Abbildung 12.4).


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 12.4    Das HTML-Formular zum Einloggen


Bevor Sie nun den Bestätigungsbutton drücken, benötigen Sie noch die CGI-Anwendung, um die Eingabe zu überprüfen.

login.c

Die CGI-Anwendung login.c macht nichts anderes, als die Daten von der Clientanwendung (login.html), die über die POST-Methode versendet wurden, zu dekodieren und zu versuchen, mit dem MySQL-Server eine Verbindung einzugehen. Gelingt dies, wird Ihnen folgende Ausgabe das bestätigen:


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 12.5    Bestätigung bei erfolgreichem Login


Wenn dies nicht gelingt, dann sollten Sie wenigstens eine Ausgabe erhalten, warum die Verbindung nicht zustande kam. Wenn die Zugangsdaten zum MySQL-Server korrekt waren, werden diese beim Drücken des Los geht's!-Buttons an die CGI-Anwendung admin.c versteckt (hidden) mit der POST-Methode mitgeschickt.

/* login.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mysql.h>
#define MAX 255
#define BUFFER 4096
#include "my_cgi.h"
static char *connect_param[4];
/* Mit dem MySQL-Server und den entsprechenden */
/* Verbindungsdaten eine Verbindung herstellen  */
static int mein_connect (MYSQL * my, struct CGI_DATEN *ptr) {
  int i;
  for( i = 0; i < 4; i++ ) {
    connect_param[i] = ptr->wert;
    ptr = ptr->next;
  }
  /* Mit dem Server verbinden */
  if (mysql_real_connect (my,   /* Zeiger auf MySQL-Handler */
                 connect_param[0],  /* Hostname */
                 connect_param[1],  /* User-Name */
                 connect_param[2],  /* Passwort für user_name */
                 connect_param[3],  /* Name der Datenbank */
                                0,  /* Port (default=0) */
                              NULL, /* Socket (default=NULL) */
                          0 /* keine Flags */ ) ==    NULL) {
    fprintf (stdout, "Fehler mysql_real_connect():"
             "%u (%s)\n", mysql_errno (my), mysql_error (my));
    exit (EXIT_FAILURE);
  }
  return 1;
}
/* Speicher freigeben und Verbindung beenden */
static void clean_up_shutdown (MYSQL * my) {
  mysql_close (my);
}
int main (int argc, char **argv) {
  MYSQL *my;
  char *str;
  struct CGI_DATEN *cgi;
  struct CGI_DATEN *free_cgi;
  char buf[BUFFER];
  /* Handle initialisieren */
  my = mysql_init (NULL);
  if (my == NULL) {
    fprintf (stderr, " Initialisierung fehlgeschlagen\n");
    exit (EXIT_FAILURE);
  }
  /* Für Fehlermeldungen */
  printf("Content-Type: text/html\n\n");
  /* Eingabe einlesen */
  str = getdata();
  if(str == NULL) {
    printf("Fehler beim Einlesen der Formulareingabe");
    return 0;
  }
  /* Hexzeichen in ASCII-Zeichen konvertieren und aus '+'
     Leerzeichen machen */
  hex2ascii(str);
  /* Liste der Formulardaten erstellen */
  cgi = erstellen(str);
  free_cgi = cgi;
  if (cgi == NULL) {
    printf("Fehler beim Erstellen der "
           "Variablen/Werteliste!!\n");
    return EXIT_FAILURE;
  }
  /* Mit dem Server verbinden */
  if (mein_connect (my, cgi) != -1)
    printf ("Erfolgreich mit dem MySQL-Server verbunden\n");
  /* Wenn alles o.k. ging, auf zum Admin-Bereich mit */
  /* den DB-Daten                                 */
  sprintf(buf,
     "<form action=\"http://localhost/cgi-bin/admin\""
     " method=\"POST\"><input type=\"hidden\"  name=\"host\""
     " value=\"%s\"><input type=\"hidden\"  name=\"user\"  "
     "value=\"%s\"><input type=\"hidden\"  name=\"passwort\"  "
     "value=\"%s\"><input type=\"hidden\"  name=\"datenbank\"  "
     "value=\"%s\">Login zur Datenbank erfolgreich. Zum"
     " Admin-Bereich auf den Button klicken.<br><input "
     "type=\"submit\"  value=\"Los gehts!\"></form>",
       connect_param[0], connect_param[1], connect_param[2],
       connect_param[3]);
  printf("%s\n",buf);
  clean_up_shutdown( my );
  return EXIT_SUCCESS;
}

Um die Anwendung login auch zu verwenden, sollte diese in das Verzeichnis cgi-bin des Webservers kopiert und die entsprechenden Zugriffsrechte sollten angepasst werden:

$ gcc -c -I/usr/include/mysql login.c
$ gcc -o login login.o -L/usr/lib/mysql -lmysqlclient
$su
Password:********
# cp login /srv/www/cgi-bin
# chmod a+rx /srv/www/cgi-bin/login

admin.c

Nach der Betätigung des Los geht's!-Buttons wird die CGI-Anwendung admin zur Eingabe von neuen News gestartet.


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 12.6    Erstellen eines neuen Newseintrags


Die Anwendung admin holt zuerst wieder die Daten, die nötig sind, um anschließend Einträge in die Datenbank zu machen. Die Daten werden danach wieder dekodiert und für die Weitergabe aufbewahrt. Jetzt können Sie im HTML-Formular Daten für die neuesten News eingeben. Bei Betätigung des Abschicken-Buttons werden diese Daten mitsamt den Daten für die Verbindung zum MySQL-Server (wieder versteckt) an die CGI-Anwendung add_db weitergegeben. Hier also der Quellcode zur CGI-Anwendung admin:

/* admin.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>
#include "my_cgi.h"
#define MAX 255
#define BUFFER 4096
static char *connect_param[4];
static int fetch_login_db( void ) {
  int i;
  char *str;
  struct CGI_DATEN *cgi;
  /* Für Fehlermeldungen */
  printf("Content-Type: text/html\n\n");
  /* Eingabe einlesen */
  str = getdata();
  if(str == NULL) {
    printf("Fehler beim Einlesen der Formulareingabe");
    return 0;
  }
  /* Hexzeichen in ASCII-Zeichen konvertieren und aus '+' */
  /* Leerzeichen machen                                   */
  hex2ascii(str);
  /* Liste der Formulardaten erstellen */
  cgi = erstellen(str);
  if (cgi == NULL) {
    printf("Fehler beim Erstellen der "
           "Variablen/Werteliste!!\n");
    return 0;
  }
  for( i = 0; i < 4; i++ ) {
    connect_param[i] = cgi->wert;
    cgi = cgi->next;
  }
  return 1;
}
static void print_admin_input( void ) {
  char buf[BUFFER];
  sprintf(buf,
    "<h1>Eintragen von neuen Artikeln</h1>"
    "<form action=\"http://localhost/cgi-bin/add_db\"  "
    "method=\"POST\">"
    "<input type=\"hidden\"  name=\"host\"  value=\"%s\">"
    "<input type=\"hidden\"  name=\"user\"  value=\"%s\">"
    "<input type=\"hidden\"  name=\"passwort\"  value=\"%s\">"
    "<input type=\"hidden\"  name=\"datenbank\"  value=\"%s\">"
    "<pre>Autor: <input type=\"text\"  name=\"autor\"  "
    "value=\"Admin\"  size=30><br>"
    "Titel: <input type=\"text\"  name=\"titel\"  size=30><br>"
    "Schlüsselworte zur Suche :\n"
    "<input type=\"text\"  name=\"suche\"  value=\"Suchwörter\""
    " size=50><br>"
    "Schlagzeilen für die Hauptseite :\n"
    "<textarea name=\"beschreibung\"  cols=\"50\"  "
    "rows=\"6\"></textarea><br>"
    "Rest vom Artikel :\n"
    "<textarea name=\"beschreibung\"  cols=\"50\"  "
    "rows=\"6\"></textarea><br>"
    "<input type=\"submit\"  value=\"Abschicken\"><input "
    "type=\"reset\"  value=\"Zurücksetzen\"></pre></form>",
    connect_param[0],connect_param[1],connect_param[2],
    connect_param[3]);
  printf("%s",buf);
}
int main (int argc, char **argv) {
  /* Login-Daten für die Datenbank abholen */
  fetch_login_db( );
  /* Eingabeformular für Admin ausgeben */
  print_admin_input( );
  return EXIT_SUCCESS;
}

Die Anwendung zur Ausführung vorbereiten:

$ gcc -c -I/usr/include/mysql admin.c
$ gcc -o admin admin.o -L/usr/lib/mysql -lmysqlclient
$ su
Password:*******
# cp admin /srv/www/cgi-bin
# chmod a+rx /srv/www/cgi-bin/admin

Hinweis   Damit Sie sich nicht immer, wie im Beispiel, als su einloggen müssen, wäre es sinnvoller, dem User Schreibrechte für das cgi-Verzeichnis zu erteilen.


add_db.c

Die CGI-Anwendung add_db holt nun alle Daten ab, die sie von der Anwendung admin per POST-Methode erhalten hat, und dekodiert diese Daten in einer leserlichen Form. Anschließend wird eine Verbindung mit dem Server hergestellt, und die Daten werden in die Datenbank mittels mysql_real_query() eingetragen. Konnten die Daten erfolgreich eingetragen werden, erscheint folgende Ausgabe auf Ihrem Browser:


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 12.7    Bei Erfolg gibt es eine entsprechende Meldung.


/* add_db.c 
 * Eine Gedächtnisstütze:
mysql> create database news;
mysql> use news;
mysql> create table data( datum TIMESTAMP, autor VARCHAR(200),
    -> suche VARCHAR(200), title VARCHAR(150), beschreibung BLOB,
    -> inhalt BLOB);
mysql> INSERT INTO data (autor, title, suche, beschreibung,
    -> inhalt)
    -> VALUES (
    -> "Jürgen Wolf", "Ein Testtitel", "suchwörter test titel",
    -> "Beispiel, wie man mit MySQL und der C-API ein eigenes
    -> Newssystem erstellt",
    -> "Der eigentliche Inhalt nach den Schlagzeilen zum Thema
    -> MySQL und der C-API");
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mysql.h>
#define MAX 255
#define BUFFER 4096
#include "my_cgi.h"
enum { HOST, USER, PASSWORT, DATENBANK,
       AUTOR, TITLE, SUCHE, BESCHREIBUNG, INHALT};
static char *param[9];
static int fetch_data( void ) {
  int i;
  char *str;
  struct CGI_DATEN *cgi;
  /* Für Fehlermeldungen */
  printf("Content-Type: text/html\n\n");
  /* Eingabe einlesen */
  str = getdata();
  if(str == NULL) {
    printf("Fehler beim Einlesen der Formulareingabe");
    return 0;
  }
  /* Hexzeichen in ASCII-Zeichen konvertieren und aus '+' */
  /* Leerzeichen machen                                   */
  hex2ascii(str);
  /* Liste der Formulardaten erstellen */
  cgi = erstellen(str);
  if (cgi == NULL) {
    printf("Fehler beim Erstellen der "
           "Variablen/Werteliste!!\n");
    return 0;
  }
  for( i = 0; i < 9; i++ ) {
    param[i] = cgi->wert;
    cgi = cgi->next;
  }
  return 1;
}
/* Mit dem MySQL-Server und den entsprechenden */
/*  Verbindungsdaten eine Verbindung herstellen */
static int mein_connect (MYSQL * my) {
  /* Mit dem Server verbinden */
  if (mysql_real_connect (my,   /* Zeiger auf MYSQL-Handler */
               param[HOST],         /* Hostname */
               param[USER],         /* User-Name */
               param[PASSWORT],     /* Passwort für user_name */
               param[DATENBANK],    /* Name der Datenbank */
                          0,        /* Port (default=0) */
                          NULL,    /* Socket (default=NULL) */
                          0 /* keine Flags */ ) ==    NULL) {
    fprintf (stdout, "Fehler mysql_real_connect():"
             "%u (%s)\n", mysql_errno (my), mysql_error (my));
    exit (EXIT_FAILURE);
  }
  return 1;
}
static void insert_into_db( MYSQL *my ) {
  char buf[8192];
  /* Tabelle */
  sprintf(buf, "INSERT INTO data (autor, title, suche, "
          "beschreibung, inhalt)"
          " VALUES (\'%s\','\%s\','\%s\', '\%s\', \'%s\');"
          ,param[AUTOR], param[TITLE], param[SUCHE],
          param[BESCHREIBUNG], param[INHALT]);
  /* printf("%s\n", buf); */
  if(mysql_real_query(my, buf, strlen(buf)) !=0) {
    fprintf (stdout, "Fehler mysql_real_connect():"
             "%u (%s)\n", mysql_errno (my), mysql_error (my));
    exit (EXIT_FAILURE);
  }
}
/* Speicher freigeben und Verbindung beenden */
static void clean_up_shutdown (MYSQL * my) {
  mysql_close (my);
}
int main (int argc, char **argv) {
  MYSQL *my;
  /* Daten abholen und für die Eintragung vorbereiten */
  fetch_data();
  /* Handle initialisieren */
  my = mysql_init (NULL);
  if (my == NULL) {
    fprintf (stderr, " Initialisierung fehlgeschlagen\n");
    exit (EXIT_FAILURE);
  }
  /* Mit dem Server verbinden */
  if (mein_connect (my) != -1)
    printf ("Erfolgreich mit dem MySQL-Server verbunden\n");
  /* Daten in die Datenbank schreiben */
  insert_into_db( my );
  printf("Eintragung erfolgreich<br>Zur Indexseite geht´s "
     "<a href=\"http://localhost/cgi-bin/index_news\">hier </a>"
     " und für weitere Artikel klicken Sie bitte"
     " <a href=\"http://localhost/login.html\">hier</a>\n");
  clean_up_shutdown( my );
  return EXIT_SUCCESS;
}

Die Anwendung für die Ausführung vorbereiten:

$ gcc -c -I/usr/include/mysql add_db.c
$ gcc -o add_db add_db.o -L/usr/lib/mysql -lmysqlclient
$ su
Password:********
# cp add_db /srv/www/cgi-bin
# chmod a+rx /srv/www/cgi-bin/add_db

Jetzt können Sie entweder einen weiteren Newseintrag machen oder zur Hauptseite index_news, auf der sich die Schlagzeilen mit einer Kurzbeschreibung befinden, wechseln. Für einen weiteren Newseintrag habe ich mich für ein erneutes Login entschieden. Wie Sie in der Praxis dabei vorgehen, bleibt Ihnen überlassen.

index_news.c

Nach den Anwendungen für den administrativen Teil folgen nun zwei CGI-Anwendungen für den Websurfer; zuerst die Titelseite mit den Schlagzeilen in Kurzform – index_news. Da die Anwendung index_news für jedermann zugänglich sein soll, wurden hierbei die Daten für den Zugriff auf dem Datenbankserver fest einkompiliert. Hierbei wäre es nicht schlecht, wenn Sie hierfür, sofern Sie die Rechte dazu haben, einen extra User (z. B. Anonymous) mit entsprechenden (Lese-)Rechten für die Datenbank news einrichten. Die Anwendung macht nichts anderes, als die Schlagzeilen aus der Datenbank news auszulesen und in lesbarere Form für den Webbrowser aufzubereiten, wie folgende Abbildung demonstrieren soll:


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 12.8    Die Startseite und auch das Portal des Newssystems


/* index_news.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>
#define MAX 255
#define BUFFER 4096
#include "my_cgi.h"
#define HOST      "localhost"
#define USER      "root"
#define PASSWORT  "k4p6m3o3"
#define DATENBANK "news"
static char *timestamp2date( char * );
static char date[11];
/* Mit dem MySQL-Server und den entsprechenden */
/* Verbindungsdaten eine Verbindung herstellen */
static int mein_connect (MYSQL * my) {
  /* Mit dem Server verbinden */
  if (mysql_real_connect (my,       /* Zeiger auf MYSQL-Handler */
                  HOST,             /* Hostname */
                  USER,             /* User-Name */
                  PASSWORT,         /* Passwort für user_name */
                  DATENBANK,        /* Name der Datenbank */
                         0,         /* Port (default=0) */
                       NULL,        /* Socket (default=NULL) */
                         0 /* keine Flags */ ) ==    NULL) {
    fprintf (stdout, "Fehler mysql_real_connect():"
             "%u (%s)\n", mysql_errno (my), mysql_error (my));
    exit (EXIT_FAILURE);
  }
  return 1;
}
static void select_data_from_db( MYSQL *my ) {
  char *tmp[6];
  MYSQL_ROW  row;
  MYSQL_RES  *mysql_res;
  unsigned long  anzahl_reihen;
  unsigned int i;
  char buf[BUF] = "SELECT * FROM data ORDER BY datum DESC";
  char bigbuf[8096];
  if(mysql_real_query(my, buf, (strlen(buf)))!=0) {
    fprintf (stdout, "Fehler mysql_real_connect():"
             "%u (%s)\n", mysql_errno (my), mysql_error (my));
    exit (EXIT_FAILURE);
  }
  /* Daten der Anfrage abholen */
  mysql_res = mysql_store_result(my);
  /* Anzahl der gefundenen Datensätze ermitteln */
  anzahl_reihen = (unsigned long) mysql_num_rows (mysql_res);
  printf ("Anzahl gefundener Artikel: %lu\n\n<br><br>",
           anzahl_reihen);
  printf("<table width=\"90 %\"> ");
  /* 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 ++)
      tmp[i] = row[i];
    sprintf(bigbuf, "<tr><td bgcolor=\"darkgrey\">Titel: "
       " %s</td></tr><tr><td>Schlagzeile :%s</td></tr>"
       "<tr><td bgcolor=\"darkgrey\"  align=\"right\">Datum "
       ":%s |  Autor :%s  |  "
       "<a href=\"http://localhost/cgi-bin/search_db?full=%s\">"
       "Den kompletten Artikel lesen</a>  |"
       "</td></tr><td><tr>&nbsp;</tr></td>",
       tmp[3], tmp[4], timestamp2date(tmp[0]), tmp[1], tmp[3]);
    printf("%s",bigbuf);
  }
  printf("</table>");
  printf("<hr><br>"
  "<form action=\"http://localhost/cgi-bin/search_db\"  "
  "method=\"POST\">Nach Artikel suchen <br>"
  "<input type=\"text\"    maxlength=\"30\"name=\"suchstring\">"
  "<input type=\"submit\"  value=\"Suche\"></form>");
  /* Speicherplatz wieder freigeben */
  mysql_free_result(mysql_res);
}
/* Extrahieren des Timestamp-Formats */
/* bspw. 200404121602... das Datum    */
/* und gibt einen String ŕ la DD:MM:YYYY zurück
 */
static char *timestamp2date( char *timestamp ) {
  char *ptr = NULL;
  date[0] = '\0';
  ptr = timestamp+6;
  strncpy(date, ptr, 2);
  strcat(date, ".");
  ptr = timestamp+4;
  strncpy(&date[3], ptr, 2);
  strcat(date, ".");
  ptr = timestamp;
  strncpy(&date[6], ptr, 4);
  date[10] = '\0';
  ptr = date;
  return ptr;
}
/* Speicher freigeben und Verbindung beenden */
static void
clean_up_shutdown (MYSQL * my) {
  mysql_close (my);
}
static void print_header( ) {
  printf("<html><head><title>News</title></head>"
         "<body bgcolor=\"white\">"
         "<h1>Vorhandene News</h1>");
}
static void print_footer( ) {
  printf("</body></html>");
}
int main (int argc, char **argv) {
  MYSQL *my;
  /* Handle initialisieren */
  my = mysql_init (NULL);
  if (my == NULL) {
    fprintf (stderr, " Initialisierung fehlgeschlagen\n");
    exit (EXIT_FAILURE);
  }
  /* Für Fehlermeldungen */
  printf("Content-Type: text/html\n\n");
  /* Mit dem Server verbinden */
  if (mein_connect (my) != -1)
    print_header( );
  /* Daten aus der Datenbank holen */
  select_data_from_db( my );
  print_footer( );
  clean_up_shutdown( my );
  return EXIT_SUCCESS;
}

Die Anwendung zur Ausführung vorbereiten:

$ gcc -c -I/usr/include/mysql index_news.c
$ gcc -o index_news index_news.o -L/usr/lib/mysql -lmysqlclient
$ su
Password:********
# cp index_news /srv/www/cgi-bin
# chmod a+rx /srv/www/cgi-bin/index_news

search_db.c

Um jetzt den vollen Report einer Schlagzeile zu lesen oder nach bestimmten Artikeln zu suchen, benötigen Sie noch die CGI-Anwendung search_db, die beides erledigt. Wollen Sie den vollen Text eines Artikels lesen, wird als CGI-Variable full mitgeschickt, da ja die Anwendung search_db den mitgesandten Text immer erst dekodiert. Ist die Variable full angegeben, wird der Wert der Variable, der dem Titel (title VARCHAR(150)) in der Datenbank news und der Tabelle data entspricht, mitsamt des kompletten Inhalts aus der Datenbank ausgelesen und in voller Form auf dem Browser ausgegeben, z. B.:


Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 12.9    Ergebnis bei einer erfolgreichen Suche


Ist die erste dekodierte Variable nicht full, wurde eine Suchanfrage gestartet. Für die Suche wurde ja in der Tabelle extra eine Spalte eingerichtet (suche VARCHAR(200)), in der nach speziellen von Ihnen vorgegebenen Schlüsselwörtern gesucht wird. Wurde Entsprechendes gefunden, wird auch dies in leserfreundlichem Stil über den Webbrowser ausgegeben.

/* search_db.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>
#define MAX 255
#define BUFFER 4096
#include "my_cgi.h"
#define HOST      "localhost"
#define USER      "root"
#define PASSWORT  "k4p6m3o3"
#define DATENBANK "news"
static char *search_string;
static char *news_full;
static char *timestamp2date( char * );
static char date[11];
static int fetch_http_string (void) {
  char *str;
  struct CGI_DATEN *cgi;
  /* 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 Formulardaten erstellen */
  cgi = erstellen (str);
  if (cgi == NULL) {
    printf ("Fehler beim Erstellen der "
            "Variablen/Werteliste!!\n");
    return 0;
  }
  /* Suche nur mit einem Suchbegriff möglich */
  news_full = cgi->variable;
  search_string = cgi->wert;
  return 1;
}
/* Mit dem MySQL-Server und den entsprechenden */
/* Verbindungsdaten eine Verbindung herstellen  */
static int mein_connect (MYSQL * my) {
  /* Mit dem Server verbinden */
  if (mysql_real_connect (my,      /* Zeiger auf MYSQL-Handler */
                        HOST,      /* Hostname */
                        USER,      /* User-Name */
                        PASSWORT,  /* Passwort für user_name */
                        DATENBANK, /* Name der Datenbank */
                          0,       /* Port (default=0) */
                          NULL,    /* Socket (default=NULL) */
                          0 /* keine Flags */ ) == NULL) {
    fprintf (stdout, "Fehler mysql_real_connect():"
             "%u (%s)\n", mysql_errno (my), mysql_error (my));
    exit (EXIT_FAILURE);
  }
  return 1;
}
/* Mit Suche integrieren */
static void
search_data_from_db (MYSQL * my) {
  char *tmp[6];
  MYSQL_ROW row;
  MYSQL_RES *mysql_res;
  unsigned long anzahl_reihen;
  unsigned int i;
  char buf[BUF];
  char bigbuf[8096];
  if (strcmp (news_full, "full") == 0) {
    sprintf ( buf,
              "SELECT * FROM data WHERE title=\'%s\';",
              search_string );
    /* printf ("%s", buf); */
    if (mysql_real_query (my, buf, strlen(buf)) != 0) {
      fprintf (stdout, "Fehler mysql_real_connect():"
               "%u (%s)\n", mysql_errno (my),
               mysql_error (my));
      exit (EXIT_FAILURE);
    }
    /* Daten der Anfrage abholen */
    mysql_res = mysql_store_result (my);
    printf ("<table width=\"90 %\">");
    /* 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++)
        tmp[i] = row[i];
      sprintf (bigbuf,
         "<tr><td bgcolor=\"darkgrey\">Titel: %s</td></tr>"
         "<tr><td>Schlagzeile :%s<br><br>Inhalt: %s</td></tr>"
         "<tr><td bgcolor=\"darkgrey\"  align=\"right\">"
         " Datum :%s |  Autor :%s  |"
         "</td></tr><td><tr>&nbsp;</tr></td>",
         tmp[3], tmp[4],tmp[5], timestamp2date(tmp[0]), tmp[1]);
      printf ("%s", bigbuf);
    }
    printf ("</table>");
    printf ("<hr><br>"
    "<form action=\"http://localhost/cgi-bin/search_db\""
    " method=\"POST\">" "Nach Artikel suchen <br>"
    "<input type=\"text\"  maxlength=\"30\"name=\"suchstring\">"
    "<input type=\"submit\"  value=\"Suche\"></form>");
  } else {
    sprintf (buf,
             "SELECT * FROM data WHERE suche LIKE \'%%%s%%\'"
             " ORDER BY datum DESC;", search_string);
    /* printf ("%s", buf); */
    if (mysql_real_query (my, buf, strlen(buf)) != 0) {
      fprintf (stdout, "Fehler mysql_real_connect():"
               "%u (%s)\n", mysql_errno (my),
               mysql_error (my));
      exit (EXIT_FAILURE);
    }
    /* Daten der Anfrage abholen */
    mysql_res = mysql_store_result (my);
    /* Anzahl der gefundenen Datensätze ermitteln */
    anzahl_reihen = (unsigned long) mysql_num_rows (mysql_res);
    printf ("Anzahl gefundener Artikel: %lu\n\n<br><br>",
            anzahl_reihen);
    printf ("<table width=\"90 %\">");
    /* 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++)
        tmp[i] = row[i];
      sprintf (bigbuf,
               "<tr><td bgcolor=\"darkgrey\">Titel: %s</td>"
               "</tr><tr><td>Schlagzeile :%s</td></tr>"
               "<tr><td bgcolor=\"darkgrey\"  align=\"right\">"
               "Datum :%s |  Autor :%s  |  <a href=\""
               "http://localhost/cgi-bin/search_db?full=%s\">"
               "Den kompletten Artikel lesen</a>  |"
               "</td></tr><td><tr>&nbsp;</tr></td>",
               tmp[3], tmp[4], timestamp2date(tmp[0]),
               tmp[1], tmp[3]);
      printf ("%s", bigbuf);
    }
    printf ("</table>");
    printf ("<hr><br><form action=\""
       "http://localhost/cgi-bin/search_db\"  method=\"POST\">"
       "Nach Artikel suchen <br><input type=\"text\""
       " maxlength=\"30\"name=\"suchstring\">"
       "<input type=\"submit\"  value=\"Suche\"></form>");
  }
  /* Speicherplatz wieder freigeben */
  mysql_free_result (mysql_res);
}
/* Extrahieren des Timestamp-Formats            */
/* bspw. 200404121602... das Datum              */
/* und gibt einen String ŕ la DD:MM:YYYY zurück */
static char *timestamp2date( char *timestamp ) {
  char *ptr = NULL;
  date[0] = '\0';
  ptr = timestamp+6;
  strncpy(date, ptr, 2);
  strcat(date, ".");
  ptr = timestamp+4;
  strncpy(&date[3], ptr, 2);
  strcat(date, ".");
  ptr = timestamp;
  strncpy(&date[6], ptr, 4);
  date[10] = '\0';
  ptr = date;
  return ptr;
}
/* Speicher freigeben und Verbindung beenden */
static void
clean_up_shutdown (MYSQL * my) {
  mysql_close (my);
}
void
print_header () {
  printf ( "<html><head><title>News</title></head>"
           "<body bgcolor=\"white\">" "<h1>News</h1>");
}
static void
print_footer (void) {
  printf ("</body></html>");
}
int main (int argc, char **argv) {
  MYSQL *my;
  /* Handle initialisieren */
  my = mysql_init (NULL);
  if (my == NULL) {
    fprintf (stderr, " Initialisierung fehlgeschlagen\n");
    exit (EXIT_FAILURE);
  }
  /* Für Fehlermeldungen */
  printf ("Content-Type: text/html\n\n");
  /* Mit dem Server verbinden */
  if (mein_connect (my) != -1)
    print_header ();
  /* Suchstring auslesen */
  fetch_http_string ();
  /* Daten aus der Datenbank holen */
  search_data_from_db (my);
  print_footer ();
  clean_up_shutdown (my);
  return EXIT_SUCCESS;
}

Die Anwendung zu Ausführung vorbereiten:

$ gcc -c -I/usr/include/mysql search_db.c
$ gcc -o search_db search_db.o -L/usr/lib/mysql -lmysqlclient
$ su
Password:********
# cp search_db /srv/www/cgi-bin
# chmod a+rwx /srv/www/cgi-bin/search_db

Der Anwender kann jetzt die aktuellen Schlagzeilen immer mit der URL http://localhost/cgi-bin/index_news in seinem Browser aufrufen. Dies nun auf Ihre Webseite zu portieren, sollte je nach Erfahrung nicht allzu schwer sein.


Rheinwerk Computing

12.6.4 MySQL-Clients mit GUdowntop

Jetzt haben Sie gesehen, dass es im Prinzip gar nicht so schwer ist, eigene MySQL-Anwendungen zu entwerfen. In diesem Beispiel haben Sie als Pseudo-GUI den Webbrowser verwendet, was auch den Vorteil hat, dass die Clientseite plattformunabhängig ist. Im Großen und Ganzen ist es auch nicht allzu schwer, wenn Sie Kenntnisse zur GUI-Programmierung mit z. B. GTK+ oder Qt haben, diese Anwendung mit einer echten grafischen Oberfläche zu versehen. Sie müssen lediglich wissen, wie man eine Abfrage an den Server stellt (mysql_real_query()) und wie Sie die Ergebnismenge, sofern eine zurückgegeben wird, bearbeiten können. All dies haben Sie hier jetzt mehrfach gesehen.


Rheinwerk Computing

12.6.5 Randnotiz  toptop

Nicht behandelt wurde das Casten von MySQL-Rückgabewerten. Angenommen man hat ein INT(2)-Feld namens zahl. Folgendes wird nicht funktionieren, es muss gecastet werden:

int i;
mysql_real_query(
    &mysql, "SELECT 'zahl' FROM 'table' LIMIT 1", 34);
result = mysql_store_result(&mysql);
row = mysql_fetch_row(result);
i = row[0];

In diesem Fall müsste es heißen:

i = (atoi)row[0];

Wohl wird aber dieses hier gehen:

printf("%s\n", row[0]);
 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

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

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


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





Copyright © Rheinwerk Verlag GmbH 2006
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