Как мне справиться с разницей в закодированных именах файлов в PHP в HFS+ и в HFS+?в другом месте?

StackOverflow https://stackoverflow.com/questions/773574

Вопрос

Я создаю очень простой поиск файлов, где база данных поиска представляет собой текстовый файл с одним именем файла в строке.База данных построена с помощью PHP, и совпадения находятся путем поиска файла (также с помощью PHP).

Это прекрасно работает в Linux, но не на Mac, когда используются символы, отличные от ascii.Похоже, что имена в HFS+ (MacOSX) кодируются иначе, чем, например, вext3 (Линукс).Вот 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 (или в файловой системе ext3, смонтированной по nfs, в MacOSX):

$ 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$

Есть ли способ заставить этот скрипт возвращать «равный» результат на обеих платформах?

Это было полезно?

Решение

MacOSX использует форму нормализации D (NFD) для кодирования UTF-8, а большинство других систем используют NFC.

NFC vs NFD

(с сайта unicode.org)

Есть несколько реализации о преобразовании NFD в NFC.Здесь я использовал PHP Класс нормализатора для обнаружения строк NFD и преобразования их в NFC.Он доступен в PHP 5.3 или через Расширение интернационализации PECL.Следующая поправка заставит скрипт работать:

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

Другие советы

Похоже, что Mac OS X/HFS+ использует комбинации символов вместо отдельных символов.Итак ó (U+00F3) вместо этого кодируется как o (U+006F) + ´ (U+CC81, СОЧЕТАНИЕ ОСТРОГО АКЦЕНТА).Смотрите также Таблица разложения Юникода Apple.

Вы проверили, что обе системы используют одну и ту же локаль?

Какую кодировку использует сценарий PHP в обеих системах?

Я бы также попробовал использовать стркмп вместо оператора равенства.Я не уверен, использует ли оператор равенства внутри себя strcmp, но в вашем случае это несложно проверить.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top