9

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

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

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

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

在较旧的服务器和 localhost (预期)中提供此功能:

'ñu'

但是在服务器中,我们遇到了问题(PHP 版本 => 5.3.6),它会\0在遇到“不常见”字符时添加空字符:è、á、ç、...

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

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


更多信息:

  • PHP version 5.3.6.
  • setlocale()没有解决任何问题。
  • default_charsetUTF-8php.ini. _
  • mbstring.internal_encoding设置为UTF-8in 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()文档(查看@hakre的答案)。

4

5 回答 5

6

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

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

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

返回

?u

这是有道理的,ñ

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

您配置了一些语言环境,使 PHP 更改\xC3为其他内容,破坏 UTF-8 字节序列并使您的 shell 显示替换字符Wikipedia

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

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

还有更多设置可以发挥作用,我开始在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_strtoupperDocsmb_convert_caseDocs

于 2012-04-14T10:17:57.807 回答
0

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

于 2012-04-24T05:24:43.207 回答
0

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

可能会有所帮助

于 2012-04-13T20:31:51.373 回答
0

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

于 2012-04-18T05:04:14.337 回答
0

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

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

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

于 2012-04-11T13:12:12.737 回答