某些多字节编码可以安全地用于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 "文本长度: ", mb_strlen($string), "\t字符串长度: ", strlen($string), " ... ", $string, "\n";
$newstring = str_replace('l', 'g', $string);
echo "文本长度: ", mb_strlen($newstring), "\t字符串长度: ", strlen($newstring), " ... ", $newstring, "\n";
$newstring = str_replace(';', ':', $string);
echo "文本长度: ", mb_strlen($newstring), "\t字符串长度: ", strlen($newstring), " ... ", $newstring, "\n";
?>
即使“l”和“;”都不出现在文本“x<y”中,str_replace()仍然找到并更改了字节。在一个例子中,它将文本更改为“x>y”,而在另一个例子中,它完全破坏了编码。
我想,这是另一个理由,如果可以的话,使用UTF-8。