function stripHtmlRegex($str) {
// 移除註釋
$str = preg_replace('//s', '', $str);
// 移除 script/style 及內容
$str = preg_replace('/<(script|style)[^>]*>.*?<\/\1>/is', '', $str);
// 移除所有標籤
$str = preg_replace('/<[^>]+>/', '', $str);
// 實體解碼
$str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
return trim($str);
}
缺點:無法處理屬性中包含 > 的情況、嵌套標籤、條件註釋、CDATA 等邊界案例。
function stripHtmlStateMachine($str) {
$len = strlen($str);
$result = '';
$inTag = false;
$tagDepth = 0; // 處理嵌套
$quoteChar = null; // 處理屬性引號
for ($i = 0; $i < $len; $i++) {
$ch = $str[$i];
if (!$inTag) {
if ($ch === '<') {
// 檢查是否為註釋
if ($i >= 2 && $str[$i-2] === '-' && $str[$i-1] === '-') {
// 註釋結束
}
}
} elseif ($ch === '<') {
$tagDepth++; // 嵌套標籤(罕見但合法)
}
}
}
return html_entity_decode(trim($result), ENT_QUOTES, 'UTF-8');
}
composer require ezyang/htmlpurifier
require_once 'vendor/autoload.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('Core.Encoding', 'UTF-8');
$config->set('HTML.Doctype', 'HTML 4.01 Transitional');
// 只允許極少標籤
$config->set('HTML.Allowed', 'p,b,i,em,strong,a[href|title],ul,ol,li,br,span[style]');
$purifier = new HTMLPurifier($config);
$cleanHtml = $purifier->purify($dirtyHtml);
| 維度 | 正則 | 狀態機 | HTMLPurifier |
|---|---|---|---|
| 安全性 | 低(易繞過 XSS) | 中(需自行完善) | 極高(白名單機制) |
| 性能 | 中 | 高 | 低(解析開銷大) |
| 依賴 | 無 | 無 | Composer 包 |
| 維護成本 | 低 | 中 | 低(庫維護) |
| 適用場景 | 簡單清洗、內部數據 | 高性能、無依賴環境 | 用戶輸入、富文本、CMS、論壇 |
strip_tags() 內建函數(但不處理實體、script 內容),配合 html_entity_decode()。$str = 'Bold';
echo strip_tags($str); // 輸出:alert(1)Bold ← script 內容未被移除!
// 正確:先移除 script/style 再 strip_tags
$str = preg_replace('/<(script|style)[^>]*>.*?<\/\1>/is', '', $str);
echo strip_tags($str); // 輸出:Bold