我可以使用PDO准备好的语句来绑定标识符(表名或字段名)或语法关键字吗?
我可以使用PDO准备好的语句来绑定标识符(表名或字段名)或语法关键字吗?
我正在处理一个动态查询,使用变量来指定表格、字段/列以及要搜索的值。在没有使用变量的情况下,我已经成功地使查询按预期工作,无论是在phpMyAdmin(手动键入查询)还是在代码中通过将变量连接成一个完整的查询来执行。\n然而,当我使用bindParam()
或bindValue()
来绑定变量时,它返回一个空数组。\n以下是我的代码:\n
function search_db($db, $searchTerm, $searchBy, $searchTable){ try{ $stmt = $db->prepare(' SELECT * FROM ? WHERE ? LIKE ? '); $stmt->bindParam(1, $searchTable); $stmt->bindParam(2, $searchBy); $stmt->bindValue(3, '%'. $searchTerm.'%'); $stmt->execute(); } catch(Exception $e) { return array(); } return $stmt->fetchAll(PDO::FETCH_ASSOC); } // 数据库初始化,创建$db变量 require(ROOT_PATH . "include/database.php"); $matches = search_db($db, 'search term', 'myColumn', 'myTable'); var_dump($matches);
\n期望的结果:从数据库返回一组行数据\n实际的结果:一个空数组
问题的原因是PDO的预处理语句只能绑定数据字面量,无法绑定标识符(例如表名或字段名)或语法关键字。这导致了一个常见的问题,即在查询中无法获取绑定的标识符的值,而只能得到字面字符串。
解决方法是开发者自己来处理标识符的安全性,因为PDO在这方面提供的帮助非常有限。为了使动态标识符安全,必须遵循以下两个严格的规则:
1. 正确格式化标识符:
- 用反引号将标识符括起来。
- 在反引号内部使用两个连续的反引号来转义。
例如,对于表名或字段名的变量$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); $field = $allowed[$key]; $query = "SELECT $field FROM t"; //value is safe
对于语法关键字,规则相同,但显然没有可用的格式化方法,因此只能使用白名单验证:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC'; $sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
通过遵循这些规则,开发者可以安全地处理动态标识符和语法关键字,从而避免注入攻击的风险。