Formation DWWM — Générer du HTML avec PHP
2025 – 2026
Pourquoi on a besoin des boucles
<!-- ❌ HTML STATIQUE -->
<!-- 100 produits = 100 lignes à la main -->
<ul>
<li>Ordinateur — 899 €</li>
<li>Souris — 25 €</li>
<li>Clavier — 45 €</li>
<li>Écran — 299 €</li>
<!-- ...96 autres lignes... -->
</ul>
<!-- Problèmes :
Modifier un produit = éditer HTML
Données BDD → impossible en HTML
-->
<?php
// ✅ HTML DYNAMIQUE
// 100 produits = toujours 5 lignes
$produits = [
"Ordinateur", "Souris",
"Clavier", "Écran",
/* ...96 autres... */
];
?>
<ul>
<?php foreach ($produits as $p): ?>
<li><?= htmlspecialchars($p) ?></li>
<?php endforeach; ?>
</ul>
<!-- Données modifiées → HTML régénéré
Peut venir d'une BDD (PDO) -->
.php, exécute le code, et envoie du HTML pur au client. Le navigateur ne voit jamais de PHP.
<?php $nom = "Marie"; ?>
<p>Bonjour <?= $nom ?> !</p>
<!-- Le navigateur reçoit uniquement : -->
<p>Bonjour Marie !</p>
while, for, foreach, do…while
| Boucle | Quand l'utiliser | Cas typique |
|---|---|---|
while |
Répéter tant qu'une condition est vraie — nombre d'itérations inconnu à l'avance | Lire un fichier ligne par ligne |
for |
Répéter un nombre défini à l'avance de fois, avec un compteur | Générer une pagination, N étoiles |
foreach |
Parcourir chaque élément d'un tableau — la boucle du quotidien | Liste de produits, utilisateurs, articles… |
do…while |
Exécuter au moins une fois, puis répéter si la condition est vraie | Menu interactif, validation avec retry |
foreach couvre ~80% des cas — elle est conçue pour parcourir les tableaux venant de la base de données.while ⏳<?php
$i = 1;
while ($i <= 5) {
echo "<p>Itération n°$i</p>";
$i++; // ← OBLIGATOIRE ! Sans ça → boucle infinie 💀
}
// Génère :
// <p>Itération n°1</p>
// <p>Itération n°2</p> ...jusqu'à 5
?>
$i, la condition reste toujours vraie → le serveur plante. La condition doit finir par devenir false.for 🔢<?php
// ┌─ Init ┬─ Condition ┬─ Incrément
for ($i = 1; $i <= 5; $i++) {
echo "<p>Itération n°$i</p>";
}
// Cas concret : pagination HTML
$pageActuelle = 3;
$totalPages = 7;
?>
<nav>
<?php for ($p = 1; $p <= $totalPages; $p++): ?>
<a href="?page=<?= $p ?>"
<?= $p === $pageActuelle ? 'class="active"' : '' ?>>
<?= $p ?>
</a>
<?php endfor; ?>
</nav>
do…while 🔁while.
<?php
$page = 1;
do {
echo "<p>Page $page</p>";
$page++;
} while ($page <= 3);
// Génère : <p>Page 1</p> <p>Page 2</p> <p>Page 3</p>
// ── Différence clé avec while : ──────────────────
$x = 10;
while ($x < 5) {
echo "while : jamais affiché"; // condition fausse dès le début
}
do {
echo "do-while : affiché une fois !"; // s'exécute toujours au moins 1x
} while ($x < 5);
?>
foreach en profondeurLa boucle du quotidien en PHP
foreach 🔬<?php
$fruits = ["Pomme", "Banane", "Orange"];
// ┌─ Tableau à parcourir
// │ ┌─ Variable temporaire (nom libre)
foreach ($fruits as $fruit) {
echo "<li>$fruit</li>";
}
// Itération 1 : $fruit = "Pomme" → <li>Pomme</li>
// Itération 2 : $fruit = "Banane" → <li>Banane</li>
// Itération 3 : $fruit = "Orange" → <li>Orange</li>
// → foreach s'arrête automatiquement
?>
$fruit reçoit la valeur courante. Nom libre, choisissez quelque chose de lisible.{ } est répété autant de fois qu'il y a d'éléments.<?php
$langages = [
"HTML", "CSS",
"JavaScript", "PHP", "SQL"
];
?>
<h2>Langages appris</h2>
<ul>
<?php foreach ($langages as $lang): ?>
<li><?= htmlspecialchars($lang) ?></li>
<?php endforeach; ?>
</ul>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
<li>PHP</li>
<li>SQL</li>
</ul>
Ce que voit l'utilisateur :
as $cle => $valeur pour accéder aux deux simultanément.
<?php
$utilisateur = [
"nom" => "Dupont",
"prenom" => "Marie",
"email" => "marie@mail.com",
"role" => "admin",
];
// ┌─ Clé ┌─ Valeur
foreach ($utilisateur as $cle => $valeur) {
echo "<p><strong>$cle</strong> : $valeur</p>";
}
// <p><strong>nom</strong> : Dupont</p>
// <p><strong>prenom</strong> : Marie</p>
// <p><strong>email</strong> : marie@mail.com</p>
// <p><strong>role</strong> : admin</p>
?>
$cle => $valeur est optionnel. Si vous n'avez besoin que des valeurs : foreach ($tab as $valeur). Ajoutez la clé uniquement quand vous en avez besoin.| nom | categorie | prix |
|---|---|---|
| Laptop | informatique | 899 |
| Souris | informatique | 25 |
| T-shirt | vêtements | 15 |
| Jean | vêtements | 50 |
← Chaque ligne = un tableau associatif
<?php
// Identique à fetchAll(PDO::FETCH_ASSOC)
$produits = [
["nom"=>"Laptop",
"categorie"=>"informatique",
"prix"=>899],
["nom"=>"Souris",
"categorie"=>"informatique",
"prix"=>25],
// ...
];
// $produits[0] = ["nom"=>"Laptop"...]
// $produits[1] = ["nom"=>"Souris"...]
?>
<?php
$produits = [
["nom" => "Laptop", "categorie" => "informatique", "prix" => 899],
["nom" => "Souris", "categorie" => "informatique", "prix" => 25],
["nom" => "T-shirt", "categorie" => "vêtements", "prix" => 15],
];
?>
<table>
<thead>
<tr><th>Nom</th><th>Catégorie</th><th>Prix</th></tr>
</thead>
<tbody>
<?php foreach ($produits as $produit): ?>
<!-- $produit = ["nom"=>"Laptop", "categorie"=>"informatique", "prix"=>899] -->
<tr>
<td><?= htmlspecialchars($produit['nom']) ?></td>
<td><?= htmlspecialchars($produit['categorie']) ?></td>
<td><?= $produit['prix'] ?> €</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
$produit est un tableau associatif complet. On accède à ses champs avec $produit['nom'], $produit['prix'], etc.count() 🔢<?php
$fruits = ["Pomme", "Banane", "Orange", "Fraise"];
// ── L'index dans un foreach ──────────────────────────
// Méthode 1 : compteur manuel
$i = 0;
foreach ($fruits as $fruit) {
echo "<li>$i. $fruit</li>";
$i++;
}
// Méthode 2 : la clé du tableau (commence à 0)
foreach ($fruits as $index => $fruit) {
echo "<li>" . ($index + 1) . ". $fruit</li>"; // +1 → affiche 1, 2, 3...
}
// ── Compter et gérer le tableau vide ─────────────────
$total = count($fruits); // 4
echo "<p>$total fruits dans la liste</p>";
if (empty($fruits)) {
echo "<p>Aucun fruit disponible.</p>";
} else {
foreach ($fruits as $fruit) {
echo "<li>" . htmlspecialchars($fruit) . "</li>";
}
}
?>
empty() avant de boucler sur des données BDD — si la table est vide, on affiche un message utile plutôt qu'un tableau HTML vide.<?php
$etapes = ["Inscription", "Validation email", "Profil complété", "Terminé"];
$total = count($etapes);
?>
<ol>
<?php foreach ($etapes as $index => $etape): ?>
<?php
$estPremiere = ($index === 0);
$estDerniere = ($index === $total - 1);
?>
<li
<?php if ($estPremiere): ?>
style="color:#f0ad4e;font-weight:bold"
<?php elseif ($estDerniere): ?>
style="color:#5cb85c;font-weight:bold"
<?php endif; ?>
>
<?= $estPremiere ? '🚀' : ($estDerniere ? '✅' : '🔹') ?>
<?= htmlspecialchars($etape) ?>
</li>
<?php endforeach; ?>
</ol>
<?php
$catalogue = [
"Informatique" => [
["nom" => "Laptop", "prix" => 899],
["nom" => "Souris", "prix" => 25],
],
"Vêtements" => [
["nom" => "T-shirt", "prix" => 15],
["nom" => "Jean", "prix" => 50],
],
];
?>
<?php foreach ($catalogue as $categorie => $produits): ?>
<section>
<h2><?= htmlspecialchars($categorie) ?></h2>
<ul>
<?php foreach ($produits as $produit): ?>
<li>
<?= htmlspecialchars($produit['nom']) ?>
— <?= $produit['prix'] ?> €
</li>
<?php endforeach; ?>
</ul>
</section>
<?php endforeach; ?>
Syntaxe, bonnes pratiques et lisibilité
{ }<?php foreach ($items as $item) { ?>
<li><?= $item ?></li>
<?php } ?>
<?php if ($ok) { ?>
<p>Vrai</p>
<?php } else { ?>
<p>Faux</p>
<?php } ?>
✅ Familière
⚠️ Les } seules sont difficiles à lire quand le HTML est long
<?php foreach ($items as $item): ?>
<li><?= $item ?></li>
<?php endforeach; ?>
<?php if ($ok): ?>
<p>Vrai</p>
<?php else: ?>
<p>Faux</p>
<?php endif; ?>
✅ Plus lisible dans les fichiers PHP/HTML
✅ endforeach, endif indiquent ce qui se ferme
<?= vs <?php echo 📢<?= $var ?> est un raccourci strict pour <?php echo $var; ?>. Préférer la forme courte dans les templates pour réduire le bruit visuel.
<!-- Forme longue -->
<p><?php echo $nom; ?></p>
<!-- Forme courte ← préférer dans les templates -->
<p><?= $nom ?></p>
<!-- Avec htmlspecialchars() -->
<p><?php echo htmlspecialchars($nom); ?></p>
<p><?= htmlspecialchars($nom) ?></p>
<!-- Avec l'alias e() — ultra concis -->
<?php function e($t) { return htmlspecialchars($t, ENT_QUOTES, 'UTF-8'); } ?>
<p><?= e($nom) ?></p>
<?= est disponible depuis PHP 5.4 et toujours activé. Utilisez-le sans restriction dans tous vos projets PHP modernes.<!-- ❌ Logique mélangée dans le HTML -->
<ul>
<?php
$tous = [["nom"=>"Pomme","stock"=>5],
["nom"=>"Poire","stock"=>0],
["nom"=>"Kiwi", "stock"=>3]];
foreach ($tous as $p) {
if ($p['stock'] > 0) {
echo "<li>" . $p['nom'] . "</li>";
}
}
?>
</ul>
<?php
// ✅ LOGIQUE en haut du fichier
$tous = [["nom"=>"Pomme","stock"=>5],
["nom"=>"Poire","stock"=>0],
["nom"=>"Kiwi", "stock"=>3]];
$resultats = array_filter(
$tous, fn($p) => $p['stock'] > 0
);
?>
<!-- AFFICHAGE — HTML propre -->
<ul>
<?php foreach ($resultats as $p): ?>
<li><?= htmlspecialchars($p['nom']) ?></li>
<?php endforeach; ?>
</ul>
foreach, if et des <?= e($var) ?>.htmlspecialchars()Pourquoi c'est indispensable dans les boucles
<?php
$commentaires = [
"Super article !",
"<script>alert('Piraté!')</script>",
"Merci pour le partage.",
];
?>
<ul>
<?php foreach ($commentaires as $c): ?>
<!-- ❌ Le script s'EXÉCUTE ! -->
<li><?= $c ?></li>
<?php endforeach; ?>
</ul>
<?php
$commentaires = [
"Super article !",
"<script>alert('Piraté!')</script>",
"Merci pour le partage.",
];
?>
<ul>
<?php foreach ($commentaires as $c): ?>
<!-- ✅ Affiché comme texte brut -->
<li><?= htmlspecialchars($c) ?></li>
<?php endforeach; ?>
</ul>
htmlspecialchars() 🔍| Entrée (données brutes) | Sortie (HTML sécurisé) | Affiché |
|---|---|---|
Bonjour Marie | Bonjour Marie | Bonjour Marie ✅ |
<b>Gras</b> | <b>Gras</b> | <b>Gras</b> (texte) |
<script>hack()</script> | <script>...</script> | Texte brut ✅ |
5 & 10 € | 5 & 10 € | 5 & 10 € |
<?php
// Syntaxe complète recommandée
function e(string $text): string {
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
// ↑ ↑
// Échappe aussi ' Encodage du fichier
}
// Usage dans une boucle
foreach ($produits as $p) {
echo "<li>" . e($p['nom']) . " — " . e($p['categorie']) . "</li>";
}
?>
htmlspecialchars() ? 🎯<?php function e($t) { return htmlspecialchars($t, ENT_QUOTES, 'UTF-8'); } ?>
<!-- ✅ Dans le contenu d'un élément -->
<?php foreach ($articles as $a): ?>
<h2><?= e($a['titre']) ?></h2>
<p><?= e($a['contenu']) ?></p>
<?php endforeach; ?>
<!-- ✅ Dans les attributs HTML -->
<?php foreach ($produits as $p): ?>
<img src="img/<?= e($p['image']) ?>" alt="<?= e($p['nom']) ?>">
<a href="?id=<?= (int)$p['id'] ?>"><?= e($p['nom']) ?></a>
<?php endforeach; ?>
<!-- ⚠️ Données numériques : cast suffit, pas besoin de e() -->
<?php foreach ($produits as $p): ?>
<td><?= (int)$p['id'] ?></td>
<td><?= (float)$p['prix'] ?> €</td>
<td><?= e($p['nom']) ?></td> <!-- String → e() obligatoire -->
<?php endforeach; ?>
e() uniquement au moment d'afficher.
Listes, tableaux, cartes, menus — les structures du quotidien
<ul> / <ol> 📋<?php
$technologies = ["HTML", "CSS", "JavaScript", "PHP", "MySQL"];
$etapes = ["Analyse", "Maquette", "Développement", "Tests", "Livraison"];
?>
<h3>Technologies maîtrisées</h3>
<ul>
<?php foreach ($technologies as $tech): ?>
<li><?= htmlspecialchars($tech) ?></li>
<?php endforeach; ?>
</ul>
<h3>Étapes du projet</h3>
<ol>
<?php foreach ($etapes as $etape): ?>
<li><?= htmlspecialchars($etape) ?></li>
<?php endforeach; ?>
</ol>
<!-- Toujours gérer la liste vide -->
<?php if (empty($technologies)): ?>
<p>Aucune technologie disponible.</p>
<?php else: ?>
<ul>
<?php foreach ($technologies as $tech): ?>
<li><?= htmlspecialchars($tech) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<table> 📊<?php
$employes = [
["id"=>1, "nom"=>"Dupont", "prenom"=>"Marie", "salaire"=>2800],
["id"=>2, "nom"=>"Martin", "prenom"=>"Jean", "salaire"=>2600],
["id"=>3, "nom"=>"Bernard", "prenom"=>"Sophie", "salaire"=>3200],
];
?>
<table border="1">
<thead>
<tr><th>#</th><th>Nom</th><th>Prénom</th><th>Salaire</th></tr>
</thead>
<tbody>
<?php foreach ($employes as $e): ?>
<tr>
<td><?= (int)$e['id'] ?></td>
<td><?= htmlspecialchars($e['nom']) ?></td>
<td><?= htmlspecialchars($e['prenom']) ?></td>
<td><?= number_format($e['salaire'], 0, ',', ' ') ?> €</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<td colspan="3"><strong>Total</strong></td>
<td><?= number_format(array_sum(array_column($employes,'salaire')), 0, ',', ' ') ?> €</td>
</tr>
</tfoot>
</table>
% retourne le reste de la division entière. $i % 2 === 0 est vrai pour les index pairs (0, 2, 4…) et faux pour les impairs (1, 3, 5…) — idéal pour alterner deux couleurs.
<?php
$commandes = [
["id"=>1001, "client"=>"Marie D.", "montant"=>89.90, "statut"=>"Livré"],
["id"=>1002, "client"=>"Jean M.", "montant"=>245.00, "statut"=>"En cours"],
["id"=>1003, "client"=>"Sophie B.", "montant"=>12.50, "statut"=>"Livré"],
["id"=>1004, "client"=>"Pierre L.", "montant"=>399.99, "statut"=>"Annulé"],
];
?>
<table>
<?php foreach ($commandes as $i => $cmd): ?>
<tr style="background: <?= $i % 2 === 0 ? '#1a1a2e' : '#16213e' ?>">
<td><?= (int)$cmd['id'] ?></td>
<td><?= htmlspecialchars($cmd['client']) ?></td>
<td><?= number_format($cmd['montant'], 2, ',', ' ') ?> €</td>
<td><?= htmlspecialchars($cmd['statut']) ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php
$produits = [
["nom"=>"Laptop", "prix"=>1299, "stock"=>5, "badge"=>"Nouveau"],
["nom"=>"Souris", "prix"=>49, "stock"=>0, "badge"=>""],
["nom"=>"Clavier", "prix"=>89, "stock"=>12, "badge"=>"Promo"],
];
?>
<div class="grille">
<?php foreach ($produits as $p): ?>
<div class="carte <?= $p['stock'] === 0 ? 'epuise' : '' ?>">
<?php if (!empty($p['badge'])): ?>
<span class="badge"><?= htmlspecialchars($p['badge']) ?></span>
<?php endif; ?>
<h3><?= htmlspecialchars($p['nom']) ?></h3>
<p><?= number_format($p['prix'], 2, ',', ' ') ?> €</p>
<?php if ($p['stock'] === 0): ?>
<p style="color:red">Épuisé</p>
<?php else: ?>
<p style="color:green"><?= $p['stock'] ?> en stock</p>
<button>Ajouter au panier</button>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php
$pageCourante = "services";
$menu = [
["label"=>"Accueil", "url"=>"/", "slug"=>"accueil"],
["label"=>"Services", "url"=>"/services", "slug"=>"services"],
["label"=>"Portfolio", "url"=>"/portfolio", "slug"=>"portfolio"],
["label"=>"Contact", "url"=>"/contact", "slug"=>"contact"],
];
?>
<nav>
<ul>
<?php foreach ($menu as $lien): ?>
<?php $estActif = ($lien['slug'] === $pageCourante); ?>
<li>
<a href="<?= htmlspecialchars($lien['url']) ?>"
<?= $estActif ? 'class="actif" aria-current="page"' : '' ?>>
<?= htmlspecialchars($lien['label']) ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</nav>
aria-current="page" indique aux lecteurs d'écran quelle page est active — attribut d'accessibilité important à systématiser dans vos menus.<select> dynamique 📥<?php
$categories = [
"informatique" => "Informatique",
"vetements" => "Vêtements",
"sport" => "Sport & Loisirs",
"maison" => "Maison & Jardin",
];
$selectionne = $_GET['categorie'] ?? 'informatique';
?>
<select name="categorie">
<option value="">-- Choisir une catégorie --</option>
<?php foreach ($categories as $valeur => $label): ?>
<option
value="<?= htmlspecialchars($valeur) ?>"
<?= $valeur === $selectionne ? 'selected' : '' ?>>
<?= htmlspecialchars($label) ?>
</option>
<?php endforeach; ?>
</select>
<!--
Génère (si $selectionne === 'vetements') :
<option value="vetements" selected>Vêtements</option>
-->
selected sur la bonne option.À vous de jouer !
$films, générez :<h1> avec le nombre de films : "5 films disponibles"<ul> : chaque <li> affiche <strong>Titre</strong> (Année) — Genrehtmlspecialchars() sur toutes les strings
$films = [
["titre"=>"Inception", "annee"=>2010, "genre"=>"Science-fiction"],
["titre"=>"Le Parrain", "annee"=>1972, "genre"=>"Drame"],
["titre"=>"Interstellar", "annee"=>2014, "genre"=>"Science-fiction"],
["titre"=>"Pulp Fiction", "annee"=>1994, "genre"=>"Thriller"],
["titre"=>"Les Évadés", "annee"=>1994, "genre"=>"Drame"],
];
<?php
$films = [
["titre"=>"Inception", "annee"=>2010, "genre"=>"Science-fiction"],
["titre"=>"Le Parrain", "annee"=>1972, "genre"=>"Drame"],
["titre"=>"Interstellar", "annee"=>2014, "genre"=>"Science-fiction"],
["titre"=>"Pulp Fiction", "annee"=>1994, "genre"=>"Thriller"],
["titre"=>"Les Évadés", "annee"=>1994, "genre"=>"Drame"],
];
$total = count($films);
?>
<h1><?= $total ?> film<?= $total > 1 ? 's' : '' ?> disponible<?= $total > 1 ? 's' : '' ?></h1>
<?php if (empty($films)): ?>
<p>Aucun film disponible.</p>
<?php else: ?>
<ul>
<?php foreach ($films as $film): ?>
<li>
<strong><?= htmlspecialchars($film['titre']) ?></strong>
(<?= (int)$film['annee'] ?>)
— <?= htmlspecialchars($film['genre']) ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
$total > 1 ? 's' : '' gère le pluriel automatiquement — "1 film disponible" vs "5 films disponibles".<table> avec :$etudiants = [
["nom"=>"Dupont", "prenom"=>"Marie", "note"=>17.5],
["nom"=>"Martin", "prenom"=>"Jean", "note"=>13.0],
["nom"=>"Bernard", "prenom"=>"Sophie", "note"=>15.5],
["nom"=>"Leroy", "prenom"=>"Pierre", "note"=>11.0],
];
<?php
$etudiants = [
["nom"=>"Dupont", "prenom"=>"Marie", "note"=>17.5],
["nom"=>"Martin", "prenom"=>"Jean", "note"=>13.0],
["nom"=>"Bernard", "prenom"=>"Sophie", "note"=>15.5],
["nom"=>"Leroy", "prenom"=>"Pierre", "note"=>11.0],
];
function getMention(float $note): string {
if ($note >= 16) return "Très Bien";
if ($note >= 14) return "Bien";
if ($note >= 12) return "Assez Bien";
return "Passable";
}
?>
<table border="1" style="border-collapse:collapse;width:100%">
<thead>
<tr style="background:#4F86C6;color:white">
<th>#</th><th>Nom</th><th>Prénom</th><th>Note</th><th>Mention</th>
</tr>
</thead>
<tbody>
<?php foreach ($etudiants as $i => $e): ?>
<tr style="background:<?= $i % 2 === 0 ? '#f9f9f9' : '#fff' ?>;color:#222">
<td><?= $i + 1 ?></td>
<td><?= htmlspecialchars($e['nom']) ?></td>
<td><?= htmlspecialchars($e['prenom']) ?></td>
<td><?= number_format($e['note'], 1, ',', '') ?>/20</td>
<td><?= getMention($e['note']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
catalogue.php qui :$produits sur le nom avec stripos()htmlspecialchars()
$produits = [
["nom"=>"Laptop", "prix"=>899, "stock"=>3],
["nom"=>"Souris", "prix"=>25, "stock"=>0],
["nom"=>"Clavier", "prix"=>45, "stock"=>7],
["nom"=>"Écran 4K", "prix"=>399, "stock"=>2],
];
<?php
$produits = [
["nom"=>"Laptop", "prix"=>899, "stock"=>3],
["nom"=>"Souris", "prix"=>25, "stock"=>0],
["nom"=>"Clavier", "prix"=>45, "stock"=>7],
["nom"=>"Écran 4K", "prix"=>399, "stock"=>2],
];
$recherche = trim($_GET['q'] ?? '');
$resultats = $recherche !== ''
? array_filter($produits, fn($p) => stripos($p['nom'], $recherche) !== false)
: $produits;
?>
<form method="GET">
<input type="text" name="q" value="<?= htmlspecialchars($recherche) ?>" placeholder="Rechercher...">
<button>Filtrer</button>
<?php if ($recherche): ?><a href="?">✕ Effacer</a><?php endif; ?>
</form>
<p><?= count($resultats) ?> produit(s) trouvé(s)</p>
<div style="display:flex;gap:16px;flex-wrap:wrap">
<?php foreach ($resultats as $p): ?>
<div style="border:1px solid #ccc;padding:16px;border-radius:8px;width:150px">
<h3><?= htmlspecialchars($p['nom']) ?></h3>
<p><?= number_format($p['prix'], 2, ',', ' ') ?> €</p>
<?php if ($p['stock'] === 0): ?>
<p style="color:red">⚠️ Épuisé</p>
<?php else: ?>
<p style="color:green">✅ <?= $p['stock'] ?> en stock</p>
<button>Ajouter</button>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
$menu. La page courante vient de $_GET['page'] ?? 'accueil'.<span> (non cliquable) avec classe actif<?php
$menu = [
["label"=>"Accueil", "slug"=>"accueil"],
["label"=>"Services", "slug"=>"services"],
["label"=>"Portfolio", "slug"=>"portfolio"],
["label"=>"Contact", "slug"=>"contact"],
];
$slugsValides = array_column($menu, 'slug');
$pageRecue = $_GET['page'] ?? 'accueil';
// Liste blanche : on n'accepte que les slugs connus
$pageCourante = in_array($pageRecue, $slugsValides) ? $pageRecue : 'accueil';
?>
<nav><ul style="display:flex;list-style:none;gap:20px;padding:0">
<?php foreach ($menu as $lien): ?>
<?php $actif = ($lien['slug'] === $pageCourante); ?>
<li>
<?php if ($actif): ?>
<span style="color:#f0ad4e;font-weight:bold" aria-current="page">
<?= htmlspecialchars($lien['label']) ?>
</span>
<?php else: ?>
<a href="?page=<?= htmlspecialchars($lien['slug']) ?>">
<?= htmlspecialchars($lien['label']) ?>
</a>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul></nav>
foreach ($tab as $val) : tableau simpleforeach ($tab as $cle => $val) : associatif: endforeach dans les templateshtmlspecialchars() sur toutes les strings affichéesempty() avant de boucler sur des données BDDwhileempty() avant de bouclerforeach pour les tableaux: endforeach dans le HTMLhtmlspecialchars() sur toute string(int) / (float) pour les nombresfunction e($t) pour aller vite$_GET/$_POST brutsfetchAll(PDO::FETCH_ASSOC) retourne exactement un tableau de tableaux associatifs — votre foreach fonctionnera sans modification !array_filter(), array_map(), usort() pour transformer avant d'afficher🔄 foreach · 🛡️ htmlspecialchars · 🌐 HTML dynamique
= Le cœur du développement web PHP !