在PHP中,我如何处理HFS +与其他地方的编码文件名的差异?

时间:2009-04-21 16:52:27

标签: php macos unicode utf-8 unicode-normalization

我正在创建一个非常简单的文件搜索,其中搜索数据库是一个文本文件,每行一个文件名。数据库是用PHP构建的,通过grepping文件(也使用PHP)可以找到匹配项。

这在Linux中很有用,但是not on Mac when non-ascii characters are used。看起来HFS +(MacOSX)上的名称编码方式与例如ext3(Linux)。这是test.php:

<?php
$mystring = "abcóüÚdefå";
file_put_contents($mystring, "");
$h = dir('.');
$h->read(); // "."
$h->read(); // ".."
$filename = $h->read();

print "string: $mystring and filename: $filename are ";

if ($mystring == $filename) print "equal\n";
else print "different\n";

运行MacOSX时:

$ php test.php
string: abcóüÚdefå and filename: abcóüÚdefå are different
$ php test.php |cat -evt
string: abcóü?M-^Zdefå$ and filename: abco?M-^Au?M-^HU?M-^Adefa?M-^J are different$

在Linux(或MacOSX上安装了nfs的ext3文件系统)上运行时:

$ php test.php
string: abcóüÚdefå and filename: abcóüÚdefå are equal
$ php test.php |cat -evt
string: abcM-CM-3M-CM-<M-CM-^ZdefM-CM-% and filename: abcM-CM-3M-CM-<M-CM-^ZdefM-CM-% are equal$

有没有办法让这个脚本在两个平台上都“平等”?

3 个答案:

答案 0 :(得分:4)

MacOSX使用标准化形式D(NFD)编码UTF-8,而most other systems use NFC

NFC vs NFD

from unicode.org

NFD到NFC转换有several implementations。在这里,我使用PHP Normalizer class来检测NFD字符串并将其转换为NFC。它可以在PHP 5.3或PECL Internationalization extension中使用。以下修订将使脚本有效:

...
$filename = $h->read();
if (!normalizer_is_normalized($filename)) {
   $filename = normalizer_normalize($filename);
}
...

答案 1 :(得分:3)

似乎Mac OS X / HFS +使用的是字符组合而不是单个字符。因此,ó(U + 00F3)被编码为o(U + 006F)+ ´(U + CC81,COMBINING ACUTE ACCENT)。另请参阅Apple’s Unicode Decomposition Table

答案 2 :(得分:0)

您是否检查过两个系统都使用相同的区域设置?

PHP脚本在两个系统上使用什么编码?

我也会尝试使用strcmp而不是equals运算符。我不确定equals运算符是否在内部使用strcmp,但在你的情况下测试是一件简单的事情。