PHP 检测文件编码的不完美解决方案

因为某些原因现在需要批量检测文件编码,看看是不是有非 UTF-8 文件混在其中
我当然是首选了我最熟悉的 PHP,感觉应该很简单

google 搜索 php detect encoding,第一个就是 PHP 官方文档 mb_detect_encoding – Manual – PHP
于是按照文档有样学样,拿个 UTF-8 文件测试一下

echo mb_detect_encoding( file_get_contents('./utf8.txt') );

当我满心以为会显示 UTF-8 的时候,看到的却是 ASCII

几经核实、尝试,发现即便我传个 'test' 进去都会返回 ASCII。只有字符串中包含汉字等非 ASCII 字符时才会返回 UTF-8。围绕这个函数搜索了一下,也看到不少说这玩意儿不靠谱的言论。不能说它错,但返回值确实不符合直觉

继续找方案,甚至还发现了用 BOM 来判断是否 UTF-8 的操作,这个更不靠谱😂
除此之外见得最多的主流(抄来抄去)解决方案是

 function detect_encoding($file) {
     $list = array('GBK', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'ISO-8859-1');
     $str = file_get_contents($file);
     foreach ($list as $item) {
         $tmp = mb_convert_encoding($str, $item, $item);
         if (md5($tmp) == md5($str)) {
             return $item;
         }
     }
     return null;
 }

通过对比转换前后的字符串是否相等来判断编码,也确实是个办法
不过对于我现在只需要判断是否 UTF-8 的需求来说没这个必要

我又把目光放回到 mb_detect_encoding,注意到它的第二个参数 encoding_list

当被测字符串的编码不在这个参数之中时函数返回 false

这个参数的默认值为 mb_detect_order() ,经测试该函数的返回值为 ['ASCII', 'UTF-8']
噢,我好像破案了 —— 当文件同时满足多种条件时,函数只返回第一个编码名称

因此只要将 UTF-8 放到最前面,或者只提供 UTF-8 即可

8 条评论

昵称
  1. 谷歌外链

    可以,Windos系统倒无所谓,遇到linux,有时直接用txt打开,很容易出问题,这个倒是可以检查下