glob () не может найти имена файлов с многобайтовыми символами в Windows? - PullRequest
30 голосов
/ 12 марта 2012

Я пишу файловый менеджер и мне нужно сканировать каталоги и иметь дело с переименованием файлов, которые могут содержать многобайтовые символы. Я работаю над этим локально на Windows / Apache PHP 5.3.8, со следующими именами файлов в каталоге:

  • filename.jpg
  • имяфайла.jpg
  • файл 件 name.jpg
  • פילענאַמע. JPG
  • 文件 名 .jpg

Тестирование на работающем сервере UNIX проснулось нормально. Локальное тестирование в Windows с использованием glob('./path/*') возвращает только первое, filename.jpg.

Используя scandir(), по крайней мере, возвращается правильное количество файлов, но я получаю имена вроде ?????????.jpg (примечание: это обычные вопросительные знаки, а не символ..

Мне понадобится написать функцию «поиска» для рекурсивного поиска по всему дереву имен файлов, соответствующих шаблону или с определенным расширением файла, и я предположил, что glob() будет правильным инструментом для этого, скорее чем сканировать все файлы и выполнить сопоставление с образцом и построение массива в коде приложения. Я открыт для альтернативных предложений, если это будет необходимо.

Предполагая, что это обычная проблема, я сразу же поискал в Google и Stack Overflow и не нашел ничего даже связанного. Это проблема Windows? Недостаток PHP? Какое решение: я могу что-нибудь сделать?

Приложение: Не уверен, насколько это связано, но file_exists() также возвращает FALSE для этих файлов, передавая полный абсолютный путь (используя Notepad ++, сам файл php является кодировкой UTF-8 без спецификации). Я уверен, что путь правильный, так как соседние файлы без многобайтовых символов возвращают TRUE.

РЕДАКТИРОВАТЬ : glob() может найти файл с именем filename-äöü.jpg. Ранее в моем файле .htaccess был AddDefaultCharset utf-8, который я раньше не рассматривал. filename-äöü.jpg печатался как filename-���.jpg. Единственный эффект, который удалял эту строку htaccess, теперь заключался в том, что имя файла печаталось нормально.

Я полностью удалил файл .htaccess, и это мой настоящий тестовый скрипт полностью (я изменил пару имен файлов из исходного поста):

print_r(scandir('./uploads/')); 
print_r(glob('./uploads/*'));

Вывод локально в Windows:

Array
(
    [0] => .
    [1] => ..
    [2] => ??? ?????.jpg
    [3] => ???.jpg
    [4] => ?????????.jpg
    [5] => filename-äöü.jpg
    [6] => filename.jpg
    [7] => test?test.jpg
)
Array
(
    [0] => ./uploads/filename-äöü.jpg
    [1] => ./uploads/filename.jpg
)

Вывод на удаленный сервер UNIX:

Array
(
    [0] => .
    [1] => ..
    [2] => filename-äöü.jpg
    [3] => filename.jpg
    [4] => test이test.jpg
    [5] => имя файла.jpg
    [6] => פילענאַמע.jpg
    [7] => 文件名.jpg
)
Array
(
    [0] => ./uploads/filename-äöü.jpg
    [1] => ./uploads/filename.jpg
    [2] => ./uploads/test이test.jpg
    [3] => ./uploads/имя файла.jpg
    [4] => ./uploads/פילענאַמע.jpg
    [5] => ./uploads/文件名.jpg
)

Поскольку это другой сервер, независимо от платформы, конфигурация может отличаться, поэтому я не уверен, что думать, и пока не могу полностью закрепить его в Windows (это может быть моя установка PHP, настройки ini или Конфигурация Apache). Есть идеи?

Ответы [ 5 ]

7 голосов
/ 27 марта 2012

Похоже, что функция glob () зависит от того, как была построена ваша копия PHP и была ли она скомпилирована с помощью Win32 API с поддержкой Unicode (я не верю, что стандартным buildid является.

Cf. http://www.rooftopsolutions.nl/blog/filesystem-encoding-and-php

Выдержка из комментариев к статье:

Филипп Верди 2010-09-26 8:53

TheВывод вашей установки PHP в Windows легко объяснить: вы установили неверную версию PHP и использовали версию, не скомпилированную для использования Unicode-версии Win32 API. По этой причине вызовы файловой системы, используемые PHP, будут использовать устаревшую версию.API «ANSI» и поэтому библиотеки C / C ++, связанные с этой версией PHP, сначала попытаются преобразовать строку PHP в кодировке UTF-8 в локальную кодовую страницу «ANSI», выбранную в рабочей среде (перед запуском PHP ознакомьтесь с командой CHCP).из окна командной строки)

Ваша версия Windows САМАЯ ВЕРОЯТНО НЕ несет ответственности за эту странную вещь. На самом деле, это ВАША версия PHP, которая не компилируетсяd и использует устаревшую ANSI-версию Win32 API (для совместимости с унаследованными 16-разрядными версиями Windows 95/98, поддержка файловой системы в ядре которой фактически не поддерживала Unicode, но использовала внутренний слой преобразования дляпреобразуйте Unicode в локальную кодовую страницу ANSI перед использованием фактической версии API ANSI.

Перекомпилируйте PHP, используя опцию компилятора, чтобы использовать версию Win32 API в формате UNICODE (которая должна быть по умолчанию сегодня, и в любом случае всегдапо умолчанию для PHP установлен на сервере, который НИКОГДА не будет Windows 95 или Windows 98 ...)

Тогда Windows сможет хранить имена файлов в кодировке UTF-16 (в том числе на томах FAT32, даже если на нихтома, он также сгенерирует псевдонимное короткое имя в формате 8.3 с использованием кодовой страницы файловой системы по умолчанию, чего можно избежать в томах NTFS.

Все, что вы описываете, это проблемы PHP (неправильный перенос на Windows илиневерная идентификация версии системы при runtime): перечитайте файлы README, поставляемые с исходными текстами PHP, поясняющие флаги компиляции.Я действительно считаю, что make-файл в Windows должен иметь возможность конфигурировать и автоматически определять, если ему действительно нужно использовать ТОЛЬКО ANSI-версию API.Если вы компилируете его для сервера, убедитесь, что скрипт Configure эффективно обнаружит полную поддержку UNICODE-версии Win32 aPI и будет использовать ее при компиляции PHP и при выборе библиотек времени выполнения для связывания.

Я использую PHP в Windows, правильно скомпилированный, и я абсолютно не знаю проблем, которые вы цитируете в своей статье.

Давайте теперь забудем навсегда эти неUNICODE-версии Win32 API (которые непоследовательно используют локальную кодовую страницу ANSI для графического интерфейса Windows и OEM-кодовую страницу для API файловой системы, API-интерфейсы, совместимые с DOS / BIOS, консольные API): эти версии не в ЮникодеAPI-интерфейсы даже НАМНОГО медленнее и дороже, чем версии API-интерфейсов Unicode, потому что они фактически переводят кодовую страницу в Unicode перед использованием основных API-интерфейсов Unicode (ситуация с ядрами на основе Windows NT полностью противоположна ситуации с версиямиWindows на основе виртуального расширителя DOS,например, Windows 95/98 / ME).

Если вы не используете собственную версию API, ваш вызов API будет проходить через слой thunking, который перекодирует строки между Unicode и одним из предыдущих версий.Кодовые страницы OEM, выбранные в соответствии с ANSI или CHCP, или кодовая страница OEM, намекаемая на файловую систему: для этого требуется дополнительное временное выделение памяти в ненативной версии Win32 API.Требуется дополнительное время, чтобы преобразовать вещи перед тем, как выполнять реальную работу, вызывая собственный API.

В итоге: бинарный файл PHP, устанавливаемый в Windows, ДОЛЖЕН быть другимв зависимости от того, если вы скомпилировали его для Windows 95/98 / SE (или старого Слой эмуляции Win16s для Windows 3.x, который был очень минимальным поддержка UTF-8, только для поддержки подмножеств Unicode используемого Unicode по кодекам ANSI и OEM, выбранным при запуске Windows из DOS удлинитель) или если он был скомпилирован для любой другой версии Windows на основе в ядре NT.

Лучшее доказательство того, что это проблема PHP, а не Windows, заключается в том, что Ваши странные результаты не будут появляться на других языках, таких как C #, Javascript, VB, Perl, Ruby ... У PHP очень плохая история в отслеживании версии (и слишком много исторических причуд исходного кода и неправильных предположения, которые должны быть отключены сегодня, и несовместимая библиотека который унаследовал все эти причуды, изначально сделанные в старых версиях PHP для старых версий Windows, которые даже официально не являются поддерживается Microsoft или даже самим PHP!).

Другими словами: RTM! Или скачайте и установите бинарную версию PHP для Windows предварительно компилируется с правильными настройками: я действительно думаю что PHP должен распространять двоичные файлы Windows, уже скомпилированные по умолчанию для Unicode-версии Win32 API, и с использованием Unicode-версия библиотек C / C ++: внутренне PHP-код преобразовать его строки UTF-8 в UTF-16 перед вызовом Win32 API, и вернуться из UTF-16 в UTF-8 при получении результатов Win32 вместо преобразование внутренних строк PHP UTF-8 обратно / в локальную кодовую страницу OEM (для вызовов файловой системы) или локальной кодовой страницы ANSI (для всех остальных Win32 API, включая реестр или процесс).

0 голосов
/ 10 августа 2016

Начиная с PHP 7.1 long и пути UTF-8 в Windows поддерживаются непосредственно в ядре.

0 голосов
/ 02 апреля 2012

PHP на окнах пока не использует Unicode API.Поэтому вы должны использовать кодировку времени выполнения (что бы это ни было), чтобы иметь возможность работать с не-ascii charset.

0 голосов
/ 20 марта 2012

Я не трогал PHP 3 или 4 года, но, возможно, это может помочь:

pathinfo () осведомлен о локали, поэтому для правильного анализа пути, содержащего многобайтовые символы, соответствующая локаль должна быть установлена ​​с помощью функции setlocale ()

И несколько прямых ссылок:

pathinfo - читать вторую заметку

о setlocale

(Я думаю, что ваша проблема возникает из-за сканирования каталогов, а не из самого кода дисплея или из заголовков, поскольку Chrome или Firefox, если я хорошо помню, может обрабатывать символы Unicode.)

0 голосов
/ 15 марта 2012

Попробуйте установить mb_internal_encoding () на " UTF-8 " перед использованием glob

mb_internal_encoding("UTF-8");
print_r(glob('./uploads/*'));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...