34

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

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

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

Depósito

我应该怎么办?

我正在使用 php5

4

9 回答 9

25

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

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

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

更糟糕的解决方案

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

在 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,并传递条目scandir让您通过utf8_encode以获取 UTF-8 中的原始文件名。

警告多多!

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

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

于 2009-10-25T14:28:23.653 回答
12

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

在 Windows 下,PHP 作为“非 Unicode 感知程序”运行,然后文件名从文件系统(Windows 2000 及更高版本)使用的 UTF-16 来回转换为选定的“代码页”。控制面板“区域和语言选项”,选项卡面板“格式”设置LC_CTYPE选项检索的代码页,而“管理->非Unicode程序的语言”设置文件名的翻译代码页。在西方国家,LC_CTYPE参数评估为language_country.1252其中 1252 是代码页,也称为“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 错误号的回复中找到。47096

于 2012-04-04T00:35:57.247 回答
9

PHP 7.1 在 Windows 上支持 UTF-8 文件名,而不管 OEM 代码页。

于 2016-07-19T19:17:26.657 回答
7

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

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

于 2009-10-06T14:19:33.087 回答
3

使用com_dotnetPHP 扩展,您可以访问 Windows' Scripting.FileSystemObject,然后使用 UTF-8 文件/文件夹名称做任何您想做的事情。

我将其打包为 PHP 流包装器,因此非常易于使用:

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

首先验证com_dotnet您的扩展是否已启用,php.ini 然后使用以下命令启用包装器:

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

最后,使用您习惯使用的函数(mkdir、fopen、rename 等),但在路径前加上win://

例如:

<?php
$dir_name = "Depósito";
mkdir('win://' . $dir_name );
?>
于 2013-11-30T10:45:59.540 回答
3

您可以使用此扩展程序来解决您的问题:https ://github.com/kenjiuno/php-wfio

$file = fopen("wfio://多国語.txt", "rb"); // in UTF-8
....
fclose($file);
于 2015-09-03T10:06:41.720 回答
0

我的一套工具可以在 Windowslinux上使用带有 UTF-8 的文件系统,PHP并且与.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);

}

其他资源

于 2014-07-23T15:59:09.530 回答
0

从这个链接尝试 CodeIgniter Text helper 阅读关于 convert_accented_characters() 函数,它可以被定制

于 2012-02-20T11:42:30.323 回答
0

我不需要写太多,它很好用:

<?php
$dir_name = mb_convert_encoding("Depósito", "ISO-8859-1", "UTF-8");
mkdir($dir_name);
?>
于 2019-01-10T09:51:06.353 回答