早期 PHP 開發常見使用 str_replace()、preg_replace() 或自訂函數過濾「危險字符」(如單引號、分號、關鍵字 union、select 等)來防禦 SQL 注入。但這種「黑名單」策略存在根本缺陷:
PDO(PHP Data Objects)與 MySQLi 皆支援預處理語句,將 SQL 邏輯與資料分離,從根本上杜絕注入風險。
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 關鍵:使用真正的預處理
]);
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');
$stmt->execute(['email' => $email, 'status' => 1]);
$user = $stmt->fetch();
$mysqli = new mysqli('localhost', $user, $pass, 'test');
$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ? AND status = ?');
$stmt->bind_param('si', $email, $status);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
雖然預處理語句已解決注入核心問題,但纏合以下措施可構建纏深防禦:
filter_var()、ctype_*() 或正則表達式驗證格式(Email、電話、身分證字號等)。(int)$_GET['id'] 或 filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT)。display_errors,記錄錯誤至日誌供開發者排查。若專案仍大量使用 mysql_* 與手動過濾函數:
magic_quotes_gpc、addslashes()、自訂 safe_replace() 等舊式過濾函數。字串過濾只能作為輔助手段,預處理語句才是防止 SQL 注入的唯一正解。現代 PHP 專案應以 PDO + 真實預處理為基礎,配合嚴格的輸入驗證與最小權限原則,構建穩健的資料庫安全防線。