2009-10-25 34 views
8

我在PHP/PDO中准备好的语句。基本查询做工精细,值传递给WHERE子句:哪些令牌可以在PDO预准备语句中进行参数化?

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

但是我有一个情况我需要传递变量的字段名。该查询(在适当的结合)工作正常:

SELECT :field FROM episode WHERE id=:id 

这一次给出了一个错误:

SELECT title FROM :field WHERE id=:id 

这一次不给一个错误,但不返回行:

SELECT title FROM episode WHERE :field=:id 

那么,什么事情应该在准备好的陈述中工作?我可以'参数化'字段名称,表格名称等等吗?

回答

10

您不能参数化表格名称,列名称或IN子句中的任何内容(感谢pointing out the IN clause restriction的c0r0ner)。

参见this question,以及随后的this comment in the PHP manual

+0

感谢您的回复。事实证明,我发布的第一个查询不起作用 - 如果你把''title''绑定到':field',那么它只是选择字符串'title'而不是字段的值。奇怪的是,没有一种方法来绑定列/表,因为现在我需要增加一些额外的安全性,PDO应该为我处理:/ – DisgruntledGoat 2009-10-26 00:27:58

+0

这背后的想法可能是你真的不应该让你的用户直接选择查询所调用的字段/表格。但我同意它确实会在你的结尾添加一些额外的工作。 – 2009-10-26 01:25:17

+0

我明白你的观点。然而,我只在我指定表的情况下使用它,但是以抽象的方式,例如'displayTable( '插曲')'。我想我并不需要担心在这种情况下的参数/安全性。 – DisgruntledGoat 2009-10-27 11:46:40

1

@乔希Leitzel

这种想法是非常有限的(并且是在我看来,仅仅因为是懒得去实现一个强大的解决方案的借口),特别是在数据库中表达的动态树结构。

请看下面的例子:

我的项目有一个逻辑结构:

一个公司层级中的实体表示。每个实体都可以在一般情况下作为层次结构的成员或作为层次结构的特定级别的成员来处理。层次结构本身是在一个表中定义为一个单一的树枝如下:

entity_structure (
    id 
    name 
    parent_entity_structure_id 
); 

和实体本身表示为:

entities (
    id 
    name 
    entity_structure_id 
    parent_id 
); 

为了便于使用,我已经建立了创建算法树的平面图。下列具体实施例说明了我的意思:

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 

这将导致所生产的以下平面表示:

entity_tree (
    entity_id 
    division_id 
    area_id 
    store_id 
) 

实体是在分割级别将具有division_id,AREA_ID和STORE_ID为NULL ,区域area_id和store_id为NULL等。

这样做的好处是它可以让您使用类似于以下语句查询分部的所有子项:

SELECT * FROM entity_tree WHERE division_id = :division_id; 

但是,这假定我知道我正在查询的实体的结构级别。这将是很好的事:

SELECT * FROM entity_tree WHERE :structure = :entity_id; 

我知道这不是很难找出一个单一实体的结构水平,但假设我通过实体的集合可能不是所有在同一水平循环。因为它是现在我必须建立对每个层次进行单独查询,但如果我能参数场我能做到以下几点:

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

导致更干净的代码,只有一个事先准备好的声明。

整个示例不使用任何用户输入。

只是要考虑。

+0

但是有什么意义呢?由于没有用户输入,因此可以在此实例中轻松使用常规变量。这里没有任何注射机会。另外,这应该已经作为我的回答的评论发布了,因为这不是OP问题的答案。 (我意识到你不能适应它,只是注意到这一点。) – 2009-10-27 19:48:40

1

您也不能参数化IN子句中的任何内容。

+0

谢谢,我忘了这一点。我会将其添加到我的答案。 – 2009-10-27 19:49:37