部落格列表頁需顯示文章前段內容,若直接截斷字串易破壞 HTML 標籤巢狀結構,導致版面錯亂。本函式以堆疊方式追蹤開合標籤,在指定長度處截斷並自動補全未閉合標籤。
<?php
function Generate_Brief($text, $length = 200) {
// 多位元組編碼設定
mb_regex_encoding('UTF-8');
mb_internal_encoding('UTF-8');
if (mb_strlen($text) <= $length) return $text;
$Foremost = mb_substr($text, 0, $length);
// 需追蹤的區塊標籤 (單獨標籤除外)
$blockTags = '(P|DIV|H[1-6]|ADDRESS|PRE|TABLE|TR|TD|TH|SELECT|TEXTAREA|OBJECT|UL|OL|LI|SPAN)';
$singleTags = '(BR|HR|IMG|INPUT|META|LINK|PARAM|AREA|BASE)';
$re = "/<(\/?)($blockTags|$singleTags)[^>]*(>?)/i";
$stack = [];
$posStack = [];
mb_ereg_search_init($Foremost, $re);
while ($pos = mb_ereg_search_pos()) {
$match = mb_ereg_search_getregs();
// $match[1] = '/' 表示結束標籤
// $match[2] = 標籤名稱
// $match[3] = 是否有 '>'
if ($match[1] === '') { // 開始標籤
$tag = strtoupper($match[2]);
// 單獨標籤且已閉合略過
if (preg_match("/^$singleTags$/i", $tag) && $match[3] !== '') continue;
array_push($stack, $tag);
array_push($posStack, $pos[0]);
} else { // 結束標籤
$endTag = strtoupper($match[2]);
if ($stack && strcasecmp(end($stack), $endTag) === 0) {
array_pop($stack);
array_pop($posStack);
// 若原標籤缺 '>' 補上
if ($match[3] === '') $Foremost .= '>';
}
}
}
// 從最外層未閉合標籤處截斷
$cutPos = array_shift($posStack) - 1;
$Foremost = mb_substr($Foremost, 0, $cutPos, 'UTF-8');
// 補全剩餘未閉合標籤 (由內而外)
while ($tag = array_pop($stack)) {
$Foremost .= "</$tag>";
}
return $Foremost;
}
?>
$content = "<div><p>這是一段很長的文章內容...</p><ul><li>項目一</li><li>項目二</li></ul></div>";
echo Generate_Brief($content, 50);
// 輸出: <div><p>這是一段很長的文章內容...</p></div> (標籤完整閉合)
mb_ereg 正則搜尋,對超長文章可能較耗資源。透過堆疊追蹤標籤巢狀關係,可在截斷 HTML 內容時自動修補標籤結構,確保前端顯示穩定。實務部署時宜配合快取或預計算策略平衡效能與功能。