表單提交資料包含特殊字元(`<`, `>`, `'`, `"`, `&`, `\` 等)時,若未正確處理,會導致 XSS 攻擊、SQL 注入、資料儲存異常或顯示錯誤。本文系統整理 PHP 核心處理函式、適用場景、常見誤區與防禦策略。
| 函式 | 主要用途 | 轉義字元 | 是否可逆 | 典型場景 |
|---|---|---|---|---|
htmlspecialchars() | HTML 輸出編碼(防 XSS) | `&` `"` `'` `<` `>` | 不可逆(顯示用) | 輸出到 HTML 內容、屬性、JS 字串 |
htmlentities() | 所有 HTML 實體編碼 | 所有可轉實體字元 | 不可逆 | 需完整實體化(較少用) |
addslashes() | 字串加反斜線(舊式 SQL/通用) | `'` `"` `\` NUL | stripslashes() 可逆 | 歷史相容、非資料庫字串儲存 |
stripslashes() | 移除反斜線 | 對應 `addslashes` | 可逆 | 處理 `magic_quotes_gpc` 遺留資料 |
strip_tags() | 移除 HTML/PHP 標籤 | 標籤結構 | 不可逆(資料遺失) | 允許部分標籤的內容過濾 |
mysqli_real_escape_string() / PDO::quote() | 資料庫專用轉義(防 SQL 注入) | 依資料庫字元集(含 `\0`, `\n`, `\r`, `\`, `'`, `"`) | 不可逆(查詢用) | **舊式字串拼接 SQL 必用** |
PDO Prepared Statements | 參數綁定(根治 SQL 注入) | 無需手動轉義 | N/A | **現代最佳實踐** |
錯誤做法:儲存前 `htmlspecialchars()` → 資料庫存 `<script>` → 後續 JSON API、CSV 匯出、搜尋皆受汙染。
正確做法:
1. **輸入驗證**:檢查長度、格式、型別、業務規則。
2. **原始儲存**:資料庫存原始用戶輸入(配合 Prepared Statements)。
3. **輸出編碼**:根據輸出語境(HTML、JS、CSS、URL、Shell)套用對應編碼函式。
| 輸出語境 | 編碼函式/方法 | 範例 |
|---|---|---|
| HTML 內容 | htmlspecialchars($str, ENT_QUOTES, 'UTF-8') | ` = h($name) ?> ` |
| HTML 屬性值 | 同上(雙引號屬性必用 ENT_QUOTES) | `` |
| JavaScript 字串 | json_encode($str)(含引號) | `` |
| URL 參數值 | urlencode($str) / rawurlencode() | `` |
| CSS 值 | 無標準函式,嚴格白名單或 `json_encode` | `style="color: = json_encode($color) ?>;"` |
| Shell 命令參數 | escapeshellarg() / escapeshellcmd() | `exec('convert ' . escapeshellarg($input))` |
<?php
// 極易漏掉、字元集不符導致繞過
$sql = "SELECT * FROM users WHERE name = '" . mysqli_real_escape_string($link, $_GET['name']) . "'";
<?php
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute([':name' => $_GET['name']]);
$user = $stmt->fetch();
優點:
- 驅動層自動處理轉義與型別
- 查詢計畫可重用(效能)
- 程式碼可讀性高、免維護轉義邏輯
PHP 5.4 已移除。若舊專案遷移發現資料多重反斜線(`\\\'`),需在入口點統一清理:
<?php
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value) {
return is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
}
$_GET = stripslashes_deep($_GET);
$_POST = stripslashes_deep($_POST);
$_COOKIE = stripslashes_deep($_COOKIE);
$_REQUEST = stripslashes_deep($_REQUEST);
}
<?php
// 通用 HTML 輸出助手
function h(string $str, int $flags = ENT_QUOTES | ENT_SUBSTITUTE, string $encoding = 'UTF-8'): string {
return htmlspecialchars($str, $flags, $encoding);
}
// 原始輸出(明確標示信任內容)
function raw(string $str): string { return $str; }
// 在模板中使用
// = h($userInput) ?> // 安全
// = raw($trustedHtml) ?> // 僅限確信安全內容
特殊字元處理的核心在於「語境感知」與「輸出時編碼」。建立統一的輸出助手函式、強制使用 Prepared Statements、移除手動轉義邏輯,即能從根本上杜絕 XSS 與 SQL 注入風險。