2013-01-07 40 views
0

我試圖更新我用下面的數據庫:PDO預處理語句 - 語法和消毒

$fields = array(
    'titulo', 
    'tipo_produto', 
    'quantidade_peso', 
    'unidade_de_venda', 
    'unidades_por_caixa', 
    'caixas_piso', 
    'pisos_palete', 
    'tipo_palete', 
    'unidades_palete', 
    'caixas_palete', 
    'uni_diametro', 
    'uni_largura', 
    'uni_profundidade', 
    'uni_altura', 
    'caixa_largura', 
    'caixa_profundidade', 
    'caixa_altura', 
    'altura_palete', 
    'volume_unidade', 
    'volume_caixa', 
    'volume_palete', 
    'peso_caixa', 
    'peso_palete' 
); 
$sql = 'UPDATE ficha_item SET '.implode(', ', array_map(create_function('$value', 'return "$value=\"" . $_POST["$value"] ."\"";'), $fields)).' WHERE id=?'; 

$stmt = $db->prepare($sql); 

$stmt->execute(array($_POST['item_id'])); 
$stmt->closeCursor(); 

這似乎是工作得很好,但我想了解一下安全性,這是在消毒所有?

我想出了這個解決方案嘗試(沒有成功),另一種解決方案後:

$fields = array(
    'titulo', 
    'tipo_produto', 
    'quantidade_peso', 
    'unidade_de_venda', 
    'unidades_por_caixa', 
    'caixas_piso', 
    'pisos_palete', 
    'tipo_palete', 
    'unidades_palete', 
    'caixas_palete', 
    'uni_diametro', 
    'uni_largura', 
    'uni_profundidade', 
    'uni_altura', 
    'caixa_largura', 
    'caixa_profundidade', 
    'caixa_altura', 
    'altura_palete', 
    'volume_unidade', 
    'volume_caixa', 
    'volume_palete', 
    'peso_caixa', 
    'peso_palete' 
); 
$sql = 'UPDATE ficha_item SET ? WHERE id=?'; 

$valuesClause = implode(', ', array_map(create_function('$value', 'return "$value=\"" . $_POST["$value"] ."\"";'), $fields)); 

$stmt = $db->prepare($sql); 

$stmt->execute(array($valuesClause, $_POST['item_id'])); 
$stmt->closeCursor(); 

沒有錯誤可言,但我的數據庫將不會被更新。我的第一個解決方案是否被消毒?我最初的想法出了什麼問題?我認爲這與PDO如何清理執行上的查詢有關......但我不知道該如何處理它。

注意:數據庫列名稱和輸入名稱相同,這就是爲什麼$value工作。如果你也想知道,由於PHP版本的活躍,匿名函數是沒有問題的。

+0

參見[如何擠錯誤消息出來PDO的?](http://stackoverflow.com/q/3726505)如何得到一個有意義的錯誤消息。丹尼爾的答案是正確的,雖然,PDO的轉義是數據而已,不列名。 –

回答

1
$fields = array(
    'titulo', 
    'tipo_produto', 
    'quantidade_peso', 
    'unidade_de_venda', 
    'unidades_por_caixa', 
    'caixas_piso', 
    'pisos_palete', 
    'tipo_palete', 
    'unidades_palete', 
    'caixas_palete', 
    'uni_diametro', 
    'uni_largura', 
    'uni_profundidade', 
    'uni_altura', 
    'caixa_largura', 
    'caixa_profundidade', 
    'caixa_altura', 
    'altura_palete', 
    'volume_unidade', 
    'volume_caixa', 
    'volume_palete', 
    'peso_caixa', 
    'peso_palete' 
); 
$sql="UPDATE ficha_item SET ".implode(", ",array_map(function($s){ 
    return "$s = ?"; 
},$fields))." WHERE id=?"; 
print_r($sql); 

輸出:

UPDATE ficha_item SET titulo = ?, tipo_produto = ?, quantidade_peso = ?, unidade_de_venda = ?, unidades_por_caixa = ?, caixas_piso = ?, pisos_palete = ?, tipo_palete = ?, unidades_palete = ?, caixas_palete = ?, uni_diametro = ?, uni_largura = ?, uni_profundidade = ?, uni_altura = ?, caixa_largura = ?, caixa_profundidade = ?, caixa_altura = ?, altura_palete = ?, volume_unidade = ?, volume_caixa = ?, volume_palete = ?, peso_caixa = ?, peso_palete = ? WHERE id=? 

這是SQL語句,你需要prepare。現在,讓你的準備好的語句

$stmt=$db->prepare($sql); 
$stmt->execute(array_merge(array_map(function($s){ 
    return $_POST[$s]; 
},$fields),array($_POST["item_id"]))); 

沒有數據庫,對我來說,測試,但這應該是在正確的軌道。

請注意,我只是遵循你的「風格」;儘管此代碼將所有$_POST作爲參數對待,並因此避免了SQL注入,但它假設每個$_POST[$fields[$idx]]都存在,這很容易被任何用戶破解,所以這是您應該清理的地方。

編輯

既然你已經更新,你不能使用匿名函數,您可以手動構建所需的數組:

$cache=array(); 
foreach($fields as $field) 
    $cache[]="$field = ?"; 
$sql="UPDATE ficha_item SET ".implode(", ",$cache)." WHERE id=?"; 

$cache=array(); 
foreach($fields as $field) 
    $cache[]=isset($_POST[$field])?$_POST[$field]:null; 
$cache[]=$_POST["item_id"] 
/*...*/ 
$stmt->execute($cache); 
2

準備好的語句是一個準備好的語句,語句參數/參數不被視爲SQL,原因很明顯。

您需要在準備語句前準備好您的查詢。

我建議你閱讀PDO手冊。您還應該看看this question以瞭解如何保護您的查詢。

$columns = array(); 
foreach ($fields as $column) 
    $columns[] = "$column = ?"; 

$sql = "UPDATE table SET " . implode(" AND ", $columns) . " WHERE id = ? "; 

// Now you may prepare the statement 
1

你有良好的目的
當你的字段是白名單在你的代碼中,它足夠保護(事實上,白名單是唯一適當的解決方案)。

因此,您唯一需要的是從白名單和$ _POST數組中獲取正確的SQL。
Voila - here is a useful function written for this very purpose
與它的代碼將是

$sql = "UPDATE ficha_item SET ".pdoSet($fields,$values)." WHERE id = :id"; 
$stmt = $db->prepare($sql); 
$values["id"] = $_POST['id']; 
$stmt->execute($values); 

(用戶自定義)功能是巨大的。不知道爲什麼沒有人使用它們。