Le problème : HTTP est sans mémoire
Chaque requête HTTP est indépendante. Le serveur ne sait pas que la personne qui visite la page 2 est la même que celle qui était sur la page 1. C'est comme si chaque fois que vous ouvriez une porte dans le bâtiment, la plomberie oubliait qui vous êtes.
Les sessions et les cookies résolvent ce problème en créant une mémoire entre les pages.
Les sessions : mémoire côté serveur
Une session stocke des données sur le serveur, liées à un visiteur via un identifiant unique :
// TOUJOURS en première ligne du fichier (avant tout HTML)
session_start();
// Stocker des données
$_SESSION['utilisateur'] = 'Alice';
$_SESSION['role'] = 'admin';
$_SESSION['connecte'] = true;
// Lire des données (sur une autre page)
session_start();
echo $_SESSION['utilisateur']; // → Alice
// Supprimer une donnée
unset($_SESSION['role']);
// Détruire toute la session (déconnexion)
session_destroy();
Important : session_start() doit être appelé avant tout output HTML, sinon PHP affiche une erreur « headers already sent ».
Sous le capot : où vivent les données ?
Un serveur, c'est une machine (souvent distante) qui fait tourner PHP et qui peut écrire des fichiers. Quand tu appelles session_start(), voici ce qui se passe vraiment :
- Au premier passage, PHP génère un identifiant unique (ex.
PHPSESSID = a1b2c3…) et crée un fichier sur le serveur pour ce visiteur (typiquement/tmp/sess_a1b2c3…, ou une entrée en base de données). - Il renvoie cet identifiant au navigateur dans un cookie. C'est la seule chose qui voyage : pas tes données, juste l'étiquette.
- À chaque requête suivante, le navigateur renvoie automatiquement ce cookie. PHP lit l'ID, ouvre le bon fichier, et remplit
$_SESSIONavec son contenu.
D'où deux choses que tu n'as plus besoin d'apprendre par cœur : tu les retrouves par la logique.
- « headers already sent » : déposer le cookie de session est un en-tête HTTP, et les en-têtes partent avant le contenu de la page. Donc
session_start()doit s'exécuter avant le moindre caractère de HTML (même un espace ou une ligne vide avant<?php). - L'expiration : comme les fichiers de session s'accumulent, le serveur les nettoie régulièrement. Une session inactive finit donc par disparaître, c'est normal.
Les cookies : mémoire côté navigateur
Un cookie est un petit fichier stocké dans le navigateur de l'utilisateur :
// Créer un cookie (expire dans 30 jours)
setcookie("theme", "dark", time() + (30 * 24 * 3600), "/");
// Lire un cookie
$theme = $_COOKIE['theme'] ?? 'light';
echo "Thème actuel : $theme";
// Supprimer un cookie (date dans le passé)
setcookie("theme", "", time() - 3600, "/");
Sessions vs Cookies :
- Session : données sur le serveur, disparaît à la fermeture du navigateur
- Cookie : données sur le navigateur, peut durer des jours/mois
Règle : les données sensibles (login, rôle, ID) vont en session. Les préférences (thème, langue) vont en cookie.
Exemple : flux de connexion
// login.php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
// Vérifier en base de données (simplifié ici)
if ($email === 'alice@exemple.fr' && password_verify($password, $hash_stocke)) {
// Connexion réussie
$_SESSION['user_id'] = 42;
$_SESSION['user_nom'] = 'Alice';
session_regenerate_id(true); // Sécurité !
header('Location: /dashboard.php');
exit;
} else {
$erreur = "Email ou mot de passe incorrect.";
}
}
// dashboard.php
session_start();
if (empty($_SESSION['user_id'])) {
header('Location: /login.php');
exit;
}
echo "Bienvenue, " . htmlspecialchars($_SESSION['user_nom']);
// logout.php
session_start();
$_SESSION = [];
session_destroy();
header('Location: /login.php');
Sécurité des sessions
session_regenerate_id(true): après le login, pour éviter le « session fixation »- Cookies HttpOnly : empêche JavaScript d'accéder au cookie de session
- Cookies Secure : le cookie n'est envoyé qu'en HTTPS
- SameSite=Strict : protège contre les attaques CSRF
// Configuration sécurisée des cookies de session
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
session_start();
// Ou avec setcookie() pour vos propres cookies
setcookie("theme", "dark", [
'expires' => time() + 86400 * 30,
'path' => '/',
'httponly' => true,
'secure' => true,
'samesite' => 'Strict'
]);
À vous d'essayer
On simule $_SESSION avec un simple tableau pour voir la logique de connexion. Modifiez, puis exécutez :
<?php
// Simulation de $_SESSION (un vrai $_SESSION exige session_start())
$session = [];
// Connexion : on stocke l'utilisateur
$session['user_id'] = 42;
$session['user_nom'] = 'Alice';
$session['role'] = 'admin';
// Sur une autre page : on verifie l'acces
if (empty($session['user_id'])) {
echo "Acces refuse : connectez-vous.";
} else {
echo "Bienvenue, " . htmlspecialchars($session['user_nom']) . "\n";
echo "Role : " . $session['role'];
}
?>
The problem: HTTP is stateless
Each HTTP request is independent. The server doesn't know that the person visiting page 2 is the same one who was on page 1. It's as if every time you opened a door in the building, the plumbing forgot who you are.
Sessions and cookies solve this problem by creating memory between pages.
Sessions: server-side memory
A session stores data on the server, linked to a visitor via a unique ID:
// ALWAYS on the first line (before any HTML)
session_start();
// Store data
$_SESSION['user'] = 'Alice';
$_SESSION['role'] = 'admin';
$_SESSION['logged_in'] = true;
// Read data (on another page)
session_start();
echo $_SESSION['user']; // → Alice
// Delete a value
unset($_SESSION['role']);
// Destroy the entire session (logout)
session_destroy();
Important: session_start() must be called before any HTML output, otherwise PHP shows a "headers already sent" error.
Under the hood: where does the data live?
A server is a machine (often remote) that runs PHP and can write files. When you call session_start(), here's what really happens:
- On the first visit, PHP generates a unique identifier (e.g.
PHPSESSID = a1b2c3…) and creates a file on the server for this visitor (typically/tmp/sess_a1b2c3…, or a database row). - It sends that identifier back to the browser in a cookie. That's the only thing that travels: not your data, just the label.
- On every following request, the browser automatically sends that cookie back. PHP reads the ID, opens the right file, and fills
$_SESSIONwith its contents.
Hence two things you no longer need to memorize: you can re-derive them by logic.
- "headers already sent": setting the session cookie is an HTTP header, and headers go out before the page content. So
session_start()must run before a single character of HTML (even a space or blank line before<?php). - Expiration: since session files pile up, the server cleans them periodically. An idle session therefore eventually disappears — that's normal.
Cookies: browser-side memory
A cookie is a small file stored in the user's browser:
// Create a cookie (expires in 30 days)
setcookie("theme", "dark", time() + (30 * 24 * 3600), "/");
// Read a cookie
$theme = $_COOKIE['theme'] ?? 'light';
echo "Current theme: $theme";
// Delete a cookie (date in the past)
setcookie("theme", "", time() - 3600, "/");
Sessions vs Cookies:
- Session — data on the server, disappears when browser closes
- Cookie — data in the browser, can last days/months
Rule: sensitive data (login, role, ID) goes in sessions. Preferences (theme, language) go in cookies.
Example: login flow
// login.php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
// Check database (simplified here)
if ($email === 'alice@example.com' && password_verify($password, $stored_hash)) {
// Login successful
$_SESSION['user_id'] = 42;
$_SESSION['user_name'] = 'Alice';
session_regenerate_id(true); // Security!
header('Location: /dashboard.php');
exit;
} else {
$error = "Invalid email or password.";
}
}
// dashboard.php
session_start();
if (empty($_SESSION['user_id'])) {
header('Location: /login.php');
exit;
}
echo "Welcome, " . htmlspecialchars($_SESSION['user_name']);
// logout.php
session_start();
$_SESSION = [];
session_destroy();
header('Location: /login.php');
Session security
session_regenerate_id(true)— after login, to prevent "session fixation"- HttpOnly cookies — prevents JavaScript from accessing the session cookie
- Secure cookies — cookie only sent over HTTPS
- SameSite=Strict — protects against CSRF attacks
// Secure session cookie configuration
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
session_start();
// Or with setcookie() for your own cookies
setcookie("theme", "dark", [
'expires' => time() + 86400 * 30,
'path' => '/',
'httponly' => true,
'secure' => true,
'samesite' => 'Strict'
]);
À vous d'essayer (vrai PHP)
$_SESSION est un simple tableau associatif. Sur un vrai serveur, session_start() le remplit automatiquement et le conserve d'une page à l'autre. Ici on l'initialise à la main pour montrer la logique de login. Change le mot de passe, puis clique sur « Run » :
<?php
// Sur un vrai serveur : session_start(); puis $_SESSION est déjà disponible.
// Ici on simule le tableau de session, car un sandbox n'a pas d'état entre les pages.
$_SESSION = [];
// Un "utilisateur en base" (le mot de passe est haché, jamais en clair)
$utilisateur = [
'id' => 42,
'nom' => 'Alice',
'role' => 'admin',
'hash' => password_hash('secret', PASSWORD_DEFAULT),
];
// Tentative de connexion
$emailSaisi = 'alice@exemple.fr';
$motDePasseSaisi = 'secret'; // ← change-le pour voir l'échec
if (password_verify($motDePasseSaisi, $utilisateur['hash'])) {
// On stocke l'identité en session
$_SESSION['user_id'] = $utilisateur['id'];
$_SESSION['user_nom'] = $utilisateur['nom'];
$_SESSION['role'] = $utilisateur['role'];
}
// Affichage selon l'état de la session
if (isset($_SESSION['user_id'])) {
echo "Bienvenue, " . $_SESSION['user_nom'] . " !\n";
echo "Rôle : " . $_SESSION['role'] . "\n";
} else {
echo "Email ou mot de passe incorrect.\n";
}
?>
Copiez ce prompt dans Claude ou ChatGPT :
Crée un système de panier d'achat en PHP avec sessions : ajouter un produit, supprimer un produit, afficher le total. Utilise $_SESSION['panier'] comme tableau associatif.
Sans relire la réponse de l'IA : pourquoi un panier d'achat se range-t-il dans $_SESSION et pas dans un cookie ? Qu'est-ce qui voyage réellement entre le navigateur et le serveur ?
$_SESSION, donc sur le serveur ; le client ne peut pas le trafiquer (changer les prix, les quantités). Seul l'identifiant PHPSESSID voyage dans un cookie : pas les données, juste l'étiquette. À chaque requête, PHP relit cet ID, ouvre le bon fichier et remplit $_SESSION. Un cookie, lui, est stocké et modifiable côté navigateur : à proscrire pour des données qu'on ne veut pas voir falsifiées.L'IA te propose ce code pour « se souvenir » de l'utilisateur connecté. Ton rôle de relecteur : l'accepter tel quel ou le rejeter, et dire pourquoi.
// Après un login réussi
setcookie("user_id", "42", time() + 86400, "/");
setcookie("role", "admin", time() + 86400, "/");
// Sur les autres pages, on fait confiance au cookie
if ($_COOKIE['role'] === 'admin') {
afficherPanneauAdmin();
}
role en admin et obtenir le panneau d'administration : c'est une élévation de privilèges. La règle de la leçon : les données sensibles (login, rôle, ID) vont en $_SESSION (serveur), jamais dans un cookie lisible. Le cookie ne doit transporter que l'identifiant de session opaque.Sans remonter dans la leçon : où vivent les données d'une session, qu'est-ce que le cookie PHPSESSID transporte vraiment, et pourquoi session_start() doit-il s'exécuter avant tout HTML ?
/tmp/sess_… ou une ligne en base). Le cookie PHPSESSID ne transporte que l'identifiant de session, pas les données : juste l'étiquette qui permet à PHP de retrouver le bon fichier à chaque requête. Et session_start() doit précéder tout HTML car déposer le cookie de session est un en-tête HTTP, et les en-têtes partent avant le contenu : un seul espace avant <?php déclenche « headers already sent ».session_regenerate_id(true) ?Sessions and cookies keep info for a visit, but it all vanishes in the end. To keep accounts, posts, orders for good, you need a database. We're tackling PDO and SQL queries from PHP.
Lesson 6: SQL databases →