在开发 PHP 网站时,用户登录功能几乎是不可或缺的一部分。然而,如果不小心处理用户输入,很容易受到 SQL 注入攻击。mysqli::stmt_init 是 mysqli 扩展提供的一个方法,可以配合预处理语句有效防止 SQL 注入。本文将通过一个具体的例子介绍如何使用它实现一个安全的登录验证机制。
SQL 注入是一种攻击技术,攻击者通过在输入字段中注入恶意 SQL 语句,从而篡改原有的查询逻辑。例如,如果直接拼接 SQL:
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
攻击者可以输入 ' OR '1'='1 作为用户名或密码,使得查询永远为真,绕过认证。
mysqli::stmt_init 用于初始化一个 mysqli_stmt 对象,它是实现预处理语句的第一步,能够将 SQL 与用户输入严格区分,从而有效防止注入攻击。
以下是一个安全登录表单验证示例:
<?php
// 数据库连接
$mysqli = new mysqli("localhost", "db_user", "db_password", "my_database");
// 检查连接
if ($mysqli->connect_errno) {
die("连接失败: " . $mysqli->connect_error);
}
// 用户提交的用户名和密码
$username = $_POST['username'];
$password = $_POST['password'];
// 初始化一个预处理语句对象
$stmt = $mysqli->stmt_init();
// 编写 SQL 查询语句,使用 ? 占位符
$sql = "SELECT id, password_hash FROM users WHERE username = ?";
// 准备语句
if ($stmt->prepare($sql)) {
// 绑定参数(s 表示 string 类型)
$stmt->bind_param("s", $username);
// 执行语句
$stmt->execute();
// 获取结果
$stmt->bind_result($user_id, $password_hash);
// 判断是否有结果
if ($stmt->fetch()) {
// 验证密码(假设数据库中存储的是 password_hash() 的结果)
if (password_verify($password, $password_hash)) {
echo "登录成功,欢迎用户 ID:$user_id";
// 设置会话或跳转,例如:
// header("Location: https://m66.net/dashboard.php");
} else {
echo "密码错误";
}
} else {
echo "用户名不存在";
}
// 关闭语句
$stmt->close();
} else {
echo "SQL 语句准备失败: " . $mysqli->error;
}
// 关闭连接
$mysqli->close();
?>
通过 mysqli::stmt_init 配合预处理语句使用 bind_param,我们可以有效阻止 SQL 注入攻击。开发中应始终使用预处理语句处理用户输入,尤其是在涉及数据库操作时。此外,还应配合使用如 password_hash() 和 password_verify() 的函数来加强密码安全性。
如果你正在构建一个登录系统或用户认证模块,请优先使用这种方式,它比传统的字符串拼接方式安全得多。