我正在开发一个动态查询,它使用变量来指定表、字段/列和要搜索的值。我已经让查询在没有变量的情况下按预期工作,无论是在 phpMyAdmin 中(手动键入查询)还是在代码中通过将变量连接到完整的查询中。
但是,当我使用 bindParam()
或 bindValue()
绑定(bind)变量时,它返回一个空数组。
这是我的代码:
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);
}
// database initialization, creates the $db variable
require(ROOT_PATH . "include/database.php");
$matches = search_db($db, 'search term', 'myColumn', 'myTable');
var_dump($matches);
预期结果:数据库中的行数组
实际结果:空数组
最佳答案
不幸的是,占位符只能表示数据文字。因此,一个非常常见的陷阱是这样的查询:
$opt = "id";
$sql = "SELECT :option FROM t";
$stm = $pdo->prepare($sql);
$stm->execute([':option' => $opt]);
$data = $stm->fetchAll();
此语句将仅返回字段集中的文字字符串 'id'
,而不是名为 id
的列的值。
因此,开发人员必须自己处理标识符 - PDO 对此问题没有帮助。
为了使动态标识符安全,必须遵循 2 条严格的规则:
- 正确设置标识符格式
- 根据硬编码白名单进行验证。
要格式化标识符,必须应用以下 2 条规则:
- 将标识符括在反引号中。
- 通过将反引号加倍来将其转义。
经过这样的格式化后,可以安全地将$table
变量插入查询中。因此,代码将是:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
然而,虽然这种格式对于像 ORDER BY 这样的情况来说已经足够了,但对于大多数其他情况,有可能进行不同类型的注入(inject):让用户选择他们可以看到的表或字段,我们可能会透露一些敏感信息,例如密码或其他个人数据。因此,最好根据允许值列表检查动态标识符。这是一个简短的示例:
$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
关于php - 我可以使用 PDO 准备语句来绑定(bind)标识符(表或字段名称)或语法关键字吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54571652/