PHP mb_detect_encoding 不再可靠地检测 UTF-8

PHP mb_detect_encoding no longer reliably detects UTF-8

提问人:Arno Schäfer 提问时间:10/3/2023 最后编辑:Arno Schäfer 更新时间:10/3/2023 访问量:78

问:

我最近从 PHP 7 切换到 PHP 8.2.7,并注意到mb_detect_encoding似乎不再可靠地工作。我正在做以下事情:

mb_detect_encoding(file_get_contents('somefile.csv'), 'UTF-8, ISO-8859-1', true);

对于一个特定文件,返回的值为 ISO-8859-1,即使它显然是 UTF-8 编码文件。它甚至有一个 UTF-8 BOM。我知道 PHP 8 中的检测算法发生了变化,但是清除 UTF-8 编码的文件怎么会被误认为是 ISO?我知道大多数 UTF-8 编码的字符串也是有效的 ISO 字符串,但是如果它看不到差异,mb_detect_encoding有什么用呢?顺便说一句。有问题的文件长 1759 字节,大约有 30 个 UTF-8 双字节字符,因此 IMO 这应该足以将其检测为 UTF-8。

我无法上传文件,但这是 .CSV 文件:

Buchungstag;Wertstellung;Umsatzart;Buchungstext;Betrag;Währung;Auftraggeberkonto;Bankleitzahl Auftraggeberkonto;IBAN Auftraggeberkonto
PHP UTF-8 MB字符串

评论

1赞 Álvaro González 10/3/2023
mb_detect_encoding()是一个名不副实的函数,从来没有做过人们想的那样。如果它报告 ISO-8859-1,则仅意味着存在一个字节序列不是有效的 UTF-8。
0赞 Olivier 10/3/2023
如何共享文件以便每个人都可以查看它?
0赞 Chris Haas 10/3/2023
我不能给你一个答案,“如果它看不到差异,mb_detect_encoding有什么好处”,但我可以告诉你,根据这一点,该命令不再被视为权威,而是应用了“启发式”。这意味着文档不再正确,并且存在更新文档的问题和 PR。建议的解决方法是在循环中使用。不理想,但这就是它似乎的地方。mb_check_encoding
0赞 Peter 10/3/2023
没有 UTF-8 BOM 这样的东西。字节顺序以 UTF-8 固定。BOM 仅与 UTF-16 和 UTF-32 相关。在 UTF-8 中,U+FEFF 对零宽度空间进行编码。可能不是这里的意图。
1赞 Chris Haas 10/3/2023
“没有 UTF-8 BOM 这样的东西” - UTF-8 有一个 BOM,但它并不意味着字节的任何顺序。某些系统(尤其是较旧的 Windows)使用它来暗示文本流被明确地解释为 UTF-8。如果您只是说 UTF-8 不需要 BOM,那就不同了。

答:

0赞 Arno Schäfer 10/3/2023 #1

我仍然觉得mb_detect_encoding坏了,但至少我发现文件开头的字节顺序标记 EF BB BF 似乎会将其扔掉。如果它存在并且文件的其余部分太短(<大约 4K),则它似乎被检测为 ISO-8859-1。

一种解决方法是先剥离潜在的 BOM:

$encoding = mb_detect_encoding(preg_replace("/^\xef\xbb\xbf/", '', file_get_contents('somefile.csv')), 'UTF-8, ISO-8859-1', true);

或使用mb_check_encoding:

$encoding = mb_check_encoding(file_get_contents('somefile.csv'), 'UTF-8') ? 'UTF-8' : 'ISO-8859-1';

评论

1赞 Evert 10/3/2023
如果出现 BOM,假设 UTF-8 不是更简单吗?我认为这是一个非常可靠的信号
0赞 Arno Schäfer 10/3/2023
对,当然。有时,最令人讨厌的解决方案只是躲避你。谢谢。