htmlentities/htmlspecialchars在php5.2.5会检测多字节的字符的完整性
本文按署名·非商业用途·保持一致授权作者:
,发表于2007年12月08日18时35分
在PHP5.2.5里有个很吐血的更新。
Fixed htmlentities/htmlspecialchars not to accept partial multibyte sequences.
也就是htmlentities/htmlspecialchars不再允许有不完整的多字节字符输入。(根据我的测试,如果有这个情况发生,那么函数就返回一个长度为0的字符串,而不是摈弃那些不完整的字符)
我拿utf-8来说吧。为了兼容旧的ansi编码文档,utf-8的编码格式是分范围来编码的。下面是utf-8的编码规则,第一个字段是unicode范围(十六进制),第二个字段其对应的编码格式(二进制)。关于utf-8和unicode的详细说明请看我的wiki:iso10646。(不过这个wiki准备要迁移了)
0000-007F | 0xxxxxxx 0080-07FF | 110xxxxx 10xxxxxx 0800-FFFF | 1110xxxx 10xxxxxx 10xxxxxx 10000-10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
在调用htmlentities的时候,函数会对输入的字符串进行检查。当发现一个以0,110,1110或者11110开头的字节(二进制),程序会认为这是一个utf-8字符的开始。假设这里检测到110开头,则下一个字节必须为10开头。否则110开头的这个字节将会被判定为一个不完整的utf-8字节。
再来看php的代码:
$text='a'.chr(220).chr(127).'b'; $text=htmlentities($text,ENT_COMPAT,'UTF-8'); var_dump($text);
这段代码,在php5.2.3是返回一个4字节的字符串。而在php5.2.5,会返回一个长度为0的字符串。如果把代码的127改为129,那么在php5.2.5下就会返回正确的结果——4个字节的字符串。
至于为什么,大家可以结合我上面所说自己想想吧。
为什么我在开头会说吐血呢。因为…..这个更新会导致一些php程序返回错误的结果。例如:Text_Wiki在对字符串进行parse和render的时候,使用了一个chr(255).chr(4x).chr(255)的字符串作为delimiter。它在进行Xhtml格式的输出的时候,会用htmlentities进行过滤,如果指定了编码为UTF-8,那么这个delimiter的每个字节都会被认为是一个非法的utf-8字符串(从上面的utf-8表可以看出,编码为十进制的255的字节不可能成为任何一个utf-8字符串的一部分),导致最后的输出会是一个空字符串。
ps:这个更新是php爸爸做的修改
ps2:最近有一个更吐血的事情。就是我的苹果机器的硬盘坏了。很多脚本,wiki,各种软件的配置,还有一个写了三周的周末项目没有备份出来。在尝试了几个修复和备份方法之后,终于放弃了,打算送修。不过今天和几个同事去打球,太累了,明天再送修了。吐血了。

2007-12-10 14:14:40
老乡,对postgresql有研究吗?
遇到个棘手的问题,
ERROR: could not read block 17 of relation 1663/16385/16489: Input/output error
用磁盘检测
fsck -y -C -V
检查数据所在的分区,没有错误。但是在其他分区有错误。
google了半天,找不到解决办法。
可以的话,加我msn: lucas_fmg@hotmail.com;
2007-12-10 23:01:40
to lucas:
抱歉了,我没使用过postgresql
2007-12-11 22:24:59
呵呵,没关系,我也是病急乱投医。
谢谢你了。
2009-10-19 14:44:09
也学了不少的东西,呵呵
2010-01-12 15:15:23
支持一下。。。。
2010-01-12 15:16:13
好东西,顶!!!!