一般來說,亂碼的出現有2種原因,首先是由于編碼(charset)設定錯誤,導緻浏覽器以錯誤的編碼來解析,進而出現了滿屏亂七八糟的“天書”,其次是檔案被以錯誤的編碼打開,然後儲存,比如一個文本檔案原先是gb2312編碼的,卻以utf-8編碼打開再儲存。要解決上述亂碼問題,首先需要知道開發中哪些環節涉及到了編碼:
1、檔案編碼:指的是頁面檔案(.html,.php等)本身是以何種編碼來儲存的。記事本和dreamweaver在打開頁面時候會自動識别檔案編碼因而不太會出問題。而zendstudio卻不會自動識别編碼,它隻會根據首選項的配置固定以某種編碼打開檔案,如果工作時候一不注意,用錯誤編碼打開檔案,做了修改之後一儲存,亂碼就出現了。
2、頁面申明編碼:在html代碼head裡面,可以用<meta http-equiv="content-type" content="text/html; charset="xxx" />(這句一定要寫在<title>xxx</title>前面,否則會導緻頁面一片空白(僅限ie+php))來告訴浏覽器網頁采用了什麼編碼,目前中文網站開發中主要用的是gb2312和utf-8兩種編碼。
3、資料庫連接配接編碼:指的是進行資料庫操作時候以哪種編碼與資料庫傳輸資料,這裡需要注意的是不要與資料庫本身的編碼混淆,比如mysql内部預設是latin1編碼,也就是說mysql是以latin1編碼來存儲資料,以其他編碼傳輸給mysql的資料會被轉換成latin1編碼。
知道了web開發中哪些地方涉及到了編碼,也就知道了亂碼産生的原因:上述3項編碼設定不一緻,由于各種編碼絕大部分是相容ascii的,是以英文符号不會出現,中文就倒黴了。下面是一些常見的錯誤情況與解決:
1、資料庫采用utf8編碼,而頁面申明編碼是gb2312,這是最常見的産生亂碼的原因。這時候在php腳本裡面直接select資料出來的就是亂碼,需要在查詢前先使用:
mysql_query("set names gbk");或mysql_query("set names gb2312");來設定mysql連接配接編碼,保證頁面申明編碼與這裡設定的連接配接編碼一緻(gbk是gb2312的擴充)。如果頁面是utf-8編碼的話,可以用:
mysql_query("set names utf8"); 注意是utf8而不是一般用的utf-8。假如頁面申明的編碼與資料庫内部編碼一緻可以不設定連接配接編碼。
注:事實上mysql的資料輸入輸出比上面講的更複雜一些,mysql配置檔案my.ini中定義了2個預設編碼,分别是[client]裡的default-character-set和[mysqld]裡的default-character-set來分别設定預設時候用戶端連接配接和資料庫内部所采用的編碼。我們上面指定的編碼其實是mysql用戶端連接配接伺服器時候的指令行參數character_set_client,來告訴mysql伺服器接受到的用戶端資料是什麼編碼的,而不是采用預設編碼。
2、頁面申明編碼與檔案本身編碼不一緻,這種情況很少發生,因為如果編碼不一緻美工做頁面時候在浏覽器看到的就是亂碼了。更多時候是釋出以後修改一些小bug,以錯誤編碼打開頁面然後儲存導緻的。或者是用某些ftp軟體直接線上修改檔案,比如cuteftp,由于軟體編碼配置錯誤而導緻轉換錯了編碼。
3、一些租用虛拟主機的朋友,明明上述3項編碼都設定正确了還是有亂碼。比方說網頁是gb2312編碼的,ie等浏覽器打開卻總是識别成utf-8,網頁head裡面已經申明是gb2312了,手動修改浏覽器編碼為gb2312後頁面顯示正常。産生原因是伺服器apache設定了伺服器全局的預設編碼,在httpd.conf裡面加了adddefaultcharset utf-8。這時候伺服器會首先發送http頭給浏覽器,其優先級比頁面裡申明編碼高,自然浏覽器就識别錯了。解決辦法有2個,請管理者在配置檔案自己的虛機裡加上一條adddefaultcharset gb2312來覆寫全局配置,或者在自己目錄的.htaccess裡配置。
亂碼解決方法
要解決亂碼問題,首先必須弄清楚自己資料庫用什麼編碼。如果沒有指明,将是預設的latin1。
我們用得最多的應該是這3種字元集 gb2312,gbk,utf8。
那麼我們如何去指定資料庫的字元集呢?下面也gbk為例
【在mysql command line client建立資料庫】
mysql> create table `mysqlcode` (
-> `id` tinyint( 255 ) unsigned not null auto_increment primary key ,
-> `content` varchar( 255 ) not null
-> ) type = myisam character set gbk collate gbk_chinese_ci;
query ok, 0 rows affected, 1 warning (0.03 sec)
mysql> desc mysqlcode;
+---------+-----------------------+------+-----+---------+----------------+
| field | type | null | key | default | extra |
| id | tinyint(255) unsigned | no | pri | | auto_increment |
| content | varchar(255) | no | | | |
2 rows in set (0.02 sec)
其中後面的type = myisam character set gbk collate gbk_chinese_ci;
就是指定資料庫的字元集,collate (校勘),讓mysql同時支援多種編碼的資料庫。
當然我們也可以通過如下指令修改資料庫的字元集
alter database da_name default character set 'charset'.
用戶端以 gbk格式發送 ,可以采用下述配置:
set character_set_client='gbk'
set character_set_connection='gbk'
set character_set_results='gbk'
這個配置就等價于 set names 'gbk'。
現在對剛才建立的資料庫操作
mysql> use test;
database changed
mysql> insert into mysqlcode values(null,'php愛好者');
error 1406 (22001): data too long for column 'content' at row 1
沒有指定字元集為gbk,插入時出錯
mysql> set names 'gbk';
query ok, 0 rows affected (0.02 sec)
指定字元集為 gbk
query ok, 1 row affected (0.00 sec)
插入成功
mysql> select * from mysqlcode;
+----+-----------+
| id | content |
| 1 | php愛好着 |
1 row in set (0.00 sec)
在沒有指定字元集gbk時讀取也會出現亂碼,如下
+----+---------+
| id | content |
| 1 | php??? |
【在phpmyadmin建立資料庫,并指定字元集】
表類型根據自己需要選,這裡選myisam(支援全文檢索);
整理選擇 gbk_chinese_ci 也就是gbk字元集
gbk_bin 簡體中文, 二進制。gbk_chinese_ci 簡體中文, 不區分大小寫。
在剛才建立的資料庫插入資料庫
再浏覽時發現是亂碼
為什麼呢?是因為資料庫為gbk字元集,而我們操作時沒有指定為gbk
回到資料庫首頁
可以看到 mysql 連接配接校對預設的latin1_bin。我們将其改為gbk_chinese_ci
再插入一條資料。看,這條已經正常了
【解決php讀取資料庫亂碼】
仍以資料庫mysqlcode為例
<?php
$conn = mysql_connect("localhost","root","89973645");
mysql_query("set names 'gbk'");//這就是指定資料庫字元集,一般放在連接配接資料庫後面就系了
mysql_select_db("test");
$sql = "select * from mysqlcode";
$result = mysql_query($sql,$conn);
?>
<head>
<meta http-equiv="content-type" content="text/html; charset=gb2312" />
<title>mysql 字元編碼</title>
</head>
<body>
<table width="300" height="32" border="1" align="center" cellpadding="0" cellspacing="0">
<tr>
<td width="71" align="center">id</td>
<td width="229" align="center">内容</td>
</tr>
<?php while($row = mysql_fetch_assoc($result)){
echo "
<td align=/"center/">".$row['id']."</td>
<td>".$row['content']."</td>
</tr>";
}?>
</table>
</body>
</html>
<?php mysql_free_result($result);?>
如果我們将mysql_query("set names 'gbk'");注釋掉,肯定時亂碼
加上那句又正常了
一句話
你資料庫用什麼編碼,在對資料庫操作之前就set names '你的編碼';