PHP MySQL Requêtes préparées


Les requêtes préparées sont très utiles pour prévenir les injections MySQL.


Requêtes préparées et paramètres liés

Les requêtes préparées sont utilisées pour exécuter plusieurs instructions SQL identiques, et elles s'exécutent plus efficacement.

Le principe de fonctionnement des requêtes préparées est le suivant :

  1. Préparation : Créez un modèle d'instruction SQL et envoyez-le à la base de données. Les valeurs réservées sont marquées avec le paramètre "?". Par exemple :

    INSERT INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?)
  2. La base de données analyse, compile et effectue l'optimisation de la requête sur le modèle d'instruction SQL, puis stocke le résultat sans l'afficher.

  3. Exécution : Enfin, les valeurs liées par l'application sont transmises aux paramètres (marqueurs "?"), et la base de données exécute l'instruction. L'application peut exécuter l'instruction plusieurs fois si les valeurs des paramètres sont différentes.

Par rapport à l'exécution directe d'instructions SQL, les requêtes préparées présentent deux avantages principaux :

  • Les requêtes préparées réduisent considérablement le temps d'analyse, car la requête n'est effectuée qu'une seule fois (bien que l'instruction soit exécutée plusieurs fois).

  • Les paramètres liés réduisent la bande passante du serveur ; il vous suffit d'envoyer les paramètres de la requête, et non l'instruction entière.

  • Les requêtes préparées sont très utiles contre l'injection SQL, car les valeurs des paramètres sont envoyées à l'aide d'un protocole différent, ce qui garantit la légitimité des données.


Requêtes préparées MySQLi

L'exemple suivant utilise des requêtes préparées dans MySQLi et lie les paramètres correspondants :

Exemple (MySQLi utilisant des requêtes préparées)

<?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDB"; //Créer la connexion $conn = new mysqli($servername, $username, $password, $dbname); //Vérifier la connexion if ($conn->connect_error) { die("Échec de la connexion :" . $conn->connect_error); } //Préparer et lier $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"); $stmt->bind_param("sss", $firstname, $lastname, $email); //Définir les paramètres et exécuter $firstname = "John"; $lastname = "Doe"; $email = "[email protected]"; $stmt->execute(); $firstname = "Mary"; $lastname = "Moe"; $email = "[email protected]"; $stmt->execute(); $firstname = "Julie"; $lastname = "Dooley"; $email = "[email protected]"; $stmt->execute(); echo "Nouvel enregistrement inséré avec succès"; $stmt->close(); $conn->close(); ?>

Analysez chaque ligne de code dans l'exemple suivant :

"INSERT INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?)"

Dans l'instruction SQL, nous avons utilisé des points d'interrogation (?), où nous pouvons remplacer les points d'interrogation par des entiers, des chaînes de caractères, des nombres à virgule flottante en double précision et des valeurs booléennes.

Ensuite, regardons la fonction bind_param() :

$stmt->bind_param("sss", $firstname, $lastname, $email);

Cette fonction associe les paramètres de l'instruction SQL et indique à la base de données les valeurs des paramètres. La liste de paramètres "sss" gère les types de données des paramètres restants. Le caractère "s" indique à la base de données que le paramètre est une chaîne de caractères.

Les paramètres ont les quatre types suivants :

  • i - entier
  • d - double
  • s - chaîne de caractères
  • b - BLOB (objet binaire volumineux)

Un type doit être spécifié pour chaque paramètre.

En indiquant à la base de données le type de données des paramètres, le risque d'injection SQL peut être réduit.

Note Remarque :Si vous souhaitez insérer d'autres données (saisie de l'utilisateur), il est très important de valider les données.


Requêtes préparées dans PDO

Dans l'exemple suivant, nous utilisons des requêtes préparées dans PDO et lions des paramètres :

Exemple (PDO utilisant des requêtes préparées)

<?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDBPDO"; try { $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); //Définir le mode d'erreur PDO sur exception $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //Préparer la requête SQL et lier les paramètres $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (:firstname, :lastname, :email)"); $stmt->bindParam(':firstname', $firstname); $stmt->bindParam(':lastname', $lastname); $stmt->bindParam(':email', $email); //Insérer une ligne $firstname = "John"; $lastname = "Doe"; $email = "[email protected]"; $stmt->execute(); //Insérer une autre ligne $firstname = "Mary"; $lastname = "Moe"; $email = "[email protected]"; $stmt->execute(); //Insérer une autre ligne $firstname = "Julie"; $lastname = "Dooley"; $email = "[email protected]"; $stmt->execute(); echo "Nouvel enregistrement inséré avec succès"; } catch(PDOException $e) { echo "Erreur : " . $e->getMessage(); } $conn = null; ?>

Autres extensions