爬蟲抓取、內容提取、XSS 防護都需要從 HTML 中移除腳本、樣式、標籤與註解。本文提供生產級正則方案,單次 preg_replace 完成多模式過濾,並處理 HTML 實體解碼,輸出純文字內容。
<?php
$search = [
// 1. 移除 (含屬性、跨行、大小寫)
"''si",
// 2. 移除
"''si",
// 3. 移除所有 HTML 標籤 <...> (含註解標籤)
"'<[/!]*?[^<>]*?>'si",
// 4. 移除 HTML 註解
"''si",
// 5. 合併多餘空白字元 (換行、Tab、多空格 → 單空格)
"'[\r\n\t\s]+'s",
// 6. HTML 實體解碼 (常見實體)
"'&(quot|#34);'i",
"'&(amp|#38);'i",
"'&(lt|#60);'i",
"'&(gt|#62);'i",
"'&(nbsp|#160);'i",
"'&(iexcl|#161);'i",
"'&(cent|#162);'i",
"'&(pound|#163);'i",
"'&(copy|#169);'i",
"'(\d+);'e", // 數字實體:執行 PHP 代碼 chr(\1)
];
$replace = [
'', // script
'', // style
'', // tags
'', // comments
' ', // whitespace
'"', // "
'&', // &
'<', // <
'>', // >
' ', //
chr(161), // ¡
chr(162), // ¢
chr(163), // £
chr(169), // ©
"chr(\\1)", // 數字實體
];
// 執行過濾
function stripHtmlTags(string $html): string {
global $search, $replace;
return preg_replace($search, $replace, $html);
}
?>
<?php
$html = <<<'HTML'
測試頁面
標題
段落內容 & 特殊字元 <test>
保留文字
HTML;
echo stripHtmlTags($html);
/*
輸出:
測試頁面 標題 段落內容 & 特殊字元 保留文字
*/
?>
// 1. strip_tags() - 簡單移除標籤 (保留文字) $text = strip_tags($html, '
'); // 允許保留
// 2. html_entity_decode() - 完整實體解碼 $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'); // 3. 組合方案 (推薦一般用途) function cleanHtml(string $html, array $allowedTags = []): string { $text = strip_tags($html, implode('', $allowedTags)); $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'); $text = preg_replace('/\s+/', ' ', $text); // 正規化空白 return trim($text); }
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| preg_replace 多模式 | 單次通過、可精確控制、支援複雜規則 | 正則複雜、效能較差、難維護 | 特殊過濾需求、舊專案相容 |
| strip_tags + html_entity_decode | 內建函式、效能高、標準合規、易維護 | 無法處理條件註解、CDATA 等邊界情況 | 95% 一般場景 (推薦) |
| DOMDocument 解析 | 結構化、最準確、支援 XPath 查詢 | 效能最低、嚴格模式易報錯 | 精確提取特定元素、結構化分析 |
| HTMLPurifier | XSS 防護最完整、白名單機制 | 效能極差、體積大 | 用戶輸入內容安全過濾 |
| 修飾符 | 含義 |
|---|---|
s (PCRE_DOTALL) | . 匹配換行符,跨行匹配 |
i (PCRE_CASELESS) | 大小寫不敏感 |
e (PREG_REPLACE_EVAL) | 替換字串作為 PHP 代碼執行 (已棄用 PHP 7.0+) |
$search = [
// ... 前面模式 ...
"'(\d+);'i", // 移除 e 修飾符
];
$replace = [
// ... 前面替換 ...
function($matches) {
$code = (int)$matches[1];
// 安全範圍檢查
return ($code < 0x110000) ? mb_chr($code, 'UTF-8') : '';
},
];
// 執行
$result = preg_replace_callback($search, $replace, $html);
⚠️ 僅移除標籤不等於 XSS 防護。攻擊者可利用屬性事件<img src=x onerror=alert(1)>、CSS expression、編碼繞過等。
生產環境必須使用 HTMLPurifier 或框架內建 XSS 過濾器。
strip_tags() + html_entity_decode()$search/$replace 定義為 static 或類常數正則過濾 HTML 適用於特定場景,通用內容提取請優先使用 strip_tags() + html_entity_decode(),安全過濾請使用 HTMLPurifier。