Chapitre 17 : Projet final

Écouter la leçon Lecture audio assistée par IA

1. Introduction au projet

Félicitations ! Vous avez parcouru tous les chapitres du module PHP. Il est maintenant temps de mettre en pratique tout ce que vous avez appris avec un projet complet.

Nous allons créer un Carnet de contacts qui permettra de :

  • ✅ Ajouter un nouveau contact
  • ✅ Afficher la liste des contacts
  • ✅ Modifier un contact existant
  • ✅ Supprimer un contact

Ce projet mettra en œuvre : les variables, les tableaux, les fonctions, les formulaires, la gestion des fichiers, et la gestion des erreurs.

2. Cahier des charges

Fonctionnalités requises

  • Créer (Create) : Formulaire pour ajouter un contact (nom, email, téléphone)
  • Lire (Read) : Afficher tous les contacts dans un tableau
  • Modifier (Update) : Éditer les informations d'un contact
  • Supprimer (Delete) : Retirer un contact de la liste

Contraintes techniques

  • Stockage des données dans un fichier JSON
  • Validation des données (email valide, champs obligatoires)
  • Gestion des erreurs avec try/catch
  • Interface simple et claire

3. Structure du projet

Créez un dossier carnet-contacts avec les fichiers suivants :

carnet-contacts/
├── index.php          (page principale)
├── contacts.json      (stockage des données)
└── style.css          (optionnel : styles CSS)

4. Code complet : index.php

Voici le code complet du projet avec commentaires détaillés :

<?php
// ============================================
// CARNET DE CONTACTS - Projet PHP
// ============================================

// Fichier de stockage des contacts
$fichierContacts = 'contacts.json';

// Initialiser le fichier s'il n'existe pas
if (!file_exists($fichierContacts)) {
    file_put_contents($fichierContacts, json_encode([]));
}

// ============================================
// FONCTIONS
// ============================================

/**
 * Lire tous les contacts depuis le fichier JSON
 */
function lireContacts($fichier) {
    try {
        $contenu = file_get_contents($fichier);
        return json_decode($contenu, true) ?? [];
    } catch (Exception $e) {
        error_log("Erreur lecture : " . $e->getMessage());
        return [];
    }
}

/**
 * Sauvegarder les contacts dans le fichier JSON
 */
function sauvegarderContacts($fichier, $contacts) {
    try {
        $json = json_encode($contacts, JSON_PRETTY_PRINT);
        file_put_contents($fichier, $json);
        return true;
    } catch (Exception $e) {
        error_log("Erreur sauvegarde : " . $e->getMessage());
        return false;
    }
}

/**
 * Valider les données d'un contact
 */
function validerContact($nom, $email, $telephone) {
    $erreurs = [];

    if (empty($nom)) {
        $erreurs[] = "Le nom est obligatoire";
    }

    if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $erreurs[] = "L'email est invalide";
    }

    if (empty($telephone)) {
        $erreurs[] = "Le téléphone est obligatoire";
    }

    return $erreurs;
}

// ============================================
// TRAITEMENT DES ACTIONS
// ============================================

$message = '';
$contacts = lireContacts($fichierContacts);

// Ajouter un contact
if (isset($_POST['ajouter'])) {
    $nom = htmlspecialchars($_POST['nom'] ?? '');
    $email = htmlspecialchars($_POST['email'] ?? '');
    $telephone = htmlspecialchars($_POST['telephone'] ?? '');

    $erreurs = validerContact($nom, $email, $telephone);

    if (empty($erreurs)) {
        $nouveauContact = [
            'id' => uniqid(),
            'nom' => $nom,
            'email' => $email,
            'telephone' => $telephone
        ];

        $contacts[] = $nouveauContact;

        if (sauvegarderContacts($fichierContacts, $contacts)) {
            $message = "✅ Contact ajouté avec succès !";
        } else {
            $message = "❌ Erreur lors de la sauvegarde";
        }
    } else {
        $message = "❌ " . implode(", ", $erreurs);
    }
}

// Supprimer un contact
if (isset($_GET['supprimer'])) {
    $id = $_GET['supprimer'];
    $contacts = array_filter($contacts, function($contact) use ($id) {
        return $contact['id'] !== $id;
    });

    // Réindexer le tableau
    $contacts = array_values($contacts);

    if (sauvegarderContacts($fichierContacts, $contacts)) {
        $message = "✅ Contact supprimé";
    }
}

// Modifier un contact
if (isset($_POST['modifier'])) {
    $id = $_POST['id'];
    $nom = htmlspecialchars($_POST['nom'] ?? '');
    $email = htmlspecialchars($_POST['email'] ?? '');
    $telephone = htmlspecialchars($_POST['telephone'] ?? '');

    $erreurs = validerContact($nom, $email, $telephone);

    if (empty($erreurs)) {
        foreach ($contacts as &$contact) {
            if ($contact['id'] === $id) {
                $contact['nom'] = $nom;
                $contact['email'] = $email;
                $contact['telephone'] = $telephone;
                break;
            }
        }

        if (sauvegarderContacts($fichierContacts, $contacts)) {
            $message = "✅ Contact modifié avec succès !";
        }
    } else {
        $message = "❌ " . implode(", ", $erreurs);
    }
}

// Récupérer le contact à modifier
$contactAModifier = null;
if (isset($_GET['modifier'])) {
    $id = $_GET['modifier'];
    foreach ($contacts as $contact) {
        if ($contact['id'] === $id) {
            $contactAModifier = $contact;
            break;
        }
    }
}

?>

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Carnet de Contacts</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: Arial, sans-serif;
            background: #f4f4f4;
            padding: 20px;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 { color: #333; margin-bottom: 20px; }
        .message {
            padding: 10px;
            margin-bottom: 20px;
            border-radius: 5px;
            background: #d4edda;
            color: #155724;
        }
        form {
            margin-bottom: 30px;
            padding: 20px;
            background: #f9f9f9;
            border-radius: 5px;
        }
        input {
            width: 100%;
            padding: 10px;
            margin: 5px 0 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        button {
            padding: 10px 20px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        button:hover { background: #0056b3; }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        th { background: #007bff; color: white; }
        .actions a {
            margin-right: 10px;
            color: #007bff;
            text-decoration: none;
        }
        .actions a:hover { text-decoration: underline; }
        .supprimer { color: #dc3545; }
    </style>
</head>
<body>
    <div class="container">
        <h1>📒 Carnet de Contacts</h1>

        <?php if ($message): ?>
            <div class="message"><?= $message ?></div>
        <?php endif; ?>

        <!-- Formulaire d'ajout/modification -->
        <form method="POST">
            <h2><?= $contactAModifier ? 'Modifier' : 'Ajouter' ?> un contact</h2>

            <?php if ($contactAModifier): ?>
                <input type="hidden" name="id" value="<?= $contactAModifier['id'] ?>">
            <?php endif; ?>

            <label>Nom :</label>
            <input type="text" name="nom"
                   value="<?= $contactAModifier['nom'] ?? '' ?>" required>

            <label>Email :</label>
            <input type="email" name="email"
                   value="<?= $contactAModifier['email'] ?? '' ?>" required>

            <label>Téléphone :</label>
            <input type="tel" name="telephone"
                   value="<?= $contactAModifier['telephone'] ?? '' ?>" required>

            <button type="submit" name="<?= $contactAModifier ? 'modifier' : 'ajouter' ?>">
                <?= $contactAModifier ? '✏️ Modifier' : '➕ Ajouter' ?>
            </button>

            <?php if ($contactAModifier): ?>
                <a href="index.php"><button type="button">Annuler</button></a>
            <?php endif; ?>
        </form>

        <!-- Liste des contacts -->
        <h2>Liste des contacts (<?= count($contacts) ?>)</h2>

        <?php if (empty($contacts)): ?>
            <p>Aucun contact pour le moment.</p>
        <?php else: ?>
            <table>
                <thead>
                    <tr>
                        <th>Nom</th>
                        <th>Email</th>
                        <th>Téléphone</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($contacts as $contact): ?>
                        <tr>
                            <td><?= htmlspecialchars($contact['nom']) ?></td>
                            <td><?= htmlspecialchars($contact['email']) ?></td>
                            <td><?= htmlspecialchars($contact['telephone']) ?></td>
                            <td class="actions">
                                <a href="?modifier=<?= $contact['id'] ?>">✏️ Modifier</a>
                                <a href="?supprimer=<?= $contact['id'] ?>"
                                   class="supprimer"
                                   onclick="return confirm('Supprimer ce contact ?')">
                                   🗑️ Supprimer
                                </a>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        <?php endif; ?>
    </div>
</body>
</html>

5. Explications du code

Fonctions principales

  • lireContacts() : Lit le fichier JSON et retourne un tableau de contacts
  • sauvegarderContacts() : Enregistre les contacts dans le fichier JSON
  • validerContact() : Vérifie que les données sont valides

Sécurité

  • Utilisation de htmlspecialchars() pour éviter les injections XSS
  • Validation de l'email avec filter_var()
  • Gestion des erreurs avec try/catch

Fonctionnalités CRUD

  • Create : Formulaire POST avec action "ajouter"
  • Read : Affichage dans un tableau HTML
  • Update : Formulaire pré-rempli avec action "modifier"
  • Delete : Lien GET avec confirmation JavaScript

6. Améliorations possibles

Pour aller plus loin, vous pouvez :

  • 🔍 Ajouter une fonction de recherche
  • 📊 Trier les contacts par nom
  • 🎨 Améliorer le design avec Bootstrap ou Tailwind
  • 💾 Utiliser une base de données MySQL au lieu de JSON
  • 🔐 Ajouter un système d'authentification
  • 📱 Rendre l'interface responsive
  • 📸 Ajouter des photos de profil

7. Exercice : Testez votre application

  1. Créez le dossier carnet-contacts
  2. Copiez le code dans index.php
  3. Lancez votre serveur local (XAMPP, Laragon, etc.)
  4. Accédez à http://localhost/carnet-contacts/
  5. Testez toutes les fonctionnalités : ajout, modification, suppression

Conclusion

🎉 Félicitations ! Vous avez terminé le module PHP et créé votre première application complète.

Ce projet vous a permis de mettre en pratique :

  • ✅ Les variables et les tableaux
  • ✅ Les fonctions
  • ✅ Les formulaires et la validation
  • ✅ La manipulation de fichiers
  • ✅ La gestion des erreurs
  • ✅ Les opérations CRUD

Vous êtes maintenant prêt à explorer des concepts plus avancés comme les bases de données MySQL, la programmation orientée objet, ou les frameworks PHP comme Laravel !

Évaluation des acquis

Quiz du chapitre 17

Correction immédiate
Ateliers pratiques & Projets

Testez vos compétences avec nos exercices guidés et le tuteur IA.

Ateliers pratiques & Corrigés détaillés

Ateliers pratiques & Corrigés

#1 — Calculatrice simple
Atelier #1

Crée un script calculette (CLI) qui demande deux nombres et une opération (+, -, *, /) puis affiche le résultat.

Correction instantanée et bienveillante
Diagnostic du tuteur IA Weegosoft :
Consulter la solution type du formateur
Solution de référence :
<?php $n1 = (float) readline("Nombre 1 : "); $op = readline("Opération (+, -, *, /) : "); $n2 = (float) readline("Nombre 2 : "); switch ($op) { case '+': echo $n1 + $n2; break; case '-': echo $n1 - $n2; break; case '*': echo $n1 * $n2; break; case '/': if ($n2 == 0) echo "Erreur div/0"; else echo $n1 / $n2; break; default: echo "Opération inconnue"; } ?>
#2 — Carnet de contacts (Tableau)
Atelier #2

Crée un tableau de contacts (nom, tel). Permets à l'utilisateur d'ajouter un contact via readline et affiche la liste.

Correction instantanée et bienveillante
Diagnostic du tuteur IA Weegosoft :
Consulter la solution type du formateur
Solution de référence :
<?php $contacts = []; while (true) { $choix = readline("1: Ajouter, 2: Lister, 3: Quitter > "); if ($choix == 3) break; if ($choix == 1) { $nom = readline("Nom : "); $tel = readline("Tel : "); $contacts[] = ["nom" => $nom, "tel" => $tel]; } elseif ($choix == 2) { foreach ($contacts as $c) { echo "- {$c['nom']} : {$c['tel']}\n"; } } } ?>
#3 — Générateur de mot de passe
Atelier #3

Crée une fonction qui génère un mot de passe aléatoire de N caractères (lettres+chiffres).

Correction instantanée et bienveillante
Diagnostic du tuteur IA Weegosoft :
Consulter la solution type du formateur
Solution de référence :
<?php function genererPass($longueur = 8) { $chars = "abcdefghijklmnopqrstuvwxyzABCD1234567890"; $pass = ""; for ($i = 0; $i < $longueur; $i++) { $pass .= $chars[rand(0, strlen($chars) - 1)]; } return $pass; } echo "Mot de passe : " . genererPass(12); ?>
Précédent
Besoin d'aide ?
Tuteur Virtuel
Bonjour ! Je suis votre tuteur virtuel. Comment puis-je vous aider avec ce cours aujourd'hui ?
Historique des conversations
Chargement...