Web

Как мне использовать функции файловой системы в PHP, используя строки UTF-8

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

<?php

$dir_name = "Depósito";

mkdir($dir_name);

?>

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

Depósito

 Что мне необходимо сделать? Я использую php5.

 

 Ответ 1

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

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

  1. После url-кодирования имя файла должно быть меньше 255 символов (возможно, байт).

  2. UTF-8 имеет несколько представлений для многих символов (используя объединение символов). Если вы не нормализуете UTF-8, у вас могут возникнуть проблемы с поиском с помощью glob или повторным открытием отдельного файла.

  3. Вы не можете полагаться на scandir или подобные функции для альфа-сортировки. Вы должны выполнять urldecode для имен файлов, а затем использовать алгоритм сортировки, понимающий UTF-8 (и возможные коллизии форматов).

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

 

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

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

Если любой байт, переданный в функцию файловой системы, совпадает с недопустимым символом файловой системы Windows в ISO-8859-1, результат не определен.

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

По этой причине вы, вероятно, должны просто использовать транслитерацию для создания имен файлов.

 

Ответ 2

В 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 нет надежного способа обнаружить такие артефакты.

 

 

Ответ 3

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

 

Ответ 4

Мой набор инструментов для использования файловой системы с 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);

}

 

Схожие статьи

Web

Применение выражения eval в php

Web

Где PHP хранит журнал ошибок?

Уязвимости Apache HTTP Server: как их обнаружить и устранить?
Web

Уязвимости Apache HTTP Server: как их обнаружить и устранить?

Web

Как зашифровать/расшифровать данные на php