Aller au contenu

PDO

Dans le contexte de PHP et MySQL, une API (Application Programming Interface) désigne un ensemble de fonctions et de méthodes permettant d'interagir avec une base de données MySQL. L'API fournit une couche d'abstraction entre le code PHP et le système de gestion de base de données (SGBD) MySQL. Cela permet aux développeurs d'exécuter des opérations sur la base de données (lecture, écriture, mise à jour, suppression) sans se soucier des détails de la communication bas niveau avec le serveur MySQL.

PHP propose deux APIs principales pour se connecter à une base de données MySQL :

MySQLi (MySQL Improved)

  • Mode mixte : Peut être utilisé en mode orienté objet ou procédural.
  • Fonctionnalités avancées : Supporte des fonctionnalités comme les transactions et les prepared statements.
  • Gestion des erreurs améliorée : Facilite le débogage des problèmes de connexion ou d'exécution.
  • Spécifique à MySQL : Convient uniquement pour les bases de données MySQL.
  • Versions prises en charge : Nécessite MySQL 4.1.3 ou plus récent.

PDO (PHP Data Objects)

  • Interface orientée objet : Offre une syntaxe plus moderne et structurée.
  • Polyvalence : Permet de se connecter à différents types de bases de données (MySQL, PostgreSQL, SQLite, etc.).
  • Prepared Statements : Aide à prévenir les injections SQL en séparant la requête SQL des données d'entrée.
  • Gestion des exceptions : Fournit un mécanisme robuste pour capturer et gérer les erreurs.

Tip

PDO est souvent préféré pour sa flexibilité et sa capacité à interagir avec différents systèmes de gestion de base de données. Cependant, MySQLi peut être une bonne option pour des projets spécifiques à MySQL, surtout si on souhaite tirer parti des fonctionnalités avancées propres à MySQL.

➡️ Documentation MySQLi

➡️ Documentation PDO

Connexion à une base de données avec PDO

➡️ PHP - PDO - Connections and Connection management

Pour établir une connexion avec PDO, suivez ces étapes :

  1. Créer une instance de la classe PDO : Cela ouvre la connexion à la base de données. Vous devez fournir les informations de connexion sous forme de chaîne DSN (Data Source Name), ainsi que le nom d'utilisateur et le mot de passe pour accéder à la base de données.

  2. Gérer les exceptions : Il est recommandé d'entourer le code de connexion par un bloc try-catch pour capturer les exceptions en cas de problème de connexion.

Exemple : Connexion à une base de données MySQL

<?php
$host = 'localhost';
$dbname = 'my_db';
$dsn = "mysql:host=$host;dbname=$dbname";
$username = 'username';
$password = 'password';

try {
    // Crée une instance PDO pour se connecter à la base de données
    $dbh = new PDO($dsn, $username, $password);

    // Configure le mode d'erreur pour lancer des exceptions
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    
} catch (PDOException $e) {
    // Capture l'erreur et affiche un message
    echo "Error : {$e->getMessage()}";
}

Explications

  • $host : Le nom d'hôte ou l'adresse IP du serveur où réside la base de données MySQL.
  • $dbname : Le nom de la base de données à laquelle vous souhaitez vous connecter.
  • $username et $password : Les identifiants nécessaires pour se connecter à la base de données.
  • DSN ($dsn) : La chaîne DSN (Data Source Name) spécifie le type de base de données, l'hôte, et le nom de la base de données.
  • PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION : Configure PDO pour lancer une exception en cas d'erreur, ce qui facilite le débogage et la journalisation.

Points importants

  • Sécurité : Évitez de stocker les informations sensibles (comme les mots de passe) en texte brut dans le code. Utilisez des variables d'environnement ou des fichiers de configuration sécurisés.
  • Gestion des erreurs : Configurer le mode d'erreur de PDO avec PDO::ERRMODE_EXCEPTION est essentiel pour capturer et gérer les problèmes de connexion ou d'exécution.
  • Centralisation : Pour des projets complexes, centralisez les connexions à la base de données dans une classe ou un fichier séparé pour une meilleure réutilisation et maintenance.

Requête préparée

➡️ PHP - PDO - Prepared statements and stored procedures

Les requêtes préparées sont un moyen efficace et sûr de communiquer avec une base de données. Elles rendent le code plus lisible et plus simple à maintenir, tout en séparant la logique SQL de la logique de programmation.

Avantages

  • Prévention des injections SQL :
    • En utilisant des marqueurs de paramètre au lieu d'insérer directement les valeurs dans la requête, vous empêchez les attaquants d'injecter du code SQL malveillant.
  • Amélioration des performances :
    • Si la même requête est exécutée plusieurs fois avec différentes valeurs, la requête est compilée une seule fois. Le serveur de base de données peut alors réutiliser le plan d'exécution, accélérant ainsi les exécutions répétées.
  • Lisibilité et maintenance :
    • La séparation des données et de la logique SQL facilite la compréhension et la gestion du code.

Fonctionnement

  1. Préparation de la requête

    • La requête SQL est envoyée au serveur de base de données avec des marqueurs de paramètre (placeholders) au lieu des valeurs réelles.
    • Ces marqueurs peuvent être :
      • ? : Placeholders anonymes.
      • :name : Placeholders nommés.
  2. Compilation de la requête par le serveur

    • Le serveur de base de données analyse, compile et optimise le plan d'exécution de la requête.
    • À ce stade, la requête n'a pas encore été exécutée.
  3. Liaison des valeurs

    • Les valeurs réelles sont transmises au serveur et associées aux marqueurs de paramètre.
    • Cette étape peut être répétée plusieurs fois avec différentes valeurs sans nécessiter une nouvelle compilation de la requête.
  4. Exécution de la requête

    • Finalement, la requête est exécutée avec les valeurs liées.

Exemple

id name email
1 Alice Dupont alice.dupont@example.com
2 Bob Martin bob.martin@example.com
3 Claire Lune claire.lune@example.com
4 Daniel Morand daniel.morand@example.com
<?php
$name = 'Bob Martin';
$email = 'bob.martin@example.com';

$query = 'SELECT * FROM user WHERE name = :name AND email = :email';
// Préparation de la requête (Étapes 1 + 2)
$stmt = $dbh->prepare($query);

// Liaison des valeurs (Étape 3)
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);

// Exécution de la requête (Étape 4)
$stmt->execute();

// Récupération des résultats
while ($row = $stmt->fetch()) {
    // Traitement de chaque ligne de résultat
    var_dump($row);
}

Dans cet exemple, :name et :email sont des marqueurs de paramètre. Leur valeur est liée ultérieurement via bindParam(). Cela garantit que les valeurs insérées dans la requête sont échappées (encodage des caractères spéciaux) et traitées correctement par le serveur de base de données, ce qui prévient les injections SQL.

pdo-prepared-statement.png

Récupération des données

Lors de l'utilisation de PDO pour interagir avec une base de données MySQL en PHP, plusieurs méthodes permettent de récupérer les résultats d'une requête. Ces méthodes offrent une flexibilité en fonction des besoins de traitement des résultats.

fetch()

➡️ PHP - PDO - fetch

  • Récupère la prochaine ligne du jeu de résultats sous forme de tableau associatif, tableau indexé, ou les deux.
  • Utilisé généralement dans une boucle pour traiter les lignes une par une.
  • Exemple : $row = $stmt->fetch(PDO::FETCH_ASSOC);
<?php
$query = 'SELECT * FROM user';
$stmt = $dbh->prepare($query);
$stmt->execute();

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    var_dump($row);
}

pdo-fetch.png

fetchAll()

➡️ PHP - PDO - fetchAll

  • Récupère toutes les lignes du jeu de résultats et les retourne sous forme de tableau.
  • Utile quand on a besoin de traiter ou d'afficher toutes les lignes en même temps.
  • Exemple : $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
<?php
$query = 'SELECT * FROM user';
$stmt = $dbh->prepare($query);
$stmt->execute();

$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($rows);

pdo-fetchAll.png

fetchColumn()

➡️ PHP - PDO - fetchColumn

  • Récupère une seule colonne de la prochaine ligne du jeu de résultats.
  • Utile pour récupérer une valeur unique d'une requête, comme un compte ou une somme.
  • Exemple : $column = $stmt->fetchColumn();
<?php
$query = 'SELECT * FROM user';
$stmt = $dbh->prepare($query);
$stmt->execute();

while ($column = $stmt->fetchColumn(1)) {
    var_dump($column);
}

pdo-fetchColumn.png

Points importants

  • PDO::FETCH_ASSOC : Retourne un tableau associatif avec les noms de colonnes comme clés.

  • PDO::FETCH_NUM : Retourne un tableau indexé numériquement.

  • PDO::FETCH_BOTH : Retourne un tableau avec les noms de colonnes comme clés et des index numériques.

Performances

  • Préférez fetch() ou fetchColumn() pour des itérations ligne par ligne.

  • Utilisez fetchAll() uniquement si toutes les données doivent être traitées simultanément.

Chaque méthode est adaptée à un cas d'utilisation spécifique et peut être utilisée pour améliorer l'efficacité et la lisibilité du code.

Récupérer une valeur auto-incrémentée

➡️ PHP - PDO - lastInsertId

La méthode lastInsertId() de l'objet PDO permet de récupérer l'ID généré automatiquement par une colonne avec un auto-increment pour la dernière ligne insérée dans une table MySQL. Cette méthode est utile pour obtenir la clé primaire d'une nouvelle insertion, par exemple pour l'utiliser dans d'autres opérations.

<?php
$name = 'John Doe';
$email = 'john.doe@example.com';

$query = 'INSERT INTO user (name, email) VALUES (:name, :email)';
$stmt = $dbh->prepare($query);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->execute();

// Récupération de l'ID auto-incrémenté
$last_id = $dbh->lastInsertId();
echo "The ID of the newly inserted line is: $last_id";

pdo-lastInsertId.png

id name email
1 Alice Dupont alice.dupont@example.com
2 Bob Martin bob.martin@example.com
3 Claire Lune claire.lune@example.com
4 Daniel Morand daniel.morand@example.com
5 John Doe john.doe@example.com

Transaction

➡️ PHP - PDO - Transactions and auto-commit

Les transactions dans les bases de données garantissent que des séries d'opérations sont effectuées de manière complète et cohérente. Si une erreur survient, toutes les modifications effectuées depuis le début de la transaction peuvent être annulées, évitant ainsi les données incohérentes. Les transactions sont particulièrement utiles pour gérer plusieurs opérations interconnectées dans des environnements avec plusieurs utilisateurs ou processus.

Exemple : Ajouter un utilisateur et un achat associé

Table user

id name email
1 Alice Dupont alice.dupont@example.com
2 Bob Martin bob.martin@example.com
3 Claire Lune claire.lune@example.com
4 Daniel Morand daniel.morand@example.com

Table purchase

id user_id date amount
1 1 2023-01-15 150.00
2 2 2023-01-17 200.00
3 1 2023-02-01 25.00

Imaginons un scénario où l'on doit ajouter un nouvel utilisateur dans la table user et enregistrer un achat associé à ce nouvel utilisateur dans la table purchase. L'utilisation d'une transaction garantira que soit les deux opérations (insert dans user et purchase) réussissent, soit aucune ne sera appliquée en cas d'erreur.

Structure de l'exemple

  1. Démarrer une transaction
  2. Ajouter un nouvel utilisateur dans la table user.
  3. Ajouter un achat pour ce nouvel utilisateur dans la table purchase.
  4. Si les deux opérations réussissent, valider la transaction.
  5. En cas d'erreur, annuler la transaction pour éviter des données incohérentes.
<?php
$dbh = new PDO($dsn, $username, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    // Début de la transaction (Étape 1)
    $dbh->beginTransaction();

    // Ajouter un utilisateur (Étape 2)
    $name = 'Eva Petit';
    $email = 'eva.petit@example.com';
    $query = 'INSERT INTO user (name, email) VALUES (:name, :email)';
    $stmt = $dbh->prepare($query);
    $stmt->bindParam(':name', $name);
    $stmt->bindParam(':email', $email);
    $stmt->execute();
    $user_id = $dbh->lastInsertId();

    // Ajouter un achat pour cet utilisateur (Étape 3)
    $date = '2023-03-15';
    $amount = 100.0;
    $query = 'INSERT INTO purchase (user_id, date, amount) VALUES (:user_id, :date, :amount)';
    $stmt = $dbh->prepare($query);
    $stmt->bindParam(':user_id', $user_id);
    $stmt->bindParam(':date', $date);
    $stmt->bindParam(':amount', $amount);
    $stmt->execute();

    // Validation de la transaction (Étape 4)
    $dbh->commit();
    echo 'Successful transaction: User and purchase added.';
} catch (PDOException $e) {
    // Annuler la transaction en cas d'erreur (Étape 5)
    $dbh->rollBack();
    echo "Transaction error: {$e->getMessage()}";
}

pdo-example.png

Table user

id name email
1 Alice Dupont alice.dupont@example.com
2 Bob Martin bob.martin@example.com
3 Claire Lune claire.lune@example.com
4 Daniel Morand daniel.morand@example.com
5 Eva Petit eva.petit@example.com

Table purchase

id user_id date amount
1 1 2023-01-15 150.00
2 2 2023-01-17 200.00
3 1 2023-02-01 25.00
4 5 2023-03-15 100.00

Points clés

  • Transaction : Toutes les opérations SQL sont exécutées dans une transaction pour garantir que soit tout est validé, soit tout est annulé.
  • lastInsertId() : Permet de récupérer l'ID généré automatiquement pour l'insertion dans une autre table.
  • Gestion des erreurs : Le bloc try-catch capture les exceptions et annule la transaction (rollBack()) en cas d'échec.
  • Atomicité : Les transactions garantissent que toutes les opérations associées sont exécutées comme une seule unité.

Les transactions sont essentielles pour assurer l'intégrité des données, surtout lorsqu'il s'agit de modifications dans plusieurs tables.