`
xombat
  • 浏览: 163691 次
  • 性别: Icon_minigender_1
  • 来自: 乌托邦
社区版块
存档分类
最新评论

Web开发中的字符集问题和解决方案(完全版)

阅读更多

很多人在开发网站开始阶段没有注意到字符集统一的重要性,因此开发的网站不是数据库中存有乱码就是web页面显示为乱码。现以web开发中的字符集为主体讨论在个人和团队web开发中需要注意的问题,和相应的解决方法。

1. 常见问题的解决<o:p></o:p>

比如我在网站开发阶段就遇到两个严重的问题:

我使用的是Zend studio的开发工具,保存代码时也是默认保存的,没有注意到字符集的问题,开始一切正常,但是当我想在页面中添加’©’这个符号的时候,网页不能正常显示。后来发现,zend 默认的保存编码是gb2321编码,而这个编码中不能表示以上那个字符,要显示那个字符有两种方式,一种是使用php中的图形函数,将copyright字符转换为图形显示在网页上。第二种方法是将网站格式完全转化为utf-8编码。我采用的是后者,将全部页面保存为utf-8格式,然后在content-type中将charset=转换为utf-8;

<o:p> </o:p>

第二个严重的问题是数据库的乱码问题。再将文章存入数据库中后,使用phpmyadmin查看其中数据显示的也全部是乱码,起初没有对这个完全正视起来,因为在php使用其中数据时没有出现异常,在网页中显示正常。但是这本就是个严重的隐患,因此今天想办法解决了,解决方法使用的是很笨的方法,将数据库中的数据读出来,存入表中,然后写一个安装文件(使用php),再连接数据库后,添加一段代码,效果如下:

$conn=new mysqli(hostname,username,passwd,dbname);

$conn->query(‘set names \’utf8\’);

这样在将php的安装文件中的数据写入数据库时就不会出现编码不一致的问题。在phpMyadmin中也能正常显示了。

<o:p> </o:p>

<o:p> </o:p>

2.原理介绍<o:p></o:p>

(摘自阿强的blog: http://www.phpchina.com/10458/viewspace_4782.html)<o:p></o:p>

1. Collations
Collations翻成中文是“校验”,在网页开发的过程中,这个词汇,只在Mysql里使用,主要作用是指导Mysql对字符的比较,比如, ASCII字符集里,Collations规定了a小于b,a等于a,以及a是否等于A之类的。通常,大家基本可以忽略Collations的存在,因为每个字符集都有一个默认的Collations,通常,使用默认的Collations就可以了。以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个Unicode编码是594EUnicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是还是<o:p></o:p>

2.字符集
与这对比的是,字符集是个更广的概念,即使是Windows下普通的文本文件,也渗及到字符集的问题。不同的字符集,规定了不同的字符的编码方式。一个 character set (字符集)是一组符号和编码,比如,ASCII字符集,包括的字符有:数字,大小写字母,分号、换行之类的符号,编码方式是用一个7bit表示一个字符(A的编码是65,b的编码是98)。ASCII只规定了英文字母的编码,非英文语言不能用ASCII编码表示,为此,不同的国家,都为自己的语言做了编码,比如,我们国家,就有GB2312编码。但每个国家之间的编码不同,也存在着一些跨平台的问题,为此,一些国际化标准组织,就制定了一些国际通用的编码,最常用的就是UTF8了。ASCII只对英文符号和英文字母做了编码,GB2312对英文符号,英文字母,汉字做了编码,UTF8对世界上所有的语言文字做了编码,所以,GB1212的字符包含了ASCII字符,UTF8包含了GB2312字符。由此可见,UTF8是所含最广字符的字符集,所以,在一些多语言的WEB系统中,一般用UTF8字符集(PHPMyAdmin使用UTF8编码)。
任何文本的存储,都渗及到字符集的概念。包括数据库,也包括普通的文本文件。
主要术语:
字符:汉字,英文字母,标点符号,拉丁文等等。
编码:将字符转换成计算机存储的格式,比如,A用65表示
字符集:一组字符以及对应的编码方式。

a. Mysql的字符集
Mysql目前支持多字符集,并且,支持在不同的字符集之间转换(便于移植和支持多语言)。
Mysql可以设置服务器级字符集、数据库级字符集、数据表级字符集、表列的字符集,实际上,最终使用字符集的地方是存储字符的列,比如,你设置 table1中col1列是字符类型,col1才用到了字符集,如果table1表的col2列是int类型,col2不使用字符集的概念。
服务器级字符集、数据库级字符集、数据表级字符集都是为列的字符集做默认选项的。
Mysql一定有一个字符集,可以通过启动时加参数指定,也可以编译时指定,也可以在配置文件里指定。Mysql服务器字符集,只是做为数据库级的默认值。创建数据库时,你可以指定字符集,如果没指定,就使用服务器的字符集。同理,创建表时,你可以指定表级的字符集,如果没指定,使用数据库的字符集做为表的字符集。创建列时,你可以指定某列的字符集,如果没指定,就使用表的字符集。
通常情况下,您只需设置服务器级的字符集,其它的数据库级,表级,以及列级的字符集,都继承自服务器级字符集。
由于UTF8是最广的字符集,所以,一般情况下,我们设置Mysql服务器级的字符集为UTF8!

b. 普通文本的字符集问题
任何文本的存储,都存在着字符集的问题,普通文本文件也不例外。
Windows2000+的系统中,打开记事本,“保存为…”对话框,就有一个选项,可以让你选择存储文本的编码方式。
通常情况下,大家都使用Windows2000+的系统,都使用默认的编码,所以,不会碰到字符集的问题。
Windows下,保存文本文件时,可以选择编码方式,但打开文本文件时,都是自动判断编码方式的。网上有一个用Windows2000+的记事本玩移动,联通的笑话,大家可以搜搜,就是因为Windows在打开文本文件时,编码判断错误引起的问题。
因为自动判断编码有时会错误,所以,有的文本文件,规定了如何识别自身所使用的编码。HTML文件就是一个这样的例子。>
HTML是文本文件。存储HTML文件的时候,需要使用一个编码,并且,在HTML文件里,也使用HTML语法,指定了该文件所使用的编码(比如< meta http-equiv="content-type" content="text/html; charset=UTF-8">)。如果HTML文件没有指定编码,则浏览器自动识别文件的编码。如果HTML指定了编码,则浏览器使用HTML指定的编码。
通常情况下,HTML文件指定的charset和HTML文件自身的编码是一致的,但也有不一致的情况,如果不一致,就会导致网页乱码(此处乱码,只和文本文件有关,和数据库无关。)使用专门的网页编辑工具(比如Dreamwave),会自动根据网页中的charset值来编码文件。

c. php+mysql的字符集问题
PHP最终生成的是文本文件,但他要取数据库里的文本,或将文本存进数据库
由于Mysql支持多字符集,默认情况下,Mysql不知道PHP发给他的是什么编码的字符,所以,Mysql要求客户端(PHP)告诉他存取的字符集是什么。  
PHP通过设置character_set_client,告诉Mysql,PHP存进数据库的是什么编码方式。
PHP通过设置character_set_results,告诉Mysql,PHP需要取什么样编码的数据。
PHP通过设置character_set_connection,告诉Mysql,PHP查询中的文本,使用什么编码。
MYSQL使用设置的编码方式存储文本。 
假设Mysql使用setserver来存储文本,PHP的character_set_client是setclient,PHP的character_set_results是setresult。那么,Mysql将PHP发来的文本,从setclient编码方式,转换成 setserver编码方式,再存入数据库,如果PHP取文本,Mysql将文本从setserver转换成setresult,再发送给PHP。
PHP文件(最终生成的HTML文件)本身有个编码,如果Mysql传过来的编码,与PHP文件自身的编码不同,那么,整个网页,必然乱码。所以,PHP一般将自己的编码方式,告诉Mysql。
要保证不乱码,就必须将三个编码统一:一是网页自身的编码,二是HTML里指定的编码,三是PHP告诉Mysql的编码(包括character_set_client和character_set_results)。
第一和第二个编码,如果使用DW之类的编辑器写的网页,通常是一致的,但用记事本写的网页,有可能不一致。(这里我感觉不太准确,需要讨论一下)
第三个编码,需要手工通知Mysql。这步可以通过在PHP里使用mysql_query(“set names characterX”)来实现。

d.字符集的转换问题
如果小字集转换成大字符集,不会丢失数据,但大字集,转换成小字集,可能会丢失数据。
比如,UTF8里有的字符,GB2312不一定有,所以,从UTF8转换到GB2312可能会丢失一些字符。
但有种情况例外,先从GB2312转成UTF8,再从UTF8转成GB2312,这种情况是不会丢数据的,因为,刚开始转换的文本,都是GB2312里的字符,所以,整个过程都是GB2312的字符在转换,不会丢失。
正因为UTF8能容纳世界上的所有字符,所以,数据库一般使用UTF8编码。这使得,任何字符都可以存进UTF8编码的数据库。

e. PHPMyAdmin乱码的问题
PHPMyAdmin支持多国语言,这就必定要求HTML页面使用UTF8编码。
HTML页面使用UTF8编码,这就必定要求PHPMyAdmin连接Mysql时,character_set_client和character_set_results使用UTF8编码。
当前情况下,PHP连接Mysql只能是使用set names(或其它几个语句)来通知Mysql的编码方式,如果没有显式的声明编码方式,都将使用latin1编码。一般的程序,都没有显式声明 character_set_client变量,所以,都是将gb2312文本,按latin1编码方式存在数据库,PHPMyAdmin再用utf8格式读取,肯定是乱码的。
如果PHP程序按正确的编码存入数据库,肯定是没有问题的。所以,需要修改的不是PHPMyAdmin.(虽然有时修改PHPMyAdmin可以解决乱码问题,但这不是问题的根本)

补充:
(参考:http://blog.csdn.net/fmddlmyy/archive/2005/05/04/372148.aspx

UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?Unicode规范中推荐的标记字节顺序的方法是BOMBOM不是“Bill Of Material”BOM表,而是Byte Order MarkBOM是一个有点小聪明的想法:<o:p></o:p>

UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFEUCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"<o:p></o:p>

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM<o:p></o:p>

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。<o:p></o:p>

Windows就是使用BOM来标记文本文件的编码方式的。

<o:p> </o:p>

讨论:<o:p></o:p>

第一和第二个编码,如果使用DW之类的编辑器写的网页,通常是一致的,但用记事本写的网页,有可能不一致。<o:p></o:p>

如果在dw中选择了:“包括Unicode签名(Bom)”那么,保存的和记事本保存的是一样的,都是前面多出三个字节。这三个字节在网页显示时有特殊的作用,如果这样保存一个网页,在html中不需要指定utf-8格式,浏览器就自动选用utf8编码,而且浏览者不能自己修改成其他的编码格式。如此保存在开发中可能是一个既保险又提高效率的好方法,但是考虑到他和其他很多开发工具的不兼容(zend中没有这个功能,而且显示代码的时候,将前三个字符显示为点,在editplus中全部显示为乱码。所以不推荐选用bom<o:p></o:p>

<o:p> </o:p>

3.团队中的字符集的同步<o:p> </o:p><o:p> </o:p>

我们推荐使用utf-8字符集,因为此字符集将所有字符都包含了进去,因此以后不会再担心字符表示不了的问题。

但是如何在团队开发重视全部参与编码的成员都保证自己的字符是utf-8编码的?我们需要考虑这些方面:开发工具的默认编码(也就是网页的编码),html中指定的编码,和php指定的编码,数据库的编码。

<o:p></o:p>

对于开发工具默认的编码,需要考虑美工的开发工具和编程人员的开发工具,最普遍的为dreamweaverzend studio,最一劳永逸的方式不是在每次保存时指定编码格式,而是在编程工具的选项或者是首选项中指定字符集编码,对于dreamweaver,打开编辑菜单,选择首选参数(或Ctrl+U),选择新建文档分类(如下),在默认编码中选择如图的utf-8,然后将下面的“当打开未指定的”,在unicode标准化表单中选择c类,但是不要选择下面的“包括unicode签名”,具体问什么,上面已经说了。这样在每次保存的时候,就默认保存为utf编码。<o:p></o:p>

<v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></v:path><o:lock v:ext="edit" aspectratio="t"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 375pt; HEIGHT: 261pt" type="#_x0000_t75" alt="" o:button="t"><v:imagedata src="file:///F:\DOCUME~1\xombat\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:href="http://www.cnbruce.com/blog/uploadfile/GIF/2006-7/28-16727-dw-utf-8.gif"></v:imagedata></v:shape>

对于php开发人员,使用zend ,选择tool->preference…进入preference对话框,选择Desktop标签,然后在Encoding文本框中选择UTF-8.在进入Debug标签,从中选定define server out put encoding ,然后在后面的文本框中选择utf-8(这一步主要是为了在zend开发环境中调试而用)

<o:p></o:p>

html中指定的编码

保存的文本是utf-8的还不够,我们还需要在html中指定编码类型,具体有两种方法,可以任选其一:

Html代码方法:在标签中加入这一行: <meta http-equiv="content-type" content="text/html; charset=UTF-8">

Php代码方法:在输出任何数据之前,加入这行代码:header(‘content-type:text/html;charset=utf<st1:chmetcnv tcsc="0" numbertype="1" negative="True" hasspace="False" sourcevalue="8" unitname="’" w:st="on">-8’</st1:chmetcnv>);

两种方法任选其一。<o:p> </o:p>

Php指定编码:

需要在连接好数据库后,加入如下一行代码,

$conn->query(‘set names \’utf8\’);

具体见第一部分问题解决。<o:p> </o:p>

数据库的编码:

这里数据库的编码,指的是数据库中默认的编码默认的编码方式使用php的函数可以查看(连接数据库后,$charset=$conn->character_set(),也可以通过查看mysql系统变量来查看; $charset就是编码类型的信息)。设定数据库的默认编码方式是在mysql 程序文件的my.ini中修改如下的指令:

将所有的都改为:default-character-set=utf8

mysqld下面添加:default-collation=utf8_general_ci(其实这行不添加也可以,utf-8默认的就是这个)

可以参阅:http://phpbb-tw.net/phpbb/viewtopic.php?t=41148&highlight=&

但不要学着他将已经保存数据的表用alter进行转换。 

<o:p></o:p>至此完。



 

分享到:
评论
1 楼 kafuka2008 2008-04-12  
顶,好帖,学习很多。。。

相关推荐

    Web开发敏捷之道第三版(中文版).pdf

    - **Hello, Rails**:通过一个简单的“Hello World”示例介绍基本的Rails应用结构和开发流程。 - **把页面连起来**:学习如何在Rails应用中创建路由和控制器,使不同的URL能够指向不同的页面或功能。 - **我们做了...

    JSF中文问题解决方法完整版

    这篇博文“JSF中文问题解决方法完整版”提供了关于如何处理JSF框架在处理中文字符时可能出现的问题的解决方案。JSF作为Java EE的一部分,常常用于企业级应用开发,但处理中文字符时可能会遇到编码不兼容、乱码等问题...

    OpenReports中文支持完全解决方案

    在默认情况下,OpenReports可能不完全支持中文显示,这可能会导致中文字符在报告中出现乱码或者无法正确显示的问题。本解决方案将详细介绍如何实现OpenReports对中文的全面支持。 1. **环境配置** 在使用...

    乱码问题解决 完全解决MYSQL数据库的乱码问题.pdf

    本文主要针对MySQL数据库的乱码问题提供详尽的解决方案,包括Web应用中的编码设置、数据库编码、开发工具的配置以及数据表中文字段的处理。 首先,Web应用中的中文问题涉及到JSP、HTML和Servlet的编码设置。在JSP...

    页面乱码解决4种方案

    **解决方案**:为了确保JSP页面能够正确地显示中文,可以在页面的第一行加入以下代码,声明该页面使用的字符集编码: ```jsp ;charset=gb2312" %&gt; ``` 这里的`gb2312`是指定了中文字符集的编码方式。完整的示例...

    GBK编码下jQuery_Ajax中文乱码解决方案

    在Web开发过程中,使用Ajax技术与服务器端交互数据时经常会遇到字符集编码的问题,尤其是在使用GBK编码的环境中,通过jQuery发起的Ajax请求往往会导致中文乱码的情况出现。这不仅影响用户体验,也给开发工作带来了...

    j s p乱码解决方案

    本文将详细解析JSP中可能出现的四种乱码情况及其解决方案。 一、JSP页面显示乱码 当JSP页面中的中文无法正常显示时,通常是因为服务器和浏览器之间的编码不一致。服务器可能使用了某种编码(如ISO-8859-1),而...

    iis支持路径中的中文

    在IT领域,尤其是在Web服务器管理与配置中,处理非英文字符集,特别是中文路径的支持,是许多管理员和技术人员经常面临的挑战。本文将深入探讨“iis支持路径中的中文”这一主题,包括理解IIS(Internet Information ...

    firebug和web_developer

    1. **信息查看**:提供有关页面的详细信息,如DOCTYPE、字符集、颜色方案等。 2. **CSS工具**:显示页面应用的所有CSS规则,可以禁用或启用特定样式。 3. **HTML工具**:查看源代码、清除格式、检查框架、验证HTML等...

    mysql的乱码解决方法.pdf

    在MySQL数据库管理中,乱码问题常常困扰着开发者和管理员,尤其是在版本升级或者跨编码环境交互时。本文将深入探讨MySQL的...在开发过程中,养成良好的编码规范,预先考虑字符集兼容性,可以大大减少乱码问题的发生。

    jspsmartupload,smartupload UTF8 版,解决乱码问题

    在IT行业中,尤其是在Web开发领域,处理文件上传和编码问题是一项常见的任务。"jspsmartupload"和"smartupload UTF8版"是针对Java Web应用的文件上传组件,旨在简化文件上传操作,并解决多语言环境下的字符编码问题...

    WebChart生成漂亮饼图源码

    8. **ChartPie.csproj**:这是项目的解决方案文件,包含了项目的所有引用、文件结构和编译设置。这将帮助开发者在IDE中管理和构建WebChart项目。 9. **licenses.licx**:这个文件记录了项目中使用的第三方库的许可...

    VSTO开发Excel工具箱源码(VB.NET版).zip

    这个压缩包为学习和开发VSTO Excel插件提供了丰富的素材,无论是初学者还是经验丰富的开发者,都能从中获益,了解如何将.NET技术应用于实际的Office解决方案中。通过深入研究这些源代码,你可以掌握如何构建高效、...

    WebLogic Web Development

    - **Tomcat关于UTF-8 JSP文件的BUG**:可能讨论了Tomcat对UTF-8编码JSP文件的处理问题及其解决方案。 - **使用FileUpload组件上传文件**:讲解了如何使用Commons FileUpload或其他库处理HTTP请求中的大文件上传。 ...

    JspSmartUpload自定义编码终版

    总的来说,"JspSmartUpload自定义编码终版"是针对中文乱码问题的一个重要解决方案,它增强了JspSmartUpload组件在处理中文字符集时的兼容性和稳定性。通过理解其工作原理,开发者可以更好地应对各种编码挑战,提升...

    学校网站最初形式与紧急的解决方案.pptx

    本资料详细阐述了学校网站的初始形态以及在面临DDoS攻击和PHP木马攻击时的紧急解决方案,同时也涵盖了PHP代码示例和其他安全措施,以及MySQL和PHP的升级问题。 首先,学校网站最初的形式通常是简单的信息发布平台,...

    pythonchallenge level2官方方法集

    PHP解决方案,展示了PHP语言在Web开发领域解决问题的能力和灵活性。 #### 43. Another PHP Solution 另一种PHP解决方案,再次确认了PHP在处理各种编程任务时的多功能性。 #### 44. COMPLETESOLUTION(IN PERL) ...

Global site tag (gtag.js) - Google Analytics