谁承认这种性格腐败?

Who recognizes this character corruption?

我有以下代码:

$files = ftp_nlist($conn_id, "/path/to/files");
$zip = new ZipArchive;
$res = $zip->open('filename.zip', ZipArchive::CREATE);
if ($res === TRUE) {
    foreach ($files as $item) {
        if ($item != '.' && $item != '..') {
            // Get file contents
            ob_start();
            @ftp_get($conn_id, "php://output", "/path/to/files/{$item}", FTP_BINARY);
            $data = ob_get_contents();
            ob_end_clean();
            $zip->addFromString($item, $data);
        }
    }
// ...
}

不幸的是,zip 文件中的文件名已损坏。例如,ßäÄçö.txt 变为 +ƒ+ñ+ä+º+¦.txt。

我假设这可以通过使用 iconv 来解决,但我找不到任何产生所需结果的编码对。据我所知,文件名存储为 UTF-8。当我不压缩文件而只是使用

下载它时
// ...
header("Content-Disposition: attachment; filename*=UTF-8''".rawurlencode($item));
//...
echo $data;

没有字符损坏。

UTF-8 中的“ßäÄçö”编码为 C3 9F C3 A4 C3 84 C3 A7 C3 B6。如果将这些字节读取为 CP-437,则会得到“├ƒ├ñ├ä├º├╢”。如果您更改所有“├"s (C3) to "+”(2B)并将最后一个字符更改为“¦”,则会得到“+ƒ+ñ+ä+º+¦”。

我不知道为什么“├”变成了“+”,也不知道为什么“╢”变成了“¦”。我尝试在 Vim 中保存名为“├ƒ├ñ├ä├º├╢.txt”的文本文件,但它创建了一个名为“+ƒ+ñ+ä+º+¦.txt”的文件。但是当我在记事本中尝试同样的事情时,它创建了正确的文件名“├ƒ├ñ├ä├º├╢.txt”。因此,无论 Zip 文件中的字节发生什么,都与 Vim 所做的相同。

附录 D 中的 Zip File Format Specification 说文件名必须是 CP-437 或 UTF-8,因此您的文件名似乎在某处被视为 CP-437,加上任何其他步骤正在处理字节 C3B6。也许 PHP 的 ZipArchive 有解决方法,或者您可以使用其他 Zip 库。快速搜索 "php ziparchive utf-8" 找到了很多结果,但我没有立即看到解决方案。

我终于在用户贡献的笔记中找到了答案here:

Zip 规范似乎将 IBM437 指定为有效编码。

$encodedFilename = iconv('utf-8', 'IBM437', $filename);
$zip->addFromString($encodedFilename, 'foo');

解决问题。