8

我有一个类似的功能

function getInfoById($id, $info) {

}

这个想法是有一个查询"SELECT $info FROM table WHERE id = $id"

这不适用于 PDO,因为您无法转义列名。我也不想使用"SELECT *",因为那不是返回更大的结果集并使用更多内存吗?

4

3 回答 3

15

是的,PDO 没有用于分隔标识符(如表名和列名)的内置函数。该PDO::quote()函数仅适用于字符串文字和日期文字。

值得一提的是,当我在 Zend Framework 上工作时,我实现了一个quoteIdentifier()函数。

您是对的,它SELECT *获取所有列,可能会使用更多内存并破坏覆盖索引的好处。

我的建议是将列名列入白名单。也就是说,确保 $info 实际上命名了table. 然后您不必担心列名不存在,或包含奇怪的字符,或任何东西。您可以控制可以合法放入查询的列集。

无论如何,您还应该分隔列名。如果列名包含标点符号、空格、国际字符或与 SQL 保留字匹配,则必须使用分隔标识符。请参阅不同的数据库是否使用不同的名称引用?

function getInfoById($id, $info) {
    // you can make this a literal list, or query it from DESC or INFORMATION_SCHEMA
    $cols = array('col1', 'col2', 'col3');

    if (array_search($info, $cols) === false) {
      return false;
    }
    $sql = "SELECT `$info` FROM table WHERE id = :id";
    $stmt = $pdo->prepare($sql);
    if ($stmt === false) {
      return false;
    }
    . . .
}

我在我的演示SQL 注入神话和谬误中展示了更多的白名单示例。

于 2012-11-19T05:57:56.847 回答
6

我会用一些正则表达式过滤掉它。把事情简单化。

此外,您应该绑定$id并拥有它:id

$info = preg_replace('/[^A-Za-z0-9_]+/', '', $info);

$stmt = $pdo->prepare('SELECT $info FROM table WHERE id = :id'); 
$stmt->bindParam(':id', $id);
$stmt->execute();
于 2012-11-19T05:45:15.077 回答
0

使用quote 和substr 怎么样?

$sql = 'SELECT * FROM table WHERE `' . substr($db->quote($field), 1, -1) . '` = :id';

这将删除转义字段周围的引号。

于 2018-12-16T02:27:31.033 回答