在 PHP 中防止 SQL 注入的最佳实践是使用 预处理语句(Prepared Statements),而不是直接拼接 SQL 字符串。以下是具体方法和示例:
方法 1:使用 PDO(推荐)
// 连接数据库
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8';
$user = 'root';
$pass = '';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false // 禁用预处理模拟
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
// 预处理语句示例
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);方法 2:使用 MySQLi
// 连接数据库
$mysqli = new mysqli('localhost', 'root', '', 'test');
if ($mysqli->connect_error) {
die("数据库连接失败: " . $mysqli->connect_error);
}
// 预处理语句示例
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param('ss', $username, $password); // 'ss' 表示两个字符串参数
$stmt->execute();
$result = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);需要注意的是:
为什么预处理安全?
预处理通过将 SQL 逻辑与数据分离,确保用户输入始终被当作数据处理(而非 SQL 代码)。避免过时方法
mysql_real_escape_string():仅对字符串有效,需配合正确字符集。addslashes():不完全可靠,已被淘汰。magic_quotes_gpc:PHP 5.4+ 已移除,绝对不要依赖。其他过滤建议
使用
filter_input()验证输入格式:$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
对输出到 HTML 的内容使用
htmlspecialchars()防止 XSS。
总结
优先使用预处理语句(PDO 或 MySQLi)。
避免手动拼接 SQL 字符串。
确保数据库连接字符集正确(如
utf8mb4)。保持 PHP 和数据库驱动更新至最新版本。
如果你在维护旧代码且无法使用预处理,至少要做到:
$username = $mysqli->real_escape_string($_POST['username']); $query = "SELECT * FROM users WHERE username = '$username'";