Aller au contenu

Exercices — Navigation et composition

Niveau 1 — Découper une page : fragments, include et require

Section intitulée « Niveau 1 — Découper une page : fragments, include et require »

Dans la construction d’un site ou une application web, le réflexe de base à avoir est : repérer ce qui se répète, le sortir dans un fichier (un fragment), et l’insérer là où il faut avec include ou require.

Exercice 1.1 : Repérer les fragments et le contenu propre

Section intitulée « Exercice 1.1 : Repérer les fragments et le contenu propre »

Voici deux pages d’un même site. Repère ce qui est identique sur les deux (à extraire dans des fragments) et ce qui est propre à chaque page.

<!doctype html>
<html lang="fr">
<head><title>Accueil — Érablière</title></head>
<body>
<nav><a href="accueil.php">Accueil</a> · <a href="contact.php">Contact</a></nav>
<main>
<h1>Bienvenue à l'Érablière dorée</h1>
<p>Nos produits d'érable, directement de la cabane.</p>
</main>
<footer>© 2025 L'Érablière dorée</footer>
</body>
</html>
<!doctype html>
<html lang="fr">
<head><title>Contact — Érablière</title></head>
<body>
<nav><a href="accueil.php">Accueil</a> · <a href="contact.php">Contact</a></nav>
<main>
<h1>Nous joindre</h1>
<p>Téléphone : 1 800 ÉRABLE.</p>
</main>
<footer>© 2025 L'Érablière dorée</footer>
</body>
</html>
Vérification Indice

Lis les deux pages côte à côte. Ce qui est rigoureusement identique peut vivre dans un seul fichier partagé. Ce qui change d’une page à l’autre reste propre à la page.

Vérification Solution

Identique → deux fragments.

  • entete.php: L’en-tête, du <!doctype html> jusqu’à la fin du <nav>.
  • pied.php: Le <footer> et la fermeture (</body></html>).

Propre à chaque page → le contenu.

  • Seul le <main> change et c’est tout ce que chaque fichier de page (accueil.php, contact.php) doit garder.

Le <title> diffère lui aussi (« Accueil — … » contre « Contact — … »). On peut résoudre ça en passant le titre à l’en-tête par une variable.

Les fragments entete.php et pied.php existent déjà (ci-dessous). Écris accueil.php pour qu’il les insère autour de son contenu, sans recopier le HTML commun.

<!doctype html>
<html lang="fr">
<head><title>L'Érablière dorée</title></head>
<body>
<nav><a href="accueil.php">Accueil</a> · <a href="contact.php">Contact</a></nav>
<footer>© 2025 L'Érablière dorée</footer>
</body>
</html>
Vérification Indice

include 'fichier.php'; insère le contenu du fichier à cet endroit, comme un copier-coller exécuté. Place l’include de l’en-tête avant ton contenu, et celui du pied après.

Vérification Solution
accueil.php
<?php include 'entete.php'; ?>
<main>
<h1>Bienvenue à l'Érablière dorée</h1>
<p>Nos produits d'érable, directement de la cabane.</p>
</main>
<?php include 'pied.php'; ?>

Le <title> change d’une page à l’autre, mais l’en-tête est partagé. Un fichier inclus voit les variables définies avant son include. Voici entete.php, qui attend désormais une variable $titre :

entete.php
<!doctype html>
<html lang="fr">
<head><title><?= htmlspecialchars($titre) ?></title></head>
<body>
<nav><a href="accueil.php">Accueil</a> · <a href="contact.php">Contact</a></nav>

Écris le début de accueil.php pour que le titre affiché soit « Accueil — Érablière ».

Vérification Indice

Définis $titre avant d’inclure entete.php. L’include n’a pas de portée séparée : il partage les variables de la page qui l’inclut.

Vérification Solution
accueil.php
<?php $titre = 'Accueil — Érablière'; ?>
<?php include 'entete.php'; ?>
<main>
<h1>Bienvenue à l'Érablière dorée</h1>
</main>
<?php include 'pied.php'; ?>

Les pages assemblées, reste à les relier et à réagir à ce que l’URL demande.

Dans entete.php, la barre de navigation relie les pages du site.
Écris le <nav> qui mène à l’accueil, aux produits et au contact (fichiers accueil.php, produits.php, contact.php).

Vérification Indice

Un lien interne, c’est <a href="produits.php">Produits</a>. Le chemin est relatif au dossier de la page courante.

Vérification Solution
<nav>
<a href="accueil.php">Accueil</a>
<a href="produits.php">Produits</a>
<a href="contact.php">Contact</a>
</nav>

Exercice 2.2 : Lire la page demandée dans l’URL

Section intitulée « Exercice 2.2 : Lire la page demandée dans l’URL »

Une URL comme produits.php?categorie=sirop transporte une donnée après le ?. PHP la dépose dans la superglobale $_GET.
Récupère la catégorie demandée, ou 'tous' si aucune n’est précisée.

// produits.php?categorie=sirop → $categorie vaut "sirop"
// produits.php → $categorie vaut "tous"
Vérification Indice

$_GET['categorie'] contient la valeur écrite après categorie=. Au premier affichage, sans paramètre, cette clé n’existe pas : ?? fournit alors la valeur par défaut.

Vérification Solution
<?php
$categorie = $_GET['categorie'] ?? 'tous';

Pour aider le visiteur à se repérer, la page courante doit se distinguer dans le menu. La page courante est connue dans $pageActive. Ajoute la classe actif au seul lien correspondant.

// Si $pageActive vaut 'produits', seul le lien Produits reçoit class="actif".
Vérification Indice

Pour chaque lien, compare sa cible à $pageActive. Si elles correspondent, écris class="actif", sinon rien. Un opérateur ternaire (?:) tient sur une ligne, à l’intérieur de l’attribut.

Vérification Solution
<nav>
<a href="accueil.php" class="<?= $pageActive === 'accueil' ? 'actif' : '' ?>">Accueil</a>
<a href="produits.php" class="<?= $pageActive === 'produits' ? 'actif' : '' ?>">Produits</a>
<a href="contact.php" class="<?= $pageActive === 'contact' ? 'actif' : '' ?>">Contact</a>
</nav>

Niveau 3 — Automatiser la composition avec des fonctions

Section intitulée « Niveau 3 — Automatiser la composition avec des fonctions »

Mêmes idées, mais cette fois on remplace les fragments par des fonctions qui retournent du HTML : plus souples, paramétrables et testables.

Exercice 3.1 : L’en-tête et le pied en fonctions

Section intitulée « Exercice 3.1 : L’en-tête et le pied en fonctions »

Transforme tes fragments en fonctions : entete($titre) ouvre la page avec un titre, pied() la referme. (C’est la version « fonction » des exercices 1.2 et 1.4.)

Signature : entete(string $titre): string et pied(): string

echo entete('Accueil');
// <!doctype html><html lang="fr"><head><title>Accueil</title></head><body>
echo pied();
// </body></html>
Vérification Indice

Chaque fonction retourne un morceau de HTML. entete reçoit le titre à insérer dans <title> ; échappe-le avec htmlspecialchars(). pied n’a besoin d’aucun paramètre.

Vérification Solution
function entete(string $titre): string
{
$titre = htmlspecialchars($titre);
return '<!doctype html><html lang="fr"><head><title>'
. $titre . '</title></head><body>';
}
function pied(): string
{
return '</body></html>';
}

Exercice 3.2 : Charger des données depuis un fichier PHP

Section intitulée « Exercice 3.2 : Charger des données depuis un fichier PHP »

Pour séparer les données de l’affichage, on les range dans un fichier PHP à part. Un fichier qui se termine par return renvoie une valeur, et require la récupère.

Voici le fichier de données ; dans produits.php, charge ce tableau dans $produits, puis affiche la liste.

data/produits.php
<?php
return [
["nom" => "Sirop d'érable 540 ml", "prix" => 14.50],
["nom" => "Beurre d'érable 250 g", "prix" => 9.95],
["nom" => "Tire sur la neige", "prix" => 6.00],
];
Vérification Indice

Un fichier qui fait return [...] renvoie cette valeur à qui l’inclut. On la capture donc dans une variable : $donnees = require 'fichier.php';. Ensuite, $produits est un tableau ordinaire — count, foreach, etc.

Vérification Solution
produits.php
<?php
$produits = require 'data/produits.php';
echo count($produits) . ' produits au catalogue :';
foreach ($produits as $p) {
$prix = number_format($p['prix'], 2, ',', ' ');
echo '<p>' . htmlspecialchars($p['nom']) . '' . $prix . ' $</p>';
}
// → 3 produits au catalogue : Sirop d'érable 540 ml — 14,50 $ ...

Dernière pièce : produire la barre de navigation par une fonction, à partir d’une liste de pages (url => libellé), en mettant en évidence la page courante. C’est l’extension de l’exercice 2.3.

Signature : menu(array $pages, string $courant): string

$pages = ['accueil' => 'Accueil', 'contact' => 'Contact'];
menu($pages, 'contact');
// <nav><a href="accueil">Accueil</a><a href="contact" class="actif">Contact</a></nav>
Vérification Indice

Parcours le tableau avec foreach ($pages as $url => $libelle). Pour chaque entrée, ajoute class="actif" si $url === $courant. Accumule les liens dans une chaîne (.=), puis enveloppe le tout dans <nav>...</nav>. Pense à htmlspecialchars() sur le libellé.

Vérification Solution
function menu(array $pages, string $courant): string
{
$liens = '';
foreach ($pages as $url => $libelle) {
$libelle = htmlspecialchars($libelle);
$classe = $url === $courant ? ' class="actif"' : '';
$liens .= '<a href="' . $url . '"' . $classe . '>' . $libelle . '</a>';
}
return '<nav>' . $liens . '</nav>';
}