Formulaires, méthodes GET et POST
Généralités
Une autre particularité d'un site web interactif est de pouvoir récupérer
et prendre en compte des données saisies par l'utilisateur et des choix
(autres que celui d'afficher une page web particulière) effectués par
celui-ci.
Les formulaire HTML mettent à la disposition de l'utilisateur :
- des zones de texte (ou de valeur numérique) à remplir :
<input type="text" name="..." ...>
- des cases à cocher :
<input type="checkbox" name="..." ...>
- des boutons radio (1 choix parmi tous ceux proposés) :
<input type="radio" name="..." ...>
- des menus déroulants :
<select name="..." ...>
<option value="...">...</option>
...
</select>
- des zones de texte de plusieurs lignes :
<textarea name="..." cols="..." rows="..." ...>...
...
</textarea>
Le but de cette page n'est pas de présenter la syntaxe détaillée de tout
ce qu'on peut mettre dans un champ de formulaire, mais un rappel rapide
de l'ensemble des possibilités est toujours utile.
Dans le programme d'exemple fourni, on remplira 2 zones de texte et,
après avoir cliqué sur un bouton, une nouvelle page s'affichera avec
les données qu'on a saisi.
Il existe deux méthodes de communication entre le navigateur web et le
serveur pour transmettre les données des formulaires : les méthodes
GET et POST.
Le programme fourni permet d'utiliser les deux méthodes de communication.
Ce qui fait le site web
Ce site web commence par demander à l'utilisateur de saisir de 2
informations :
Après avoir cliqué sur la bouton
Répondre, l'utilisateur
obtient une réponse qui tient compte des données qu'il a saisies.
Elle est de la forme :
Si l'utilisateur a rempli les deux champs, ce qu'il a introduit apparaît
à la place des pointillés.
Dans le cas contraire, le programme Arduino se débrouille pour donner
quand même une réponse cohérente.
En dessous de cette réponse, l'utilisateur dispose de 2 liens pour
demander de recommencer soit avec la même méthode de communication,
soit avec l'autre.
Fonctionnement du programme Arduino
Pour téléverser le programme sur la carte Arduino, il faut d'abord mettre
dans un répertoire les 3 fichiers suivants :
Sur la carte SD, on mettra les fichiers :
On supposera que l'adresse MAC et l'adresse IP de la carte Ethernet
ont été configurées conformément à ce qui est dit dans la page
Généralités
Avant d'examiner la fonction
loop (), intéressons-nous à
2 déclarations de variables au début du programme :
// Nom du fichier à récupérer + paramètres
GET
char url [50];
// Paramètres POST
char post [50];
La variable
url est déjà connue. Elle n'était pas utilisée pour
le compteur de passage qui affiche toujours la même page, mais elle a
servi dans les différentes versions du site statique pour récupérer le
nom du fichier HTML à afficher.
Dans le cas du site statique, on avait besoin de 14 caractères, soit la
longueur maximale d'un nom de fichier MS-DOS + 2.
A présent, la variable
url va contenir aussi les paramètres passés
avec la méthode GET. Il faut donc prévoir davantage de caractères.
Plus précisément, l'envoi par le navigateur des valeurs d'un formulaire avec
la méthode GET se fait en demandant un URL rallongé de la forme :
adresse_ip/fichier_php?variable1=valeur1&variable2=valeur2....
avec une liste de variables et de valeurs plus ou moins longue.
Le nom des variables n'est pas du au hasard, il correspond aux noms
choisis dans le formulaire HTML :
Dans le cas de notre programme, on a 2 variables :
<input type="text" name="nom" maxlength="20" ...>
...
<input type="text" name="classe" maxlength="20" ...>
Si l'envoi du formulaire se fait avec la méthode GET, ce qui est précisé
un peu avant avec le nom de la page de réponse à afficher :
<form action=repget.ahp method=get>
l'URL demandée sera de la forme :
adresse_ip/repget.ahp?nom=...&classe=...
avec les données saisies par l'utilisateur à la place des pointillés.
Pour qu'une partie des données saisies par l'utilisateur ne soit pas
perdue, il faut que la variable
url ait au moins le nombre de
caractères qu'il y a à partir du / jusqu'à la fin de l'URL.
Une autre variable a été déclarée pour ce programme :
// Paramètres POST
char post [50];
Si l'envoi du formulaire se fait avec la méthode POST, les valeurs envoyées
sont stockées dans cette variable. Sa taille doit être au moins le nombre
de caractères qu'il y aurait à partir du ? jusqu'à la fin de l'URL.
Intéressons-nous maintenant à ce que fait la fonction
loop ()
Lorsque la carte Arduino détecte une demande de page, comme pour tous
les autres programmes, la fonction
lire_trame_client (...)
est appelée.
Mais cette fois-ci, elle l'est avec 5 paramètres :
lire_trame_client (client, url, sizeof (url), post, sizeof (post));
Ces paramètres sont :
- Identifiant du client web.
- Nom de la variable qui contiendra le nom de la page demandée par
le navigateur et les paramètres transmis par la méthode GET.
- Taille de la variable précédente.
- Nom de la variable qui contiendra les paramètres transmis par la
méthode POST.
- Taille de la variable précédente.
Remarque : Cette manière d'appeler
lire_trame_client (...) permet dans le même programme de
traiter des valeurs passées par la méthode GET et des valeurs passées
par la méthode POST.
Toutefois, si le site web n'utilise que la méthode GET, on pourra se
contenter d'appeler la fonction
lire_trame_client (...) avec
seulement 3 paramètres et un nombre de caractères suffisant pour la
variable
url.
Au contraire, si le site web n'utilise que la méthode POST, il faudra
appeler la fonction
lire_trame_client (...) avec ses 5
paramètres, mais 14 caractères suffiront pour la variable
url.
Normalement, on a récupéré de nom de la page demandée par le navigateur.
Mais, il se peut qu'elle n'ait pas été indiquée, si par exemple on a tapé
seulement l'adresse IP de la carte Arduino.
Dans ce cas, on choisit d'appeler la page de saisie du formulaire par la
méthode GET :
// si aucun nom de fichier ne figure dans l'url
if (! url [1])
// mettre le nom du fichier d'accueil
strcpy (url, "get.htm");
En supposant que l'ouverture du fichier contenant la page à afficher se
passe bien, 2 cas se présentent :
- Fichier AHP : on doit faire un traitement particulier.
- Fichier HTML classique : on envoie juste ce fichier.
Mais peut-être n'avez-vous jamais entendu parler de fichier AHP ?
C'est tout à fait normal.
La saisie d'un formulaire peut se faire avec un fichier HTML classique
(s'il n'y a pas de contrôle d'erreur). Par contre, le traitement des
données saisies, se fait, sur un serveur web classique, au moyen d'un
fichier PHP.
L'une des significations du sigle PHP est "PHP Hypertext Protocol".
Mais comme ça a été précisé, la carte Arduino a trop peu de mémoire pour
posséder un vrai interpréteur PHP.
J'ai donc décidé que lorsque des données saisies par l'utilisateur sont
traitées par le serveur, le fichier correspondant à la page web après ce
traitement seraient des fichiers AHP (suffixe
.ahp) abréviation
de "Arduino Hypertext Protocol".
Il y a quand me une grosse différence avec un fichier PHP. Un
vrai
fichier PHP (je sais qu'il y en a qui mélangent du HTML et du code PHP
dans le même fichier, ce que je désapprouve) c'est un programme. Ce
programme pourra éventuellement utiliser un ou plusieurs squelettes de
fichier HTML.
Un fichier AHP, c'est un squelette de fichier HTML et la partie programme
est intégrée au serveur Arduino.
Cette manière de procéder a ses limites : autant un site web peut
utiliser des dizaines ou centaines de fichiers PHP (chacun faisant un
travail différent), autant le programme Arduino qui permettrait la même
chose serait très long, et peut être qu'on manquerait de mémoire.
Mais pour un petit nombre de traitements simples, pas de problème.
On commence donc par tester si on a affaire à un fichier AHP. Ça pourrait
se faire en testant les 4 derniers caractères (suffixe) du fichier
sélectionné. Toutefois, comme les fichiers AHP de ce programme ont pour
nom
repget.ahp et
reppost.ahp, le test est fait sur
les 3 lettres du début :
// si page de réponse à un formulaire
if (memcmp (url, "rep", 3) == 0)
{
Si c'est bien l'un des deux fichiers AHP, on commence par récupérer les
valeurs des variables. Selon le fichier AHP, ça se fait par la méthode
GET ou la méthode POST.
// si réponse à un formulaire par la méthode get
if (memcmp (url,"repget", 6) == 0)
{
// récupérer les valeurs des variables
lecvar_get ("nom", url, valnom);
lecvar_get ("classe", url, valclasse);
}
// sinon méthode post
else
{
// récupérer les valeurs des variables
lecvar_post ("nom", post, valnom);
lecvar_post ("classe", post, valclasse);
}
Les fonctions
lecvar_get (...) et
lecvar_post (...)
utilisent avec la même liste de paramètres :
- Le nom de la variable du formulaire dont on veut récupérer la
valeur.
- La variable qui contient la liste des variables du formulaire
avec leurs valeurs.
- La variable qui va stocker la valeur trouvée.
Comme 2ème paramètre, on utilise pour
lecvar_get (...)
la variable qui était le 2ème paramètre de la fonction
lire_trame_client (...) et pour
lecvar_post (...)
la variable qui était le 4ème paramètre de cette fonction.
Remarque : Le formulaire qui a permit de saisir les 2 valeurs
autorisait pour chacune 20 caractères :
<input type="text" name="nom" maxlength="20" ...>
...
<input type="text" name="classe" maxlength="20" ...>
Les variables qui mémorisent ces valeurs utilisent un caractère de
plus :
char valnom [21], valclasse [21];
Ce caractère supplémentaire est nécessaire compte tenu de la manière dont
sont mémorisées les chaines de caractères en langage C.
On a récupéré les informations saisies par l'utilisateur. On va les afficher
dans une nouvelle page HTML qui est construite à partir du fichier
repget.ahp ou
reppost.ahp selon le mode de transmission
des valeurs saisies.
Le contenu de ces 2 fichiers ne diffère qu'au niveau de leur titre et des
liens en bas de page. Voici le code source du premier :
La partie du code source qui nous intéresse est celle-ci :
<p style="font-size : 30" align="center">
Bonjour XXXNOM
de XXXCLASSE
</p>
Il faut d'abord remplacer
XXXNOM par le nom saisi pat l'utilisateur
dans le formulaire. Mais il peut très bien n'en avoir saisi aucun ! Dans ce
cas, on va l'appeler "inconnu".
// si nom inconnu
if (! *valnom)
// l'initialiser
strcpy (valnom, "inconnu");
Tout est prêt pour recopier le début du fichier AHP (qui contient du HTML)
jusqu'à la ligne qui contient
XXXNOM en remplaçant
XXXNOM
par la valeur du nom mémorisé. Cela se fait en utilisant la même fonction
que pour le programme "compteur de passages".
// copier la page HTML jusqu'à l'affichage du nom
coprep_chaine (descfic, client, "XXXNOM", valnom);
A présent, on va s'occuper de la 2ème valeur mémorisée. Mais le traitement
va être différent si l'utilisateur n'a rien saisi pour la classe dont il
fait partie.
// si classe inconnue
if (! *valclasse)
// sauter l'indication de la classe
sauter_jusque_chaine (descfic, "XXXCLASSE");
// sinon
else
// copier avec le nom de la classe
coprep_chaine (descfic, client, "XXXCLASSE", valclasse);
Si la variable
valclasse est vide, on utilise une nouvelle
fonction :
sauter_jusque_chaine (descfic, "XXXCLASSE");
Cette fonction lit les lignes du fichier AHP à partir de celle où on
s'était arrêté précédemment, jusqu'à la ligne qui contient
XXXCLASSE
mais renvoie pas ces lignes vers le navigateur web.
Dans le cas particulier des fichiers
repget.ahp et
reppost.ahp, comme la partie du fichier AHP qu'on ne veut pas
envoyer au navigateur se limite à la ligne qui suit l'endroit où on s'était
arrêté, une autre instruction aurait pu réaliser le même travail :
lire_ligne (descfic);
Dans le cas où la variable
valclasse contient une chaine de
caractères, on utilise comme pour la variable
valnom la fonction
coprep_chaine (...) pour remplacer
XXXCLASSE par
le bon contenu.
Dans le code source des fichier AHP, le message
Bonjour XXXNOM
de XXXCLASSE
est sur 2 lignes. Mais comme il n'y a pas de balise de passage à la ligne
après le nom, tout le texte apparaitra sur la même ligne dans la fenêtre
du navigateur (sauf si la largeur de cette fenêtre est très faible).
Selon que l'utilisateur ait ou non saisi une information pour sa classe,
la chaine de caractère affichée sera de la forme :
ou seulement
On a fini avec les traitements spécifiques aux fichiers AHP. Le déroulement
du programme se poursuit avec l'instruction :
// envoi de la page ou de la fin de page
copie_jusque_fin (descfic, client);
Dans le cas d'un fichier AHP, on s'était arrêté à la ligne :
</p>
et cette instruction renvoie au navigateur la fin du fichier AHP à partir
de cette ligne là.
Si au contraire, on doit envoyer un fichier HTML, les traitements
concernant la récupération des valeurs du formulaire et leurs affichage
n'ont pas été effectués :
// si page de réponse à un formulaire
if (memcmp (url, "rep", 3) == 0)
{
// séquence d'instructions qu'on n'exécute pas dans le cas d'un
fichier HTML
}
// envoi de la page ou de la fin de page
copie_jusque_fin (descfic, client);
et dans ce cas, la fonction
copie_jusque_fin () envoie la
totalité du contenu du fichier HTML au navigateur.