Apprendre PHP

PDO en PHP : connexion + requêtes préparées (anti-injection SQL)

01 mars 2026 | 5 min de lecture
Retour aux apprendre php






1) Connexion propre à MySQL avec PDO


Si vous concaténez encore des variables dans du SQL, vous vous exposez à l’injection SQL. Avec PDO, on sépare la requête (structure) des données (valeurs).



[php]$host = ‘localhost’;
$db = ‘ma_base’;
$user = ‘root’;
$pass =  »;
$charset = ‘utf8mb4’;

$dsn = « mysql:host=$host;dbname=$db;charset=$charset »;

$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // exceptions
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // tableau associatif
PDO::ATTR_EMULATE_PREPARES => false, // vraies requêtes préparées
];

try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
die(« Erreur connexion :  » . $e->getMessage());
}[/php]

Pourquoi ces options sont importantes



  • ATTR_ERRMODE = EXCEPTION : oblige à gérer les erreurs proprement.

  • FETCH_ASSOC : récupère des tableaux associatifs (plus lisible).

  • EMULATE_PREPARES = false : demande à MySQL de préparer réellement la requête (meilleure protection).

  • utf8mb4 : gère correctement les emojis et la plupart des caractères Unicode.




Astuce : gardez la création de $pdo dans un fichier dédié (ex : db.php) et incluez-le là où vous en avez besoin. Ça évite de dupliquer la config et ça rend le code plus maintenable.




2) SELECT avec requête préparée


Exemple : table users (id, email, password).



[php]$email = $_GET[’email’] ??  »;

$sql = « SELECT * FROM users WHERE email = :email »;

$stmt = $pdo->prepare($sql);
$stmt->execute([’email’ => $email]);

$user = $stmt->fetch();

if ($user) {
echo $user[’email’];
}[/php]

Règle : ne concaténez jamais une variable utilisateur dans le SQL.




Mauvais : injection SQL potentielle.


[php]$email = $_GET[’email’] ??  »;
$sql = « SELECT * FROM users WHERE email = ‘$email' »;[/php]



3) INSERT sécurisé


Pour un mot de passe, utilisez password_hash(). Jamais de stockage en clair.



[php]$email = $_POST[’email’] ??  »;
$password = $_POST[‘password’] ??  »;

$sql = « INSERT INTO users (email, password) VALUES (:email, :password) »;
$stmt = $pdo->prepare($sql);

$stmt->execute([
’email’ => $email,
‘password’ => password_hash($password, PASSWORD_DEFAULT),
]);[/php]


Note : pour être propre, validez aussi l’email (ex : filter_var($email, FILTER_VALIDATE_EMAIL)) et gérez le cas “email déjà utilisé” côté base (index UNIQUE).




4) UPDATE


Cast de l’ID en int et requête préparée, toujours.



[php]$newEmail = $_POST[’email’] ??  »;
$userId = (int)($_POST[‘id’] ?? 0);

$sql = « UPDATE users SET email = :email WHERE id = :id »;
$stmt = $pdo->prepare($sql);

$stmt->execute([
’email’ => $newEmail,
‘id’ => $userId,
]);[/php]



5) Pourquoi les requêtes préparées protègent de l’injection SQL


Un attaquant peut tenter d’envoyer une valeur du type :



[sql]test@example.com’ OR 1=1 –[/sql]

Sans requête préparée, la requête devient :



[sql]SELECT * FROM users WHERE email = ‘test@example.com’ OR 1=1 –‘[/sql]

Résultat : vous pouvez retourner toute la table.




Info : avec une requête préparée, la structure SQL est préparée séparément et la valeur est transmise comme donnée. La chaîne ci-dessus ne peut pas “casser” la requête : elle est traitée littéralement.




6) Gérer les erreurs : dev vs prod



En développement


[php]ini_set(‘display_errors’, 1);
error_reporting(E_ALL);[/php]

En production


[php]ini_set(‘display_errors’, 0);
ini_set(‘log_errors’, 1);[/php]


Attention : ne jamais afficher des erreurs SQL en production. Ça leak des infos (structure de tables, chemins, versions) exploitables par un attaquant.




7) Exemple complet minimal fonctionnel


Une page simple : récupération d’un utilisateur par id, requête préparée, sortie échappée.



[php]$pdo = new PDO(
« mysql:host=localhost;dbname=ma_base;charset=utf8mb4 »,
« root »,
«  »,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]
);

$id = (int)($_GET[‘id’] ?? 0);

$stmt = $pdo->prepare(« SELECT * FROM users WHERE id = :id »);
$stmt->execute([‘id’ => $id]);

$user = $stmt->fetch();

if ($user) {
echo htmlspecialchars($user[’email’], ENT_QUOTES, ‘UTF-8’);
} else {
echo « Utilisateur introuvable. »;
}[/php]



8) Erreurs fréquentes



  • Oublier charset=utf8mb4 dans le DSN (problèmes d’encodage).

  • Concaténer des variables utilisateur dans le SQL (injection SQL).

  • Afficher les erreurs SQL en production (fuite d’informations).

  • Oublier PDO::ATTR_EMULATE_PREPARES => false.

  • Stocker des mots de passe en clair (utilisez password_hash() / password_verify()).





Conclusion


PDO + requêtes préparées, c’est la base : plus sûr, plus propre, plus maintenable. Si votre code PHP touche une base, partez sur PDO.




À faire ensuite :

  • Authentification en PHP : login/logout + sessions + protections (session fixation, timeout, etc.)

  • Transactions PDO : beginTransaction(), commit(), rollBack()

  • Structurer un mini “repository” PDO réutilisable (DRY)



GET vs POST : lequel choisir et pourquoi

Objectif : comprendre en profondeur la différence entre GET vs POST en PHP, savoir quand utiliser chaque méthode HTTP selon le contexte (SEO, sécurité, logique métier, API) et éviter les erreurs d’architecture fréquentes. Choisir entre GET et POST en PHP…

Formulaire PHP POST : validation propre + gestion erreurs

Traiter un formulaire PHP POST semble simple : on récupère $_POST et on fait “le truc”. En réalité, c’est là que commencent les failles (XSS), les erreurs utilisateur mal gérées et les doublons de soumission. Dans ce tutoriel, vous allez…