PHP7 Windows 服务器上的 UTF-8 文件名,由 ZipArchive 引起的新现象
PHP7 UTF-8 filenames on Windows server, new phenomenon caused by ZipArchive
更新:
准备向使 PHP 7 成为可能的伟人报告错误 我再次修改了我的研究,并试图将其分解为几行简单的代码。在执行此操作时,我发现 PHP 本身并不是问题的原因。完成后,我会在这里分享我的结果。只是想让你知道,不要浪费你的时间什么的:)
概要:PHP7 现在似乎可以写入 UTF-8 文件名但无法访问它们?
序言:我在这里阅读了大约 10-15 篇涉及该主题的文章,但它们并没有帮助我解决问题,而且它们都比 PHP7 版本早。在我看来,这可能是一个新问题,我想知道它是否可能是一个错误。我花了很多时间试验 en-/decoding 个字符串,并试图找出一种方法让它工作 - 但无济于事。
大家好,来自德国的问候(在这里插入害羞的非我的母语评论),我希望你能帮助我解决我遇到的这个新现象。从 PHP 7 附带的意义上说,它似乎是 "new"。
我认为大多数在 Windows 系统上使用 PHP 的人都非常熟悉文件名问题和 PHP 的透明包装器,它管理对没有权限的文件的访问-ASCII 文件名(或 windows-1252 或任何系统代码页)。
我不太确定如何处理这个主题,正如您所看到的,我在撰写问题方面不是很有经验,所以请不要立即撕毁我的脑袋。是的,我会努力保持简短。我们开始吧:
第一个症状:更新到 PHP7 后,我有时会在访问我的软件生成的文件时遇到问题。有时它像往常一样工作,有时则不然。我发现不同之处在于 PHP7 现在似乎能够写入 UTF-8 文件名,但无法访问具有这些名称的文件。
在两个独立的 "identical" 系统(仅 PHP 版本不同)生成上述文件后,文件在硬盘上的命名方式如下:
PHP 5.5: Lokaltest_KG_æ¼¢å—_汉å—_Krümhold-DEZ1604-140081-complete.zip
PHP 7: Lokaltest_KG_汉字_汉字_Krümhold-DEZ1604-140081-complete.zip
很棒,PHP 7 能够在 HDD 上写入 unicode 文件名,并且在 windowsafaik 上使用 UTF-16。现在的缺点是,当我尝试访问这些文件时,例如 is_file()
PHP 5.5 有效,但 PHP 7 无效。
考虑这个代码片段(注意:我"hacked"进入这个函数是因为它是最简单的方法,它不是为此目的而编写的)。在生成一个 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(database/internal 编码)转换为 UTF-16(windows 文件系统)似乎也不起作用。
我已经无能为力了,遗憾的是这个问题对我们来说非常重要,因为我们无法在后台出现这个问题的情况下更新我们的系统。我希望有人能对此有所了解。很抱歉 post,我不确定我的观点能否得到很好的理解。
加法:
$file = utf8_decode($file);
var_dump(is_file($file));
die();
为包含日文字母的文件名提供 false。当我更改用于创建文件名的输入时,文件名现在是 Lokaltest_KG_Krümhold-DEZ1604-140081-complete.zip 上面的代码提供了 true。所以 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)
更新:
准备向使 PHP 7 成为可能的伟人报告错误 我再次修改了我的研究,并试图将其分解为几行简单的代码。在执行此操作时,我发现 PHP 本身并不是问题的原因。完成后,我会在这里分享我的结果。只是想让你知道,不要浪费你的时间什么的:)
概要:PHP7 现在似乎可以写入 UTF-8 文件名但无法访问它们?
序言:我在这里阅读了大约 10-15 篇涉及该主题的文章,但它们并没有帮助我解决问题,而且它们都比 PHP7 版本早。在我看来,这可能是一个新问题,我想知道它是否可能是一个错误。我花了很多时间试验 en-/decoding 个字符串,并试图找出一种方法让它工作 - 但无济于事。
大家好,来自德国的问候(在这里插入害羞的非我的母语评论),我希望你能帮助我解决我遇到的这个新现象。从 PHP 7 附带的意义上说,它似乎是 "new"。
我认为大多数在 Windows 系统上使用 PHP 的人都非常熟悉文件名问题和 PHP 的透明包装器,它管理对没有权限的文件的访问-ASCII 文件名(或 windows-1252 或任何系统代码页)。
我不太确定如何处理这个主题,正如您所看到的,我在撰写问题方面不是很有经验,所以请不要立即撕毁我的脑袋。是的,我会努力保持简短。我们开始吧:
第一个症状:更新到 PHP7 后,我有时会在访问我的软件生成的文件时遇到问题。有时它像往常一样工作,有时则不然。我发现不同之处在于 PHP7 现在似乎能够写入 UTF-8 文件名,但无法访问具有这些名称的文件。
在两个独立的 "identical" 系统(仅 PHP 版本不同)生成上述文件后,文件在硬盘上的命名方式如下:
PHP 5.5: Lokaltest_KG_æ¼¢å—_汉å—_Krümhold-DEZ1604-140081-complete.zip
PHP 7: Lokaltest_KG_汉字_汉字_Krümhold-DEZ1604-140081-complete.zip
很棒,PHP 7 能够在 HDD 上写入 unicode 文件名,并且在 windowsafaik 上使用 UTF-16。现在的缺点是,当我尝试访问这些文件时,例如 is_file()
PHP 5.5 有效,但 PHP 7 无效。
考虑这个代码片段(注意:我"hacked"进入这个函数是因为它是最简单的方法,它不是为此目的而编写的)。在生成一个 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(database/internal 编码)转换为 UTF-16(windows 文件系统)似乎也不起作用。
我已经无能为力了,遗憾的是这个问题对我们来说非常重要,因为我们无法在后台出现这个问题的情况下更新我们的系统。我希望有人能对此有所了解。很抱歉 post,我不确定我的观点能否得到很好的理解。
加法:
$file = utf8_decode($file);
var_dump(is_file($file));
die();
为包含日文字母的文件名提供 false。当我更改用于创建文件名的输入时,文件名现在是 Lokaltest_KG_Krümhold-DEZ1604-140081-complete.zip 上面的代码提供了 true。所以 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)