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()

php怎样判断字符串是啥编码

致命错误:调用未定义函数 mb_detect_encoding()

PHPmyadmin 问题 - 致命错误:未捕获错误:调用未定义函数 mb_detect_encoding()

PHPmyadmin问题 - 致命错误:未捕获错误:调用未定义函数mb_detect_encoding()