我可以使用PDO准备语句绑定标识符(表或字段名称)或语法关键字吗?
我正在处理一个dynamic查询,它使用variables来指定表,字段/列和要search的值。 我已经得到的查询没有variables的预期工作,无论是在phpMyAdmin(手动键入查询),并从代码内通过将variables连接成一个完整的查询。
但是,当我使用bindParam()
或bindValue()
绑定variables时,它将返回一个空数组。
这是我的代码:
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);
预期结果 :数据库中的行数组
实际结果 :一个空数组
我可以使用PDO准备语句绑定标识符(表或字段名称)或语法关键字吗?
不幸的是,准备语句只能表示一个数据文字。 所以,一个非常常见的错误就是这样的查询:
$opt = "id"; $sql = "SELECT :option FROM t WHERE id=?"; $stm = $pdo->prepare($sql); $stm->execute(array($opt)); $data = $stm->fetchAll();
取决于PDO设置,这个查询将导致错误(在使用实际准备的语句的情况下)或只是字段集中的string'id'
(在仿真准备的情况下)。
所以,开发者必须自己处理标识符 – PDO对这个问题没有帮助 。
要使dynamic标识符安全,必须遵循两个严格的规则:
- 正确地格式化标识符
- 以针对硬编码的白名单进行validation。
要格式化标识符,必须应用以下两条规则:
- 用反引号括起标识符。
- 通过加倍他们逃脱反向内部。
格式化之后,将$ tablevariables插入查询是安全的。 所以,代码将是:
$field = "`".str_replace("`","``",$field)."`"; $sql = "SELECT * FROM t ORDER BY $field";
但是,尽pipe这样的格式对于ORDER BY这样的情况来说已经足够了,但在其他大多数情况下,还是有可能进行不同的注入:让用户select他们可以看到的表或字段,我们可以显示一些敏感信息,如密码或其他个人信息。 所以,最好在允许值列表中检查dynamic标识符。 这里是一个简单的例子:
$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 :: quote的用户注释