PHP中的UTF8文件名和不同的Unicode编码

6
我在一台运行Linux的服务器上有一个包含Unicode字符的文件。如果我通过SSH进入服务器并使用tab键自动补全来访问包含unicode字符的文件/文件夹,那么我访问该文件/文件夹时没有任何问题。但是,当我尝试通过PHP访问文件时(我从中访问文件系统的函数是stat),问题就出现了。如果我将PHP脚本生成的路径输出到浏览器并将其粘贴到终端中,文件似乎也存在(即使查看终端,文件路径完全相同)。
我设置PHP使用UTF8作为其默认编码方式,并设置了mb_internal_encoding。我检查了PHP文件路径字符串编码方式,并且它是UTF8,正如应该的那样。进一步探索后,我决定对终端的tab键补全产生的é字符进行hexdump并与PHP脚本或手动键入字符(在OS X上是option+e+e)所创建的'regular' é字符的hexdump进行比较。以下是结果:
echo -n é | hexdump
0000000 cc65 0081                              
0000003
echo -n é | hexdump
0000000 a9c3                                   
0000002
允许在终端中正确引用文件的é字符是3个字节的字符。我不确定接下来该怎么办,我应该在PHP中使用哪种编码方式?我是否应该通过iconvmb_convert_encoding将路径转换为另一种编码方式?
3个回答

6
由于两个答案中给出的提示,我能够查找一些规范化给定字符的不同Unicode分解方法的方法。在我面临的情况下,我正在访问由OS X Carbon应用程序创建的文件。它是一个相当流行的应用程序,因此其文件名似乎遵循特定的Unicode分解。
在PHP 5.3中引入了一组新函数,允许您将Unicode字符串规范化为特定分解。显然,有四种分解标准,您可以将其分解为Unicode字符串。自版本2.3以来,Python具有Unicode规范化功能,通过unicode.normalize实现。这篇文章对Python处理Unicode字符串的方式有所帮助,更好地理解编码/字符串处理。
以下是规范化Unicode文件路径的快速示例:
filePath = unicodedata.normalize('NFD', filePath)

我发现NFD格式适用于我所有的目的,不知道这是否是Unicode文件名的标准分解形式。


3

这个三字节序列实际上是utf8表示的 e (0x65) 后面跟着一个带重音符号的 ´ (0xcc 0x81),而0xc3 0xa9则直接表示é
一个支持utf-8的排序应该意识到可能的分解,但我不知道如何在Mac上启用它(并且可能需要重新编译php源代码)。
我能提供的最好建议就是参考“在Gentoo中使用UTF-8”


1
首先:您应该尽量避免在文件名中强加语义。我无法确定为什么PHP会在您的情况下生成文件名,因此我无法建议您如何应用此规则。
é的不同(两个字节和三个字节)表示是Unicode中这个字符的组合和分解变体的UTF-8编码。在Unicode中,这些是表示相同视觉字符的不同方式。Unicode具有“规范化”的概念,在其中将所有相同字符的表示转换为单个表示,类似于将两个字符串压缩为小写以执行无大小写比较。
Linux不会自动执行规范化或任何其他处理来处理文件名,因此文件可以使用预组合(例如两个字节序列)或分解(例如三个字节序列)字符或任何混合形式进行命名,这取决于命名文件的人。如果您正在创建文件,则可以设置策略(例如始终使用预组合字符)并编写一些代码来强制执行它。否则,您不能依赖任何特定的规则。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接