PHP 函数 mb_detect_encoding 严格模式
Posted
技术标签:
【中文标题】PHP 函数 mb_detect_encoding 严格模式【英文标题】:PHP function mb_detect_encoding strict mode 【发布时间】:2016-12-31 05:29:03 【问题描述】:函数mb_detect_encoding中有一个严格模式的参数。
在第一条,最受好评的评论中:
<?php
$str = 'áéóú'; // ISO-8859-1
mb_detect_encoding($str, 'UTF-8'); // 'UTF-8'
mb_detect_encoding($str, 'UTF-8', true); // false
这是真的,是的。但是谁能给我一个解释,为什么会这样?
【问题讨论】:
最终该标志被传递给here;但如果我能弄清楚它的作用,我该死的…… FWIW,还有一个理由不使用这个函数,因为检测编码基本上是不可能的。非常有趣的问题。 @deceze 搞笑:整个源码中关于strict
的评论只有/* set strict flag */
@Álvaro 是的,非常有帮助。 谢谢,伙计们…… ಠ_ಠ
【参考方案1】:
此答案中的所有内容均基于我对代码 here 和 here 的阅读。
不是我写的,也不是用调试器单步调试的,这只是我的解释。
似乎意图是为了严格模式检查整个字符串是否对编码有效,而非严格模式将允许可能的子序列是有效字符串的一部分。 例如,如果字符串以多字节字符的第一个字节结尾,则它在严格模式下不匹配,但在非严格模式下仍符合 UTF-8 条件模式。
但是似乎有一个错误*,在非严格模式下,在某些情况下只检查字符串的第一个字节。
示例:
字节 0xf8
不允许在 UTF-8 中的任何地方使用。当放置在字符串 mb_detect_encoding()
的开头时,无论使用哪种模式,它都会正确返回 false。
$str = "\xf8foo";
var_dump(
mb_detect_encoding($str, 'UTF-8'), // bool(false)
mb_detect_encoding($str, 'UTF-8', true) // bool(false)
);
但只要前导字节可能出现在 UTF-8 序列中的任何位置,非严格模式就会返回 UTF-8。
$str = "foo\xf8";
var_dump(
mb_detect_encoding($str, 'UTF-8'), // string(5) "UTF-8"
mb_detect_encoding($str, 'UTF-8', true) // bool(false)
);
因此,虽然您的 ISO-8859-1 字符串 'áéóú'
不是有效的 UTF-8,但第一个字节 "\xe1"
可能出现在 UTF-8 中,mb_detect_encoding()
会错误地返回该字符串。
*我已经在https://bugs.php.net/bug.php?id=72933打开了一份报告
【讨论】:
【参考方案2】:áéóú
在 ISO-8859-1 中编码为:
e1 e9 f3 fa
如果您将其误解为 UTF-8,您只会得到四个无效的字节序列。多字节扩展基本上是为了忽略错误而设计的。例如,mb_convert_encoding()
会将这些序列替换为 question marks 或您使用 mb_substitute_character()
设置的任何内容。
我有根据的猜测是,严格的编码决定了应该如何处理无效的字节序列:
false
表示删除它们
true
表示保留它们
如果您忽略这些无效序列,您显然会丢弃非常有价值的信息,并且您只能在非常有限的情况下获得合理的结果,例如
$str = chr(81);
var_dump( mb_detect_encoding($str, ['ISO-8859-1', 'Windows-1252']) );
var_dump( mb_detect_encoding($str, ['Windows-1252', 'ISO-8859-1']) );
总而言之,mb_detect_encoding()
通常没有你想象的那么有用,而且使用默认参数完全是废话。
【讨论】:
笑还是哭,这是个问题。【参考方案3】:因为$str
不是实际的UTF-8
,而是ISO-8859-1
。因为当不严格比较时,UTF-8
可能会被视为与 ISO-8859-1
相同,但是当使用严格模式时,只有实际的 UTF-8
适合 UTF-8
比较(explained here)
【讨论】:
这些特定字符在 UTF-8 和 8859 中看起来非常不同。它们肯定不相同,不能“被同等对待”。这仅适用于前 128 个字符 (ASCII),它们不属于这些字符。该字符串在 UTF-8 中是完全无效的,句号。以上是关于PHP 函数 mb_detect_encoding 严格模式的主要内容,如果未能解决你的问题,请参考以下文章
致命错误:在 Windows 中调用未定义的函数 mb_detect_encoding()
致命错误:调用未定义的函数 mb_detect_encoding()
致命错误:调用未定义函数 mb_detect_encoding()