oct 2007
11
Tutoriel Javascript/PHP/Ajax : Verifier les données d'un formulaire
Par Anthony, à 22h34 dans Développement | #36 | RSS | 11066 lectures
A la demande de Zen (mais avec beaucoup de retard), voici un tutoriel mettant en application les bonnes pratiques énoncées dans mon précédent billet sur la vérification des données d'un formulaire. Le but de ce tutoriel est donc de proposer un formulaire à un visiteur, tout en lui simplifiant la tâche via des fonctionnalités coté client, mais avec surtout de bonnes vérifications coté serveur. Il s'agit donc d'un exemple précis utilisant comme technologies les langages PHP pour la vérification coté serveur, Javascript pour la vérification coté client, ainsi que Ajax pour faciliter l'utilisation du formulaire au visiteur. Je ne rentrerais par contre pas dans tous les détails du code, notamment pour la partie Ajax. Des connaissances (ou des recherches personnelles) vous seront alors peut-être nécessaire pour mettre ce tutoriel en production sur un projet personnel.
Le résultat souhaité
Pour ce tutoriel, nous prendrons comme exemple un formulaire d'inscription à un service quelconque. Ce formulaire sera très simple pour se cantonner au but du tutoriel et demandera seulement un nom d'utilisateur, un mot de passe, une adresse email et le code postal du visiteur.
Concernant les vérifications :
- Pour le champ "Nom d'utilisateur" : on utilisera Ajax pour aller vérifier si le nom désiré est déjà pris ou pas.
- Pour le champ "Mot de passe" : on utilisera une fonction Javascript qui affichera un message suivant le niveau de sécurité du mot de passe (faible/correct/elevé). La vérification sera sommaire, car elle dépendra seulement du nombre de caractères saisis.
- Pour le champ "Adresse e-mail" : on contrôlera avec une fonction Javascript si l'adresse saisie respecte bien le format d'une adresse e-mail (xxx@xxx.xx).
- Pour le champ "Code Postal" : on limitera la longueur du champ à 5 caractères grâce à XHTML. On pourrait également faire une fonction Javascript qui vérifiera que la donnée saisie est uniquement composée de caractères numériques. On va partir du principe qu'il s'agit d'un champ non obligatoire : on n'effectuera alors un contrôle que coté serveur, afin de ne pas perdre de temps inutilement dans une vérification coté client (aussi simple qu'elle soit dans cette exemple).
Création du formulaire
Afin de commencer par le commencement, nous allons tout d'abord mettre en place notre formulaire XHTML, avec 4 champs de saisie pour le nom d'utilisateur, le mot de passe, l'adresse email et le code postal. Nous ajoutons aussi 4 balises span pour afficher les messages d'alerte pour chaque champ, dont l'id sera le nom du champ concerné suivi de "_alert" afin de pouvoir pointer facilement dessus via le DOM pour modifier le message. Pour le champ Code postal, l'attribut maxlength avec une valeur de 5 limitera le nombre de caractères saisissables.
L'attribut action du formulaire appelera ce même fichier. Pourquoi ? Parce qu'ainsi, en cas d'erreur, on pourra réafficher facilement les valeurs saisies par le visiteur grace à $_POST["nom_du_champ"]. Vu que le formulaire s'appelle lui-même, il faudra alors détecter si il a été soumis pour inclure le traitement des données avant son réaffichage. Nous allons créer un tableau de données en PHP pour pouvoir transmettre les messages d'erreurs entre la vérification coté serveur (PHP) et le formulaire. L'affichage se fera dans les balises span correspondant à chaque champ. On rajoute également un paragraphe p au dessus du formulaire qui servira à afficher le message de confirmation d'inscription en cas de réussite.
form.php
<?php // si le formulaire a été soumis, on inclut le traitement if($_POST) include("verifForm.php"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <title>Tutoriel Javascript/PHP/Ajax : Verifier les données d'un formulaire</title> <link type="text/css" rel="stylesheet" href="style.css" /> <script type="text/javascript" src="function.js"></script> <script type="text/javascript" src="XHRConnection.js"></script> </head> <body> <h1>Tutoriel Javascript/PHP/Ajax : Verifier les données d'un formulaire</h1> <p>Source du tutoriel : <a href="http://blog.aguillem-creations.fr/36-tutoriel-javascript-php-ajax-verifier-les-donnees-d-un-formulaire">Tutoriel Javascript/PHP/Ajax : Verifier les données d'un formulaire</a></p> <?php if (!empty($message["ok"])) { ?> <p><?php print $message["ok"];?></p> <?php } ?> <form action="form.php" method="post" class="formulaire"> <p> <label>Nom d'utilisateur : </label> <input type="text" id="username" name="username" value="<?php print $_POST["username"];?>" /> <span id="username_alert"><?php print $message["username"];?></span> </p> <p> <label>Mot de passe : </label> <input type="password" id="password" name="password" value="<?php print $_POST["password"];?>" /> <span id="password_alert"><?php print $message["password"];?></span> </p> <p> <label>Adresse e-mail : </label> <input type="text" id="email" name="email" value="<?php print $_POST["email"];?>" /> <span id="email_alert"><?php print $message["email"];?></span> </p> <p> <label>Code postal : </label> <input type="text" id="codepostal" name="codepostal" value="<?php print $_POST["codepostal"];?>" maxlength="5" size="5" /> <span id="codepostal_alert"><?php print $message["codepostal"];?></span> </p> <p> <input type="submit" value="Valider" /> </p> </form> </body> </html>
Vérifications coté serveur
Une fois le formulaire mis en place, le plus important est de s'attaquer à la vérification des données coté serveur, dans ce cas en PHP. Là, il y a deux possibilités : faire un script linéaire ou découper en fonctions. On utilisera cette deuxième option afin de faciliter la réutilisation des fonctions de vérifications standards. Dans le cas de traitements ou vérifications vraiment spécifiques, il peut être plus judicieux d'en faire un script linéaire plutôt que s'embêter à en faire des fonctions réutilisables qui ne seront pas forcément adaptées à d'autres cas. Il ne s'agit pas pour autant d'un développement orienté objet...
Nous allons donc vérifier chaque champ avant de valider l'inscription. Si il y a des erreurs, nous retournerons les messages à afficher via le tableau $message.
verifForm.php
<?php include("function.php"); // on vide le tableau d'erreur unset($message); // recupération des valeurs du formulaire $username = $_POST["username"]; $password = $_POST["password"]; $email = $_POST["email"]; $codepostal = $_POST["codepostal"]; // on verifie que le nom n'est pas vide avant de lancer la verification qui implique des requetes SQL if(!empty($username)) $dispoUsername = verifDispoUsername($username); // on verifie que le password n'est pas vide $validPassword = (!empty($password)); // on vérifie le format de l'adresse email $validEmail = validEmail($email); // on verifie le format du code postal $validCodePo = validCodePostal($codepostal); if($dispoUsername && $validPassword && $validEmail && $validCodePo) { // si tous les criteres sont validés, on envoie un message de validation $message["ok"] = "L'inscription a bien été effectuée"; // on vide les données pour éviter un doublon des données en cas de nouvelle soumission du formulaire unset($_POST); } else { // si les criteres ne sont pas tous validés, on envoie le(s) message(s) d'erreur correspondant(s) if(!$dispoUsername) $message["username"] = "Le nom d'utilisateur est soit vide, soit deja utilisé"; if(!$validPassword) $message["password"] = "Le mot de passe est vide"; if(!$validEmail) $message["email"] = "L'adresse email n'est pas correcte"; if(!$validCodePo) $message["codepostal"] = "Le code postal n'est pas correct"; } ?>
Et voici le fichier contenant les fonctions nécessaires, qui pourront être éventuellement réutilisables dans d'autres pages ou d'autres projets.
function.php
<?php /**************************************************************************** ' Verifie l'authentificité d'une adresse email ' @author bobocop (arobase) bobocop (point) cz ' @adaptation GUILLEMETTE Anthony ' @email aguillem16 (arobase) gmail (point) com ' @date 01/12/2006 ' @param string email email a verifier ' @return boolean validité de l'email ****************************************************************************/ function validEmail($email) { // Auteur : bobocop (arobase) bobocop (point) cz // Traduction des commentaires par mathieu // Le code suivant est la version du 2 mai 2005 qui respecte les RFC 2822 et 1035 // http://www.faqs.org/rfcs/rfc2822.html // http://www.faqs.org/rfcs/rfc1035.html $atom = '[-a-z0-9!#$%&\'*+\\/=?^_`{|}~]'; // caractères autorisés avant l'arobase $domain = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)'; // caractères autorisés après l'arobase (nom de domaine) $regex = '/^' . $atom . '+' . // Une ou plusieurs fois les caractères autorisés avant l'arobase '(\.' . $atom . '+)*' . // Suivis par zéro point ou plus séparés par des caractères autorisés avant l'arobase '@' . // Suivis d'un arobase '(' . $domain . '{1,63}\.)+' . // Suivis par 1 à 63 caractères autorisés pour le nom de domaine séparés par des points $domain . '{2,63}$/i'; // Suivi de 2 à 63 caractères autorisés pour le nom de domaine // test de l'adresse e-mail if (preg_match($regex, $email)) { return true; } else { return false; } } /**************************************************************************** ' Verifie l'authentificité d'un code postal ' @author GUILLEMETTE Anthony ' @email aguillem16 (arobase) gmail (point) com ' @date 29/04/2007 ' @param string codepo code postal a verifier ' @return boolean validité du code postal ****************************************************************************/ function validCodePostal($codepo) { $ereg = '([0-9]{5})'; // format d'un code postal // test du code postal if (ereg($regex, $email)) { return true; } else { return false; } } /**************************************************************************** ' Verifie la disponibilité d'un pseudo ' @author GUILLEMETTE Anthony ' @email aguillem16 (arobase) gmail (point) com ' @date 27/04/2007 ' @param string username pseudo a verifier ' @return boolean dispo disponibilité du pseudo ****************************************************************************/ function verifDispoUsername($username) { // tableau de données qui simule une table contenant des noms d'utilisateurs // dans un cas réel il y aurait vérification dans la base de données via une requete MySQL $pseudo_existant = array("aguillem", "zen", "audrey", "test", "stephane"); // verifie si le pseudo existe dans le tableau if (!in_array(strtolower($username), $pseudo_existant)) { $dispo = true; } else { $dispo = false; } return $dispo; } ?>
Attention : Dans notre exemple, nous n'utilisons pas de bases de données pour vérifier la disponibilité du nom d'utilisateur, mais un tableau de valeurs. Dans un cas concret, il faudrait certainement lancer une requête SQL, ce qui peut ouvrir des failles face à des attaques de type injection SQL. Un article entier étant nécessaire pour bien aborder ce sujet, je ne peux que vous conseiller d'aller vous renseigner par vous même sur le sujet ;)
Vérification coté client
Maintenant que la vérification coté serveur est effectuée, on peut rajouter des fonctionnalités pour faciliter la tâche de l'utilisateur. Il faut toujours garder à l'esprit que ces vérifications ne sont que des "plus", et ne doivent surtout pas être nécessaires.
Pour faciliter la saisie du formulaire au visiteur, éviter les appels serveurs et les rechargements de pages inutiles, nous allons créer des petites fonctions Javascript qui controleront les données. En plus, ça ajoutera un peu d'intéractivité dans la page. Concernant les éventuels messages d'erreur, nous préfèrerons les afficher dans une balise p prévu à cet effet plutôt que via des window.alert, qui peuvent etre très genant et énervant pour certains.
Nous allons tout d'abord vérifier les champs obligatoires, en récupérant le champ via la commande getElementById. Nous pourrons alors tester sa valeur et retourner le message correspondant. C'est ici que nous appellerons les fonctions qui vérifieront le niveau de sécurité du mot de passe et la validité de l'adresse email. Une autre fonction plus particulière, se chargera de faire un appel au serveur, grâce à la librairie XHRConnection, pour vérifier la disponibilité du nom d'utilisateur. Nous utiliserons le DOM pour intégrer le message d'erreur dans la page. Le fichier function.js contiendra les fonctions de vérifications Javascript ainsi que l'appel asynchrone au code PHP. Le fichier verifUsername.php sera appelé par l'appel asynchrone et vérifira la disponibilité du nom d'utilisateur et renverra le résultat via un fichier XML.
function.js
function init() {
// on recupere chaque champ a verifier
var username = document.getElementById('username');
var password = document.getElementById('password');
var email = document.getElementById('email');
// initialise l'appel aux fonctions pour chaque champ
// il y a des différences de traitement DOM entre IE et Firefox, notamment pour l'affectation d'évenement
// pour IE
if (window.attachEvent) {
username.onkeyup = function() { verifUsername(username); };
password.onkeyup = function() { verifPassword(password); };
email.onkeyup = function() { verifEmail(email); };
}
// pour Firefox
else {
username.setAttribute('onKeyUp', 'verifUsername(username)');
password.setAttribute('onKeyUp', 'verifPassword(password)');
email.setAttribute('onKeyUp', 'verifEmail(email)');
}
}
function verifUsername(username) {
var XHR = new XHRConnection();
XHR.appendData("username", username.value);
XHR.sendAndLoad("verifUsername.php", "POST", afficheDispo);
}
function verifPassword(password) {
motDePasse = password.value;
password_alert = document.getElementById('password_alert');
// suppression du texte existant
while(password_alert.firstChild != null) {
password_alert.removeChild(password_alert.firstChild);
}
// creation du message suivant le cas
if(motDePasse.length < 6) {
var texte = document.createTextNode("Niveau faible");
}
if(motDePasse.length >= 6 && motDePasse.length < 8) {
var texte = document.createTextNode("Niveau correct");
}
if(motDePasse.length >= 8) {
var texte = document.createTextNode("Niveau élevé");
}
password_alert.appendChild(texte);
}
function verifEmail(email) {
adresse = email.value;
email_alert = document.getElementById('email_alert');
// suppression du texte existant
while(email_alert.firstChild != null) {
email_alert.removeChild(email_alert.firstChild);
}
// creation du message suivant le cas
if (!checkEmail(adresse)) {
var texte = document.createTextNode("Adresse incorrecte");
email_alert.appendChild(texte);
} else {
var texte = document.createTextNode("Adresse correcte");
email_alert.appendChild(texte);
}
}
function checkEmail(email) {
var arobase = email.indexOf("@");
var point = email.lastIndexOf(".");
if((arobase < 3) || (point + 3 > email.length) || (point < arobase+3)) {
return false;
}
return true;
}
function afficheDispo(obj) {
username_alert = document.getElementById('username_alert');
// suppression du texte existant
while(username_alert.firstChild != null) {
username_alert.removeChild(username_alert.firstChild);
}
// Construction des noeuds
var tabResult = obj.responseXML.getElementsByTagName('resultat');
var resultat = tabResult.item(0);
var dispo = resultat.getAttribute('dispo');
// creation du message suivant le cas
if (dispo == "true") {
var texte = document.createTextNode("Le nom d'utilisateur est disponible");
username_alert.appendChild(texte);
} else {
if (dispo == "false") {
var texte = document.createTextNode("Le nom d'utilisateur n'est pas disponible");
username_alert.appendChild(texte);
}
}
}
verifUsername.php
<?php include("function.php"); // recupération du username $username = $_POST["username"]; // on verifie que le username est dispo if($username != "" && verifDispoUsername($username)) { $dispoUsername = "true"; } else { $dispoUsername = "false"; } // on cree une feuille xml header('Content-type: text/xml'); // on retourne le resultat sous format xml $xml = '<resultats>'; $xml .= '<resultat dispo="'.$dispoUsername.'" />'; $xml .= '</resultats>'; print $xml; ?>
Et voilà...
Nous avons donc là un formulaire suivant les bonnes pratiques générales de vérification des données, où nous essayons avant tout de faciliter l'utilisation pour l'internaute, tout en ne négligeant pas les non-utilisateurs de Javascript, et où nous évitons aussi les appels serveurs inutiles.
J'ai mis du temps à commencer ce tutoriel et surtout à le finir. Il se peut donc que les technologies et méthodes utilisées ne soient pas les plus optimales ou pratiques. Néanmoins, il démontre les bonnes pratiques à suivre pour faire un formulaire ergonomique et accessible et pour vérifier les données de manière optimale.
Et voici la démo et les sources du tutoriel...
Tags : ajax, bonnes pratiques, développement, ergonomie, formulaire, javascript, php, xhtml

Commentaires
#1 - Le 12 octobre 2007 à 09h42, par zEn
#2 - Le 12 octobre 2007 à 14h01, par Aguillem
#3 - Le 12 octobre 2007 à 17h29, par zEn
#4 - Le 25 janvier 2008 à 13h01, par Tid
#5 - Le 26 janvier 2008 à 21h21, par Aguillem
#6 - Le 08 mars 2008 à 10h17, par Arrangeur
#7 - Le 10 mars 2008 à 09h03, par Aguillem
#8 - Le 24 mars 2008 à 18h38, par Gobi
#9 - Le 05 juin 2008 à 21h27, par roblès
#10 - Le 12 août 2008 à 03h38, par soirée paris
#11 - Le 02 septembre 2008 à 16h43, par neang
Ajouter un commentaire
Les commentaires pour ce billet sont fermés.