Php 理解PDO准备的语句和绑定参数

Php 理解PDO准备的语句和绑定参数,php,mysql,pdo,prepare,bindparam,Php,Mysql,Pdo,Prepare,Bindparam,根据经验,并且不断地被告知使用准备好的语句和绑定参数的好处,我在代码中不断地使用这两种技术,但是我想确切地理解这两种技术的目的: 根据我对准备好的声明的理解: $sql = "SELECT * FROM myTable WHERE id = ".$id; $stmt = $conn->prepare($sql); $stmt->execute(); 前面的代码应该使用我提出的查询在数据库中创建一种缓冲区。根据我的理解,前面的代码是不安全的,因为字符串$sql可以是任何东西,这取决于

根据经验,并且不断地被告知使用准备好的语句和绑定参数的好处,我在代码中不断地使用这两种技术,但是我想确切地理解这两种技术的目的:

根据我对准备好的声明的理解:

$sql = "SELECT * FROM myTable WHERE id = ".$id;
$stmt = $conn->prepare($sql);
$stmt->execute();
前面的代码应该使用我提出的查询在数据库中创建一种缓冲区。根据我的理解,前面的代码是不安全的,因为字符串
$sql
可以是任何东西,这取决于
$id
实际上是什么,如果
$id
=
1;下拉表myTable--,我将插入恶意查询,即使我有一个准备好的语句

据我所知这是绑定参数的关键所在。如果我改为执行以下操作:

$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
数据库应该事先准确地知道sql语句的所有部分:
选择以下列:
*
来自myTable
其中id=
“用户输入的变量”,如果
“用户输入的变量”!=变量
,则查询失败


有人告诉我我的理解是正确的,也有人告诉我我的理解是错误的。如果我错了,对了,或者遗漏了什么,有人能告诉我吗?并尽可能详细阐述,非常感谢所有反馈

第一个案例是不安全的,你是对的。但是,重要的是要理解,只有在使用变量数据和/或重复执行同一查询时,准备语句才有价值。如果您正在执行没有变量的纯语句,您可以简单地执行以下操作:

$sql = "SELECT * from myTable WHERE this_column IS NOT NULL";
$result = $conn->query($sql);
最后是要使用的
PDO语句
对象,就像使用
PDO::exec()时一样

对于你的第二个例子,同样,你基本上是正确的。发生的情况是传递给数据库的变量被转义和引用(除非您在
PDOStatement::bindParam()
的第三个参数中另有指定,否则它将作为字符串发送,这在大多数情况下是可以的。)因此,如果发送了错误数据,查询不会“失败”。它的行为就像您传递了一个在数据库中不作为ID存在的有效数字一样。当然,即使有一份准备正确的声明,你仍然容易受到攻击

此外,为了简化操作,您可以使用如下准备好的语句进行隐式绑定:

$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([":id"=>$id]);
或者甚至像这样,使用未命名的参数:

$sql = "SELECT * FROM myTable WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);

当然,在我输入答案的时候,大部分的问题都已经在评论中解释过了

第一个案例是不安全的,你是对的。但是,重要的是要理解,只有在使用变量数据和/或重复执行同一查询时,准备语句才有价值。如果您正在执行没有变量的纯语句,您可以简单地执行以下操作:

$sql = "SELECT * from myTable WHERE this_column IS NOT NULL";
$result = $conn->query($sql);
最后是要使用的
PDO语句
对象,就像使用
PDO::exec()时一样

对于你的第二个例子,同样,你基本上是正确的。发生的情况是传递给数据库的变量被转义和引用(除非您在
PDOStatement::bindParam()
的第三个参数中另有指定,否则它将作为字符串发送,这在大多数情况下是可以的。)因此,如果发送了错误数据,查询不会“失败”。它的行为就像您传递了一个在数据库中不作为ID存在的有效数字一样。当然,即使有一份准备正确的声明,你仍然容易受到攻击

此外,为了简化操作,您可以使用如下准备好的语句进行隐式绑定:

$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([":id"=>$id]);
或者甚至像这样,使用未命名的参数:

$sql = "SELECT * FROM myTable WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);

当然,在我输入答案的时候,大部分的问题都已经在评论中解释过了

第一段代码保护您不受任何影响,因为您仍在将
$id
直接从
$\u POST['id']
传递到query@RiggsFolly因此,我的假设是正确的,即准备好的语句需要
bindParam()
才能安全?您必须使用
?,?
或第二种机制您也可以使用
$stmt->execute([':id'=>$id])
但是基本上绑定是不可见的。关于准备语句,您还缺少的一点是,如果您想在循环中加载数据,您可以
->prepare()
一次并
bind;多次执行()。因此,只需编译和优化一次查询,但要使用它100次。第一段代码可以保护您免受任何影响,因为您仍在将
$id
直接从
$\u POST['id']
传递到query@RiggsFolly因此,我的假设是正确的,即准备好的语句需要
bindParam()
要确保安全,您必须使用
?,?
或第二种机制。您还可以使用
$stmt->execute([':id'=>$id])
但是基本上绑定是不可见的。关于准备语句,您还缺少的一点是,如果您想在循环中加载数据,您可以
->prepare()
一次并
bind;多次执行()。因此,只需编译和优化一次查询,但要使用它100次