2009-10-25 2 views
8

Je suis jouer avec les commandes préparées en PHP/AOP. Les requêtes de base fonctionnent très bien, en passant une valeur à la clause WHERE:Quels jetons peuvent être paramétrés dans AOP préparé des déclarations?

$stmt = $db->prepare('SELECT title FROM episode WHERE id=:id'); 
$stmt->bindParam(':id', $id, PDO::PARAM_INT); 
$id = 5; 
$stmt->execute(); 

Cependant, j'ai une situation où je dois passer des variables pour les noms de champ. Cette requête (avec reliure appropriée) fonctionne très bien:

SELECT :field FROM episode WHERE id=:id 

Celui-ci donne une erreur:

SELECT title FROM :field WHERE id=:id 

Celui-ci ne donne pas une erreur, mais retourne aucune ligne:

SELECT title FROM episode WHERE :field=:id 

Alors, quelles choses devraient fonctionner dans les déclarations préparées? Puis-je 'paramétrer' les noms de champs, les noms de tables et ainsi de suite?

Répondre

10

Vous ne pouvez pas paramétrer les noms de tables, les noms de colonnes ou quoi que ce soit dans une clause IN (grâce à c0r0ner pour pointing out the IN clause restriction).

Voir this question, puis this comment in the PHP manual.

+0

Merci pour la réponse. Il s'avère que la première requête que j'ai posté ne fonctionne pas - si vous liez, par exemple, '' title'' à ': field', alors il sélectionne simplement la chaîne 'title' et non la valeur du champ. Étrange qu'il n'y a pas de méthode pour lier les colonnes/tables, puisque maintenant je dois ajouter une sécurité supplémentaire, que PDO était censé gérer pour moi:/ – DisgruntledGoat

+0

La pensée derrière ceci est probablement que vous ne devriez vraiment pas laisser votre les utilisateurs choisissent directement les champs/tables que votre requête appelle. Mais je suis d'accord que cela ajoute un peu de travail supplémentaire de votre côté. –

+0

Je vois ce que vous voulez dire. Cependant, je l'utilise dans une situation où seulement je spécifie les tables, mais d'une manière abstraite, par exemple. 'displayTable ('épisode')'. Je suppose que je n'ai pas vraiment besoin de me soucier des paramètres/de la sécurité dans ce cas. – DisgruntledGoat

1

@ Josh Leitzel

Cette façon de penser est très restrictive (et à mon avis, juste une excuse pour être trop paresseux pour mettre en œuvre une solution solide), en particulier pour les structures d'arbres dynamiques exprimés dans une base de données.

Prenons l'exemple suivant:

Mon projet a une structure logique:

Une hiérarchie de l'entreprise est exprimée en termes d'entités. Chaque entité peut traiter dans le cas général d'être un membre de la hiérarchie ou en tant que membre d'un niveau spécifique de la hiérarchie. La hiérarchie elle-même est définie dans une table comme une branche d'arbre unique comme suit:

entity_structure (
    id 
    name 
    parent_entity_structure_id 
); 

et les entités elles-mêmes sont exprimés en:

entities (
    id 
    name 
    entity_structure_id 
    parent_id 
); 

Pour la facilité d'utilisation, je l'ai construit un algorithme qui crée une vue à plat de l'arbre. L'exemple concret suivant illustre ce que je veux dire:

SELECT * FROM entity_structure; 

id  | name    | entity_structure_parent_id 
----------------------------------------------------------- 
1  | Company   | null (special one that always exists) 
2  | Division   | 1 
3  | Area    | 2 
4  | Store    | 3 

Cela se traduirait par la représentation plane suivante étant produite:

entity_tree (
    entity_id 
    division_id 
    area_id 
    store_id 
) 

Les entités qui sont au niveau de la division aurait division_id, area_id et STORE_ID NULL , Une zone area_id et store_id comme NULL, etc

La bonne chose à ce sujet est que vous permet d'interroger tous les enfants d'une division en utilisant une déclaration similaire à la suivante:

SELECT * FROM entity_tree WHERE division_id = :division_id; 

Cependant, cela suppose que je connais le niveau de la structure de l'entité que je suis l'interrogation.Ce serait bien de le faire:

SELECT * FROM entity_tree WHERE :structure = :entity_id; 

Je sais que ce n'est pas difficile de comprendre le niveau de la structure d'une seule entité, mais suppose que je suis en boucle à travers une collection d'entités qui ne sont pas tous au même niveau . Comme il est maintenant, je dois construire une requête distincte pour chaque niveau de la hiérarchie, mais si je pouvais paramétrez les champs que je pouvais faire ce qui suit:

$children = array(); 
$stmt = $pdo->prepare('SELECT entity_id FROM entity_tree WHERE :structure = :entityId'); 
foreach ($entities AS $entity) { 
    $stmt->execute(array(
     ':structure' = $entity->getEntityStructureId(), 
     ':entityId' = $entity->getId() 
    )); 

    $children[$entity->getId()] = $stmt->fetchAll(PDO::FETCH_COLUMN); 
} 

entraînant un code plus propre et une seule déclaration préparée.

L'exemple complet n'utilise aucune entrée de l'utilisateur.

Juste quelque chose à considérer.

+0

Quel est le point, cependant? Vous pouvez tout aussi bien utiliser des variables régulières dans cette instance puisqu'il n'y a pas d'entrée utilisateur. Il n'y a aucune chance d'injection ici. En outre, cela aurait dû être posté comme un commentaire à ma réponse puisque ce n'est pas une réponse à la question du PO. (Je me rends compte que vous n'auriez pas été capable de l'adapter, juste en notant cela.) –

1

Vous ne pouvez pas non plus paramétrer quoi que ce soit dans la clause IN.

+0

Merci, j'ai oublié cela. Je vais l'ajouter à ma réponse. –

Questions connexes