2016-08-24 98 views
6

在函数mb_detect_encoding中有严格模式的参数。PHP函数mb_detect_encoding严格模式

在第一个,最upvoted评论:

<?php 
$str = 'áéóú'; // ISO-8859-1 
mb_detect_encoding($str, 'UTF-8'); // 'UTF-8' 
mb_detect_encoding($str, 'UTF-8', true); // false 

这是真实的,是的。但有谁能给我一个解释,为什么?

+1

最终该标志被穿过,以[这里](https://github.com/php/php-src/blob/打开这个报告c72282a13b12b7e572469eba7a7ce593d900a8a2/EXT/MBSTRING/libmbfl/mbfl/mbfilter.c#L718);但如果我能弄清楚它的功能,我会受到诅咒...... – deceze

+0

FWIW,*另一个原因是从来没有使用过这个功能,因为*检测*编码从根本上说是不可能的。非常有趣的问题。 – deceze

+0

@deceze滑稽:关于整个源代码中'strict'的唯一评论是'/ * set strict flag * /' –

回答

4

本答案中的所有内容都基于我对代码herehere的阅读。

我没有写它,我没有用调试器来完成它,这只是我的解释而已。


看来,意图是严格模式,并检查字符串作为一个整体是有效的编码,而非严格的模式将允许子序列能成为其中的一部分有效的字符串。例如,如果字符串以多字节字符的第一个字节结尾,则它在严格模式下不会匹配,但在非严格模式下仍可以使用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

因为$str不是实际的UTF-8,而是ISO-8859-1。由于当不严格比较,UTF-8可以被处理相同ISO-8859-1,但使用严格模式时仅实际UTF-8适合用于UTF-8比较(explained here

+1

这些特定的字符在UTF-8和8859中看起来非常不同。它们肯定不是“相同”,不能被“对待相同”。这仅适用于前128个字符(ASCII),这些不属于这些字符。该字符串在UTF-8期间明显无效。 – deceze

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()是一般不像你的东西是有用的,它是使用默认参数总废话。

+0

不管是笑还是哭,这就是问题所在。 – deceze