5

我在运行 linux 的服务器上有一个包含 Unicode 字符的文件。如果我通过 SSH 连接到服务器并使用制表符完成导航到包含 unicode 字符的文件/文件夹,则访问文件/文件夹没有问题。当我尝试通过 PHP 访问文件时出现问题(我访问文件系统的函数是stat)。如果我将 PHP 脚本生成的路径输出到浏览器并将其粘贴到终端,则该文件似乎也存在(即使查看终端,文件路径完全相同)。

我通过 php_ini 和 set 将 PHP 设置为使用 UTF8 作为其默认编码mb_internal_encoding。我检查了 PHP 文件路径字符串编码,它应该是 UTF8。再摸索一下,我决定hexdump将终端的制表符完成hexdump的 é 字符与 PHP 脚本创建的“常规” é 字符进行比较,或者通过键盘手动输入字符(option+e+e on操作系统 x)。结果如下:

回声-né | 十六进制转储
0000000 cc65 0081                              
0000003
回声-né | 十六进制转储
0000000 a9c3                                   
0000002

允许在终端中正确引用文件的 é 字符是 3 字节字符。我不确定从这里去哪里,我应该在 PHP 中使用什么编码?我应该通过iconv或将路径转换为另一种编码mb_convert_encoding吗?

4

3 回答 3

6

感谢两个答案中给出的提示,我能够四处寻找并找到一些方法来规范化给定字符的不同 unicode 分解。在我遇到的情况下,我正在访问由 OS X Carbon 应用程序创建的文件。这是一个相当流行的应用程序,因此它的文件名似乎遵循特定的 unicode 分解。

在 PHP 5.3 中引入了一组新函数,允许您将 unicode 字符串规范化为特定的分解。显然,您可以将 unicode 字符串分解为四种分解标准。自 2.3 版以来,Python 通过unicode.normalize具有 unicode 规范化功能。这篇关于 python 处理 unicode 字符串的文章有助于更好地理解编码/字符串处理。

下面是一个规范化 unicode 文件路径的简单示例:

filePath = unicodedata.normalize('NFD', filePath)

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

于 2009-12-19T20:25:12.770 回答
3

三字节序列实际上是一个e (0x65)后跟一个组合 ´ (0xcc 0x81)的 utf8 表示,而 0xc3 0xa9 “直接”代表é
一个 utf-8 感知排序规则应该知道可能的分解,但我不知道如何在 mac 上启用它(并且可能重新编译 php 源代码)。
我能提供的最好的就是“Using UTF-8 with Gentoo”的描述。

于 2009-07-07T08:26:13.377 回答
1

首先:您应该尽量避免对文件名强加语义。我真的不知道为什么 PHP 在你的场景中生成文件名,所以我不能建议你应该如何应用这个规则。

é 的不同(两个字节和三个字节)表示是 Unicode 中该字符的组合和分解变体的 UTF-8 编码。在 Unicode 中,这些是表示相同视觉字符的不同方式。Unicode 具有“规范化”的概念,其中同一字符的所有表示都转换为单个表示,有点像将两个字符串压缩为小写以执行无大小写比较。

Linux 不会自动对文件名执行规范化或任何其他处理,因此文件可以使用预先组合(如两个字节序列)或分解(如三个字节序列)字符或两者的任何混合来命名,这取决于谁命名文件。如果您正在创建文件,您可以设置一个策略(例如,始终使用预先组合的字符)并编写一些代码来强制执行它。否则,您不能在这里依赖任何特定规则。

于 2009-07-14T17:41:44.570 回答