Windows服务器上的PHP7 UTF-8文件名,由ZipArchive引起的新现象

标签 php windows utf-8 filenames php-7

更新:

为使PHP 7成为可能的优秀人员准备一个错误报告,我再次修改了研究并将其分解为几行简单的代码。这样做时,我发现PHP本身不是问题的原因。完成后,我将在这里分享我的结果。只是为了您知道并且不要浪费您的时间或其他:)

简介:PHP7现在似乎可以写入UTF-8文件名,但无法访问它们?

序言:我在这里阅读了大约10到15篇涉及该主题的文章,但是它们并没有帮助我解决问题,而且它们都早于PHP7版本。在我看来,这可能是一个新问题,我想知道它是否可能是一个错误。我花了很多时间尝试对字符串进行编码/解码,并试图找到一种使之工作的方法-无济于事。

祝大家有美好的一天,并收到德国的问候(在这里插入害羞的非我本国语言的备注),希望您能对我遇到的这种新现象有所帮助。从PHP 7附带的意义上来说,它似乎是“新的”。

我认为大多数在Windows系统上使用PHP的人都非常熟悉文件名的问题以及PHP的透明包装,该包装管理对具有非ASCII文件名的文件(或Windows-1252或系统代码页)的访问。

我不太确定该如何处理该主题,如您所见,我对撰写问题的经验还不是很丰富,所以请不要立即动脑筋。是的,我会努力保持简短。开始了:

第一个症状:更新到PHP7后,有时我在访问由我的软件生成的文件时遇到问题。有时它像往常一样工作,有时却不行。我发现不同之处在于,PHP7现在似乎可以写入UTF-8文件名,但无法访问具有这些名称的文件。

在两个单独的“相同”系统(仅在PHP版本中有所不同)上生成了所述文件后,这就是在硬盘驱动器上命名文件的方式:

PHP 5.5:Lokaltest_KG_æ¼¢å—_汉å—_Krmmhold-DEZ1604-140081-complete.zip

PHP 7:Lokaltest_KG_汉字_汉字_Krümhold-DEZ1604-140081-complete.zip

出色,PHP 7能够在HDD上编写unicode文件名,而在Windows afaik上使用UTF-16。现在的缺点是,当我尝试使用is_file()访问这些文件时,PHP 5.5可以运行,而PHP 7则不能。

考虑一下此代码段(注意:我“侵入”了此函数,因为这是最简单的方法,并非出于此目的而编写的)。在生成一个zip文件后,将使用客户的名称和其他值来确定适当的名称,然后调用此函数。那些从数据库出来。 PHP的数据库和内部编码均为UTF-8。 clearstatcache本身不是必需的,但我将其包括在内以使情况更清楚。 重要:发生的所有事情都由PHP7完成,没有其他实体负责创建zip文件。确切地说,它是使用class ZipArchive完成的。实际上,即使它是zip归档也无关紧要,关键是文件名和文件内容是由PHP7成功创建的。

public static function downloadFileAsStream( $file )
{
    clearstatcache();
    print $file . "<br/>";
    var_dump(is_file($file));
    die();
}       

输出为:
D:/htdocs/otm/.data/_tmp/Lokaltest_KG_漢字_汉字_Krümhold-DEZ1604-140081-complete.zip
bool(false) 

因此,PHP7能够生成文件-它们确实确实存在于硬盘驱动器上,并且合法,可访问且全部可用-但无法访问它们。 is_file不是唯一失败的函数,例如file_exists()也会失败。

进行编码转换的小实验,让您体验一下我尝试过的事情:
public static function downloadFileAsStream( $file )
{
    clearstatcache();
    print $file . "<br/>";
    print mb_detect_encoding($file, 'ASCII,UTF-16,windows-1252,UTF-8', false) . "<br/>";
    print mb_detect_encoding($file, 'ASCII,UTF-16,windows-1252,UTF-8', true) . "<br/>";

    if (($detectedEncoding = mb_detect_encoding($file, 'ASCII,UTF-16,windows-1252,UTF-8', true)) != 'windows-1252')
    {
        $file = mb_convert_encoding($file, 'UTF-16', $detectedEncoding);
    }

    print $file . "<br/>";
    var_dump(is_file($file));
    die();
}       

输出为:
D:/htdocs/otm/.data/_tmp/Lokaltest_KG_漢字_汉字_Krümhold-DEZ1604-140081-complete.zip
UTF-8
UTF-8
D:/htdocs/otm/.data/_tmp/Lokaltest_KG_o"[W_lI[W_Kr�mhold-DEZ1604-140081-complete.zip
NULL 

因此,从UTF-8(数据库/内部编码)转换为UTF-16(Windows文件系统)似乎也不起作用。

我在这里处于尽头,可悲的是,对于我们来说,这个问题非常重要,因为我们无法在后台出现此问题的情况下更新系统。我希望有人可以对此有所了解。抱歉,很长的帖子,我不确定我能不能很好地理解我的观点。

添加:
$file = utf8_decode($file);
var_dump(is_file($file));
die();

为带有日语字母的文件名提供false。当我更改用于创建文件名的输入时,使文件名现在为Lokaltest_KG_Krümhold-DEZ1604-140081-complete.zip,上面的代码可以实现。因此,utf8_decode会有所帮助,但只能使用一小部分unicode(德国变音符)吗?

最佳答案

在这里回答我自己的问题:真正的坏男孩是ZipArchive组件,该组件使用错误的文件名编码创建了文件。我写了一个希望有用的错误报告:https://bugs.php.net/bug.php?id=72200

考虑以下简短脚本:

print "php default_charset: ".ini_get('default_charset')."\n"; // just 4 info (UTF-8)

$filename = "bugtest_müller-lüdenscheid.zip"; // just an example
$filename = utf8_encode($filename); // simulating my database delivering utf8-string

$zip = new ZipArchive();
if( $zip->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true )
{
    $zip->addFile('bugtest.php', 'bugtest.php'); // copy of script file itself
    $zip->close();
}

var_dump( is_file($filename) );  // delivers ?

输出:
output PHP 5.5.35:
    php default_charset: UTF-8
    bool(true)

output PHP 7.0.6:
    php default_charset: UTF-8
    bool(false)

关于Windows服务器上的PHP7 UTF-8文件名,由ZipArchive引起的新现象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37138463/

相关文章:

php - PHP中的单选按钮和搜索文本框

php - XAMPP错误: MySQL shutdown unexpectedly

php - Python RESTful 客户端,例如来自 PHP 的 Guzzle

c - C 中的内存管理(分配)

java - character_result_set 在 mysql 中为空

unicode - UTF-8编码为什么前缀10?

php - 如何删除特定页面的缓存

windows - 如何让我的安装程序将 Visual Studio 2013 (VC120) 运行时部署到 Windows XP?

python - 如何使用 windows python ping 服务器/网站?

browser - unicode box-drawing 在浏览器中无法正确呈现