it-swarm.dev

Como eu uso funções do sistema de arquivos em PHP, usando strings UTF-8?

Eu não posso usar mkdir para criar pastas com caracteres UTF-8:

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

quando eu navego por esta pasta no Windows Explorer, o nome da pasta é semelhante ao seguinte:

Depósito

O que devo fazer?

Estou usando php5

31
Acacio Nerull

Apenas urlencode a string desejada como um nome de arquivo. All caracteres retornados de urlencode são válidos em nomes de arquivos (NTFS/HFS/UNIX), então você pode apenas urldecode os nomes de arquivos de volta para UTF-8 (ou qualquer codificação em que eles estivessem).

Advertências (todas se aplicam também às soluções abaixo): 

  • Após a codificação url, o nome do arquivo deve ter menos de 255 caracteres (provavelmente bytes).
  • O UTF-8 possui várias representações para muitos caracteres (usando caracteres combinados). Se você não normalizar seu UTF-8, poderá ter problemas para pesquisar com glob ou reabrir um arquivo individual.
  • Você não pode confiar em scandir ou funções similares para classificação alfa. Você deve urldecode os nomes dos arquivos, em seguida, usar um algoritmo de classificação ciente de UTF-8 (e agrupamentos).

Soluções piores

A seguir estão as soluções menos atraentes, mais complicadas e com mais ressalvas.

No Windows, o invólucro do sistema de arquivos PHP espera e retorna as seqüências de caracteres ISO-8859-1 para nomes de arquivos/diretórios. Isso lhe dá duas opções:

  1. Use UTF-8 livremente em seus nomes de arquivos, mas entenda que caracteres não ASCII serão aparecem incorretos fora do PHP. Um caractere não-ASCII UTF-8 será armazenado como vários caracteres simples ISO-8859-1. Por exemplo. ó será exibido como ó no Windows Explorer.

  2. Limite seus nomes de arquivos/diretórios para caracteres representáveis ​​em ISO-8859-1 . Na prática, você passará suas strings UTF-8 através de utf8_decode antes de usá-las em funções do sistema de arquivos, e passará as entradas scandir através de utf8_encode para obter os nomes de arquivos originais em UTF- 8.

Advertências em abundância!

  • Se qualquer byte passado a uma função do sistema de arquivos corresponder a um caractere inválido do sistema de arquivos do Windows em ISO-8859-1, você estará sem sorte.
  • O Windows maio usa uma codificação diferente de ISO-8859-1 em idiomas não ingleses. Eu acho que normalmente será um ISO-8859- #, mas isso significa que você precisará usar mb_convert_encoding em vez de utf8_decode.

Esse pesadelo é porque você provavelmente deveria apenas transliterate criar nomes de arquivos.

23
Steve Clay

Sob Unix e Linux (e possivelmente sob o OS X também), a codificação atual do sistema de arquivos é dada pelo parâmetro LC_CTYPE locale (veja function setlocale()). Por exemplo, ele pode avaliar algo como en_US.UTF-8, o que significa que a codificação é UTF-8. Em seguida, os nomes de arquivos e seus caminhos podem ser criados com fopen() ou recuperados por dir() com essa codificação.

No Windows, PHP funciona como um "programa que não reconhece Unicode", os nomes de arquivos são convertidos de um UTF-16 usado pelo sistema de arquivos (Windows 2000 e posterior) para o "código" selecionado. página". O painel de controle "Opções regionais e de idioma", guia "Formatos" define a página de código recuperada pela opção LC_CTYPE, enquanto a "Linguagem administrativa -> para programas não-Unicode" define a página de códigos de tradução para nomes de arquivos. Nos países ocidentais, o parâmetro LC_CTYPE é avaliado como algo como language_country.1252, em que 1252 é a página de código, também conhecida como "Windows-1252 encoding", que é similar (mas não exatamente igual) a ISO-8859-1. No Japão, a página de código 932 é normalmente definida, e assim por diante para outros países. Sob PHP você pode criar arquivos cujo nome pode ser expresso com a página de código atual. Vice-versa, os nomes de arquivo e os caminhos recuperados do sistema de arquivos são convertidos de UTF-16 para bytes usando a página de código atual "melhor ajuste" .

Esse mapeamento é aproximado, portanto, alguns caracteres podem ser mutilados de maneira imprevisível. Por exemplo, Caffé Brillì.txt seria retornado por dir() como o PHP string Caff\xE9 Brill\xEC.txt como esperado se a página de código atual for 1252, enquanto retornaria o Caffe Brilli.txt aproximado em um sistema japonês porque as vogais acentuadas estão faltando no código 932 página e, em seguida, substituídos por suas vogais não-acentuadas "best-fit". Os caracteres que não podem ser traduzidos são recuperados como ? (ponto de interrogação). Em geral, no Windows, não há maneira segura de detectar esses artefatos.

Mais detalhes estão disponíveis na minha resposta ao PHP bug no. 47096 .

12
Umberto Salsi

O PHP 7.1 suporta nomes de arquivos UTF-8 no Windows, desconsiderando a página de códigos do OEM.

8
Anatol Belski

O problema é que o Windows usa o utf-16 para cadeias de arquivos, enquanto o Linux e outros usam conjuntos de caracteres diferentes, mas geralmente o utf-8. Você forneceu uma string utf-8, mas isso é interpretado como outra codificação de conjunto de caracteres de 8 bits no Windows, talvez Latin-1, e então o caractere não-ascii, que é codificado com 2 bytes em utf-8, é tratado como se fosse 2 caracteres no Windows.

Uma solução normal é manter seu código-fonte 100% em ascii e ter strings em outro lugar.

7
Lars D

Usando a extensão com_dotnet PHP, você pode acessar o Scripting.FileSystemObject do Windows e fazer tudo o que quiser com nomes de arquivos/pastas UTF-8.

Eu empacotei isso como um wrapper stream PHP, então é muito fácil de usar:

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

Primeiro, verifique se a extensão com_dotnet está ativada em seu php.ini E ative o wrapper com:

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

Finalmente, use as funções que você está acostumado (mkdir, fopen, rename, etc.), mas prefixe seu caminho com win://

Por exemplo:

<?php
$dir_name = "Depósito";
mkdir('win://' . $dir_name );
?>
3
Nicolas Grekas

Você poderia usar esta extensão para resolver seu problema: https://github.com/kenjiuno/php-wfio

$file = fopen("wfio://多国語.txt", "rb"); // in UTF-8
....
fclose($file);
2
Oleg

Eu não preciso escrever muito, funciona bem:

<?php
$dir_name = mb_convert_encoding("Depósito", "ISO-8859-1", "UTF-8");
mkdir($dir_name);
?>
0
Yesterday

Tente o ajudante de texto CodeIgniter de este link Leia sobre a função convert_accented_characters (), ele pode ser costumizado

0
TomoMiha

Meu conjunto de ferramentas para usar o sistema de arquivos com UTF-8 no windowsOUlinux via PHP e compatível com o arquivo de verificação .htaccess existe:

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);

}

Recursos adicionais

0
RafaSashi