2009-10-25 14 views
8

Estoy jugando con declaraciones preparadas en PHP/PDO. Las consultas básicas funcionan bien, pasar un valor a la cláusula WHERE:¿Qué tokens se pueden parametrizar en declaraciones preparadas con PDO?

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

Sin embargo, tengo una situación en la que necesito para pasar variables para los nombres de los campos. Esta consulta (con la unión apropiada) funciona bien:

SELECT :field FROM episode WHERE id=:id 

Esto se da un error:

SELECT title FROM :field WHERE id=:id 

Ésta no da un error, pero no devuelve ninguna fila:

SELECT title FROM episode WHERE :field=:id 

Entonces, ¿qué cosas deberían funcionar en las declaraciones preparadas? ¿Puedo 'parametrizar' nombres de campos, nombres de tablas, etc.?

Respuesta

10

No se pueden parametrizar nombres de tablas, columnas ni nada en una cláusula IN (gracias a c0r0ner para pointing out the IN clause restriction).

Consulte this question, y posteriormente this comment in the PHP manual.

+0

Gracias por la respuesta. Resulta que la primera consulta que publiqué no funciona: si enlaza, digamos, '' title'' to ': field', entonces simplemente selecciona la cadena 'title' y no el valor del campo. Es extraño que no haya un método para enlazar columnas/tablas, ya que ahora tengo que agregar algo de seguridad extra, que PDO se suponía que manejara para mí:/ – DisgruntledGoat

+0

El pensamiento detrás de esto es probablemente que realmente no deberías dejar que tu los usuarios eligen directamente qué campos/tablas invoca su consulta. Pero estoy de acuerdo en que agrega un poco más de trabajo de tu parte. –

+0

Veo tu punto. Sin embargo, lo estoy usando en una situación en la que solo especifico las tablas, pero de forma abstracta, p. 'displayTable ('episode')'. Supongo que realmente no necesito preocuparme por los parámetros/seguridad en este caso. – DisgruntledGoat

1

@ Josh Leitzel

que pensar es muy restrictiva (y en mi opinión es sólo una excusa por ser demasiado vago para poner en práctica una solución robusta), especialmente para estructuras de árbol dinámicas expresan en una base de datos.

Considere el siguiente ejemplo:

Mi proyecto tiene una estructura lógica:

Una jerarquía de la empresa se expresa en términos de entidades. Cada entidad puede tratarse en el caso general de ser un miembro de la jerarquía o como miembro de un nivel específico de la jerarquía. La jerarquía misma se define en una tabla como una sola rama de un árbol de la siguiente manera:

entity_structure (
    id 
    name 
    parent_entity_structure_id 
); 

y las propias entidades se expresan como:

entities (
    id 
    name 
    entity_structure_id 
    parent_id 
); 

Para facilidad de uso que he construido un algoritmo que crea una vista plana del árbol. El siguiente ejemplo concreto ilustra lo que quiero decir:

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 

Esto resultaría en la representación plana siguiente se produce:

entity_tree (
    entity_id 
    division_id 
    area_id 
    store_id 
) 

entidades que están en el nivel de división tendría division_id, area_id y STORE_ID como NULL , Un area area_id y store_id como NULL, etc.

Lo bueno de esto es que le permite consultar a todos los hijos de una división usando una declaración similar a la siguiente:

SELECT * FROM entity_tree WHERE division_id = :division_id; 

Sin embargo, esto supone que conozco el nivel de estructura de la entidad que estoy consultando.Sería bueno hacer:

SELECT * FROM entity_tree WHERE :structure = :entity_id; 

Yo sé que no es difícil de averiguar el nivel de la estructura de una sola entidad, pero supongo que estoy bucle a través de una colección de entidades que no están todos en el mismo nivel . Como está ahora tengo que construir una consulta independiente para cada nivel de la jerarquía, pero si pudiera parametrizar los campos que podía hacer lo siguiente:

$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); 
} 

lo que resulta en un código más limpio y sólo una declaración preparada.

Todo el ejemplo no utiliza ninguna entrada de usuario.

Sólo algo a considerar.

+0

¿Cuál es el punto, sin embargo? De la misma manera, podría usar variables regulares con la misma facilidad ya que no hay entradas de usuario. No hay ninguna posibilidad de inyección aquí. Además, esto debería haber sido publicado como un comentario a mi respuesta, ya que esta no es una respuesta a la pregunta del OP. (Me doy cuenta de que no habrías podido caber, solo notando esto.) –

1

No se puede parametrizar nada dentro de la cláusula IN.

+0

Gracias, me olvidé de eso. Lo agregaré a mi respuesta. –

Cuestiones relacionadas