我正在尝试使用以下内容更新我的数据库:
$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 :(得分: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 :(得分: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=?
这是prepare
所需的 SQL语句。现在来获取准备好的声明:
$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 :(得分: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);
(用户定义)功能很棒。 Dunno为什么没有人使用它们。