一些多字节编码可以安全地用于 str_replace() 等,而另一些则不行。仅仅确保所有涉及的字符串使用相同的编码是不够的:显然它们必须使用相同的编码,但这还不够。它必须是正确的编码类型。
UTF-8 是安全的编码之一,因为它被设计为明确地说明每个编码字符在构成编码文本的字节串中的起始位置和结束位置。有些编码是不安全的:文本中一个字符的最后一个字节后跟下一个字符的第一个字节,可能组合起来形成一个有效的字符。str_replace() 不了解“字符”、“字符编码”或“编码文本”。它只知道字节串。对于 str_replace() 来说,两个相邻的字符具有两个字节的编码,就像一个四字节序列,它不会知道不应该尝试匹配中间两个字节。
虽然可以找到 str_replace() 篡改文本的实际示例,但可以使用 HTML-ENTITIES 编码来说明这一点。它不是安全的编码之一。传递到 str_replace() 的所有字符串都是有效的 HTML-ENTITIES 编码文本,因此“所有输入都使用相同的编码”规则得到满足。
文本是“x<y”。它由字节串 [78 26 6c 74 3b 79] 表示。请注意,文本有三个字符,但字符串有六个字节。
<?php
$string = 'x<y';
mb_internal_encoding('HTML-ENTITIES');
echo "Text length: ", mb_strlen($string), "\tString length: ", strlen($string), " ... ", $string, "\n";
$newstring = str_replace('l', 'g', $string);
echo "Text length: ", mb_strlen($newstring), "\tString length: ", strlen($newstring), " ... ", $newstring, "\n";
$newstring = str_replace(';', ':', $string);
echo "Text length: ", mb_strlen($newstring), "\tString length: ", strlen($newstring), " ... ", $newstring, "\n";
?>
即使“x<y”文本中没有出现 'l' 或 ';',str_replace() 仍然找到并更改了字节。在一个情况下,它将文本更改为“x>y”,而在另一个情况下,它完全破坏了编码。
我想,这是另一个使用 UTF-8 的理由。