PHP處理各種字符串時(shí)有時(shí)會(huì)碰到亂碼的問(wèn)題,其實(shí)我們?cè)陂_(kāi)發(fā)實(shí)踐中只要堅(jiān)持一個(gè)原則:編輯代碼、存儲(chǔ)數(shù)據(jù)、輸出數(shù)據(jù)等都統(tǒng)一使用UTF-8編碼。堅(jiān)持這個(gè)原則會(huì)規(guī)避很多字符串亂碼的問(wèn)題。
PHP有mbstring擴(kuò)展,自帶幾種字符串截取函數(shù),其中常用到的就是 substr 和 mb_substr。
當(dāng)操作 Unicode 字符集的時(shí)候,使用相應(yīng)的函數(shù)代替原生的字符串函數(shù)。舉個(gè)例子,一個(gè)文件編碼為 UTF-8 的 PHP 代碼,假如使用 strlen() 函數(shù)是錯(cuò)誤的,請(qǐng)使用 mb_strlen() 函數(shù)代替。
如果你使用substr截取中文字符時(shí)會(huì)出現(xiàn)亂碼,這是因?yàn)閟ubstr是按字節(jié)來(lái)截取的。即UTF-8編碼的中文,使用substr截取,只會(huì)截取1/3個(gè)中文,當(dāng)然出現(xiàn)亂碼了。UTF-8編碼時(shí),一個(gè)漢字是3個(gè)字節(jié)。同樣其他國(guó)家不同語(yǔ)言文字會(huì)產(chǎn)生多字節(jié)字符串問(wèn)題,所以我們統(tǒng)統(tǒng)使用mb_strlen()來(lái)處理。
如果不清楚字符串的編碼格式的話,可以用mb_detect_encoding檢查。
如果要轉(zhuǎn)換編碼,使用函數(shù)iconv(),如GB2312 轉(zhuǎn)UTF-8:
iconv("GB2312","UTF-8",$text);
當(dāng)遇到無(wú)法確定原編碼是何種編碼,或者iconv轉(zhuǎn)化后無(wú)法正常顯示時(shí)可用mb_convert_encoding 函數(shù)。
$str = mb_convert_encoding($str, "UTF-8");
其實(shí)在php.ini中有個(gè)選項(xiàng)設(shè)置default_charset = "UTF-8";,很多字符串處理函數(shù)如htmlentities()會(huì)使用這個(gè)默認(rèn)字符集。
我們可以使用header()函數(shù)明確指定字符集,在PHP返回的響應(yīng)中,Content-Type首部默認(rèn)也使用這個(gè)值。
header("Content-Type: text/html;charset=utf-8");
當(dāng)然,我們?cè)趧?chuàng)建HTML文檔的頭部也應(yīng)該加入這個(gè)mata標(biāo)簽:
<meta charset="UTF-8" />
雖然我們將php代碼、輸出數(shù)據(jù)時(shí)都使用UTF-8,但是可能還會(huì)遇到很多詭異現(xiàn)象。比如,我遇到的坑,當(dāng)要從服務(wù)器上下載一個(gè)文件時(shí),IE瀏覽器、Edge在下載中文文件名時(shí)會(huì)亂碼,還有當(dāng)文件名包含空字符時(shí),下載后的文件名稱空格變成了+號(hào)等等這些詭異現(xiàn)象。
其實(shí),PHP通過(guò) header() 函數(shù)下載文件的時(shí)候,也要考慮瀏覽器和操作系統(tǒng)(大部分人使用的是 Windows),對(duì)于 Chrome 來(lái)說(shuō),輸出的文件名編碼可以是 UTF-8,Chrome 會(huì)自動(dòng)將文件名轉(zhuǎn)換為 GBK 編碼。
而對(duì)于IE 來(lái)說(shuō),它繼承了操作系統(tǒng)的環(huán)境,所以下載文件名假如是中文必須轉(zhuǎn)碼為 UTF-8 編碼,否則下載的時(shí)候用戶看到的是亂碼文件名。 解決辦法有了:
$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 客戶端連接的時(shí)候也保持 UTF-8,具體到 PHP 中,就是 mysqli 或者 PDO 擴(kuò)展連接 Mysql 的時(shí)候都設(shè)置 UTF-8 作為連接編碼,兩邊保持一致,一般就不會(huì)遇到亂碼問(wèn)題。
例如使用PDO鏈接Mysql時(shí),使用UTF-8字符集:
$pdo->query('SET NAMES utf8;');
1.處理多字節(jié)字符串時(shí)一定要知道數(shù)據(jù)的字符編碼;
2.使用UTF-8字符編碼存儲(chǔ)數(shù)據(jù);
3.使用UTF-8字符編碼輸出數(shù)據(jù)。