博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

编码问题

Posted on 2015-12-17 21:44  苍老的小孩  阅读(117)  评论(0编辑  收藏  举报

       参考:summer_cool的博客(http://www.cnblogs.com/summer-cool/p/3932658.html)

       web开发中经常涉及前端网页——php——mysql之间的数据交互,当数据只有英文时通常不会有什么问题,但一旦涉及中文,三个地方的某一处字符编码不一致(如,网页使用的时gbk而mysql使用utf-8)就有可能导致乱码的出现。

(注:关于字符编码请参见百度百科:http://baike.baidu.com/view/1204863.htm?fr=aladdin)

前端网页编码:

通常我们都认为可以通过<head>标签内的<meta>项(如<META http-equiv="content-type" content="text/html; charset=xxx">)来设置整个页面的字符编码。大部分页面可以采用这种方式来告诉浏览器显示这个页面的时候采用什么编码,但是有的时候我们会发现有了这句还是不行,不管xxx是哪一种,浏览器采用的始终都是一种编码。

这种情况涉及到http协议通信中的头部(header)部分,实际上,用户浏览网页时,服务器发送给用户的内容不仅包括我们的网页(包括html/css/js这些代码内容),还包括被称为头部(header)的描述性内容,这些内容会告知客户端将要接收的数据的类型(是html还是纯文本还是多媒体文件等)、大小、来源等信息(如果想要看一下这些信息,可以使用telnet工具(而不是通过浏览器)按照http协议自己发起get等请求试试)。由于头部是优先于html发送的,<meta>作为html的一部分其优先级也低于头部,如果在头部中已经包含了有关网页字符编码的描述,浏览器最终就会按头部中说明的字符编码集来解析网页。

在php中,可以使用 header("content-type:text/html; charset=xxx"); 来发送关于字符集的头部。

而对于apache服务器来说,它具有一个AddDefaultCharset的功能,也就是会为每个发送的网页按照服务器默认的字符集设定好对应头部。

查看/etc/apache2/httpd.conf(2.4之前)或/etc/apache2/conf-available/charset.conf(2.4及以后),里面有一句AddDefaultCharset xxx如果这一句未处于注释状态,那么为每个网页添加默认字符集头部的功能就处于开启状态,此时单独设置<meta>标签里的字符集便没有效果。

注意:html页面所标明的编码方式应该与实际在编写html页面(其实就是纯文本)时保存所用的编码方式一致。

一般而言,为了兼容中文甚至更多的其它语言,使用utf-8编码方式是最省事的一种方式,因为utf-8几乎支持世界上的所有常用语言。

 

mysql数据库编码:

在终端下mysql -uusername -ppassword 后进入mysql的控制程序,再键入show variables like 'character%'; (注意往mysql终端中键入命令语句或sql语句时分号不可以省略)可以看到类似下图:

上面列举了mysql在各个层面上所使用的字符集,其中(*)

character-set-server/default-character-set:服务器字符集,默认情况下所采用的。 
character-set-database:数据库字符集。 
character-set-table:数据库表字符集。 
优先级依次增加。所以一般情况下只需要设置character-set-server,而在创建数据库和表时不特别指定字符集,这样统一采用character-set-server字符集。 
character-set-client:客户端的字符集。客户端默认字符集。当客户端向服务器发送请求时,请求以该字符集进行编码。 
character-set-results:结果字符集。服务器向客户端返回结果或者信息时,结果以该字符集进行编码。 
在客户端,如果没有定义character-set-results,则采用character-set-client字符集作为默认的字符集。所以只需要设置character-set-client字符集。

于是我们会发现,上图所示的character-set-server使用的不是utf8(注:在mysql中,utf-8编码方式的表示为utf8,没有“-”)。这是因为mysql默认的存储方式在没有修改的情况下就是latin1。在这种情况下,我们在使用mysql终端进行创建数据库和数据表的操作时,若在sql语句中没有指定所使用字符集,那么存储时使用的编码方式就会是latin1,明显,中文存放在这种本来用于存放拉丁文的编码方式下显示出来肯定是乱码。

那么怎么修改它呢,可以使用set character-set-server = utf8;(由于character-set-server优先级高,只修改它即可达到修改数据库存储编码方式的效果)。此后在终端里使用sql建表时表的存储编码方式即是utf-8。

但是,这个修改只对当前服务有效,使用quit;退出后再次进入mysql终端就会发现字符集又变回了latin1了。想要使修改永久生效的方法我目前找到的资料显示只有通过重新编译mysql时修改编译参数达到,如果有高手知道怎么不通过编译实现烦请留言告知。

 

php编码:

那么,说到了mysql,php在和mysql进行交互时要怎么保证传输数据过程中不出现乱码呢?

按照(*)处的描述,实际上,为了使得存入mysql和从mysql中取出数据时不出现乱码,我们只要使得以下三个系统参数设置为与服务器字符集character-set-server相同的字符集。 他们是:
character_set_client:客户端的字符集。 
character_set_results:结果字符集。 
character_set_connection:连接字符集。 
设置这三个系统参数可以通过向MySQL发送语句:set names xxx (xxx可以是utf8)来实现

因此,当涉及从php往mysql发送中文等非英文字符时,在mysql_connect语句后使用mysql_query("set names utf8");语句(这里假设数据库存储用的是utf8)后就可以放心传送和取回中文了。

此外,由于html页面实际上也可能由php动态生成,怎么保证php动态生成的页面所使用的编码方式和头部或<meta>里声明的一样呢?

在php目录下找到php.ini文件修改default_charset = "utf-8“即可使得php在输出页面时使用utf-8来编码。