「不信任任何輸入」是安全開發鐵律。本文整理 PHP 歷史轉義函數演進、情境化處理策略、現代最佳實踐,建立完整資料淨化防護體系。
| 函數/特性 | 狀態 | 問題 | 現代替代 |
|---|---|---|---|
| magic_quotes_gpc | PHP 5.4 移除 | 自動跳脫汙染原始資料、雙重跳脫、誤導安全感 | 手動情境化處理 |
| addslashes() | 不推薦 | 非資料庫專用、多位元組字元繞過風險 | PDO Prepared Statements |
| mysql_real_escape_string() | PHP 7.0 移除 (mysql_*) | 需連線資源、僅限 MySQL | PDO::quote() 或參數化查詢 |
| ereg/eregi_replace() | PHP 7.0 移除 | POSIX 正則效能差、不支援 Unicode | preg_replace() / 專用函數 |
<?php
function h($str, $flags = ENT_QUOTES | ENT_SUBSTITUTE, $encoding = 'UTF-8') {
return htmlspecialchars($str, $flags, $encoding);
}
// 使用
echo "<div>" . h($userInput) . "</div>";
echo "<input value='" . h($userInput) . "'>"; // ENT_QUOTES 處理單引號
?>
ENT_QUOTES:雙引號+單引號皆編碼ENT_SUBSTITUTE:無效編碼字元替換為 而非空字串ENT_HTML5:HTML5 模式(PHP 5.4+)同 htmlspecialchars($str, ENT_QUOTES),確保單引號也被編碼防止屬性突破。
<?php
function jsEscape($str) {
return json_encode($str, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
}
// 使用
echo "<script>var user = " . jsEscape($name) . ";</script>";
json_encode 自動處理 Unicode、換行、引號、控制字元,最安全。
<?php
$url = 'https://example.com/search?q=' . urlencode($keyword);
// 空格→+,特殊字元→%XX
// RFC 3986 標準編碼(空格→%20)
$url = 'https://example.com/search?q=' . rawurlencode($keyword);
<?php
// PDO Prepared Statement
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status = ?');
$stmt->execute([$email, $status]);
$rows = $stmt->fetchAll();
// 命名參數(可讀性更好)
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute([':email' => $email]);
絕對禁止:"SELECT * FROM users WHERE email = '$email'" 字串拼接。
<?php
$cmd = 'convert ' . escapeshellarg($inputFile) . ' ' . escapeshellarg($outputFile);
exec($cmd, $output, $returnCode);
<?php
$pattern = '/^' . preg_quote($userPrefix, '/') . '.*$/';
| 資料類型 | 驗證方法 | 淨化方法 |
|---|---|---|
| 整數 | filter_var($v, FILTER_VALIDATE_INT) | (int)$v |
| 浮點數 | filter_var($v, FILTER_VALIDATE_FLOAT) | (float)$v |
| filter_var($v, FILTER_VALIDATE_EMAIL) | 無(驗證通過即可用) | |
| URL | filter_var($v, FILTER_VALIDATE_URL) | 無 |
| IP | filter_var($v, FILTER_VALIDATE_IP) | 無 |
| 布林 | filter_var($v, FILTER_VALIDATE_BOOLEAN) | filter_var($v, FILTER_VALIDATE_BOOLEAN) |
| 字串長度 | mb_strlen($v) <= $max | mb_substr($v, 0, $max) |
| 白名單值 | in_array($v, $allowed, true) | 無 |