php - 我可以使用 PDO 准备语句来绑定(bind)标识符(表名或字段名)或语法关键字吗?

标签 php mysql pdo prepared-statement

我正在处理一个动态查询,它使用变量来指定一个表、一个字段/列和一个要搜索的值。我已经让查询在没有变量的情况下按预期工作,无论是在 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 条严格的规则:

  • 正确格式化标识符
  • 根据硬编码白名单对其进行验证。

要格式化一个标识符,必须应用这两条规则:

  • 用反引号括起标识符。
  • 通过将反引号加倍来转义内部的反引号。

经过这样的格式化后,可以安全地将 $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/23482104/

相关文章:

php - 我如何使用 jquery ajax 获取图像?

php - 包含月份和年份的排序字符串 - 'may - 2016'

mysql - 安装后立即拒绝用户 'root' @'localhost' 的访问

javascript - 从 PHP 到 Javascript 的数组处理

php - 使用 find (cakePHP) 时临时删除连接

MYSQL 在 'is null'后使用 'on',在 'where'语句中使用 'left join'

mysql - Rank() 超过 MySQL 中的分区依据

php PDO 传输结果集到数据库

php - PDO mysql 更新错误

php - PDO - 连接查询并输出正确的数据