84669 人学习
152542 人学习
20005 人学习
5487 人学习
7821 人学习
359900 人学习
3350 人学习
180660 人学习
48569 人学习
18603 人学习
40936 人学习
1549 人学习
1183 人学习
32909 人学习
为什么我无法将表名传递给准备好的 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"
要了解为什么绑定表(或列)名称不起作用,您必须了解准备好的语句中的占位符如何工作:它们不是简单地替换为(适当转义的)字符串,并执行生成的 SQL。相反,要求“准备”语句的 DBMS 会针对如何执行该查询提出完整的查询计划,包括将使用哪些表和索引,无论您如何填写占位符,这些计划和索引都是相同的。
SELECT name FROM my_table WHERE id = :value 的计划将与您替换 :value 的内容相同,但表面上相似的 SELECT name FROM :table WHERE id = :value 无法计划,因为 DBMS 不知道您实际要从中选择哪个表。
SELECT name FROM my_table WHERE id = :value
:value
SELECT name FROM :table WHERE id = :value
这也不是像 PDO 这样的抽象库可以或应该解决的问题,因为它会破坏准备好的语句的 2 个关键目的:1)允许数据库提前决定如何运行查询,以及多次使用同一个计划; 2) 通过将查询逻辑与变量输入分离来防止安全问题。
表名和列名不能用 PDO 中的参数替换。
在这种情况下,您只需手动过滤和清理数据。实现此目的的一种方法是将简写参数传递给将动态执行查询的函数,然后使用 switch() 语句创建用于表名称的有效值白名单或列名。这样,用户输入就不会直接进入查询。例如:
function buildQuery( $get_var ) { switch($get_var) { case 1: $tbl = 'users'; break; } $sql = "SELECT * FROM $tbl"; }
通过不保留默认情况或使用返回错误消息的默认情况,您可以确保只使用您想要使用的值。
要了解为什么绑定表(或列)名称不起作用,您必须了解准备好的语句中的占位符如何工作:它们不是简单地替换为(适当转义的)字符串,并执行生成的 SQL。相反,要求“准备”语句的 DBMS 会针对如何执行该查询提出完整的查询计划,包括将使用哪些表和索引,无论您如何填写占位符,这些计划和索引都是相同的。
SELECT name FROM my_table WHERE id = :value
的计划将与您替换:value
的内容相同,但表面上相似的SELECT name FROM :table WHERE id = :value
无法计划,因为 DBMS 不知道您实际要从中选择哪个表。这也不是像 PDO 这样的抽象库可以或应该解决的问题,因为它会破坏准备好的语句的 2 个关键目的:1)允许数据库提前决定如何运行查询,以及多次使用同一个计划; 2) 通过将查询逻辑与变量输入分离来防止安全问题。
表名和列名不能用 PDO 中的参数替换。
在这种情况下,您只需手动过滤和清理数据。实现此目的的一种方法是将简写参数传递给将动态执行查询的函数,然后使用 switch() 语句创建用于表名称的有效值白名单或列名。这样,用户输入就不会直接进入查询。例如:
通过不保留默认情况或使用返回错误消息的默认情况,您可以确保只使用您想要使用的值。