php中的UTF-8问题:var_export()返回\ 0 null字符,而ucfirst(),strtoupper()等表现得很奇怪

时间:2012-03-16 16:47:34

标签: php utf-8 localization joyent

我们正在处理之前从未发生过的Joyent Solaris服务器中的一个奇怪的错误(不会发生在localhost或其他两个具有相同php配置的Solaris服务器上)。实际上,我不确定我们是否必须查看php或solaris,以及它是否是软件或硬件问题......

我只想发布这个,以防有人指出我们正确的方向。

因此,在处理奇怪的字符时,问题似乎出现在var_export()中。 在CLI中执行此操作,我们在localhost机器和两个服务器中获得预期结果,但不在第三个服务器中获得。所有这些都配置为使用utf-8

$ php -r "echo var_export('ñu', true);"

在较旧的服务器和localhost (预期)

中提供此功能
'ñu'

但是在服务器中我们遇到了( PHP Version => 5.3.6 )的问题,每当遇到“不常见”字符时它会添加\0个空字符:è, á,ç,......你说出来。

'' . "\0" . '' . "\0" . 'u'

关于应该在哪里查看的任何想法?提前谢谢。


更多信息:

  • PHP version 5.3.6
  • setlocale()没有解决任何问题。
  • default_charsetUTF-8中为php.ini
  • mbstring.internal_encoding设置为UTF-8中的php.ini
  • mbstring.func_overload = 0
  • 这在CLI(示例)和Web应用程序(php-fpm + nginx)中都会发生。
  • iconv编码也是UTF-8
  • 所有文件utf-8已编码。

system('locale')返回:

LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_ALL=

到目前为止已完成的一些测试(CLI):

正常行为:

$ php -r "echo bin2hex('ñu');" => 'c3b175'
$ php -r "echo mb_strtoupper('ñu');" => 'ÑU'
$ php -r "echo serialize(\"\\xC3\\xB1\");" => 's:2:"ñ";'
$ php -r "echo bin2hex(addcslashes(b\"\\xC3\\xB1\", \"'\\\\\"));" => 'c3b1'
$ php -r "echo ucfirst('iñu');" => 'Iñu'

不正常:

$ php -r "echo strtoupper('ñu');" => 'U' 
$ php -r "echo ucfirst('ñu');" => '?u' 
$ php -r "echo ucfirst(b\"\\xC3\\xB1u\");" => '?u' 
$ php -r "echo bin2hex(ucfirst('ñu'));" => '00b175'
$ php -r "echo bin2hex(var_export('ñ', 1));" => '2727202e20225c3022202e202727202e20225c3022202e202727'
$ php -r "echo bin2hex(var_export(b\"\\xC3\\xB1\", 1));" => '2727202e20225c3022202e202727202e20225c3022202e202727'

所以问题似乎出现在var_export()"string functions that use the current locale but operate byte-by-byte" Docs中(查看@ hakre的回答)。

5 个答案:

答案 0 :(得分:6)

我建议你验证你遇到问题的PHP二进制文件。检查编译器标志及其使用的库。

通常PHP内部使用二进制字符串,这意味着像ucfirst这样的函数逐字节工作,只支持你的语言环境支持(如果配置的话)。请参阅Details of the String TypeDocs

$ php -r "echo ucfirst('ñu');" 

返回

?u

这是有道理的,ñ

LATIN SMALL LETTER N WITH TILDE (U+00F1)    UTF8: \xC3\xB1

您配置了一些区域设置,使PHP将\xC3更改为其他内容,打破UTF-8字节序列并使shell显示� replacement characterWikipedia

我建议如果你真的想分析这些问题,你应该从hexdumps开始,然后在shell和其他地方显示内容。 知道你可以明确定义二进制字符串b"string"(这是向前兼容性,你已经启用了一些编译标志,并且你正在进行unicode实验吗?),而且你也可以按字面意思写字符串,这里是hex-way for UTF-8:

 $ php -r "echo ucfirst(b\"\\xC3\\xB1u\");"

还有更多可以发挥作用的设置,我开始列出an answer to Preparing PHP application to use with UTF-8中的一些点。


多字节ucfirst变体的示例:

/**
 * multibyte ucfirst
 *
 * @param string $str
 * @param string|null $encoding (optional)
 * @return string
 */
function mb_ucfirst($str, $encoding = NULL)
{
    $first = mb_substr($str, 0, 1, $encoding);
    $rest = mb_substr($str, 1, strlen($str), $encoding);
    return mb_strtoupper($first, $encoding) . $rest;
}

请参阅mb_strtoupperDocs以及mb_convert_caseDocs

答案 1 :(得分:0)

在php中尝试强制utf-8:

<? ini_set( 'default_charset', 'UTF-8' ); ?>

在任何页面/模板的顶部(第一行代码)中。它主要帮助我解决我的特殊角色。不确定它对你有帮助,试试吧。

答案 2 :(得分:0)

可能所有服务器都处于良好状态。在其中一条评论中,您说过只有ucfirst()和var_export()问题。根据这些回复,您可能会看到此SOQ。使用多字节字符串时,大多数php字符串函数将无法正常工作。这就是为什么php有separate set of functions来处理它们的原因。

This可能会有所帮助

答案 3 :(得分:0)

我通常会将utf8_encode('ñu')用于所有法语字符

答案 4 :(得分:0)

phpunit测试正在添加到https://gist.github.com/68f5781a83a8986b9d30 - 我们可以建立一个更好的单元测试套件,以便我们可以找出预期的输出应该是什么?