Un formulaire PHP s'envoie au script qui l'a affiché : écrivez <form method="post"> avec des champs nommés, et quand $_SERVER['REQUEST_METHOD'] vaut 'POST', lisez chaque champ avec $_POST['name']. Échappez tout ce que vous réaffichez avec htmlspecialchars().
Exécutez ce bloc, tapez un nom dans le formulaire et cliquez sur Send : le même script s'exécute à nouveau, cette fois avec $_POST rempli.
Trois choses se passent ici, dont tout traitement de formulaire a besoin :
- La vérification de la méthode. À la première visite, la requête est un GET et il n'y a rien à traiter.
?? 'GET'ne compte que quand le fichier s'exécute en ligne de commande, oùREQUEST_METHODn'est pas défini ; sur un serveur web, il l'est toujours. ?? ''sur chaque champ. Un champ peut manquer (un champ renommé, une requête envoyée par un script), et lire une clé manquante affiche un warning.- L'échappement à l'affichage. Le nom revient deux fois dans la page, et
htmlspecialchars()garantit qu'une valeur comme<b>Ada</b>s'affiche en texte au lieu de devenir du balisage. Les détails sont sur la page htmlspecialchars.
Valider un formulaire et afficher les erreurs à côté des champs
Rassemblez les erreurs dans un tableau indexé par nom de champ. Si le tableau est vide, le formulaire est valide ; sinon, réaffichez le formulaire avec chaque message sous son champ et la saisie du visiteur toujours en place. Envoyez-le vide, puis avec un email invalide, puis avec des valeurs valides.
novalidate désactive les vérifications du navigateur pour que vous voyiez fonctionner celles de PHP. Gardez les deux dans un vrai formulaire : la validation du navigateur est un confort pour le visiteur, la validation PHP est celle qui compte, car n'importe qui peut envoyer une requête sans votre formulaire. filter_var() traite l'email et la plage d'entiers en un appel chacun ; la page filter_var présente ses autres filtres.
Cases à cocher, boutons radio et listes déroulantes
Un champ texte envoie toujours une valeur, même vide. Les autres contrôles non :
- Une case non cochée n'envoie rien du tout, sa clé manque donc dans
$_POST. - Des cases nommées
topics[]arrivent sous forme de tableau :$_POST['topics']vaut['php', 'sql']. - Un groupe radio ou un
<select>envoie lavaluede l'option choisie.
Pour garder le choix après l'envoi, affichez checked ou selected sur l'option qui correspond. Cochez quelques cases, choisissez un niveau et cliquez sur Save.
Les deux vérifications après la lecture de la saisie comptent plus qu'il n'y paraît. array_intersect() écarte tout sujet absent de votre liste, et la vérification is_string() plus array_key_exists() remet le niveau à une valeur par défaut si quelqu'un envoie une valeur que vous n'avez jamais proposée (ou un tableau, ce qui ferait lever une erreur à $levels[$level]). Une liste déroulante limite ce qu'un navigateur peut envoyer, pas ce qu'une requête peut contenir.
Formulaires en plusieurs étapes avec des champs cachés
Un champ caché transporte une valeur d'une étape à la suivante sans l'afficher. Ici, l'étape 1 demande un nom, l'étape 2 demande une langue et transmet le nom dans un champ caché, et l'étape 3 affiche les deux. Parcourez les trois étapes.
Les champs cachés sont visibles dans le code source de la page et modifiables comme n'importe quel champ, ils conviennent donc pour transporter les réponses du visiteur entre les étapes, mais jamais pour un prix, un identifiant d'utilisateur ou un rôle. Gardez ceux-là sur le serveur, dans une session ; voir sessions et cookies.
Post/Redirect/Get : éviter le renvoi à l'actualisation
Après un POST réussi, si le script affiche directement une page « merci », actualiser demande au navigateur de renvoyer le POST, et la commande ou le commentaire est enregistré deux fois. La solution est d'enregistrer, de rediriger, et d'afficher le résultat sur un GET :
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$errors = validate($_POST);
if (!$errors) {
save_comment($_POST);
$_SESSION['flash'] = 'Comment posted.';
header('Location: /comments.php', true, 303);
exit;
}
// On errors, fall through and print the form with the messages.
}
$flash = $_SESSION['flash'] ?? null;
unset($_SESSION['flash']);
303 See Other indique au navigateur de suivre la redirection avec un GET. Le exit après header() compte : sans lui, le reste du script continue de s'exécuter. La redirection doit aussi avoir lieu avant toute sortie, sinon PHP refuse avec « headers already sent ».
Les vrais formulaires ajoutent aussi un jeton CSRF : une valeur aléatoire stockée dans la session et dans un champ caché, comparée avec hash_equals() à l'envoi, pour qu'un autre site ne puisse pas envoyer votre formulaire au nom d'un visiteur connecté.
Tester la validation sans navigateur
Placez les règles dans une fonction qui prend un tableau et renvoie les erreurs. La page l'appelle avec $_POST, et vous pouvez l'appeler avec n'importe quel tableau, ce qui rend les cas limites faciles à essayer. Ajoutez vos propres cas à la liste.
Le quatrième cas est celui qu'on oublie. Une requête peut envoyer name[]=x, ce qui fait de $_POST['name'] un tableau, et passer un tableau à trim() lève une TypeError et arrête le script. Vérifier d'abord is_string() transforme une saisie hostile en erreur de validation ordinaire. Le cast (string) des blocs précédents évite aussi la TypeError, mais transforme le tableau en mot Array et affiche un warning, is_string() est donc la vérification la plus propre.
Erreur fréquente : lire $_POST avant l'envoi du formulaire
Le premier script de formulaire le plus courant lit les champs en haut du fichier :
<?php
$name = $_POST['name'];
echo "Hello, $name";
À la première visite, rien n'a été envoyé, donc PHP affiche :
Warning: Undefined array key "name" in /var/www/form.php on line 2
La solution est le modèle du premier bloc : ne traiter le formulaire que si la requête est un POST, et lire chaque champ avec une valeur par défaut, $_POST['name'] ?? ''. Si le warning apparaît après l'envoi, comparez l'attribut name du HTML avec la clé en PHP : name="Name" et $_POST['name'] sont des clés différentes.
Questions fréquentes
Comment envoyer un formulaire PHP sur la même page ?
Écrivez <form method="post"> sans action (ou avec action=""). Le navigateur renvoie la requête à l'URL courante, donc le même script affiche le formulaire et le traite : vérifiez $_SERVER['REQUEST_METHOD'] === 'POST' et lisez les champs dans $_POST.
Comment garder les valeurs d'un formulaire après l'envoi en PHP ?
Réaffichez la valeur envoyée dans le champ, échappée : <input name="email" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>">. Pour une case à cocher, affichez checked, et pour une option de liste, selected, quand la valeur envoyée correspond.
Comment obtenir les valeurs de plusieurs cases à cocher en PHP ?
Donnez aux cases à cocher le même nom terminé par des crochets, name="topics[]". PHP place alors les valeurs cochées dans un tableau, $_POST['topics']. Les cases non cochées n'envoient rien, utilisez donc $_POST['topics'] ?? [] et comparez chaque valeur à la liste que vous avez proposée.
Pourquoi actualiser la page renvoie-t-il mon formulaire PHP ?
La dernière requête était un POST, donc le navigateur la répète à l'actualisation. Après un envoi réussi, redirigez avec header('Location: /thanks.php'); exit; (le modèle Post/Redirect/Get). L'actualisation répète alors un GET sans conséquence.
Peut-on utiliser $_POST en toute sécurité en PHP ?
Non, chaque valeur de $_POST vient du visiteur et peut être n'importe quoi, y compris du HTML, du SQL ou un tableau là où vous attendiez une chaîne. Validez-la à l'entrée (filter_var, contrôles de longueur et listes de valeurs autorisées) et échappez-la à la sortie (htmlspecialchars pour le HTML, requêtes préparées pour le SQL).