PHP處理各種字符串時有時會碰到亂碼的問題,其實我們在開發實踐中只要堅持一個原則:編輯代碼、存儲數據、輸出數據等都統一使用UTF-8編碼。堅持這個原則會規避很多字符串亂碼的問題。
PHP有mbstring擴展,自帶幾種字符串截取函數,其中常用到的就是 substr 和 mb_substr。
當操作 Unicode 字符集的時候,使用相應的函數代替原生的字符串函數。舉個例子,一個文件編碼為 UTF-8 的 PHP 代碼,假如使用 strlen() 函數是錯誤的,請使用 mb_strlen() 函數代替。
如果你使用substr截取中文字符時會出現亂碼,這是因為substr是按字節來截取的。即UTF-8編碼的中文,使用substr截取,只會截取1/3個中文,當然出現亂碼了。UTF-8編碼時,一個漢字是3個字節。同樣其他國家不同語言文字會產生多字節字符串問題,所以我們統統使用mb_strlen()來處理。
如果不清楚字符串的編碼格式的話,可以用mb_detect_encoding檢查。
如果要轉換編碼,使用函數iconv(),如GB2312 轉UTF-8:
iconv("GB2312","UTF-8",$text);
當遇到無法確定原編碼是何種編碼,或者iconv轉化后無法正常顯示時可用mb_convert_encoding 函數。
$str = mb_convert_encoding($str, "UTF-8");
其實在php.ini中有個選項設置default_charset = "UTF-8";,很多字符串處理函數如htmlentities()會使用這個默認字符集。
我們可以使用header()函數明確指定字符集,在PHP返回的響應中,Content-Type首部默認也使用這個值。
header("Content-Type: text/html;charset=utf-8");
當然,我們在創建HTML文檔的頭部也應該加入這個mata標簽:
<meta charset="UTF-8" />
雖然我們將php代碼、輸出數據時都使用UTF-8,但是可能還會遇到很多詭異現象。比如,我遇到的坑,當要從服務器上下載一個文件時,IE瀏覽器、Edge在下載中文文件名時會亂碼,還有當文件名包含空字符時,下載后的文件名稱空格變成了+號等等這些詭異現象。
其實,PHP通過 header() 函數下載文件的時候,也要考慮瀏覽器和操作系統(大部分人使用的是 Windows),對于 Chrome 來說,輸出的文件名編碼可以是 UTF-8,Chrome 會自動將文件名轉換為 GBK 編碼。
而對于IE 來說,它繼承了操作系統的環境,所以下載文件名假如是中文必須轉碼為 UTF-8 編碼,否則下載的時候用戶看到的是亂碼文件名。 解決辦法有了:
$agent=$_SERVER["HTTP_USER_AGENT"]; if(strpos($agent,'MSIE')!==false ){ $filename = iconv("UTF-8","GBK","中文附件.pdf"); header("Content-Disposition: attachment; filename=\"$filename\""); }
首先保證你的 Mysql 都是 UTF-8。然后 Mysql 客戶端連接的時候也保持 UTF-8,具體到 PHP 中,就是 mysqli 或者 PDO 擴展連接 Mysql 的時候都設置 UTF-8 作為連接編碼,兩邊保持一致,一般就不會遇到亂碼問題。
例如使用PDO鏈接Mysql時,使用UTF-8字符集:
$pdo->query('SET NAMES utf8;');
1.處理多字節字符串時一定要知道數據的字符編碼;
2.使用UTF-8字符編碼存儲數據;
3.使用UTF-8字符編碼輸出數據。