Aller au contenu

Préserver les données

Jusqu’ici, chaque requête que nous effectuons au serveur repartait de zéro, sans préserver nos données soumises (via formulaire) ou changements d’états. On a pu observer cette limite au travail pratique : sans mécanisme de conservation, une réservation disparaît au rafraîchissement suivant.

Ce chapitre présente deux façons de conserver des données au-delà d’une requête : les sessions, propres à un visiteur et de courte durée, puis les bases de données, durables et partagées par tous.

Le protocole HTTP est sans état : le serveur traite chaque requête indépendamment, sans conserver en mémoire les données transmises ou modifiées par la précédente. Deux requêtes du même visiteur (utilisateur) sont considérées comme deux exécutions séparées qui ne partagent aucune variable.

Pour qu’une donnée survive d’une requête à l’autre, il faut la ranger quelque part de persistant, puis la relire. C’est le rôle des mécanismes de préservation.

Le moyen le plus simple, déjà à votre portée, consiste à faire voyager l’état dans l’URL, via les requêtes de paramètre (placées après ?). Chaque lien ou formulaire transporte les valeurs à conserver dans la chaîne de requête, que la page suivante récupère dans $_GET.

<?php
// Le tri courant est transmis d'une page à l'autre par les liens.
$tri = $_GET['tri'] ?? 'nom';
echo '<a href="produits.php?tri=nom">Par nom</a> ';
echo '<a href="produits.php?tri=prix">Par prix</a>';

Une session est un espace de stockage sur le serveur, associé à un visiteur particulier. Les données y restent disponibles d’une requête à l’autre, pendant toute la durée de la visite.

session_start() ouvre ou reprend la session du visiteur. Elle doit être appelée sur chaque page qui utilise la session, avant toute sortie HTML. Ensuite, la superglobale $_SESSION se manipule comme un tableau associatif.

<?php
session_start(); // toujours avant toute sortie
// Au premier passage, la clé n'existe pas : on part de 0.
$_SESSION['visites'] = ($_SESSION['visites'] ?? 0) + 1;
echo 'Vous avez consulté cette page ' . $_SESSION['visites'] . ' fois.';

À chaque rechargement, le compteur augmente : la valeur a bien été conservée entre les requêtes. On préserve de la même façon des données plus utiles, comme par exemple, un panier d’achat.

<?php
session_start();
// Ajouter un produit au panier.
$_SESSION['panier'][] = "Sirop d'érable 540 ml";
// Afficher le panier.
foreach ($_SESSION['panier'] ?? [] as $article) {
echo htmlspecialchars($article) . '<br>';
}

Les données de session vivent sur le serveur. Pour savoir à quel visiteur elles appartiennent, PHP dépose dans le navigateur un témoin nommé PHPSESSID, qui contient seulement un identifiant. À la requête suivante, le navigateur renvoie ce témoin, et PHP retrouve les données correspondantes.

  1. Navigateur vers Serveur PHP : 1re requête (aucun témoin encore)
  2. Serveur PHP vers Navigateur : 200 · Réponse et dépôt du témoin PHPSESSID
  3. Navigateur vers Serveur PHP : 2e requête (renvoie PHPSESSID)
  4. Serveur PHP : PHP retrouve $_SESSION à partir de l'identifiant
  5. Serveur PHP vers Navigateur : 200 · Réponse : les données sont conservées
Deux requêtes reliées par le témoin de session

Sur le serveur, PHP les écrit dans un fichier temporaire, un par session, nommé d’après l’identifiant (par exemple sess_a1b2c3d4...).
À session_start(), PHP lit l’identifiant dans le témoin, ouvre le fichier correspondant, et reconstitue le tableau $_SESSION.
À la fin du script, il réécrit ce tableau dans le fichier. $_SESSION n’est donc qu’une image en mémoire du contenu de ce fichier, le temps d’une requête.

On retire une donnée avec unset, et on termine la session avec session_destroy.

<?php
session_start();
unset($_SESSION['panier']); // retirer une seule donnée
session_destroy(); // terminer toute la session

Une session se termine aussi d’elle-même après un délai d’inactivité ou à la fermeture du navigateur.

Une session est temporaire : elle dure le temps d’une visite et n’appartient qu’à un visiteur. Pour conserver des données durablement, et les partager entre tous les visiteurs, il faut une base de données.

Un fichier de données en PHP convient à un petit catalogue fixe. Dès que les données changent souvent, grossissent, ou doivent être interrogées de multiples façons, on utilise une base de données.

Une base de données relationnelle organise l’information en tables. Chaque table a des colonnes (les champs) et des lignes (les enregistrements). Voici une table produits :

idnomprix
1Sirop d’érable 540 ml14.50
2Beurre d’érable 250 g9.95
3Tire sur la neige6.00

Trois notions à retenir :

  • une clé primaire identifie chaque ligne de façon unique (ici la colonne id) ;
  • une clé étrangère relie une table à une autre (par exemple une table commandes qui référence l’id d’un produit) ;
  • le langage SQL sert à interroger et modifier les données, avec quatre opérations principales : SELECT (lire), INSERT (ajouter), UPDATE (modifier) et DELETE (supprimer).

Le schéma ci-dessous illustre ces relations. Une table commandes et une table produits sont reliées par une table intermédiaire, lignes_commande.

Schéma relationnel
clé primaire (PK) clé étrangère (FK)
produitsPKidINTnomVARCHARprixDECIMALcommandesPKidINTdateDATEclientVARCHARlignes_commandePKidINTFKcommande_idINTFKproduit_idINTquantiteINT
Chaque ligne de lignes_commande relie une commande à un produit.

MySQL est un système de gestion de base de données relationnelle : un serveur qui stocke les bases et exécute les requêtes SQL. XAMPP en fournit une version compatible, MariaDB, qui s’utilise de la même façon.

phpMyAdmin est un outil web, inclus dans XAMPP, pour gérer MySQL depuis le navigateur : créer des bases et des tables, écrire du SQL, parcourir les données.

  1. Dans le panneau de contrôle de XAMPP, démarrez MySQL en plus d’Apache.
  2. Ouvrez http://localhost/phpmyadmin dans le navigateur.
  3. Onglet « Bases de données » : créez une BD nommée erabliere.
  4. Sélectionnez cette base, puis l’onglet « SQL », et exécutez le code ci-dessous.
  5. Onglet « Parcourir » : les trois produits doivent apparaître.
CREATE TABLE produits (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
prix DECIMAL(6, 2) NOT NULL
);
INSERT INTO produits (nom, prix) VALUES
('Sirop d''érable 540 ml', 14.50),
('Beurre d''érable 250 g', 9.95),
('Tire sur la neige', 6.00);

PHP communique avec la BD à l’aide de PDO (PHP Data Objects), une interface commune à plusieurs systèmes de base de données. On ouvre la connexion une fois, en précisant l’hôte, le nom de la BD et l’encodage.

<?php
$dsn = 'mysql:host=localhost;dbname=erabliere;charset=utf8mb4';
$utilisateur = 'root';
$motDePasse = '';
try {
$pdo = new PDO($dsn, $utilisateur, $motDePasse);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
exit('Connexion impossible : ' . $e->getMessage());
}

La connexion en main, on interroge la base. Une simple lecture de tous les produits :

<?php
$requete = $pdo->query('SELECT id, nom, prix FROM produits');
$produits = $requete->fetchAll(PDO::FETCH_ASSOC);
foreach ($produits as $produit) {
echo htmlspecialchars($produit['nom']) . ' : '
. number_format($produit['prix'], 2, ',', ' ') . ' $<br>';
}

Dès qu’une valeur vient du client, on n’assemble jamais la requête par concaténation. On utilise une requête préparée : la valeur voyage à part, ce qui empêche l’injection SQL.

<?php
$requete = $pdo->prepare('SELECT id, nom, prix FROM produits WHERE prix <= :max');
$requete->execute(['max' => 10]);
$abordables = $requete->fetchAll(PDO::FETCH_ASSOC);
Les requêtes préparées protègent l’entrée vers la BD comme htmlspecialchars protège la sortie vers le HTML. Toute donnée venue du client passe par un paramètre (:max), jamais par concaténation dans la chaîne SQL.
Vérification Pourquoi une session ne suffit-elle pas à conserver le catalogue de produits d'une boutique ?

Une session est propre à un visiteur et temporaire : chaque personne aurait son propre catalogue, qui disparaîtrait à la fin de sa visite. Le catalogue doit être unique, durable et partagé par tous : c’est le rôle d’une base de données. La session convient plutôt à des données propres à la visite en cours, comme le panier.

  • HTTP est sans état : sans mécanisme de préservation, chaque requête oublie la précédente.
  • Une session (session_start, $_SESSION) conserve des données sur le serveur pour un visiteur, le temps de sa visite ; le navigateur ne garde que l’identifiant PHPSESSID.
  • Une session est temporaire et individuelle ; pour des données durables et partagées, on utilise une base de données relationnelle (tables, clés primaires et étrangères, SQL).
  • MySQL stocke les données ; phpMyAdmin permet de les gérer depuis le navigateur.
  • PHP se connecte avec PDO, et interroge la base de données par des requêtes préparées pour se prémunir contre l’injection SQL.

Quiz. Où sont conservées les données d'une session ?

Quiz. Quel appel doit précéder toute sortie HTML pour utiliser une session ?

Quiz. Dans une table relationnelle, à quoi sert la clé primaire ?

Quiz. Pourquoi utiliser une requête préparée quand une valeur vient du client ?