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

PHP
2994
8
2020-05-21

因为某些原因现在需要批量检测文件编码,看看是不是有非 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 即可

昵称
邮箱
网址
谷歌外链的头像 2021-11-21 21:46

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

Kenvix的头像 2021-02-17 16:29

但是PHP说的也确实没毛病,UTF-8本来就向下兼容ASCII,从二进制角度看也完全相等,把一个纯ASCII文件直接当作UTF-8编码就好了

xiaobeii的头像 2020-05-24 17:30
xiaobeii

我之前用来处理txt文本转excel乱码的时候用的,也都是网上抄的,能用就行- -
function characet($data)
{
if (!empty($data))
{
$fileType = mb_detect_encoding($data, array('UTF-8', 'GBK', 'LATIN1', 'BIG5'));
if ($fileType != 'UTF-8')
{
$data = mb_convert_encoding($data, 'utf-8', $fileType);
}
}
return $data;
}

weapon_zhang的头像 2020-05-24 12:52
weapon_zhang

我在PHP官方文档看到了这么一句话,15年前的
If you need to distinguish between UTF-8 and ISO-8859-1 encoding, list UTF-8 first in your encoding_list:
mb_detect_encoding($string, 'UTF-8, ISO-8859-1');
if you list ISO-8859-1 first, mb_detect_encoding() will always return ISO-8859-1.

weapon_zhang的头像 2020-05-24 12:40
weapon_zhang

另辟蹊径,方法独到,佩服佩服

惶心的头像 2020-05-21 15:27

哈哈哈哈哈哈我以为只有我会这样 - 想用某语言实现某功能:Google 搜索 {lang-name} + {target}

nothing的头像 2020-05-21 17:05
nothing

+1

mokeyjay的头像 2020-05-21 15:33
mokeyjay 博主

这不是基本操作吗😆