Cours PHP pour Débutants

Module 4 : PHP et MySQL - Connexion et CRUD

Niveau : Intermédiaire

Pourquoi connecter PHP à MySQL ?

Applications dynamiques

  • Stockage persistant des données
  • Gestion des utilisateurs et authentification
  • Contenu personnalisé pour chaque visiteur
  • Applications complexes (blogs, e-commerce, etc.)

Architecture typique

Client (Navigateur) → PHP (Serveur) → MySQL (Base de données)

PHP agit comme intermédiaire entre l'utilisateur et la base de données.

1. Connexion à MySQL avec PHP

Méthodes de connexion

Ancienne méthode (dépréciée)

<?php
// À ÉVITER - Non sécurisé et déprécié
$conn = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('ma_bdd');
?>

Vulnérable aux injections SQL. Ne plus utiliser.

Méthode recommandée (PDO)

<?php
try {
    $pdo = new PDO(
        'mysql:host=localhost;dbname=ma_bdd;charset=utf8',
        'user',
        'pass',
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
    );
} catch (PDOException $e) {
    die("Erreur connexion : " . $e->getMessage());
}
?>

Sécurisé, supporte plusieurs SGBD, gestion d'erreurs.

Bonnes pratiques

  • Utilisez PDO (PHP Data Objects) pour sa sécurité et flexibilité
  • Placez les informations de connexion dans un fichier séparé (config.php)
  • Ne stockez jamais les mots de passe en clair dans le code
  • Utilisez le charset UTF-8 pour supporter tous les caractères
  • Activez le mode erreur avec PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION

2. Requêtes Préparées

Pourquoi utiliser des requêtes préparées ?

Sécurité

Protection contre les injections SQL, une des vulnérabilités les plus critiques.

Sans requête préparée

// DANGEREUX - Injection SQL possible
$sql = "SELECT * FROM users WHERE id = $id";

Avec requête préparée

// SÉCURISÉ - Les données sont échappées
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);

Performance

Meilleures performances pour les requêtes répétitives.

  • Le plan d'exécution est compilé une seule fois
  • Seules les données changent entre les exécutions
  • Réduction de la charge serveur

Types de requêtes préparées

SELECT
INSERT
UPDATE
DELETE
<?php
// Préparation
$stmt = $pdo->prepare("SELECT * FROM articles WHERE categorie = ? AND publie = ?");

// Exécution avec paramètres
$stmt->execute(['technologie', 1]);

// Récupération des résultats
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);

// Utilisation
foreach ($articles as $article) {
    echo "<h2>{$article['titre']}</h2>";
}
?>
<?php
// Préparation
$stmt = $pdo->prepare("INSERT INTO utilisateurs 
    (nom, email, mot_de_passe) 
    VALUES (?, ?, ?)");

// Exécution avec paramètres
$success = $stmt->execute([
    'Alice', 
    'alice@exemple.com', 
    password_hash('monmotdepasse', PASSWORD_DEFAULT)
]);

// Vérification
if ($success) {
    $id = $pdo->lastInsertId();
    echo "Nouvel ID : $id";
}
?>
<?php
// Préparation
$stmt = $pdo->prepare("UPDATE articles 
    SET titre = ?, contenu = ? 
    WHERE id = ?");

// Exécution avec paramètres
$success = $stmt->execute([
    'Nouveau titre', 
    'Nouveau contenu...', 
    42
]);

// Vérification
if ($success) {
    echo "{$stmt->rowCount()} ligne(s) modifiée(s)";
}
?>
<?php
// Préparation
$stmt = $pdo->prepare("DELETE FROM commentaires 
    WHERE id = ? AND utilisateur_id = ?");

// Exécution avec paramètres
$success = $stmt->execute([15, 42]);

// Vérification
if ($success && $stmt->rowCount() > 0) {
    echo "Commentaire supprimé";
} else {
    echo "Erreur ou aucun commentaire supprimé";
}
?>

3. CRUD Complet avec PHP/MySQL

Application de gestion d'articles

Structure de la table

CREATE TABLE articles (
    id INT AUTO_INCREMENT PRIMARY KEY,
    titre VARCHAR(255) NOT NULL,
    contenu TEXT NOT NULL,
    date_creation DATETIME DEFAULT CURRENT_TIMESTAMP,
    date_modification DATETIME ON UPDATE CURRENT_TIMESTAMP,
    auteur_id INT NOT NULL,
    FOREIGN KEY (auteur_id) REFERENCES utilisateurs(id)
);

Fichier de configuration

<?php
// config.php
return [
    'db' => [
        'host' => 'localhost',
        'dbname' => 'monblog',
        'user' => 'root',
        'pass' => '',
        'charset' => 'utf8mb4'
    ]
];

Implémentation du CRUD

Create - Création d'un article

<?php
// create_article.php
require 'config.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $titre = $_POST['titre'] ?? '';
    $contenu = $_POST['contenu'] ?? '';
    $auteurId = $_SESSION['user_id'] ?? 0;
    
    try {
        $pdo = new PDO(
            "mysql:host={$config['db']['host']};dbname={$config['db']['dbname']};charset={$config['db']['charset']}",
            $config['db']['user'],
            $config['db']['pass'],
            [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
        );
        
        $stmt = $pdo->prepare("INSERT INTO articles 
            (titre, contenu, auteur_id) 
            VALUES (?, ?, ?)");
            
        $stmt->execute([$titre, $contenu, $auteurId]);
        
        header("Location: article.php?id=" . $pdo->lastInsertId());
        exit;
    } catch (PDOException $e) {
        die("Erreur : " . $e->getMessage());
    }
}
?>

Read - Lecture d'articles

<?php
// list_articles.php
require 'config.php';

try {
    $pdo = new PDO(...); // Voir connexion précédente
    
    // Récupérer tous les articles
    $stmt = $pdo->query("SELECT * FROM articles ORDER BY date_creation DESC");
    $articles = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    // Afficher les articles
    foreach ($articles as $article) {
        echo "<article>";
        echo "<h2>{$article['titre']}</h2>";
        echo "<p>{$article['contenu']}</p>";
        echo "</article>";
    }
} catch (PDOException $e) {
    die("Erreur : " . $e->getMessage());
}
?>

Update - Modification d'un article

<?php
// update_article.php
require 'config.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $id = $_POST['id'] ?? 0;
    $titre = $_POST['titre'] ?? '';
    $contenu = $_POST['contenu'] ?? '';
    $auteurId = $_SESSION['user_id'] ?? 0;
    
    try {
        $pdo = new PDO(...); // Voir connexion précédente
        
        // Vérifier que l'auteur est bien le propriétaire
        $stmt = $pdo->prepare("SELECT id FROM articles 
            WHERE id = ? AND auteur_id = ?");
        $stmt->execute([$id, $auteurId]);
        
        if ($stmt->rowCount() === 0) {
            die("Article non trouvé ou non autorisé");
        }
        
        // Mettre à jour l'article
        $stmt = $pdo->prepare("UPDATE articles 
            SET titre = ?, contenu = ? 
            WHERE id = ?");
            
        $stmt->execute([$titre, $contenu, $id]);
        
        header("Location: article.php?id=$id");
        exit;
    } catch (PDOException $e) {
        die("Erreur : " . $e->getMessage());
    }
}
?>

Delete - Suppression d'un article

<?php
// delete_article.php
require 'config.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $id = $_POST['id'] ?? 0;
    $auteurId = $_SESSION['user_id'] ?? 0;
    
    try {
        $pdo = new PDO(...); // Voir connexion précédente
        
        // Vérifier les droits
        $stmt = $pdo->prepare("SELECT id FROM articles 
            WHERE id = ? AND auteur_id = ?");
        $stmt->execute([$id, $auteurId]);
        
        if ($stmt->rowCount() === 0) {
            die("Article non trouvé ou non autorisé");
        }
        
        // Supprimer l'article
        $stmt = $pdo->prepare("DELETE FROM articles WHERE id = ?");
        $stmt->execute([$id]);
        
        header("Location: articles.php");
        exit;
    } catch (PDOException $e) {
        die("Erreur : " . $e->getMessage());
    }
}
?>

Exercice Pratique

Système de gestion de tâches

Créez une application de gestion de tâches avec :

  1. Une base de données avec une table taches
  2. Un script PHP pour ajouter des tâches
  3. Une page pour lister toutes les tâches
  4. La possibilité de marquer une tâche comme terminée
  5. La possibilité de supprimer des tâches
  6. Une protection contre les injections SQL

Solution Guidée