MySQL PDO查询语法错误与?参数

时间:2013-08-05 07:11:27

标签: php mysql syntax parameters pdo

作为一个新手,我已经按照PHP MySQL教程建议使用常规的MySQL php函数。但是,由于我被告知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

为什么?我不知道语法有什么问题。 tutorial I'm reading告诉我,我应该使用bindValue或execute(array(stuff))来添加参数而不是“。$ id”。和喜欢,因为它更安全,但这无论出于何种原因都不起作用。

2 个答案:

答案 0 :(得分:1)

不幸的是,预准备语句只能表示数据文字。 (在模拟准备的情况下)。 因此,开发人员必须自己处理标识符 - PDO为此事提供无帮助

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

  1. 正确格式化标识符。手段
    • 将标识符括在反引号中。
    • 通过加倍来逃避反击。
  2. 根据硬编码白名单进行验证。
  3. 格式化后,可以安全地将$ 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
    

答案 1 :(得分: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";
}

仍然,感谢阅读!