PHP读取ZIP文件中JSON数据及子目录内容问题求助
问题描述
我尝试通过PHP读取远程ZIP文件中的JSON数据,但无法成功获取。现有代码用ZipArchive打开远程ZIP链接,尝试读取index.json,同时需要读取ZIP内Objects文件夹及其子目录下的所有JSON文件。另外我有一段将ZIP解压到FTP后可正常运行的代码,希望能解决直接读取ZIP内所有JSON数据的问题。
现有远程读取代码
$url = 'https://website.com/wb9f4a8e744a1'; // 点击该链接会下载ZIP文件 $z = new ZipArchive(); if ($z->open($url)) { $json = $z->getFromName("index.json"); if ($json) { // 解析JSON数组 $json_array = json_decode($json); var_dump($json_array); } }
ZIP文件结构
index.json Objects/ // 需要读取该文件夹及其子目录下的文件 2/9/289892.json 4/z/24522.json v/9a/45582.json
解压到FTP后可运行的代码
$data = file_get_contents($url); $characters = json_decode($data); foreach ($characters as $character) { echo $character->label . '<br>'; $dossier = 'objects/' . $character->file; $data2 = file_get_contents($dossier); $characters2 = json_decode($data2, true); }
解决方案
1. 排查远程ZIP读取失败原因
ZipArchive::open()直接读取远程URL需要满足两个前提:
- PHP配置中
allow_url_fopen必须开启 - 服务器支持HTTP流包装器(大部分环境默认支持)
可以添加错误排查代码定位问题:
$url = 'https://website.com/wb9f4a8e744a1'; $z = new ZipArchive(); $openResult = $z->open($url); if ($openResult !== true) { switch ($openResult) { case ZipArchive::ER_OPEN: echo '无法打开文件'; break; case ZipArchive::ER_READ: echo '读取文件错误'; break; case ZipArchive::ER_NOZIP: echo '不是有效的ZIP文件'; break; default: echo '打开失败,错误码:' . $openResult; } exit; }
2. 遍历ZIP内所有JSON文件(含子目录)
如果能成功打开ZIP,可遍历所有条目,筛选出目标文件:
$url = 'https://website.com/wb9f4a8e744a1'; $z = new ZipArchive(); if ($z->open($url) === true) { // 读取index.json $indexJson = $z->getFromName('index.json'); if ($indexJson) { $indexData = json_decode($indexJson); echo 'index.json解析结果:<br>'; var_dump($indexData); } else { echo '未找到index.json<br>'; } // 遍历Objects目录下的JSON文件 echo '<br>Objects目录下的JSON数据:<br>'; for ($i = 0; $i < $z->numFiles; $i++) { $filename = $z->getNameIndex($i); // 筛选Objects目录下的.json文件 if (str_starts_with($filename, 'Objects/') && pathinfo($filename, PATHINFO_EXTENSION) === 'json') { $jsonContent = $z->getFromIndex($i); if ($jsonContent) { $jsonData = json_decode($jsonContent, true); echo '<br>文件:' . $filename . '<br>'; var_dump($jsonData); } } } $z->close(); } else { echo '无法打开远程ZIP文件'; }
3. 备选方案:先下载ZIP到本地再处理
如果直接远程读取失败,可先将ZIP下载到临时目录,兼容性更好:
$url = 'https://website.com/wb9f4a8e744a1'; $tempZip = tempnam(sys_get_temp_dir(), 'remote_zip'); // 下载ZIP到临时文件 if (copy($url, $tempZip)) { $z = new ZipArchive(); if ($z->open($tempZip) === true) { // 读取index.json $indexJson = $z->getFromName('index.json'); if ($indexJson) { $indexData = json_decode($indexJson); var_dump($indexData); } // 遍历Objects目录下的JSON for ($i = 0; $i < $z->numFiles; $i++) { $filename = $z->getNameIndex($i); if (str_starts_with($filename, 'Objects/') && pathinfo($filename, PATHINFO_EXTENSION) === 'json') { $jsonContent = $z->getFromIndex($i); $jsonData = json_decode($jsonContent, true); var_dump($jsonData); } } $z->close(); } // 删除临时文件 unlink($tempZip); } else { echo '无法下载远程ZIP文件'; }
4. 适配解压后代码的逻辑
如果要沿用解压后代码的逻辑(通过index.json里的file字段找对应文件),可直接在ZIP内读取对应路径:
$url = 'https://website.com/wb9f4a8e744a1'; $z = new ZipArchive(); if ($z->open($url) === true) { $indexJson = $z->getFromName('index.json'); if ($indexJson) { $characters = json_decode($indexJson); foreach ($characters as $character) { echo $character->label . '<br>'; // 注意ZIP内路径大小写敏感,要和实际目录名保持一致 $filePath = 'Objects/' . $character->file; $jsonContent = $z->getFromName($filePath); if ($jsonContent) { $characters2 = json_decode($jsonContent, true); var_dump($characters2); } else { echo '未找到文件:' . $filePath . '<br>'; } } } $z->close(); }
注意:ZIP内的路径大小写敏感,要和实际ZIP中的
Objects/保持一致,解压后代码用的objects/是小写,可能是因为FTP服务器不区分大小写,但ZIP内是严格区分的。
内容的提问来源于stack exchange,提问作者Fabien
相关产品推荐
相关产品推荐

