如何使用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,你可能会遇到search
glob
或重新打开单个文件的麻烦。 - 您不能依靠
scandir
或类似的function进行字母sorting。 您必须对文件名进行urldecode
,然后使用urldecode
UTF-8(和归类)的sortingalgorithm。
更糟的解决scheme
以下是不那么有吸引力的解决scheme,更复杂和更多的警告。
在Windows上,PHP文件系统包装程序预期并返回文件/目录名称的ISO-8859-1string。 这给你两个select:
-
在你的文件名中可以自由使用UTF-8,但是明白在PHP之外非ASCII字符将显示不正确 。 一个非ASCII的UTF-8字符将被存储为多个单一的 ISO-8859-1字符。 例如
ó
将在Windows资源pipe理器中显示为ó
。 -
将文件/目录名限制为可在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包装器,因此它非常易于使用:
首先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); }
其他资源
- “file_exists”中的特殊字符问题(php)
- 带重音的PHP file_exists返回false
- http://www.developpez.net/forums/d825883/php/php-sgbd/php-mysql/mkdir-accents/
- http://en.wikipedia.org/wiki/Uname#Table_of_standard_uname_output