当前位置: 首页> 最新文章列表> 为什么使用 zip_read() 获取的条目在读取内容时会报错?

为什么使用 zip_read() 获取的条目在读取内容时会报错?

M66 2025-06-12

在使用 PHP 的 Zip 扩展处理 ZIP 压缩包时,zip_read()zip_entry_read() 是两个经常一起配合使用的函数。然而,很多开发者在实际使用时,遇到了一个令人困惑的问题:用 zip_read() 迭代条目,再通过 zip_entry_read() 读取内容时,会报错,甚至返回空内容或乱码。这是什么原因导致的?本文将深入分析原因并给出解决方案。

问题重现

考虑下面这段代码:

$zip = zip_open('http://m66.net/test.zip');
if (is_resource($zip)) {
    while ($entry = zip_read($zip)) {
        echo '正在读取文件: ' . zip_entry_name($entry) . PHP_EOL;
        if (zip_entry_open($zip, $entry)) {
            $contents = zip_entry_read($entry);
            echo $contents . PHP_EOL;
            zip_entry_close($entry);
        }
    }
    zip_close($zip);
}

运行上述代码时,有可能会出现如下错误:

Warning: zip_entry_read(): supplied resource is not a valid Zip Entry resource in...

或者读取到的内容为空,完全不符合预期。

原因分析

这个问题的根源通常是以下几点之一:

1. 文件路径是 URL 而非本地路径

尽管 zip_open() 支持传入一个文件路径,但它不一定支持远程 URL。如上例中使用的是 http://m66.net/test.zip,这取决于你的 PHP 是否启用了 allow_url_fopen,以及底层的 ZIP 扩展是否支持从流资源正确读取 ZIP 数据。大多数情况下,zip_open() 要求是一个可直接 seek 的本地文件。

2. zip_entry_read() 的调用方式错误

zip_entry_read() 需要明确指定读取的长度。如果不指定长度,它会默认读取 1024 字节,这在文件较大时会导致内容不完整;而如果文件为空或位置不正确,则可能直接失败。

3. 条目未成功打开或资源无效

使用 zip_entry_open() 打开条目时,如果失败,随后的 zip_entry_read() 将无法执行。此外,某些版本的 PHP 在多个条目间切换读取时存在兼容性问题,尤其是在压缩方式非 STORE 或 DEFLATE 的情况下。

正确做法

为确保 ZIP 条目能正确读取,应遵循以下步骤:

$localFile = 'test.zip';
copy('http://m66.net/test.zip', $localFile); // 将远程文件下载到本地

$zip = zip_open($localFile);
if (is_resource($zip)) {
    while ($entry = zip_read($zip)) {
        $name = zip_entry_name($entry);
        echo "读取文件: $name" . PHP_EOL;

        if (zip_entry_open($zip, $entry)) {
            $size = zip_entry_filesize($entry);
            $contents = zip_entry_read($entry, $size);
            echo "内容: " . PHP_EOL . $contents . PHP_EOL;

            zip_entry_close($entry);
        } else {
            echo "无法打开条目: $name" . PHP_EOL;
        }
    }
    zip_close($zip);
}

这里有几个关键点:

总结

使用 zip_read() 报错的主要原因,通常是资源打开方式不正确、未正确指定读取长度或远程路径处理不当。建议始终使用本地文件路径,并配合 zip_entry_filesize() 精确读取内容。如果有更高的需求,也可以考虑使用 ZipArchive 类,它提供了更高级、稳定的接口。

通过正确的流程,可以让 ZIP 文件的读取变得更加安全、稳定、高效。