如何使用UTF-8string在PHP中使用文件系统function?

我无法使用mkdir创buildUTF-8字符的文件夹。

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

但是,当我在Windows资源pipe理器中浏览此文件夹时,文件夹名称如下所示:

 Depósito 

我该怎么办?

只需urlencode作为一个文件名所需的string。urlencode返回的所有字符在文件名(NTFS / HFS / UNIX)中都是有效的,然后你可以将文件名urldecode解码回UTF-8(或者他们所在的任何编码)。

注意事项(全部适用于以下解决scheme):

  • 在URL编码之后,文件名必须less于255个字符(可能是字节)。
  • UTF-8对多个字符(使用组合字符)具有多个表示 。 如果你没有规范你的UTF-8,你可能会遇到searchglob或重新打开单个文件的麻烦。
  • 您不能依靠scandir或类似的function进行字母sorting。 您必须对文件名进行urldecode ,然后使用urldecode UTF-8(和归类)的sortingalgorithm。

更糟的解决scheme

以下是不那么有吸引力的解决scheme,更复杂和更多的警告。

在Windows上,PHP文件系统包装程序预期并返回文件/目录名称的ISO-8859-1string。 这给你两个select:

  1. 在你的文件名中可以​​自由使用UTF-8,但是明白在PHP之外非ASCII字符将显示不正确 。 一个非ASCII的UTF-8字符将被存储为多个单一的 ISO-8859-1字符。 例如ó将在Windows资源pipe理器中显示为ó

  2. 将文件/目录名限制为可在ISO-8859-1中表示的字符 。 实际上,在使用文件系统函数之前,你需要先通过utf8_decode传递你的UTF-8string,然后通过utf8_encode通过scandir提供的条目来获取UTF-8的原始文件名。

注意嘉豪!

  • 如果传递给文件系统函数的任何字节与ISO-8859-1中的无效Windows文件系统字符相匹配,那么您就不幸运了。
  • Windows 可能在非英文语言环境中使用ISO-8859-1以外的编码。 我猜它通常是ISO-8859-#之一,但这意味着你将需要使用mb_convert_encoding而不是utf8_decode

这个噩梦是为什么你应该可能只是音译创build文件名。

在Unix和Linux下(也可能在OS X下),当前的文件系统编码由LC_CTYPE语言环境参数给出(参见函数setlocale() )。 例如,它可以评估为en_US.UTF-8 ,这意味着编码是UTF-8。 然后文件名和它们的path可以用fopen()创build,或者用dir()用这个编码检索。

在Windows下,PHP作为“非Unicode感知程序”运行,然后文件名从文件系统(Windows 2000及更高版本)使用的UTF-16来回转换为选定的“代码页”。 控制面板“区域和语言选项”,选项卡面板“格式”设置LC_CTYPE选项检索的代码页,而“pipe理 – >非Unicode程序的语言”设置文件名的翻译代码页。 在西方国家, LC_CTYPE参数的计算结果类似于language_country.1252 ,其中1252是代码页,也被称为“Windows-1252编码”,与ISO-8859-1类似(但不完全相同)。 在日本,通常会设置932代码页,以此类推其他国家。 在PHP下,您可以创build名称可以用当前代码页表示的文件。 反之亦然,从文件系统检索的文件名和path将使用“最适合”当前代码页从UTF-16转换为字节。

这个映射是近似的,所以一些angular色可能会以不可预知的方式被破坏。 例如,如果当前代码页是1252, Caff\xE9 Brill\xEC.txt按照预期返回dir()作为PHPstringCaff\xE9 Brill\xEC.txt ,而它将返回日文系统上的近似Caffe Brilli.txt因为932代码页缺less重音元音,然后用它们的“最适合”非重音元音replace。 无法翻译的字符被检索为? (问号)。 一般来说,在Windows下没有安全的方法来检测这种文物。

更多的细节可以在我的回复中find。 47096 。

问题是Windows使用utf-16作为文件系统string,而Linux和其他版本使用不同的字符集,但通常是utf-8。 您提供了一个utf-8string,但是这被解释为Windows中的另一个8位字符集编码,可能是Latin-1,然后在utf-8中使用2个字节编码的非ascii字符被视为如果它在Windows中是2个字符。

一个正常的解决scheme是保持你的源代码100%的ASCII,并有其他地方的string。

无论OEM代码页如何,PHP 7.1都支持Windows上的UTF-8文件名。

谢谢。

使用com_dotnet PHP扩展,您可以访问Windows的Scripting.FileSystemObject ,然后用UTF-8文件/文件夹名称做所有你想要的。

我将它打包为一个PHPstream包装器,因此它非常易于使用:

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

首先validation您的php.ini启用了com_dotnet扩展,然后启用包装:

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

最后,使用你习惯的函数(mkdir,fopen,rename等),但是用win://前缀

例如:

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

你可以使用这个扩展来解决你的问题: https : //github.com/kenjiuno/php-wfio

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

从这个链接尝试CodeIgniter文本助手阅读有关convert_accented_characters()函数,它可以costume

我在Windows Linux上通过PHP使用带有UTF-8文件系统的工具,并与.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); } 

其他资源