處理用戶提交的富文本、評論、文章內容時,需要過濾 HTML 標籤、轉義實體、防範 XSS 攻擊。本文匯總 PHP 內置函數與自定義過濾方案,涵蓋標籤剝離、實體轉義、SQL 注入防護等實用場景。
<?php
$html = '<p>內容</p><script>alert(1)</script><b>粗體</b>';
// 剝離所有標籤
echo strip_tags($html);
// 輸出: 內容alert(1)粗體
// 保留允許的標籤(如 <p>、<b>、<img>)
echo strip_tags($html, '<p><b><img>');
// 輸出: <p>內容</p>alert(1)<b>粗體</b>
?>
strip_tags() 不屬性過濾,<img src=x onerror=alert(1)> 會保留危險屬性,不可單獨用於 XSS 防護。'<p><a>'(無空格、無屬性)。<?php
$input = '<script>alert(1)</script>';
echo htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
// 輸出: <script>alert(1)</script>
?>
ENT_QUOTES 轉義單雙引號,'UTF-8' 指定編碼。將所有可轉義字符轉為實體(含中文),體積膨脹大,一般不推薦,優先用 htmlspecialchars()。
<?php
/**
* 深度過濾 HTML:移除腳本/樣式、剝離標籤、轉義實體、規範空白
* @param string $string
* @return string
*/
function strip_html_deep($string) {
if (!is_string($string)) return '';
// 1. 移除 script/style 標籤及內容
$string = preg_replace('/<(script|style)[^>]*>.*?<\/\1>/is', '', $string);
// 2. 移除 HTML 註釋
$string = preg_replace('/<!--.*?-->/s', '', $string);
// 3. 剝離所有標籤(保留文本)
$string = strip_tags($string);
// 4. 轉義 HTML 實體(防殘留尖括號)
$string = htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
// 5. 規範空白字符:換行/制表/多空格 → 單空格
$string = preg_replace('/\s+/u', ' ', $string);
// 6. 去首尾空白
return trim($string);
}
// 測試
$dirty = "<div>Hello<script>alert(1)</script> <b>World</b></div>";
echo strip_html_deep($dirty); // Hello World
?>
使用 HTMLPurifier 庫(業界標準),而非自寫正則:
<?php
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed', 'p,b,i,u,em,strong,a[href|title],img[src|alt|width|height],br,ul,ol,li');
$purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html);
?>
原文提供的 stripslashes_array 和 lib_replace_end_tag 屬於早期「過濾法」防注入,**現代最佳實踐是參數化查詢(Prepared Statements)**:
<?php
// PDO 預處理(防注入標準)
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();
// MySQLi 預處理
$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ?');
$stmt->bind_param('s', $email);
$stmt->execute();
?>
切勿使用字符串拼接 SQL,任何過濾函數都有繞過風險。
| 輸出上下文 | 編碼函數 | 示例 |
|---|---|---|
| HTML 文本內容 | htmlspecialchars($str, ENT_QUOTES, 'UTF-8') | <div>= h($name) ?></div> |
| HTML 屬性值 | htmlspecialchars($str, ENT_QUOTES, 'UTF-8') | <input value="= h($val) ?>"> |
| URL 參數 | urlencode($str) | <a href="?q== urlencode($kw) ?>> |
| JavaScript 字符串 | json_encode($str)(含引號) | <script>var x = = json_encode($str) ?>;</script> |
| CSS 值 | 專用轉義庫 | 避免直接內聯 |
<?php
// 通用 HTML 轉義助手
function h($str, $double_encode = true) {
return htmlspecialchars((string)$str, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', $double_encode);
}
// 只允許安全標籤的輸出(需 HTMLPurifier)
function safe_html($html, $config = null) {
static $purifier = null;
if ($purifier === null) {
require_once 'HTMLPurifier.auto.php';
$cfg = HTMLPurifier_Config::createDefault();
$cfg->set('HTML.Allowed', 'p,b,i,u,em,strong,a[href|title],img[src|alt],br,ul,ol,li,span[style],div[class]');
$purifier = new HTMLPurifier($cfg);
}
return $purifier->purify($html);
}
// 移除所有標籤並獲取純文本
function plain_text($html) {
return trim(preg_replace('/\s+/u', ' ', strip_tags($html)));
}
?>
h()、urlencode()、json_encode()),富文本用 HTMLPurifier 白名單過濾。Content-Security-Policy (CSP) 頭,禁用內聯腳本,限制資源來源。「過濾 HTML」不是單一函數能解決的,而是分層防護體系。棄用舊式「過濾法」防注入,擁抱預處理與上下文編碼,引入 HTMLPurifier 處理富文本,構建可維護的安全防線。