Qu'est-ce que CGI
CGI est actuellement géré par NCSA, qui définit CGI comme suit :
CGI (Common Gateway Interface), Common Gateway Interface, est un programme qui s'exécute sur un serveur tel qu'un serveur HTTP et fournit une interface avec la page HTML du client.
navigation sur le Web
Pour mieux comprendre le fonctionnement de CGI, nous pouvons commencer par cliquer sur un lien ou une URL sur une page Web :
1. Utilisez votre navigateur pour accéder à l'URL et vous connecter au serveur Web HTTP.
2. Après avoir reçu les informations de la demande, le serveur Web analysera l'URL et vérifiera si le fichier consulté existe sur le serveur. Si le fichier existe, il renverra le contenu du fichier, sinon il renverra un message d'erreur.
3. Le navigateur reçoit des informations du serveur et affiche le fichier ou le message d'erreur reçu.
Les programmes CGI peuvent être des scripts Python, des scripts PERL, des scripts SHELL, des programmes C ou C++, etc.
Schéma d'architecture CGI
Prise en charge et configuration du serveur Web
Avant d'effectuer une programmation CGI, assurez-vous que votre serveur Web prend en charge CGI et a configuré un gestionnaire CGI.
Apache prend en charge la configuration CGI :
Configurez le répertoire CGI :
ScriptAlias /cgi-bin/ /var/www/cgi-bin/
Tous les programmes CGI d'exécution du serveur HTTP sont enregistrés dans un répertoire préconfiguré. Ce répertoire est appelé répertoire CGI, et par convention, il est nommé /var/www/cgi-bin.
Les fichiers CGI ont une extension .cgi et Perl peut également utiliser une extension .pl.
Par défaut, la configuration du serveur Linux s'exécute dans le répertoire cgi-bin dans /var/www.
Si vous souhaitez spécifier un autre répertoire pour exécuter les scripts CGI, vous pouvez modifier le fichier de configuration httpd.conf comme suit :
<Répertoire "/var/www/cgi-bin"> AllowOverride None Options +ExecCGI Order autoriser, refuser Autoriser de tous</Directory>
Ajoutez le suffixe .pl à AddHandler afin que nous puissions accéder aux fichiers de script Perl se terminant par .pl :
AddHandler cgi-script .cgi .pl .py
Le premier programme CGI
Ci-dessous nous créons un fichier test.cgi, le code est le suivant :
code test.cgi
#!/usr/bin/perl imprimer " Type de contenu :text/html r n r n " ; ' <html> ' ; imprimer ' <tête> ' ; imprimer ' <
meta charset="utf-8"> ' ; ' <title>Tutoriel Codeur (codercto.com) </title> ' ; ' </head> ' ; imprimer ' <corps> ' ; imprimer ' <h2>Bonjour
Word </h2> ' ; ' <p>Le premier programme CGI du didacticiel du programmeur. </p> ' ; imprimer ' </corps> ' ; imprimer ' </html> ' ; Ensuite, ouvrez http://localhost/cgi-bin/test.cgi via le navigateur, les résultats de sortie sont les suivants :
Le contenu de sortie de la première ligne du script « Content-type : text/htmlrnrn » est envoyé au navigateur et indique au navigateur que le type de contenu affiché est « text/html ».
en-tête HTTP
Le "Content-type:text/html" dans le contenu du fichier test.cgi fait partie de l'en-tête HTTP, qui est envoyé au navigateur pour indiquer au navigateur le type de contenu du fichier.
Le format de l'en-tête HTTP est le suivant :
Nom du champ HTTP : contenu du champ
Par exemple:
Type de contenu :text/htmlrnrn
Le tableau suivant présente les informations couramment utilisées dans les en-têtes HTTP des programmes CGI :
tête | décrire |
---|
Type de contenu : | Les informations MIME demandées correspondant à l’entité. Par exemple : Type de contenu :texte/html |
Expire : Date | Date et heure d’expiration de la réponse |
Emplacement : URL | Utilisé pour rediriger le destinataire vers l'emplacement d'une URL non demandée pour compléter la demande ou identifier une nouvelle ressource. |
Dernière modification : Date | L'heure de la dernière modification de la ressource demandée |
Longueur du contenu : N | Longueur du contenu demandé |
Set-Cookie : chaîne | Définir un cookie HTTP |
Variables d'environnement CGI
Tous les programmes CGI reçoivent les variables d'environnement suivantes, qui jouent un rôle important dans les programmes CGI :
nom de la variable | décrire |
---|
CONTENT_TYPE | La valeur de cette variable d'environnement indique le type MIME des informations transmises. Actuellement, la variable d'environnement CONTENT_TYPE est généralement : application/x-www-form-urlencoded, ce qui indique que les données proviennent de formulaires HTML. |
CONTENT_LENGTH | Si la méthode de transfert d'informations entre le serveur et le programme CGI est POST, cette variable d'environnement est le nombre d'octets de données valides pouvant être lus à partir de l'entrée standard STDIN. Cette variable d'environnement doit être utilisée lors de la lecture des données saisies. |
HTTP_COOKIE | Contenu du COOKIE dans le client. |
HTTP_USER_AGENT | Fournissez des informations sur le navigateur du client, y compris les numéros de version ou d'autres données exclusives. |
PATH_INFO | La valeur de cette variable d'environnement représente d'autres informations de chemin qui suivent immédiatement le nom du programme CGI. Il apparaît souvent comme paramètre dans les programmes CGI. |
QUERY_STRING | Si la méthode de transfert d'informations entre le serveur et le programme CGI est GET, la valeur de cette variable d'environnement correspond à l'information transférée. Ces informations suivent le nom du programme CGI, séparé par un point d'interrogation « ? ». |
REMOTE_ADDR | La valeur de cette variable d'environnement est l'adresse IP du client qui envoie la demande, comme 192.168.1.67 ci-dessus. Cette valeur est toujours présente. Et c'est l'identifiant unique que le client Web doit fournir au serveur Web, qui peut être utilisé dans les programmes CGI pour distinguer les différents clients Web. |
REMOTE_HOST | La valeur de cette variable d'environnement contient le nom d'hôte du client qui a envoyé la requête CGI. Si la requête que vous souhaitez interroger n'est pas prise en charge, il n'est pas nécessaire de définir cette variable d'environnement. |
REQUEST_METHOD | Fournit la méthode par laquelle le script est appelé. Pour les scripts utilisant le protocole HTTP/1.0, seuls GET et POST sont significatifs. |
SCRIPT_FILENAME | Chemin complet vers le script CGI |
SCRIPT_NAME | Le nom du script CGI |
SERVER_NAME | Il s'agit du nom d'hôte, de l'alias ou de l'adresse IP de votre serveur WEB. |
SERVEUR_LOGICIEL | La valeur de cette variable d'environnement contient le nom et le numéro de version du serveur HTTP qui appelle le programme CGI. Par exemple, la valeur ci-dessus est Apache/2.2.14(Unix) |
Ce qui suit est un simple script CGI qui génère des variables d'environnement CGI :
Exemple
#!/usr/bin/perl imprimer " Type de contenu : texte/html n n " ; ' <
meta charset="utf-8"> ' ; " <font size=+1>Variable d'environnement :</font> n " ; ( trier clés %ENV ) { imprimer " <b> $_ </b> : $ENV { $_ } <br> n " ; 1 ; Téléchargement de fichier
Si nous voulons télécharger des fichiers via Perl CGI, nous devons définir différentes informations d'en-tête, comme indiqué ci-dessous :
Exemple
#!/usr/bin/perl # En-tête HTTP imprimer " Content-Type:application/octet-stream; name= " FileName " r n " ; " Content-Disposition: attachment; filename= " FileName " r n n " # Le contenu réel du fichier sera entendu. ouvrir ( FICHIER , " <NomFichier " ) ; while ( lire ( FILE , $buffer , 100 ) ) { print ( " $ tampon " ) ; Transférer des données à l'aide de la méthode GET
La méthode GET envoie les informations utilisateur codées au serveur. Les informations sur les données sont incluses dans l'URL de la page demandée, séparées par "?", comme indiqué ci-dessous :
http://www.test.com/cgi-bin/test.cgi?key1=value1&key2=value2
Quelques notes supplémentaires sur les requêtes GET :
Les requêtes GET peuvent être mises en cache
Les requêtes GET restent dans l'historique du navigateur
Les requêtes GET peuvent être mises en signet
Les requêtes GET ne doivent pas être utilisées lors du traitement de données sensibles
Les requêtes GET ont des limites de longueur
Les requêtes GET ne doivent être utilisées que pour récupérer des données
Exemple d'URL simple : méthode GET
Ce qui suit est une URL simple qui utilise la méthode GET pour envoyer deux paramètres au programme test.cgi :
/cgi-bin/test.cgi?name=Tutoriel Codeur&url=http://www.codercto.com
Voici le code du fichier test.cgi :
Exemple
#!/usr/bin/perl locale ( $buffer , @pairs , $pair , $name , $value , %FORM ) # Lire les informations textuelles ; $ENV { ' REQUEST_METHOD ' } =~ tr / a - z / A - Z / si ( $ENV { ' REQUEST_METHOD ' } équip " OBTENIR " ) { $ buffer = $ENV { ' QUERY_STRING ' } ; # Lire les informations sur la paire nom/valeur @pairs = split ( //&/, $ buffer ) ; $paire ( @paires ) { ( $name , $value ) = split ( /=/, $pair ) ; $value =~ tr /+/ / ; $value =~ s / % ( .. ) / pack ( " C " , hex ( $1 ) ) / par exemple ; $FORM { $ nom } = $valeur } $nom = $ FORM { nom } ; $url = $FORM { url } ; " Type de contenu :text/html r n r n " ; " <html> " ; imprimer " <tête> " ; imprimer ' <
meta charset="utf-8"> ' ; ' <title>Tutoriel Codeur (codercto.com) </title> ' ; " </head> " ; imprimer " <corps> " ; imprimer " <h2> $nom URL : $ url </h2> " ; " </body> " ; imprimer " </html> " ; Vérifiez le navigateur et le résultat est le suivant :
Exemple de formulaire simple : méthode GET
Ce qui suit est un formulaire HTML qui utilise la méthode GET pour envoyer deux données au serveur. Le script du serveur soumis est également le fichier test.cgi. Le code test.html est le suivant :
code du fichier test.html
< ! HTML > <html> <tête> < méta jeu de caractères = " utf-8 " > <title> Tutoriel Codeur ( codercto.com ) </title> </ tête > <corps> < formulaire action = " /cgi-bin/test.cgi " method = " get " > nom du site : < entrée tapez = " texte " nom = " nom " > < br /> URL du site : < entrée tapez = " texte " nom = " url " /> < entrée tapez = " soumettre " valeur = " soumettre " /> </form> </corps> </html> Dans le navigateur, l'effet d'exécution est le suivant :
Transmettre les données en utilisant la méthode POST
Il est plus sûr et fiable d'utiliser la méthode POST pour transmettre des données au serveur. Certaines informations sensibles telles que les mots de passe des utilisateurs doivent utiliser POST pour transmettre des données.
Ce qui suit est également test.cgi, qui peut également gérer les données du formulaire POST soumises par le navigateur :
code test.cgi
#!/usr/bin/perl locale ( $buffer , @pairs , $pair , $name , $value , %FORM ) # Lire les informations textuelles ; $ENV { ' REQUEST_METHOD ' } =~ tr / a - z / A - Z / si ( $ENV { ' REQUEST_METHOD ' } équip " POSTE " ) { lire ( STDIN , $buffer , $ ENV { ' CONTENT_LENGTH ' } ) else ; { $ buffer = $ENV { ' QUERY_STRING ' } ; # Lire les informations sur la paire nom/valeur @pairs = split ( //&/, $ buffer ) ; $paire ( @paires ) { ( $name , $value ) = split ( /=/, $pair ) ; $value =~ tr /+/ / ; $value =~ s / % ( .. ) / pack ( " C " , hex ( $1 ) ) / par exemple ; $FORM { $ nom } = $valeur } $nom = $ FORM { nom } ; $url = $FORM { url } ; " Type de contenu :text/html r n r n " ; " <html> " ; imprimer " <tête> " ; imprimer ' <
meta charset="utf-8"> ' ; ' <title>Tutoriel Codeur (codercto.com) </title> ' ; " </head> " ; imprimer " <corps> " ; imprimer " <h2> $nom URL : $ url </h2> " ; " </body> " ; imprimer " </html> " ; Ce qui suit est un formulaire HTML qui utilise la méthode GET pour envoyer deux données au serveur. Le script du serveur soumis est également le fichier test.cgi. Le code test.html est le suivant :
code test.html
< ! HTML > <html> <tête> < méta jeu de caractères = " utf-8 " > <title> Tutoriel Codeur ( codercto.com ) </title> </ tête > <corps> < formulaire action = " /cgi-bin/test.cgi " method = " post " > Nom du site : < entrée tapez = " texte " nom = " nom " > < br /> URL du site : < entrée tapez = " texte " nom = " url " /> < entrée tapez = " soumettre " valeur = " soumettre " /> </form> </corps> </html> Dans le navigateur, l'effet d'exécution est le suivant :
Transmettre les données des cases à cocher via le programme CGI
La case à cocher est utilisée pour soumettre une ou plusieurs données d'option. Le code test.html est le suivant :
code test.html
< ! HTML > <html> <tête> < méta jeu de caractères = " utf-8 " > <title> Tutoriel Codeur ( codercto.com ) </title> </ tête > <corps> < formulaire action = " /cgi-bin/test.cgi " méthode = " POST " cible = " _blank " > < entrée tapez = " case à cocher " nom = " codercto " valeur = " sur " /> Tutoriel du codeur < entrée tapez = " case à cocher " nom = " google " valeur = " sur " /> Google < entrée tapez = " soumettre " valeur = " Sélectionnez le site " /> </form> </corps> </html> Voici le code du fichier test.cgi :
code test.cgi
#!/usr/bin/perl locale ( $buffer , @pairs , $pair , $name , $value , %FORM ) # Lire les informations ; $ENV { ' REQUEST_METHOD ' } =~ tr / a - z / A - Z / si ( $ENV { ' REQUEST_METHOD ' } équip " POSTE " ) { lire ( STDIN , $buffer , $ ENV { ' CONTENT_LENGTH ' } ) else ; { $ buffer = $ENV { ' QUERY_STRING ' } ; # Lire les informations sur la paire nom/valeur @pairs = split ( //&/, $ buffer ) ; $paire ( @paires ) { ( $name , $value ) = split ( /=/, $pair ) ; $value =~ tr /+/ / ; $value =~ s / % ( .. ) / pack ( " C " , hex ( $1 ) ) / par exemple ; $FORM { $ nom } = $valeur } si ( $FORM { code de code } ) { $codercto_flag = " ON " ; } autre { $ codercto_flag = " OFF » ; si ( $FORM { google } ) { $google_flag = " ON " ; } autre { $ google_flag = " OFF » ; imprimer " Type de contenu :text/html r n r n " ; " <html> " ; imprimer " <tête> " ; imprimer ' <
meta charset="utf-8"> ' ; ' <title>Tutoriel Codeur (codercto.com) </title> ' ; " </head> " ; imprimer " <corps> " ; imprimer " <h2> Statut sélectionné du didacticiel Coder : $ codercto_flag </h2> " ; " <h2> État de
la sélection Google : $google_flag </h2> " ; " </body> " ; imprimer " </html> " ; Dans le navigateur, l'effet d'exécution est le suivant :
Transmettre les données radio via le programme CGI
Radio ne transmet qu'une seule donnée au serveur. Le code test.html est le suivant :
code test.html
< ! HTML > <html> <tête> < méta jeu de caractères = " utf-8 " > <title> Tutoriel Codeur ( codercto.com ) </title> </ tête > <corps> < formulaire action = " /cgi-bin/test.cgi " méthode = " poster " cible = " _blank " > < entrée tapez = " radio " nom = " site " valeur = " codercto " /> Tutoriel du codeur < entrée tapez = " radio " nom = " site " valeur = " google " /> Google < entrée tapez = " soumettre " valeur = " soumettre " /> </form> </corps> </html> Le code du script test.cgi est le suivant :
code test.cgi
#!/usr/bin/perl locale ( $buffer , @pairs , $pair , $name , $value , %FORM ) # Lire les informations ; $ENV { ' REQUEST_METHOD ' } =~ tr / a - z / A - Z / si ( $ENV { ' REQUEST_METHOD ' } équip " POSTE " ) { lire ( STDIN , $buffer , $ ENV { ' CONTENT_LENGTH ' } ) else ; { $ buffer = $ENV { ' QUERY_STRING ' } ; # Lire les informations sur la paire nom/valeur @pairs = split ( //&/, $ buffer ) ; $paire ( @paires ) { ( $name , $value ) = split ( /=/, $pair ) ; $value =~ tr /+/ / ; $value =~ s / % ( .. ) / pack ( " C " , hex ( $1 ) ) / par exemple ; $FORM { $ nom } = $valeur } $site = $ FORM { site } ; " Type de contenu :text/html r n r n " ; " <html> " ; imprimer " <tête> " ; imprimer ' <
meta charset="utf-8"> ' ; ' <title>Tutoriel Codeur (codercto.com) </title> ' ; " </head> " ; imprimer " <corps> " ; imprimer " <h2> Site Web sélectionné $ site </h2> " ; " </body> " ; imprimer " </html> " ; Dans le navigateur, l'effet d'exécution est le suivant :
Transmettre les données Textarea via le programme CGI
Textarea transmet plusieurs lignes de données au serveur. Le code test.html est le suivant :
code test.html
< ! HTML > <html> <tête> < méta jeu de caractères = " utf-8 " > <title> Tutoriel Codeur ( codercto.com ) </title> </ tête > <corps> < formulaire action = " /cgi-bin/test.cgi " méthode = " poster " cible = " _blank " > < zone de texte nom = " contenu du texte " col = " 40 " rows = " 4 " > Entrez le contenu ici... </ textarea > < entrée tapez = " soumettre " valeur = " soumettre " /> </form> </corps> </html> Le code du script test.cgi est le suivant :
code test.cgi
#!/usr/bin/perl locale ( $buffer , @pairs , $pair , $name , $value , %FORM ) # Lire les informations ; $ENV { ' REQUEST_METHOD ' } =~ tr / a - z / A - Z / si ( $ENV { ' REQUEST_METHOD ' } équip " POSTE " ) { lire ( STDIN , $buffer , $ ENV { ' CONTENT_LENGTH ' } ) else ; { $ buffer = $ENV { ' QUERY_STRING ' } ; # Lire les informations sur la paire nom/valeur @pairs = split ( //&/, $ buffer ) ; $paire ( @paires ) { ( $name , $value ) = split ( /=/, $pair ) ; $value =~ tr /+/ / ; $value =~ s / % ( .. ) / pack ( " C " , hex ( $1 ) ) / par exemple ; $FORM { $ nom } = $valeur } $text_content = $ FORM { textcontent } ; " Type de contenu :text/html r n r n " ; " <html> " ; imprimer " <tête> " ; imprimer ' <
meta charset="utf-8"> ' ; ' <title>Tutoriel Codeur (codercto.com) </title> ' ; " </head> " ; imprimer " <corps> " ; imprimer " <h2>
Le contenu du texte saisi est : $text_content </h2> " ; " </body> " ; imprimer " </html> " ; Dans le navigateur, l'effet d'exécution est le suivant :
Transmettre les données déroulantes via le programme CGI
Le code de la liste déroulante HTML est le suivant :
code test.html
< ! HTML > <html> <tête> < méta jeu de caractères = " utf-8 " > <title> Tutoriel Codeur ( codercto.com ) </title> </ tête > <corps> < formulaire action = " /cgi-bin/test.cgi " méthode = " poster " cible = " _blank " > < sélectionner nom = " liste déroulante " > < option valeur = " codercto " sélectionné > Tutoriel Codeur </ option > < option valeur = " google " > Google </ option > </sélectionner> < entrée tapez = " soumettre " valeur = " soumettre " /> </form> </corps> </html> Le code du script test.cgi est le suivant :
code test.cgi
#!/usr/bin/perl locale ( $buffer , @pairs , $pair , $name , $value , %FORM ) # Lire les informations ; $ENV { ' REQUEST_METHOD ' } =~ tr / a - z / A - Z / si ( $ENV { ' REQUEST_METHOD ' } équip " POSTE " ) { lire ( STDIN , $buffer , $ ENV { ' CONTENT_LENGTH ' } ) else ; { $ buffer = $ENV { ' QUERY_STRING ' } ; # Lire les informations sur la paire nom/valeur @pairs = split ( //&/, $ buffer ) ; $paire ( @paires ) { ( $name , $value ) = split ( /=/, $pair ) ; $value =~ tr /+/ / ; $value =~ s / % ( .. ) / pack ( " C " , hex ( $1 ) ) / par exemple ; $FORM { $ nom } = $valeur } $site = $FORM { liste déroulante } ; " Type de contenu :text/html r n r n " ; " <html> " ; imprimer " <tête> " ; imprimer ' <
meta charset="utf-8"> ' ; ' <title>Tutoriel Codeur (codercto.com) </title> ' ; " </head> " ; imprimer " <corps> " ; imprimer " <h2>Le site
sélectionné est : $site </h2> " ; " </body> " ; imprimer " </html> " ; Dans le navigateur, l'effet d'exécution est le suivant :
Utilisation de cookies dans CGI
Un gros défaut du protocole http est qu'il ne juge pas l'identité de l'utilisateur, ce qui apporte de gros inconvénients aux programmeurs. L'émergence de la fonction cookie compense ce défaut.
Les cookies enregistrent des données sur le disque dur du client via le navigateur du client lorsque le client accède au script. Les informations sur les données sont récupérées la prochaine fois que le client accède au script, réalisant ainsi la fonction de discrimination d'identité. Les cookies sont souvent utilisés dans la vérification de l'identité.
Syntaxe des cookies
L'envoi des cookies http s'effectue via des en-têtes http, antérieurs au transfert des fichiers. La syntaxe de l'en-tête set-cookie est la suivante :
Set-cookie:name=name;expires=date;path=path;domain=domain;secure
name=name : la valeur du cookie doit être définie (name ne peut pas utiliser " ; " et " , "). Utilisez " ; " pour séparer plusieurs valeurs de nom, par exemple : name1=name1;name2=name2;name3=name3 .
expires=date : durée de validité du cookie, format : expires="Wdy,DD-Mon-YYYY HH:MM:SS"
path=path : Définissez le chemin pris en charge par les cookies. Si path est un chemin, le cookie prendra effet sur tous les fichiers et sous-répertoires de ce répertoire. Par exemple : path="/cgi-bin/". le cookie sera effectif Désigne prendre effet sur ce fichier, par exemple : path="/cgi-bin/cookie.cgi".
domain=domain : Le nom de domaine efficace pour les cookies, par exemple : domain="www.codercto.com"
sécurisé : Si cet indicateur est donné, cela signifie que le cookie ne peut être transmis que via un serveur https avec protocole SSL.
La réception des cookies s'effectue en définissant la variable d'environnement HTTP_COOKIE. Les programmes CGI peuvent obtenir des informations sur les cookies en récupérant cette variable.
Paramètres des cookies
Le paramétrage des cookies est très simple, le cookie sera envoyé séparément dans l'en-tête http. L'exemple suivant définit l'ID utilisateur, le mot de passe et expire dans les cookies :
Exemple
#!/usr/bin/perl imprimer " Set-Cookie:UserID=XYZ; n " ; " Set-Cookie:Mot de passe=XYZ123; n " ; imprimer " Set-Cookie:Expires=Mardi 31 décembre 2017 23:12:40 GMT " ; n " ;print " Set - Cookie : Domain = www codercto . n " ; print " Set - Cookie : Path =/ perl ; n " ;print " Contenu - type : text / html r n r n " ;.......Autre contenu HTML Rechercher des cookies
La page de récupération des informations sur les cookies est très simple. Les informations sur les cookies sont stockées dans la variable d'environnement CGI HTTP_COOKIE. Le format de stockage est le suivant :
Exemple
#!/usr/bin/perl $rcvd_cookies = $ENV { ' HTTP_COOKIE ' } ; @cookies = split / ; / , $ rcvd_cookies ; $cookie ( @cookies ) { ( $key , $val ) = split ( /=/, $cookie ) # se divise sur le premier = ; $clé = ~ s /^ s +//; $val =~
s /^ s +//; $clé =~
s / s +$//; $val =~ s / s +$/ /; si ( $clé équip " ID de l'utilisateur " ) { $user_id = $val ; } elsif ( $clé équip " Mot de passe " ) { $mot de passe = $val ; } } imprimer " ID utilisateur = $user_id n " ; " Mot de passe = $mot de passe n " ; Le résultat de l’exemple ci-dessus est :
ID utilisateur = XYZMot de passe = XYZ123
Module CGI
Perl fournit de nombreux modules CGI intégrés, les deux suivants sont couramment utilisés :
Module CGI
Berkeley cgi-lib.pl