我正在研究PDO并尝试更简单地使用插入和更新查询。我对上一个问题得到了很好的答案,但他们也指出我的查询中存在严重的注入问题。我已经尝试过自己解决这个问题,但事实并没有像我想象的那样顺利。如何在这些查询中删除注入问题?请帮我!
function pdoSet($fields, &$values, $source = array()){
$set = '';
$values = array();
if(!$source) $source = &$_POST;
foreach($fields as $field){
if(isset($source[$field])){
$set .= " $field =:$field, ";
$values[$field] = $source[$field];
}
}
return substr($set, 0, -2);
}
$fields = array(
'name'
, 'part'
, 'tel'
, 'email'
, 'title'
, 'contents'
);
if(!$idx){
$fields[] = 'reg_date';
$values[] = 'now()';
$st = $pdo -> prepare("insert into qna_board set ".pdoSet($fields, $values));
$st->execute($values);
}else{
$st = $pdo -> prepare("update qna_board set ".pdoSet($fields, $values)." where idx = :idx");
$st ->bindParam(":idx", $idx);
$st->execute($values + compact('idx'));
}
答案 0 :(得分:0)
首先,你的代码看起来很容易被SQL注入(就像在his answer中所说的Deceze),但经过仔细研究后我确信它是安全的。
看起来令人不安的部分是:
foreach($fields as $field){
if(isset($source[$field])){
$set .= " $field =:$field, ";
$values[$field] = $source[$field];
}
}
您正在动态生成column => placeholder
对,看起来这些值来自$_POST
超全局,但它们不是。{传递给pdoSet()
的第一个参数始终是硬编码数组,而不是基于保护您注射的用户输入。
作为旁注,我会重新考虑你的代码设计。你说你只是在学习PDO(我鼓掌,这是一个很好的驱动程序),所以这里有一个非常简单的OOP片段,它更清晰一点,你可以自己做一个:
class FooBarBaz
{
/**
* @var PDO
*/
protected $pdo;
/**
* @param string $index
* @param array $input_values
* @return bool
*/
public function update($index = null, Array $input_values = null)
{
if (is_null($input_values))
{
$input_values = $_POST;
}
$column_list = [
'name',
'part',
'tel',
'email',
'title',
'contents',
];
$placeholders = [];
$query_values = [];
foreach ($column_list as $column_name)
{
if (array_key_exists($column_name, $input_values))
{
$placeholders[] = sprintf('`%s` = :%s', $column_name, $column_name);
$query_values[$column_name] = $input_values[$column_name];
}
}
if (isset($index))
{
$sql = sprintf('UPDATE qna_board SET %s WHERE idx = :idx', implode(',', $placeholders));
$query_values['idx'] = $index;
}
else
{
$sql = sprintf('INSERT INTO qna_board SET %s, reg_date = NOW()', implode(',', $placeholders));
}
return $this->pdo->prepare($sql)->execute($query_values);
}
}
也不是我如何从字面上指定SQL函数NOW()
。这是因为这样的数据必须在分析时(see this answer)传递给PDO。请注意,您还应该检查错误/异常(您应该配置PDO以使用后者)并适当地处理它们。一个好的DBAL也会从程序员那里抽象出许多PDO的“胆量”,这通常是件好事(当然,一旦你练习了基础知识)。