Glorious paint avec d'un côté une variable PHP concaténée dans la requête c'est pas bien, de l'autre try catch qui contiennent prepare et execute yay fun

PHP / Bonnes pratiques / Créer une requête SQL via PHP


📅

🏷️


Introduction

Lors de la création de sites dynamiques en PHP, la communication avec la base de données est primordiale. Elle permet notamment de créer du contenu, le modifier, le supprimer et enfin de le récupérer toi aussi brille dans les soirées en société avec cet acronyme à coucher dehors ).

Cet article est dédié aux bonnes pratiques recommandées (selon moi, et la doc PHP) afin de

  • Ne pas risquer d’attaques de type injections SQL
  • Ne pas solliciter le serveur inutilement
  • Fournir de bons retours utilisateurs (ergonomie++)

Nous allons donc voir comment créer des requêtes solides.

Attention, cet article traite de la prévention des injections SQL, mais ne traite pas de la gestion des attaques de type XSS (injection de javascript).
Je recommande l’utilisation de htmlspecialchars, ainsi que la lecture d’un stackoverflow dédié#merciDave #missYou #keurhSurTwa #PA107forEver

Edit 2023 : Go PDO->prepare & bindParams

Mise en place

Afin de pouvoir bénéficier des exemples ci-dessous, vous devrez avoir

  • Un serveur PHP installé ; en local, je recommande WAMP
  • La base de données d’exemple (Merci 3WA !) qu’il vous faudra avoir installé sur votre serveur (import depuis phpMyAdmin)
  • Un navigateur web, avec accès au localhost/

Fichier récapitulatif

Parlons peu mais parlons bien : voici des exemples concrets

En cas de problème, n’oubliez pas de configurer la connexion dans php/_connexion.php 😉

Méthodologie

La gestion du SQL en PHP a bien évoluée au fil des années. Les exemples ci-dessous sont récents.

Je vous recommande toutefois de vérifier leur actualité sur la documentation PHP officielle

Pas trop d’intérêt à faire un récapitulatif ici, passons directement au concret.

prepare & execute

La méthode prepare d’un objet PDO nous permet de créer une requête préparée.

C’est à dire que cette requête est stockée dans une variable dédiée, qui pourra être réutilisé en fonction des besoins.

Cette méthode fonctionne en symbiose avec une autre méthode : execute. Cette méthode permet d’exécuter la requête ainsi préparée (de faire l’appel au serveur).

Lien vers documentation php.

Ajouter des variables

Plusieurs méthodes existent :

  • méthode bindParams
  • tableau associatif passé en paramètre de execute
  • ancienne méthode avec des ? (variables anonymes)

Nous utiliserons bindParams. Pour cela, il faut l’appeler de cette manière après avoir préparée la requête, mais avant l’exécution de la requête préparée.

Les variables sont définies avec “:”.
Par exemple pour inclure une variable “id_article” dans mon SQL, dans mon SQL, j’utiliserai “:id_article”.

Le lien avec la variable php se fait dans bindParams : $requetePreparee->bindParam(‘:orderNumber’, $reqOrderNumber);

Attention à ne jamais passer de variable “telles quelles” !

Par exemple : $id_article = $_GET[“idarticle”]; $requetePreparee = $pdo->prepare(” SELECT * FROM orders WHERE orderNumber = ” . $id_article . ” ; “);

Il s’agit d’une très mauvaise pratique. En effet les variables récupérées depuis le site (en GET ou POST ou autres) peuvent être interceptées et/ou modifiées, et utilisée pour rajouter du code dangereux : typiquement dans le code ci dessus, si on modifie l’url appelée, on peut passer n’importe quoi, y compris du code SQL destructeur.

En utilisant “;” en début d’instruction, on met fin a la requête en cours et on peut en faire exécuter une autre à la suite au serveur…

L’utilisation de prepare, execute et bindParams permet d’éviter ce genre de problèmes : les variables transmises de cette manière sont “assainies” : tous les caractères spéciaux qui pourraient entraîner des modifications de code sont convertis en chaînes de caractères inoffensifs et transmis tels quels.

Afin de limiter les dégâts en cas d’un éventuel piratage, je vous encourage également à créer un utilisateur par base de données. En cas d’attaque réussie, seulement une base est touchée, et non l’ensemble.

Erreurs php avec try… catch et errorInfo

Enfin, afin de gérer nous même les éventuelles erreurs de connexion PHP ou de syntaxe SQL plutôt que de laisser PHP faire (il affiche tout un peu en vrac dans un tableau et arrête l’affichage de la page la ou il en est..), nous utiliserons un bloc try… catch.

  • Le bloc try { } permet d’exécuter du code avec un genre de filet de sécurité.
  • En cas de problème, le contenu du bloc catch { } est exécuté.
  • Si tout se déroule correctement, le contenu du bloc try est exécuté.

Cela nous permet donc de gérer les erreurs dans le bloc catch, en utilisant le paramètre PDOException $e, déjà disponible dans PHP (cela fait partie du PDO…).

Cette variable contient les informations relatives à l’erreur, le tout dans un tableau associatif. Cela nous permet d’afficher l’erreur (ou une partie seulement) de la manière que nous souhaitons.

Gestion de l’encodage : caractères spéciaux, accentués, etc.

Voir l’article dédié à la gestion de l’encodage.

Optimisations avancées

Mise en fonctions

J’ai pris pour habitude de placer chaque requête dans une fonction.
De cette manière la requête SQL est prête à être utilisée : si je veux récupérer un article, je lui donne l’id de l’article à récupérer, et la fonction me renvoie un tableau associatif contenant les champs voulus.

Par exemple : $article12 = recupArticle(12);

Cela simplifie également la relecture et la maintenance du code.

Structure de projet

Afin de vous y retrouver plus simplement et de ne pas avoir de fichiers de code de 600 lignes, je vous recommande vivement de créer un fichier par fonction, et de regrouper ces fichiers par thèmes/entité.

Par exemple, pour mes articles j’aurai 5 fonctions : ajouter un article, modifier, supprimer, récupérer tous les articles, récupérer un article.

Je crée donc 5 fonctions, contenues dans 5 fichiers (ajouter.php, modifier.php, etc.), eux-mêmes contenus dans le dossier “/article”.

C’est un peu fastidieux, mais cela évite l’anarchie dès que le projet se développe. Cela permet également de bosser de manière compartimentée : en cas de problème j’inclus mes fichiers un par un jusqu’à trouver celui qui ne fonctionne pas.

Notes sur l’AJAX

Attention ! si vous souhaitez réutiliser les mêmes fonctions pour Ajax, vous ne pourrez pas appeler directement ces fichiers.

En effet, la valeur de retour renvoyée par PHP lorsqu’il est appelé en Ajax est ce que le PHP a affiché. Par conséquent, il faudra faire un fichier dédié à l’exécution de cette fonction (en gros, construire une API :)).

Pour cela, il faudra créer un fichier qui inclura note fichier php/_connexion.php, afin de permettre la connexion à la base de données, puis inclure le fichier contenant la fonction (afin de la mettre à disposition) et enfin appeler cette fonction, puis afficher son contenu.

Lecture recommandée

Cette méthodologie est particulièrement efficace lors de l’utilisation de formulaires. Je vous recommande l’article lié concernant la gestion des formulaires et de leurs données. // TODO aussi :3 // Edit 2023 > :33


Commentaires

Laisser un commentaire

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