此 Substring() 函式專為 GB18030、GB2312、Big5 編碼設計,不支援 UTF-8。核心邏輯:逐位元組掃描,依編碼區間判斷雙位元組字元,正確計數與截取。
function Substring($str, $max) {
$cnt = 0; // 實際字元計數
$index = 0; // 當前位元組索引
$output = ''; // 輸出緩衝
while ($cnt < $max && $index < strlen($str)) {
$output .= $str[$index];
// Big5 範圍判斷:首位元組 0x81-0xFE,次位元組 0x40-0x7E 或 0xA1-0xFE
if (ord($str[$index]) >= 0x81 && ord($str[$index]) <= 0xfe) {
if ($index + 1 < strlen($str)) {
$next = ord($str[$index + 1]);
if (($next >= 0x40 && $next < 0x7e) || ($next >= 0xa1 && $next <= 0xfe)) {
$index++;
$output .= $str[$index];
}
}
}
// GB2312 範圍判斷:首位元組 0xA1-0xF7,次位元組 0xA1-0xFE
else if (ord($str[$index]) >= 0xa1 && ord($str[$index]) <= 0xf7) {
$output .= $str[$index];
if ($index + 1 < strlen($str)) {
if (ord($str[$index + 1]) >= 0xa1 && ord($str[$index + 1]) < 0xfe) {
$index++;
$output .= $str[$index];
}
}
}
// ASCII 單位元組字元
else {
// 無需額外處理
}
$cnt++;
$index++;
}
return $output;
}
$index + 1 < strlen($str) 防止越界讀取$cnt 計算顯示字元數而非位元組數mb_substr$encoding 參數,內部路由至 mb_substr 或保留舊邏輯// 統一入口,自動適配編碼
function safe_substr($str, $start, $length, $encoding = 'UTF-8') {
if (function_exists('mb_substr')) {
return mb_substr($str, $start, $length, $encoding);
}
// 降級:僅支援 GBK/Big5
if (in_array(strtoupper($encoding), ['GBK', 'GB2312', 'BIG5'])) {
return Substring($str, $length); // 簡化版
}
// 最後防線:單純位元組截取(風險自負)
return substr($str, $start, $length);
}
歷史遺留專案中此類函式仍有價值,但新專案請直接擁抱 mbstring 與 UTF-8,從根源消除編碼地獄。