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

eil*_*rra 9 php localization utf-8 joyent

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

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

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

$ php -r "echo var_export('ñu', true);"
Run Code Online (Sandbox Code Playgroud)

在旧服务器和localhost (预期)中给出:

'ñu'
Run Code Online (Sandbox Code Playgroud)

但是在服务器中我们遇到了问题(PHP版本=> 5.3.6),\0每当遇到"不常见"的字符时它会添加空字符:è,á,ç,......你给它命名.

'' . "\0" . '' . "\0" . 'u'
Run Code Online (Sandbox Code Playgroud)

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


更多信息:

  • PHP version 5.3.6.
  • setlocale() 没有解决任何问题.
  • default_charsetUTF-8php.ini.
  • mbstring.internal_encoding被设置为UTF-8php.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=
Run Code Online (Sandbox Code Playgroud)

到目前为止完成的一些测试(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'
Run Code Online (Sandbox Code Playgroud)

不正常:

$ 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'
Run Code Online (Sandbox Code Playgroud)

所以,问题似乎是在var_export()"使用当前的区域设置字符串的功能,但操作逐字节" 的文档(查看@ hakre的答案).

hak*_*kre 6

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

通常PHP内部使用二进制字符串,这意味着像ucfirst字节一样工作的函数只支持你的语言环境支持(如果配置的话).请参阅字符串类型文档的详细信息.

$ php -r "echo ucfirst('ñu');" 
Run Code Online (Sandbox Code Playgroud)

回报

?u
Run Code Online (Sandbox Code Playgroud)

这是有道理ñ

LATIN SMALL LETTER N WITH TILDE (U+00F1)    UTF8: \xC3\xB1
Run Code Online (Sandbox Code Playgroud)

您配置了一些区域设置,使PHP更改\xC3为其他内容,打破UTF-8字节序列并使您的shell显示 替换字符Wikipedia.

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

 $ php -r "echo ucfirst(b\"\\xC3\\xB1u\");"
Run Code Online (Sandbox Code Playgroud)

还有更多的设置可以发挥作用,我开始在准备PHP应用程序与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;
}
Run Code Online (Sandbox Code Playgroud)

查看mb_strtoupper文档mb_convert_case文档.


Dud*_*ist 0

尝试在 php 中强制使用 utf-8:

<? ini_set( 'default_charset', 'UTF-8' ); ?>
Run Code Online (Sandbox Code Playgroud)

在任何页面/模板的最顶部(第一行代码)。它主要帮助我处理我的特殊角色。不确定它是否也能帮助你,尝试一下。