ajax+php应用的乱码问题分析与解决

来源:互联网 发布:如何安装proteus软件 编辑:程序博客网 时间:2024/06/15 05:08
出处:www.phpchina.com 作者:jidixuelang 时间:2007年3月2日 本站原创,转帖请注明出处

下期预告:ajax+php实现title效果全面解析


相信做ajax+php应用的朋友都遇到过乱码的问题

现在,你们是不是都有了自己的一套解决方案呢?

我原来推荐朋友做AJAX应用时,使用全UTF-8编码.其实是在逃避问题

而且大家应该会注意到,很多ajax应用前台HTML并不是UTF-8的

鉴于很多初学者,仍然为此困惑.我这里抛砖引玉

洋洋洒洒写了一大堆,别嫌我罗嗦  

我在网上写东西一般是想到什么写什么,不咋检查滴.出现什么逻辑错误,或者影响理解的错别字,请指出!谢谢

注意红色的和加粗的部分


明确问题:

很多朋友出现乱码后,就在论坛发帖,或网上搜寻相关文章 .

然后,很快就认识了 header("content-type:text/html; charset=utf-8"),iconv('gbk', 'utf-8', " ...."),mysql_query(set names xxx)

以及一个什么php实现的unescape函数等等

甚至连为什么产生乱码都没去想,问题有时候还真被解决了                       [这就是互联网的神奇之处]

其实,根本问题很容易理解,就是存储方式和读取方式不一致

你存储的是一段utf-8编码的文字,却告诉浏览器用gb2312的方式去解析.问题自然就来了!

如下面这段代码,用记事本保存为html文件,IE打开是没有任何问题的!如果你把第四行的gb2312改为utf-8那问题自然就来了

因为记事本默认的是用ANSI标准保存,而gb2312是其中的一种!对于简体中文的操作系统,我们存储的是一段gb2312数据!如果你骗浏览器这

是一段utf-8的数据,那这个忠实的仆人自然就会犯错误了![gb2312改成utf-8(请在记事本中修改)后,标题和内容成乱码了]

[Copy to clipboard] [ - ]
CODE:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
</head>

<body>
<p>无标题文档</p>
</body>
</html>

整个ajax+php应用中,数据要转手两次 存在于三个层次中  分别是前台html 后台php 以及数据库

下面将按一个读取的过程,依次分析两次转手的过程

数据库<->php过程分析

mysql编码问题,应该是我们论坛的朋友最熟悉的,就不多说了!

而且没有什么可说的,你只要能确定你当前数据库中的数据不是乱码就行了

这里,提一下 mysql_query("SET NAMES '编码格式如(utf8)'")

我找了一段网上关于set names 的说明:

[复制PHP代码] [ - ]
PHP代码如下:
SET NAMES显示客户端发送的SQL语句中使用什么字符集。因此,SET NAMES 'cp1251'语句告诉服务器“将来从这个客户端传来的信息采用字符集cp1251”。它还为服务器发送回客户端的结果指定了字符集。(例如,如果你使用一个SELECT语句,它表示列值使用了什么字符集。)
SET NAMES 
'x'语句与这三个语句等价:

mysql
SET character_set_client x;
mysqlSET character_set_results x;
mysqlSET character_set_connection x;
将x设置为character_set_connection也就设置了collation_connection是x的默认校对规则。


感觉它说得不够俗,咱来通俗点:

其实,他的作用就是告诉数据库,"我传给你的将是一段X编码的数据,请按X编码理解","你传给我的数据也必须翻译成X编码的,我只懂X编码"


注意上面的两个引号部分,这说明他分别设定了读取和写入两个层次

所以在PHP读取MYSQL中的数据的时候,只要你的数据库中的数据本身不是乱码!你执行mysql_query("SET NAMES '编码格式如(utf8)'")后,

读取出来的数据,都将是UTF-8格式的正常数据!同理,只要你执行sql 语句里的数据都是utf-8格式的,存如数据库后都不会是乱码.


下面来做个实验:

[复制PHP代码] [ - ]
PHP代码如下:

<?php
/*
                ......省略......

        $conn = mysql_connect($hostname,$username,$password);
        mysql_query("SET NAMES 'UTF8'"); 

                ......省略......
        
        类似以上方式随便在数据库中读取一段数据,他都将保存成一段utf-8格式编码的数据
        
        这里为了你测试方便,我用iconv函数模拟了一下     [本页左上方,可以查看iconv的详细内容]
        
        如楼上所说,用记事本保存这段代码,所有数据格式将是gb2312的  因此下面的变量$test未经过iconv之前,将是gb2312格式的数据!
        
        经过iconv后 变成一段utf-8格式的数据
        
        而输出的HTML 如果你不手动设置一下header  各个浏览器的处理方式是不一样   有兴趣的可以自行测试一下
        
        所以为了统一一下,这里设置一下header
        
        执行结果第一行将是乱玛,第二行是正常的!    为什么 应该还是很容易理解的吧!
        
*/

header("content-type:text/html; charset=utf-8"); 

$test "大家好!";                   

echo 
$test."<br />";

$test iconv('gbk''utf-8'$test);             //我假设这个将是你从数据库中读出来的正常的UTF-8数据

echo $test;


?>


请将header("content-type:text/html; charset=utf-8"); 改为header("content-type:text/html; charset=gb2312"); 再测试一下

这从侧面说明了header的作用  他并未转换任何数据  而仅仅通知一下浏览器应该用什么方式理解数据  这是浏览器对http协议的实现,我们不用管它

ps:

对PHP应用来说,乱码问题到此已经结束.但对ajax+php应用来说,还没有,还有一个php经ajax处理-到HTML页面的过程

后面将分别对IE浏览器和非IE浏览器 做进一步讲解


这部分写完了,还没跟大家说在PHP部分究竟应该怎么做! 为什么?晚上写完了你就知道了!

这里理解一下,set names iconv 和header先

HTML<->PHP过程分析
接着中午的讲.

本来说,按IE和非IE浏览器分别讲一下,php与前台通过ajax交互这一过程的.细想了下,发现没这必要! [文中的非IE浏览器指FF和OPERA]

这两类浏览器对ajax的实现区别很大,但这个具体的实现对我门程序员来说是透明的 我们没有必要去深究

我们只要知道具体应用的时候,有哪些需要注意的地方就行了

IE是通过内置的ActiveXObject来实现ajax的,而非IE浏览器是用XMLHttpRequest类来实现的.一些细微的差别因此而来!

以下是我自己总结的几条规律:[初看的时候,你可能不理解,下面会一一解释]

1.AJAX读取的时候,对IE浏览器来说,只要php端传给他的是UTF-8的数据,他就能正常显示.

2.AJAX读取的时候,对非IE浏览器来说.只要数据在php本身能正常显示,他被传到浏览器中也能正常显示.

3.AJAX写入的时候,IE与非IE浏览器是一样的.不管你在浏览器端是什么编码格式的数据,被传到PHP中后,都将变成正常的UTF-8格式数据!

四楼有张图,可以参照一下



针对IE:

这里先说一下,传给他是UTF-8数据是什么意思.请看下面这两段代码!
[这里默认为你的编辑器用gb2312格式保存文件!这点很重要!若不是,结果将不同!但不代表原理有误!]

[复制PHP代码] [ - ]
PHP代码如下:

<?php

header
("content-type:text/html; charset=gb2312"); 

$test "大家好!";                   

$test iconv('gbk''utf-8'$test);             

echo 
$test;


?> 




[复制PHP代码] [ - ]
PHP代码如下:

<?php

header
("content-type:text/html; charset=utf-8"); 

$test "大家好!";                   

$test iconv('gbk''utf-8'$test);             
echo 
$test;


?> 


虽然以上两段代码执行后,一段乱码,一段正常!

但不可否认,经过iconv处理后,他门输出的都是UTF-8编码的数据!

如前面所说:"AJAX读取的时候,对IE浏览器来说,只要php端传给他的是UTF-8的数据,他就能正常显示."

因此,这两段代码在IE下,用AJAX读取过去,都将是正常显示的!


测试HTML页面 [请将上面的两段PHP依次保存为test.php.与该HTML文件放同一目录下做测试]

[Copy to clipboard] [ - ]
CODE:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
<script type="text/javascript">
function manageres()
{
     var objText    =  this.req.responseText;
         var objChange  =  document.getElementById("result");
     objChange.innerHTML  =  objText;
}
function createrep() {
    if (typeof XMLHttpRequest != "undefined") {
                return new XMLHttpRequest();
        }
    else if (window.ActiveXObject) {
                var Versions = [ "MSXML2.XMLHttp.5.0","MSXML2.XMLHttp.4.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp","Microsoft.XMLHttp"];
                for (var i = 0; i < Versions.length; i++) {
                try {
                var XMLHttp = new ActiveXObject(Versions);
                return XMLHttp;
                }
                catch (e) {}
                }
    }  
}
var net=new Object();
net.ContentLoader=function(){                                                                                                  
        this.req=null;
        this.onload=manageres;
}

net.ContentLoader.prototype={
        loadXMLDoc:function(query){
                this.req=createrep();
                if (this.req){
                var loader=this;
                this.req.open('GET',"test.php?date="+new Date().getTime(),true);
                this.req.onreadystatechange=function(){
                loader.onReadyState.call(loader);
                }
                this.req.send(null);
                }
        },

        onReadyState:function(){
                var req=this.req;
                var ready=req.readyState;
                if (ready==4){
                var httpStatus=req.status;
                if (httpStatus==200 || httpStatus==0){
                this.onload.call(this);
                }
                }
        }
}

var selector = new net.ContentLoader();


</script>
</head>

<body onload="selector.loadXMLDoc();">
<div id="result"></div>
</body>
</html>

IE下测试均正常的.而FF和OPERA下,用第一段PHP测试的话将是乱码!





针对非IE浏览器[FF,OPERA]:


下面再引入第三段PHP

[复制PHP代码] [ - ]
PHP代码如下:

<?php

header
("content-type:text/html; charset=gb2312"); 

$test "大家好!";                   

echo 
$test;


?> 


这段php直接执行是能正常显示的,不会出现乱码!

它和第二段php一起佐证我的第二个结论:

"AJAX读取的时候,对非IE浏览器来说.只要数据在php本身能正常显示,他被传到浏览器中也能正常显示."

所以,你用第二和第三段PHP做为test.php的话 ,会发现test.html页面在ff与opera下均是正常的!而用第三段的话ie下是乱码!


你真的理解了,我总结的这两条了吗? 请思考,5楼留下的那个题目!

至于,第三个结论,请自行证明!因为要证明的话,最好联系数据库做测试最好!我这里就不做了!
最终结论:

我们只要保证三点,就可以使你的AJAX+PHP应用中不出现乱码了!而且是兼容各种浏览器的!

1.在php页面中,使用mysql_query("SET NAMES 'UTF8'");读取数据库中的文件!

2.在文件前面设置header("content-type:text/html; charset=utf-8")

3.php文件中不能出现一个汉字!这些汉字多办是不必要的,或是应该直接保存在js文件中的![初学者喜欢用中文表名的毛病也要注意了.]



至于9楼所说的那种采集程序,没用到数据库.正好可以归为另一类.就要用到iconv了之类的转换函数了


对于这类ajax应用,我们前面得到的最终结论,你只要改动第一条就行了

1.在php页面中,使用iconv('gbk', 'utf-8', $test); iconv('gb2312', 'utf-8', $test)将获取的数据转换成utf-8编码就行了!

[当然,被采集的页面本身是utf-8编码就不需要转换了,但其他两条仍需遵守!]

综上,你的php页面能正常的取到utf-8数据,输出的文件头(header())为utf-8就不会出现乱码!

关键还是理解在各个过程中,编码的变化过程! 以及IE与非IE浏览器的区别!



[请点击查看大图]
[attach]8651[/attach]


[常见问题列表:]
1.Cannot add header information - headers already sent by ...错误!
这是UTF-8头问题!你找一个能显示UTF-8头的编辑器,会看到你的PHP页面开头是"锘?<?php".这是你的编辑器转换页面格式的时候自动添加上去的,少数编辑器可以通过设置禁止.

2.data too long for column  错误
请不要从字面上理解这个错误! 在AJAX应用中,这个错误通常是由于你的SQL语句和数据的编码中有中文且和set names 的格式不一样(如果你没设置set names 那就是和数据库的默认设置不一样),从而出现乱码造成的!
还有一种情况看这个帖子:http://www.phpchina.com/bbs/thread-19695-1-1.html
 
原创粉丝点击