HomeMapIndexSearchNewsArchivesLinksAbout LF
[Top Bar]
[Bottom Bar]
[Photo of the Author]
Luis Colorado

Über den Autor:
Luis Colorado ist als Administrator von UNIX Systemen und Internetzugängen bei der spanischen Telefónica Sistemas S.A. tätig. Er machte seinen Abschluß in Physik an der Universidad Complutense of Madrid und entwickelte eine Anzahl von frei verfügbaren UNIX Werzeugen.

M@il an den Autor

Inhalt:
Einführung
Motivation
M4
Funktionsweise
Übertragung der Informationen vom Benutzer an das CGI
Download

PG2CGI: WWW basierter Datenbankzugriff

[Ilustration]


Zusammenfassung:
Vorgestellt wird ein Programm, das den Zugriff auf eine Datenbank von HTML Seiten aus erlaubt. Als Ziele bei der Entwicklung von PG2CGI standen Kontrolle über den Datenzugriff, eine flexible Konfigurierung und die Unabhängigkeit von Layoutformaten im Vordergrund. Das Programm resultierte aus Ideen, die mir während des Lesens diverser Artikel über M4 kamen (Artikel der letzten 12 Monate in Linux Journal und LinuxFocus).


Einführung

Dieser Artikel beschreibt die Gründe, weshalb ich ein Softwarepaket für den WWW basierten Datenbankzugriff entwickelte. Es ist nicht meine Absicht, hier eine Gebrauchsanweisung für PG2CGI zu schreiben (entsprechende Dokumentation kommt mit der Software mit, die Adresse ist weiter unten zu finden), als es vielmehr vorzustellen und hoffentlich den Leser zu animieren, PG2CGI zu benutzen und mir seine Erfahrungen zu schildern.

Motivation

Ich schrieb dieses Programm in Folge einer Serie von Artikeln, die im Linunx Journal und LinuxFocus erschienen sind und den Einsatz von M4 für die Verwaltung von HTML Dokumenten erörterten. Diese Artikel zeigten die Vorteile und das Potential von M4 als eigenständiges Werkzeug für die Pflege von WWW Seiten und die dynamische Generierung ihrer Inhalte auf.

Es steht die Verfügbarkeit einer ganzen Reihe von WWW Serven und Datenbanksystemen im krassen Gegensatz zu der Tatsache, daß Werkzeuge fehlen, die in der Lage sind, beide Umgebungen zu verbinden (die meisten dieser Programme sind kommerziell oder haben ernsthafte Mängel in Bezug auf die Formate, die verwendet werden können).

PG2CGI vereint die Bereiche Datenbank und WWW. Bei der Entwicklung wurde darauf geachtet, daß es folgende Anforderungen erfüllt: PG2CGI erfüllt diese Anforderungen, wobei leichte Einbußen bei der Effizienz in Kauf genommen werden (M4 wird während der Ausführung wiederholt ausgeführt). Allerdings sind die Ergebnisse in den meisten Fällen zufriedenstellend (man bedenke, daß oft schon die Anfrage an die Datenbank länger dauert, als die dynamische Generierung des HTML Textes!).

M4

M4 ist ein vor langer Zeit entwickeltes Werkzeug für die Verarbeitung von Makros. PG2CGI nutzt intensiv M4: Der wiederholte Aufruf eines Makroprozessors kann zu Einbußen bei der Effizienz führen, obwohl unsere Tests mit dem GNU M4 Werkzeug durchaus befriedigende Ergebnisse lieferten.

Reguläre Ausdrücke:

Unser Programm greift intensiv auf reguläre Ausdrücke für die Verifizierung der angewendeten Konfigurationsregeln zurück. Regulärer Ausdrücke weisen gegenüber einfachen Vergleichen eine höhere Funktionalität auf. Unter anderem haben sie folgende Vorteile:
PG2CGI benutzt reguläre Ausdrücke für die Verifikation der benutzten Konfigurationsregeln.
Die Syntax der Ausdrücke und die Analyse der Daten für die Treiber, die in regulären Ausdrücken weitergereicht werden, kann dank der Möglichkeit, mehrere Teilausdrücke in einem einzelnen regulären Ausdruck zu gruppieren, relativ einfach ausgeführt werden.

Beispiel: Angenommen, der Client muß Informationen in query_string übergeben, wobei die Daten der folgenden Syntax entsprechen müssen:
 FIELD=value
Außerdem muß query_string diesem Format genügen, weitere Informationen sollten nicht in diesem String enthalten sein.

Durch den folgenden Term in der Auswahlregel kann diese Syntax einfach erzwungen werden:
 QUERY_STRING: "^FIELD=[^&]*$";
Die obige Zeile gewährleistet, daß dies Regel nur angewendet wird, wenn QUERY_STRING die entsprechende Syntax aufweist. Desweiteren erlaubt das Programm, den entsprechenden Wert zu analysieren, falls dieser im obigen Ausdruck geklammert wird.
 QUERY_STRING: "^FIELD=([^&]*)$";
Während dieses Prozesses transformiert das Programm ebenfalls die Escape Sequenzen der Form %xx, die durch den Navigator eingeführt werden.

Funktionsweise

Nun wird es Zeit, die Funktionsweise des Programmes zu beschreiben. Wird es zum ersten Mal gestartet, so liest es Umgebungsvariablen des WWW Servers aus und konfiguriert sich anhand dieser selbst. Diese Variablen sind die einzigen Informationen, die das Programm benötigt, wie zum Beispiel Informationen über den Client, Art und Ursprung der Anfrage oder welche Art von Informationen (MIME Typen) vom Client unterstützt werden. PG2CGI wählt dann die zu benutzende Regel aufgrund ihrer linken Seite aus. Momentan existieren drei Typen von Regeln: Mit diesen Mechanismen wird es nun möglich, Regeln aufzustellen. Dazu wird eine Anzahl von Termen zu einem regulären Ausdruck angeordnet, der eine gültige linke Regelseite spezifiziert.. Die Terme stehen zwischen einem Paar geschweifter Klammern "{}".

Linke und rechte Seite einer Regel werden durch geschweifte Klammern "{}" umschlossen und durch einen Pfeil "->" voneinander getrennt.

Die Terme der rechten Regelseite haben die gleiche Syntax, wie die der linken Seite: einen Variablennamen, gefolgt von einem Doppelpunkt ":", sowie eine Zeichenfolge (in Anführungszeichen) und einem Semikolon ";" als Endzeichen. Alle Terme der rechten Regelseite sind von M4 auszuführende Zuweisungen von gegebenen Werte an die Variablen. Weitere Variablen können entweder in der Datei mit der Vorlage oder von dem entsprechen Treiber benutzt werden.

Wie erreichen die Informationen des Benutzers das CGI?

Ganz einfach. Aus den Zuordnungen, die durch die regulären Ausdrücke der Terme der linken Seite jeder Regel erzeugt worden sind, werden Zuweisungen an Variablen generiert, wobei die Namen dieser neuen Variablen die Form "term_<i>_match_<j> haben. <i> deutet an, daß es sich um den i-ten Term, <j> um den j-ten Teil (links beginnend) des regulären Ausdruckes handelt. Angenommen, query_string wird durch den Client mit folgendem Wert übergeben:
`NAME=JOSE&FAMNAME1=DE+LA+FUENTE&FAMNAME2=LOPEZ'

und die Regel auf dem WWW-Server sei wie folgt definiert:
     QUERY_STRING: "NAME=([^&]*)";
     QUERY_STRING: "FAMNAME1=([^&]*)";
     QUERY_STRING: "FAMNAME2=([^&]*)";
das Ergebnis wäre dann:
     term_0_match_0  <- "NAME=JOSE";
     term_0_match_1  <- "JOSE";
     term_1_match_0  <- "FAMNAME1=DE LA FUENTE";  
           (man beachte, daß "+" Zeichen durch Leerzeichen " " ersetzen worden sind)
     term_1_match_1  <- "DE LA FUENTE";
     term_2_match_0  <- "FAMNAME2=LOPEZ";
     term_2_match_1  <- "LOPEZ";

Treiber:

Der Gebrauch der Treiber wird in diesem Artikel nicht beschrieben, da dies ausführlich in der Dokumentation erläutert wird, die mit PG2CGI mitkommt. Der interessierte Leser sollte einen Blick in die beigefügte Referenzdokumentation werfen.
Momentan steht nur ein Treiber zur Verfügung, und zwar für die Anbindung an PostgreSQL Datenbanken (Treiber ist POSTGRESQL).  Allerdings bestehen Pläne, einen Treiber für LDAP Datenbanken  zu entwickeln.
 

Beispiel:

Im Folgenden betrachten wir nun beispielhaft einen kompletten Quelltext:

Betrachtet wird das Ankündigungsverzeichnis  (verwaltet durch eine Datenbank) auf slug.ctv.es (unter dem Verweis zu finden, der sich den Quelltexten anschließt). Es ist ein recht einfaches Beispiel, daß zwei Vorlagen benutzt, eine für das Betrachten einzelner Einträge der Liste und eine für eine komplette Auflistung.
 
/etc/html2sql.cfg
{
  PATH_INFO: "^/avisos/?$"; # Regel wird mittels PATH_INFO ausgewählt
  [SERVER_ADMIN: ".*"];     # Optionale Informationen in SERVER_ADMIN. 
} -> {
  DRIVER:   "POSTGRESQL";
  PGTTY:    "/dev/console";  # Logs werden an die Konsole geschickt
  PGDATABASE:     "postgres";
# Es wird eine Anfrage gestellt (dabei wird die oid immer mit übergeben.
# Sie wird intern benutzt, um den jeweiligen Datensatz 
# mittels der Vorlage darzustellen).
  PGQUERY:  "select oid,ct,titulo,texto,mt"
      " from avisos"
      " where (dt is NULL or dt > 'now')"
      " order by mt desc";
# Datei, die die Vorlage enthält 
  M4FILE:    "/usr/local/etc/httpd/plantillas_m4/avisos.m4";
  WEBMASTER: "term_1_match_0";
  #TESTMODE: "TRUE";
}

# Die folgende Regel ermöglicht die Wahl einer Ankündigung (aviso)
# mit einer bekannten OID (Primärschlüssel). Die Information ist in der
# Variable  PATH_INFO des CGI enthalten.

{
  PATH_INFO: "^/avisos/([0-9]+)/?$";
  SERVER_ADMIN: ".*";
} -> {
  DRIVER:   "POSTGRESQL";
  PGTTY:    "/dev/console";  # as before, write logs to the console
  PGDATABASE:     "postgres";
  OID:      "term_0_match_1"; # assign an OID

# Auch hier ist die Auswahl wichtig. Die OID des Feldes wird am Anfang  
# mit übergeben, für den Fall, daß ein Verweis fuer das Löschen dieses
# Eintrages gesetzt werden sollte.

  PGQUERY:  "select oid,ct,titulo,texto,mt,dt,autor"
            " from avisos"
            " where (dt is NULL or dt > 'now') and oid=OID";
# Hier wird nun eine andere Vorlage benutzt.
  M4FILE:    "/usr/local/etc/httpd/plantillas_m4/avisos_oid.m4";
  WEBMASTER: "term_1_match_0";
  #TESTMODE: "TRUE";
}

 
/usr/local/etc/httpd/plantillas_m4/avisos.m4
define(<<<for>>>, <<<dnl
ifelse(eval((<<<$2>>>) <= (<<<$3>>>)), 1,
<<<define(<<<$1>>>,<<<$2>>>)$4<<<>>>dnl
for(<<<$1>>>,eval(<<<$2>>>+1),<<<$3>>>, <<<$4>>>)dnl
>>>)dnl
>>>)dnl
divert(0)dnl
Mime-Version: 1.0
Content-type: text/html

<HTML>
  <BODY BGCOLOR="#ffffff">
    <CENTER>
      <H1>AVISOS A LOS NAVEGANTES QUE PASAN POR SLUG</h1>
    </center>
    <B>Nota:</b> Esta secci&oacute;n ha sido creada para dar a conocer
    cualquier noticia de inter&eacute;s relacionada con
    <A HREF="http://slug.ctv.es/">SLUG</a>,
    <A HREF="http://LuCAS.ctv.es/">LuCAS</a>,
    <A HREF="http://www.HispaLinux.ctv.es/">HispaLinux</a>
    y en general, cualquier servicio prestado por <B>slug.ctv.es</b>.<p>
    <CENTER><HR WIDTH=100></center>
ifelse(PGRES_RESULTSTATUS, <<<PGRES_TUPLES_OK>>>,<<<dnl
ifelse(PGRES_NTUPLES, 0,<<<dnl

      <!-- la tabla est\xe1 vac\xeda -->
      No hay avisos.<p>

>>>,<<<dnl /* PGRES_NTUPLES != 0 )( */
      <CENTER>
        <!-- contenido de la tabla -->
        <TABLE>
          <TR>
            <TH></th>
            <TH ALIGN="LEFT">Fecha-Hora&nbsp;</th>
            <TH ALIGN="LEFT">Asunto&nbsp;</th>
          </tr>

for(<<<i>>>,0,eval(PGRES_NTUPLES-1),<<<dnl
          <TR>
            <TD>
              <A HREF="/cgi-bin/pg2cgi/avisos/cell(i,0)">
                <IMG SRC="/icons/burst.gif">
              </a>
            </td>
            <TD><B>cell(i,1)&nbsp;</b></td>
            <TD>cell(i,2)&nbsp;</td>
          </tr>
>>>)dnl /* for */

        </table>
      </center>

>>>)dnl /* PGRES_NTUPLES */

>>>,<<<dnl /* ifelse PGRES_RESULTSTATUS )(*/

      Error en el resultado: <B>PGRES_RESULTSTATUS</b><BR>
      Mensaje del servidor: PGRES_ERRORMSG<P>

>>>)dnl

      <CENTER><HR WIDTH=100></center>
      <FONT SIZE=-2>
        <A HREF="mailto:WEBMASTER?subject=TABLON DE ANUNCIOS"><CODE>WEBMASTER</code></a>
      </font>
  </body>
</html>


 
/usr/local/etc/httpd/plantillas_m4/avisos_oid.m4
divert(-1)
$Id: generic_list.m4,v 1.1 1998/07/06 17:13:33 luis Exp $
define(<<<cell>>>, <<<PGRES_CELL_$1_$2>>>)
define(<<<field>>>, <<<PGRES_FNAME_$1>>>)
define(<<<for>>>, <<<dnl
ifelse(eval((<<<$2>>>) <= (<<<$3>>>)), 1,
<<<define(<<<$1>>>,<<<$2>>>)$4<<<>>>dnl
for(<<<$1>>>,eval(<<<$2>>>+1),<<<$3>>>, <<<$4>>>)dnl
>>>)dnl
>>>)dnl
divert(0)dnl
Mime-Version: 1.0
Content-type: text/html

<HTML>
  <BODY BGCOLOR="#ffffff">
    <CENTER>
      <H1>AVISO OID</h1>
    </center>
    <CENTER><HR WIDTH=100></center>

ifelse(PGRES_RESULTSTATUS, <<<PGRES_TUPLES_OK>>>,<<<dnl
ifelse(PGRES_NTUPLES, 0,<<<dnl

      <!-- la tabla est\xe1 vac\xeda -->
      No existe el aviso OID, o ha caducado.<p>

>>>,<<<dnl /* PGRES_NTUPLES != 0 )( */
      <CENTER>
        <!-- contenido de la tabla -->
        <TABLE>
          <TR VALIGN="BASELINE">
            <TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Fecha de entrada:</b></font> </td>
            <TD width="80%">cell(0,1)</td>
          </tr><TR VALIGN="BASELINE">
            <TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Fecha &uacute;ltima modif:</b></font> </td>
            <TD>cell(0,4)</td>
          </tr><TR VALIGN="BASELINE">
            <TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Fecha eliminaci&oacute;n:</b></font> </td>
            <TD WIDTH=*>cell(0,5)</td>
          </tr><TR VALIGN="BASELINE">
            <TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Autor:</b></font> </td>
            <TD><font size=+1><a href="mailto:cell(0,6)?subject=[TABLON-SLUG] cell(0,2)">cell(0,6)</a></font></td>
          </tr><TR VALIGN="BASELINE">
            <TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Asunto:</b></font> </td>
            <TD><font size=+1><B>cell(0,2)<B></font></td>
          </tr><TR>
            <TD COLSPAN=2 BGCOLOR="#c0ffff"><font color="#404040">cell(0,3)</font></td>
          </tr>
        </table>
      </center>

>>>)dnl /* PGRES_NTUPLES */

>>>,<<<dnl /* ifelse PGRES_RESULTSTATUS )(*/

      Error en el resultado: <B>PGRES_RESULTSTATUS</b><BR>
      Mensaje del servidor: PGRES_ERRORMSG<P>

>>>)dnl

      <CENTER><HR WIDTH=100></center>
      <FONT SIZE=-2>
        <A HREF="mailto:WEBMASTER?subject=TABLON DE ANUNCIOS"><CODE>WEBMASTER</code></a>
      </font>
  </body>
</html> 


Ergebnisse sind unter dieser URL zu finden:
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/

bzw. unter:
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/20384

Download

PG2CGI kann von den folgenden Adressen bezogen werden:
http://slug.ctv.es/~luis/utils/pg2cgi.tar.gz
http://slug.ctv.es/~luis/utils/pg2cgi.README
ftp://slug.ctv.es/pub/slug/luis/pg2cgi.tar.gz
ftp://slug.ctv.es/pub/slug/luis/pg2cgi.README

Übersetzung: Harald Radke
Webpages maintained by Miguel Ángel Sepúlveda
© Luis Colorado 1998
LinuxFocus 1999