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

2022-08-30 13:39:22

我无法使用创建包含 UTF-8 字符的文件夹:mkdir

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

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

Depósito

我该怎么办?

我使用的是 php5


答案 1

只需将所需的字符串作为文件名进行urlencode从 中返回的所有字符在文件名(NTFS/HFS/UNIX)中都有效,然后您可以只将文件名返回到 UTF-8(或它们所在的任何编码)。urlencodeurldecode

注意事项(也适用于以下解决方案):

  • url 编码后,文件名必须少于 255 个字符(可能是字节)。
  • UTF-8 对许多字符具有多种表示形式(使用组合字符)。如果不规范化 UTF-8,则可能无法搜索或重新打开单个文件。glob
  • 您不能依赖或类似的函数进行 Alpha 排序。然后,文件名必须使用可识别 UTF-8(和排序规则)的排序算法。scandirurldecode

更差的解决方案

以下是不太吸引人的解决方案,更复杂,并且有更多的警告。

在 Windows 上,PHP 文件系统包装器需要并返回 ISO-8859-1 字符串作为文件/目录名称。这为您提供了两种选择:

  1. 在文件名中自由使用 UTF-8,但要了解非 ASCII 字符在 PHP 之外会出现不正确的情况。非 ASCII UTF-8 字符将存储为多个单个 ISO-8859-1 字符。例如: 将显示在 Windows 资源管理器中。óó

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

注意事项很多!

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

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


答案 2

在Unix和Linux下(也可能在OS X下),当前的文件系统编码由locale参数给出(参见函数)。例如,它的计算结果可能类似于编码为 UTF-8。然后,可以使用此编码创建或检索文件名及其路径。LC_CTYPEsetlocale()en_US.UTF-8fopen()dir()

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

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

更多细节可以在我对PHP错误号47096的回复中找到。


推荐