小马曾经有讲过PHP函数mb_detect_encoding误判带来的坑,今天再来讲讲这个函数的惊天秘密。你准备好了吗?
前景回顾
我们回顾一下之前的误判场景。逻辑代码是这样的:$encode = mb_detect_encoding($name, array('ASCII','UTF-8','GB2312', 'GBK', 'BIG5'));$name = mb_convert_encoding($name, 'UTF-8', $encode);
这段代码检测字符串的编码,然后得到字符串编码,并统一转为utf-8。嗯,一切似乎很合理。但是小马当时得到了一个非必现的BUG反馈,有些字符编码格式有问题导致业务逻辑失败呢。后来经过排查是mb_detect_encoding的误判问题。通过更换参数数组顺序得到解决。调整之后的代码:$encode = mb_detect_encoding($name, array('ASCII','GB2312', 'GBK', 'BIG5','UTF-8'));嗯,似乎案子就这样破了。
这是当时的卷宗
新的惊天秘密
然而,这真的是想多了,一个猝不及防的问题又悄然出现了。什么?案子还是没破?难道是案中有案,另有玄机。没错,你猜对了。接下来我们来看看两个案发现场。
以下是想实现一个支持中文汉字字母数字的正则校验,因为正则表达式是utf8的,所以我们同样先判断字符编码处理,然后统一转为utf8,然后使用正则进行校验。看起来似乎也很完美。
此时带着甜美的味道,我们来看下面的代码。上面未转码的正则校验正确,一旦转码,正则校验就不是我们预期的结果了。显然场面已经失控。
再来看下面这个场景,显然连转换编码都没达到预期的utf8,更不要说过正则了。请注意,代码是一样的,只是传参的字符串不一样而已。
很显然这个不是我们想要的
不得不说的是,有些函数转码utf8正常,而且正则校验也正常。
哈哈,大家来找茬,通过上面的两个例子,细心的不细心的你都能很快发现,尽管我们使用了调整正确顺序后的函数,但是我们可以看到,下面输出的结果是不一样的。这就引发思考了。说明这个编码检测函数还是不靠谱。PHP的汉字编码处理真是个头疼的问题。不过这个坑一定要特别小心!
怎么解决呢?小马暂时想到的就是:
先判断编码检测完转换utf8是否成功,如果成功,做相对应编码的正则校验(比较繁琐);
不通过正则校验,直接交给业务校验或者查询匹配来处理(依赖DB需酌情考虑);
如果业务允许,就先测试这个字符串校验是否可以正常,然后再交由前端业务使用(依赖业务);
那么对于PHP该怎么处理对于汉字字母数字的校验呢?正确的打开方式是什么呢?您有什么高见呢?欢迎讨论指点。