【问题标题】:php PDO UPDATE statements: which is safer?php PDO UPDATE 语句:哪个更安全?
【发布时间】:2012-08-18 15:55:56
【问题描述】:

我正在学习 PDO,发现很难确保我的语句正常工作。我有一个 PHP 函数,它通过简单地将数字 1 添加到总数中来更新我的数据库。

    function add_rating($place_id,$rating_id) {

    //make $db accessible inside the function
    global $db;

    // query v1
    $sql = "UPDATE places_ratings SET ? +1 WHERE place_id=?";
    $q = $db->prepare($sql);
    $q->execute(array($rating_id,$place_id));   

}

我尝试了这种变体,但我都无法开始工作。我不知道我是不是用错了问号。我关注了this guideprevious SO question。最后我尝试了另一种第一次奏效的方法,所以我很想重新使用它,因为它看起来也简单多了。

    function add_rating($place_id,$rating_id) {

    //make $db accessible inside the function
    global $db;

    // query v2
    $query = "UPDATE places_ratings SET $rating_id = ($rating_id +1) WHERE place_id = $place_id";
    $update = $db->query($query);

}

我的问题是:哪种说法更好/更安全?其次,我对带有问号的第一个版本做错了什么?谢谢...

【问题讨论】:

    标签: php mysql pdo


    【解决方案1】:

    一般来说,第一个示例中的准备好的语句更安全,因为它们不受 SQL 注入的影响。

    您的示例不起作用,因为您无法在准备好的语句中使用 ? 参数指定字段名称。即使您的 SQL 仍然是错误的,这将扩展为

     UPDATE places_ratings SET whatever +1 WHERE place_id=?
    

    这是无效的。

    如果您的$rating_id 是在代码中生成的,而不是从用户输入中获取的,您可以将这两种方法结合起来。

    【讨论】:

    • 感谢您指出问号的用法。 $rating_id 不是用户生成的,不是。
    【解决方案2】:

    准备好的语句不是就像将变量复制'n'粘贴到一段文本中。 查询逻辑和查询应该处理的之间的预处理语句分开。它们在那里,所以你可以告诉你的数据库“你应该这样做”,让数据库理解它,然后给它应该用来做某事的值。逻辑本身不能可变,需要第一次完成。

    因此,您只能对值使用占位符。您的查询需要阅读UPDATE ... SET FIELD = VALUE WHERE FIELD = VALUEFIELD 部分需要在语句中,VALUE 部分可以使用占位符。看起来您的 $rating_id 变量是变量字段名称。首先,这是个坏主意。如果可能,您不应使字段名称可变。但是,如果必须,您不能为它们使用准备好的语句占位符。相反,您必须这样做:

    $rating_id = 'field_name';
    $query = "UPDATE places_ratings SET `$rating_id` = `$rating_id` + 1 WHERE `place_id` = ?";
    $stmt = $db->prepare($query);
    $stmt->execute(array($place_id));
    

    您需要确保$rating_id 是安全的并且包含已知的、列入白名单的值。不要让用户以任何方式为其提供值。

    【讨论】:

      【解决方案3】:

      请去了解prepared statements 是什么。您还可以使用tutorial,它不会宣传不良做法和易受攻击的代码。

      正确创建和使用的预处理语句总是比连接查询字符串更安全,因为预处理语句分别发送查询逻辑和数据。

      另外,如果您使用的是 PDO,那么通常应该优先使用 bindParam() 方法,而不是直接在 execute() 方法中将值作为数组传递。这是因为,在 execute() 中传递值时,这些值被绑定为 PDO::PARAM_STR,即使 DB 列期望为整数。

      附: 停止在您的代码中使用 global !!

      【讨论】:

      • 如果我不使用全局 - 让 $db 在函数内部工作的更好方法是什么?
      • 作为参数传入。或者开始学习如何编写面向对象的代码并在构造函数中提供数据库连接。您当前的代码违反了Law of Demeter
      猜你喜欢
      • 2011-09-21
      • 2018-10-05
      • 2012-10-16
      • 2015-12-08
      • 2010-11-21
      • 2012-08-12
      • 2012-07-12
      • 2012-06-07
      相关资源
      最近更新 更多