在 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'";