在 Blog、CMS 列表頁常需顯示文章前段內容,直接 substr 易導致 HTML 標籤未閉合破壞版面。本函數採用堆疊機制追蹤標籤開合,截斷處自動補全未閉合標籤,支援區塊級元素(div、p、table 等)與單一標籤(img、br、hr 等)識別。
define("BRIEF_LENGTH", 800); // 摘要字元上限
function Generate_Brief($text) {
global $Briefing_Length;
if(strlen($text) <= BRIEF_LENGTH) return $text;
$Foremost = substr($text, 0, BRIEF_LENGTH);
$re = '/<(\/?)(P|DIV|H[1-6]|ADDRESS|PRE|TABLE|TR|TD|TH|INPUT|SELECT|TEXTAREA|OBJECT|A|UL|OL|LI|BASE|META|LINK|HR|BR|PARAM|IMG|AREA|SPAN)[^>]*(>?)/i';
$Single = '/BASE|META|LINK|HR|BR|PARAM|IMG|AREA|INPUT/i';
$Stack = array(); $posStack = array();
preg_match_all($re, $Foremost, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
for($i=0; $i<count($matches); $i++) {
if($matches[$i][1][0] == "") { // 開啟標籤
$Elem = $matches[$i][2][0];
if(preg_match($Single, $Elem) && $matches[$i][3][0] != "") continue;
array_push($Stack, strtoupper($matches[$i][2][0]));
array_push($posStack, $matches[$i][2][1]);
if($matches[$i][3][0] == "") break;
} else { // 關閉標籤
$StackTop = $Stack[count($Stack)-1];
$End = strtoupper($matches[$i][2][0]);
if(strcasecmp($StackTop, $End) == 0) {
array_pop($Stack); array_pop($posStack);
if($matches[$i][3][0] == "") $Foremost .= ">";
}
}
}
$cutpos = array_shift($posStack) - 1;
$Foremost = substr($Foremost, 0, $cutpos);
return $Foremost;
}
function Generate_Brief($text) {
global $Briefing_Length;
mb_regex_encoding("UTF-8");
if(mb_strlen($text) <= BRIEF_LENGTH) return $text;
$Foremost = mb_substr($text, 0, BRIEF_LENGTH);
$re = '<(\/?)(P|DIV|H[1-6]|ADDRESS|PRE|TABLE|TR|TD|TH|INPUT|SELECT|TEXTAREA|OBJECT|A|UL|OL|LI|BASE|META|LINK|HR|BR|PARAM|IMG|AREA|INPUT|SPAN)[^>]*(>?)';
$Single = '/BASE|META|LINK|HR|BR|PARAM|IMG|AREA|INPUT|BR/i';
$Stack = array(); $posStack = array();
mb_ereg_search_init($Foremost, $re, 'i');
while($pos = mb_ereg_search_pos()) {
$match = mb_ereg_search_getregs();
if($match[1] == "") {
$Elem = $match[2];
if(mb_eregi($Single, $Elem) && $match[3] != "") continue;
array_push($Stack, mb_strtoupper($Elem));
array_push($posStack, $pos[0]);
} else {
$StackTop = $Stack[count($Stack)-1];
$End = mb_strtoupper($match[2]);
if(strcasecmp($StackTop, $End) == 0) {
array_pop($Stack); array_pop($posStack);
if($match[3] == "") $Foremost .= ">";
}
}
}
$cutpos = array_shift($posStack) - 1;
$Foremost = mb_substr($Foremost, 0, $cutpos, "UTF-8");
return $Foremost;
}
函數針對常見區塊標籤優化,若內容含罕見標籤(如 SVG、Canvas、Web Components),需擴充 $re 模式。生產環境建議搭配 HTML Purifier 先淨化內容再摘要。