避免乱码的方法通常是:php页面和mysql字符集统一、查询前用“set names utf8”
我一直是这样做,但是不知道为什么。
因为我从php发给mysql 的中文,不都是符合php所使用的编码规则的二进制串吗?那我管mysql的编码是什么呢?只要我取出来还是这个串,在php中就不会是乱码啊。然后我了一个试验:
(1)一个php页面往某表里插中文
(2)一个php页面从这个表里取插入的中文
(3)表是utf-8的,俩php页面是gb2312也就是我在gb2312的php页面,往utf8的表里插值、取值。
结果是,在查看这张表的时候,确实中文是乱码。然后取出到php页面时,就能正常显示中文了。
这也应验了我刚才的猜测。但我后来在取值的php页面上用了“set names utf8”,取出来的中文就是乱码了。让我百思不得其解。
我知道set names utf8是用来指定php和mysql交互的字符集的,但是它只要传过来的还是我插进去的那个二进制串,就不应该出现乱码啊?这是为什么呢???望大家指教!!!
我一直是这样做,但是不知道为什么。
因为我从php发给mysql 的中文,不都是符合php所使用的编码规则的二进制串吗?那我管mysql的编码是什么呢?只要我取出来还是这个串,在php中就不会是乱码啊。然后我了一个试验:
(1)一个php页面往某表里插中文
(2)一个php页面从这个表里取插入的中文
(3)表是utf-8的,俩php页面是gb2312也就是我在gb2312的php页面,往utf8的表里插值、取值。
结果是,在查看这张表的时候,确实中文是乱码。然后取出到php页面时,就能正常显示中文了。
这也应验了我刚才的猜测。但我后来在取值的php页面上用了“set names utf8”,取出来的中文就是乱码了。让我百思不得其解。
我知道set names utf8是用来指定php和mysql交互的字符集的,但是它只要传过来的还是我插进去的那个二进制串,就不应该出现乱码啊?这是为什么呢???望大家指教!!!
在mysql+php程序开发中,总结了产生乱码原因:mysql数据库默认的编码是utf8,如果这种编码与你的PHP网页不一致,可能就会造成MYSQL乱码. MYSQL中创建表时会让你选择一种编码,如果这种编码与你的网页编码不一致,也可能造成MYSQL乱码. MYSQL创建表时添加字段是可以选择编码的,如果这种编码与你的网页编码不一致,也可能造成MYSQL乱码. 用户提交页面的编码与显示数据的页面编码不一致,就肯定会造成PHP页面乱码. 如用户输入资料的页面是big5码, 显示用户输入的页面却是gb2312,这种100%会造成PHP页面乱码. PHP页面字符集不正确. PHP连接MYSQL数据库语句指定的编码不正确.
但麻烦大家仔细看下我的问题,我问的不是如何避免出现乱码~我第一句我就说了吗“避免乱码的方法通常是:php页面和mysql字符集统一、查询前用set names utf8”麻烦大家别再回答有关如何避免出现乱码的问题了。再次感谢大家对我问题的回答!!!:)
2,PHP文件内的字面常量字符串一定要和Mysql的CONNECTTION/CLIENT/RESULT编码一致。
3,输出到HTML页面的Content-Type一定要和CONNECTTION/CLIENT/RESULT编码一致。
mysql相信你的配置,懂吗。你配置CLIENT/CONNECTION/RESULT都是UTF8,那么它就相信你传给它的数据都是UTF8编码的,它不会识别它们,在它眼里只有字节流,而且它确信特殊字节,比如:',NULL,\之类的字符都被\转义过,这样它就可以编码无关的识别SQL命令了,到这里为止,它不会做任何转换,记住。然后MYSQL有个SERVER编码,或者说数据库的表有编码,那么MYSQL这时候会依据CONNECTTION/CLIENT编码向存储编码进行转换,数据就那么存在数据库里了,等你查询的时候,它又会做一次转换,从存储编码转向RESULT编码,所以CONNECTTION/CLIENT/RESULT三者统一就OK了,并且保证PHP的确传递的是UTF8编码数据。
SET character_set_client = x;
SET character_set_results = x;
SET character_set_connection = x;
而这3个设置决定了不同阶段的字符集------------------------------------如果不加set names utf8
一般缺省情况下这3个设定都是latin1,你可以用show VARIABLES like 'character_set%'看一下ok,这时,
字符集的变化情况是
gbk(输入页面)->latin1(character_set_client)->latin1(character_set_connection)->utf8(数据库)->latin1(character_set_connection)->latin1(character_set_results)->gbk(输出页面)比如你输入一个"严"
"D1CF"(输入的一个gbk字符,被解释为2个latin1字符,因为你的client是latin1)
=>"D1""CF"(2个latin1字符ÑÏ)
->"c391""c38f"(2个utf8字符,进db,注意这时是4个字节,2个字符)
->"D1""CF"(2个latin1字符ÑÏ)
没了....嗯?为啥没了还能在页面上看到正确的汉字"严"???如果你在页面上"查看源代码", 你会看到那是"乱码"(latin字符)
这个是因为html页面是流方式输出到浏览器,浏览器只知道接受一串字符过来,然后根据你指定的编码,比如<meta http-equiv="Content-Type" content="text/html; charset=gbk"/>
来分析显示字符,注意2个latin1字符D1CF和一个gbk汉字严在二进制下是无法区分的,所以它就解释其为汉字,
如果你charset=ISO-8859-1了,它就变"乱码"了-----------------------------------------------------------------好, 这下来说set names utf8后, 就是
set character_set_client = utf8;
set character_set_results = utf8;
set character_set_connection = utf8;那么,字符集变化为
gbk(输入页面)->utf8(character_set_client)->utf8(character_set_connection)->utf8(数据库)->utf8(character_set_connection)->utf8(character_set_results)->gbk(输出页面)那么"严"的变化为
"D1CF"(输入的一个gbk字符,因为你client是utf8....被当成utf8字符)
->但是...好像不是合法的utf8字符....所以...(这步我没测试,到底转成了什么我也不知道)
->"乱码"(?个utf8字符)(存入数据库)
->"乱码"(原样取出并传到客户端,因为db和results都是utf8)
页面上就更是乱码了,而且无法变化页面字符集来得到正确的汉字----------------------------------------------------------所以,很多人都知道,你的这个情况应该set names gbk,就是
set character_set_client = gbk;
set character_set_results = gbk;
set character_set_connection = gbk;那么,字符集变化为
gbk(输入页面)->gbk(character_set_client)->gbk(character_set_connection)->utf8(数据库)->gbk(character_set_connection)->gbk(character_set_results)->gbk(输出页面)那么"严"的变化为
"D1CF"(输入的一个gbk字符,因为你client是gbk,所以被正确解释成gbk字符)
->"e4b8a5"(一个utf8字符,进db,注意这时是3个字节,1个字符)
->"D1CF"(转回正确的gbk字符)
这时你"查看源代码",应该也是正确的字符"严"---------------------------------------------------------应该足够明白了吧, 所以我经常让人用length和CHAR_LENGTH测数据库里的字符串的字节数和字符数,
大体可以知道保存的字符是否正确嗯,有问题欢迎再探讨
character_set_client / character_set_results / character_set_connection
这几个mysql既然放在不同的设置变量里,它们是完全可以设置成不同的字符集的,虽然我们很多时候都不需要. 1)这几个是基于连接,所以set names要放在connect之后,
你完全可以让不同的客户端使用不同的client/results,比如一个人gbk连上来,一个人big5连上来,他们可以分别看见gbk/big5的页面2)你可以完全可以client设成gbk, results设成big5,
这样你可以发送gbk字符串到服务端,存utf8进db,再big5输入....(当然,可想而知这个应用比较特别)3)你的编码必须兼容,不同的编码包含不同的字符,在字符从一个集转向另一个集的情况,目标集没有的字符会变成?,这个是不可逆的
比如你不能cient/result/db是utf8,然后connection是latin1....这样因为汉字在latin1里都是不存在的,会全部变成?,然后也变不回来了
放进去的是什么,拿出来的就是什么!
至于数据在数据库是如何存放的,就不是我们需要考虑的了。这就是问什么我们选择使用数据库系统而不是文件系统的原因。
引入字符集的原因在于,我们不仅仅是在数据库里简单的存放数据,还需要通过数据库进行检索和排序
由于不同的字符集的检索和排序的规则是有所区别的,所以需要制定字符集。这就是所谓的“二进制可靠”
另外,存放在数据库中的内容是给大家使用的,有人需要utf-8字符集,有人需要gbk字符集,但是你并不可能对同一内容去保存多个字符集版本。
你只需通过 set names 通知一下 mysql 现在使用什么字符集进行交互就可以了
字符集的转换工作就由 mysql 来完成了
但我对其中还是有点不太明白,这段:
比如你输入一个"严"
"D1CF"(输入的一个gbk字符,被解释为2个latin1字符,因为你的client是latin1)
=>"D1""CF"(2个latin1字符ÑÏ)
->"c391""c38f"(2个utf8字符,进db,注意这时是4个字节,2个字符)
->"D1""CF"(2个latin1字符ÑÏ)“严”字在第一次被解释成latin1的时候,被翻译成了字符ÑÏ,但是它底层的值还是D1CF。
那为什么到入db,被解释成utf8的时候,就改变它的底层值编程4个字节了呢?而刚才解释成latin1的时候是没有改变底层值的啊。
比如你输入一个"严"
"D1CF"(输入的一个gbk字符,被解释为2个latin1字符,因为你的client是latin1)
不是“解释为”而是当做
由于表是 utf8 的,所以在入库时 mysql 要做 latin1 到 utf8 的编码转换,出库时 mysql 要做 utf8 到 latin1 的编码转换
于是,放进去什么,拿出来还是什么