MySQL的编码问题和乱码问题对于新手来讲是一个麻团,剪不断,理还乱.
这次我碰到的问题是一个我大概5年前写的一个PHP小程序。那时还是一个初学Web程序的小菜鸟,几乎理所应当的犯了初学者该犯的所有错误。
想不到的是,5年中,那个小程序还一直被使用着。更想不到的是,我居然还有机会再次去维护它。
程序其实没有问题,中文输入和输出都很正常,只是PhpMyAdmin查看数据库,所有中文全是乱码。看看软件配置:
CentOS 4.1, Apache 2.0.53下运行的MySQL 4.1, PHP 5.2, PhpMyAdmin 2.6.1。 软件版本有点老,特别是PhpMyAdmin, 但是在公司内网,要升级软件可没那么容易。
仔细看了一下MySQL的编码,用命令: show variables like ‘char%’
1. mysql 命令行下直接使用:show variables like ‘char%’
character-set-client latin1
character-set-connection latin1
character-set-database latin1
character-set-results latin1
character-set-server latin1
character-set-system utf8
character-sets-dir /usr/share/mysql/charsets/
这没啥意外的,毕竟是那帮的瑞典人弄出来的嘛,默认就是全是latin1。但命令行下的中文也是乱码,这个稍后再看。
2. 程序页面里使用 mysql_query(“show variables like ‘char%'”) 输出结果:
character-set-client latin1
character-set-connection latin1
character-set-database latin1
character-set-results latin1
character-set-server latin1
character-set-system utf8
character-sets-dir /usr/share/mysql/charsets/
跟命令行下一样。这个也能理解,因为在程序里面没有对编码有个任何的改变。
3. 在PhpMyAdmin(版本2.6.1)的页面中使用mysql_query(“show variables like ‘char%'”) 输出结果:
character-set-client utf8
character-set-connection latin1
character-set-database latin1
character-set-results utf8
character-set-server latin1
character-set-system utf8
character-sets-dir /usr/share/mysql/charsets/
其中两行不一致。
原因分析和解决:
我发现小程序网页页面使用的是gb2312编码。也就是说,程序交给数据库的是gb2312版本的字符编码,数据库当成了latin1的编码格式在存储,而PhpMyAdmin用utf8格式来提取和显示的。天哪,什么乱七八糟的。
小程序能正常显示中文的原因是,gb2312的编码,以latin1编码连接,存储,提取,所以存和取的过程中编码没有变,提取到网页上之后,又以gb2312的编码方式显示,一切正常。
那么我要做的是PhpMyAdmin也以这样的过程执行就好了。其实MySQL命令行下的满足了数据库部分的要求,是不是显示部分编码由问题呢?那就试试吧:
1.退出MySQL Client, 在Linux命令行下Locale一下。嗯,本地编码是zh_CN.utf8的。
2.于是执行: export LANG=zh_CN.gb2312
3.然后: mysql -h localhost -u user -p 连接到数据库,执行一条查询语句,果然中文显示正常了。
看来我的推断是正确的。现在的问题是如何让PhpMyAdmin也这样做:
1. 首先要把页面编码变成gb2312。 看起来要把PhpMyAdmin的语言改为English, 因为直接在中文版上改编码,显然会让网页上的正常中文字变为乱码。然后进入./lang 目录下,把english-utf8.inc.php文件顶部附近的下面一行:
$charset=utf8 改为 $charset=gb2312
因为任何编码都不会让英文变成乱码。刷新PhpMyAdmin的页面,然后查看页面html源码可以发现页面的charset由utf8变成了gb2312:
<meta http-equiv=content-type content=”text/html; charset=gb2312“>
2. 再次在PhpMyAdmin的页面中使用mysql_query(“show variables like ‘char%'”), 输出结果变成了:
character-set-client gb2312
character-set-connection latin1
character-set-database latin1
character-set-results gb2312
character-set-server latin1
character-set-system utf8
character-sets-dir /usr/share/mysql/charsets/
看来character-set-client和character-set-results的编码跟页面编码是一致的。
3. 如何独立设置character-set-client和character-set-results呢?修改./libraries 的database_interface.lib.php文件,找到下边这一行:
$mysql-charset=$GLOBALS[‘mysql-charset-map’][$GLOBALS[‘charset’]];
改为:
$mysql-charset=”latin1″;
至此mysql_query(“show variables like ‘char%'”)输出的结果与程序页面一致,PhpMyAdmin也变查询出来的中文显示也没有乱码了。唯一的遗憾是PhpMyAdmin主页面显示的MySQL Charset: GB2312 Simpfilied Chinese(gb2312), 不过也无伤大雅了。
后记:
为了杜绝编码问题,以后一定要在程序开发的时候,在MySQL连接函数里面加上”SET NAMES UTF8″,这样至少也好转换一些。