Lesson 4/7 8 min

Forms and GET/POST

Retrieve data submitted by users through HTML forms and validate it server-side.

FR EN

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)
// 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 votre bouclier contre les attaques XSS (Cross-Site Scripting). Utilisez-le chaque fois que vous affichez 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)
// 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";
}
?>
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

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.
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

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 ?
Next step

A form captures data fine, but PHP forgets it the moment the next page loads. So how do you keep a visitor logged in from page to page? Off to sessions and cookies, the memory that survives a reload.

Lesson 5: Sessions and cookies →
Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement