# PHP et bases de données : PDO et mysqli

> PHP et bases de données : PDO et mysqli comparés, requêtes préparées, gestion des erreurs depuis PHP 8 et identifiants d'accès sûrs en exploitation.

Source : https://phpsos.de/fr/php/php-und-datenbanken/  
État : 25/10/2026  
Fournisseur : PHP SOS, Assistance d'urgence PHP et sécurité des serveurs. Aide immédiate par WhatsApp : https://wa.me/491736494914?text=Bonjour%20PHP%20SOS%2C%20nous%20avons%20besoin%20d%27aide%20avec%20notre%20serveur%20PHP.%20Entreprise%20%3A%20%E2%80%A6%20Site%20web%20%3A%20%E2%80%A6

**En bref :** PHP accède aux bases de données via deux interfaces répandues : PDO (PHP Data Objects) fonctionne avec de nombreux systèmes de bases de données via une interface unifiée, mysqli est conçu pour MySQL et MariaDB. Avec les deux, les requêtes préparées, c'est-à-dire des requêtes avec marqueurs, protègent de façon fiable contre l'injection SQL. Depuis PHP 8.0 (PDO) et 8.1 (mysqli), les deux signalent par défaut les erreurs sous forme d'exception.

## Comment PHP dialogue avec les bases de données

Presque toute application PHP stocke ses contenus dans une base de données : pages, commandes, comptes utilisateurs, réglages. Le script PHP établit pour cela une connexion, envoie une requête dans le langage SQL et traite le résultat. Les identifiants d'accès figurent le plus souvent dans un fichier de configuration sur le même serveur.

C'est important pour la direction, car la base de données contient généralement les données les plus précieuses de l'entreprise. Qui peut exécuter du code sur le serveur web peut en règle générale aussi lire le fichier de configuration et accéder à la base avec ces identifiants.

## PDO et mysqli comparés

| Caractéristique | PDO | mysqli |
|---|---|---|
| Bases de données | nombreuses, via des pilotes comme `PDO_MYSQL`, `PDO_PGSQL`, `PDO_SQLITE`, `PDO_SQLSRV`, `PDO_OCI` | MySQL et MariaDB |
| Marqueurs | nommés (`:name`) et positionnels (`?`) | positionnels (`?`) |
| Style | orienté objet | orienté objet et procédural |
| Erreurs sous forme d'exception | par défaut depuis PHP 8.0.0 | par défaut depuis PHP 8.1.0 |
| Forme abrégée pour les requêtes avec paramètres | `prepare()` et `execute()` avec un tableau | `execute_query()` depuis PHP 8.2.0 |

En pratique, c'est souvent le framework ou le CMS qui décide. Beaucoup apportent leur propre couche de base de données, qui utilise en interne PDO ou mysqli. Qui reprend une application peut déterminer, par une simple recherche dans le code source, quelle interface est utilisée et où naissent les requêtes :

```bash
# Où l'application établit-elle des connexions, où naissent les requêtes ?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
```

Les occurrences de `->query(` ne sont pas automatiquement peu sûres. Mais elles méritent un second regard, car des valeurs peuvent y atterrir directement dans le texte SQL, au lieu d'être transmises par des marqueurs. Les projets plus anciens mélangent précisément les deux styles, et la vérification vaut la peine avant toute mise à jour importante.

## Requêtes préparées : le schéma le plus important

Avec une requête préparée, la requête est envoyée à la base avec des marqueurs et les valeurs sont transmises séparément. Selon le manuel PHP, cela protège contre l'injection SQL si toutes les saisies utilisateur passent par des marqueurs.

```php
<?php
declare(strict_types=1);

$pdo = new PDO(
    'mysql:host=localhost;dbname=shop;charset=utf8mb4',
    $dbUser,
    $dbPass,
    [PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);

$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE plz = :plz AND aktiv = :aktiv');
$stmt->execute(['plz' => $plz, 'aktiv' => 1]);

foreach ($stmt as $zeile) {
    echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}
```

La même chose avec mysqli, dans la forme abrégée disponible depuis PHP 8.2 :

```php
<?php
$db = new mysqli('localhost', $dbUser, $dbPass, 'shop');
$ergebnis = $db->execute_query('SELECT id, name FROM kunden WHERE plz = ?', [$plz]);

foreach ($ergebnis as $zeile) {
    echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}
```

Les développeurs devraient connaître deux limites. Les marqueurs ne doivent pas être placés entre guillemets ; pour les recherches `LIKE`, les caractères joker `%` font partie de la valeur transmise. Et les marqueurs ne remplacent que des valeurs, pas des noms de tables ou de colonnes. La manière de résoudre ces cas particuliers en toute sécurité est montrée dans le guide [Empêcher l'injection SQL en PHP](https://phpsos.de/fr/ratgeber/sql-injection-php/).

## Gestion des erreurs : des exceptions plutôt que des erreurs silencieuses

Autrefois, les deux interfaces fonctionnaient par défaut de façon silencieuse : une requête échouée renvoyait `false`, et qui ne le vérifiait pas continuait à travailler avec des données vides. Cela a changé :

- **PDO :** depuis PHP 8.0.0, `PDO::ERRMODE_EXCEPTION` est la valeur par défaut. Les erreurs lèvent une `PDOException`.
- **mysqli :** depuis PHP 8.1.0, le signalement des erreurs est réglé sur `MYSQLI_REPORT_ERROR` et `MYSQLI_REPORT_STRICT`. Les erreurs lèvent une `mysqli_sql_exception` ; auparavant, le signalement était désactivé.

Pour la sécurité, cela signifie : les exceptions doivent être interceptées et consignées, mais ne doivent jamais aboutir dans le navigateur avec du texte SQL, des noms de tables ou des identifiants. La manière de bien séparer cela est décrite sur la page [Erreurs et exceptions en PHP](https://phpsos.de/fr/php/fehler-und-exceptions/).

## Attribuer correctement identifiants et droits

La base de données n'est protégée que dans la mesure où le sont ses identifiants. Ces règles ont fait leurs preuves :

1. **Un utilisateur distinct par application :** ne jamais utiliser l'administrateur de la base pour le site web.
2. **Seuls les droits nécessaires :** un site web a généralement besoin de lire, écrire, modifier et supprimer dans sa propre base, mais pas de droits sur d'autres bases ni sur des fonctions du serveur.
3. **Pas de connexion à distance sans raison :** la base ne devrait être joignable que depuis le serveur web, pas depuis Internet.
4. **Identifiants en dehors de la racine web :** les fichiers de configuration et `.env` ne doivent pas être accessibles par URL. Plus de détails dans l'article [Protéger les identifiants et les fichiers .env](https://phpsos.de/fr/blog/env-dateien-schuetzen/).
5. **Connexion chiffrée avec des serveurs séparés :** si la base se trouve sur une autre machine, la connexion devrait être chiffrée, afin que identifiants et contenus ne circulent pas en clair sur le réseau.
6. **Accès distincts pour la maintenance :** sauvegarde, analyses et administrateurs reçoivent leurs propres utilisateurs. On peut ainsi retracer dans le journal qui a fait quoi, et un accès peut être bloqué sans perturber le site web.

## Bases de données, PHP2Shell et le cas d'urgence

PHP2Shell ne concerne pas la base de données elle-même, mais l'interpréteur PHP : CVE-2026-109618 et CVE-2026-109619 permettent d'exécuter du code malveillant sans authentification. Si cela réussit, le code s'exécute avec les droits du processus PHP et peut donc en règle générale lire le fichier de configuration contenant les identifiants de la base de données. Les requêtes préparées n'y changent rien, car l'attaque ne passe pas du tout par une requête SQL.

Sont donc obligatoires la mise à jour vers PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 et le redémarrage de tous les processus PHP. S'il existe des indices d'une attaque réussie, il faut aussi de nouveaux identifiants de base de données, une vérification de la base à la recherche de contenus injectés et une évaluation de l'obligation de notification au titre du RGPD. Une [réponse à incident](https://phpsos.de/fr/leistungen/incident-response/) structurée est ici judicieuse.

> **Astuce:**
> Ne changez les mots de passe de la base de données qu'après le nettoyage du serveur. Tant que du code malveillant s'exécute, il peut aussi relire les nouveaux identifiants.

## Comment PHP SOS aide-t-il concrètement ?

- Nous vérifions comment votre application accède à la base de données, et si utilisateurs, droits et accès réseau correspondent au minimum requis.
- Nous contrôlons si les fichiers de configuration et d'identifiants se trouvent en dehors de la racine web et ne sont pas accessibles publiquement.
- Après un incident, nous renouvelons les identifiants dans le bon ordre et vérifions la base à la recherche de code injecté.
- Nous documentons les résultats de manière à ce que délégués à la protection des données et assureurs puissent les comprendre.


## Questions fréquentes

**Dois-je utiliser PDO ou mysqli ?**  
Pour les nouveaux projets, PDO est le plus souvent le choix le plus flexible, car il fonctionne avec de nombreuses bases de données via la même interface. mysqli est pertinent si vous n'utilisez que MySQL ou MariaDB et avez besoin de leurs fonctions spécifiques. Les deux sont sûrs si les requêtes préparées sont employées de façon systématique.

**PDO lève-t-il automatiquement des exceptions en cas d'erreur ?**  
Oui, depuis PHP 8.0.0, PDO::ERRMODE_EXCEPTION est la valeur par défaut. Auparavant, c'était le mode silencieux, dans lequel les erreurs n'étaient consultables que via errorCode() et errorInfo(). Les applications plus anciennes définissent souvent encore expressément ce mode.

**Les marqueurs peuvent-ils aussi remplacer des noms de tables ou de colonnes ?**  
Non. Les marqueurs ne tiennent lieu que de valeurs. Les noms de tables et de colonnes, par exemple pour un tri, doivent être vérifiés par rapport à une liste fixe de noms autorisés avant d'être insérés dans la requête.

**Dois-je changer le mot de passe de la base de données après PHP2Shell ?**  
La mise à jour seule ne l'exige pas. Mais s'il existe des indices que le serveur a été compromis, tous les identifiants figurant dans des fichiers de configuration sont à considérer comme connus. Vous devriez alors les renouveler après le nettoyage.

## Sources

- [Manuel PHP : requêtes préparées PDO](https://www.php.net/manual/en/pdo.prepared-statements.php)
- [Manuel PHP : gestion des erreurs PDO](https://www.php.net/manual/en/pdo.error-handling.php)
- [Manuel PHP : mysqli::execute_query](https://www.php.net/manual/en/mysqli.execute-query.php)
- [Manuel PHP : mysqli_driver::$report_mode](https://www.php.net/manual/en/mysqli-driver.report-mode.php)
