Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Non-Officiels > Programmation > Python > Aperçu de la CGI avec Python > Lecture du tutoriel

Aperçu de la CGI avec Python

Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
Avatar
Auteur : Krankkatze
Note : 19 / 20 (10 votes)
Visualisations : 5 014

Plus d'informations Plus d'informations
Vous aimeriez rendre votre site interactif, par exemple pour mettre en place un compteur de visites, un formulaire de contact, un petit jeu, ...
Pour ça, tout le monde utilise le PHP. Mais, vous faites partie d'une élite éclairée, et vous aimeriez le faire avec Python. C'est faisable !
Voici un aperçu de la CGI avec ce langage.

Juste une chose avant de commencer, si vous n'avez pas d'hébergeur qui vous permette d'utiliser Python sur vos pages web, regardez donc cette liste. Si vous hébergez votre site vous même, alors sachez qu'il vous suffit d'installer Apache et Python.
Sommaire du tutoriel :
Icône du chapitre

Préparation

Pour que vos scripts soient exploitables, il faut tout d'abord configurer Apache.
Créons un fichier .htaccess, que vous placerez à la racine du site (en effet, ce fichier fonctionne récursivement : tous les répertoires situés dans le répertoire contenant votre .htaccess seront assujettis aux règles que vous définirez dans celui-ci). Le voici :
Code : Apache
1
2
AddHandler cgi-script .py
Options +ExecCGI

Ces deux lignes indiquent que les fichiers .py doivent être interprétés avant d'être envoyés au client. Le comportement par défaut serait d'envoyer le fichier comme s'il s'agissait d'un fichier texte ordinaire.
Une bonne chose à faire est de configurer Apache pour considérer vos fichiers index.py comme les indexes de vos répertoires. Pour cela, vous pouvez ajouter la ligne suivante à votre .htaccess :
Code : Apache
1
DirectoryIndex index.py

Néanmoins, il reste une chose très importante à faire : rendre votre script exécutable. Je dois reconnaître que je me suis souvent fait avoir par ce genre d'erreur. C'est assez pervers car vous ne savez pas pourquoi votre script échoue : vous vous retrouvez face à une erreur 500 fort peu explicite.
Pour ce faire, sous UNIX, il faut utiliser la commande suivante :
Code : Bash
1
chmod +x fichier.py

Vous devez le faire sur chacun de vos scripts.

Maintenant, nous allons voir comment rédiger nos fichiers Python.

La rédaction des scripts

Lorsque vous utilisez python pour votre site web, vous générez du HTML.
Il vous faut le préciser : vous pourriez très bien renvoyer une image, aussi faut il informer le client de la nature du document renvoyé.
Pour ce faire, il faut tout simplement utiliser print :
Code : Python
1
2
3
4
5
#!/usr/bin/python

print 'Content-type: text/html'
print 
# Là commence votre code.

La première ligne est importante : il s'agit du shebang. Il indique quel interpréteur Python utiliser.
La seconde (en réalité, la troisième car j'ai sauté une ligne) indique le type de document envoyé.
La dernière écrit une ligne vide. En effet, le client et le serveur communiquent par le protocole HTTP. Ce dernier est composé d'un en-tête, dans lequel des informations comme le nom et la version du client, ceux du serveur, le poids du fichier, l'état de la requête (vous savez, 200 OK, 404 Not Found, 500 Internal Server Error, ...), etc., et du corps de la requête, qui contient, dans le cas d'une requête du serveur vers le client, le fichier envoyé. Ces deux blocs (en-tête et corps) sont séparés par une ligne vide. Pour plus d'informations, regardez donc l'article sur Wikipedia.

Le type de fichier (que j'ai spécifié à la deuxième ligne avec 'Content-type: text/html'), fait partie de l'en-tête de la requête. Or, la page que vous souhaitez envoyer se trouve dans le corps. C'est pourquoi vous devez les séparer à l'aide de cette ligne vide.

Votre script est maintenant prêt. Vous pouvez désormais écrire votre code HTML, toujours à l'aide de print :
Code : Python
1
2
3
4
5
#!/usr/bin/python

print 'Content-type: text/html'
print
print '<html><head><title>...'

Vous pouvez, plutôt que de vous esquinter à écrire ligne par ligne :
Code : Python
1
2
3
4
5
6
print '<html>'
print '<head>'
print '<title>Mon super site en Python qui powne tout XdXDxDXDXd</title>'
print '</head>'
print '<body>'
# ... Je vous épargne la suite de cette horreur.

Utiliser la syntaxe suivante, qui n'est pas toujours connue :
Code : Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
print '''
<html>
     <head>
          <title>Mon super site en Python qui powne tout XdXDxDXDXd</title>
     </head>
     <body>
          <p>Vous êtes jaloux, hein ?</p>
     </body>
</html>
'''

Vous constatez qu'à l'intérieur des ''', vous pouvez utilisez l'indentation que vous voulez.
Il est bien entendu important de rendre son site conforme aux normes de la W3C.

Si vous avez eu l'occasion de faire une erreur dans votre code, vous avez sûrement pu admirer une erreur 500. Et, vous l'avez remarqué, c'est très génant pour le dépistage d'erreurs. Le module cgitb va pouvoir vous aider.
Pour cela, il faut l'importer, puis l'activer :
Code : Python
1
2
import cgitb
cgitb.enable()

C'est fait ! Maintenant, les erreurs s'afficheront sur la page. Ces deux lignes vous seront certainement utiles !

Mise en pratique : un compteur de visites

Maintenant que vous connaissez le strict minimum, pourquoi ne pas l'employer ? Nous allons réaliser un compteur de visites.
Il serait judicieux de tenter de le faire seul. Néanmoins, je vous donne ma méthode :
Tout d'abord, je tente d'ouvrir un fichier en mode lecture ('r' pour read). Je stocke son contenu dans la variable nbr_visiteurs, en le transformant en un nombre (car il s'agit pour l'instant d'une chaîne). Si cela ne marche pas (pour la bonne raison que mon fichier n'existe pas, ou que son contenu n'est pas un nombre), alors nbr_visiteurs = 0.
Cela donne :
Code : Python
1
2
3
4
5
try: # Pour essayer le code qui suit. Si ledit code ne fonctionne pas, alors except: est appelé. Autrement, on continue.
    fichier = open('compteur','r') # Lecture dans le fichier, appelé 'compteur'.
nbr_visiteurs = int(fichier.read()) # int() transforme son argument (à savoir, le contenu du fichier retourné par fichier.read()) en un nombre.
except Exception:
    nbr_visiteurs = 0 # Si le fichier est inexistant (= page jamais visitée) ou incorrect, on repart de 0.

Maintenant, nous allons ouvrir le fichier avec l'option 'w' pour write. S'il existe, il sera supprimé et recréé vide. Sinon, il sera tout simplement créé. Dans les deux cas, nous n'aurons plus qu'à écrire dedans la valeur nbr_visiteurs + 1 (car il faut compter le visiteur qui charge la page :-) ), en la transformant en une chaine avec la fonction str().
Code : Python
1
2
fichier = open('compteur','w')
fichier.write(str(nbr_visiteurs+1))

Finalement, on indique au visiteur le nombre de visites :
Code : Python
1
print nbr_visiteurs+1,'visites \o/'


Ce qui, avec le code minimal, donne :
Code : Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/usr/bin/python

print 'Content-type: text/html'
print

try:
    fichier = open('compteur','r')
    nbr_visiteurs = int(fichier.read())
except Exception:
    nbr_visiteurs = 0
    fichier = open('compteur','w')
fichier.write(str(nbr_visiteurs+1))
print nbr_visiteurs+1,'visites \o/'

Traiter un formulaire

Un des points inévitables en CGI est le traitement de formulaires. En Python, c'est faisable aussi.

Nous travaillons maintenant avec des données envoyées par l'utilisateur. Nous allons notamment les afficher à l'écran. Or, si le visiteur décide de mettre du HTML dans les données qu'il envoie, cela peut présenter une faille.

Prenons un cas concret. Si le visiteur entre le code suivant :
Code : HTML
1
<script type="text/javascript">alert('OLOL CMT G T PWNED');</script>
Une alerte s'affichera sur l'écran du visiteur ! Et rien ne l'empêche de se faire passer pour vous "Votre session va expirer. Entrez votre mot de passe à nouveau.", de le récupèrer puis de se le faire envoyer par mail, le tout en JavaScript !
Pour pallier à ce problème, nous allons utiliser une fonction fort pratique : cgi.escape(). C'est un peu l'équivalent de htmlentities() en PHP : elle remplace les caractères < et > par &lt; et &gt;. De ce fait, le code Javascript cité plus haut s'affichera tel quel, au lieu d'être exécuté.
Aussi, prenez l'habitude de sécuriser toutes les données envoyées par le visiteur à l'aide de cette fonction.

Pour traiter un formulaire, nous devons tout d'abord importer le module CGI. Vous savez comment faire :
Code : Python
1
import cgi

À partir de là, ça se corse :-° On va créer une instance de la classe cgi.FieldStorage(), qui contiendra le formulaire envoyé. Puis, on pourra en extraire les informations avec instance.getvalue('nom'). Cela vous semble tordu ? En vérité, c'est très simple.
Code : Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/usr/bin/python

import cgi

print 'Content-type: text/html'
print
formulaire = cgi.FieldStorage()
if formulaire.getvalue('nom') == None:
    print '''
Veuillez remplir le formulaire : 
<form action="formulaire.py" method="post">
<input type="text" name="nom" />
<input type="submit"></form>
    '''
else:
    print 'Ainsi, vous vous appelez',cgi.escape(formulaire.getvalue('nom')),' ?' # N'oubliez pas de sécuriser le code !

Ce code, enregistré dans un fichier formulaire.py (autrement, il vous faudra le modifier, car le formulaire renvoie vers formulaire.py), créera une instance de cgi.FieldStorage() dans la variable formulaire.
Si formulaire.getvalue('nom') == None, alors le champ 'nom' était vide, voire non envoyé.
On présente donc le formulaire au client. Autrement, on récupère la valeur du champ 'nom' avec formulaire.getvalue('nom'), et on l'affiche tout en prenant soin de le sécuriser avec cgi.escape().
Si le champ s'était appelé 'prenom', vous comprenez bien qu'on aurait récupéré sa valeur avec formulaire.getvalue('prenom').

Vous voulez une bonne nouvelle ? Pour un formulaire envoyé avec GET (c'est à dire que les valeurs des champs se retrouvent dans l'url, dans le style page.py?var=valeur&var2=valeur2), c'est exactement pareil.
Ainsi, le script suivant enregistré sous essai.py et appelé avec essai.py?var=1&var2=2 affichera 'Var = 1 et Var2 = 2'.
Code : Python
1
2
3
4
5
6
7
8
9
#!/usr/bin/python

import cgi

print 'Content-type: text/html'
print

form = cgi.FieldStorage()
print 'Var = ',cgi.escape(form.getvalue('var')),' et Var2 = ',cgi.escape(form.getvalue('var2'))

Mise en Pratique : Un livre d'or

Le livre d'or est une des fonctionnalités qu'on se plaît à implémenter sur son site. Grâce aux formulaires et à la manipulation de fichiers, c'est tout à fait faisable en Python.
Nous allons tout d'abord créer un formulaire tout simple, puis le traiter. Ensuite, nous verrons comment lire le fichier dans lequel seront enregistrés les messages.
Le formulaire ressemblera à ça :
Code : HTML
1
2
<form action="enregistrement.py" method="post"><p>Vous avez une remarque, un commentaire, un conseil ? Signez le livre d'or !</p>
<p><p>Pseudonyme : <input type="text" name="pseudo" /><br />Site web : <input type="text" name="site" /><br />Message :<br /><textarea name="message"></textarea><br /><input type="submit" /></form>

À vous de le faire correspondre à vos besoins.
Pour la gestion du formulaire :
Code : Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/python

import cgi

print 'Content-type: text/html'
print

print '<html><head><title>Mon super site</title></head><body>'
formulaire = cgi.FieldStorage()
if formulaire.getvalue('message') != None:
    print '<p>Merci d\'avoir particip&eacute; au livre d\'or. Vous pouvez le visiter <a href="livreor.py">ici</a>.</p>'
    message = formulaire.getvalue('message')
    site = formulaire.getvalue('site')
    pseudo = formulaire.getvalue('pseudo')
    try:
        fichier = open('livreor','r')
        livreor = fichier.read()
    except IOError:
        livreor = ''
    message_poste = '<message><auteur>'+cgi.escape(pseudo)+'</auteur><site>'+cgi.escape(site)+'</site><contenu>'+cgi.escape(message)+'</contenu></message>\n'
    fichier = open('livreor','w')
    fichier.write(message_poste+livreor)
else:
    print '''Erreur : vous n'avez pas rempli le formulaire.'''
print '</body></html>'


C'est tout simple :

L'écriture est terminée. Chaque message est écrit dans le format:Code : XML
1
<message><auteur>Auteur</auteur><site>Site</site><contenu>Contenu</contenu></message>
.
Nous n'avons plus qu'à le lire !
Code : Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/python

def trouver(chaine,chaine1,chaine2):
    position_chaine1 = chaine.index(chaine1) + len(chaine1)
    position_chaine2 = chaine.index(chaine2,position_chaine1)
    return chaine[position_chaine1:position_chaine2]

def isoler_message(chaine):
    dico = {}
    try:
        message = trouver(chaine,'<message>','</message>')
        dico['auteur'] = trouver(message,'<auteur>','</auteur>')
        dico['site'] = trouver(message,'<site>','</site>')
        dico['contenu'] = trouver(message,'<contenu>','</contenu>')
        return dico
    except Exception:
        return 0

def supprimer(chaine):
    return chaine.replace('<message>'+trouver(chaine,'<message>','</message>')+'</message>','')

print 'Content-type: text/html'
print 
print '''
<html>
<head>
<title>Le livre d'or</title>
</head>
<body>
'''
try:
    fichier = open('livreor','r')
    contenu = fichier.read()
    continuer = True
    while continuer:
        message = isoler_message(contenu)
        if not message:
            continuer = False
        else:
            print '<p>De : <b><a href="',message['site'],'">',message['auteur'],'</a></b></p>'
            print '<p>',message['contenu'],'</p>'
        print '<br /><br />'
        chaine = supprimer(chaine)
except Exception:
    print 'Il n\'y a aucun message dans le livre d\'or'
print '</body></html>'


Ma première fonction, trouver(), retourne la première chaîne trouvée entre chaine1 et chaine2 dans chaine. Son fonctionnement est simple, lisez le code si vous souhaitez le comprendre.

La seconde, isoler_message(), utilise trouver() pour trouver le premier message (la première chaîne entre <message> et </message>), puis extrait les différentes informations (l'auteur, le site, et le contenu). Finalement, elle retourne le dictionnaire dans lequel elle a tout enregistré.

La troisième, supprimer(chaine), supprime le premier message (le texte entre <message> et </message>, ainsi que les deux balises), pour que la lecture puisse être recommencée sur le message suivant.

On commence par afficher le début du HTML de la page. Puis, on essaye de lire le fichier livreor, puis d'isoler le premier message, de l'afficher, et de le supprimer de la liste, avant de recommencer, jusqu'à ce qu'il n'y ait plus de messages.
Si cela ne fonctionne pas, on affiche qu'il n'y a pas de message dans le livre d'or.
C'est tout à fait rudimentaire. À vous d'ajouter ce que vous voulez : datez les messages, faites des pages lors de l'affichage, ...

Vous voyez que, en travaillant des fichiers et en traitant des formulaires, vous pouvez déjà aller loin. Légèrement modifié, ce livre d'or peut vous fournir un système de news.

Afficher sa source

Une dernière astuce dont j'aimerai vous faire part est l'affichage de la source. En effet, il est agréable de pouvoir avoir le code d'un site web sous les yeux, pour pouvoir s'en inspirer, ou même donner des conseils au webmaster.
Ce genre de chose ne doit PAS être implémenté sur des pages sensibles comme l'administration, à moins que vous ne soyez absolument certain(e) de la sécurité de votre code.

Pour afficher la source, le client n'aura qu'à entrer l'URL de la page ainsi :
http://site.web/index.py?source=1
Il nous faudra donc utiliser cgi.FieldStorage(), et tester si source=1. Dans ce cas, on lit le fichier, et on l'affiche entre <pre> et </pre>, pour que le code HTML et les sauts à la ligne apparaissent.Puis, on s'arrête là avec sys.exit(0).
Autrement, on envoie la page comme d'habitude.
Voici mon code :
Code : Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/usr/bin/python

import sys # Nécéssaire pour votre sys.exit(0)
import cgi

print 'Content-type: text/html'
print
form = cgi.FieldStorage()
if form.getvalue('source') == '1':
    fichier = open('fichier.py','r')
    print '<pre>'+fichier.read()+'</pre>
    sys.exit(0) # On s'arrête là.
# Suite du code

C'est enfantin mais pratique ^^

Ce tutoriel n'est ici que pour solliciter votre enthousiasme. Pour pouvoir mettre en place un site web plus complexe, utilisant une base de données, par exemple, vous devez vous tourner vers la documentation.
J'espère vous avoir intéressé et donné des idées.
Bonne continuation avec Python !
Merci à delroth et plus généralement à tout #python pour l'aide qui m'a été apportée lors de la création de mon propre site, et sans qui ce tutoriel n'aurait pas vu le jour.
Retour en haut Retour en haut


Créé : le 22/04/2008 à 19:54:39
Modifié : le 22/08/2008 à 16:10:15
Avancement : 0%
Licence : Copie non autorisée

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | RSS tutoriels | RSS news
Édité par Simple IT SARL : Nous contacter | Notre blog | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !

Hébergement web - Correction de tutoriels - Créer un site
Vous souhaitez apparaître ici ? Contactez-nous.

Nombre de connectés 171 Zéros connectés | Requêtes SQL 8 requêtes | Temps de génération de la page : Total (SQL) 0.0248s (0.0145s)