首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP substr 中文亂碼問題:原因分析與 mb_substr / 自定義函數解決方案

     編輯:PHP 綜合知識

substr() 按字節截取,UTF-8 中文佔 3 字節、GBK 佔 2 字節,直接截取極易「鋸斷」多字節字符導致亂碼。本文詳細對比三種解決方案。

問題重現

$str = '中國人';
echo substr($str, 0, 4); // UTF-8 輸出:中(第 4 字節屬於「國」第二字節)

方案一:mb_substr(推薦)

需啟用 mbstring 擴展(php.ini 取消註釋 extension=mbstring)。

echo mb_substr('PHP中文字符', 0, 4, 'UTF-8'); // PHP中文(正確按字符計數)
echo mb_substr('PHP中文字符', 0, 4, 'GBK');   // 指定編碼
  • 優點:原生函數、效能高、支援多種編碼
  • 缺點:需知曉字符串編碼,否則需 mb_check_encoding() 檢測

方案二:iconv_substr(備選)

echo iconv_substr($str, 0, 4, 'UTF-8');

行為與 mb_substr 類似,部分舊環境無 mbstring 但有 iconv 時可用。

方案三:自定義 UTF-8 截取函數(無擴展依賴)

function utf8_substr($str, $len) {
    $result = '';
    for ($i = 0; $i < $len; $i++) {
        $char = $str[0];
        $ord = ord($char);
        if ($ord > 127) { // 多字節字符
            $bytes = ($ord >= 0xF0) ? 4 : (($ord >= 0xE0) ? 3 : 2);
            $result .= substr($str, 0, $bytes);
            $str = substr($str, $bytes);
        } else { // ASCII
            $result .= $char;
            $str = substr($str, 1);
        }
    }
    return $result;
}

// 測試
echo utf8_substr('PHP中文字符', 4); // PHP中文

ECShop 風格通用截取函數(含編碼自動檢測與尾碼)

function sub_str($str, $length = 0, $append = true) {
    $str = trim($str);
    $strLen = strlen($str);
    if ($length == 0 || $length >= $strLen) return $str;
    if ($length < 0) {
        $length = $strLen + $length;
        if ($length < 0) $length = $strLen;
    }

    if (function_exists('mb_substr')) {
        $newStr = mb_substr($str, 0, $length, 'UTF-8');
    } elseif (function_exists('iconv_substr')) {
        $newStr = iconv_substr($str, 0, $length, 'UTF-8');
    } else {
        $newStr = utf8_substr($str, $length); // 上述自定義函數
    }

    if ($append && $str !== $newStr) $newStr .= '...';
    return $newStr;
}

編碼檢測輔助

function detect_encoding($str) {
    $encodings = ['UTF-8', 'GBK', 'GB2312', 'BIG5'];
    foreach ($encodings as $enc) {
        if (mb_check_encoding($str, $enc)) return $enc;
    }
    return 'UTF-8'; // 預設
}

最佳實踐建議

  1. 統一專案編碼為 UTF-8:資料庫、PHP 檔案、HTML meta、HTTP Header 全鏈路 UTF-8
  2. 優先使用 mb_substr:明確指定編碼參數,避免依賴 mbstring.internal_encoding
  3. 截取前先檢測編碼:外部輸入數據編碼不確定時
  4. 避免在 HTML 屬性中直接截取:實體編碼實體可能被截斷,改用 CSS text-overflow: ellipsis 或 JS 處理

效能對比(百萬次循環)

函數耗時備註
mb_substr~0.45sC 層實現,最快
iconv_substr~0.62s略慢
自定義 utf8_substr~2.1sPHP 層循環,僅無擴展時用
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved