Pourquoi ne puis-je pas transmettre un nom de table à une instruction PDO préparée ?
$stmt = $dbh->prepare('SELECT * FROM :table WHERE 1'); if ($stmt->execute(array(':table' => 'users'))) { var_dump($stmt->fetchAll()); }
Existe-t-il un autre moyen sûr d'insérer des noms de table dans des requêtes SQL ? Par sécurité, je veux dire que je ne veux pas le faire
$sql = "SELECT * FROM $table WHERE 1"
Pour comprendre pourquoi la liaison des noms de table (ou de colonne) ne fonctionne pas, vous devez comprendre comment fonctionnent les espaces réservés dans les instructions préparées : ils ne sont pas simplement remplacés par une chaîne (correctement échappée) et le SQL résultant. En revanche, un SGBD qui nécessite une instruction « prepare » proposera un plan de requête complet expliquant comment exécuter la requête, y compris les tables et les index qui seront utilisés, qui seront les mêmes quelle que soit la façon dont vous remplissez les espaces réservés.
SELECT name FROM my_table WHERE id = :value
的计划将与您替换:value
的内容相同,但表面上相似的SELECT name FROM :table WHERE id = :value
Ne peut pas être planifié car le SGBD ne sait pas dans quelle table vous effectuez réellement votre sélection.Ce n'est pas non plus un problème qu'une bibliothèque d'abstraction comme PDO peut ou devrait résoudre, car elle va à l'encontre de 2 objectifs clés des instructions préparées : 1) permettre à la base de données de décider à l'avance comment exécuter une requête et d'utiliser le même plan. plusieurs fois ; 2) ) évite les problèmes de sécurité en séparant la logique de requête de l'entrée variable.
Les noms de tables et de colonnes ne peuvent pas être remplacés par des paramètres dans PDO.
Dans ce cas, il vous suffit de filtrer et de nettoyer manuellement les données. Une façon d'y parvenir consiste à transmettre un argument abrégé à une fonction qui exécutera la requête de manière dynamique, puis à utiliser une instruction switch() pour créer une liste blanche de valeurs ou de noms de colonnes valides pour le nom de la table. De cette façon, les entrées de l'utilisateur ne vont pas directement dans la requête. Par exemple :
En ne conservant pas la casse par défaut ou en utilisant une casse par défaut qui renvoie un message d'erreur, vous vous assurez que seules les valeurs que vous souhaitez utiliser sont utilisées.