如何使用UTF-8字符串在PHP中使用文件系统函数?

Aca*_*ull 33 php filesystems directory utf-8 mkdir

我不能mkdir用来创建UTF-8字符的文件夹:

<?php
$dir_name = "Depósito";
mkdir($dir_name);
?>
Run Code Online (Sandbox Code Playgroud)

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

Depósito
Run Code Online (Sandbox Code Playgroud)

我该怎么办?

我正在使用php5

Ste*_*lay 24

只是urlencode希望作为文件名的字符串. 返回的所有字符urlencode在文件名(NTFS/HFS/UNIX)中都有效,然后您可以urldecode将文件名恢复为UTF-8(或者它们所处的任何编码).

警告(也适用于以下解决方案):

  • 在url-encoding之后,文件名必须小于255个字符(可能是字节).
  • UTF-8具有多个字符的多个表示(使用组合字符).如果您没有规范化UTF-8,则可能无法搜索glob或重新打开单个文件.
  • 您不能依赖scandir或类似的功能进行alpha排序.您必须urldecode使用文件名使用知道UTF-8(和排序规则)的排序算法.

更糟糕的解决方案

以下是不太有吸引力的解决方案,更复杂,更多的警告.

在Windows上,PHP文件系统包装器期望并返回文件/目录名称的ISO-8859-1字符串.这给你两个选择:

  1. 在文件名中自由使用UTF-8,但要理解PHP之外的非ASCII字符会出现错误.非ASCII UTF-8字符将存储为多个单个 ISO-8859-1字符.例如,ó将出现ó在Windows资源管理器中.

  2. 将文件/目录名限制为ISO-8859-1中可表示的字符.在实践中,您将utf8_decode在文件系统函数中使用它们之前传递UTF-8字符串,并传递条目scandir可以通过utf8_encodeUTF-8获取原始文件名.

警告嘉豪!

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

这个噩梦就是为什么你应该只是音译来创建文件名.


小智 12

在Unix和Linux下(也可能在OS X下),当前文件系统编码由LC_CTYPElocale参数给出(参见function setlocale()).例如,它可以评估为类似的东西en_US.UTF-8意味着编码是UTF-8.然后,可以使用此编码创建文件名及其路径,也可以使用此编码fopen()检索文件名dir().

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

这种映射是近似的,因此某些字符可能会以不可预测的方式被破坏.例如,如果当前代码页是1252,将按预期Caffé Brillì.txt返回dir()PHP字符串Caff\xE9 Brill\xEC.txt,而它将返回Caffe Brilli.txt日语系统的近似值,因为932代码页中缺少重音元音,然后替换为"最适合" "非重音元音.根本无法翻译的字符被检索为?(问号).通常,在Windows下,没有安全的方法来检测此类工件.

更多细节可以在我对PHP bug no的回复中找到.47096.


Ana*_*ski 8

PHP 7.1支持Windows上的UTF-8文件名而忽略OEM代码页.


Lar*_*s D 7

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

一个常见的解决方案是将源代码保持在ascii中100%,并在其他地方使用字符串.