Une CGI (Common Gateway Interface) permet d'interfacer une page HTML avec une application externe de traitement des données saisies dans cette page.
Le schéma ci-dessous donne un bref aperçu du fonctionnement d'une CGI :
Le client (navigateur) en 1 saisit les données dans la page HTML. Ces données sont envoyées au serveur 2 qui lance la CGI en 3. Le résultat est ensuite retourné au client.
La CGI est un programme exécutable qui peut donc utiliser n'importe quel langage de programmation :
Pour des raisons
de portabilité, le langage PERL est souvent utilisé pour
l'écriture des CGI.
Cependant, pour des raisons de simplicité de syntaxe, nous utiliserons
ici le shell UNIX standard (Bourne Shell).
Format d'appel d'une CGI
Une page HTML désirant utiliser une CGI aura le format suivant:
<HEAD>
<TITLE>Test CGI</TITLE>
</HEAD>
<BODY>
<HR>
<FORM ACTION="action.cgi">
NOM : <INPUT NAME="NOM" SIZE="40"><BR>
PRENOM : <INPUT NAME="PRENOM" SIZE="40"><BR>
<P>
<INPUT NAME="SUBMIT" TYPE=SUBMIT VALUE="Envoyer">
<INPUT NAME="RESET" TYPE=RESET VALUE=Effacer">
</FORM>
</BODY>
</PRE>
Le nom du programme
CGI est passé au paramètre ACTION de la définition
de la forme (FORM).
Les types INPUT permettent de saisir les données, les boutons de
type SUBMIT et RESET permettent respectivement la validation des données
(et donc le lancement de la CGI action.cgi) et la remise à zéro
des zones de saisie. La liste des types utilisés par les formes
est disponible sur http://www.htmlhelp.com/reference/wilbur/quickref.html
Le résultat de l'affichage de cette page puis de la saisie d'un nom et d'un prénom est le suivant:
En appuyant sur Envoyer, on obtient la page HTML:
Cette page a donc été calculée dynamiquement à partir des données fournies lors de la saisie.
Avant de détailler l'écriture d'une CGI, il est nécessaire de définir quelques bases concernant l'utilisation du shell UNIX.
Notion de Shell UNIX
2.1
Définition
Le
shell est un langage de commande interprétée, similaire
aux célèbres fichiers .BAT du système MS-DOS.
Un shell (ou interpréteur) est affecté à tout utilisateur
UNIX. Le shell standard est le Bourne Shell correspondant au programme
/bin/sh.
Par défaut, le shell utilise le clavier comme entrée standard
et l'écran comme sortie standard mais il est très simple
de les rediriger en utilisant les caractères '<' et '>' ou bien
le pipe symbolisé par le caractère '|'.
2.2
Utilisation
Le shell permet de lancer des commandes simples ou bien des suites de
commandes que l'on peut sauver dans un fichier appelé shell-script.
Par exemple:
#!/bin/sh
# Cet exemple simple dit bonjour
echo Bonjour $USER !
donne comme résultat
pierre@pcpf % ./test1.sh
Bonjour pierre !
Le caractère # indique un commentaire. La première ligne est théoriquement obligatoire et indique au système quel interpréteur utiliser pour traiter le fichier (ici le shell /bin/sh). Pour un programme en PERL on aurait:
#!/usr/local/bin/perl
print "Ceci est un
programme PERL";
exit (0);
Attention car un shell-script doit être EXECUTABLE sinon on obtient le message:
pierre@pcpf % ./test1.sh
bash: ./test1.sh: Permission denied
Il faut alors faire:
pierre@pcpf % sh
test1.sh
Bonjour pierre !
ou bien le rendre
exécutable par:
chmod +x test1.sh
2.3
Les variables d'environnement
Cette notion est fondamentale dans le système UNIX. Tout processus
UNIX s'exécute dans un environement hérité de son
père. Cet environnement comprend un certain nombre de variables
contenant des chaînes de caractères. Un utilisateur peut
connaître la liste des variables de son environnement par la commande
env:
pierre@pcpf % env
HOSTNAME=pcpf.lectra.fr
LOGNAME=pierre
EMACS=t
MINICOM=-c on
TERM=dumb
HOSTTYPE=i386
PATH=:/bin:/usr/bin:/usr/X11R6/bin:/usr/ucb:/usr/local/bin:/sbin:
/usr/X11/bin:/usr/andrew/bin:/usr/openwin/bin:/usr/games:.
:/usr/local/bin:/sbin:/usr/X11/bin:/usr/andrew/bin:/usr/openwin/bin:/usr/games:.
HOME=/home/system/pierre
SHELL=/bin/bash
PS1=pierre@pcpf %
PS2=>
USER=pierre
MANPATH=/usr/local/man:/usr/man/preformat:/usr/man:/usr/X11/man:/usr/openwin/man
LESS=-MM
COLUMNS=86
DISPLAY=:0.0
OSTYPE=Linux
...
On peut également connaître la valeur d'une variable donnée en faisant simplement:
pierre@pcpf % echo
$HOME
/home/system/pierre
ou bien créer une nouvelle variable en faisant:
pierre@pcpf % X=titi
pierre@pcpf % export X
pierre@pcpf % echo $X
titi
Le commande export permet à la variable d'être visible depuis les environnements fils de l'environnement courant. Pour effacer le contenu d'une variable, on fera:
pierre@pcpf % unset
X
pierre@pcpf % echo $X
pierre@pcpf %
A l'intérieur d'un shell-script, les variables spéciales $1, $2, etc. représentent les paramètres passés au shell-script. Le shell-script:
#! /bin/sh
echo "mes paramètres sont:"
echo
echo "Le premier: $1"
echo "Le deuxième: $2"
echo "Tous: $*"
echo "Le nombre de paramètres: $#"
donne à l'exécution:
pierre@pcpf % par.sh
toto tutu titi
mes paramètres sont:
Le premier: toto
Le deuxième: tutu
Tous: toto tutu titi
Le nombre de paramètres: 3
La variable spéciale $* contient tous les paramètres passés. La variable $# contient le nombre de ces paramètres. La commande set permet de re-affecter les valeurs des paramètres au cours de l'exécution:
#! /bin/sh
echo "mes paramètres sont:"
echo
echo "Le premier: $1"
echo "Le deuxième: $2"
echo "Tous: $*"
echo "Le nombre de paramètres: $#"
# Nouveaux paramètres
NOUVEAU="un deux"
set $NOUVEAU
echo "Nouveaux paramètres:"
echo
echo "Le premier: $1"
echo "Le deuxième: $2"
echo "Tous: $*"
echo "Le nombre de paramètres: $#"
qui donne:
pierre@pcpf % par2.sh
titi toto
mes paramètres sont:
Le premier: titi
Le deuxième: toto
Tous: titi toto
Le nombre de paramètres: 2
Nouveaux paramètres:
Le premier: un
Le deuxième: deux
Tous: un deux
Le nombre de paramètres: 2
Il est également possible d'effectuer des boucles et des tests sur les valeurs des variables.
Voici un exemple
de boucle:
pierre@pcpf % for i in un deux trois
> do
> echo "La valeur de i est $i"
> done
La valeur de i est un
La valeur de i est deux
La valeur de i est trois
Voici un exemple de test. Soit le shell-script:
#! /bin/sh
if [ "$SEX" = "M" ]; then
echo "Sans contrefaçon, je suis un garçon
!"
else
echo "Femme des années 80, lalalère !"
fi
qui donne à l'exécution:
pierre@pcpf % export
SEX=M
pierre@pcpf % ./sex.sh
Sans contrefaçon, je suis un garçon !
pierre@pcpf % unset SEX
pierre@pcpf % ./sex.sh
Femme des années 80, lalalère !
Un possibilité très intéressante est l'affectation d'une variable par le résultat de l'exécution d'une autre commande:
pierre@pcpf % X=`date`
pierre@pcpf % echo $X
Mon May 12 09:50:18 MET DST 1997
Ceci est très
utilisé dans la rédaction des CGI.
Il est également possible d'évaluer le contenu d'une variable
dans le shell courant par la commande eval. Bien entendu ce contenu doit
respecter la syntaxe du shell:
pierre@pcpf % X=`echo
"Y=2"`
pierre@pcpf % echo $X
Y=2
pierre@pcpf % echo $Y
pierre@pcpf % eval
$X
pierre@pcpf % echo $Y
2
Cette commande est utilisée systématiquement pour le traitement d'une CGI en shell.
On peut aussi affecter
une variable en lisant sa valeur sur l'entrée standard:
pierre@pcpf % read X
toto
pierre@pcpf % echo $X
toto
Les commandes vues précédemment sont intégrées au shell (elle sont dites builtin):
pierre@pcpf % type
echo
echo is a shell builtin
pierre@pcpf % type eval
eval is a shell builtin
pierre@pcpf % type set
set is a shell builtin
pierre@pcpf % type unset
unset is a shell builtin
Quelques commandes utiles
Les commandes UNIX suivantes sont très utilisées pour la rédaction des CGI en shell.
CAT
Cette commande permet d'afficher le contenu d'un fichier sur la sortie
standard:
pierre@pcpf % cat /etc/issue
Welcome to Linux 2.0.29.
Un syntaxe particulère permet aussi d'afficher les lignes précédant un marqueur donné (très utile pour afficher du HTML dynamiquement):
pierre@pcpf % cat
<<FIN
> tuti
> titu
> titi
> FIN
tuti
titu
titi
GREP
Permet de rechercher une chaîne de caractères dans un ensemble
de fichiers:
pierre@pcpf % grep
BODY *.html
adresses.html:<BODY>
adresses.html:</BODY>agences.html:<BODY>
agences.html:</BODY>
cartes.html:<BODY>
cartes.html:</BODY>
...
Grâce au shell, on peut également affecter une variable avec le résultat de la commande:
SITELINE=`grep [${i}
] $SCRIPTFILE`
SED
SED (Stream EDitor) est la version ligne du fameux éditeur ED (connu
déjà sur Mini6 !). Il est d'un maniement assez peu convivial
mais il est très puissant pour le traitement des chaînes
de caractères:
pierre@pcpf % echo
tititoto
tititoto
pierre@pcpf % echo tititoto | sed -e 's/toto/tutu/g'
tititutu
Cette commande est à la base du décodage des paramètres d'un CGI en shell.
Structure d'un script CGI
4.1 Structure de
base
Voici un exemple simple de CGI minimal:
#!/bin/sh
echo MIME-Version: 1.0
echo Content-type: text/html
echo
echo "<BODY>Script minimal</BODY>"
Les 3 commandes echo au début du fichier sont indispensables pour indiquer au serveur la version et le type de données MIME (Multimedia Internet Mail Extensions) retourné par la CGI. Dans notre cas, la CGI génère dynamiquement une page HTML (d'ou le type text/html). Cette CGI n'utilise pas de variable et affiche simplement un message dans la page HTML.
4.2 Transfert des
données entre
HTML et CGI
Dans le cas de pages plus évoluées, le système de CGI utilise 2 méthodes pour transférer les données saisies dans la page HTML:
o La méthode GET. Dans cette méthode, les données sont transmises à la CGI grâce à la variable d'environnement QUERY_STRING sous la forme:
NOM=Pierre&PRENOM=Ficheux&SUBMIT=Envoyer
Il faut donc extraire les données en utilisant par exemple l'utilitaire sed dans une ligne du type:
QUERY=`echo $QUERY_STRING | sed -e "s/=/='/g" -e "s/&/';/g" -e "s/+/ /g" -e "s/%0d%0a/<BR>/g" -e "s/$/'/" `
pour obtenir la variable QUERY que l'on peut évaluer dans le shell courant:
NOM='Pierre';PRENOM='Ficheux';SUBMIT='Envoyer'
ce qui crée 3 nouvelles variables NOM, PRENOM et SUBMIT utilisables dans la suite du shell-script.
o La méthode GET est utilisée par défaut. Elle n'est cependant pas recommandée dans le cas du passage d'une grande quantité de données à cause des troncatures possibles de la chaîne QUERY_STRING.
o La méthode POST. Les données sont alors transmises par l'entrée standard de la CGI. On validera alors une pseudo variable QUERY_STRING par
read QUERY_STRING
Dans ce cas la, la taille des données n'est pas limitée. On peut connaître cette taille par le contenu de la variable CONTENT_LENGTH. L'utilisation de la méthode POST nécessite une commande HTML du type:
<FORM ACTION="action.cgi" METHOD="POST">
Le type de méthode utilisé peut-être récupéré par la CGI dans le variable REQUEST_METHOD.
Voici donc une nouvelle version du script capable de traiter une méthode GET ou POST:
#!/bin/sh
echo MIME-Version:
1.0
echo Content-type: text/html
echo
if [ "$REQUEST_METHOD"
= "POST" ]; then
read QUERY_STRING
fi
QUERY=`echo $QUERY_STRING | sed -e "s/=/='/g" -e "s/&/';/g" -e "s/+/
/g" -e "s/%0d%0a/<BR>/g" -e "s/$/'/" `
eval $QUERY
cat <<EOF
<BODY>
<H1>Je m'appelle $NOM $PRENOM</H1>
</BODY>
EOF
4.3 Test de CGI sans serveur
Le système de CGI nécessite à priori un serveur HTTP pour fonctionner. Il est cependant possible de tester une CGI en mode GET en dehors de l'utilisation d'un serveur et même d'un client HTTP. Pour cela il suffit:
- d'affecter la variable QUERY_STRING avec une chaîne respectant la syntaxe de transfert des données CGI.
pierre@gwladys %
QUERY_STRING="NOM=Pierre&PRENOM=Ficheux&SUBMIT=Envoyer"
pierre@gwladys % export QUERY_STRING
- d'exécuter
la CGI dans le shell courant:
pierre@gwladys % ./action.cgi
MIME-Version: 1.0
Content-type: text/html
<BODY>
<H1>Je m'appelle Pierre Ficheux</H1>
</BODY>
On peut également
utiliser l'option <EM>-x</EM> pour utiliser le mode trace du
shell:
pierre@gwladys %
sh -x action.cgi
+ echo MIME-Version: 1.0
MIME-Version: 1.0
+ echo Content-type: text/html
Content-type: text/html
+ echo
+ [ = POST
]
+ echo NOM=Pierre&PRENOM=Ficheux&SUBMIT=Envoyer
+ sed -e s/=/='/g -e s/&/';/g -e s/+/ /g -e s/%0d%0a/<BR>/g -e
s/$/'/
QUERY=NOM='Pierre';PRENOM='Ficheux';SUBMIT='Envoyer'
+ eval NOM='Pierre';PRENOM='Ficheux';SUBMIT='Envoyer'
NOM=Pierre
PRENOM=Ficheux
SUBMIT=Envoyer
+ cat
<BODY>
<H1>Je m'appelle Pierre Ficheux</H1>
</BODY>
<BODY>
<H1>Je m'appelle Pierre Ficheux</H1>
</BODY>
Bibliographie
http://www.univ-rennes1.fr/CRI/doc-html/cgi-ismap/GUT.html (World-Wide Web et les formulaires électroniques)
http://www.htmlhelp.com/reference/wilbur (Manuel de référence HTML-3.2)