2009-10-25 32 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