PHP PDO 语句是否可以接受表名或列名作为参数?

2022-08-30 06:08:54

为什么我无法将表名传递给准备好的 PDO 语句?

$stmt = $dbh->prepare('SELECT * FROM :table WHERE 1');
if ($stmt->execute(array(':table' => 'users'))) {
    var_dump($stmt->fetchAll());
}

有没有另一种安全的方法可以将表名插入到 SQL 查询中?有了安全,我的意思是我不想做

$sql = "SELECT * FROM $table WHERE 1"

答案 1

表和列名不能由 PDO 中的参数替换。

在这种情况下,您只需要手动过滤和清理数据。执行此操作的一种方法是将速记参数传递给将动态执行查询的函数,然后使用语句创建要用于表名或列名的有效值的白名单。这样,任何用户输入都不会直接进入查询。例如:switch()

function buildQuery( $get_var ) 
{
    switch($get_var)
    {
        case 1:
            $tbl = 'users';
            break;
    }

    $sql = "SELECT * FROM $tbl";
}

通过不保留默认大小写或使用返回错误消息的默认大小写,可以确保仅使用要使用的值。


答案 2

要了解为什么绑定表(或列)名称不起作用,您必须了解预准备语句中的占位符的工作原理:它们不是简单地替换为(适当转义的)字符串,而是执行生成的SQL。相反,要求“准备”语句的 DBMS 会针对如何执行该查询(包括它将使用哪些表和索引)提出一个完整的查询计划,无论您如何填写占位符,这些计划都将是相同的。

无论您替换什么,其计划都将是相同的,但是看似相似的计划无法计划,因为DBMS不知道您实际上要从哪个表中进行选择。SELECT name FROM my_table WHERE id = :value:valueSELECT name FROM :table WHERE id = :value

这也不是像PDO这样的抽象库可以或应该解决的问题,因为它会破坏预准备语句的2个关键目的:1)允许数据库提前决定如何运行查询,并多次使用相同的计划;和 2) 通过将查询的逻辑与变量输入分开来防止安全问题。


推荐