Aller au contenu

Construire une page dynamique

Le contenu d’une page Web peut être préparé à l’avance ou produit au moment où la page est demandée. Dans le premier cas, on parle généralement de contenu statique. Dans le second, la page est générée dynamiquement.

Tout au long du cours, nous rencontrerons différentes façons de construire une page web. Chaque stratégie répondra aux deux questions suivantes:

  • où le contenu est-il produit : sur le serveur ou dans le navigateur ?
  • quand est-il produit : avant la requête ou lorsque l’utilisateur demande la page ?

Une page web statique, soit un fichier .html est envoyé tel quel par le serveur : ce que vous écrivez est exactement ce que le navigateur reçoit. Lorsqu’un langage de programmation ou de scripting comme PHP (fichier .php) est utilisé pour décrire la page, il est d’abord exécuté par le serveur pour produire le HTML qui sera envoyé par le serveur.

Le navigateur ne reçoit jamais le code PHP, seulement le HTML produit.

Le type de rendu décrit plus haut est appelé rendu côté serveur : le serveur construit le HTML de la page avant de l’envoyer au navigateur. Cette approche est particulièrement utile lorsque le contenu doit être disponible dès la réponse du serveur, par exemple pour produire des pages à partir de données, centraliser la logique de présentation ou permettre une navigation classique où chaque adresse correspond à une page produite par le serveur. PHP fonctionne naturellement de cette façon : une requête arrive, le serveur exécute le programme PHP et retourne le HTML obtenu.

Le navigateur peut cependant lui aussi construire ou modifier une interface grâce à JavaScript. On parle alors de rendu côté client lorsque la construction d’une partie importante de l’interface se fait dans le navigateur après le chargement du JavaScript. Dans une application monopage (Single Page Application ou SPA), le serveur peut envoyer une structure HTML initiale relativement minimale, puis JavaScript prend en charge une grande partie de la construction de l’interface et de la navigation.

Suivez les trois moments du trajet, dans un mode puis dans l’autre : le début et la fin se ressemblent, c’est au milieu que tout se joue.
Section intitulée « Suivez les trois moments du trajet, dans un mode puis dans l’autre : le début et la fin se ressemblent, c’est au milieu que tout se joue. »
Où le HTML est-il produit ?
PHP construit le HTML avant l’envoi
produits.phpphp
<h1>Nos produits</h1>

<p><?= count($products) ?> produits au catalogue.</p>

<ul>
<?php foreach ($products as $product): ?>
  <li>
    <?= $product['name'] ?> — <?= $product['price'] ?> $

    <?php if ($product['stock'] > 0): ?>
      <strong>Disponible</strong>
    <?php else: ?>
      <strong>Rupture de stock</strong>
    <?php endif; ?>
  </li>
<?php endforeach; ?>
</ul>
PHP contient une boucle foreach et une condition if. Ces instructions déterminent quels éléments HTML doivent être produits.
Le PHP ne franchit jamais la frontière du serveur.

Chaque affichage d’une page PHP suit le même trajet, du clic jusqu’à l’écran.

  1. Le navigateur envoie une requête HTTP vers une adresse.

  2. Le serveur repère le fichier visé et exécute le code PHP qu’il contient.

  3. PHP récupère ou prépare les données nécessaires : un tableau, un fichier, plus tard une base de données.

  4. PHP produit le contenu HTML à partir de ces données.

  5. Le serveur retourne la réponse HTTP, dont le corps est ce HTML.

  6. Le navigateur interprète et affiche le HTML reçu.

  1. Navigateur vers Serveur + PHP : GET /produits.php
  2. Serveur + PHP : exécute produits.php
  3. Serveur + PHP vers Données : lecture des données (tableau, fichier ou base de données)
  4. Données vers Serveur + PHP : 2 produits
  5. Serveur + PHP : produit le HTML
  6. Serveur + PHP vers Navigateur : 200 · HTML produit
  7. Navigateur : interprète et affiche
Cycle de vie d'une requête vers une page PHP
VérificationVous modifiez une variable PHP dans produits.php. Sa valeur sera-t-elle encore là quand l'utilisateur cliquera vers contact.php ?

Non. Chaque requête déclenche une nouvelle exécution, indépendante de la précédente. Pour conserver une information d’une page à l’autre, il faut la transmettre explicitement (chaîne de requête, formulaire) ou la stocker (session, fichier, base de données).

Voici une page de produits parfaitement ordinaire, écrite en HTML pur.

<h1>Nos produits</h1>
<ul>
<li>Tire sur la neige — 6,25 $</li>
<li>Sirop d'érable 540 ml — 14,50 $</li>
</ul>

Elle a l’air simple, et elle l’est. Pourtant elle contient déjà les trois éléments d’une page dynamique, mêlés au point d’être indiscernables : les données, la logique qui détermine quoi afficher, et la présentation.

Les données sautent aux yeux : deux noms, deux prix. La présentation aussi : un titre, une liste. La logique, elle, est invisible — et c’est tout le problème. Le catalogue compte en réalité trois produits ; le beurre d’érable est en rupture et n’apparaît pas. La liste est triée par prix croissant. Le montant est écrit « 14,50 $ », avec la virgule et l’espace. Trois décisions ont donc bien été prises, mais hors du fichier : quelqu’un les a évaluées de tête, une fois, puis a écrit le résultat.

Construire une page dynamique, c’est ressortir ces éléments du HTML un par un, et les confier au serveur. Parcourez les quatre étapes : l’écran affiché reste rigoureusement le même, seule l’organisation change.

D'une page statique à une page dynamique
Le résultat affiché est le même aux quatre étapes. Seule change la place de chaque ingrédient.
donnéesécrites dans le HTMLlogiquedans la tête de l'auteurstructurerépétée à la main

Tout est écrit à la main. Les trois produits du catalogue n'apparaissent pas : il en manque un, et l'ordre n'est pas celui du catalogue.

produits.html
<h1>Nos produits</h1><ul>  <li>Tire sur la neige — 6,25 $</li>  <li>Sirop d'érable 540 ml — 14,50 $</li></ul>
Ce qui coince encoreLa logique existe pourtant : quelqu'un a décidé d'écarter le produit en rupture, de trier par prix et d'écrire « 14,50 $ ». Ces décisions ont été prises de tête, puis effacées. Rien dans le fichier n'en garde la trace, et personne ne peut les vérifier.
Affichage identique aux quatre étapes

Chaque extraction règle un problème et en révèle un autre. Sortir les données donne une source unique, mais la page continue de choisir ses produits à la main. Écrire la logique rend les règles lisibles, mais le HTML, resté figé, se met à contredire ce que la logique affirme. Ce n’est qu’à la dernière étape, quand la structure devient une boucle, que les trois pièces s’accordent.

Préparez d’abord, affichez ensuite. Tout ce qui calcule, filtre ou trie se place avant le premier caractère de HTML. La partie basse du fichier ne fait plus que parcourir et afficher : elle reste lisible même pour quelqu’un qui ne connaît pas PHP.

Un site PHP est composé de plusieurs pages reliées par des liens HTML ordinaires. Naviguer vers une autre page déclenche une nouvelle requête : le cycle vu plus haut, répété.

<nav>
<a href="index.php">Accueil</a>
<a href="produits.php">Produits</a>
<a href="contact.php">Contact</a>
</nav>

Chacune de ces pages a besoin du même en-tête, de la même navigation, du même pied de page, souvent des mêmes données et des mêmes fonctions. Les recopier serait ingérable : la moindre retouche obligerait à ouvrir tous les fichiers. On les inclut plutôt.

Lorsqu’il rencontre include ou require, PHP exécute le fichier demandé à cet endroit du programme. Le HTML produit par ce fichier s’insère donc à cet endroit dans la réponse. Mais on ne s’en sert pas pour la même chose, et c’est ce qu’on attend du fichier qui dicte le mécanisme à employer.

Le cadre commun. L’en-tête et le pied de page entourent le contenu de chaque page. Ils produisent du HTML, une fois par page.

<?php require __DIR__ . "/includes/header.php"; ?>
<main>
<h2>Nos produits</h2>
</main>
<?php require __DIR__ . "/includes/footer.php"; ?>

Le fragment répété. Un bloc qui revient — la carte d’un produit — est extrait puis inclus à chaque tour de boucle. Ici, la répétition est le but : surtout pas de _once.

<?php foreach ($afficher as $p): ?>
<?php include __DIR__ . "/partials/product-card.php"; ?>
<?php endforeach; ?>

Les déclarations. Un fichier de fonctions ou de classes produit rien à l’écran : il déclare. Le charger deux fois provoque une erreur fatale, puisqu’on ne peut pas redéclarer une fonction.

<?php
require_once __DIR__ . "/lib/functions.php"; // formatPrix() déclarée ici, une seule fois

Les données. Un fichier peut se contenter de return une valeur. C’est l’approche privilégiée pour les fichiers de configuration. On l’importe alors comme une expression, et la donnée cesse d’être mêlée à la page qui l’affiche — c’est l’extraction de l’étape 2, mais dans un fichier séparé.

data/products.php
<?php
return [
["nom" => "Sirop d'érable 540 ml", "prix" => 14.50, "stock" => 8],
["nom" => "Beurre d'érable 250 g", "prix" => 9.95, "stock" => 0],
];
<?php
$products = require __DIR__ . "/data/products.php";

Les quatre cas se distinguent par ce que le fichier produit, et cela suffit à trancher.

Cas d’usage Ce que le fichier produit Mécanisme
En-tête, pied de page du HTML, une fois par page include ou require
Fragment répété du HTML, à chaque tour de boucle include, jamais _once
Fonctions, classes rien à l’écran, des déclarations require_once
Données, configuration rien à l’écran, une valeur retournée require avec affectation

Reste à choisir entre include et require, qui ne diffèrent que par leur réaction à un fichier manquant.

Mécanisme Fichier introuvable
include avertissement, le script continue
require erreur fatale, le script s’arrête

require dès que la page n’a aucun sens sans le fichier. Un en-tête absent, une configuration manquante, un fichier de fonctions introuvable : mieux vaut un arrêt net qu’une page à moitié construite, qui s’effondrera trois lignes plus loin avec un message incompréhensible.

Les quatre cas se retrouvent dans une seule page. Sélectionnez un fichier pour isoler sa contribution au HTML final, ou suivez une ligne include pour aller voir le fichier qu’elle appelle.

Composition d'une page
Choisissez un fichier, ou suivez une ligne include.
Fichiers du site
includes/
partials/
data/
produits.phppage
<?php$titre    = "Nos produits";?> <main>  <h2><?php echo htmlspecialchars($titre); ?></h2>   <?php foreach ($products as $p): ?>  <?php endforeach; ?></main> 
HTML produit par produits.php
data/products.php
aucune sortie : ce fichier retourne un tableau, il n'affiche rien
includes/header.php
<header>
  <h1>L'Érablière dorée</h1>
  <nav>…</nav>
</header>
produits.php
<main>
  <h2>Nos produits</h2>
partials/product-card.phptour 1
  <article class="carte">
    <h3>Sirop d'érable 540 ml</h3>
    <p>14,50 $</p>
  </article>
partials/product-card.phptour 2
  <article class="carte">
    <h3>Beurre d'érable 250 g</h3>
    <p>9,95 $</p>
  </article>
produits.php
</main>
includes/footer.php
<footer>
  <p>© 2026 L'Érablière dorée</p>
</footer>
Le HTML final ne vient pas d'un seul fichier : chaque bloc porte le nom de celui qui l'a produit. Choisissez un fichier pour isoler sa contribution.

Notez ce que produit chacun : data/products.php n’écrit rien mais fournit la matière ; header.php et footer.php posent le cadre ; product-card.php apparaît deux fois, une par produit ; et produits.php lui-même se réduit à trois variables et quatre inclusions.

Composer un site, c’est séparer progressivement ses responsabilités. Le diagramme de séquence de la deuxième section suivait la requête entre les machines ; celui-ci suit les responsabilités à l’intérieur du serveur, de la demande jusqu’à l’écran.

Le trajet complet d'une page dynamique1. Requête : Un clic ou une adresse saisie : le navigateur demande une page au serveur. 2. Page PHP : Le serveur exécute le fichier visé, dans un script neuf. Les variables de la requête précédente n'existent plus : le script repart de zéro. 3. Préparation des données : Le script rassemble sa matière : tableau, fichier importé, base de données. 4. Composition de la présentation : La logique filtre et trie ; le gabarit et les parties incluses assemblent. 5. HTML produit : Plus une seule balise PHP. Chaque donnée affichée est passée par htmlspecialchars(). 6. Réponse : Le serveur renvoie ce HTML dans le corps de la réponse HTTP. 7. Navigateur : Le navigateur interprète et affiche. Le prochain clic relance le trajet.RequêteUn clic ou une adresse saisie : le navigateur demande une page au serveur.Page PHPLe serveur exécute le fichier visé, dans un script neuf.⚠Les variables de la requête précédente n'existent plus : le script repart de zéro.Préparation des donnéesLe script rassemble sa matière : tableau, fichier importé, base de données.Composition de la présentationLa logique filtre et trie ; le gabarit et les parties incluses assemblent.HTML produitPlus une seule balise PHP. Chaque donnée affichée est passée par htmlspecialchars().RéponseLe serveur renvoie ce HTML dans le corps de la réponse HTTP.NavigateurLe navigateur interprète et affiche. Le prochain clic relance le trajet.

Chaque étape a désormais son fichier, ou sa portion de fichier. C’est ce qui rend le site plus facile à comprendre, à modifier et à faire évoluer : on sait toujours où intervenir, et un changement reste local.

VérificationVous extrayez vos fonctions d'affichage dans lib/functions.php. Quel mécanisme d'inclusion, et pourquoi ?

require_once. require parce qu’une page privée de ses fonctions ne peut pas s’afficher : l’arrêt immédiat vaut mieux qu’une erreur obscure plus loin. Et _once parce qu’un fichier qui déclare des fonctions ne peut pas être chargé deux fois — PHP refuse toute redéclaration.

  • Le PHP reste sur le serveur : si vous voyez <?php dans le code source affiché par le navigateur, le fichier n’a pas été exécuté.
  • Les variables du script ne survivent pas à la requête. : les variables disparaissent à la fin du script. Transmettre ou stocker, jamais espérer.
  • Préparer, puis afficher : la logique en haut du fichier, la présentation en bas.
  • Échapper systématiquement : htmlspecialchars(...) sur tout ce qui s’affiche, y compris dans les fragments réutilisés.
  • _once pour les déclarations, include simple pour un fragment que l’on veut répéter.
  • Chemin d’URL ou chemin de fichier : href pour le navigateur, include/require avec __DIR__ pour le serveur.
  • Une page PHP est exécutée sur le serveur ; le navigateur ne reçoit que le HTML produit. Le rendu côté client, lui, construit l’interface en JavaScript après réception.
  • Le cycle d’une page dynamique va de la requête HTTP à l’affichage, en passant par l’exécution du fichier, la préparation des données et la production du HTML.
  • Une page dynamique combine données, logique et présentation — dans cet ordre, de préférence.
  • Un site s’assemble à partir de pages reliées par des liens, de parties incluses (header.php, footer.php, partials/) et de fichiers de données importés par require.
  • require convient aux fichiers indispensables, require_once aux fichiers qui déclarent des fonctions ou des classes, et include aux fragments de présentation que l’on veut pouvoir répéter.
  • Un lien utilise un chemin d’URL interprété par le navigateur, tandis que include et require utilisent des chemins de fichiers interprétés sur le serveur. __DIR__ permet d’ancrer ces chemins sur le fichier courant.

Quiz. Pourquoi le navigateur ne reçoit-il jamais de code PHP ?

Quiz. Que se passe-t-il exactement quand l'utilisateur clique sur <a href='produits.php'> ?

Quiz. À quoi sert __DIR__ dans require __DIR__ . '/data/products.php' ?