0

作为一个新手,我遵循了建议使用常规 MySQL php 函数的 PHP MySQL 教程。但是,由于有人告诉我 PDO 是更好的选择,我一直在将我的代码转换为它。我刚刚遇到以下问题:

    $query = $uspdb->prepare("SELECT post_id, is_approved, reports FROM ? WHERE id=? AND ?");
    $query->bindValue(1, $table, PDO::PARAM_INT);
    $query->bindValue(2, $id, PDO::PARAM_INT);
    $query->bindValue(3, checkPermission("comment_moderation"),PDO::PARAM_BOOL);
    $query->execute;
    $result = $query->fetch(PDO::FETCH_ASSOC);

第一行抛出以下 PDO 异常:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? WHERE id=? AND ?' at line 1

这是为什么?我不知道语法可能有什么问题。我正在阅读的教程告诉我应该使用 bindValue 或 execute(array(stuff)) 添加参数,而不是“.$id”。等等,因为它更安全,但无论出于何种原因,这都不起作用。

4

2 回答 2

1

不幸的是,准备好的语句只能表示数据文字。(在模拟准备的情况下)。因此,开发人员必须自己处理标识符 - PDO对此没有任何帮助

为了使动态标识符安全,必须遵循 2 条严格的规则:

  1. 正确格式化标识符。方法
    • 将标识符括在反引号中。
    • 通过将它们加倍来逃避内部的反引号。
  2. 根据硬编码的白名单对其进行验证。

格式化后,将 $table 变量插入查询是安全的。因此,代码将是:

$field = "`".str_replace("`","``",$field)."`";
$sql   = "SELECT * FROM t ORDER BY $field";

然而,尽管这样的格式对于像 ORDER BY 这样的情况就足够了,但对于大多数其他情况,可能会有不同类型的注入:让用户选择他们可以看到的表或字段,我们可能会透露一些敏感信息,例如密码或其他个人数据。因此,最好根据允许值列表检查动态标识符。这是一个简短的例子:

$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed));
if ($key === false) {
    throw new Exception('Wrong field name');
}
$field = $allowed[$key];
$query   = "SELECT $field FROM t"; //value is safe
于 2013-08-05T07:16:18.270 回答
0

通常,我在提出问题后几秒钟就解决了我的问题。

问题是您只能绑定这样的键值,而不是表名或列名。我必须像以前一样手动插入表名和列名:

$query = $uspdb->prepare("SELECT post_id, is_approved, reports FROM $table WHERE id=? AND ?");
$query->execute(array($id,checkPermission("comment_moderation")));
$result = $query->fetch(PDO::FETCH_ASSOC);

如果表或列名由用户自行决定,您应该通过额外的步骤对其进行清理,这些步骤在上面您的常识的回复中有详细说明。就我而言,它是以下代码:

$type = $_GET[type];

switch($type) {
    case "review":
        $table = "site_cmt_reviews";
        break;
    default:
        $table = "site_cmt_articles";
}

不过,感谢您的阅读!

于 2013-08-05T07:17:58.460 回答