Corrigé du TD 4

Il fallait tout d'abord faire fonctionner l'appel du script par le formulaire. On commencera donc par un formulaire minimaliste, contenant seulement le bouton "envoyer" :

<HTML>
<HEAD>
    <TITLE>Inscription </TITLE>
    <META http-equiv="Content-Script-Type" content="text/javascript">
</HEAD>
<BODY>
    <H3 ALIGN=CENTER>Formulaire d'inscription</H3>

    <FORM ACTION="http://localhost:8888/cgi-bin/register.cgi" METHOD="POST" onsubmit="return false">
        <input TYPE="button" VALUE=" Envoyer " onclick="this.form.submit(  )" />
    </FORM>

</BODY>
</HTML>

Pour le script, on lira attentivement la documentation du module cgi.

Il est précisé que le script doit être placé dans un sous-répertoire cgi-bin de la racine du serveur, qu'il doit être éxécutable par celui-ci (mode 755), et que sa première action doit être d'imprimer "content-type: text/html", suivi d'une ligne blanche. Tout ce qui est avant la ligne blanche est interprété comme un en-tête.

Un script minimal sera donc :

#!/usr/bin/python

print "content-type: text/html"
print

html = "<html>Hello, cgi world!\n</html>"
print html

Noter qu'à ce stade, le module cgi n'est pas utilisé. Noter aussi que la première ligne doit être #!/usr/bin/python. Un script cgi peut être écrit dans n'importe quel langage, le serveur ne peut pas deviner que c'est du Python. Ceci fait, il n'y a plus aucune difficulté à compléter le formulaire. Les fichiers utilisés par le script devront être créés d'avance, y compris les fichiers de verrouillage. Le formulaire pourrait ressembler à ceci :

    <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD> 
<TITLE>Inscription au 6ème congrès de la FFFF</TITLE>
<META http-equiv="Content-Script-Type" content="text/javascript">
</HEAD>

<BODY>
<H1 ALIGN=CENTER>Fédération Française de Friture à Froid </H1>
<H2 ALIGN=CENTER>Inscription au 6ème Congrès</H2>
<HR>
<FORM ACTION="http://localhost:8888/cgi-bin/register.cgi" METHOD="POST" onsubmit="return false">
<TABLE ALIGN="CENTER">
<TR><TD></TD></TR>
<TR><TD>Nom  </TD><TD>  <INPUT TYPE="TEXT" NAME="nom" SIZE=40></TD></TR>
<TR><TD>Prénom  </TD><TD><INPUT TYPE="TEXT" NAME="prenom" SIZE=40></TD></TR>
<TR><TD>Email </TD><TD>  <INPUT TYPE="TEXT" NAME="email" SIZE=40></TD></TR>
<TR><TD>Société </TD><TD>  <INPUT TYPE="TEXT" NAME="institution" SIZE=40></TD></TR>
<TR><TD>Téléphone </TD><TD>  <INPUT TYPE="TEXT" NAME="phone" SIZE=40></TD></TR>
<TR><TD>Arrivée</TD><TD></TD></TR>
<TR><TD>(date et heure)</TD><TD>  <INPUT TYPE="TEXT" NAME="arrivee" SIZE=40></TD></TR>
<TR><TD>Depart</TD><TD></TD></TR>
<TR><TD>(date et heure)</TD><TD>  <INPUT TYPE="TEXT" NAME="depart" SIZE=40></TD></TR>
</TABLE>
<hr>
<p> <input TYPE="button" VALUE=" Envoyer " onclick="this.form.submit(  )" />
</form>
</body>
</html>

Et le script serait quelque chose du genre :

#!/usr/bin/python
#-*- coding: utf-8 -*-
import cgi, string, sys, os, fcntl

# pour remplacer sauts de lignes et tabulations par des espaces
tt = string.maketrans(string.whitespace, ' '*6)

# lecture des donnees du formulaire
form = cgi.FieldStorage()


# format pour la page de confirmation de l'inscription
html = """
<TITLE> Confimation d'inscription </TITLE>
<H1> Inscription enregistrée </H1>
<H2> 6ème congrès de la FFFF </H2>
<BR>
<BR> %(nom)s %(prenom)s
<BR> %(email)s
<BR>
<BR> %(institution)s
<BR> %(phone)s  
<BR> Arrivée : %(arrivee)s
<BR> Depart : %(depart)s
<BR>
<HR>
"""

data = {}

fields = ['nom', 'prenom', 'email', 'institution', 'phone', 'arrivee', 'depart']

for field in fields:
        if field not in form: data[field] = ''
        else: data[field] = form[field].value

# une ligne du fichier csv
row = string.translate('|'.join([data[field] for field in fields]),tt)+'|'+'\n'


# ecriture fichier csv (exclusion mutuelle par fichier de lock)
# on utilise un fichier auxiliaire csv.lck pour éviter de laisser un verrou sur participants.csv si
# le programme se plante
lockfile = open('csv.lck', 'r')
fcntl.flock(lockfile.fileno(), fcntl.LOCK_EX)
f = open('participants.csv','a')
f.write(row)
f.close()
fcntl.flock(lockfile.fileno(), fcntl.LOCK_UN)

# ecriture liste de participants
participant =  data['nom']+' '+data['prenom'] +' : ' + data['email']+'\n'

lockfile = open('txt.lck', 'r')
fcntl.flock(lockfile.fileno(), fcntl.LOCK_EX)

f = open('participants.txt','a')
f.write(participant)
f.close()
fcntl.flock(lockfile.fileno(), fcntl.LOCK_UN)



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

print html % data

Pour avoir la liste des participants avec leurs emails au format html, avec des liens mailto:, le mieux serait de l'inclure dans une page shtml. Mais le serveur basique de Python ne gère pas le shtml, on se contentera donc d'un simple fichier texte.

Pour récupérer les adresses, on utilisera une expression régulière. Noter que ce n'est pas trivial si on veut tenir compte de toutes les possibilités, voici celle du validateur de Django :

email_re = re.compile(
    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain

Il serait beaucoup plus simple d'extraire les liens mailto: avec HTMLParser. Pour envoyer un message, le script minimal serait :

# -*- coding: utf-8 -*-
import sys, smtplib

From = 'toto@pouet.com'
To = 'gerard.mansoif@ffff.org'
fromto = "From: Toto <toto@pouet.com>\nTo: "+To+"\n"
subj = "Subject: Brocolis pas chers"+"\n\n"
headers=fromto + subj

text = """ Grand choix de légumes pas chers :
http://pouet.com
"""

text =  text + '\n'

msg = headers+text

smtp = smtplib.SMTP()
smtp.connect('smtp.mail.yahoo.fr', 25)
smtp.sendmail(From, To, msg)
smtp.quit()

sys.exit(0)
In []: