当前位置: 首页 > 知识库问答 >
问题:

何时在PHP Mysqli中使用准备好的语句?-用户表单搜索输入与选择查询

李兴安
2023-03-14

我试图理解什么时候应该在php/mysqli中使用准备好的语句。每个php/mysqli查询应该使用准备好的语句,还是只使用涉及用户输入的查询和实例。。。比如一个html表单,它要求用户输入要在数据库中搜索的数据?

我正在将旧的php5/mysql代码迁移到php7/mysqli。我有许多查询mysql数据库的php文件。我想澄清一下,如果我需要为每个连接到mysql数据库的php文件使用准备好的语句。。。例如,通过“php require”引用的php文件,包括简单的sql select语句来呈现图像和指向html页面的链接?

<?php

//establish connection

$con = new mysqli('localhost','uid','pw','db');

//check connection

if ($con->connect_error) {
die("Connection failed: " . $con->connect_error);  
}

//search variable that stores user input

$search = "%{$_POST['search']}%";

//prepare, bind and fetch

$stmt = $con->prepare("SELECT image, caption FROM `tblimages`
WHERE catid = 3 AND caption LIKE ? order by caption ASC");
$stmt->bind_param("s", $search);
$stmt->execute();
$stmt->bind_result($image,$caption);

while ($stmt->fetch()) {
echo "{$image} <br> {$caption} <br>";    
}

$stmt->close();

//close database connection

mysqli_close($con);

?>

上面的代码很有效,是我第一次使用预处理语句。它从表单(空白框输入搜索词-帖子)中获取用户输入,并搜索数据库。。。然后将结果呈现到html页面。这似乎是对预先准备好的语句的合理使用。然而我有其他php文件,其中用户从表单中的下拉框中选择数据以呈现结果(用户不会像上面那样将数据输入搜索框)。我是否也会对该实例使用准备好的语句?另外,我是否为通过“php require”引用的php文件使用准备好的语句,并包括简单的sql select语句来呈现图像和指向html页面的链接?我还没有找到使用准备好的语句来防止sql注入的具体实例的说明。欢迎任何澄清或参考。

共有2个答案

钱星辰
2023-03-14

以下是MySQLi prepared语句在PHP中的工作方式:

准备一个以空值作为占位符的SQL查询(每个值都有一个问号)。通过声明每个变量及其类型,将变量绑定到占位符。执行查询。允许的四种变量类型:

i-整数

D-双

s-字符串

b-水滴

顾名思义,准备好的语句是一种准备MySQL调用的方法,无需存储变量。你告诉它变量最终会到达那里——只是还没有。演示它的最佳方式是通过示例。

$stmt = $mysqli->prepare("SELECT * FROM myTable WHERE name = ? AND age = ?");
$stmt->bind_param("si", $_POST['name'], $_POST['age']);
$stmt->execute();
//fetching result would go here, but will be covered later
$stmt->close();

如果您以前从未见过准备好的声明,这可能看起来有点奇怪。基本上,您正在为SQL语句创建一个模板。在本例中,我们从myTable中选择所有内容,其中name和age相等?。问号只是值的位置的占位符。

bind\u param()方法用于将变量附加到准备好的模板中的伪值。注意变量前的引号中有两个字母。这会告诉数据库变量类型。s指定名称为字符串值,而i强制年龄为整数。这正是为什么我没有在名称的问号周围添加引号,就像我通常在SQL调用中为字符串添加引号一样。你可能以为我忘记了,但事实是根本没有必要这样做(事实上,如果在?周围加引号,实际上是行不通的,因为它将被视为字符串文字,而不是虚拟占位符)。

您已经告诉它,当您调用bind_param()时,它将是一个字符串文字,因此即使恶意用户试图将SQL插入到您的用户输入中,它仍然会被视为一个字符串。$stmt-

贝滨海
2023-03-14

简短回答:始终使用准备好的陈述。

长答案:

预准备语句将您的数据与SQL命令分开。它们由PDO或MySQLi提供。它们最大的优点是,如果您的数据被视为数据,则不可能有SQL注入。另一个优点是,您可以使用不同的数据集一遍又一遍地执行相同的查询,这可能对您的性能更好,并且通常会使您的代码更干净。

然而,有时您希望基于用户的选择或操作进行某种动态查询。您可能知道,表名和列名不是数据,而是SQL查询的一部分,因此不能将它们分开。然后,准备好的语句的替代方法是有一个可能值的白名单,并且只允许根据白名单验证用户输入。

您可能会问什么是查询、实查询、多查询和PDO::exec
正如PHP手册所示,当您只需要执行不带任何变量的常量查询时,或者当您有一个无法准备的查询时,它们都很好。例如

$mysqli->query('SELECT Name FROM City LIMIT 10');
$pdo->exec('DELETE FROM fruit');
$mysqli->multi_query('DELETE FROM fruit; DELETE FROM pets;');

如果您知道数据的类型和值,该怎么办?您是否也应准备/绑定<是的!养成用SQL查询绑定所有数据的习惯。没有理由做出例外。要在代码中跟踪这些异常要困难得多,并且始终确保不会用一些未知输入覆盖“safe”值。

如果您仍然不确定如何使用预先准备好的语句,或者您认为它们太复杂(其实不是),那么可以在https://phpdelusions.net

 类似资料:
  • 问题内容: 我已经使用预备语句尝试了几次,但是它返回SQL异常。这是我的代码: 运行此程序时,出现以下SQL异常: 有什么建议可以使这项工作吗?任何代码都值得赞赏。 问题答案: 您需要使用: 代替 当您将字符串传递给 该 查询时,将按字面意义执行查询,因此将其发送到数据库,然后数据库会产生错误。通过传递查询字符串,您不会执行传递值的“已缓存”准备语句。

  • 问题内容: 我的目的是在表中找到与存储在String中的集合匹配的所有项目: 这似乎并不完美,它总是向我发出以下警告: 如果我有一个参数,这将是显而易见的: 但是由于我不得不处理这个问题,这对我来说有点复杂。 问题答案: Prepared语句没有参数,因为您在准备列表之前已将列表插入到该语句中。 至此,您创建的SQL语句为: 由于该语句没有参数,因此失败。而不是将项目插值到语句(容易注入)中,而是

  • 问题内容: 我创建了一个准备好的选择查询,但该查询似乎没有接听,或者结构错误。我正在尝试显示user_id图像的最后一个。显示用户的图像,但这是他们拥有的第一个id图像。我试着做,那是同一回事。 我这样做对吗? 问题答案: 我认为您不能: 在order by子句中使用占位符 绑定列名:您只能绑定值或变量,并将其值注入到prepared语句中。

  • 问题内容: 在mysqli准备好的语句中,NULL变成’‘(对于字符串)或0(对于整数)。我想将其存储为真正的NULL。有什么办法吗? 问题答案: 我知道这是一个旧线程,但是可以将真实的NULL值绑定到准备好的语句(请阅读this)。 实际上,您可以使用mysqli_bind_parameter将NULL值传递给数据库。只需创建一个变量并将NULL值(请参见手册页)存储到该变量并将其绑定即可。无论

  • 问题内容: 我正在使用JDBC模板,并希望使用准备好的语句从数据库中读取数据。我遍历.csv文件中的许多行,并且在每一行上执行一些具有相应值的SQL选择查询。 我想加快从数据库中的读取速度,但是我不知道如何使JDBC模板与准备好的语句一起使用。 有PreparedStatementCreator和PreparedStatementSetter。如本例所示,它们都是使用匿名内部类创建的。但是在Pre