Smarty 內建的 truncate 修飾器預設以 位元組 計算長度,對於 UTF-8 或 GB2312 編碼的中文字串會導致「半個字元」殘缺、亂碼或長度不準確。
路徑:smarty/plugins/modifier.truncate.php
核心改動:引入 SubstrGB() 函式以雙位元組判斷方式正確截取中文字元。
$length) {
$length -= strlen($etc);
if (!$break_words) {
$string = preg_replace('/\s+\S+$/', '', SubstrGB($string, 0, $length + 1));
}
return SubstrGB($string, 0, $length) . $etc;
}
return $string;
}
/**
* 針對 GB2312/Big5 雙位元組編碼的安全截取
*/
function SubstrGB($str, $start, $len) {
$tmp = '';
for ($i = 0; $i < $start + $len; $i++) {
// 判斷是否為雙位元組中文字元(0xA1-0xFE 範圍)
if (ord($str[$i]) >= 161 && ord($str[$i]) <= 254 &&
ord($str[$i+1]) >= 161 && ord($str[$i+1]) <= 254) {
$tmpstr = $str[$i] . $str[++$i];
} else {
$tmpstr = $str[$i];
}
if ($i >= $start && $i < ($start + $len)) {
$tmp .= $tmpstr;
}
}
return $tmp;
}
?>
ord() 檢查相鄰兩字元是否落在 0xA1–0xFE 區間,若是則視為一個中文字元,索引 $i 額外 +1 跳過第二個位元組。$start 落在中文字元中間,自動往前補齊,避免殘缺。{$long_text|truncate:30:"..."} {* 輸出前 30 個中文字元 + ... *}
若專案採用 UTF-8,建議改用 mb_substr() 或正則 /[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+/ 進行多位元組安全截取,原理相同但位元組判斷邏輯不同。