mysqli_stmt::prepare 是 mysqli 扩展中用于预处理 SQL 语句的方法。与直接使用 SQL 查询字符串相比,预处理语句可以减少 SQL 注入的风险。这是因为在执行 SQL 时,用户输入的内容并不会直接拼接到查询字符串中,而是作为绑定参数进行传递。
<span><span><span class="hljs-variable">$conn</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title function_ invoke__">mysqli</span></span><span>(</span><span><span class="hljs-variable">$host</span></span><span>, </span><span><span class="hljs-variable">$user</span></span><span>, </span><span><span class="hljs-variable">$password</span></span><span>, </span><span><span class="hljs-variable">$database</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$conn</span></span><span>->connect_error) {
</span><span><span class="hljs-keyword">die</span></span><span>(</span><span><span class="hljs-string">"Connection failed: "</span></span><span> . </span><span><span class="hljs-variable">$conn</span></span><span>->connect_error);
}
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable">$conn</span></span><span>-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"SELECT * FROM users WHERE username = ? AND password = ?"</span></span><span>);
</span></span>
在上述代码中,SQL 查询包含两个问号(?),它们是占位符,用来接受后续绑定的参数。
在预处理语句中,使用 bind_param() 方法来将用户输入的值绑定到占位符上。此时,绑定的参数值将不会直接插入到 SQL 语句中,而是通过预处理语句传递。bind_param() 方法需要两个参数:数据类型的说明符和要绑定的变量。
常见的数据类型说明符有:
i:整数(int)
d:双精度浮动点数(double)
s:字符串(string)
b:BLOB(binary data)
<span><span><span class="hljs-variable">$username</span></span><span> = </span><span><span class="hljs-string">'john_doe'</span></span><span>;
</span><span><span class="hljs-variable">$password</span></span><span> = </span><span><span class="hljs-string">'password123'</span></span><span>;
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">bind_param</span></span><span>(</span><span><span class="hljs-string">'ss'</span></span><span>, </span><span><span class="hljs-variable">$username</span></span><span>, </span><span><span class="hljs-variable">$password</span></span><span>);
</span></span>
在这个例子中,'ss' 表示绑定的两个参数都是字符串类型。参数 $username 和 $password 将被安全地绑定到 SQL 查询中的占位符。
在参数绑定完成之后,调用 execute() 方法来执行预处理语句。如果绑定的参数类型正确,执行语句将正常运行。
<span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>();
</span></span>
execute() 方法返回一个布尔值,表示语句是否执行成功。如果需要获取查询结果,可以使用 get_result() 方法(针对 SELECT 查询)来获取执行结果。
对于 SELECT 语句,执行完预处理语句后,通常需要获取查询的结果。使用 get_result() 方法可以将查询结果转换为一个 mysqli_result 对象,从中可以获取数据。
<span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">get_result</span></span><span>();
</span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-variable">$row</span></span><span> = </span><span><span class="hljs-variable">$result</span></span><span>-></span><span><span class="hljs-title function_ invoke__">fetch_assoc</span></span><span>()) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-variable">$row</span></span><span>[</span><span><span class="hljs-string">'username'</span></span><span>] . </span><span><span class="hljs-string">' - '</span></span><span> . </span><span><span class="hljs-variable">$row</span></span><span>[</span><span><span class="hljs-string">'email'</span></span><span>] . </span><span><span class="hljs-string">'<br>'</span></span><span>;
}
</span></span>
在这个例子中,查询结果按行提取,并输出用户名和电子邮件。
虽然预处理语句能够防止 SQL 注入,但在实际开发中,仍然可能遇到各种错误。为了有效调试,我们可以使用 error 方法来获取相关的错误信息。
<span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$stmt</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">die</span></span><span>(</span><span><span class="hljs-string">'Error preparing statement: '</span></span><span> . </span><span><span class="hljs-variable">$conn</span></span><span>->error);
}
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>()) {
</span><span><span class="hljs-keyword">die</span></span><span>(</span><span><span class="hljs-string">'Execute error: '</span></span><span> . </span><span><span class="hljs-variable">$stmt</span></span><span>->error);
}
</span></span>
这里使用了 conn->error 和 stmt->error 来捕捉数据库连接和执行语句的错误信息。这能够帮助我们及时发现并解决问题。
使用完预处理语句后,我们需要调用 close() 方法来关闭语句和数据库连接,以释放资源。
<span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">close</span></span><span>();
</span><span><span class="hljs-variable">$conn</span></span><span>-></span><span><span class="hljs-title function_ invoke__">close</span></span><span>();
</span></span>
这不仅是一个良好的编程习惯,而且能有效地避免资源泄露。
相关标签:
mysqli_stmt