De nos jours, énormément de sites dynamiques utilisent une base de données SQL. Tout le monde sait que l’accès à une base de données prend un temps non négligeable dans le traitement d’un site web. De plus, pour ceux qui se sont déjà intéressé à la sécurité, vous avez sûrement remarqué la quantité énorme de failles qu’il peut exister entre un script et sa base de données.
Nous allons voir dans cet article comment gagner en performance et en sécurité grâce aux requêtes préparées.
Intérêts d’utiliser les requêtes préparées
Optimisation des performances
Dans un article précédent je vous ai déjà présenté comment économiser le temps d’accès en utilisant un système de cache des données. Mais il est tout de même nécessaire de lire ou d’écrire dans une base de temps en temps. Et à ce moment là le cache ne peut plus rien pour nous.
Le principe des requêtes préparées est, comme son nom l’indique, de préparer les requêtes pour ensuite les utiliser. Ainsi, au lieu de recalculer la requête à chaque fois qu’on lui envoi, la base de données va la calculer une seule fois. Les fois suivantes, la base de données n’aura qu’à les exécuter.
Un petit schéma vaut mieux qu’un long discours :
Légende :
- Vert : Toujours la même structure de requête (par exemple : un SELECT où seule la condition change)
- Rouge : L’analyse faite par la base de données
- Bleu : La réponse
Amélioration de la sécurité
Vous vous êtes déjà occupé de protéger votre site contre les injections SQL. Mais ça vous fait perdre pas mal de temps d’écrire l’appel à une fonction qui sécurise vos données à chaque fois que vous voulez exécuter un requête.
Le second principe des requêtes préparées c’est de ne plus traiter les données comme faisant partie de la requête mais vraiment comme des données. Lors de la préparation d’une requête la base de données crée en réalité des cases dans lesquelles elle va « binder » les valeurs qu’on lui donne.
Il n’y a donc plus moyen de pirater une requête avec des valeurs frauduleuses.
Création d’un SELECT préparé
Partons d’une requête de sélection simple :
SELECT car_name, car_type FROM car WHERE car_id = 1 |
Cette requête peut être découpée en deux parties : Une partie fixe et une partie variable.
La partie fixe est celle que l’on va envoyer à la base de données pour préparer l’exécution.
La partie variable est celle qui va changer en fonction de la voiture qu’on veut charger. Il s’agit de 1 c’est cette valeur que nous allons « binder ».
<?php $pdo = new PDO('mysql:host=127.0.0.1;dbname=mabase', 'root', 'motdepasse'); $stmt = $pdo->prepare('SELECT * FROM message WHERE message_id = :id'); $stmt->bindValue(':id', 3, PDO::PARAM_INT); $stmt->execute(); print_r($stmt->fetchObject()); ?> |
Dans ce bout de code, on voit bien que quelque soit l’id souhaité la requête ne changera pas. Seule la valeur change, et elle est appliqué après.
INSERT préparé
INSERT INTO message (message_content, message_value) VALUES (:content,:VALUE) |
Bind des valeurs :
<?php $stmt->bindValue(':content', 'Un super message'); $stmt->bindValue(':value', 56, PDO::PARAM_INT); $stmt->execute(); ?> |
UPDATE préparé
UPDATE message SET message_content = :content WHERE message_id = :id |
Bind des valeurs :
<?php $stmt->bindValue(':content', 'Un super message'); $stmt->bindValue(':id', 3, PDO::PARAM_INT); $stmt->execute(); ?> |
DELETE préparé
DELETE message WHERE message_id = :id |
Bind des valeurs :
<?php $stmt->bindValue(':id', 3, PDO::PARAM_INT); $stmt->execute(); ?> |
Conclusion
Les exemples ont été faits sur des requêtes très simples mais peuvent être appliquées sur des requêtes bien plus poussées. L’intérêt serai donc encore plus grand d’utiliser PDO avec les requêtes préparées.
Publié dans PHP
Waouh. Super clair ce tuto ! Précis, concis, et en plus le schéma est super clair !
Merci.
Tuto bien détaillé, j’ai pu régler mon problème en moins de 5 minutes ca fait plaisir, surtout après des heures de recherches.
Bonjour
J’ai bien compris le principe mais comment faire lorsque le WHERE concerne une variable
comme ici $requete=mysql_query (« SELECT PrenomEleve FROM eleves WHERE IdEleve=' ».$_GET[‘IdEleve’]. »‘ »);
Comment faire l’équivalent en PDO.
Merci d’avance
Kami
Salut,
tout d’abord, pour utiliser PDO il faut complètement abandonner les fonctions du type mysql_, il faut complètement utiliser PDO.
Pour te connecter c’est simple : $pdo = new PDO(‘mysql:host=localhost;dbname=mabase’, ‘root’, ‘password’);
Ensuite, pour exécuter une sélection c’est :
$stmt = $pdo->prepare(‘SELECT PrenomEleve FROM eleves WHERE IdEleve = :id’);
$stmt->bindValue(‘:id’, intval($_GET[‘IdEleve’]));
$stmt->execute();
$result = $stmt->fetchObject();
Et voilà, l’objet est stocké dans $result.
PS : Le « intval » permet de ne laisser passer que les nombres entiers.
cf : Règle numéro 1 de la sécurité, tout ce qui vient de l’utilisateur est potentiellement une tentative de piratage.
Merci beaucoup , des explications comme cela j’en re-demande.
Continue t’chouette.
s’il vous plait je suis sur la conception d’un site web et je voudrais avoir l’équivalent de ces deux requêtes en PDO
première requête:
0){
while($res=mysql_fetch_array($req)){
extract($res);?>
<?php
echo "$titre »;
echo »;
echo »$resume« ;
}
}
else echo « pas d’articles »; ?>
0){
$res=mysql_fetch_assoc($req);
extract($res);
echo « $titrePoste par: $auteur, le $date »;
echo « $cont »;
affiche_commentaire($id);
echo « Poster vos commentaires »;
inserer_formulaire($id);
}
}?>
merci d’avance Siata
Ce qui va changer dans ton code entre les appels « mysql_ » et pdo, c’est la partie « mysql_fetch_assoc ».
Avec PDO, l’équivalent à « while($res = mysql_fetch_array($req)) » est « while($res = $stmt->fetchObject()) »
Merci, clair, concis, efficace,
en lien avec les bonnes pratique sécurité (notamment l’utilisation du bind.
Un peu de fraicheur sur le monde des requêtes avec PDO dans ce monde