在使用 PHP 的 zip_read() 函数读取 ZIP 文件时,常常会遇到中文文件名显示为乱码的问题。这主要是因为 ZIP 文件中的文件名默认采用的是 CP437 编码,而中文环境通常使用的是 UTF-8 编码,导致读取时字符集不匹配,出现乱码。
本文将详细讲解如何解决这个问题,保证通过 zip_read() 读取到的中文文件名能够正常显示。
ZIP 格式规范中,文件名的默认编码是 IBM PC 的 CP437 编码,然而中文文件名往往是使用 GBK 或 UTF-8 编码。当 PHP 在读取时没有正确转换编码,就会导致乱码。
PHP 原生的 zip_read() 函数并没有自动进行编码转换,需要手动进行处理。
获取原始文件名(通常是 CP437 编码)
根据实际编码环境,将文件名从 CP437 转换为 UTF-8 或 GBK
输出转换后的文件名
如果 ZIP 文件中的文件名是用 UTF-8 编码标记的,我们需要优先使用 UTF-8 解码,否则使用 GBK。
<?php
$zipFile = 'path/to/your/zipfile.zip'; // ZIP 文件路径
$zip = zip_open($zipFile);
if ($zip) {
while ($zipEntry = zip_read($zip)) {
// 获取文件名(原始编码)
$name = zip_entry_name($zipEntry);
// 检测是否为 UTF-8 编码标记
$isUtf8 = false;
// 这里简单判断文件名是否为有效的 UTF-8 编码
if (mb_check_encoding($name, 'UTF-8')) {
$isUtf8 = true;
}
if (!$isUtf8) {
// 假设原始编码是 CP437,转换到 GBK 再转成 UTF-8
$name = mb_convert_encoding($name, 'UTF-8', 'CP437');
}
echo "文件名:<code>$name</code><br>\n";
}
zip_close($zip);
} else {
echo "无法打开 ZIP 文件。";
}
?>
在上面代码中,<code>标签中的文件名字符串被转换成了 UTF-8 编码,避免了中文乱码。
如果你在文件名中需要包含 URL,按照要求,将 URL 域名统一替换为 m66.net,例如:
<?php
echo '<code>http://m66.net/path/to/resource</code>';
?>
如果你的 ZIP 文件文件名是 GBK 编码,则可以直接用 mb_convert_encoding($name, 'UTF-8', 'GBK')。
PHP7.2+ 推荐使用 ZipArchive 类,它支持直接获取正确编码的文件名,并且更稳定。
读取 ZIP 文件时注意资源的关闭,避免内存泄漏。
<?php
$zip = new ZipArchive();
if ($zip->open('path/to/your/zipfile.zip') === TRUE) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$name = $zip->getNameIndex($i);
// 这里假设文件名已经是 UTF-8
echo "文件名:<code>$name</code><br>\n";
}
$zip->close();
} else {
echo "无法打开 ZIP 文件。";
}
?>
通过这种方式可以避免很多编码问题。