php中的UTF-8问题:var_export()返回\0个空字符,而ucfirst()、strtoupper()等行为异常
我们正在处理Joyent Solaris服务器中以前从未发生过的一个奇怪错误(在localhost或其他两个具有相同php配置的Solaris服务器中不会发生)。事实上,我不确定我们是否必须研究php或solaris,以及这是一个软件还是硬件问题 我只是想把这个贴出来,以防有人能给我们指出正确的方向 因此,在处理奇怪字符时,问题似乎出在php中的UTF-8问题:var_export()返回\0个空字符,而ucfirst()、strtoupper()等行为异常,php,utf-8,localization,joyent,Php,Utf 8,Localization,Joyent,我们正在处理Joyent Solaris服务器中以前从未发生过的一个奇怪错误(在localhost或其他两个具有相同php配置的Solaris服务器中不会发生)。事实上,我不确定我们是否必须研究php或solaris,以及这是一个软件还是硬件问题 我只是想把这个贴出来,以防有人能给我们指出正确的方向 因此,在处理奇怪字符时,问题似乎出在var_export()中。 在CLI中执行此操作,我们在本地主机和其中两台服务器上获得了预期的结果,但在第三台服务器上没有。所有这些都配置为使用utf-8 $
var_export()
中。
在CLI中执行此操作,我们在本地主机和其中两台服务器上获得了预期的结果,但在第三台服务器上没有。所有这些都配置为使用utf-8
$ php -r "echo var_export('ñu', true);"
在较旧的服务器和本地主机中提供此功能(预期):
'ñu'
但在服务器中,我们遇到了问题(PHP版本=>5.3.6),每当遇到“不常见”字符时,它就会添加\0
空字符:è,á,ç。。。你说吧
'' . "\0" . '' . "\0" . 'u'
你知道我们应该去哪里吗?提前谢谢
更多信息:
PHP版本5.3.6
无法解决任何问题setlocale()
中的默认字符集是php.ini
UTF-8
中的php.ini
设置为mbstring.internal_encoding
UTF-8
mbstring.func\u重载=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的答案)。在php中尝试强制utf-8:
<? ini_set( 'default_charset', 'UTF-8' ); ?>
在任何页面/模板的顶部(代码的第一行)。它主要帮助我处理我的特殊角色。不确定它是否也能帮助您,请尝试一下。可能您的所有服务器都处于良好状态。在其中一条评论中,您说您只对ucfirst()和var_export()有异议。根据这些回答,您可能会看到这一点。大多数php字符串函数在处理多字节字符串时无法正常工作。这就是php必须处理这些问题的原因
可能会有帮助我建议您验证您遇到问题的PHP二进制文件。检查编译器标志及其使用的库 通常PHP在内部使用二进制字符串,这意味着像
ucfirst
这样的函数逐字节工作,并且只支持您的语言环境支持的内容(如果和类似配置)。看
返回
?u
这是有道理的,ñ
是
LATIN SMALL LETTER N WITH TILDE (U+00F1) UTF8: \xC3\xB1
您已经配置了一些区域设置,使PHP将\xC3
更改为其他内容,从而打破UTF-8字节序列并使shell显示
我建议,如果你真的想分析问题,你应该从下一步开始,看看如何在shell和其他地方显示。
要知道,您可以显式定义二进制字符串b“string”
(这是向前兼容性,可能您启用了一些编译标志,并且您使用的是unicode实验?),而且您还可以按字面意思编写字符串,这里是UTF-8的十六进制方式:
$ php -r "echo ucfirst(b\"\\xC3\\xB1u\");"
还有更多的设置可以发挥作用,我开始在中列出一些要点
多字节
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;
}
请参见和。我通常对所有法语字符使用
utf8_encode('ñu')
,phpunit测试,因为这项测试正在添加到-我们能否建立一个更好的单元测试套件,以便我们能够确定预期的输出应该是什么?我首先检查每个服务器上运行的软件版本。特别是php。一个版本中的函数采用UTF-8,而另一个版本中的相同函数采用ISO-8859-1。还可以尝试比较locale(1)
的输出和/或检查以LC
开头的环境变量。这是否只发生在CLI上?这可能是Solaris终端处理Unicode的一些特殊情况。或者从保证不包含NUL
字节的源代码文件运行时也会发生这种情况吗?请检查两件事,一件是在CLI上执行的php.ini(可能不同于通过Web服务器执行的php.ini),在那里将默认字符集设置为“utf-8”。其次,检查/etc/locale.gen,如果您在这台服务器上有一个en_US.UTF-8,我相信这与Solaris和PHP使用的system C库有关。我要说的是,编译后的包已经被宿主弄乱了,否则strtoupper
一定在工作。获取正确的二进制文件。默认字符集为php.ini
中的UTF-8
。无论如何,谢谢。我已经做了“十六进制测试”:所有服务器,包括“坏家伙”,在执行$php-r“echo bin2hex('ñu');”时返回c3b175
。不确定我应该如何解释这一点…和$php-r“echo ucfirst(b \“\\xC3\\xB1u\”;“
返回?u
”。以及bin2hex(ucfirst('ñu'))的含义是什么代码>给予?(您的报告显示,对于这两种情况,PHP都在字符串中使用UTF-8序列,因此在这些系统中是相同的)。bin2hex(ucfirst('ñu')
返回00b175
。由于这与strtoupper
有关,我怀疑它与编译PHP时的底层c库有关。您应该向Joynet支持人员咨询,并要求他们提供正确配置/编译的二进制文件。另外,我建议您获得一个PHP版本,它是一个更流行的PHP5.3版本,比如PHP5.3.10。谢谢Vinay,但这似乎是一个潜在的C问题,可能是编译问题。仍在努力寻找答案,但PHP似乎没有找到答案
/**
* 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;
}