Peut PHP PDO États accepter la table ou de la colonne de nom de paramètre?
Pourquoi je ne peux pas passer le nom de la table pour un AOP déclaration?
$stmt = $dbh->prepare('SELECT * FROM :table WHERE 1');
if ($stmt->execute(array(':table' => 'users'))) {
var_dump($stmt->fetchAll());
}
Est-il un autre moyen sûr pour insérer un nom de table dans une requête SQL? Sûr, je veux dire que je ne veux pas faire
$sql = "SELECT * FROM $table WHERE 1"
Vous devez vous connecter pour publier un commentaire.
Table et les noms de Colonnes NE peuvent pas être remplacés par les paramètres de l'AOP.
Dans ce cas, vous voulez simplement de filtre et nettoyez les données manuellement. Une façon de le faire est de passer en sténographie des paramètres à la fonction qui va exécuter la requête dynamiquement et ensuite utiliser un
switch()
instruction pour créer une liste de valeurs valides pour être utilisé pour le nom de la table ou de la colonne. De cette façon, aucune intervention de l'utilisateur ne va jamais directement dans la requête. Ainsi, par exemple:En ne laissant aucun cas de défaut ou à l'aide d'un cas par défaut renvoie un message d'erreur vous assurer que seules les valeurs que vous souhaitez pour vous servir.
array('u'=>'users', 't'=>'table', 'n'=>'nonsensitive_data')
etc.)default
. Si l'utilisation de ce modèle, vous devez soit l'étiquette de l'un de voscase
s commedefault
, ou ajouter une erreur explicite cas commedefault: throw new InvalidArgumentException;
if ( in_array( $tbl, ['users','products',...] ) { $sql = "SELECT * FROM $tbl"; }
. Merci pour l'idée.mysql_real_escape_string()
. Peut-être ici, je peux le dire sans que quelqu'un saut en disant "Mais vous n'en avez pas besoin, avec AOP"À comprendre pourquoi la liaison d'une table (ou une colonne) de nom ne fonctionne pas, vous devez comprendre comment les espaces réservés dans les instructions préparées de travail: ils ne sont pas simplement substitué en tant que (convenablement échappé) les chaînes de caractères, et le SQL exécuté. Au lieu de cela, un SGBD demandé de "préparer" un état, vient avec un plan de requête pour la façon dont il exécute cette requête, y compris les tables et les index qu'elle utiliserait, qui sera la même quelle que soit la façon dont vous remplissez les espaces réservés.
Le plan de
SELECT name FROM my_table WHERE id = :value
sera la même quelle que soit vous remplacez la:value
, mais apparemment similairesSELECT name FROM :table WHERE id = :value
ne peut pas être prévu, parce que le SGBD n'a aucune idée de ce que la table que vous êtes, en réalité, va sélectionner à partir.Ce n'est pas quelque chose d'une abstraction de la bibliothèque comme AOP peut ou doit contourner, car il irait à l'encontre de la touche 2 fins de déclarations préparées à l'avance: 1) pour permettre la base de données de décider à l'avance comment une requête doit être exécutée, et utiliser le même plan plusieurs fois; et 2) pour éviter des problèmes de sécurité en séparant la logique de la requête à partir de la variable d'entrée.
TOP
/LIMIT
/OFFSET
clauses, alors ce serait un peu hors de place comme une caractéristique.prepare()
méthode un peu mieux.Je vois que c'est un vieux post, mais j'ai trouvé utile et j'ai pensé partager une solution similaire à ce que @kzqai suggéré:
J'ai une fonction qui reçoit deux paramètres comme...
L'intérieur, j'ai de contre-vérifier les tableaux que j'ai mis en place pour s'assurer que les tables et les colonnes avec des "bienheureux" tables sont accessibles:
Puis la vérification de PHP avant d'exécuter AOP ressemble...
$pdo->query($sql)
À l'aide de l'ancien n'est pas intrinsèquement plus sûr que le dernier, vous devez désinfecter l'entrée qu'il fait partie d'un tableau de paramètres ou d'une variable simple. Donc je ne vois pas quelque chose de mal avec l'aide de la dernière forme avec
$table
, à condition que vous assurez-vous que le contenu de$table
est sûr (numérique plus souligne?) avant de l'utiliser.(Réponse tardive, consulter ma note de côté).
La même règle s'applique lors de la tentative de créer une "base de données".
Vous ne pouvez pas utiliser une requête préparée à se lier à une base de données.
I. e.:
ne fonctionnera pas. Utiliser une liste fiable à la place.
Note de côté: j'ai ajouté cette réponse (comme un wiki de la communauté) car il est souvent utilisé pour fermer les questions avec les, où certaines personnes affiché des questions semblables à essayer de lier un base de données et non pas un tableau et/ou de la colonne.
Partie de moi se demande si vous pouvez fournir votre propre désinfection fonction aussi simple que cela:
Je n'ai pas vraiment pensé, mais il semble que rien enlever à l'exception des caractères et des caractères de soulignement pourrait fonctionner.
MyLongTableName
il est facile à lire, mais si vous vérifiez le nom enregistré il serait (probablement) êtreMYLONGTABLENAME
ce qui n'est pas très lisible, doncMY_LONG_TABLE_NAME
est effectivement plus lisible.Select * From $table
. Une liste blanche ou la stricte correspondance de modèle (par exemple, "les noms commençant communication de suivi de 1 à 3 chiffres seulement") est vraiment essentiel ici.Comme pour la question principale dans ce fil, les autres postes, il est clair pourquoi on ne peut pas lier les valeurs pour les noms de colonne lors de la préparation de déclarations, voici donc une solution:
Ci-dessus est juste un exemple, donc inutile de le dire, copiez->coller ne fonctionne pas. Ajuster à vos besoins.
Maintenant, cela peut ne pas fournir la sécurité à 100%, mais il permet un certain contrôle sur les noms de colonne quand ils "viennent" comme des chaînes dynamiques et peuvent être modifiées sur les utilisateurs finaux. En outre, il n'est pas nécessaire de construire un tableau avec votre colonne de la table des noms et des types car ils sont extraits à partir de la information_schema.