Chapitre 38 : Projet final – Blog dynamique
Créez un système de blog complet en PHP avec une interface publique et une interface d'administration
1. Objectif du projet
Développer un blog dynamique avec :
- Gestion complète des articles (CRUD)
- Système de commentaires
- Espace d'administration sécurisé
- Interface responsive
2. Structure de la base de données
-- Table des articles
CREATE TABLE `articles` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`titre` VARCHAR(255) NOT NULL,
`slug` VARCHAR(255) NOT NULL UNIQUE,
`contenu` LONGTEXT NOT NULL,
`auteur` VARCHAR(100) NOT NULL,
`date_creation` DATETIME DEFAULT CURRENT_TIMESTAMP,
`date_modification` DATETIME ON UPDATE CURRENT_TIMESTAMP,
`image` VARCHAR(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Table des commentaires
CREATE TABLE `commentaires` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`article_id` INT NOT NULL,
`auteur` VARCHAR(100) NOT NULL,
`email` VARCHAR(255) NOT NULL,
`contenu` TEXT NOT NULL,
`date_creation` DATETIME DEFAULT CURRENT_TIMESTAMP,
`approuve` TINYINT(1) DEFAULT 0,
FOREIGN KEY (`article_id`)
REFERENCES `articles`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Table des utilisateurs (pour l'administration)
CREATE TABLE `utilisateurs` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`email` VARCHAR(180) NOT NULL UNIQUE,
`roles` JSON NOT NULL,
`password` VARCHAR(255) NOT NULL,
`nom` VARCHAR(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3. Exemples de code clés
Connexion à la base de données (PDO)
<?php
// config/database.php
declare(strict_types=1);
$host = 'localhost';
$dbname = 'blog_php';
$username = 'root';
$password = '';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
];
try {
$pdo = new PDO(
"mysql:host=$host;dbname=$dbname;charset=utf8mb4",
$username,
$password,
$options
);
} catch (PDOException $e) {
error_log('Erreur de connexion : ' . $e->getMessage());
header('HTTP/1.1 500 Database Error');
exit('Une erreur de base de données est survenue');
}
Modèle Article
<?php
// src/Model/Article.php
declare(strict_types=1);
class Article
{
private ?int $id;
private string $titre;
private string $slug;
private string $contenu;
private string $auteur;
private DateTime $dateCreation;
private ?DateTime $dateModification;
private ?string $image;
public function __construct(
string $titre,
string $slug,
string $contenu,
string $auteur,
?string $image = null,
?int $id = null,
?DateTime $dateCreation = null,
?DateTime $dateModification = null
) {
$this->id = $id;
$this->titre = $titre;
$this->slug = $slug;
$this->contenu = $contenu;
$this->auteur = $auteur;
$this->image = $image;
$this->dateCreation = $dateCreation ?? new DateTime();
$this->dateModification = $dateModification;
}
// Getters et méthodes de persistence...
}
4. Espace d'administration
<?php
// admin/index.php
declare(strict_types=1);
require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/../config/bootstrap.php';
use App\Auth;
use App\Controller\AdminController;
// Sécurité
if (!Auth::check()) {
header('Location: login.php');
exit;
}
// Routing basique
$action = $_GET['action'] ?? 'dashboard';
try {
$controller = new AdminController();
switch ($action) {
case 'articles':
$controller->listArticles();
break;
case 'edit-article':
$id = $_GET['id'] ?? null;
$controller->editArticle($id);
break;
case 'delete-article':
$controller->deleteArticle((int)$_GET['id']);
break;
case 'comments':
$controller->manageComments();
break;
default:
$controller->dashboard();
}
} catch (Exception $e) {
error_log($e->getMessage());
header('HTTP/1.1 500 Internal Server Error');
exit('Une erreur est survenue');
}
5. Résumé du projet
- ✅ Architecture MVC moderne
- ✅ Sécurité renforcée (XSS, CSRF, SQLi, injections)
- ✅ Validation des données côté serveur
- ✅ Gestion des erreurs et logs
- ✅ Interface responsive et accessible