strlen() 返回字節數,UTF-8 下一個漢字佔 3 字節,導致長度統計失真。正確方案是使用 mb_strlen() 或 iconv_strlen() 按字符數統計。
<?php $str = "Hello世界"; // 5 ASCII + 2 中文 = 7 字符,5 + 6 = 11 字節 echo "strlen: " . strlen($str) . "\n"; // 11 (字節數) echo "mb_strlen: " . mb_strlen($str, 'UTF-8') . "\n"; // 7 (字符數) echo "iconv_strlen: " . iconv_strlen($str, 'UTF-8') . "\n"; // 7 (字符數) ?>
| 函數 | 擴展依賴 | 編碼參數 | 速度 | 備註 |
|---|---|---|---|---|
| strlen | 核心 | 無 | 極快 | 僅統計字節 |
| mb_strlen | mbstring | 可選 (第 2 參數) | 快 | 推薦,支援列表編碼,可設內部編碼 |
| iconv_strlen | iconv | 必填 (第 2 參數) | 中等 | 較舊項目常用,需顯式指定編碼 |
| grapheme_strlen | intl (ICU) | 可選 | 較慢 | 按字素簇統計,正確處理 Emoji 組合字符 (如 👨👩👧👦 算 1 個) |
<?php
// 1. 統一設置內部編碼 (項目啟動時)
mb_internal_encoding('UTF-8');
// 2. 直接使用 mb_strlen (無需每次傳編碼)
$len = mb_strlen($str);
// 3. 表單驗證示例:用戶名 2-20 字符
if (mb_strlen($username) < 2 || mb_strlen($username) > 20) {
throw new Exception('用戶名長度需 2-20 字符');
}
// 4. 截取前 N 字符 (配合 mb_substr)
$summary = mb_substr($content, 0, 100) . '...';
?>
VARCHAR(20) 存儲字符數 (utf8mb4),PHP 驗證必須用 mb_strlen 對齊。mb_strlen("👨👩👧👦") === 7 (碼位數),grapheme_strlen() === 1 (視覺字符)。展示層建議用 grapheme_strlen。