Table des matières

Introduction : 5

Un bref aperçu du langage : 6

Le programme « Hello World » 7

Poser une question et se souvenir du résultat. 7

Avoir le choix. 7

Demander le mot Magique. 7

Plus qu’un seul mot magique. 8

Donner à chaque personne son propre mot magique. 8

Gérer différente forme d’entrées. 9

Travailler par module : 9

Mettre les mots magiques dans un fichier séparé. 9

Assurons un taux modeste de sécurité : 9

Prévenir d'une intrusion éventuelle : 10

Plusieurs fichier de mot magique : 11

Lister les mots magiques : 11

Rendre les vieux fichiers plus remarquables : 11

Introduction au CGI 12

Common Gateway Interface (CGI). 12

Pourquoi Cgi? 13

Choix De Langage : 13

Avertissements 13

Hello World 14

Dissection de hello.cgi 16

Hello World! En C 16

Sortie Du Cgi 16

Installation et Exécution de programmes CGI 17

Configuration de serveur pour le cgi. 18

Installation CGI sur Serveurs UNIX 18

Quelques serveurs communs d’Unix 19

Installation des cgi sur Windows 19

Installation de cgi sur le Macintosh 20

L'exécution de cgi 20

HTML formes 20

La soumission de forme : 21

variable d’environnement 22

GET Versus POST 23

L'entrée (INPUT) encodée : 23

L'analyse de l'entrée 25

Cgi-lib.pl 25

cgihtml 26

Un simple programme cgi 26

Exemples de CGI : 27

Librairie Vidéo Online : 27

La Basse de donne 27

Moteur et annotations de requête 30

Le Programme de Administrateur 34


Introduction :


Le langage le plus adapté pour mettre en place les procédures CGI est le langage PERL (Practical Extraction and Report Language), écrit par Larry Wall.

Il vous permettra même de bénéficier sur votre Macintosh ou votre PC d'un langage aussi puissant que les ShellScripts d'Unix. Perl a connu quelques critiques en 1995-1996 comme tout l'univers des CGI car le langage JAVA tenait le haut de l'affiche.

Mais aujourd'hui :

l'annonce par Microsoft de Windows NT 5 incluant Perl comme langage de scripting,

le support de Perl en mode kernel par les serveurs Apache et Netscape permet une exécution des scripts en Perl sans lancement de l'interpréteur Perl qui se trouve maintenant en mémoire en accès direct avec le serveur HTTP,

Le nombre grandissant de bibliothèques Perl ont rendu à ce langage ses lettres de noblesse bien méritées.

Il existe plusieurs versions de langage PERL, celle qui est explicitée ici est la version Perl 5.004 qui existe en environnement UNIX, PC et Macintosh.

De bons manuels de langage PERL existent sur Internet, si vous désirez apprendre ce langage, et ce en langue anglaise. Des interpréteurs PERL sont également disponibles sur Internet. Le tout a l'avantage d'être gratuit.

Tout ce que vous désirez connaître sur le langage PERL se trouve sur la page Yahoo

[www.yahoo.com/Computers_and_Internet/Programming_Languages/Perl/]

Mais c'est surtout un répertoire appelé CPAN (Comprehensive Perl Archive Network) qui regroupe l'ensemble des ressources relatives au langage PERL. On y trouve les documents, les sources, les librairies officielles relatives au langage.

Les CPAN possèdent de nombreux sites miroirs et le site principal est www.CPAN.org

Il existe une news sur le langage PERL : comp.lang.perl.misc [news:comp.lang.perl.misc]

Désormais un groupe français existe : fr.comp.lang.perl



Un bref aperçu du langage :



Le programme « Hello World »


#!/usr/bin/perl -w

print ("Hello, world!\n");


La première ligne indique que c’est un programme Perl et son path (son UNIX), la première ligne est aussi une commande pour le compilateur  Perl l’option –w affichera tous les avertissements lors de la compilation.

La deuxième ligne est le programme lui-même.


Poser une question et se souvenir du résultat.


#!/usr/bin/perl -w

print "What is your name? ";

$name = <STDIN>;

chomp ($name);

print "Hello, $name!\n";


Le signe $ indique que name est une variable scalaire, chomp quand à lui élimine le <\n> qui termine le string.


Avoir le choix.


#!/usr/bin/perl

print "What is your name? ";

$name = <STDIN>;

chomp ($name);

if ($name eq "Randal") {

print "Hello, Randal! How good of you to be here!\n";

} else {

print "Hello, $name!\n"; # ordinary greeting

}


L’opérateur eq compares les deux strings. S’il sont égaux (tous les caractères sont identique et leur longeurs sont égales), le résultat est vrai.


Demander le mot Magique.


#!/usr/bin/perl -w

$secretword = "llama"; # the secret word

print "What is your name? ";

$name = <STDIN>;

chomp $name;

if ($name eq "Randal") {

print "Hello, Randal! How good of you to be here!\n";

} else {

print "Hello, $name!\n"; # ordinary greeting

print "What is the secret word? ";

$guess = <STDIN>;

chomp ($guess);

while ($guess ne $secretword) {

print "Wrong, try again. What is the secret word? ";

$guess = <STDIN>;

chomp ($guess);

}

}


En premier nous définissons le mot magique, puis demandons le nom et enfin le mot magique pour tout le monde sauf Randal.


Plus qu’un seul mot magique.


#!/usr/bin/perl -w

@words = qw(camel llama alpaca);

print "What is your name? ";

$name = <STDIN>;

chomp ($name);

if ($name eq "Randal") {

print "Hello, Randal! How good of you to be here!\n";

} else {

print "Hello, $name!\n"; # ordinary greeting

print "What is the secret word? ";

$guess = <STDIN>;

chomp ($guess);

$i = 0; # try this word first

$correct = "maybe"; # is the guess correct or not?

while ($correct eq "maybe") { # keep checking til we know

if ($words[$i] eq $guess) { # right?

$correct = "yes"; # yes!

} elsif ($i < 2) { # more words to look at?

$i = $i + 1; # look at the next word next time

} else { # no more words, must be bad

print "Wrong, try again. What is the secret word?";

$guess = <STDIN>;

chomp ($guess);

$i = 0; # start checking at the first word again

}

} # end of while not correct

} # end of "not Randal"


La deuxième ligne indique que l’on travaille avec un tableau, qui est initialisé à l’aide de qw, remarque importante les tableaux se comporte comme en C, le premier élément se trouve dans la case 0.

Vous aurez aussi remarqué que la variable words est précédé une fois du signe @ et une autre fois de $, cela s’explique par le type d’accès que l’on fait sur la variable, si on la considère comme tableau@ ou comme string$.


Donner à chaque personne son propre mot magique.


Nous allons initialiser un type de tableau particulier de la manière suivante :


Personne

Mot Magique

Fred

Camel

Barney

Llama

Betty

Alpaca

Wilma

alpaca


#!/usr/bin/perl

%words = qw(

fred camel

barney llama

betty alpaca

wilma alpaca

);

print "What is your name? ";

$name = <STDIN>;

chomp ($name);

if ($name eq "Randal") {

print "Hello, Randal! How good of you to be here!\n";

} else {

print "Hello, $name!\n"; # ordinary greeting

$secretword = $words{$name}; # get the secret word

print "What is the secret word? ";

$guess = <STDIN>;

chomp ($guess);

while ($guess ne $secretword) {

print "Wrong, try again. What is the secret word? ";

$guess = <STDIN>;

chomp ($guess);

}

}


Ce type de tableaux particulier est appelé « table de Hachage », c’est à dire que fred, barney, .. sont des clés qui permettent de récupérer le mot magique.

Remarque si le nom n’est pas trouvé, on recevra un string vide.


Gérer différente forme d’entrées.


Un des problèmes restant dans notre programme est que Randal, Randal, RanDaL ne sont pas considérer de la même manière alors qu’ilsont identique…pour cela nous allons ajouter une instruction qui vas remplacer les caractères A-Z par a-z, ce qui donne : $name =~ tr/A-Z/a-z/;


Travailler par module :


sub good_word {

my($somename,$someguess) = @_; # name the parameters

$somename =~ s/\W.*//; # get rid of everything after first word

$somename =~ tr/A-Z/a-z/; # lowercase everything

if ($somename eq "randal") { # should not need to guess

return 1; # return value is true

} elsif (($words{$somename} || "groucho") eq $someguess) {

return 1; # return value is true

} else {

return 0; # return value is false

}

}

Voici un bel exemple de fonction Perl, les paramètres se trouvent dans @_, la fonction my les déclare et les assigne comme private.


Mettre les mots magiques dans un fichier séparé.


sub init_words {

open (WORDSLIST, "wordslist");

while ($name = <WORDSLIST>) {

chomp ($name);

$word = <WORDSLIST>;

chomp ($word);

$words{$name} = $word;

}

close (WORDSLIST);

}


On travaille ici avec un simple fichier texte, composé du nom <CR> mot magique <CR> et ainsi de suite…


Une amélioration possible serait possible au niveau du test de la boucle while , il serait en effet plus propre de mettre while ( defined ($name = <WORDLIST>) ) { car lorsque l’on atteint eof, le string renvoyé n’est pas vide mais undef.


Assurons un taux modeste de sécurité :


Imaginons que la liste de mots magiques doive changer au moins une fois par semaine, si les dernières modifications date de plus d'une semaine on refusera de démarrer le programme.


sub init_words {

open (WORDSLIST, "wordslist") ||

die "can't open wordlist: $!";

if (-M WORDSLIST >= 7.0) { # comply with bureaucratic policy

die "Sorry, the wordslist is older than seven days.";

}

while ($name = <WORDSLIST>) {

chomp ($name);

$word = <WORDSLIST>;

chomp ($word);

$words{$name} = $word;

}

close (WORDSLIST) || die "couldn't close wordlist: $!";

}


la valeur de -M WORDLIST est comparée à 7 s'il est plus grand nous travaillons avec un mauvais fichier.


Prévenir d'une intrusion éventuelle :


Corsons encore un petit peu le tout en ajoutant le fait que chaque mauvais mot magique provoque l'envoi d'un mail vers l'administrateur.


sub good_word {

my($somename,$someguess) = @_; # name the parameters

$somename =~ s/\W.*//; # get rid of stuff after

# first word

$somename =~ tr/A-Z/a-z/; # lowercase everything

if ($somename eq "randal") { # should not need to guess

return 1; # return value is true

} elsif (($words{$somename}||"groucho") eq $someguess) {

return 1; # return value is true

} else {

open MAIL,"|mail YOUR_ADDRESS_HERE";

print MAIL "bad news: $somename guessed $someguess\n";

close MAIL;

return 0; # return value is false

}

}


Vous devez rajouter l'adresse de votre administrateur à la place de |mail YOUR_ADDRESS_HERE

Cette ligne est composée du pipe symbol "|" qui signifie que nous allons travailler avec une ligne de commande plutôt qu'avec un fichier.


Plusieurs fichier de mot magique :

sub init_words {

while ( defined($filename = glob("*.secret")) ) {

open (WORDSLIST, $filename) ||

die "can't open wordlist: $!";

if (-M WORDSLIST < 7.0) {

while ($name = <WORDSLIST>) {

chomp $name;

$word = <WORDSLIST>;

chomp $word;

$words{$name} = $word;

}

}

close (WORDSLIST) || die "couldn't close wordlist: $!";

}

}


La fonction glob retourne succesivement le différent nom de fichier qui correspondent au critère de recherche.


Lister les mots magiques :


Comment faire pour lister tous les mots magiques et leur utilisateur correspondant ?

Attention il s'agit maintenant d'une autre application.


#!/usr/bin/perl

while ( defined($filename = glob("*.secret")) ) {

open (WORDSLIST, $filename) || die "can't open wordlist: $!";

if (-M WORDSLIST < 7.0) {

while ($name = <WORDSLIST>) {

chomp ($name);

$word = <WORDSLIST>;

chomp ($word);

write; # invoke format STDOUT to STDOUT

}

}

close (WORDSLIST) || die "couldn't close wordlist: $!";

}

format STDOUT =

@<<<<<<<<<<<<<<< @<<<<<<<<< @<<<<<<<<<<<

$filename, $name, $wor

.


La chose importante à remarquer sont les 4 dernières lignes qui représentent le format de sortie des données, le mot réservé format indique que l'on va définir un format, STDOUT précise quel type de format nous allons utiliser, les lignes suivantes sont le format lui-même.


Nous pourrions rajouter

format STDOUT_TOP =

Page @<<

$%


Filename Name Word

================ ========== ============

.

Pour définir un format d'en tête de page.


Rendre les vieux fichiers plus remarquables :


Lorsque nous listons les fichiers *.secret et que l'on remarque que leur période de validité est écoulée nous allons maintenant les renommer en *.old.


sub init_words {

while ( defined($filename = glob("*.secret")) ) {

open (WORDSLIST, $filename) ||

die "can't open wordlist: $!";

if (-M WORDSLIST < 7.0) {

while ($name = <WORDSLIST>) {

chomp ($name);

$word = <WORDSLIST>;

chomp ($word);

$words{$name} = $word;

}

} else { # rename the file so it gets noticed

rename ($filename,"$filename.old") ||

die "can't rename $filename to $filename.old: $!";

}

close (WORDSLIST) || die "couldn't close wordlist: $!";

}

}


Remarquer la fonction rename qui permet de renommer les fichiers trop âgés, en fichier *.old.







Introduction au CGI


Common Gateway Interface (CGI).


Le CGI (interface de passerelle commune) est une interface avec le web serveur qui vous permet d'étendre la fonctionnalité du serveur. En utilisant le cgi, vous pouvez agir l'un sur l'autre avec les utilisateurs qui accèdent à votre site. À un niveau théorique, le cgi vous permet d'étendre la capacité de votre serveur pour analyser (interpréter) le date de l ‘utilisateur en prévenant du browser. À un niveau pratique, le cgi est une interface qui permet au programmeur d'écrire des programmes qui peuvent facilement communiquer avec le serveur.


Normalement, si vous vouliez étendre les capacités du serveur de Web, vous devriez modifier le serveur vous-même. C'est une solution indésirable parce qu'il exige une compréhension profond de programmation réseau, de l'Internet et le protocole de World Wide Web. Il exigerait également éditer et recompilé le code source de serveur ou écrire un serveur fait sur commande pour chaque tâche. Par exemple, supposez que vous voulez configurer votre serveur comme un Gateway de Web à e-mail (exemple Hot mail) qui prendrait d’un coté les donnes entrées par l’utilisateur via le browser et de l’autre coté l’envoyer par e-mail. Vous devriez insérer le code dans le serveur qui :

D'abord, une telle tâche exige avoir accès au code de serveur, quelque chose qui n'est pas toujours possible. En second lieu, il est difficile d’exigé des connaissances techniques étendues. Troisièmement, cela fonctionne seulement pour un serveur spécifique. Si vous voulez déplacer votre web serveur à une plate-forme différente, vous devriez recommencer où au moins dépenser beaucoup de temps pour porter le code pour la nouvelle plate-forme.


Pourquoi Cgi?


Le cgi fournit une solution portable et simple à ces problèmes. Le protocole de cgi définit une voie standard pour que les programmes communiquent avec le web serveur. Sans beaucoup de connaissance spéciale, vous pouvez écrire un programme en n'importe quel langage de programmation qui se connecte par cette interface. Ce programme fonctionnera avec tous les serveurs de Web qui comprennent le protocole cgi.


La transmission de cgi est manipulée avec l'entrée et la sortie standard, qui signifie que si vous savez écrire et lire des données avec votre langage de programmation préfère, vous pouvez écrire une application de web serveur. Autre qu'analyser (interpréter) l'entrée et sortie, programmer des applications cgi est presque équivalent à programmer n'importe quelle autre application. Par exemple, si vous voulez programmer votre programme de "Hello World! " , Vous devrez utiliser les fonctions et le format d’impression défini par votre langage pour que les programmes de cgi impriment le message approprié.



Choix De Langage :

Puisque le cgi est « une interface commune » vous n'êtes limités à aucun langage de programmation spécifique. On peut servir de n'importe quel langage qui peut faire cela :


Presque tous les langages de programmation et beaucoup de langages script possède ces trois activités, et vous pouvez utiliser n'importe lesquelles.


Les langages se divisent en deux classes : compilé ou interprété. Un langage compilé comme C ou C++ tend à être plus petit et plus rapide, tandis que langage interprété tel que Rexx ou VBA charger un interprète parfois plus grand que le programme même. En plus on peut distribuer des binaires (code compilé dans le langage machine) sans code source si votre langage est compilé. La distribution des séquences type interprétées signifie normalement distribuer le code source.


Les deux langages le plus utilisés pour la programmation de cgi sont C et Perl. Tous les deux ont leurs propres avantages et inconvénients. Le Perl est un langage de très haut niveau pourtant un puissant particulièrement utile pour analyser le texte. Bien que sa facilité d'utilisation, flexibilité, et puissance lui fassent un langage attrayant pour le cgi, sa taille relativement grande et l’exécution lente le rend parfois peu convenable pour certaines applications. Les programmes C sont plus petits, plus efficaces, et offrent un contrôle plus bas niveau du système, mais sont plus difficiles à programmer, et n'ont pas des fonctions faciles intégrées pour le traitement de textes, et sont aussi plus difficile a debouger.


Avertissements


Il y a quelques solutions alternatives aux applications de cgi. Beaucoup de serveurs incluent maintenant un API de programmation qui permet plus facilement de programmer des extensions directes au serveur, par opposition aux applications séparées de cgi. Le serveur APIs tendent à être plus efficace que des programmes de cgi. D'autres serveurs incluent la fonctionnalité intégrée qui peut manipuler d’événements spéciaux sans cgi, tel que l'interface de base de données. En plus quelques applications peuvent être manipulées par certaines nouvelles technologies de côté client (plutôt que côté serveur) comme Java notamment.


Avec un tel changement rapide de technologie, le cgi devient-il rapidement désuet ?


Probablement pas. Le cgi a plusieurs avantages par rapport aux technologies plus nouvelles.


Hello World


On peut ramener la programmation cgi à deux tâches : acquérant l'information du web browser et la renvoie de l'information au browser. C'est assez intuitif une fois qu’on se rend compte comment les applications cgi sont habituellement utilisées. Souvent, l'utilisateur est présenté avec une forme pour se terminer, comme celle sur le schéma 1.1. Une fois que l'utilisateur complète ce formulaire et le soumet, l'information est envoyée à un programme de cgi. Le programme de cgi doit alors convertir l'information au quelque chose qu'elle comprenne, le traiter convenablement, et renvoyer quelque chose de retour au browser, si c'est un formulaire de réception simple ou les résultats d'une enquête complexe sur une base de données.



Figure 1 – Un simple formulaire cgi.


En d'autres termes, la programmation cgi exige de comprendre comment obtenir l’information d'entrée du web browser et comment envoyer la sortie a lui. Ce qui se passe entre l'entrée et la sortie dépend de la volonté de programmer. On constate que la complexité principale de la programmation cgi résidu à cette étape intermédiaire ; après avoir compris la façon de traiter les entrée et les sorties, on a compris tous ce qu’il faut pour devenir un programmeur cgi.


Hello, world! En Perl.


#!/usr/local/bin/perl

# hello.cgi - My first CGI program


print "Content-Type: text/html\n\n";


print "<html> <head>\n";

print "<title>Hello, world!</title>";

print "</head>\n";

print "<body>\n";

print "<h1>Hello, world!</h1>\n";

print "</body> </html>\n";



Sauvez ce programme comme hello.cgi, et placer-le dans l'endroit approprié.

Dans la plupart des cas, le répertoire approprié est appelé cgi-bin.

Maintenant, il suffit d’appeler le programme a partir de votre web browser. Dans la plu part des cas, cela signifie ouvrir le URL suivant : http://hostname/directoryname/hello.cgi


Dissection de hello.cgi


D'abord, vous utilisez des commandes print simples. Les programmes de cgi n'exigent aucuns traitements ou « handle » spécial de fichier pour la sortie. Pour envoyer l’output au browser, il suffit d’imprimer simplement au stdout.


En second lieu, notez que le contenu du premier ligne d’impression (Content-Type : text/html) n'apparaît pas sur votre web browser. On peut envoyer n’importe quelle information qu’on veut au browser (un page HTML, des graphiques ou des sons), mais d'abord, il faut dire au browser quel type de données vous lui envoyez. Cette ligne indique au browser quel genre d'information il va interpréter dans ce cas, un page HTML.


Troisièmement, le programme s'appelle le hello.cgi. Il n'est pas toujours nécessaire d'utiliser l’extension cgi avec le nom de programme cgi. Bien que le code source pour beaucoup de langages utilisent également des extensions, l'extension de cgi n'est pas employée pour indiquer le type de langage, mais est une façon pour que le serveur identifie le fichier en tant qu'exécutable plutôt qu'un graphique ou un page HTML. Les serveurs sont souvent configurés pour essayer seulement d'exécuter ces fichiers qui ont cette extension, affichant les contenus de tous les autres. Bien qu'il ne puisse pas être nécessaire d'utiliser l'extension cgi, c'est toujours une bonne pratique.


En résumé, hello.cgi se compose de deux parts principales:


Hello World! En C


Pour démontrer l’indépendance de langage des programmes cgi, voici le programme équivalent à hello.cgi écrit en C.


/* hello.cgi.c - Hello, world CGI */


#include <stdio.h>


int main() {

printf("Content-Type: text/html\r\n\r\n");

printf("<html> <head>\n");

printf("<title>Hello, World!</title>\n");

printf("</head>\n");

printf("<body>\n");

printf("<h1>Hello, World!</h1>\n");

printf("</body> </html>\n");

}


Ni le serveur web ni le browser tien au langage que vous utilisez pour écrire votre programme. Bien que chaque langage ait des avantages et des inconvénients pour le cgi, le meilleur chose à faire est d’utiliser le langage avec lequel vous êtes le plus confortable.


Sortie Du Cgi


Le web browser, comme dans "Hello World!" , accepte deux types des données :


Ces deux blocs d'information sont séparés par un interligne.


Le header s'appelle un HTTP header. Il fournit des renseignements importants sur l'information que le browser va recevoir. Il y a plusieurs types différents d'en-têtes de HTTP. Le plus commun est celui qu’on vienne utiliser précédemment : Le header « Content-Type ».

On peut utiliser différentes combinaisons des en-têtes HTTP en les séparant avec un retour de chariot et une interligne ( \r\n ), la ligne blanche qui sépare l'en-tête des données se compose d'un retour chariot et d'une interligne.


Le header Content-type décrive le type de data que le cgi return. Le format général pour le header est :

Content-Type : subtype/type


Le subtype/type est un extension Internet universel valide du type (MIME). Le type de MIME le plus commun est le type de HTML : text/html.


Exemple de types MIME utiliser.



Type MIME

Description

text/html

HyperText Markup Language (HTML)


text/plain

Plain fichiers text


image/gif

GIF fichiers graphiques


image/jpeg

JPEG fichiers graphiques compressé


audio/basic

Sun *.au fichiers audio


audio/x-wav

Windows fichiers *.wav




Après l'en-tête et l'interligne, on imprime simplement les données comme on veut qu'il apparaisse. Si on envoie de l’HTML, alors il faut imprimer les tags et les données de HTML au stdout suivant le header. On peut également envoyer des graphiques, sons, et d'autres fichiers binaires aussi bien en imprimant le contenu du fichier au stdout.


Installation et Exécution de programmes CGI


Pour le cgi il faudra bien configurer le serveur web. Ainsi de suite quelques détails de différents serveurs pour différentes plates-formes de manière assez détaillée, mais il faudra consulter la documentation de serveur spécifique pour la meilleure configuration possible.

Tous les serveurs exigent de l'espace pour les fichiers de serveur et l'espace pour les documents de HTML, la zone de serveur s'appelle ServerRoot et la zone de document s'appelle DocumentRoot. Sur des machines de Unix, le ServerRoot est typiquement dans /usr/local/etc/httpd/ et le DocumentRoot est typiquement dans /usr/local/etc/httpd/htdocs /. Ceci n’est pas forcement vrai sur touts le système, cependant, on cas contraire il faut remplacer toutes les références à ServerRoot et à DocumentRoot pour le ServerRoot et DocumentRoot d’un différent type de serveur.

Quand on accède à des fichiers en utilisant le browser web, on indique le fichier dans le URL relativement au DocumentRoot. Par exemple, si on a le fichier /usr/local/etc/httpd/htdocs/index.html dans le machine mymachine.org, il faut accéder par le URL suivant :

http://mymachine.org/index.html


Configuration de serveur pour le cgi.


La plupart des serveurs de Web sont pré configurés pour utiliser des programmes de cgi. Il y a généralement deux choses qui indiquent au serveur, qu'un fichier soit une application de cgi ou pas :

L’indication des programmes cgi par leur extension de fichier peut être utile en raison de sa flexibilité. On n'est pas limité à un seul répertoire pour des programmes cgi. La plupart des serveurs peuvent être configurés pour identifier le cgi par l’extension de nom de fichier, bien que pas tous soient configurés de cette façon par défaut.


Installation CGI sur Serveurs UNIX


N'importe comment le serveur d'Unix est configuré, on doit prendre quelques mesures pour assurer que les applications cgi exécutées correctement. Le serveur web fonctionnera normalement en tant qu'utilisateur inexistant (c'est-à-dire, l'utilisateur d'Unix nobody, un compte qui n'a aucun droit d'accès au fichier, et ne peut faire un login ). En conséquence, les applications cgi compilées devraient être exécutables par tout le monde et les scripts cgi (écrites en Per, shell de Bourne, ou un langage script différent) devraient être exécutables lisibles par tout le monde.

Pour assurer ça, il faut que les fichiers cgi aient l’attribue 755, on faisant cela on assure que tout le monde pourra lire et exécuter le fichier. La commande Unix est chmod 755 filename.

Si on utilise un langage script tel perl, il ne faut pas oublier de spécifier le chemin complet pour l’interpréteur donc tout script doit commence par :


#!/usr/local/bin/perl

Il faut surtout pas mettre l’interpréteur dans le même répertoire (cgi-bin) que le script par raisons de sécurité.


Quelques serveurs communs d’Unix


Les serveurs de NCSA et d'Apache ont les fichiers de configuration semblables parce que le serveur d'Apache a été initialement basé sur le code de NCSA. Par défaut, ils sont configurés pour penser que n'importe quel fichier dans le répertoire de cgi-bin (situé par défaut dans ServerRoot) est un programme de cgi. Pour changer l'emplacement de répertoire de cgi-bin, on peut éditer le fichier de configuration en conf/srm.conf. La syntaxe pour configurer ce répertoire est :

ScriptAlias fakedirectoryname realdirectoryname

Où le fakedirectoryname est le nom de répertoire faux (/cgi-bin) et realdirectoryname est la voie d'accès complète où les programmes de cgi sont enregistrés réellement. Vous pouvez configurer plus d'un ScriptAlias en ajoutant plus de lignes de ScriptAlias.

La configuration de défaut est suffisante pour les besoins de la plupart des personnes. On doit éditer la ligne dans le fichier de srm.conf de toute façon pour indiquer le correct realdirectoryname. Si, par exemple, nos programmes cgi sont dans /usr/local/etc/httpd/cgi-bin, la ligne de ScriptAlias dans votre fichier de srm.conf devrait ressembler au suivant :

ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/

Pour accéder au référencer notre programme cgi dans ce répertoire, nous devront utiliser l’URL suivant :

http://hostname/cgi-bin/program-name

Le hostname est le nom d'hôte de serveur web et programname est le nom de programme cgi. Par exemple, supposez que il y a un copie de la programme hello.cgi dans le répertoire cgi-bin (par exemple, /usr/local/etc/httpd/cgi-bin) sur le serveur web appelé www.company.com. Pour accéder à cette cgi, on emploie le URL suivant:

http://www.company.com/cgi-bin/hello.cgi

Si on veut configurer le NCSA ou le serveur Apache pour identifier n'importe quel fichier avec l'extension .cgi comme programme cgi, On doit éditer deux fichiers de configuration. D'abord, dans le fichier de srm.conf, de commenter la ligne suivante:

AddType application/x-httpd-cgi .cgi

Ceci associera le type CGI de MIME avec l’extension .cgi . Ensuite, il faut modifier le fichier access.conf pour permettre à GCIs d'être exécutés dans n'importe quel répertoire. Pour faire ceci, ajoutez l'option ExecCGI à la ligne d'option. Elle semblera probablement quelque chose comme la ligne suivante:

Option Indexes FollowSymLinks ExecCGI

Maintenant, n'importe quel fichier avec l’extension cgi est considéré comme programme cgi; et on pourra l’accéder comme n’import quel autre fichier sur le serveur.

Le serveur CERN est configuré de la même façon que le NCSA et l’Apache. A la place de ScriptAlias il utilise le command Exec. Par exemple, dans le fichier httpd.conf , on verra le ligne :

Exec /cgi-bin/* /usr/local/etc/httpd/cgi-bin/*


Installation des cgi sur Windows


La plupart des serveurs disponibles pour les Windows 3,1, Windows 95, et Windows NT sont configurés en utilisant la méthode d'extension de fichier pour l'identification de cgi. D'une façon générale, la modification de serveur web windows exige simplement exécuter le programme de configuration du serveur et faire les changements appropriés.

La configuration de serveur pour exécuter correctement des scripts (telles que le Perl) est parfois difficile. Avec le DOS ou les Windows, on ne peut pas indiquer l'interprète sur la première ligne de script comme on peut avec UNIX. Quelques serveurs sont pré configurés pour associer certaines extensions de nom de fichier à un interprète. Par exemple, beaucoup de serveurs de Web de Windows supposeront que les fichiers terminant dans le pl sont des scripts Perl.

Si le serveur ne fait pas ce type d'association de fichier, on peut définir un fichier batch qui appelle l'interprète et la script au même temp. Comme avec le serveur d'Unix, il ne faut pas installer le répertoire d’interprète dans le cgi-bin ou dans aucun des répertoires accessibles du Web.

Installation de cgi sur le Macintosh


Les deux serveurs les plus connus pour Macintosh sont StarNine's WebStar et son prédécesseur de MacHTTP. Tous les deux identifient GCIs en regardant l'extension du nom de fichier.

MacHTTP comprend deux extensions différentes: le .cgi et le .acgi, qui représente les programmes CGI asynchrones. CGI normal installés sur le Macintosh (avec l'extension de cgi) maintiendront le serveur web occupé jusqu'à ce que l’exécution de cgi soit terminée, forçant le serveur de mettre toutes autres demandes en attentes. Le cgi asynchrone, permettra au serveur de recevoir des demandes même tout en exécutant.

Le developeur cgi Macintosh utilisant ces serveurs de Web devrait simplement utiliser autant que possible l'extension .acgi plutôt que l'extension de cgi. Ceci devrait fonctionner avec la plupart des programmes.




L'exécution de cgi


Après l’installation de cgi, il existe plusieurs voies de l'exécuter. Si le cgi est un programme de sortie-seulement, tel que le programme « Hello World ! » Alors on peut l'exécuter en accédant simplement à son URL.



HTML formes


Les deux tags (étiquettes) les plus importantes sous une forme de HTML sont le <form> et <input> étiquettes. On peut créer la plupart des formes de HTML en utilisant seulement ces deux étiquettes.


Le <form> Étiquette


L’étiquette <form> est employée pour définir quelle partie d'un fichier de HTML doit être utilisée pour l'input d'utilisateur. C’est avec cette méthode que la plupart des pages HTML appellent le programme de cgi. Les attributs de l'étiquette indiquent le nom et l'emplacement du programme, le type d’encodage utilisé, et quelle méthode est employée pour transférer les données à employer par le programme.

La ligne suivante montre les caractéristiques pour l’étiquette <form>:


<FORM ACTION= « url » METHODE=[POST|GET] ENCTYPE= »… »>


Après que l'utilisateur complète la forme et soumet l'information, toute l'information est encodée et passée vers le programme de cgi. Le programme cgi décode l'information et la traite.

Finalement, l'attribut de MÉTHODE décrit comment le programme de cgi devrait recevoir l'entrée. Les deux méthodes GET et POST diffère dans leur façon dont ils passent l'information vers le programme cgi.


Pour que le browser puisse permettre à l'utilisateur d'entrer de données, toutes les étiquettes et l’information de forme doivent être entourées par le <form> étiquette. Il ne faut pas oublier le </form> fermant, pour indiquer l'extrémité de la forme. On ne peut pas avoir une forme dans une forme, bien qu’on puisse installer une forme qui permet de soumettre des parties de l'information à différents endroits.


Le <input> Étiquette


On peut créer des barres de saisie des textes, des boutons radio, des checkboxes, et d'autres moyens de recevoir l'input en utilisant l’étiquette <input>.Pour mettre en application cette zone, on emploie l’étiquette <input> avec les attributs suivants:


<INPUT TYPE=text NAME=" . . . " VALUE=" . . . " SIZE= MAXLENGTH= >


Le NAME est le nom symbolique de la variable qui contient la valeur écrite par l'utilisateur. Si on ajoute l'attribut de VALEUR, ce texte sera placé comme texte par défaut dans la zone de saisie des textes. L'attribut de SIZE permet d'indiquer une longueur horizontale pour la zone d'entrée tel qu’il apparaîtra sur le browser. Le MAXLENGTH indique le nombre maximum des caractères que l'utilisateur peut entrer dans la zone. Les attributs VALUE, de SIZE, et MAXLENGTH sont facultatifs.


La soumission de forme :


S’il y a seulement une zone pour recevoir des textes dans La forme, l'utilisateur peut soumettre la forme en tapant simplement l'information et en appuyant entrez. Autrement, on doit avoir une certaine facilité pour l'utilisateur de soumettre l’information , et il le fait avec l’aide de boutonne « submit » :


<input type = submit>

Ce tag crée un boutonne nommé e »submit ». Quand l'utilisateur a terminé remplir la forme en cliquetant le bouton submit.



Recevant l'input du browser.


Dans des exemples précédents, vous avez vu comment écrire un programme de cgi qui envoie l'information du serveur au browser. En réalité, un programme de cgi qui sort seulement des données n'a pas beaucoup d'applications les plus importantes est la capacité du cgi pour recevoir l'information du browser, la méthode qui donne au Web sa nature interactive.


Un programme de cgi reçoit deux types d'information du browser.


variable d’environnement


La connaissance de variable d’environnement en cgi peut être très importante, en tant qu'outil d’étude et comme outil pour le debougage. Le tableau ici énumère certaines des variables d'environnement disponibles cgi. On peut aussi écrire un programme cgi qui imprimer tous les variables d’environnements et leur valeur de web browser.


Variable d’Environnement But

REMOTE_ADDR L’adresse IP de la machine client

REMOTE_HOST Le nome d’hôte de la machine client

HTTP_ACCEPT List le type de MIME que le browser sait lire

HTTP_USER_AGENT Info de browser (nom, version, OS, etc…)

REQUEST_METHOD GET or POST

CONTENT_LENGTH La taille d’input si c’est POST. Si pas de input or GET , ceci est indefini

QUERY_STRING Contient l’info d’input quand on utilise la methode GET

PATH_INFO Permet à l’ utilisateur de spécifier un chemin de la Ligne de command CGI exemple : http://hostname/cgibin/programname/path).

PATH_TRANSLATED Traduit le chemin relatif de PATH_INFO au chemin système


Pour d'écrire une application de cgi qui affiche les variables d'environnement, on doit savoir-faire deux choses:

- Déterminer toutes les variables d’environnement et leurs valeurs correspondantes.

- Imprimez les résultats au browser.


On sait déjà faire le dernier. En Perl, les variables d'environnement sont enregistrées dans la table associatif %ENV, qui est indexée par le nom de variable d'environnement.

Ici le listing perl pour accomplir cette tache :

#!/usr/local/bin/perl


print "Content-type: text/html\n\n";


print "<html> <head>\n";

print "<title>CGI Environment</title>\n";

print "</head>\n";

print "<body>\n";

print "<h1>CGI Environment</h1>\n";


foreach $env_var (keys %ENV) {

print "<B>$env_var</B> = $ENV{$env_var}<BR>\n";

}


print "</body> </html>\n";


En peut également faire la même chose en C++ :


#include <stdio.h>


extern char **environ;


int main()

{

char **p = environ;


printf("Content-Type: text/html\r\n\r\n");

printf("<html> <head>\n");

printf("<title>CGI Environment</title>\n");

printf("</head>\n");

printf("<body>\n");

printf("<h1>CGI Environment</h1>\n");


while(*p != NULL)

printf("%s<br>\n",*p++);


printf("</body> </html>\n");

}


GET Versus POST


Quelle est la différence entre les méthodes GET et POST ? GET fait passer la chaîne de caractères encodée par l'intermédiaire de la variable d'environnement QUERY_STRING, tandis que le POST la passe par le stdin. Le POST est la méthode préférable, particulièrement pour des formes avec beaucoup de données, parcequ'il n'y a aucune limite au nombres d'information que l’on peut envoyer. D’autre part, on est limité avec la méthode GET par la quantité de l'espace d'environnement qu’on a.

Pour déterminer quelle méthode est utilisée, le programme cgi contrôle la variable d'environnement REQUEST_METHOD, qui sera soit en GET soit en PUT. Si elle est placée au POST, la longueur d'information encodée est enregistrée dans la variable d'environnement CONTENT_LENGTH.




L'entrée (INPUT) encodée :



Quand l'utilisateur soumet une forme, le browser encode d'abord l'information avant de l'envoyer au serveur et ultérieurement à l'application de cgi. Quand vous utilisez l’étiquette <input>, chaque zone est nommée un nom symbolique, qui peut être considéré comme un variable. La valeur écrite par l'utilisateur peut être considérée comme la valeur de la variable.


Afin d'indiquer ceci, le browser utilise quelque chose appelé le spécification d’encodage de l’URL (URL encoding spécification), qui peut se résumer comme suit:


- Séparer les différentes zones avec l'esperluette (&).

- Séparer les noms et les valeurs avec les signes égaux (=), avec le nom à gauche et la valeur du côté droit.

- Remplacer les espaces par des plus (+).

- Remplacer tous les caractères " anormaux " par un signe de pour cent (%) suivi du code de caractère hexadécimal de deux-chiffre.

La chaîne de caractères encodée finale semblera à quelque chose comme ce qui suit :


name1=value1&name2=value2&name3=value3...


Par exemple le code HTML suivant :

<html> <head>

<title>Name and Age</title>

</head>

<body>

<form action="/cgi-bin/nameage.cgi" method=POST>

Enter your name : <input type=text name="name"><p>

Enter your age : <input type=text name="age"><p>

<input type=submit>

</form>

</body> </html>

Produira la page web suivante:



Si l’utilisateur entre Joe Zorglup dans le champ name et 20 dans l’age , l’input sera encodé comme ceci :

name=Joe+Schmoe&age=20


L'analyse de l'entrée


Pour que cette information soit utile, on doit pouvoir analyser l'information dans quelque chose que les programmes cgi puisse utiliser. Pour tous les buts pratiques, on ne doit jamais penser à la façon analyser l'entrée parce que plusieurs personnes ont déjà écrit librement les bibliothèques disponibles qui font l'analyse pour vous.


L'idée générale pour la plupart des bibliothèques écrites en différant langages est d’analyser la chaîne de caractères encodée et de placer les paires nom/valeur dans une structure de données. Il y a un avantage clair à utiliser un langage qui a les structures de données intégrées telles que le Perl; cependant, la plupart des bibliothèques pour les langages plus élémentaires tels que C et C++ incluent des implantations et sous-programmes pour de structure-data.

Il ne faut pas comprendre chaque détail des ces bibliothèques, ce qui est vraiment important est d’apprendre de l’utiliser pour faire le travaille de la programmation cgi plus facile.


Cgi-lib.pl


cgi-lib.pl tire profit des tables associatifs du Perl. La fonction &ReadParse analyse la chaîne de caractères d'entrée et introduit chaque paire de name/value par le nom. Par exemple, les lignes appropriées du Perl pour décoder la chaîne de caractères d'entrée de name/age seraient :


&ReadParse(*input);


Maintenant, si on veut voir la valeur écrite pour le "nom " on peut accéder à la variable associative $input{"name" }. De même, pour accéder à la valeur pour l'"age" On regarde la variable $input{"age" }.


cgihtml


C n'a aucune structure de données intégrée, ainsi cgihtml implémente sa propre liste enchaîner pour l'usage d'analyse de cgi. Il définit le structure de l'entrytype comme suit:

typedef struct {

char *name;

char *value;

} entrytype;


Afin d'analyser la chaîne de caractères d'entrée de name/âge en C en utilisant le cgihtml, on doit faire comme suite:


llist input ; / * déclarez la liste chaîné appelé input * /

read_cgi_input(&input); / * analysez l'entrée et l'endroit dans la liste chaîné */


Pour accéder à l'information pour l'âge, on peut soit l’analyser par la liste manuellement ou utiliser la fonction de cgi_val().


# include <stdlib.h>

# include <string.h>

char * âge = malloc(sizeof(char) * strlen(cgi_val(input, "age")) + 1);

strcpy(age,cgi_val(input, "age"));


La valeur pour l' âge est maintenant enregistrée dans le string age.



Un simple programme cgi



On va écrire un programme cgi appelé nameage.cgi qui traite la forme de name/age. L’analyse du data est minimale. nameage.cgi décode simplement l'entrée et affiche le nom et l'âge de l'utilisateur. Bien qu'il n'y ait pas beaucoup d'utilitaire dans un tel programme, ceci démontre l'aspect le plus crucial de la programmation de cgi: entrée et sortie.

On utilise la même forme comme décrit précédemment, appelant les zones nom et age.


Nameage.cgi en Perl


#!/usr/local/bin/perl

# nameage.cgi

require 'cgi-lib.pl'


&ReadParse(*input);

print "Content-Type: text/html\r\n\r\n";

print "<html> <head>\n";

print "<title>Name and Age</title>\n";

print "</head>\n";

print "<body>\n";

print "Hello, " . $input{'name'} . ". You are\n";

print $input{'age'} . " years old.<p>\n";

print "</body> </html>\n";


nameage.cgi En C.

/* nameage.cgi.c */


#include <stdio.h>

#include "cgi-lib.h"


int main()

{

llist input;


read_cgi_input(&input);

printf("Content-Type: text/html\r\n\r\n");

printf("<html> <head>\n");

printf("<title>Name and Age</title>\n");

printf("</head>\n");

printf("<body>\n");

printf("Hello, %s. You are\n",cgi_val(input,"name"));

printf("%s years old.<p>\n",cgi_val(input,"age"));

printf("</body> </html>\n");

}



Exemples de CGI :


Librairie Vidéo Online :


Une petite application cgi en perl utilisent une basse de donner, celui ci est une librairie vidéo on-line, tous les utilisateurs pourront consulter est ajouter leur commentaire, et l’administrateur pourra modifier le db


La Basse de donne


Chaque record va contenir l’information obligatoire suivant :


et optionnel :


Si on a plusieurs films, et la collection croît. Ajouter, effacer, et éditer des champs dans les enregistrements vont être des tâches communes. Puisque chaque enregistrement est quelque peu grand (certainement plus long qu'une ligne à 80 colonnes) et parce que nous devons modifier des enregistrements facilement, une base de données de fichier-système semble idéale. Chaque fichier contiendra les attributs avec un fichier par film. Ajouter un film signifie ajouter un nouveau fichier ; effacer un film signifie retirer un fichier. Nous pouvons facilement éditer deux enregistrements différents dans la base de données simultanément parce que nous n'aurons pas besoin de verrouiller (lock) la base de données entièrement pour éditer différents enregistrements.

Les gens questionneront la base de données seulement pour des titres de film, ainsi il semble approprié de faire au nom de fichier le titre de film. Cependant, la plupart des titres de film ont plusieurs mots et contiennent souvent les signes de ponctuation qui sont des caractères interdit dans les noms de fichier. Donc on utilisera un fichier d'index pour les titres et les noms de fichier. Quand nous créons de nouveaux enregistrements, le nom de fichier sera génère par une combinaison de l’heure et le ID de procès comme ceci :


$filename = time.".".$$;

while (-e $dbasedir.$filename) {

$filename = time.".".$$;

}


Bien qu'il soit peu probable que le nom de fichier existe déjà, on met la boucle pour le contrôle et pour voir si le nom de fichier existe déjà.

Le fichier d'index contient le nom de fichier et le titre du film séparé par deux caractères (||). (pipline), la probabilité d'un titre de film contenant deux pipes consécutives est mince, et la probabilité du nom de fichier contenant cette chaîne de caractères délimitante est zéro. Bien que cette prétention soit sûre pour cette application, nous filtrerions dehors ces caractères du titre juste au cas ou. Le fichier index ressemble ce qui suit :

12879523.1234||Star Wars

98543873.2565||Hellène va au Texas

Pour interpréter l’index on utilise le code suivant :


($filename,$title) = split(/\|\|/,$line);


Le fichier d'index et tous les enregistrements sont stocker dans le même répertoire, enregistré dans la variable $dbasedir. Le nom du fichier d'index est enregistré dans $$indexfile. Ces deux variables sont enregistrées dans un fichier d'en-tête global, video.ph.


Chaque enregistrement contient un identificateur de zone directement suivi d'un signe égal (=) et la valeur de la zone entourée par les croisillons ({}). De nouveau, bien qu'il soit peu probable que n'importe quel élément dans l'enregistrement contient des croisillons, les doubles check est nécessaire. Pour l’exercice, au lieu de filtrer hors des croisillons, on encodera le caractère de croisillons en utilisant le codage hexadécimal (les mêmes utilisations encodantes de codage de URL d'arrangement). Encoder des croisillons utilisant la notation hexadécimale signifie encoder le symbole de pour cent aussi bien. Voici le code correspondant :


sub encode {

local($data) = @_;


$data =~ s/([\%\{\}])/uc sprintf("%%%02x",ord($1))/eg;

return $data;

}


sub decode {

local($data) = @_;


$data =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;

return $data;

}




Notre ficher va être comme ceci :


TITLE={Rumble in the Bronx}

DIRECTORS={Stanley Tong}

ACTORS={Jackie Chan}

DESCRIPTION={A fast-paced action film, Jackie Chan displays his

incredible athleticism in this non-stop, beautifully choreographed

film. Fun to watch; we give it a two thumbs up!}

LINK={http://www.rumble.com/}

ANNOTATE={Jackie Chan is nothing compared to Arnold! Go Arnold!

Terminator forever!}




Le code pour analyser le fichier record :



# read fields of each record

open(RECORD,$dbasedir.$filename)

|| &CgiDie("Error","Couldn't Open Record");

$/ = '}';

while ($field = <RECORD>) {

$field =~ s/^[\r\n]//;

if ($field =~ /^TITLE=\{/) {

($TITLE = $field) =~ s/^TITLE=\{//;

$TITLE =~ s/\}//;

$TITLE = &decode($TITLE);

}

elsif ($field =~ /^DIRECTORS=\{/) {

($DIRECTORS = $field) =~ s/^DIRECTORS=\{//;

$DIRECTORS =~ s/\}//;

$DIRECTORS = &decode($DIRECTORS);

}

elsif ($field =~ /^ACTORS=\{/) {

($ACTORS = $field) =~ s/^ACTORS=\{//;

$ACTORS =~ s/\}//;

$ACTORS = &decode($ACTORS);

}

elsif ($field =~ /^DESCRIPTION=\{/) {

# doesn't handle multi paragraphs correctly

($DESCRIPTION = $field) =~ s/^DESCRIPTION=\{//;

$DESCRIPTION =~ s/\}//;

$DESCRIPTION =~ s/</&lt\;/g;

$DESCRIPTION =~ s/>/&gt\;/g;

$DESCRIPTION = &decode($DESCRIPTION);

}

elsif ($field =~ /^LINK=\{/) {

($LINK = $field) =~ s/^LINK=\{//;

$LINK =~ s/\}//;

push(@links,$LINK);

}

elsif ($field =~ /^ANNOTATE=\{/) {

($ANNOTATE = $field) =~ s/^ANNOTATE=\{//;

$ANNOTATE =~ s/\}//;

$ANNOTATE =~ s/</&lt\;/g;

$ANNOTATE =~ s/>/&gt\;/g;

push(@annotations,$ANNOTATE);

}

}

$/ = '\n';

close(RECORD);



Puisque les enregistrements et l'index sont constamment mis à jour, on doit s'assurer que tous les programmes peuvent lire et écrire aux enregistrements. Le serveur web en question s'exécute comme utilisateur nobody de groupe httpd. Donc il faut créer le répertoire de base de données, possédé par le groupe httpd, en lui faisant utilisateur et groupe-lisible, writeable, et exécutable. Pour s'assurer que les permissions sur n'importe quel fichier modifié ou créé sont correctes, on doit inclure la commande suivante dans le fichier d'en-tête video.ph pour placer les permissions :


umask(017);


Moteur et annotations de requête


Maintenant qu’on a créé une base de données, on est prêt à concevoir le moteur de requête. Le moteur de requête fera deux choses: Il affichera la liste de films disponibles, et il permettra à des utilisateurs de choisir des films pour voir l'information plus détaillée. L'énumération des films est une question d'analyser le fichier index et l'affichage des données en utilisant le <select> type de forme. L'utilisateur alors peut choisir les films au sujet dont lui ou elle veut plus de détails. Après que l'utilisateur cliquette le bouton de soumission, le programme lit et analyse les enregistrements choisis et les affiche dans le HTML.


On va separer les variables communes et les fonctions en le écrivent dans le fichier header video.ph. :


# header file for video, annotate


$dbasedir = '/casa/groups/pfoho/vdbase/';

$indexfile = 'index';

$passwdfile = 'passwd';

$cgibin = '/pfoho-cgi';


# set default umask (-rw-rw----)

umask(017);


sub wait_for_lock {

local($file) = @_;


while (-e "$dbasedir$file.LOCK") {

sleep 2;

}

}


sub lock_file {

local($file) = @_;


open(LOCK,">$dbasedir$file.LOCK");

print LOCK "$$\n";

close(LOCK);

}


sub unlock_file {

local($file) = @_;


unlink("$dbasedir$file.LOCK");

}


sub encode {

local($data) = @_;


$data =~ s/([\%\{\}])/uc sprintf("%%%02x",ord($1))/eg;

return $data;

}


sub decode {

local($data) = @_;


$data =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;

return $data;

}


Pour le moteur de recherche , si il reçoit pas de data ,il lis chaque record , et l’affichera :


Motorrech.pl


#!/usr/local/bin/perl


require 'cgi-lib.pl';

require 'video.ph';


# open index and map to associative array

open(INDEX,$dbasedir.$indexfile) || &CgiDie("Error","Couldn't Open Index");

while ($line = <INDEX>) {

$line =~ s/[\r\n]//g;

($filename,$title) = split(/\|\|/,$line);

$index{$title} = $filename;

}

close(INDEX);


if (&ReadParse(*input)) { # retrieve dbase items

print &PrintHeader,&HtmlTop("Video Information");

print "<hr>\n";

foreach $filename (split("\0",$input{'video'})) {

# clear @links and @annotations

@links = ();

@annotations = ();

# read fields of each record

open(RECORD,$dbasedir.$filename)

|| &CgiDie("Error","Couldn't Open Record");

$/ = '}';

while ($field = <RECORD>) {

$field =~ s/^[\r\n]//;

if ($field =~ /^TITLE=\{/) {

($TITLE = $field) =~ s/^TITLE=\{//;

$TITLE =~ s/\}//;

$TITLE = &decode($TITLE);

}

elsif ($field =~ /^DIRECTORS=\{/) {

($DIRECTORS = $field) =~ s/^DIRECTORS=\{//;

$DIRECTORS =~ s/\}//;

$DIRECTORS = &decode($DIRECTORS);

}

elsif ($field =~ /^ACTORS=\{/) {

($ACTORS = $field) =~ s/^ACTORS=\{//;

$ACTORS =~ s/\}//;

$ACTORS = &decode($ACTORS);

}

elsif ($field =~ /^DESCRIPTION=\{/) {

# doesn't handle multi paragraphs correctly

($DESCRIPTION = $field) =~ s/^DESCRIPTION=\{//;

$DESCRIPTION =~ s/\}//;

$DESCRIPTION =~ s/</&lt\;/g;

$DESCRIPTION =~ s/>/&gt\;/g;

$DESCRIPTION = &decode($DESCRIPTION);

}

elsif ($field =~ /^LINK=\{/) {

($LINK = $field) =~ s/^LINK=\{//;

$LINK =~ s/\}//;

push(@links,$LINK);

}

elsif ($field =~ /^ANNOTATE=\{/) {

($ANNOTATE = $field) =~ s/^ANNOTATE=\{//;

$ANNOTATE =~ s/\}//;

$ANNOTATE =~ s/</&lt\;/g;

$ANNOTATE =~ s/>/&gt\;/g;

push(@annotations,$ANNOTATE);

}

}

$/ = '\n';

close(RECORD);

# print fields

print "<h2>$TITLE</h2>\n";

print "<p><b>Director(s):</b> $DIRECTORS<br>\n";

print "<b>Actors:</b> $ACTORS</p>\n\n";

print "<p>$DESCRIPTION</p>\n\n";

if ($#links != -1) {

print "<h3>Links</h3>\n";

print "<ul>\n";

foreach $link (@links) {

print " <li><a href=\"$link\">$link</a>\n";

}

print "</ul>\n\n";

}

if ($#annotations != -1) {

print "<h3>Other Comments</h3>\n";

foreach $annotation (@annotations) {

print "<p>$annotation</p>\n\n";

}

}

print "<p><b><a href=\"$cgibin/annotate?$index{$TITLE}\">";

print "Add Your Own Comments/Links</a></b></p>\n\n";

print "<hr>\n\n";

}

print &HtmlBot;

}

else { # show list

# print list

print &PrintHeader,&HtmlTop("Videos");

print "<form method=POST>\n";

print "<select name=\"video\" size=20 MULTIPLE>\n";

foreach $key (sort(keys %index)) {

print "<option value=\"$index{$key}\">$key\n";

}

print "</select>\n";

print "<p><input type=submit value=\"Select Videos\"></p>\n";

print "</form>\n";

print &HtmlBot;

}




Quand on affiche l'information détaillée de chaque enregistrement, il donne également l'option d'ajouter une annotation ou un lien web. Pour faire ainsi, elle appelle le programme annotent.pl . Le programme annotent.pl utilise une stratégie a généralement utilisé en programmation cgi. La première forme qui annote les affichages obtient l'annotation et/ou les liens de l'utilisateur pour un film spécifique. Quand l'utilisateur cliquette le bouton de soumission, le même lien s'appelle. Cependant, parce que le Web est apatride, on doit passer de façon ou d'autre l'état approprié information dans ce cas, le nom de fichier du enregistrer- au programme de cgi. Cet état peut être passé de plusieurs façons.


Dans annotent.pl, on passe le nom de fichier dans le URL. Pour analyser l'information, les contrôles de programme cgi d'abord regarde si l'information existe dans la variable d'environnement QUERY_STRING. Si l'information d'état apparaît dans QUERY_STRING, annotent.pl détermine alors si l'information supplémentaire a été soumise par l'intermédiaire de la méthode POST. Si elle a, alors la variable d'environnement REQUEST_METHOD est placée au POST ; autrement, elle est égale a GET. La fonction &MethGet de cgi-lib.pl renvoie true si le cgi s'appelle en utilisant la méthode GET et faux si le cgi s'appelle en utilisant la méthode de POST. Le listing suivant contient le code squelette pour passer l'information d'état vers l'application cgi :



if ($ENV{'QUERY_STRING'}) { # can add some sort of state condition here as well

if (!&MethGet && &ReadParse(*input)) {

# state + additional input submitted

}

else {

# state and no additional input passed; probably just need

# to display form here

}

}


Puisque annote.pl modifie un enregistrement, il doit s'assurer que personne d'autre utilise l'enregistrement, créez une lock, exécutez l'action, et puis unlock le fichier.



Annonate.pl


#!/usr/local/bin/perl


require 'cgi-lib.pl';

require 'video.ph';


$recordname = $ENV{'QUERY_STRING'};


if ($recordname) {

if (!&MethGet && &ReadParse(*input)) { # add info to database

$comment = $input{'comments'};

$comment = &encode($comment);

@templinks = split(/\n/,$input{'links'});

@links = grep(!/^$/,@templinks);

&wait_for_lock($recordname);

&lock_file($recordname);

open(RECORD,">>$dbasedir$recordname") ||

&CgiDie("Error","Couldn't Open Record");

print RECORD "ANNOTATE={$comment}\n" unless (!$comment);

foreach $link (@links) {

print RECORD "LINK={$link}\n";

}

close(RECORD);

&unlock_file($recordname);

print &PrintHeader,&HtmlTop("Added!");


print &HtmlBot;

}

else { # show form

# check index; map filename to title

open(INDEX,$dbasedir.$indexfile)

|| &CgiDie("Error","Couldn't Open Index");

while ($line = <INDEX>) {

$line =~ s/[\r\n]//g;

($filename,$title,$sum,$num) = split(/\|\|/,$line);

$index{$filename} = $title;

}

close(INDEX);

# print form

print &PrintHeader,&HtmlTop("Add Comments");

print "<h2>$index{$recordname}</h2>\n";

print "<hr>\n";

print "<form action=\"$cgibin/annotate?$recordname\" ";

print "method=POST>\n";

print "<h3>Comments:</h3>\n";

print "<textarea name=\"comments\" rows=8 cols=70></textarea>\n";

print "<h3>Links (one per line)</h3>\n";

print "<textarea name=\"links\" rows=3 cols=70></textarea>\n";

print "<p><input type=submit value=\"Submit Comments/Links\">\n";

print "</form>\n";

print &HtmlBot;

}

}



Le Programme de Administrateur


Le programme questionne simplement les enregistrements et les affiches à partir de la base de données. Bien que annoate.pl soit légèrement plus complexe, il n'ait pas exigé beaucoup de codage complexe.

L’outil gestion appelée vadmin a plusieurs conditions :

Ce doit être protégé par un mot de passe de sorte que seulement certains utilisateurs puissent lui accéder. Les utilisateurs peuvent changer leurs mots de passe après qu'ils seront autorisés. Utilisant cet outil, les utilisateurs doivent pouvoir ajouter, effacer, et éditer des films.

Le mot de passe protégeant le programme de cgi signifie en utilisant le dispositif d'accès de fichier de serveur. Le programme fonctionne sur un serveur de Apache, ainsi il faut créer le répertoire d'un administrateur spécial dans le cgi-coffre et l'ai protégé utilisant les htaccess classe.


.htaccess file. :

AuthUserFile /casa/groups/pfoho/vdbase/passwd

AuthGroupFile /casa/groups/pfoho/vdbase/group

AuthName VideoAdministration

AuthType Basic


<Limit GET POST>

require group vadmin

</Limit>



ils nous restent seulement d’écrire le vadmin.pl :


#!/usr/local/bin/perl


require '../cgi-lib.pl';

require '../video.ph';


$command = $ENV{'QUERY_STRING'};


if ($command eq "add") {

if (!&MethGet && &ReadParse(*input)) {

# create new record

$filename = time.".".$$;

while (-e $dbasedir.$filename) {

$filename = time.".".$$;

}

&wait_for_lock($filename);

&lock_file($filename);

open(RECORD,">$dbasedir$filename")

|| &CgiDie("Error","Couldn't Write New Record");

$input{'title'} =~ s/\|\|//g; # remove double pipes just in case

print RECORD "TITLE=\{".&encode($input{'title'})."\}\n";

print RECORD "DIRECTORS=\{".&encode($input{'directors'})."\}\n";

print RECORD "ACTORS=\{".&encode($input{'actors'})."\}\n";

print RECORD "DESCRIPTION=\{".&encode($input{'description'})."\}\n";

if ($input{'links'}) {

@templinks = split(/\n/,$input{'links'});

@links = grep(!/^$/,@templinks);

foreach $link (@links) {

print RECORD "LINK={$link}\n";

}

}

close(RECORD);

&unlock_file($filename);

# update index

&wait_for_lock($indexfile);

&lock_file($indexfile);

open(INDEX,">>$dbasedir$indexfile")

|| &CgiDie("Error","Can't update index");

print INDEX "$filename||$input{'title'}||||\n";

close(INDEX);

&unlock_file($indexfile);

# send success message

print &PrintHeader,&HtmlTop("Record Added");


print &HtmlBot;

}

else {

&form_add;

}

}

elsif ($command eq "del") {

if (!&MethGet && &ReadParse(*input)) {

open(INDEX,$dbasedir.$indexfile)

|| &CgiDie("Error","Couldn't Open Index");

while ($line = <INDEX>) {

$filename = (split(/\|\|/,$line))[0];

$index{$filename} = $line;

}

close(INDEX);

# delete file and update array

foreach $filename (split("\0",$input{'video'})) {

&wait_for_lock($filename);

unlink($dbasedir.$filename)

|| &CgiDie("Error","Can't delete record");

delete $index{$filename};

}

# backup and update index file

&wait_for_lock($indexfile);

&lock_file($indexfile);

rename($dbasedir.$indexfile,"$dbasedir$indexfile.bak");

open(INDEX,">$dbasedir$indexfile")

|| &CgiDie("Error","Couldn't Open Index");

foreach $key (sort(keys(%index))) {

print INDEX $index{$key};

}

close(INDEX);

&unlock_file($indexfile);

# send success message

print &PrintHeader,&HtmlTop("Records Deleted");


print &HtmlBot;

}

else {

&form_del;

}

}

elsif ($command eq "editmenu") {

if (!&MethGet && &ReadParse(*input)) {

# open file

open(RECORD,$dbasedir.$input{'video'})

|| &CgiDie("Error","Can't Open Record");

$/ = '}';

while ($field = <RECORD>) {

$field =~ s/^[\r\n]//;

if ($field =~ /^TITLE=\{/) {

($TITLE = $field) =~ s/^TITLE=\{//;

$TITLE =~ s/\}//;

$TITLE = &decode($TITLE);

}

elsif ($field =~ /^DIRECTORS=\{/) {

($DIRECTORS = $field) =~ s/^DIRECTORS=\{//;

$DIRECTORS =~ s/\}//;

$DIRECTORS = &decode($DIRECTORS);

}

elsif ($field =~ /^ACTORS=\{/) {

($ACTORS = $field) =~ s/^ACTORS=\{//;

$ACTORS =~ s/\}//;

$ACTORS = &decode($ACTORS);

}

elsif ($field =~ /^DESCRIPTION=\{/) {

# doesn't handle multi paragraphs correctly

($DESCRIPTION = $field) =~ s/^DESCRIPTION=\{//;

$DESCRIPTION =~ s/\}//;

$DESCRIPTION =~ s/</&lt\;/g;

$DESCRIPTION =~ s/>/&gt\;/g;

$DESCRIPTION = &decode($DESCRIPTION);

}

elsif ($field =~ /^LINK=\{/) {

($LINK = $field) =~ s/^LINK=\{//;

$LINK =~ s/\}//;

push(@links,$LINK);

}

elsif ($field =~ /^ANNOTATE=\{/) {

($ANNOTATE = $field) =~ s/^ANNOTATE=\{//;

$ANNOTATE =~ s/\}//;

$ANNOTATE =~ s/</&lt\;/g;

$ANNOTATE =~ s/>/&gt\;/g;

push(@annotations,$ANNOTATE);

}

}

$/ = '\n';

close(RECORD);

# print edit form

print &PrintHeader,&HtmlTop("Edit Item");

print "<form action=\"$cgibin/admin/vadmin?edit\" method=POST>\n";

print "<input type=hidden name=\"record\" ";

print "value=\"$input{'video'}\">\n";

print "<p><b>Title:</b> ";

print "<input name=\"title\" value=\"$TITLE\"><br>\n";

print "<b>Director(s):</b> ";

print "<input name=\"directors\" value=\"$DIRECTORS\"><br>\n";

print "<b>Actors:</b> ";

print "<input name=\"actors\" value=\"$ACTORS\"></p>\n\n";

print "<p><textarea name=\"description\" rows=8 cols=70>\n";

print "$DESCRIPTION</textarea></p>\n\n";

if ($#links != -1) {

print "<h3>Edit Links</h3>\n";

print "<p>Check off items you want to delete.</p>\n";

print "<p>";

$i = 0;

foreach $link (@links) {

print "<input type=checkbox name=\"dl\" value=\"$i\">";

print "<input name=\"l$i\" value=\"$link\"><br>\n";

$i++;

}

print "</p>\n";

}

if ($#annotations != -1) {

print "<h3>Edit Annotations</h3>\n";

print "<p>Check off items you want to delete.</p>\n";

$i = 0;

foreach $annotation (@annotations) {

print "<p><input type=checkbox name=\"da\" value=\"$i\">";

print "<textarea name=\"a$i\" rows=8 cols=70>\n";

print "$annotation</textarea></p>\n";

$i++;

}

}

print "<p><input type=submit value=\"Submit Changes\"></p>\n";

print "</form>\n";

print &HtmlBot;

}

else {

&form_editmenu;

}

}

elsif ($command eq "edit") {

if (!&MethGet && &ReadParse(*input)) {

$filename = $input{'record'};

undef %dellinks;

undef %delnotes;

foreach $dlink (split("\0",$input{'dl'})) {

$dellinks{$dlink} = 1;

}

foreach $dnote (split("\0",$input{'da'})) {

$delnotes{$dnote} = 1;

}

$input{'title'} =~ s/\|\|//g; # remove double pipes just in case

# backup old record

rename($dbasedir.$filename,"$dbasedir$filename.bak")

|| &CgiDie("Error","Couldn't backup record");

# write new record

&wait_for_lock($filename);

&lock_file($filename);

open(RECORD,">$dbasedir$filename")

|| &CgiDie("Error","Couldn't Update Record");

print RECORD "TITLE=\{".&encode($input{'title'})."\}\n";

print RECORD "DIRECTORS=\{".&encode($input{'directors'})."\}\n";

print RECORD "ACTORS=\{".&encode($input{'actors'})."\}\n";

print RECORD "DESCRIPTION=\{".&encode($input{'description'})."\}\n";

$i = 0;

while ($input{"l$i"} && !$dellinks{$i}) {

print RECORD "LINK=\{".$input{"l$i"}."\}\n";

$i++;

}

$i = 0;

while ($input{"a$i"} && !$delnotes{$i}) {

print RECORD "ANNOTATE=\{".$input{"a$i"}."\}\n";

$i++;

}

close(RECORD);

&unlock_file($filename);

# update index with new title

# backup and update index file

&wait_for_lock($indexfile);

&lock_file($indexfile);

rename($dbasedir.$indexfile,"$dbasedir$indexfile.bak")

|| &CgiDie("Error","Can't backup index");

open(INDEX,"$dbasedir$indexfile.bak")

|| &CgiDie("Error","Can't Open Old Index");

open(NINDEX,">$dbasedir$indexfile")

|| &CgiDie("Error","Couldn't Open Index");

while ($line = <INDEX>) {

if ($line =~ /^$filename\|\|/) {

($fn,$ti) = split(/\|\|/,$line);

print NINDEX "$filename||$input{'title'}||$num||$sum";

}

else {

print NINDEX $line;

}

}

close(INDEX);

close(NINDEX);

&unlock_file($indexfile);

# send success message

print &PrintHeader,&HtmlTop("Record Updated");


print &HtmlBot;

}

else {

print "Location: $cgibin/admin/vadmin?editmenu\n\n";

}

}

elsif ($command eq "passwd") {

if (!&MethGet && &ReadParse(*input)) {

$uname = $input{'uname'};

$old = $input{'old'};

$new = $input{'new'};

$confirm = $input{'confirm'};

# open password file

$FOUND = 0;

open(PASSWD,$dbasedir.$passwdfile)

|| &CgiDie("Error","Can't open password file");

# check username

while (!$FOUND && ($line = <PASSWD>)) {

$line =~ s/[\r\n]//g;

($username,$password) = split(/:/,$line);

if ($username eq $uname) {

$FOUND = 1;

}

}

&CgiDie("Error","Invalid Username") unless ($FOUND);

# check old password

$salt = substr($password,0,2);

if (crypt($old,$salt) ne $password) {

&CgiDie("Error","Invalid Password");

}

# new=confirm?

&CgiDie("Error","New passwords don't match") unless ($new eq $confirm);

# change that badboy!

@saltchars = ('a'..'z','A' 'Z','0' '9',' ','/');

srand(time|$$);

$salt = splice(@saltchars,rand @saltchars,1);

$salt .= splice(@saltchars,rand @saltchars,1);

$npasswd = crypt($new,$salt);

# backup passwd file

&wait_for_lock($passwdfile);

&lock_file($passwdfile);

rename($dbasedir.$passwdfile,"$dbasedir$passwdfile.bak")

|| &CgiDie("Error","Can't backup password file");

open(PASSWD,"$dbasedir$passwdfile.bak")

|| &CgiDie("Error","Can't open password file");

open(NPASSWD,">$dbasedir$passwdfile")

|| &CgiDie("Error","Can't change password file");

while ($line = <PASSWD>) {

if ($line =~ /^$uname:/) {

print NPASSWD "$uname:$npasswd\n";

}

else {

print NPASSWD $line;

}

}

close(PASSWD);

close(NPASSWD);

&unlock_file($passwdfile);

# print success message

print &PrintHeader,&HtmlTop("Password changed!");


print &HtmlBot;

}

else {

&form_passwd;

}

}

else {

&form_menu;

}


sub form_menu {

print &PrintHeader,&HtmlTop("Welcome Admin!");

print <<EOM;

<ul>

<li><a href="$cgibin/admin/vadmin?add">Add New Item</a>

<li><a href="$cgibin/admin/vadmin?del">Delete Item</a>

<li><a href="$cgibin/admin/vadmin?editmenu">Edit Item</a>

<li><a href="$cgibin/admin/vadmin?passwd">Change password</a>

</ul>

EOM

print &HtmlBot;

}


sub form_add {

print &PrintHeader,&HtmlTop("Add New Item");

print <<EOM;

<form action="$cgibin/admin/vadmin?add" method=POST>


<p>Title: <input name="title"><br>

Director(s): <input name="directors"><br>

Actors: <input name="actors"></p>


<p>Description:<br>

<textarea name="description" rows=8 cols=70>

</textarea></p>


<p>Links (one on each line):<br>

<textarea name="links" rows=3 cols=70>

</textarea></p>


<p><input type=submit value="Add Item"></p>


</form>

EOM

print &HtmlBot;

}


sub form_del {

open(INDEX,$dbasedir.$indexfile)

|| &CgiDie("Error","Couldn't Open Index");

while ($line = <INDEX>) {

$line =~ s/[\r\n]//g;

($filename,$title) = split(/\|\|/,$line);

$index{$title} = $filename;

}

close(INDEX);

# print list

print &PrintHeader,&HtmlTop("Delete Item");

print "<form action=\"$cgibin/admin/vadmin?del\" method=POST>\n";

print "<select name=\"video\" size=20 MULTIPLE>\n";

foreach $key (sort(keys %index)) {

print "<option value=\"$index{$key}\">$key\n";

}

print "</select>\n";

print "<p><input type=submit value=\"Delete Videos\"></p>\n";

print "</form>\n";

print &HtmlBot;

}


sub form_editmenu {

open(INDEX,$dbasedir.$indexfile)

|| &CgiDie("Error","Couldn't Open Index");

while ($line = <INDEX>) {

$line =~ s/[\r\n]//g;

($filename,$title) = split(/\|\|/,$line);

$index{$title} = $filename;

}

close(INDEX);

print &PrintHeader,&HtmlTop("Edit Which Item?");

print "<form action=\"$cgibin/admin/vadmin?editmenu\" method=POST>\n";

print "<select name=\"video\" size=20>\n";

foreach $key (sort(keys %index)) {

print "<option value=\"$index{$key}\">$key\n";

}

print "</select>\n";

print "<p><input type=submit value=\"Edit Video\"></p>\n";

print "</form>\n";

print &HtmlBot;

}


sub form_passwd {

print &PrintHeader,&HtmlTop("Change Password");

print <<EOM;

<form action="$cgibin/admin/vadmin?passwd" method=POST>


<p><b>Username:</b> <input name="uname" value="$ENV{'REMOTE_USER'}"></p>


<p><b>Old Password:</b> <input type=password name="old"></p>


<p><b>New Password:</b> <input type=password name="new"><br>

<b>New Password (again):</b> <input type=password name="confirm"></p>


<p><input type=submit value=\"Change password\"></p>


</form>

EOM

print &HtmlBot;

}


Maintenant nous avons tous les CGI nécessaire à la gestion et à l'utilisation de notre site "Vidéo".


Ecrire à l'auteur