Как мне использовать функции файловой системы в PHP, используя строки UTF-8? - PullRequest
33 голосов
/ 06 октября 2009

Я не могу использовать mkdir для создания папок с символами UTF-8:

<?php
$dir_name = "Depósito";
mkdir($dir_name);
?>

когда я просматриваю эту папку в проводнике Windows, имя папки выглядит следующим образом:

Depósito

Что мне делать?

Я использую php5

Ответы [ 9 ]

23 голосов
/ 25 октября 2009

Просто urlencode желаемая строка в качестве имени файла. Все символы , возвращаемые из urlencode, допустимы в именах файлов (NTFS / HFS / UNIX) тогда вы можете просто urldecode имена файлов вернуться к UTF-8 (или к любой другой кодировке).

Предостережения (все также применимы к решениям ниже):

  • После URL-кодирования имя файла должно быть не более 255 символов (возможно, байтов).
  • UTF-8 имеет несколько представлений для многих символов (с использованием комбинированных символов). Если вы не нормализуете свой UTF-8, у вас могут возникнуть проблемы с поиском по glob или повторным открытием отдельного файла.
  • Нельзя полагаться на scandir или аналогичные функции для альфа-сортировки. Вы должны urldecode имена файлов, а затем использовать алгоритм сортировки с учетом UTF-8 (и параметров сортировки).

Хуже решений

Ниже приведены менее привлекательные решения, более сложные и с большим количеством оговорок.

В Windows оболочка файловой системы PHP ожидает и возвращает строки ISO-8859-1 для имен файлов / каталогов. Это дает вам два варианта:

  1. Свободно используйте UTF-8 в именах файлов, но помните, что символы, не входящие в ASCII, будут выглядеть некорректно вне PHP. Символ не-ASCII UTF-8 будет храниться в виде нескольких одинарных ISO-8859-1 символов. Например. ó будет отображаться как ó в проводнике Windows.

  2. Ограничьте имена файлов / каталогов символами, представленными в ISO-8859-1 . На практике вы передадите свои строки UTF-8 через utf8_decode, прежде чем использовать их в функциях файловой системы, и передадите записи scandir через * 1054. *, чтобы получить исходные имена файлов в UTF-8.

Предостережения в изобилии!

  • Если какой-либо байт , переданный функции файловой системы, соответствует недопустимому символу файловой системы Windows в ISO-8859-1, вам не повезло.
  • Windows может использовать кодировку, отличную от ISO-8859-1, в неанглийских локалях. Я предполагаю, что обычно это один из ISO-8859- #, но это означает, что вам нужно будет использовать mb_convert_encoding вместо utf8_decode.

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

12 голосов
/ 04 апреля 2012

В Unix и Linux (и, возможно, также в OS X) текущая кодировка файловой системы задается параметром LC_CTYPE locale (см. Функцию setlocale()). Например, он может оценить что-то вроде en_US.UTF-8, что означает кодировку UTF-8. Затем имена файлов и их пути могут быть созданы с помощью fopen() или получены с помощью dir() с этой кодировкой.

В Windows PHP работает как «не поддерживающая Юникод программа», затем имена файлов конвертируются из UTF-16, используемого файловой системой (Windows 2000 и более поздние версии), в выбранную «кодовую страницу». Панель управления «Язык и региональные стандарты», вкладка «Форматы» устанавливает кодовую страницу, полученную с помощью параметра LC_CTYPE, а «Административный -> Язык для программ, не поддерживающих Юникод», устанавливает кодовую страницу перевода для имен файлов. В западных странах параметр LC_CTYPE оценивается примерно как language_country.1252, где 1252 - это кодовая страница, также известная как «кодировка Windows-1252», которая аналогична (но не совсем равна) ISO-8859-1. В Японии вместо этого обычно устанавливается кодовая страница 932 и так далее для других стран. Под PHP вы можете создавать файлы, чье имя может быть выражено с помощью текущей кодовой страницы. И наоборот, имена файлов и пути, извлеченные из файловой системы, преобразуются из UTF-16 в байты с использованием наиболее подходящей текущей кодовой страницы .

Это сопоставление является приблизительным, поэтому некоторые символы могут быть искажены непредсказуемым образом. Например, Caffé Brillì.txt будет возвращено dir() в виде строки PHP Caff\xE9 Brill\xEC.txt, как и ожидалось, если текущая кодовая страница равна 1252, тогда как в японской системе будет возвращено приблизительное значение Caffe Brilli.txt, поскольку ударные гласные отсутствуют в 932 кодовую страницу, а затем заменить ее «наилучшим образом» не акцентированные гласные. Символы, которые вообще не могут быть переведены, извлекаются как ? (знак вопроса). Как правило, в Windows нет безопасного способа обнаружения таких артефактов.

Более подробная информация доступна в моем ответе на Ошибка PHP №. 47096 .

8 голосов
/ 19 июля 2016

PHP 7.1 поддерживает имена файлов UTF-8 в Windows независимо от кодовой страницы OEM.

7 голосов
/ 06 октября 2009

Проблема в том, что Windows использует utf-16 для строк файловой системы, тогда как Linux и другие используют разные наборы символов, но часто utf-8. Вы указали строку utf-8, но это интерпретируется как другая 8-битная кодировка набора символов в Windows, может быть Latin-1, а затем символ не ascii, который кодируется с 2 байтами в utf-8, обрабатывается как если в Windows было 2 символа.

Обычное решение - сохранить исходный код на 100% в ascii и иметь строки в другом месте.

3 голосов
/ 30 ноября 2013

Используя расширение com_dotnet PHP, вы можете получить доступ к Windows 'Scripting.FileSystemObject, а затем делать все, что вам нужно, с именами файлов / папок UTF-8.

Я упаковал это как упаковщик потока PHP, поэтому его очень легко использовать:

https://github.com/nicolas-grekas/Patchwork-UTF8/blob/lab-windows-fs/class/Patchwork/Utf8/WinFsStreamWrapper.php

Сначала убедитесь, что расширение com_dotnet включено в вашем php.ini затем включите обертку с помощью:

stream_wrapper_register('win', 'Patchwork\Utf8\WinFsStreamWrapper');

Наконец, используйте функции, к которым вы привыкли (mkdir, fopen, rename и т. Д.), Но перед вашим путем добавьте win://

Например:

<?php
$dir_name = "Depósito";
mkdir('win://' . $dir_name );
?>
2 голосов
/ 03 сентября 2015

Вы можете использовать это расширение для решения вашей проблемы: https://github.com/kenjiuno/php-wfio

$file = fopen("wfio://多国語.txt", "rb"); // in UTF-8
....
fclose($file);
0 голосов
/ 10 января 2019

Мне не нужно много писать, все работает хорошо:

<?php
$dir_name = mb_convert_encoding("Depósito", "ISO-8859-1", "UTF-8");
mkdir($dir_name);
?>
0 голосов
/ 23 июля 2014

Мой набор инструментов для использования файловой системы с UTF-8 на Windows ИЛИ Linux через PHP и совместим с .htaccess Файл проверки существует:

function define_cur_os(){

    //$cur_os=strtolower(php_uname());

    $cur_os=strtolower(PHP_OS);

    if(substr($cur_os, 0, 3) === 'win'){

        $cur_os='windows';

    }

    define('CUR_OS',$cur_os);

}

function filesystem_encode($file_name=''){

    $file_name=urldecode($file_name);

    if(CUR_OS=='windows'){

        $file_name=iconv("UTF-8", "ISO-8859-1//TRANSLIT", $file_name);

    }     

    return $file_name;

}

function custom_mkdir($dir_path='', $chmod=0755){

    $dir_path=filesystem_encode($dir_path);

    if(!is_dir($dir_path)){

        if(!mkdir($dir_path, $chmod, true)){

            //handle mkdir error

        }
    }
    return $dir_path;
}

function custom_fopen($dir_path='', $file_name='', $mode='w'){

    if($dir_path!='' && $file_name!=''){

        $dir_path=custom_mkdir($dir_path);

        $file_name=filesystem_encode($file_name);

        return fopen($dir_path.$file_name, $mode);

    }

    return false;

}

function custom_file_exists($file_path=''){

    $file_path=filesystem_encode($file_path);

    return file_exists($file_path);

}

function custom_file_get_contents($file_path=''){

    $file_path=filesystem_encode($file_path);

    return file_get_contents($file_path);

}

Дополнительные ресурсы

0 голосов
/ 20 февраля 2012

Попробуйте CodeIgniter Text helper из по этой ссылке Читайте о функции convert_accented_characters (), ее стоимость может быть оценена

...