编码检查 UTF-8 浏览器编码

编码问题一直是做网站开发的工程师们很头疼的事,如果你希望自己的网站能够被更多不同语言环境的人浏览和使用,那就一定要解决好编码的问题。

我的经验是,从HTML页面的编码,到PHP程序文件的编码,到数据库的设计以及与PHP之间连接的编码,全部使用UTF-8,这样就能保证你的页面不会出现乱码。

不要总是觉得,你的网站是给中国人用的,不给其他国家的人使用。如果你的中国用户希望保存一些日文、韩文等亚洲文字, 你也没有理由拒绝吧?

还是在一开始就解决好编码的问题为好,做网站,免不了这一步,今天不做,以后迟早要还的。

如果你认为我说的毫无道理,那我给大家引用一篇W3C组织的官方说明吧:

http://www.w3.org/International/questions/qa-forms-utf-8.en.php

注意回答部分的第一句:The best way to deal with encoding issues in (X)HTML forms is to serve all your pages in UTF-8.

用UTF-8吧,肯定没错的,你可以避免很多很多问题。

不过,就算页面使用了UTF-8,也还是会遇到一个问题:

浏览器接收编码的转换问题。

就这个问题的说明,我做了一个测试页面,可以在我的Google SVN下载:

http://leakon.googlecode.com/svn/trunk/leakon/php/detect_utf8/

在浏览器里打开test.php页面即可。

这个页面是UTF-8编码的,如果你不是用SVN软件CheckOut而是直接复制的源码,请记得要把test.php这个文件保存成UTF-8格式。

这个页面有一个Form表单,你可以在输入框内输入中文,然后看地址栏里word字段的值,一个汉字对应3个%,因为UTF-8是变长编码的,针对不同的文字,%的数量是1-4个。

如果你熟悉GBK编码的页面,应该注意到每个汉字对应2个%,因为汉字都是双字节编码的。

这个时候,如果你足够细心,应该可以发现一个冲突的问题。

如果,我在浏览器的地址栏的word字段后面直接输入汉字,得到的是什么结果呢?给大家一个提示,这里最好使用Firefox浏览器,如果你在地址栏输入中文,Firefox会按照GBK的编码方式,按双字节编码,也就是一个汉字对应2个%。

可是你的页面默认是接收UTF-8编码的字符的,给你一个GBK编码,你会解析成乱码。

很多网站存在这个问题,包括Google和Yahoo。 他们只对各自的中文网站就解决了这个问题,英文的和日文的都没有处理。下面我们逐一测试一下:

我们给一个测试用例,中文:百度;GBK:%B0%D9%B6%C8;UTF-8:%E7%99%BE%E5%BA%A6。

看到了吧,GBK是4个%,UTF-8是6个%。

  1. http://www.google.cn/search?hl=zh-CN&q=%E7%99%BE%E5%BA%A6&btnG=Google+%E6%90%9C%E7%B4%A2&meta=
  2. http://www.google.cn/search?hl=zh-CN&q=%B0%D9%B6%C8&btnG=Google+%E6%90%9C%E7%B4%A2&meta=
  3. http://yahoo.cn/s?p=%E7%99%BE%E5%BA%A6&v=web
  4. http://yahoo.cn/s?p=%B0%D9%B6%C8&v=web
  5. http://www.google.com/search?hl=en&q=%E7%99%BE%E5%BA%A6&btnG=Google+Search
  6. http://www.google.com/search?hl=en&q=%B0%D9%B6%C8&btnG=Google+Search
  7. http://search.yahoo.com/search?p=%E7%99%BE%E5%BA%A6&fr=yfp-t-501&toggle=1&cop=mss&ei=UTF-8&vc=&fp_ip=CN
  8. http://search.yahoo.com/search?p=%B0%D9%B6%C8&fr=yfp-t-501&toggle=1&cop=mss&ei=UTF-8&vc=&fp_ip=CN
  9. http://www.google.co.jp/search?hl=ja&newwindow=1&q=%E7%99%BE%E5%BA%A6&btnG=%E6%A4%9C%E7%B4%A2&lr=
  10. http://www.google.co.jp/search?hl=ja&newwindow=1&q=%B0%D9%B6%C8&btnG=%E6%A4%9C%E7%B4%A2&lr=
  11. http://search.yahoo.co.jp/search?p=%E7%99%BE%E5%BA%A6&ei=UTF-8&fr=sfp_as&x=wrt
  12. http://search.yahoo.co.jp/search?ei=UTF-8&fr=sfp_as&p=%B0%D9%B6%C8&meta=vc%3D

以上是对Google和Yahoo两大搜索引擎的中文、英文、日文网站进行UTF-8、GBK编码的访问。

可以看到,2家公司只对中文网站做了编码检查,发现不是UTF-8就对关键词进行编码转换,得到了正确的结果,英文和日文都没有处理,给GBK编码时得到的是乱码。

他们就忽略了英文和日文用户搜索中文的需求。

其实,这个问题不是不可以解决的,中文网站都做到了,其他语言的怎么就不行呢?

这个不讨论了,还是说说怎么检查UTF-8编码吧。

其实就是一段正则表达式:

$regex = ‘/^(‘
. ‘[\x09\x0A\x0D\x20-\x7E]|’ # ASCII
. ‘[\xC2-\xDF][\x80-\xBF]|’ # non-overlong 2-byte
. ‘\xE0[\xA0-\xBF][\x80-\xBF]|’ # excluding overlongs
. ‘[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|’ # straight 3-byte
. ‘\xED[\x80-\x9F][\x80-\xBF]|’ # excluding surrogates
. ‘\xF0[\x90-\xBF][\x80-\xBF]{2}|’ # planes 1-3
. ‘[\xF1-\xF3][\x80-\xBF]{3}|’ # planes 4-15
. ‘\xF4[\x80-\x8F][\x80-\xBF]{2}’ # plane 16
. ‘)*\z/x’;

大家从SVN里可以下载源码。

我封装了一个类,DetectUT8,用于检测和转换编码。

过程是这样的:如果检查到不是UTF-8编码,就进行GBK -> UTF-8的转换。因为在地址栏输入的非ASCII字符都会按照GBK编码。

转换函数会检查系统是否启用了 mbstring 函数库,如果没有,则改用 iconv 转换。

这里要注意一点,不要把UTF-8写成utf8,也不要写成其他格式,iconv 的检查比较严格。

如果内置了 mbstring 函数,还是用 mb_detect_encoding 比较保险,但经测试表明,用上面这段正则,编码检测的成功率和 mb_detect_encoding 没有差别。

还要重申一个问题,编码检测的可靠性不是 100%,但应用这种方法已经极大地改善了用户体验,建议大家都采用这种方式。

Leave a Reply

Your email address will not be published.

*