如何在我的查询中使用原始字段名称?

时间:2015-01-26 08:34:27

标签: php mysql pdo

我正在研究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'));
}

1 个答案:

答案 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的“胆量”,这通常是件好事(当然,一旦你练习了基础知识)。