Имена файлов UTF8 в PHP и различные кодировки Unicode

У меня есть файл, содержащий символы Unicode на сервере с Linux. Если я использую SSH на сервере и использую tab-completion для перехода к файлу / папке, содержащей символы Unicode, у меня нет проблем с доступом к файлу / папке. Проблема возникает, когда я пытаюсь получить доступ к файлу через PHP (функция, к которой я обращалась в файловой системе, была stat ). Если я выведу путь, сгенерированный PHP-скриптом, в браузер и вставляю его в терминал, файл также, кажется, существует (даже если смотреть на терминал, пути к файлу точно такие же).

Я устанавливаю PHP для использования UTF8 в качестве кодировки по умолчанию через php_ini, а также для установки mb_internal_encoding . Я проверил строчную кодировку с файловым файлом PHP, и он выходит как UTF8, как и следовало ожидать. Еще немного подумав, я решил использовать hexdump символ é для завершения табуляции терминала и сравнить его с hexdump символом «регулярного» символа, созданного скриптом PHP, или вручную вводить символ через клавиатуру (опция + e + e на os x). Вот результат:

 echo -n é |  шестнадцатеричного
 0000000 cc65 0081                              
 0000003
 echo -n é |  шестнадцатеричного
 0000000 a9c3                                   
 0000002

Символ é, который позволяет корректную ссылку на файл в терминале, является 3-байтным. Я не уверен, куда идти отсюда, какую кодировку я должен использовать в PHP? Должен ли я преобразовывать путь в другую кодировку через iconv или mb_convert_encoding ?

Благодаря советам, приведенным в двух ответах, я смог совать и найти некоторые методы для нормализации разного разложения Unicode данного символа. В ситуации, с которой я столкнулся, я обращался к файлам, созданным приложением OS X Carbon. Это довольно популярное приложение, и, следовательно, его имена файлов, похоже, соответствуют определенному разложению в unicode.

В PHP 5.3 был введен новый набор функций, который позволяет вам нормализовать строку юникода для определенной декомпозиции. По-видимому, существует четыре стандарта разложения, которые вы можете разложить на строку unicode. У Python была нормализация нормализации unicode с версии 2.3 через unicode.normalize . Эта статья о обработке python строк unicode была полезной для понимания кодирования / обработки строк немного лучше.

Ниже приведен краткий пример нормализации пути к файлу unicode:

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

Я обнаружил, что формат NFD работал во всех моих целях, интересно, это ли это стандартная декомпозиция для имен файлов Unicode.

Трехбайтная последовательность представляет собой фактически представление utf8 e (0x65), за которым следует объединение '(0xcc 0x81) , а 0xc3 0xa9 стоит «прямо» для é .
Учетная команда utf-8 должна знать о возможных разложениях, но я не знаю, как вы можете включить это (и, возможно, перекомпилировать источник php) на mac.
Лучшее, что я могу предложить, это описание «Использование UTF-8 с Gentoo» .

Во-первых: вы должны стараться избегать наложения семантики на имена файлов. Я не могу сказать, почему PHP генерирует имена файлов в вашем сценарии, поэтому я не могу предложить, как вы должны применять это правило.

Различные (два байта и три байта) представления é являются кодировками UTF-8 составленных и разложенных вариаций этого символа в Unicode. В Unicode это различные способы представления одного и того же визуального символа. В Unicode есть понятие «канонизацизация», в котором все представления одного и того же символа преобразуются в одно представление, вроде как раздавливание двух строк в нижний регистр, чтобы выполнить бесполезное сравнение.

Linux не выполняет канонизацию или любую другую обработку автоматически для имен файлов, поэтому файл может быть назван с предустановленным (например, двумя байтовыми последовательностями) или разложенными (например, тремя байтовыми последовательностями) символами или любым сочетанием двух, это зависит от того, кто назвал файл. Если вы создаете файлы, вы можете установить политику (например, всегда использовать прекомпонованные символы) и написать код для ее принудительного применения. В противном случае вы не можете полагаться на какое-либо конкретное правило здесь.