更新:
为使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/