我在运行linux的服务器上有一个包含Unicode字符的文件。如果我SSH到服务器并使用tab-completion导航到包含unicode字符的文件/文件夹,我访问文件/文件夹没有问题。当我尝试通过PHP访问文件时出现问题(我从stat
访问文件系统的函数)。如果我将PHP脚本生成的路径输出到浏览器并将其粘贴到终端中,该文件似乎也存在(即使查看终端文件路径完全相同)。
我将PHP设置为通过php_ini使用UTF8作为其默认编码,并设置mb_internal_encoding
。我检查了PHP文件路径字符串编码,它应该是UTF8。稍微多了一点,我决定hexdump
终端标签完成的é字符,并将其与PHP脚本创建的'常规'é字符的hexdump
进行比较,或者手动输入键盘上的字符(OS x上的选项+ e + e)。结果如下:
echo -n é | hexdump 0000000 cc65 0081 0000003 echo -n é | hexdump 0000000 a9c3 0000002
允许终端中正确文件引用的é字符是3字节的字符。我不知道从哪里开始,我应该在PHP中使用什么编码?我应该通过iconv
还是mb_convert_encoding
?
答案 0 :(得分:5)
感谢两个答案中给出的提示,我能够找到一些方法来规范化给定字符的不同unicode分解。在我遇到的情况下,我正在访问由OS X Carbon应用程序创建的文件。它是一个相当流行的应用程序,因此它的文件名似乎遵循特定的unicode分解。
在PHP 5.3中引入了new set of functions,允许您将unicode字符串规范化为特定的分解。显然有四种分解标准可以将unicode字符串分解为。自版本2.3以来,Python已通过unicode.normalize获得了unicode规范化功能。关于python处理unicode字符串的This article有助于更好地理解编码/字符串处理。
以下是规范化unicode文件路径的快速示例:
filePath = unicodedata.normalize('NFD', filePath)
我发现NFD格式适用于我的所有目的,我想知道这是否是unicode文件名的标准分解。
答案 1 :(得分:3)
三字节序列实际上是e (0x65)的utf8表示,后跟combining ´ (0xcc 0x81),而0xc3 0xa9直接表示é。
知道utf-8的归类应该知道可能的分解,但是我不知道如何在mac上启用它(并且可能重新编译php源代码)。
我能提供的最好的是"Using UTF-8 with Gentoo"描述。
答案 2 :(得分:1)
首先:你应该尽量避免对文件名强加语义。我无法确定为什么PHP会在您的方案中生成文件名,因此我无法建议您应该如何应用此规则。
é的不同(两个字节和三个字节)表示是Unicode中该字符的组合和分解变体的UTF-8编码。在Unicode中,这些是表示相同视觉角色的不同方式。 Unicode具有“规范化”的概念,其中相同字符的所有表示都被转换为单个表示,有点像将两个字符串压缩为小写以执行无标记比较。
Linux不会自动为文件名执行规范化或任何其他处理,因此文件可以用预先组合(如两个字节序列)或分解(如三个字节序列)字符或两者的任意组合命名,它是由谁命名的文件。如果要创建文件,可以设置策略(例如,始终使用预组合字符)并编写一些代码来强制执行。否则,你不能在这里依赖任何特定的规则。