【PHP問題大全】--PHP連接MySQL出現亂碼的編碼解決辦法
PHP連接MySQL的過程中如果出現亂碼很多人會說,用"Set names '??'"就能解決問題,但很多時候還是會出現各種怪現象,比如說頁面能正常存取,但是phpmyadmin不能正常存取等現象。小弟經過驗證,產生了一些個人看法,歡迎大家討論和指正。
MySQL數據庫操作過程中出現了三種字符集:
1、頁面字符集(也就是 c)
2、連接字符集(也就是 "Set names 'GBK'")
3、字段字符集(無論是庫還是表的字符集,將最終反映到字段上)
一、實驗:
1、情況一
數據庫字段字符集:utf-8
連接字符集:沒有顯式設置,默認爲latin1
頁面字符集:gbk
存入過程:
1)頁面用GBK表示的SQL向服務器提交存入請求;
2)默認情況下(不用Set Names '??')服務器用latin1打開連接;
3)服務器誤認爲當前的SQL語句是用latin1表示的;
4)服務器將GBK字符當作latin1字符,錯誤的運用“latin1轉UTF-8函數”將字符轉換後存入UTF-8字段中;
5)( 錯誤的latin1(其實是GBK) => 錯誤的UTF-8)
6)如果用phpmyadmin打開該表(用utf8連接)將會看到該字段爲亂碼;
讀取過程:
1)默認情況下(不用Set Names '??')服務器用latin1打開連接;
2)服務器將UTF-8字段中的值轉換爲latin1返回給客戶端;
3)(錯誤的UTF-8 => 錯誤的latin1(其實是GBK))該過程爲存入過程5的逆過程。(剛好錯錯得對了)
4)將服務器誤認爲是latin1的GBK編碼按頁面字符集正常顯示;
用示意圖來表示就是:
CODE
存入過程:
----------------------
頁面 連接 存儲
----------------------
GBK => latin1 => utf-8
---------------
------------- |
| +------- 該過程得到的utf-8是一串不知所云的亂碼,但MySQL固執的認爲這串碼爲UTF-8
|
+------ MySQL將GBK誤認爲是latin1
讀取過程:
----------------------
頁面 連接 存儲
----------------------
GBK <= latin1 <= utf-8
---------------
------------- |
| +------- 正是這串亂碼經過逆過程轉換回正確的GBK編碼,只是MySQL認爲是latin1而已
|
+------ MySQL將誤認爲是latin1的GBK編碼傳回了頁面,剛好得到正確的編碼。
2、情況二
數據庫字段字符集:utf-8
連接字符集:gbk
頁面字符集:gbk
文字描述略。
示意圖:
CODE
存入過程:
----------------------
頁面 連接 存儲
----------------------
GBK => GBK => utf-8
------------
------------- |
| +------- 該過程得到的utf-8是由GBK轉換而來的,是正確的utf-8編碼
|
+------ 頁面字符集等於連接字符集,MySQL認爲頁面傳遞給它的是GBK編碼,它的想法正好符合事實。
讀取過程:
----------------------
頁面 連接 存儲
----------------------
GBK <= GBK <= utf-8
---------------
------------- |
| +------- 用“utf-8轉GBK函數”將正確的utf-8編碼轉換回GBK
|
+------ 頁面字符集等於連接字符集,顯示沒有任何問題。
3、情況三
數據庫字段字符集:gbk
連接字符集:沒有顯式設置,默認爲latin1
頁面字符集:gbk
CODE
存入過程:
----------------------
頁面 連接 存儲
----------------------
GBK => latin1 => GBK
------------
------------- |
| +------- 字符被“latin1轉GBK函數”轉換的成了亂碼,但MySQL認爲它是GBK,所以工具無法正常顯示。
|
+------ MySQL認爲頁面傳遞給它的是latin1編碼,它將在後續過程中畫蛇添足地將正確的GBK轉換爲亂碼。
讀取過程:
----------------------
頁面 連接 存儲
----------------------
GBK <= latin1 <= GBK
---------------
------------- |
| +------- “GBK轉latin1函數”將亂碼轉換爲GBK,但MySQL卻認爲它們是latin1
|
+------ 錯誤的latin1編碼其實是正確的GBK編碼,頁面顯示正常,但工具顯示不正常。
二、字符集之間的轉換
筆者試着將GBK字符誤當作latin1轉換爲錯誤的utf-8能成功,逆過程中將亂碼轉換回latin1得到的剛好是正確的GBK
CODE
$str = "中文測試";
$str_tran = iconv('latin1', 'utf-8', $str);
echo $str_tran; // 顯示亂碼,既不是GBK也不是utf-8和latin1
echo "<br>-----------<br>";
$str_re_tran = iconv('utf-8', 'latin1', $str_tran);
echo $str_re_tran; // 顯示 “中文測試”
而將GBK字符誤當作utf-8轉換爲錯誤的GBK編碼則出現錯誤
CODE
$str = "中文測試";
#$str_tran = iconv('utf-8', 'gbk', $str); // 錯誤!!!
可見一種編碼是否能被當作另一種編碼被轉換爲第三種編碼,取決於編碼的固有屬性,上面我們舉的第一個例子只是碰巧GBK編碼能被誤當作latin1被轉換爲utf-8。如果是如下情況,則數據庫肯定不能正常存取數據。
GBK => utf-8 => GBK(未實驗)
三、結論
頁面能正常存取但phpmyadmin不能正常存取,從嚴格意義上來說應該是一種錯誤,頁面是否能正常存取取決於連接字符集是否能正常的被轉換爲存儲字符集。
要保證頁面能正常存取,並且工具也能正常使用,一般保持頁面字符集等於或兼容連接字符集就可以了。
【但是更多情況是,夠買的虛擬主機提供的數據庫編碼是固定的,自己無法調整,這時候只能調整PHP程序了】
php中讀取數據庫產生亂碼的原因與解決方法
以數據庫database爲例
<?PHP
$conn = mysql_connect("localhost","root","");
//////////////////////////請根據你的數據庫編碼在鏈接數據庫的地方加入如下編碼就可以了
mysql_query("set names 'gbk'");//這就是指定數據庫字符集//////////////////////////////////////////
///////////////////////////////
mysql_select_db("database");
$sql = "select * from database";
$result = mysql_query($sql,$conn);?>
<head>
<meta http-equiv="Content-Type" c />
<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 "
<tr>
<td align=\"center\">".$row['w3skyid']."</td>
<td>".$row['w3skycontent']."</td>
</tr>";
}
?>
</table>
</body>
</html>
<?PHP
mysql_free_result($result);
?>
如果我們將mysql_query("set names 'gbk'");註釋掉,肯定時亂碼.加上那句又正常了
頁面申明編碼:在HTML代碼HEAD裏面,可以用<meta http-equiv="Content-Type" cXXX" />來告訴瀏覽器網頁採用了什麼編碼,目前中文網站開發中主要用的是GB2312和UTF-8兩種編碼。
MySQL數據庫操作過程中出現了三種字符集:
1、頁面字符集(也就是 c)
2、連接字符集(也就是 "Set names 'GBK'")
3、字段字符集(無論是庫還是表的字符集,將最終反映到字段上)
一、實驗:
1、情況一
數據庫字段字符集:utf-8
連接字符集:沒有顯式設置,默認爲latin1
頁面字符集:gbk
存入過程:
1)頁面用GBK表示的SQL向服務器提交存入請求;
2)默認情況下(不用Set Names '??')服務器用latin1打開連接;
3)服務器誤認爲當前的SQL語句是用latin1表示的;
4)服務器將GBK字符當作latin1字符,錯誤的運用“latin1轉UTF-8函數”將字符轉換後存入UTF-8字段中;
5)( 錯誤的latin1(其實是GBK) => 錯誤的UTF-8)
6)如果用phpmyadmin打開該表(用utf8連接)將會看到該字段爲亂碼;
讀取過程:
1)默認情況下(不用Set Names '??')服務器用latin1打開連接;
2)服務器將UTF-8字段中的值轉換爲latin1返回給客戶端;
3)(錯誤的UTF-8 => 錯誤的latin1(其實是GBK))該過程爲存入過程5的逆過程。(剛好錯錯得對了)
4)將服務器誤認爲是latin1的GBK編碼按頁面字符集正常顯示;
用示意圖來表示就是:
CODE
存入過程:
----------------------
頁面 連接 存儲
----------------------
GBK => latin1 => utf-8
---------------
------------- |
| +------- 該過程得到的utf-8是一串不知所云的亂碼,但MySQL固執的認爲這串碼爲UTF-8
|
+------ MySQL將GBK誤認爲是latin1
讀取過程:
----------------------
頁面 連接 存儲
----------------------
GBK <= latin1 <= utf-8
---------------
------------- |
| +------- 正是這串亂碼經過逆過程轉換回正確的GBK編碼,只是MySQL認爲是latin1而已
|
+------ MySQL將誤認爲是latin1的GBK編碼傳回了頁面,剛好得到正確的編碼。
2、情況二
數據庫字段字符集:utf-8
連接字符集:gbk
頁面字符集:gbk
文字描述略。
示意圖:
CODE
存入過程:
----------------------
頁面 連接 存儲
----------------------
GBK => GBK => utf-8
------------
------------- |
| +------- 該過程得到的utf-8是由GBK轉換而來的,是正確的utf-8編碼
|
+------ 頁面字符集等於連接字符集,MySQL認爲頁面傳遞給它的是GBK編碼,它的想法正好符合事實。
讀取過程:
----------------------
頁面 連接 存儲
----------------------
GBK <= GBK <= utf-8
---------------
------------- |
| +------- 用“utf-8轉GBK函數”將正確的utf-8編碼轉換回GBK
|
+------ 頁面字符集等於連接字符集,顯示沒有任何問題。
3、情況三
數據庫字段字符集:gbk
連接字符集:沒有顯式設置,默認爲latin1
頁面字符集:gbk
CODE
存入過程:
----------------------
頁面 連接 存儲
----------------------
GBK => latin1 => GBK
------------
------------- |
| +------- 字符被“latin1轉GBK函數”轉換的成了亂碼,但MySQL認爲它是GBK,所以工具無法正常顯示。
|
+------ MySQL認爲頁面傳遞給它的是latin1編碼,它將在後續過程中畫蛇添足地將正確的GBK轉換爲亂碼。
讀取過程:
----------------------
頁面 連接 存儲
----------------------
GBK <= latin1 <= GBK
---------------
------------- |
| +------- “GBK轉latin1函數”將亂碼轉換爲GBK,但MySQL卻認爲它們是latin1
|
+------ 錯誤的latin1編碼其實是正確的GBK編碼,頁面顯示正常,但工具顯示不正常。
二、字符集之間的轉換
筆者試着將GBK字符誤當作latin1轉換爲錯誤的utf-8能成功,逆過程中將亂碼轉換回latin1得到的剛好是正確的GBK
CODE
$str = "中文測試";
$str_tran = iconv('latin1', 'utf-8', $str);
echo $str_tran; // 顯示亂碼,既不是GBK也不是utf-8和latin1
echo "<br>-----------<br>";
$str_re_tran = iconv('utf-8', 'latin1', $str_tran);
echo $str_re_tran; // 顯示 “中文測試”
而將GBK字符誤當作utf-8轉換爲錯誤的GBK編碼則出現錯誤
CODE
$str = "中文測試";
#$str_tran = iconv('utf-8', 'gbk', $str); // 錯誤!!!
可見一種編碼是否能被當作另一種編碼被轉換爲第三種編碼,取決於編碼的固有屬性,上面我們舉的第一個例子只是碰巧GBK編碼能被誤當作latin1被轉換爲utf-8。如果是如下情況,則數據庫肯定不能正常存取數據。
GBK => utf-8 => GBK(未實驗)
三、結論
頁面能正常存取但phpmyadmin不能正常存取,從嚴格意義上來說應該是一種錯誤,頁面是否能正常存取取決於連接字符集是否能正常的被轉換爲存儲字符集。
要保證頁面能正常存取,並且工具也能正常使用,一般保持頁面字符集等於或兼容連接字符集就可以了。
【但是更多情況是,夠買的虛擬主機提供的數據庫編碼是固定的,自己無法調整,這時候只能調整PHP程序了】
php中讀取數據庫產生亂碼的原因與解決方法
以數據庫database爲例
<?PHP
$conn = mysql_connect("localhost","root","");
//////////////////////////請根據你的數據庫編碼在鏈接數據庫的地方加入如下編碼就可以了
mysql_query("set names 'gbk'");//這就是指定數據庫字符集//////////////////////////////////////////
///////////////////////////////
mysql_select_db("database");
$sql = "select * from database";
$result = mysql_query($sql,$conn);?>
<head>
<meta http-equiv="Content-Type" c />
<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 "
<tr>
<td align=\"center\">".$row['w3skyid']."</td>
<td>".$row['w3skycontent']."</td>
</tr>";
}
?>
</table>
</body>
</html>
<?PHP
mysql_free_result($result);
?>
如果我們將mysql_query("set names 'gbk'");註釋掉,肯定時亂碼.加上那句又正常了
頁面申明編碼:在HTML代碼HEAD裏面,可以用<meta http-equiv="Content-Type" cXXX" />來告訴瀏覽器網頁採用了什麼編碼,目前中文網站開發中主要用的是GB2312和UTF-8兩種編碼。
http://www.wangminghui.com/bbs/redirect.php?fid=5&tid=1447&goto=nextoldset