PHP : PDO Requêtes préparées

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 :

Transactions avec la base de données

Transactions avec la base de données

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
Sur le premier schéma on voit que la base de données fait l’analyse à chaque requête.
Sur le second (requêtes préparées) on voit que la base de données ne refais pas l’analyse si la requête est construite de la même façon.

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.

Tagués avec : , , , , , , ,
Publié dans PHP
8 commentaires pour “PHP : PDO Requêtes préparées
  1. martin dit :

    Waouh. Super clair ce tuto ! Précis, concis, et en plus le schéma est super clair !

    Merci.

  2. colas dit :

    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.

  3. kami dit :

    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

  4. Olivier PEREZ dit :

    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.

  5. Bouli dit :

    Merci beaucoup , des explications comme cela j’en re-demande.
    Continue t’chouette.

  6. Siata dit :

    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

  7. Olivier PEREZ dit :

    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()) »

  8. edouard dit :

    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 =)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*