Home Map Index Search News Archives Links About LF
[Top Bar]
[Bottom Bar]
[Photo of the Author]
Luis Colorado
A propos de l'Auteur

Luis Colorado travaille comme administrateur de systèmes Unix et d'accès Internet pour Telefónica Sistemas S.A. en Espagne. Il est diplômé de Physique de Universidad Complutense à Madrid et a developpé plusieurs utilitaires libres pour Unix. 

Ecrire à l'auteur
Contenu
Introduction
Motivation
M4
Comment ça marche?
Transférer des données de l'utilisateur vers la CGI
Télécharger

PG2CGI: Accéder à une base de données depuis le web

[Ilustration]

Résumé:

Cet article décrit un programme qui permet d'accéder à une base de données depuis une page HTML. L'objectif de ce programme est le contrôle de l'accès aux données, la flexibilité de la configuration et l'indépendance vis à vis de la mise en page. Ce programme est le résultat d'une série d'idées provenant de la lecture de plusieurs articles sur M4 qui sont sortis récemment dans les magazines Linux Journal et LinuxFocus (www.linuxfocus.org) pendant ces 12 derniers mois.


Introduction

Cet article décrit le raisonnement et les idées qui m'ont conduit à developper ce programme. Ce n'est pas un manuel (un guide de références accompagne la distribution du logiciel PG2CGI, l'URL de ce package est en fin de page) mais plutôt une présentation et une invitation à l'utiliser puis communiquer eventuellement leurs problèmes à l'auteur.

Motivation

J'ai écrit ce programme comme une réponse à une série d'articles publiés dans Linux Journal et LinuxFocus sur l'utilisation de M4 pour la gestion de documents HTML. Ces articles démontrent les avantages et le potentiel de M4, comme outil autonome, pour la maintenance et la génération dynamique de pages.

De plus, la disponibilité de nombreux serveurs web et moteurs de base de données contraste avec le manque d'utilitaires qui permettent d'interfacer les 2 environnements (La majorité de ces applications sont commerciales ou ont de sérieuses insuffisances dans les formats qu'elles peuvent prendre en compte).

Le programme tente d'unifier les 2 mondes grâce à une application qui satisfait les points suivants:

L'utilitaire présenté ici satisfait à ces exigences en contre partie d'une petite perte de perfomances (il doit lancer M4 plusieurs fois durant son exécution) mais les résultats sont satisfaisants dans la plupart des cas (Il faut prendre en considération que souvent, la requête sur la base de données prend plus de temps que la génération dynamique de la page HTML)

M4

M4 est un outil de trairement de macros developpé il y a bien longtemps. Notre logiciel en fait un usage intensif. Ce dernier point peut provoquer des pertes d'efficacité bien que nos tests avec l'utilitaire GNU M4 aient été relativement satisfaisants.

Expressions régulières:

Notre utilitaire fait un usage intensif des expressions régulières pour vérifier les règles de configuration à employer. Les expressions régulières sont préférées aux simples comparaisons parce qu'elles apportent de meilleures fonctionnalités et plus de possiblités. L'emploi des expressions régulièrers apporte, entre autres:
PG2CGI utilise les expressions régulières pour vérifier les règles de configuration à employer.

Prenons un exemple: Supposons que le client doive nous transmettre des informations dans la QUERY_STRING, au format suivant:

CHAMP=Valeur
Notez que la query_string doit satisfaire ce format et aucune information ne doit être ajoutée à la chaîne de caractères.

La mise en oeuvre de cette syntaxe se fait facilement en écrivant les termes suivants dans la règle de sélection:

 QUERY_STRING: "^CHAMP=[^&]*$";
La ligne ci-dessus garantit que la règle sera invoquée seulement si la QUERY_STRING est au bon format... Mais, de plus, si nous plaçons des parenthèses autour de la valeur, alors le programme pourra analyser la valeur correspondante:
 QUERY_STRING: "^CHAMP=([^&]*)$";
Dans le processus, le programme transforme les séquences d'échappement de la forme %xx introduite pour le navigateur.

Comment cela fonctionne-t-il?

C'est le moment de décrire comment fonctionne le programme. Lorsqu'il est lancé pour la 1ère fois, il reçoit les variables d'environnement du serveur web et se configure en fonction de leurs valeurs. Les variables d'environnement sont tout ce que le programme a à sa disposition pour savoir: Qui est le client? D'où vient la requête? Quelle est la requête? Quels types d'information (MIME type) sont supportées par le client? etc... PG2CGI sélectionne ensuite, la règle qui sera utilisée, basée sur l'énoncé de la partie gauche de la règle. Actuellement, il existe 3 types de règle: Avec toute cette artillerie, nous pouvons commencer à construire des règles. Nous regrouperons un nombre de termes qui nous permettront de construire une règle valide. Nous les placerons entre accolades "{ }" et nous les appellerons "la partie gauche de la règle".

La partie gauche et la partie droite d'une règle sont délimitées par des accolades "{ }" et sont séparées par le symbole`->'.

La partie droite contient les termes avec une même syntaxe: un nom de variable, le caractère ':', une chaîne de caractères et le caractère fin de chaîne ';'. Tous les termes du coté droit sont des assignations de valeurs à des variables effectuées par M4.

D'autres variables peuvent-être utilisées aussi bien par le modèle de fichier que par le pilote correspondant.

Comment les informations en provenance du client atteignent la CGI?

Très simplement. Les groupes créés à partir des expressions régulières, dans la partie gauche des définitions de chaque règle, sont transformés en variables. (Les noms utilisés pour ces nouvelles variables sont de la forme `term_<i>_match_<j>', où <i> se réfère au numéro du terme dans la règle et <j> se réfère au numéro du groupe en comptant à partir de la gauche de l'expression régulière. Ainsi, si la query_string passée au client est:
`NAME=JOSE&FAMNAME1=DE+LA+FUENTE&FAMNAME2=LOPEZ'

et la règle déclarée dans le site web est :

     QUERY_STRING: "NAME=([^&]*)";
     QUERY_STRING: "FAMNAME1=([^&]*)";
     QUERY_STRING: "FAMNAME2=([^&]*)";
Le résultat serait:
     term_0_match_0  <- "NAME=JOSE";
     term_0_match_1  <- "JOSE";
     term_1_match_0  <- "FAMNAME1=DE LA FUENTE"
;  
           
(noté le remplacement du caractère + par ` ')
     term_1_match_1  <- "DE LA FUENTE";
     term_2_match_0  <- "FAMNAME2=LOPEZ";
     term_2_match_1  <- "LOPEZ";
Pilotes:

Nous ne décrirons pas, dans cet article, l'utilisation des pilotes. Tout est déjà expliqué dans la documentation fournie avec la distribution de PG2CGI. Le lecteur intéressé est encouragé à lire le manuel de référence

Pour le moment, il n'existe qu'un seul pilote pour la connexion à la base de données PostgreSQL. Cependant, l'auteur a prévu d'écrire un autre pilote pour les bases de type LDAP.

Un exemple:

Examinons maintenant le source d'un exemple complet.

Considérons la table de déclarations provenant de la base de données de déclarations à slug.cvt.es (Suivez le lien "AVISO A LOS NAVEGANTES"). C'est un exemple très simple qui utilise 2 modèles pour voir des enregistrements individuellement ou une liste complète. /etc/html2sql.cfg
{
  PATH_INFO: "^/avisos/?$"; # Selectionne by PATH_INFO
  [SERVER_ADMIN: ".*"];     
# Obtient des informations de SERVER_ADMIN. Optionnel
} -> {
  DRIVER:   "POSTGRESQL";
  PGTTY:    "/dev/console";  # Envoie les log à la console
  PGDATABASE:     "postgres";
# Nous faisons une requête (Toujours écrire l'oid qui
# l'utilisera en interne dans le fichier modèle
# pour lier les enregistrements individuels).
  PGQUERY:  "select oid,ct,titulo,texto,mt"
      " from avisos"
      " where (dt is NULL or dt > 'now')"
      " order by mt desc";
# Fichier contenant le modèle
  M4FILE:    "/usr/local/etc/httpd/plantillas_m4/avisos.m4";
  WEBMASTER: "term_1_match_0";
  #TESTMODE: "TRUE";
}

# La règle de sélection suivante permet de sélectionner une déclaration (aviso)
# avec un OID connu (clé primaire ou primary key). L'information est incluse dans
# la variable PATH_INFO de la CGI.

{
  PATH_INFO: "^/avisos/([0-9]+)/?$";
  SERVER_ADMIN: ".*";
} -> {
  DRIVER:   "POSTGRESQL";
  PGTTY:    "/dev/console";  # Comme précédemment, permet 
d'écrire les "logs" sur la console
  PGDATABASE:     "postgres";
  OID:      "term_0_match_1"; # assigne un OID

# Encore une fois la sélection est importante. Nous incluons l'OID
# au début du champ pour le cas où nous souhaitons écrire
# un hyperlien pour effacer cet enregistrement.

  PGQUERY:  "select oid,ct,titulo,texto,mt,dt,autor"
            " from avisos"
            " where 
(dt is NULL or dt > 'now') and oid=OID";
# Le modèle est différent maintenant
  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> 

Le résultat peut-être vu à ces adresses:
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/
ou
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/20384

Téléchargements

Le programme PG2CGI peut-être téléchargé aux URLs suivantes:
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

Traduit, de l'anglais, par Éric Santonacci, texte original en espagnol

© Luis Colorado 1998
LinuxFocus 1999
Contacter le Webmestre