Traitement des formulaires avec $_GET et $_POST

Rechercher
Boutique en ligne, solution e-commerce, script PHP et PERL : RAYNETTE

Traitement des formulaires avec $_GET et $_POST

  • Par Emacs
  • 24 commentaires
  • 149028 lectures
  • RSS -  Atom

Qui dit « site web dynamique » dit généralement « formulaires » et donc traitement de ces derniers. PHP a notamment été inventé pour ce type de tâche et c'est ce que nous allons étudier dans ce nouveau tutoriel. Nous apprendrons à exploiter les formulaires par le biais des tableaux superglobaux $_GET et $_POST. Nous déterminerons aussi la différence qui existe dans l'utilisation de chacun d'eux.

Remarques :

[1] Pour la suite du tutoriel, nous considèrerons que les bases concernant les formulaires HTML sont acquises. Nous n'aborderons que synthétiquement les points essentiels de ces derniers à savoir les noms, valeurs, enctypes et methodes.
[2] Par ailleurs nous considèrerons que tous les tutoriels précédents des bases de PHP sont compris et acquis.

Traitement PHP ou traitement Javascript ?

Il est bien évident que TOUS les formulaires doivent être traités en priorité avec PHP. Toutefois, rien n'empêche l'utilisation de Javascript en tant que surcouche au travail de PHP. Pourquoi PHP en priorité alors ? Il y'a plusieurs raisons à cela :

  • PHP est executé sur le serveur alors que Javascript est exécuté sur le client (navigateur). De ce fait, il peut-être désactivé ou non fonctionnel rendant les contrôles impossibles.
  • Etant exécuté sur le serveur, seul le programme peut agir sur les informations transmises. La sécurité est alors accrue par rapport aux contrôles côtés client.
  • PHP dispose d'une série de fonctions natives capables de manipuler les variables et de les contrôler.
  • La puissance des expressions régulières permet aussi de vérifier des formats de données personnalisés.

Remarque : dans la mesure où les informations proviennent de personnes anonymes, nous ne pouvons garantir la véracité et la dangerosité de ces dernières. C'est pourquoi tout doit être vérifié. Le principe numéro 1 lorsque l'on interagit avec un utilisateur est de ne jamais lui faire confiance.

Les parties essentielles d'un formulaire

Introduction

Afin de pouvoir faire dialoguer correctement un formulaire HTML avec un script PHP, il faut s'assurer que les points suivants soient présents :

  • L'attribut action de la balise <form> est renseigné par l'url du fichier PHP qui va recevoir les informations. Cela peut-être un fichier différent de la page courante mais il est conseillé de traiter les formulaires dans la même page.
  • La méthode HTTP (attribut method) du formulaire est renseignée par l'une de ces deux valeurs : get ou post.
  • Si l'on a affaire à un formulaire d'upload de fichiers, la balise <form> doit comporter l'attribut enctype et la valeur multipart/form-data.
  • Tous les éléments d'un formulaire doivent posséder un attribut name rempli par une valeur. Le nom du champ sera ensuite considéré par le script PHP comme une variable contenant la valeur saisie.

A titre d'information, voici un exemple tout simple de formulaire d'upload qui présente tous les éléments obligatoires évoqués ici.

Exemple de formulaire d'upload
<!-- Debut du formulaire -->
<form enctype="multipart/form-data" action="./upload.php" method="post">
<fieldset>
<legend>Formulaire</legend>
<p>
<label>Envoyer le fichier :</label>
<input name="fichier" type="file" />
<input type="submit" name="submit" value="Uploader" />
</p>
</fieldset>
</form>
<!-- Fin du formulaire -->

Détaillons ici les méthodes GET et POST. Quelle différence les sépare ? Pour laquelle opter ?

La méthode HTTP GET

La méthode GET (celle qui est utilisée par défaut si rien n'est renseigné) fait circuler les informations du formulaire en clair dans la barre d'adresse en suivant le format ci-après :

Exemple d'url créée à partir de la méthode GET d'un formulaire
http://www.unsite.com/chemin/scriptphp.php?var1=valeur1&var2=valeur2

Cette adresse signifie que nous allons transmettre à la page scriptphp.php les couples variable / valeur transmis en paramètre. La première variable d'une url est toujours précédée du symbôle ? alors que les autres seront précédées du symbôle &. Les noms des variables correspondent aux attributs name des éléments du formulaire et les valeurs aux attributs value.

Note : contrairement à ce que l'on peut lire fréquemment sur la toile, la limite maximale d'une URL n'est pas de 255 caractères. Il n'existe en réalité aucune limite standard. En effet, la taille maximale d'une URL peut-être configurée à la fois côté serveur ou côté client. Un administrateur de serveur web peut à sa guise augmenter ou diminuer la longueur maximale des URLs. Quant aux navigateurs, eux aussi fixent par défaut une taille maximale. Il est donc recommandé de ne pas abuser de la longueur d'une URL lorsque l'on ne maîtrise pas l'intégralité de son environnement de production (serveur Web et clients).

La méthode HTTP POST

La méthode POST, quant à elle, transmet les informations du formulaire de manière masquée mais non cryptée. Le fait de ne pas afficher les données ne signifie en rien qu'elles sont cryptées. Rappelons nous d'ailleurs que ces informations utilisent le protocole HTTP et non HTTPS qui lui crypte les données.

Quelle est la meilleure méthode à adopter alors ? Et bien la réponse est : « ça dépend ». Le choix de l'une ou de l'autre se fera en fonction du contexte. Si par exemple, nous souhaitons mettre en place un moteur de recherches alors nous pourrons nous contenter de la méthode GET qui transmettra les mots-clés dans l'url. Cela nous permettra aussi de fournir l'url de recherches à d'autres personnes. C'est typiquement le cas des URLs de Google :

Exemple d'une URL du moteur de recherches Google
http://www.google.fr/search?q=php

La méthode POST est préférée lorsqu'il y'a un nombre important de données à transmettre ou bien lorsqu'il faut envoyer des données sensibles comme des mots de passe. Dans certains cas, seule la méthode POST est requise : un upload de fichier par exemple.

Les tableaux superglobaux $_POST et $_GET

$_GET et $_POST sont des tableaux de données associatifs et superglobaux. Voici leurs principales caractéristiques :

  • Ils sont générés à la volée par PHP avant même que la première ligne du script ne soit exécuté.
  • Ce sont des tableaux associatifs comme ceux que l'on déclare traditionnellement. Leur manipulation est exactement semblable à ces derniers. Les clés correspondent aux noms des variables transmises et les valeurs à celles associées à ces variables.
  • Ils sont superglobaux, c'est à dire visibles de partout dans le programme (même à l'intérieur d'une fonction utilisateur).
  • Ils sont accessibles en lecture et en écriture. Il est donc possible de les modifier.

Le tableau $_GET contient tous les couples variable / valeur transmis dans l'url. Pour accéder à la valeur d'une variable dont le nom est prenom, on l'appelle ainsi :

Lecture d'une variable appartenant au tableau $_GET
<?php
echo $_GET['prenom'];
?>

Le tableau $_POST contient tous les couples variable / valeur transmis en POST, c'est à dire les informations qui ne proviennent ni de l'url, ni des cookies et ni des sessions. Pour accéder à la valeur d'une variables dont le nom est prenom, on l'appelle ainsi :

Lecture d'une variable appartenant au tableau $_POST
<?php
echo $_POST['prenom'];
?>

La casse des variables est importante. Il faut bien penser à mettre $_GET et $_POST en majuscules. Dans le cas contraire, il sera impossible d'obtenir une valeur et une erreur de type undefined variable sera retournée.

Note : il existe aussi le tableau associatif superglobal $_REQUEST qui regroupe les 3 tableaux $_GET, $_POST et $_COOKIE que nous verrons au prochain cours. Il fonctionne exactement comme tous les autres tableaux.

Exemple simple et concret de traitement de formulaire

Dans cette partie, nous allons utiliser un exemple simple de traitement de formulaire. Nous récupèrerons et vérifierons les données en provenance d'un formulaire d'authentification. Les principes de session seront évincés car ils ne constituent pas l'objet majeur du cours. Nous nous intéresserons uniquement à la saisie et la réception des données du formulaire.

Voici les pré-requis nécessaire à l'élaboration de notre exemple :

  • Un formulaire d'identification a besoin de deux éléments : un champ texte qui reçoit le login et un champ password qui reçoit le mot de passe du visiteur.
  • Nous traiterons les données dans la même page avant la première balise html du document. Notre formulaire devra donc s'appeller lui même.
  • Les identifiants de comparaison seront stockés dans deux constantes.
  • Les erreurs seront signalées à l'utilisateur.
  • Le login sera réaffiché dans le champ si l'utilisateur s'est trompé.
  • Si toutes les informations sont vérifiées, un message de réussite simulera l'ouverture de la session du membre.

Passons au script complet. Il est entièrement commenté donc seules quelques petites explications seront apportées ensuite :

Script complet d'identification : exemple de traitement de formulaire
<?php
/*****************************************
* Constantes et variables
*****************************************/
define('LOGIN','Rasmus'); // Login correct
define('PASSWORD','lerdorf'); // Mot de passe correct
$message = ''; // Message à afficher à l'utilisateur
/*****************************************
* Vérification du formulaire
*****************************************/
// Si le tableau $_POST existe alors le formulaire a été envoyé
if(!empty($_POST))
{
// Le login est-il rempli ?
if(empty($_POST['login']))
{
$message = 'Veuillez indiquer votre login svp !';
}
// Le mot de passe est-il rempli ?
elseif(empty($_POST['motDePasse']))
{
$message = 'Veuillez indiquer votre mot de passe svp !';
}
// Le login est-il correct ?
elseif($_POST['login'] !== LOGIN)
{
$message = 'Votre login est faux !';
}
// Le mot de passe est-il correct ?
elseif($_POST['motDePasse'] !== PASSWORD)
{
$message = 'Votre mot de passe est faux !';
}
else
{
// L'identification a réussi
$message = 'Bienvenue '. LOGIN .' !';
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" >
<head>
<title>Formulaire d'identification</title>
</head>
<body>
<?php if(!empty($message)) : ?>
<p><?php echo $message; ?></p>
<?php endif; ?>
<form action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES); ?>" method="post">
<fieldset>
<legend>Identifiant</legend>
<p>
<label for="login">Login :</label>
<input type="text" name="login" id="login" value="<?php if(!empty($_POST['login'])) { echo htmlspecialchars($_POST['login'], ENT_QUOTES); } ?>" />
</p>
<p>
<label for="password">Mot de passe :</label>
<input type="password" name="motDePasse" id="password" value="" />
<input type="submit" name="submit" value="Identification" />
</p>
</fieldset>
</form>
</body>
</html>

D'un point de vue général, nous avons structuré la page de cette façon :

  1. Déclaration des constantes et variables.
  2. Traitement des données.
  3. Présentation des données

Ce schéma de conception fait partie des bonnes pratiques de développement à adopter. On traite toujours les informations avant de les présenter. Avec cette méthode, nous pourrons par exemple effectuer des redirections sans risque d'erreur d'entêtes déjà envoyés.

Quelques lignes du code méritent tout de même des explications :

La première condition vérifie que le tableau $_POST existe et n'est pas vide. Si c'est le cas, alors elle renverra vrai (TRUE) et sera franchie pour accéder aux tests suivants.

On effectue ensuite une série de tests pour contrôler que les champs du formulaire ont bien été remplis et que les valeurs transmises correspondent aux constantes définies en tête du fichier. La fonction empty() vérifie que la variable passée en paramètre existe et qu'elle est vide ou nulle. Si l'on détecte une erreur, on l'enregistre dans la variable $message.

Si aucune erreur n'est détectée, cela signifie que les idenfiants sont corrects. On entre alors dans la clause else. Pour information, nous aurions du, en réalité, ouvrir une session et rediriger l'utilisateur vers la page protégée.

Dans le corps de la page, nous ajoutons une condition qui vérifie si la variable $message existe et qu'elle est bien remplie. Si c'est le cas, on franchit la condition et l'on affiche le message dans un bloc de paragraphe HTML.

La fonction htmlspecialchars() protège les variables en transformant les chevrons (< et >) et certains caractères HTML en entités HTML équivalentes. On utilise cette fonction pour se protéger d'éventuels actes de piratage par injection de code Javascript ou HTML (attaques de Cross Site Scripting ou XSS).

Nous appelons la variable d'environnement $_SERVER['REQUEST_URI'] qui contient l'url qui mène jusqu'à la page courante. Grâce à elle, nous précisons que le fichier qui va recevoir les données est lui même. Il est nécessaire de protéger cette variable car elle est sensible au piratage par injection de code HTML.

Enfin, dans l'attribut value du champ texte login, nous replaçons la dernière valeur postée par l'utilisateur. On la protège aussi car si le visiteur poste du code html, celui-ci sera directement interprêté. Il faut donc s'assurer de la sécurité de la variable que l'on souhaite réafficher.

Un mot sur les apostrophes magiques

Si la directive magic_quotes_gpc (GPC pour GET / POST et COOKIE) du php.ini est activée sur le serveur web, alors PHP va automatiquement protéger les chaînes en échappant par un antislash certains caractères spéciaux (apostrophes, guillemets...). Si par exemple nous postons la chaîne L'école est finie alors nous obtiendrons le résultat suivant :

Résultat d'une chaine de caractères échappée automatiquement
L\'école est finie

Cette protection agit donc comme la fonction addslashes(). L'antislash protège ici l'apostrophe. Ce caractère peut-être dangereux dans une requête SQL s'il n'est pas échappé. On parle de risque de piratage par injection de code SQL. Il faut alors faire attention à ne pas échapper une nouvelle fois les données avec cette fonction si les apostrophes magiques sont activées car les antislashes seraient alors eux aussi échapper par d'autres antislashes. Notre exemple précédent pourrait alors ressembler à cela si l'on échappe les données plusieurs fois :

Résultat d'une chaine de caractères échappée automatiquement
L\\\\\\\\\'école est finie

Cette initiative de protection a suscité de nombreux débats dans la communauté PHP car elle était en effet prévue pour combler les trous de sécurité créés par des programmeurs débutants et peu soucieux de la sécurité. Le passage à PHP 6 entraînera la désactivation de cette directive, ce qui forcera les développeurs à protéger eux mêmes leurs applications.

Nous recommandons de désactiver cette directive soit directement dans le php.ini si l'on a la main mise sur le serveur web ou bien en ajoutant cette ligne en haut de chacune des pages PHP :

Configuration temporaire du serveur web
<?php
// Désactivation des magic_quotes_gpc
ini_set('magic_quotes_gpc', 0);
?>

Conclusion

Nous sommes arrivés au terme de ce tutoriel. Nous avons tout d'abord démontré en quoi PHP devait être utilisé en priorité par rapport à Javascript pour traiter les formulaires. Puis, nous avons déterminé les éléments essentiels d'un formulaire HTML qui permettent un traitement par un script PHP. Dans cette lancée, nous avons expliqué les caractéristiques de chacune des deux méthodes HTTP GET et POST. Nous nous sommes ensuite arrêtés sur les tableaux superglobaux $_GET, $_POST et $_REQUEST qui permettent de récupérer les informations issues d'un formulaire ou d'une URL. Nous avons d'ailleurs illustré leur emploi au moyen d'un exemple de script réel modélisant un système d'identification, avant de conclure sur des principes de sécurité tels que les failles par injection de code HTML ou Javascript (XSS) et l'injection de commandes SQL.



Les commentaires

1. Par bertrand le 28/10/2007 18:23

ce tutorial est un petit chef d'oeuvre car il resume toutes les failles que le debutant devra eviter et donc je lui donne la meilleur note possible. medaille assurée au Jo

2. Par Emacs le 28/10/2007 22:02

Merci beaucoup Bertrand. C'est aussi notre objectif de sensibiliser le développeur aux soucis liés à la sécurité. C'est pourquoi nous en parlons brièvement dans ce tutoriel

3. Par saturn2 le 28/12/2007 12:48

Bon tutos clair et précis

4. Par algeo le 11/02/2008 17:10

formulaire d'upload? est ce que tu peux preciser de quoi il s'agit stp.

5. Par Chrisvip le 11/02/2008 18:17

Emacs -> C'est caractères et pas caracères

6. Par Emacs le 11/02/2008 21:39

@algeo : que veux-tu savoir ?
@Chrisvip : thanks je corrige ces malheureux copiés / collés

7. Par algeo le 12/02/2008 14:38

c'est le mot upload que je ne saisie pas.

8. Par Emacs le 12/02/2008 21:10

Upload = transfert d'un fichier depuis ton poste vers le serveur web

9. Par Altidor Evans le 26/03/2008 17:25

Ce tutorial est vraiment intéressant pour moi, c’est un petit chef d’œuvre.
Mais j’aimerais savoir si je veux en dessus de chaque champ afficher le message correspondant.
Merci !

10. Par Emacs le 26/03/2008 19:42

Merci Altidor Evans pour ton commentaire. Si tu veux faire ça, tu devras tester individuellement chaque champ et stocker les messages d'erreurs dans un tableau associatif. Par exemple :

$erreurs['nom_du_champ'] = 'Erreur pour ce champ';

++

Hugo.

11. Par bibi le 30/04/2008 13:36

C'est très bien fait, il manque juste un point sur lequel je bloque :
php semble poser probleme si le nom des champs contient des . ou des [].

En effet, dans le 1er cas, il transform les . en _
Dans le 2me cas, tout ce qui se trouve apres un ] si ce n'est pas un [ alors c'est ignoré aussi.
Pouvez-vous m'en dire plus ?
Petite explication de l'utilisation :
c'est un formulaire qui a été créé en JAVA et dont je récup les champs. En java le . représente un attribut de la classe et le [] un tableau.

Une classe maclasse ayant pour attribut :
mavar => string
montab => array
ca donne :
name="maclasse.mavar"
name="maclasse.montab[0].monautrevar.var.var.var.tabvar[0].var"
....

12. Par Emacs le 30/04/2008 14:33

@Bibi : en php les nom des champs deviennent des noms de variables. Or il ne peut y'avoir des points dans les noms de variable. D'où le fait que tu ne puisses pas utiliser le point dans les noms de tes champs.

Concernant les crochets, PHP les accepte. Si j'ai plusieurs checkboxes dont le nom est "produits[]" et la valeur l'id du produit par exemple, alors je récupèrerai en sortie un tableau indexé numériquement dans la variable $_POST['produits']. Si tu exécutes ces 3 lignes de code quand tu postes le formulaire, tu verras bien un tableau avec des identifiants :

<?php
echo '<pre>';
var_dump($_POST['produits']);
echo '</pre>';
?>

++

13. Par Emacs le 30/04/2008 14:37

@Bibi (encore) : en PHP (et en Java aussi je pense), on ne peut pas transmettre d'objet d'une page à une autre par un formulaire. Le seul moyen d'y parvenir c'est de le sérialiser (fonction serialize()) dans un champ caché puis de le désérialiser de l'autre côté (fonction unserialize()).

++

14. Par popp le 12/05/2008 16:41

interressant ton dvpt

15. Par Paul le 17/11/2008 15:09

Bonjour, très bon tutoriel. Je ne comprend pas pourquoi il faut placer la fonction htmlspecialchars() pour l'affichage du message d'erreur. En fait, je ne vois pas comment on pourrait y injecter du code car le message est pré-programmé. Merci de votre aide.

16. Par Emacs le 17/11/2008 21:30

Effectivement dans ce cas là ce n'est pas nécessaire. Je vais mettre le tutoriel à jour tout de suite

17. Par Yann le 27/11/2008 17:54

Dans le paragraphe d'intro: c'est "la différence QUI existe" et non " la différence qu'il existe "
Merci beaucoup pour le tutorial

18. Par Emacs le 27/11/2008 20:50

Merci Yann j'ai corrigé cette faute et ainsi que d'autres en repassant tout le tutoriel en revue

19. Par frame1 le 20/01/2009 16:09

c tres interessant merci

20. Par bilgo le 07/05/2009 16:01

Bonjour,

Votre tutoriel a résolu presque tous mes problèmes en matière de $_GET et $_POST. Merci. Je garde ce site comme référence première.

21. Par Noobix le 26/05/2009 17:17

Bonjour Emacs.

Tout d'abord félicitation pour tes tutos qui sont de très bonnes qualités.

J'aurai cependant 2 petites questions.


1°) Dans ton exemple tu utilise

endif;

Je voulais connaitre les raisons de cette utilisation car c'est la première fois que je la vois et même sur http://fr.php.net/manual/fr/control-structures.if.php

Il n'est pas indiqué que l'on puisse utiliser le endif.

2°) Quels est la différence en empty et isset, laquel utiliser.

Merci encore pour ce tutos

Cordialement Noobix

22. Par alll le 11/06/2009 16:37

Bonjour,
j'ai un petit pb,
j'ai une liste deroulante que me donne le nom-prenom que j'ai recuperer ds la table eleve et je veux l'enregistrer ds ma table pret mais sa ne marche pas .
svp est ce je peux avoir votre aide .
Cordialemnt,

23. Par Amine14 le 10/07/2009 08:57

c'est bien comme tutoriel, en fait j'ai pas tout compris (c'est normal je suis encore débutant )mais bon, je vous remercie
et puisque votre site prend le nom "Apprendre php", j'ai une question (concernant les variables) à vous demander, si c'est possible
Ma question : comment ajouter ou modifier une variable, mais avant, comment créer une table? -j'ai Wamp- (gardez l'esprit que je suis débutant et Merci! lol)

24. Par denami.infox le 16/08/2009 17:06

Bonjour,
j'ai besoin de votre aide s'il vous plait, depuis presque 2 jours j'essaye d'utiliser une variable $_post pour faire un update sur ma base de données mais la requête ne s'exécute pas comme je le veux,le champs pour lequel j'ai effectué l'update devient vide.