在PHP中,为了防止SQL注入攻击,有两种主要的方法来确保用户输入的安全性,当向MySQL数据库插入数据时:
-
mysqli_real_escape_string()
:
mysqli_real_escape_string()
是MySQLi扩展提供的一个函数,它会对字符串中的特殊字符进行转义,特别是那些可能导致SQL注入的字符,如单引号 ('
)、双引号 ("
)、反斜线 (\
) 和NULL字节。使用方法如下:$conn = mysqli_connect("localhost", "username", "password", "database"); $unescaped_string = $_POST['user_input']; $escaped_string = mysqli_real_escape_string($conn, $unescaped_string); // 使用转义后的字符串构建SQL查询 $sql = "INSERT INTO table (column) VALUES ('$escaped_string')"; mysqli_query($conn, $sql);
注意,这个函数的效果依赖于当前数据库连接的字符集设置,所以在使用前应当确保已经正确设置了连接的字符集,否则可能会有潜在的安全风险。
-
预处理语句(Prepared Statements):
预处理语句是一种更安全的方式来执行动态SQL,它会在服务器端独立编译SQL模板,并将用户输入作为参数传递,从而彻底杜绝SQL注入。在PHP中,你可以使用MySQLi或PDO扩展来实现预处理语句。使用MySQLi:
$stmt = mysqli_prepare($conn, "INSERT INTO table (column) VALUES (?)"); mysqli_stmt_bind_param($stmt, "s", $unescaped_string); mysqli_stmt_execute($stmt);
或者在PHP 8中,如果MySQLi扩展引入了新的接口(实际上PHP 8并没有增加
execute_query
这样的新方法),假设存在类似简化的方法,可能是这样的:// 假设PHP 8中存在某种简化形式,但实际上并不真实存在 $stmt = mysqli_prepare_and_execute($conn, "INSERT INTO table (column) VALUES (?)", [$unescaped_string]);
**其中的?为占位符
通过告诉数据库参数的数据类型,可以降低 SQL 注入的风险。参数有
以下四种类型:
•i-integer(整型)
•d-double(双精度浮点型)
※s-string(字符串)
•b-BLOB(binary large object:二进制大对象)
每个参数都需要指定类型。//预处理 $sql = "INSERT INTO user (username, password, phone)VALUES (?,?,?)"; $stmt = $conn->prepare($sql); $stmt->bind_param("sss",$username,$password, $phone); //执行 $stmt->execute(); //获取结果 if ($stmt->affected_rows >e) { echo“插入成功“; } else { echo“插入失败”;
使用PDO**:
$pdo = new PDO("mysql:host=localhost;dbname=database;charset=utf8", "username", "password"); $stmt = $pdo->prepare("INSERT INTO table (column) VALUES (:value)"); $stmt->bindParam(':value', $unescaped_string); $stmt->execute();
预处理的优势在于它将SQL结构与数据值分离,确保了即使用户输入包含恶意的SQL代码,也不会被执行,而是当作普通文本对待。
php8新方法
$name=“这是一个‘送命题'“; //mysqli_execute_query $sql = "INSERT INTO user (username, password, phone) VALUES (?,?,?)1'; conn->execute_query(conn−>executequery(sql,[$name,'123456','13888888888']);
无论是PHP 7还是PHP 8,预处理语句的使用方式都是推荐的最佳实践,因为它能提供更高的安全性并可提高性能(因为对于相同的查询结构,数据库只需解析一次)。