Leçon 5/8 8 min

Formulaires et GET/POST

Récupérez les données envoyées par vos utilisateurs via des formulaires HTML et validez-les côté serveur.

Du formulaire HTML au traitement PHP

Voici le flux complet quand un utilisateur soumet un formulaire :

  1. L'utilisateur remplit le formulaire HTML et clique sur « Envoyer »
  2. Le navigateur envoie les données au serveur (via GET ou POST)
  3. PHP récupère les données dans $_GET ou $_POST
  4. PHP traite, valide et répond
<!-- Le formulaire HTML -->
<form action="traitement.php" method="POST">
    <label>Votre nom :</label>
    <input type="text" name="nom">

    <label>Votre email :</label>
    <input type="email" name="email">

    <button type="submit">Envoyer</button>
</form>
// traitement.php
$nom = $_POST['nom'];
$email = $_POST['email'];
echo "Merci $nom, nous vous contacterons à $email.";

D'abord : les superglobales

Avant de parler de GET et POST, il faut connaître la famille à laquelle ils appartiennent : les superglobales. Ce sont des tableaux que PHP remplit tout seul à chaque requête, et qui sont accessibles partout dans ton code (même à l'intérieur d'une fonction, sans avoir à écrire global). C'est par elles que les données du monde extérieur (le navigateur, le serveur) entrent dans ton programme.

Les principales :

  • $_GET : les données passées dans l'URL (après le ?).
  • $_POST : les données envoyées dans le corps d'une requête POST (formulaires).
  • $_REQUEST : un mélange de $_GET, $_POST et $_COOKIE. Pratique mais ambigu : mieux vaut viser directement le bon tableau.
  • $_SERVER : des infos sur la requête et le serveur (méthode HTTP, URL, en-têtes, IP du visiteur…).
  • $_SESSION : les données mémorisées entre les pages pour un visiteur (panier, connexion).
  • $_COOKIE : les cookies renvoyés par le navigateur.
  • $_FILES : les fichiers envoyés (upload).
  • $_ENV : les variables d'environnement du serveur.
  • $GLOBALS : toutes les variables globales du script.

On s'en sert comme de n'importe quel tableau associatif : $_POST['email'], $_SERVER['REQUEST_METHOD'], $_SESSION['user']. Pas besoin de les déclarer ni de les importer : elles sont toujours là.

Celles qui transportent des données venues du visiteur ($_GET, $_POST, $_REQUEST, $_COOKIE, $_FILES) ne sont jamais fiables : n'importe qui peut envoyer n'importe quoi. On valide systématiquement à l'entrée et on échappe à l'affichage (on y revient plus bas). À l'inverse, $_SESSION vit côté serveur : elle, on la contrôle.

Les deux que tu croiseras le plus, et de loin, ce sont $_GET et $_POST. Regardons-les de près.

$_GET vs $_POST

Les deux méthodes pour envoyer des données :

  • GET : données visibles dans l'URL : page.php?q=php&page=2
  • POST : données invisibles (dans le corps de la requête)
Prédisez avant de lire

Un formulaire de connexion envoie un identifiant et un mot de passe. Avant de dérouler : quelle est la vraie différence entre envoyer ces champs en $_GET et en $_POST ? Où se retrouvent les données dans chaque cas ? Et peut-on dire que $_POST est « sécurisé » parce que les données ne sont pas dans l'URL ?

Voir la réponse

Avec GET, les données sont collées dans l'URL (?login=alice&pwd=…) : visibles dans la barre d'adresse, enregistrées dans l'historique du navigateur et les logs serveur, mémorisables en favori, et de taille limitée. Avec POST, elles voyagent dans le corps de la requête, donc absentes de l'URL. Mais attention : POST n'est pas « sécurisé » pour autant. Le corps d'une requête POST circule en clair, tout aussi lisible et modifiable par l'utilisateur (via les outils du navigateur ou un proxy). Seul HTTPS chiffre la communication. La règle : GET pour récupérer ou naviguer (recherche, filtre, lien partageable), POST pour les actions qui changent l'état (créer, modifier, envoyer un formulaire) ; et ne jamais faire confiance à l'un ni à l'autre : toute donnée venant du client doit être validée côté serveur.

// GET : pour les recherches, filtres, pagination
// URL : recherche.php?q=php&page=2
$recherche = $_GET['q'];      // "php"
$page = $_GET['page'];        // "2"

// POST : pour les formulaires sensibles (login, contact, paiement)
$email = $_POST['email'];
$password = $_POST['password'];

Règle : utilisez POST pour tout ce qui modifie des données ou contient des informations sensibles. GET uniquement pour lire/rechercher.

Validation des données

Règle d'or : ne jamais faire confiance aux données utilisateur. Un utilisateur (ou un bot) peut envoyer n'importe quoi.

// Vérifier que le champ existe et n'est pas vide
if (empty($_POST['nom'])) {
    $erreur = "Le nom est obligatoire.";
}

// Valider un email
$email = $_POST['email'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $erreur = "Email invalide.";
}

// Nettoyer les données contre le XSS
$nom = htmlspecialchars($_POST['nom'], ENT_QUOTES, 'UTF-8');
// Transforme <script>alert('hack')</script>
// en &lt;script&gt;alert('hack')&lt;/script&gt;

htmlspecialchars() est ton bouclier contre les attaques XSS (Cross-Site Scripting). Utilise-le chaque fois que tu affiches des données saisies par un utilisateur.

Exemple complet : formulaire de contact

<?php
$erreurs = [];
$succes = false;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 1. Récupérer et nettoyer
    $nom   = htmlspecialchars(trim($_POST['nom'] ?? ''), ENT_QUOTES, 'UTF-8');
    $email = trim($_POST['email'] ?? '');
    $msg   = htmlspecialchars(trim($_POST['message'] ?? ''), ENT_QUOTES, 'UTF-8');

    // 2. Valider
    if (empty($nom))   $erreurs[] = "Le nom est obligatoire.";
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $erreurs[] = "Email invalide.";
    if (strlen($msg) < 10) $erreurs[] = "Message trop court (min 10 caractères).";

    // 3. Traiter si pas d'erreurs
    if (empty($erreurs)) {
        // Envoyer un email, sauvegarder en BDD, etc.
        $succes = true;
    }
}
?>

<?php if ($succes): ?>
    <p class="success">Merci <?= $nom ?>, message envoyé !</p>
<?php else: ?>
    <?php foreach ($erreurs as $e): ?>
        <p class="error"><?= $e ?></p>
    <?php endforeach; ?>

    <form method="POST">
        <input name="nom" value="<?= $nom ?? '' ?>" placeholder="Nom">
        <input name="email" value="<?= $email ?? '' ?>" placeholder="Email">
        <textarea name="message"><?= $msg ?? '' ?></textarea>
        <button>Envoyer</button>
    </form>
<?php endif; ?>

Sécurité : ne jamais faire confiance

Résumé des bonnes pratiques :

  • htmlspecialchars() : contre le XSS, à chaque affichage
  • filter_var() : pour valider emails, URLs, nombres
  • trim() : supprimer les espaces parasites
  • empty() : vérifier qu'un champ n'est pas vide
  • Requêtes préparées : contre l'injection SQL (leçon 6)

From HTML form to PHP processing

Here's the full flow when a user submits a form:

  1. The user fills in the HTML form and clicks "Submit"
  2. The browser sends the data to the server (via GET or POST)
  3. PHP retrieves the data in $_GET or $_POST
  4. PHP processes, validates and responds
<!-- The HTML form -->
<form action="process.php" method="POST">
    <label>Your name:</label>
    <input type="text" name="name">

    <label>Your email:</label>
    <input type="email" name="email">

    <button type="submit">Submit</button>
</form>
// process.php
$name = $_POST['name'];
$email = $_POST['email'];
echo "Thanks $name, we'll contact you at $email.";

First: the superglobals

Before talking about GET and POST, you need to know the family they belong to: the superglobals. These are arrays that PHP fills automatically on every request, and that are accessible everywhere in your code (even inside a function, without writing global). They're how data from the outside world (the browser, the server) enters your program.

The main ones:

  • $_GET — data passed in the URL (after the ?).
  • $_POST — data sent in the body of a POST request (forms).
  • $_REQUEST — a mix of $_GET, $_POST and $_COOKIE. Handy but ambiguous: better to target the right array directly.
  • $_SERVER — info about the request and the server (HTTP method, URL, headers, visitor IP…).
  • $_SESSION — data remembered across pages for a visitor (cart, login).
  • $_COOKIE — the cookies sent back by the browser.
  • $_FILES — the files uploaded.
  • $_ENV — the server's environment variables.
  • $GLOBALSall the script's global variables.

You use them like any associative array: $_POST['email'], $_SERVER['REQUEST_METHOD'], $_SESSION['user']. No need to declare or import them: they're always there.

The ones carrying data from the visitor ($_GET, $_POST, $_REQUEST, $_COOKIE, $_FILES) are never trustworthy: anyone can send anything. You validate systematically on the way in and escape on the way out (more below). Conversely, $_SESSION lives on the server: that one you control.

The two you'll meet by far the most are $_GET and $_POST. Let's look at them closely.

$_GET vs $_POST

Two methods to send data:

  • GET — data visible in the URL: page.php?q=php&page=2
  • POST — data invisible (in the request body)
Predict before reading

A login form sends a username and a password. Before scrolling down: what is the real difference between sending those fields via $_GET and via $_POST? Where does the data end up in each case? And can you say that $_POST is "secure" because the data is not in the URL?

See the answer

With GET, the data is appended to the URL (?login=alice&pwd=…): visible in the address bar, recorded in the browser history and server logs, bookmarkable, and size-limited. With POST, it travels in the request body, so it is absent from the URL. But beware: POST is not “secure” for that reason. The body of a POST request travels in plain text, just as readable and modifiable by the user (via browser dev tools or a proxy). Only HTTPS encrypts the communication. The rule: GET for retrieving or navigating (search, filter, shareable link), POST for actions that change state (create, modify, submit a form); and never trust either one: any data coming from the client must be validated server-side.

// GET — for searches, filters, pagination
// URL: search.php?q=php&page=2
$search = $_GET['q'];      // "php"
$page = $_GET['page'];     // "2"

// POST — for sensitive forms (login, contact, payment)
$email = $_POST['email'];
$password = $_POST['password'];

Rule: use POST for anything that modifies data or contains sensitive info. GET only for reading/searching.

Data validation

Golden rule: never trust user data. A user (or a bot) can send anything.

// Check that the field exists and isn't empty
if (empty($_POST['name'])) {
    $error = "Name is required.";
}

// Validate an email
$email = $_POST['email'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $error = "Invalid email.";
}

// Sanitize data against XSS
$name = htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8');
// Transforms <script>alert('hack')</script>
// into &lt;script&gt;alert('hack')&lt;/script&gt;

htmlspecialchars() is your shield against XSS attacks (Cross-Site Scripting). Use it every time you display user-entered data.

Complete example: contact form

<?php
$errors = [];
$success = false;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 1. Retrieve and sanitize
    $name  = htmlspecialchars(trim($_POST['name'] ?? ''), ENT_QUOTES, 'UTF-8');
    $email = trim($_POST['email'] ?? '');
    $msg   = htmlspecialchars(trim($_POST['message'] ?? ''), ENT_QUOTES, 'UTF-8');

    // 2. Validate
    if (empty($name))  $errors[] = "Name is required.";
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = "Invalid email.";
    if (strlen($msg) < 10) $errors[] = "Message too short (min 10 characters).";

    // 3. Process if no errors
    if (empty($errors)) {
        // Send email, save to DB, etc.
        $success = true;
    }
}
?>

<?php if ($success): ?>
    <p class="success">Thanks <?= $name ?>, message sent!</p>
<?php else: ?>
    <?php foreach ($errors as $e): ?>
        <p class="error"><?= $e ?></p>
    <?php endforeach; ?>

    <form method="POST">
        <input name="name" value="<?= $name ?? '' ?>" placeholder="Name">
        <input name="email" value="<?= $email ?? '' ?>" placeholder="Email">
        <textarea name="message"><?= $msg ?? '' ?></textarea>
        <button>Submit</button>
    </form>
<?php endif; ?>

Security: never trust input

Summary of best practices:

  • htmlspecialchars() — against XSS, on every output
  • filter_var() — to validate emails, URLs, numbers
  • trim() — remove trailing whitespace
  • empty() — check that a field is not empty
  • Prepared statements — against SQL injection (lesson 6)

À vous d'essayer (vrai PHP)

On simule un envoi de formulaire avec un tableau $donnees (comme $_POST), on valide, puis on affiche en sécurisant avec htmlspecialchars. Modifie les données, puis clique sur « Run » :

<?php
// En vrai, ces données viendraient de $_POST. On les simule ici.
$donnees = [
    'nom'   => 'Alice',
    'email' => 'alice@exemple.fr',
];

$erreurs = [];

// Validation
$nom   = trim($donnees['nom'] ?? '');
$email = trim($donnees['email'] ?? '');

if ($nom === '')                                     $erreurs[] = "Le nom est obligatoire.";
if (!filter_var($email, FILTER_VALIDATE_EMAIL))      $erreurs[] = "Email invalide.";

// Résultat
if ($erreurs) {
    foreach ($erreurs as $erreur) {
        echo "Erreur : $erreur\n";
    }
} else {
    echo "Merci $nom ! Message envoyé à $email.\n";

    // Et SI on réaffiche un nom dans une PAGE HTML, on l'échappe (anti-XSS).
    // htmlspecialchars transforme les balises en texte inoffensif :
    $dangereux = 'Bob <script>alert(1)</script>';
    echo "\nÉchappé pour le HTML : " . htmlspecialchars($dangereux, ENT_QUOTES, 'UTF-8') . "\n";
}
?>

🎯 Pratique

S'entraîner (clique pour ouvrir) :

Prompt IA
Avec l'IA

Copiez ce prompt dans Claude ou ChatGPT :

Crée un formulaire d'inscription PHP complet avec validation : nom, email, mot de passe (min 8 caractères), confirmation du mot de passe. Affiche les erreurs au-dessus du formulaire et pré-remplit les champs en cas d'erreur.
💬 Ré-explique sans regarder
Ré-explique sans regarder

L'IA t'a écrit un formulaire d'inscription avec validation. Sans le relire : pourquoi faut-il valider en PHP côté serveur alors que le navigateur fait déjà des vérifications (required, type="email") ?

Une bonne explication dit : les vérifications du navigateur sont du confort, pas une barrière. N'importe qui peut contourner le HTML (désactiver le JS, modifier la page, ou envoyer la requête à la main avec curl ou Postman) et viser directement ton traitement.php. Le serveur est le seul endroit que l'attaquant ne contrôle pas : c'est donc le seul endroit où la validation est réelle. filter_var(..., FILTER_VALIDATE_EMAIL) et empty() côté PHP sont la vraie barrière ; le HTML n'est qu'une aide pour l'utilisateur honnête.
⚖️ Juge le code de l'IA
Accepter ou rejeter le code de l'IA

L'IA te propose ce traitement de recherche. Ton rôle de relecteur : l'accepter tel quel ou le rejeter, et dire pourquoi.

<?php
$q = $_GET['q'];
echo "<h1>Résultats pour : $q</h1>";
?>
À rejeter : faille XSS. $_GET['q'] vient du visiteur et est réaffiché tel quel dans le HTML. Une URL comme ?q=<script>…</script> exécuterait le script dans le navigateur de la victime. Le réflexe pro : échapper à l'affichage avec htmlspecialchars($q, ENT_QUOTES, 'UTF-8'), et au passage gérer le cas où q n'existe pas ($_GET['q'] ?? '') pour éviter le warning. Le code « marche » sur un test gentil, mais il est exploitable : c'est exactement le genre de ligne qu'il ne faut jamais laisser passer.
🧠 Rappel libre
Rappel libre

Sans remonter dans la leçon : quand choisis-tu $_POST plutôt que $_GET, et à quoi sert htmlspecialchars() ?

$_GET met les données dans l'URL (recherches, filtres, pagination : rien de sensible, c'est partageable et mis en cache). $_POST les met dans le corps de la requête : on l'utilise dès qu'on modifie des données ou qu'il y a du sensible (login, contact, paiement). htmlspecialchars() transforme les caractères HTML (<, >, ", &) en entités : c'est le bouclier anti-XSS, à appliquer à chaque fois qu'on réaffiche une donnée venue de l'utilisateur.
Quelle méthode HTTP utiliser pour un formulaire de login ?
Quelle fonction PHP protège contre les attaques XSS ?
Que contient $_GET pour l'URL page.php?id=42 ?
Quelle est la première chose à faire avec les données d'un formulaire ?
Prochaine étape

Un formulaire récupère bien une donnée, mais PHP l'oublie dès la page suivante. Comment garder un visiteur connecté de page en page ? Direction les sessions et les cookies, la mémoire qui survit au rechargement.

Leçon 6 : Sessions et cookies →

Une erreur dans cette leçon, un passage flou, une question ? Écrivez-moi : chaque retour améliore ce cours.

Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement