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. 


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:

Être facile à configurer. La configuration du système est contrôlée par un seul fichier ce qui permet un haut niveau de flexibilité dans la configuration

Permettre le contrôle de la sécurité du site. L'application supporte une méthode assez générale pour sélectionner une configuration et peut être facilement configurable pour contrôler l'accès au site web

C'est un fait bien connu que HTML est un langage de formatage pour formater des documents qui pourront être affichés avec un navigateur Internet. Une caractéristique de base d'un bon générateur de texte est un langage convenable pour formater le texte offrant suffisamment de possiblités de contrôle pour l'arrangement des paragraphes et parties de texte dans la composition finale de la page. Cependant, dans la plupart des langages de formatage, il y a toujours une série de macros qui permettent de manipuler les éléments flottants du document (tables, images, etc, qui s'ajustent dynamiquement sur la page au chargement).
La plupart des utilitaires que je connais pour interfacer HTML et des bases de données, génèrent l'information sur le texte affiché en étendant le jeu de balises HTML (NdT: en anglais, tag). Ces nouvelles balises prennent le rôle de 'macros'. Cependant, cette approche à un serieux inconvénient: La plupart du temps, nous devons modifier les éléments dans les balises du code HTML natif et c'est une limitation importante. Souvent, ces utilitatires doivent créer des balises dans le but d'obtenir un effet déterminé sur une balise HTML existante. Mon programme utilise M4 dans le but de remplacer les macros partout où cela est nécessaire. Le programme ne génère aucun texte formaté, et c'est pourquoi il est indépendant du format de sortie du langage utilisé. Le programme génère une série de macros comme résultat d'une requête puis M4 génère un document HTML en utilisant ces macros et un modèle HTML donné.

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 , texte original en espagnol

© Luis Colorado 1998
LinuxFocus 1999
Contacter le .