关于字符集的若干问题总结

来源:互联网 发布:如何查询淘宝买家等级 编辑:程序博客网 时间:2024/05/17 07:19

html页面的字符集:utf-8 gb2321

<meta http-equiv="Content-Type" content="text/html;charset=gb2312">
<meta http-equiv=Content-Type content="text/html;charset=utf-8">
注意:这里最好不使用gbk。如果使用gbk某些浏览器可能会不认并使用utf-8或其他编码编码


源文件编码:text file encoding

linux的文件系统默认采用utf-8编码
windows(中文)的文件系统默认采用gbk编码
文件系统编码涉及文件和文件名的编码
开发工具可以为项目设定默认的文件编码,如eclipse 项目的text file encoding就是设置默认的文件编码
在windows下sublime默认使用utf-8编码,notepad++可以转换文件编码
注意:如果文件使用中文命名,那么项目在不同文件系统中迁移,就要转换文件名的编码,否则可能造成文件不能被识别。
最好源文件采用utf-8编码,文件名中使用英文和字符来命名,来保证项目的可移植性。
注意:如果php文件的编码gbk,那么文件中的字符串的值也是gbk编码的。
js虽然认为字符串是utf-8的编码方式的,但js本身并不会处理他
但ajax中的send函数会把字符串处理成以utf-8编码的详见ajax传参


浏览器自动检测对页面编码集的影响

如果页面的源文件的编码与Content-type不一致很可能导致浏览器启动自动编码,导致不同浏览器的不同表现。
为了避免不必要的麻烦和各种不可预测bug的产生,一定要让页面源文件的编码与Content-type一致。
//保证文件的meta与file_encoding一致,由于浏览器的自动识别功能如果不一致可能导致不同浏览器的不同识别
例如html文件或生成html的php文件的文件编码一致


php internal_encoding();

设置/获取内部字符编码
默认为:ISO-8859-1
可以设置:utf-8/gbk(CP936)
不知道有什么用,设置为不同值未对程序造成结果上的影响。


变量与字符串

字符串的编码集就是文件的编码集
变量只是存储了不同字符串的值,其编码集就是传入值的编码集。
赋值过程中,变量并不转码。
无论是php中还是js中都是这样。
注意:但是函数可以转码。如php中的mb_convert_encoding()函数和js中的send()


mb_convert_encoding(str,to,from);

$name =mb_convert_encoding($str, "utf-8","gbk");
php中的字符串转码函数。可以对php变量中的字符串进行转码。


mysql表字符集:latin1,utf8,gbk

ENGINE=InnoDB AUTO_INCREMENT=79 DEFAULT CHARSET=gbk;
ENGINE=MYISAM AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
在表定义语句的最后面设置
注意此处要写utf8,utf-8是不被识别的。
ENGINE表类型:MyISAM类型不支持事务处理等高级处理。默认使用InnoDB。
参考文献:http://www.360doc.com/content/14/0702/11/13883922_391427906.shtml
AUTO_INCREMENT第一个数据的AUTO_INCREMENT值
1.latin1 (参考百度百科)
  Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。
  ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
  ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。
  因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。
参考文献:http://blog.163.com/longsu2010@yeah/blog/static/173612348201162813357867/
2.utf8
在mysql里没有“-”,UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。UTF-8用1到4个字节编码UNICODE字符。
3.gbk
国标码。每个汉字及符号以两个字节来表示。
注意:latin1字符集理论上可以让表存储任何字符集的数据,但是你在解码每个数据的时候,必须其对应的字符集,否则会解码错误导致乱码
例如你可以把utf8的数据和gbk的数据存在不同列中甚至不同行中,只要最后的解码正确,你依然可以得到正确的结果,
使用set names latin1.解码在php中实现。mysql仅仅存储数据流。
这种做法相当的繁琐,和不推荐。


set names

mysql_query("set names utf8");//php不推荐虽然用着没什么问题
//mysql_set_charset("gbk"); //PHP 5.5.0 起已废弃,并在将来会被移除
$mysqli->set_charset("utf8")//设置在数据库间传输字符时所用的默认字符编码。最新推荐
mysqli_set_charset($link, "utf8")//过程化风格。最新推荐
$charset = mysqli_character_set_name($link);//返回当前数据库连接的默认字符编码
注意这里依然要填utf8
参考文献:
http://php.net/manual/zh/mysqli.character-set-name.php
http://php.net/manual/zh/mysqli.set-charset.php
character_set_client/character_set_connection/character_set_results这三个MySQL的”环境变量”, 这里再简单介绍下, 这三个变量, 分别告诉MySQL服务器, 客户端的编码集, 在传输给MySQL服务器的时候的编码集, 以及期望MySQL返回的结果的编码集. 
比如, 通过使用”SET NAMES utf8″, 就告诉服务器, 我用的是utf-8编码, 我希望你也给我返回utf-8编码的查询结果.
参考文章中提倡的:mysql_set_charset("gbk");mysql_set_charset("gbk");本扩展自 PHP 5.5.0 起已废弃,并在将来会被移除。
参考文章:http://www.jb51.net/article/29576.htm(有恶意广告小心)
set names设置了php与mysql沟通的默认字符集,包括php上传mysql和mysql返回php的默认沟通字符集。
注意:尽量使set names的值与php文件的编码一致,这样php文件中的字符串直接传入数据库不会乱码。否则php字符串要进行转码


ajax提交

ajax中用到了JavaScript技术。
JavaScript采用UTF-16编码的Unicode字符集,JavaScript字符串是有一组无符号的16位值组成的序列。
JavaScript定义的各式字符串操作方法均作用于16位值,而非字符,且不会对代理项对做单独处理,同样js不会对字符串做标准化的加工,甚至不能保证字符串是合法的UTF-16格式。
参考《JavaScript权威指南》第6版39页
当客户端页面采用gb2312编码,且php源文件也采用gbk编码是测试情况
异步post核心代码
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","post.php",true);//如果使用post.php?name=中文 //则传递的值可以是gbk编码//经测试使用get方式也可以传递gbk
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded;");//加上charset=gb2312;send()依然按utf-8编码
xmlhttp.send("name=中文烧烤机");//该代码导致post的数据为utf-8编码
因此以$.post(),或者$.ajax()进行post异步必然使用utf-8字符集编码,而且content-type参数经测试无效。因为在 XMLHttpRequest()中无效所以在Jquery中设置也无效
使用$.get(url,data,fun);如果使用data传递参数,还是以utf-8的字符集编码,只有在url中传参才能使用gbk字符集
经测试发现:$.post,$.ajax,$.get(url,data,fun)的表现一致,在url中传参为参数编码为gbk,在data中传参编码为utf-8
经测试发现:xmlhttp.open(method,url,true);无论是post还是get,在url中传参为参数编码为gbk
经测试发现:xmlhttp.send(data);post传参为utf-8编码,get传参无效。
注意:$.get()的表现与$post()表现一致
根据以上测试,可以认为通常的异步操作(不再url里传值)提交的参数必然是utf-8编码的
备注:由于没有测试究竟是utf-8还是utf-16字符集,而仅是测试按utf-8方式解码是否成功,因此本文中的utf-8代指utf-8系列字符集。


ajax返回

返回的数据更像是变量里的值。如果返回的是一部分html代码,如果我们将这段代码直接回显在页面上$().html(),那么这些数据解码的字符集是utf-8
注意:异步获取的数据在页面上以utf-8的方式解码,即使该页面的解码字符集是gbk
因此如果服务器端返回给ajax的数据如果是gbk格式的,那么ajax中会出现乱码。


json返回

json格式在开发中用的十分广泛。在php中json_encode函数可以直接将数组转成 json格式,十分方便。但是有可能你在使用json_encode函数时,无奈的发现中文被编码成null了。原来json只支持转义utf-8编码格式的中文。php数组使用json_encode函数中文被编码成null的原因是转义gbk 或者别的编码时,中文被忽略了。一般出现在文档编码或者输出的内容编码是非UTF-8时,也就是说,GBK或者GB2312的中文,就会出现编码失败的现象。
php数组使用json_encode函数中文被编码成null的原因和解决办法,如果你的程序是采用utf-8编码,请确保文件保存为utf-8 无bom格式,如果你的程序是gbk的,可以先转成utf-8编码后在使用json_encode函数。
http://blog.csdn.net/shrimpma/article/details/7586660
json返回是ajax返回中的一种,但其几乎不能与gbk打交道。
首先如果是数组里有gbk编码的值,json_encode()函数返回一个空。
只有先把数组里的gbk数据先用mb_convert_encoding("中文","utf-8","gbk")先转为utf-8编码,然后才能使用json_encode()编码返回,否则会编码失败返回空。
php文件或者客户端文件编码为gbk也可以是用json,包括json的函数。就像gbk编码html文件一样可以运行js一样。
json_encode()的数组必须是utf-8编码的数组。json对象也是utf-8编码的。
最重要的json对象必须是utf-8编码的。


页面提交字符集由什么决定:当前页面的解码字符集。
经测试,form直接提交,参数的字符集与当前页面编码的字符集一致。
与当前页面编码字符集一致的还有上面ajax中的url提交。
因此页面提交的post,get,方式和$.post,$.ajax,$.get(url,data,fun),xmlhttp.open(method,url,true)中url提交数据,其数据编码格式与当前页面的当前编码字符集一致。
注意:详见 浏览器自动检测对页面编码集的影响


5c问题

参考文章:http://www.jb51.net/article/29576.htm(有恶意广告小心)
<?php //默认mysql连接字符集是latin1, (经典的5c问题):
$db = mysql_connect('localhost', 'root' ,''); 
mysql_select_db("test"); 
$a = "\x91\x5c";//"慭"的gbk编码, 低字节为5c, 也就是ascii中的"\" 
var_dump(addslashes($a)); 
var_dump(mysql_real_escape_string($a, $db)); 
mysql_query("set names gbk"); 
var_dump(mysql_real_escape_string($a, $db)); 
mysql_set_charset("gbk"); 
var_dump(mysql_real_escape_string($a, $db));
结果:
  string(3) "慭\" 
  string(3) "慭\" 
  string(3) "慭\" 
  string(2) "慭" 
对于mysql_real_escape_string($a, $db)使用mysql_set_charset("gbk"); 会使其结果更正确,虽然好像没什么卵用。


当表的字符集是latin1,使用set names latin1, 如果不使用mysql_real_escape_string转换字符那么插入语句会执行不了。也就是无法插入数据库
使用mysql_real_escape_string后能够正确的插入数据库并正确读取
string(4) "慭慭" //php中的字符串
string(6) "慭\慭\" //mysql_real_escape_string转换后的字符串,mysql_set_charset("latin1");对结果没有影响
string(4) "慭慭"//从数据库读取的字符串


当表的字符集是latin1,使用set names gbk, 不论是否使用mysql_real_escape_string转换字符,插入语句都可以执行。
但读出的中文为乱码。即使普通的中文字符也是乱码
string(4) "中文" //php中的字符串
string(2) "??" //从数据库读取的字符串
string(4) "慭慭" string(4) "慭慭" string(2) "??"


当表的字符集是gbk时,使用set names gbk 可以直接放入sql语句(不使用mysql_real_escape_string),能够正确插入数据库并读写
string(4) "慭慭" //php中的字符串
string(6) "慭\慭\" //mysql_real_escape_string转换后的字符串,mysql_query("set names gbk");
string(4) "慭慭" //mysql_real_escape_string转换后的字符串,mysql_set_charset("gbk");
string(4) "慭慭"//从数据库读取的字符串


总结

set names是mysql对php的数据字符集格式接口
浏览器器当前页面的当前解码字符集是页面提交的字符集
通常ajax提交使用utf-8编码
php文件的编码字符集(text file encoding)决定php字符串的编码集
变量只是存储字符串的值,并不影响字符串的字符集。







0 0
原创粉丝点击