Mini-projets Projet 2
Un livre d'or
La base de données en SQL, puis la page PHP qui reçoit les messages d'un formulaire et les affiche sans faille XSS.
À la fin de ce projet, tu sauras
- Créer la table d'une application et la remplir
- Lire les données dans le bon ordre
- Traiter un formulaire en PHP et protéger l'affichage
- Ranger ses fonctions dans un fichier séparé
Ce que tu vas construire
Un livre d'or : les visiteurs laissent un petit message, et la page affiche tous les messages, du plus récent au plus ancien. C'est le schéma de presque toutes les applications web :
- une base de données garde les messages (SQL) ;
- un formulaire HTML envoie un nouveau message ;
- une page PHP vérifie ce qui arrive, l'enregistre et affiche la liste.
Les cours utilisés
- SQL : créer des tables, ajouter des lignes, trier ;
- PHP : formulaires, fonctions, inclure un fichier.
Attention : tout ce qu'un visiteur écrit doit passer par htmlspecialchars() avant d'être affiché. Sinon, quelqu'un peut glisser du code JavaScript dans un message, qui s'exécuterait chez tous les autres visiteurs : c'est la faille XSS.
À retenir
- Une application web = une base de données + des formulaires + des pages qui lisent et affichent.
CREATE TABLEavecNOT NULLpour les champs obligatoires ;INSERT INTO … VALUESpour ajouter.ORDER BY id DESC: du plus récent au plus ancien.- En PHP :
trim($_POST["x"] ?? ""), vérifier que ce n'est pas vide, puis enregistrer. - Toujours
htmlspecialchars()à l'affichage : contre la faille XSS.
Voir la fiche de révision de cette leçon (à imprimer ou à relire avant un contrôle)
Étape 1 · Créer la table messages
Facile ✓ RéussiCrée la table messages avec trois colonnes : id (INTEGER PRIMARY KEY), auteur et contenu (TEXT NOT NULL). Puis ajoute deux messages :
- id 1, auteur
Léa, contenuSuper site !; - id 2, auteur
Tom, contenuMerci pour les cours.
Écris une requête : elle s'exécute pendant que tu tapes, sur une base d'exemple qui repart de zéro à chaque fois.
Voir les tables de la base d'exemple
classes (3 lignes)
| id | nom |
|---|---|
| 1 | BTS SIO 1 |
| 2 | BTS SIO 2 |
| 3 | Terminale STMG |
eleves (7 lignes)
| id | prenom | nom | age | ville | classe_id |
|---|---|---|---|---|---|
| 1 | Léa | Martin | 18 | Chartres | 1 |
| 2 | Tom | Bernard | 19 | Dreux | 2 |
| 3 | Inès | Petit | 18 | Chartres | 1 |
| 4 | Hugo | Durand | 20 | Paris | 2 |
| 5 | Chloé | Lambert | 17 | Lucé | 3 |
| 6 | Nathan | Dubois | 19 | Chartres | 1 |
| 7 | Sarah | Moreau | 18 | Dreux | NULL |
notes (9 lignes)
| id | eleve_id | matiere | note |
|---|---|---|---|
| 1 | 1 | Développement | 16 |
| 2 | 1 | Réseau | 12 |
| 3 | 2 | Développement | 11 |
| 4 | 2 | Réseau | 15 |
| 5 | 3 | Développement | 18 |
| 6 | 4 | Réseau | 9 |
| 7 | 6 | Développement | 13 |
| 8 | 6 | Réseau | 14 |
| 9 | 5 | Gestion | 15 |
Consignes à réussir
- À faire : Les requêtes s'exécutent sans erreur
- À faire : La table messages a les colonnes id, auteur et contenu
- À faire : La table contient exactement les deux messages
- À faire : auteur et contenu sont obligatoires (NOT NULL)
Bravo, cet exercice est réussi !
- Indice 1 :
CREATE TABLE messages ( id INTEGER PRIMARY KEY, auteur TEXT NOT NULL, contenu TEXT NOT NULL ); - Indice 2 : Un message :
INSERT INTO messages (id, auteur, contenu) VALUES (1, 'Léa', 'Super site !'); - Indice 3 : Les textes SQL sont entre apostrophes simples, et chaque requête finit par
;.
Toujours bloqué ? Voir une solution
CREATE TABLE messages (
id INTEGER PRIMARY KEY,
auteur TEXT NOT NULL,
contenu TEXT NOT NULL
);
INSERT INTO messages (id, auteur, contenu) VALUES (1, 'Léa', 'Super site !');
INSERT INTO messages (id, auteur, contenu) VALUES (2, 'Tom', 'Merci pour les cours.'); Étape 2 · Lire les messages
Moyen ✓ RéussiLa table existe (les requêtes de l'étape 1 sont déjà en haut, avec un troisième message). Ajoute en dessous la requête que la page utilisera : elle renvoie seulement l'auteur et le contenu, du message le plus récent (le plus grand id) au plus ancien.
Écris une requête : elle s'exécute pendant que tu tapes, sur une base d'exemple qui repart de zéro à chaque fois.
Voir les tables de la base d'exemple
classes (3 lignes)
| id | nom |
|---|---|
| 1 | BTS SIO 1 |
| 2 | BTS SIO 2 |
| 3 | Terminale STMG |
eleves (7 lignes)
| id | prenom | nom | age | ville | classe_id |
|---|---|---|---|---|---|
| 1 | Léa | Martin | 18 | Chartres | 1 |
| 2 | Tom | Bernard | 19 | Dreux | 2 |
| 3 | Inès | Petit | 18 | Chartres | 1 |
| 4 | Hugo | Durand | 20 | Paris | 2 |
| 5 | Chloé | Lambert | 17 | Lucé | 3 |
| 6 | Nathan | Dubois | 19 | Chartres | 1 |
| 7 | Sarah | Moreau | 18 | Dreux | NULL |
notes (9 lignes)
| id | eleve_id | matiere | note |
|---|---|---|---|
| 1 | 1 | Développement | 16 |
| 2 | 1 | Réseau | 12 |
| 3 | 2 | Développement | 11 |
| 4 | 2 | Réseau | 15 |
| 5 | 3 | Développement | 18 |
| 6 | 4 | Réseau | 9 |
| 7 | 6 | Développement | 13 |
| 8 | 6 | Réseau | 14 |
| 9 | 5 | Gestion | 15 |
Consignes à réussir
- À faire : Les requêtes s'exécutent sans erreur
- À faire : Seulement les colonnes auteur et contenu
- À faire : Trié du plus récent au plus ancien
- À faire : Le résultat est le bon : Inès, Tom, puis Léa
Bravo, cet exercice est réussi !
- Indice 1 : On choisit les colonnes après
SELECT:SELECT auteur, contenu FROM messages. - Indice 2 : Pour trier :
ORDER BY id. Du plus grand au plus petit :DESC. - Indice 3 :
SELECT auteur, contenu FROM messages ORDER BY id DESC;
Toujours bloqué ? Voir une solution
CREATE TABLE messages (
id INTEGER PRIMARY KEY,
auteur TEXT NOT NULL,
contenu TEXT NOT NULL
);
INSERT INTO messages (id, auteur, contenu) VALUES (1, 'Léa', 'Super site !');
INSERT INTO messages (id, auteur, contenu) VALUES (2, 'Tom', 'Merci pour les cours.');
INSERT INTO messages (id, auteur, contenu) VALUES (3, 'Inès', 'Très clair, merci !');
-- ta requête :
SELECT auteur, contenu FROM messages ORDER BY id DESC; Étape 3 · La page PHP
Pour aller plus loin ✓ RéussiLe formulaire envoie deux champs en POST : auteur et contenu. Pour l'exercice, il envoie l'auteur Hugo et le contenu <b>Bravo</b>, qui contient du HTML : il ne doit pas être interprété.
- dans
fonctions.php, écrisafficherMessage(array $message): stringqui renvoie<p><strong>auteur</strong> : contenu</p>, l'auteur et le contenu passés parhtmlspecialchars(); - dans
index.php, inclusfonctions.phpavecrequire_once; - récupère
$_POST["auteur"]et$_POST["contenu"](avec?? ""ettrim) ; s'ils ne sont pas vides, ajoute le message au tableau$messages; - affiche chaque message avec
foreachet ta fonction.
Clique sur ▶ Exécuter (ou Ctrl + Entrée) pour lancer ton code.
Données envoyées par le formulaire
Consignes à réussir
- À faire : fonctions.php définit afficherMessage
- À faire : L'affichage passe par htmlspecialchars
- À faire : index.php inclut fonctions.php
- À faire : Les champs vides sont refusés
- À faire : La page affiche les trois messages ▶ vérifié quand tu exécutes
- À faire : Le HTML du visiteur est neutralisé (<b>) ▶ vérifié quand tu exécutes
Bravo, cet exercice est réussi !
- Indice 1 : Dans
fonctions.php:return "<p><strong>" . htmlspecialchars($message["auteur"]) . "</strong> : " . htmlspecialchars($message["contenu"]) . "</p>"; - Indice 2 : Dans
index.php:$auteur = trim($_POST["auteur"] ?? "");, pareil pour$contenu, puisif ($auteur !== "" && $contenu !== "") { $messages[] = [...]; }. - Indice 3 : Pour finir :
foreach ($messages as $message) { echo afficherMessage($message); }
Toujours bloqué ? Voir une solution
index.php
<?php
// les messages déjà enregistrés (dans un vrai site, ils viendraient de la base avec un SELECT)
$messages = [
["auteur" => "Léa", "contenu" => "Super site !"],
["auteur" => "Tom", "contenu" => "Merci pour les cours."],
];
// 1. inclure fonctions.php
require_once "fonctions.php";
// 2. récupérer et vérifier le nouveau message envoyé par le formulaire
$auteur = trim($_POST["auteur"] ?? "");
$contenu = trim($_POST["contenu"] ?? "");
if ($auteur !== "" && $contenu !== "") {
$messages[] = ["auteur" => $auteur, "contenu" => $contenu];
}
// 3. afficher tous les messages
foreach ($messages as $message) {
echo afficherMessage($message);
} fonctions.php
<?php
function afficherMessage(array $message): string
{
return "<p><strong>" . htmlspecialchars($message["auteur"]) . "</strong> : " . htmlspecialchars($message["contenu"]) . "</p>";
} Défi réussi !
Ton badge Mini-projets passe en or dès que toutes les leçons du cours sont terminées. Retrouve tes badges sur la page d'accueil.