Exercice : Sauvegarder un formulaire dans un fichier JSON

    5tq

Exercice : Sauvegarder un formulaire en JSON

🎯 Objectif

Créer une page "Ajouter un message" qui :

  1. Affiche un formulaire
  2. Valide les données
  3. Les sauvegarde dans data/messages.json
  4. Redirige vers une liste qui affiche tous les messages

À la fin de cet exercice, tu sais faire de la persistance de données sans base de données.


Structure du projet

site-modulaire/
├── data/
│   └── messages.json        ← créé automatiquement
├── includes/
│   ├── header.php
│   ├── nav.php
│   └── footer.php
├── messages-liste.php       ← affiche tous les messages
└── messages-ajouter.php     ← formulaire + traitement

messages-ajouter.php — Formulaire + traitement

<?php
// ======================================================
// TRAITEMENT DU FORMULAIRE (si soumis)
// ======================================================
$erreurs = [];        // contiendra les messages d'erreur
$success = false;     // passera à true si tout est ok

if ($_SERVER["REQUEST_METHOD"] === "POST") {

    // --- 1. RÉCUPÉRER et nettoyer les données ---
    $nom     = trim($_POST["nom"]     ?? "");
    $email   = trim($_POST["email"]   ?? "");
    $message = trim($_POST["message"] ?? "");

    // --- 2. VALIDER ---
    if (empty($nom)) {
        $erreurs[] = "Le nom est obligatoire.";
    }
    if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $erreurs[] = "L'email est invalide.";
    }
    if (empty($message)) {
        $erreurs[] = "Le message est obligatoire.";
    } elseif (strlen($message) < 10) {
        $erreurs[] = "Le message doit faire au moins 10 caractères.";
    }

    // --- 3. SAUVEGARDER si pas d'erreurs ---
    if (empty($erreurs)) {

        $fichier = "data/messages.json";

        // Lire les messages existants (ou tableau vide si premier message)
        if (file_exists($fichier)) {
            $messages = json_decode(file_get_contents($fichier), true) ?? [];
        } else {
            $messages = [];
        }

        // Créer le nouvel enregistrement
        $nouveauMessage = [
            "id"      => time(),                        // identifiant unique (timestamp)
            "nom"     => $nom,
            "email"   => $email,
            "message" => $message,
            "date"    => date("d/m/Y à H:i"),           // ex: 14/04/2025 à 16:30
        ];

        // Ajouter à la fin du tableau
        $messages[] = $nouveauMessage;

        // Réécrire tout le fichier JSON
        file_put_contents(
            $fichier,
            json_encode($messages, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
        );

        // --- 4. REDIRIGER après succès (pattern PRG) ---
        header("Location: messages-liste.php?success=1");
        exit;
    }
}

// ======================================================
// AFFICHAGE DE LA PAGE
// ======================================================
$pageTitle = "Nouveau message";
require 'includes/header.php';
require 'includes/nav.php';
?>

<main class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-7">

            <h1>Envoyer un message</h1>

            <!-- Affiche les erreurs si il y en a -->
            <?php if (!empty($erreurs)) : ?>
                <div class="alert alert-danger">
                    <strong>Corrige les erreurs suivantes :</strong>
                    <ul class="mb-0 mt-2">
                        <?php foreach ($erreurs as $e) : ?>
                            <li><?= htmlspecialchars($e) ?></li>
                        <?php endforeach; ?>
                    </ul>
                </div>
            <?php endif; ?>

            <form method="POST" action="" class="mt-3">

                <div class="mb-3">
                    <label for="nom" class="form-label">Nom *</label>
                    <input type="text"
                           id="nom"
                           name="nom"
                           class="form-control <?= in_array("Le nom est obligatoire.", $erreurs) ? 'is-invalid' : '' ?>"
                           value="<?= htmlspecialchars($_POST['nom'] ?? '') ?>"
                           required>
                </div>

                <div class="mb-3">
                    <label for="email" class="form-label">Email *</label>
                    <input type="email"
                           id="email"
                           name="email"
                           class="form-control"
                           value="<?= htmlspecialchars($_POST['email'] ?? '') ?>"
                           required>
                </div>

                <div class="mb-3">
                    <label for="message" class="form-label">Message * (min. 10 caractères)</label>
                    <textarea id="message"
                              name="message"
                              class="form-control"
                              rows="5"
                              required><?= htmlspecialchars($_POST['message'] ?? '') ?></textarea>
                </div>

                <div class="d-flex gap-2">
                    <button type="submit" class="btn btn-primary">Envoyer ✉️</button>
                    <a href="messages-liste.php" class="btn btn-outline-secondary">Annuler</a>
                </div>

            </form>
        </div>
    </div>
</main>

<?php require 'includes/footer.php'; ?>

messages-liste.php — Afficher tous les messages

<?php
$pageTitle = "Messages reçus";
require 'includes/header.php';
require 'includes/nav.php';

// Lire les messages depuis le fichier JSON
$fichier = "data/messages.json";

if (file_exists($fichier)) {
    $messages = json_decode(file_get_contents($fichier), true) ?? [];
    // Afficher les plus récents en premier (inverser le tableau)
    $messages = array_reverse($messages);
} else {
    $messages = [];
}
?>

<main class="container mt-5">

    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1>Messages reçus</h1>
        <a href="messages-ajouter.php" class="btn btn-primary">+ Nouveau message</a>
    </div>

    <!-- Message de succès après redirection -->
    <?php if (isset($_GET['success'])) : ?>
        <div class="alert alert-success alert-dismissible fade show">
            ✅ Message envoyé avec succès !
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
        </div>
    <?php endif; ?>

    <?php if (empty($messages)) : ?>

        <div class="alert alert-info">
            Aucun message pour l'instant.
            <a href="messages-ajouter.php">Sois le premier !</a>
        </div>

    <?php else : ?>

        <?php foreach ($messages as $m) : ?>
            <div class="card mb-3 shadow-sm">
                <div class="card-body">
                    <div class="d-flex justify-content-between">
                        <h5 class="card-title mb-1"><?= htmlspecialchars($m['nom']) ?></h5>
                        <small class="text-muted"><?= htmlspecialchars($m['date']) ?></small>
                    </div>
                    <small class="text-muted"><?= htmlspecialchars($m['email']) ?></small>
                    <p class="card-text mt-2"><?= nl2br(htmlspecialchars($m['message'])) ?></p>
                </div>
            </div>
        <?php endforeach; ?>

    <?php endif; ?>

</main>

<?php require 'includes/footer.php'; ?>

Ce qu'il faut retenir

Opération Code PHP
Lire un JSON json_decode(file_get_contents($f), true)
Ajouter un élément $tableau[] = $nouvelElement
Écrire un JSON file_put_contents($f, json_encode($t, JSON_PRETTY_PRINT))
Vérifier si vide empty($tableau)
Inverser ordre array_reverse($tableau)
Date/heure date("d/m/Y à H:i")
Identifiant unique time() (timestamp Unix)

✅ Vérifie

  1. Envoie 3 messages → ils apparaissent dans messages-liste.php
  2. Ouvre data/messages.json dans VS Code → le JSON est bien formé
  3. Essaie de soumettre le formulaire vide → les erreurs s'affichent
  4. Après envoi, actualise la page liste → pas de re-soumission (grâce au redirect)

🏆 Challenge

  1. Ajoute un bouton "Supprimer" sur chaque message
    (indice : passe l'id en GET, filtre le tableau avec array_filter(), réécris)
  2. Affiche le nombre total de messages dans le titre
  3. Limite l'affichage aux 10 derniers messages

Pour aller plus loin