原文: http://hi.baidu.com/cuttinger/blog/item/c8e44623e3c9e4499822edff.html
概述:分析php引擎是如何处理不同编码的php脚本的,并通过构造一个GBK的php脚本,诱发了php引擎处理php脚本时产生错误,证实了前面的分析。
1。背景
php有个看起来很平常的特性,就是php文件中的字符串,打印出来的时候,并不改变字符串的编码。
举例来说,就是php文件中的字符串,如下:
$a = "中国";
echo $a;
如果php文件是utf8编码保存,那么访问这个web页面的时候,打印出来的就是utf8的”中国“二字;而如果该文件是gbk编码保存,那么访问这个web页面的时候,打印出来的就是gbk的”中国“二字。
根据这个简单的现象,可以很容易得到一个结论,那就是php引擎本身不处理字符集的问题,他把文件中所有的字符串都保持原状拷贝到内存空间中。
这很容易理解,我可以接受这种解释。
2。疑问
问题来了,php引擎来处理php脚本的时候,需要分析php脚本的词法结构,这时候php引擎不了解php脚本的编码方式,读取字符串的时候,如果字符串中的某些多字节字符的某一字节,恰好对php引擎分析php脚本产生干扰怎么办?
我们知道,utf8与ascii兼容,其多字节字符中的每一部分都不会落在ascii码的编码范围内。
GB2312也不会,它的双字节字符中,高字节是从A1-F7,低字节是从A1-FE,也不会落在ascii码的编码范围内。
但是!但是GBK并不是这样。GBK的整体编码范围是为0x8140-0xFEFE,不包括低字节是0×7F的组合。高字节范围是0×81-0xFE,低字节范围是0x40-7E和0x80-0xFE。
这就意味着,有部分双字节字符的低字节部分,与ascii码重合。更重要的,40-7E范围内,存在着在php词法解析中有至关重要作用的字符'\',没错,就是0x5C,反斜杠,转义符号。
从理论上讲,如果字符串中含有一个字符,这个字符的低字节恰好是0x5C,php引擎就会把它当作一个转义符号来理解。这样,php处理这个脚本就会产生错误。
我需要找个证据,证明这一点。
3。证据
找个GBK码表,随便找个符合上述条件的中文字符。
关键词 ”gbk 码表“,在百度上搜一下,就能找到一些码表。
某个码表上,有这样的一行
810 1 2 3 4 5 6 7 8 9 A B C D E F
4 丂 丄 丅 丆 丏 丒 丗 丟 丠 両 丣 並 丩 丮 丯 丱
5 丳 丵 丷 丼 乀 乁 乂 乄 乆 乊 乑 乕 乗 乚 乛 乢
6 乣 乤 乥 乧 乨 乪 乫 乬 乭 乮 乯 乲 乴 乵 乶 乷
对表中的任意一个汉字,比如丏,81指得是这个字符的高位字节,44指的是这个字符的低位字节,其编码就是8144。
很容易的,我们可以发现,815C就是我们需要的那个字符,就是“乗”。
构造如下php脚本,注意文件的保存编码为gbk。
$a = "测试乗nabc";
echo $a;
访问这个页面,察看源码,看到的结果如下:
看到这里我就明白了——php引擎分析到这儿的时候,它是这样理解的
B2 E2 CA D4 81 5C 6E 61 62 63
其中,5c和6E联合起来,成了 \n,回车符号,而81,孤零零的打印出来——这是一个非法的gbk字符,所以在页面上显示了一个黑黑的问号。
看到这里,一切已经水落石出了,前面的猜测,完全正确。
4。影响
问题看起来很严重,不过大可不必太担心。因为我们常用的汉字,都是GB2312范围内,他们都没有这个问题。我们的php脚本中,一般不会直接包含那些在gb2312之外的字符,这个问题,在这个层面上影响不大。
不过,如果需要处理一些来自网友提交的数据的时候,比如,对网友提交的内容中的特定字符,比如反斜杠进行替换的时候,遇到这个问题的可能性就很大了。处理的方法也比较简单,就是使用多字节的字符串处理函数 mb_string——会损失一些效率。