PHP Conference Japan 2024

ZipArchive::open

(PHP 5 >= 5.2.0, PHP 7, PHP 8, PECL zip >= 1.1.0)

ZipArchive::open打开一个 ZIP 文件归档

描述

public ZipArchive::open(字符串 $filename, 整数 $flags = 0): 布尔值|整数

打开一个新的或现有的 zip 归档文件以进行读取、写入或修改。

从 libzip 1.6.0 开始,空文件不再是有效的归档文件。

参数

filename

要打开的 ZIP 归档文件的名称。

flags

用于打开归档文件的模式。

返回值

成功时返回 true,错误时返回 false 或以下错误代码之一

ZipArchive::ER_EXISTS
文件已存在。
ZipArchive::ER_INCONS
Zip 归档文件不一致。
ZipArchive::ER_INVAL
无效的参数。
ZipArchive::ER_MEMORY
内存分配失败。
ZipArchive::ER_NOENT
没有这样的文件。
ZipArchive::ER_NOZIP
不是 zip 归档文件。
ZipArchive::ER_OPEN
无法打开文件。
ZipArchive::ER_READ
读取错误。
ZipArchive::ER_SEEK
查找错误。

范例

示例 #1 打开并提取

<?php
$zip
= new ZipArchive;
$res = $zip->open('test.zip');
if (
$res === TRUE) {
echo
'ok';
$zip->extractTo('test');
$zip->close();
} else {
echo
'failed, code:' . $res;
}
?>

示例 #2 创建一个归档文件

<?php
$zip
= new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
if (
$res === TRUE) {
$zip->addFromString('test.txt', 'file content goes here');
$zip->addFile('data.txt', 'entryname.txt');
$zip->close();
echo
'ok';
} else {
echo
'failed';
}
?>

示例 #3 创建一个临时归档文件

<?php
$name
= tempnam(sys_get_temp_dir(), "FOO");
$zip = new ZipArchive;
$res = $zip->open($name, ZipArchive::OVERWRITE); /* 作为空文件无效,将其截断 */
if ($res === TRUE) {
$zip->addFile('data.txt', 'entryname.txt');
$zip->close();
echo
'ok';
} else {
echo
'failed';
}
?>
添加注释

用户贡献的注释 20 条注释

eric at webdeveric dot com
15 年前
使用 php 5.2.6,以下代码创建了一个新的 zip 或替换了一个现有的 zip。
请注意,我只使用了 ZIPARCHIVE::OVERWRITE 标志。

<?php
$zip
= new ZipArchive();
$opened = $zip->open( $zipFileName, ZIPARCHIVE::OVERWRITE );
if(
$opened !== true ){
die(
"无法打开 {$zipFileName} 以进行写入。");
}
$zip->addFromString( $name, $contents );
$zip->close();
?>

现在,使用 php 5.2.8,它不起作用并给出以下警告

警告:ZipArchive::addFromString() [ziparchive.addfromstring]:在 [myfile] 的 [myline] 行上,Zip 对象无效或未初始化

要解决此问题,您必须将标志指定为创建或覆盖。

<?php
$zip
= new ZipArchive();
$opened = $zip->open( $zipFileName, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE );
if(
$opened !== true ){
die(
"无法打开 {$zipFileName} 进行写入.");
}
$zip->addFromString( $name, $contents );
$zip->close();
?>

在谷歌搜索错误信息时,我发现很多人遇到了同样的问题,但无法弄清楚原因。
希望这对某些人有所帮助。
abolfazl dot ziaratban at gmail dot com
9年前
<?php
#由abolfazl ziaratban创作 (c)
#许可证 GPL

class zip extends ZipArchive
{
public function
message($code)
{
switch (
$code)
{
case
0:
return
'没有错误';

case
1:
return
'不支持多磁盘zip档案';

case
2:
return
'重命名临时文件失败';

case
3:
return
'关闭zip档案失败';

case
4:
return
'查找错误';

case
5:
return
'读取错误';

case
6:
return
'写入错误';

case
7:
return
'CRC错误';

case
8:
return
'包含的zip档案已关闭';

case
9:
return
'没有此文件';

case
10:
return
'文件已存在';

case
11:
return
'无法打开文件';

case
12:
return
'无法创建临时文件';

case
13:
return
'Zlib错误';

case
14:
return
'内存分配失败';

case
15:
return
'条目已更改';

case
16:
return
'不支持的压缩方法';

case
17:
return
'文件结尾过早';

case
18:
return
'无效的参数';

case
19:
return
'不是zip档案';

case
20:
return
'内部错误';

case
21:
return
'zip档案不一致';

case
22:
return
'无法删除文件';

case
23:
return
'条目已被删除';

default:
return
'发生了未知错误('.intval($code).')';
}
}

public function
isDir($path)
{
return
substr($path,-1) == '/';
}

public function
getTree()
{
$Tree = array();
$pathArray = array();
for(
$i=0; $i<$this->numFiles; $i++)
{
$path = $this->getNameIndex($i);
$pathBySlash = array_values(explode('/',$path));
$c = count($pathBySlash);
$temp = &$Tree;
for(
$j=0; $j<$c-1; $j++)
if(isset(
$temp[$pathBySlash[$j]]))
$temp = &$temp[$pathBySlash[$j]];
else
{
$temp[$pathBySlash[$j]] = array();
$temp = &$temp[$pathBySlash[$j]];
}
if(
$this->isDir($path))
$temp[$pathBySlash[$c-1]] = array();
else
$temp[] = $pathBySlash[$c-1];
}
return
$Tree;
}
}
?>
Fred Johnson
4年前
请注意,ZipArchive不支持生成流式ZIP文件内容(即,在开始生成数据(例如从数据库中)时立即开始向用户发送数据)。这意味着您必须首先将整个文件写入磁盘,然后将文件发送给用户。根据数据量的大小,这可能需要一段时间,并且可能会超出服务器超时限制。

GitHub上有一些可用的PHP用户库可以将ZIP文件内容流式传输到用户,只要任何数据写入相关类即可。

cubiclesoft/php-zipstreamwriter
maennchen/ZipStream-PHP

也许ZipArchive的未来版本将提供类似的功能。
jj at icglink dot com
16年前
如果您正在输出输出并对数字感到困惑...也许这会有所帮助。但我也不确定它是否准确。

ZIPARCHIVE::ER_EXISTS - 10
ZIPARCHIVE::ER_INCONS - 21
ZIPARCHIVE::ER_INVAL - 18
ZIPARCHIVE::ER_MEMORY - 14
ZIPARCHIVE::ER_NOENT - 9
ZIPARCHIVE::ER_NOZIP - 19
ZIPARCHIVE::ER_OPEN - 11
ZIPARCHIVE::ER_READ - 5
ZIPARCHIVE::ER_SEEK - 4
jekillen at prodigy net
9年前
调用ZipArchive->open()不会创建空的zip档案文件。
我以惨痛的教训发现了这一点。我编写了产生积极
结果的代码:例如,对ZipArchive的调用的返回值为TRUE
并且未创建空zip文件。因此,至少调用
ZipArchive->addFromString(<filename.zip>, '<minimal content>')
在创建新的zip档案文件时。
ohcc at 163 dot com
9年前
<?php
// 当目标文件不存在时使用ZipArchive::OVERWRITE可能会导致类似这样的错误
// Warning: ZipArchive::addFile(): Invalid or uninitialized Zip object
// 当您想要替换可能不存在的zip档案时,请尝试使用ZipArchive::OVERWRITE|ZipArchive::CREATE
$zip = new ZipArchive;
$rt=$zip->open('i.zip',ZipArchive::OVERWRITE);
echo
$rt;
// 当i.zip不存在时,$rt为9,ZipArchive::ER_NOENT,或"没有此文件".
$zip->addFile('wuxiancheng.cn.sql','db.sql');
// 触发错误,消息为"Warning: ZipArchive::addFile(): Invalid or uninitialized Zip object ..."


// 使用ZipArchive::OVERWRITE|ZipArchive::CREATE
$zip = new ZipArchive;
$zip->open('i.zip',ZipArchive::OVERWRITE|ZipArchive::CREATE);
$zip->addFile('wuxiancheng.cn.sql','db.sql');
?>
walter at clevertechie dot com
12年前
如果您有要覆盖的档案,只需使用

ZIPARCHIVE::CREATE

它将覆盖现有的档案,并在档案不存在时创建新的档案。

ZIPARCHIVE::OVERWRITE不会同时适用于这两种情况。

(PHP版本5.4.4)
Jan Vavra
13年前
http://bugs.php.net/bug.php?id=54128中所述,在Windows Server系统(2003、2008)和IIS上,当您想要解压缩存储在C:\Windows\Temp文件夹中的文件时会出现问题。
工作进程IUSR_XXX的用户对C:\Windows\Temp没有目录列表权限,这是ZipArchive::open()以错误11(打开错误)失败的原因。因此,将要解压缩的文件存储在sys_get_temp_dir()定义的文件夹中不是一个好主意。

sunil dt bhave at gmail dt com
13年前
尽管 API 说明这些标志是可选的,但我发现必须指定标志 ZIPARCHIVE::CREATE 才能打开一个存档。
这是在安装了 PHP 5.3.0 的 Windows 7 系统上。
rickky at gmail dot com
17 年前
如果您要写入或保存到的目录没有设置正确的权限,您将不会收到任何错误消息,并且看起来一切正常……除了它没有改变!

相反,请确保您收集 ZipArchive::close() 的返回值。如果它是 false……则表示它没有成功。
Eric Langlois
10 年前
<?PHP
$zip
= new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);

if (
$res === TRUE) {
//代码在此处

$zip->close();
} else {
switch(
$res){
case
ZipArchive::ER_EXISTS:
$ErrMsg = "文件已存在。";
break;

case
ZipArchive::ER_INCONS:
$ErrMsg = "Zip 存档不一致。";
break;

case
ZipArchive::ER_MEMORY:
$ErrMsg = "内存分配失败。";
break;

case
ZipArchive::ER_NOENT:
$ErrMsg = "没有此文件。";
break;

case
ZipArchive::ER_NOZIP:
$ErrMsg = "不是 Zip 存档。";
break;

case
ZipArchive::ER_OPEN:
$ErrMsg = "无法打开文件。";
break;

case
ZipArchive::ER_READ:
$ErrMsg = "读取错误。";
break;

case
ZipArchive::ER_SEEK:
$ErrMsg = "查找错误。";
break;

default:
$ErrMsg = "未知(代码 $rOpen)";
break;


}
die(
'ZipArchive 错误: ' . $ErrMsg);
}
?>
ohcc at 163 dot com
8 年前
ZipArchive::OVERWRITE 并不意味着当调用 ZipArchive::open() 时现有文件将被删除。

实际上,在 PHP 将 zip 存档保存到磁盘之前,现有文件将被删除。

PHP 执行以下步骤完成压缩

1. 当调用 ZipArchive::open('xx.zip') 时
如果 'xx.zip' 存在并且是 zip 存档,它将被打开并作为临时 zip 文件读取,
如果文件不存在,并且应用了 ZipArchive::CREATE,php 将创建一个临时的空 zip 文件
在这些情况下,ZipArchive::open() 返回 true,否则返回一个整数错误代码。
2. 当调用 addFile()、addFromString() 等方法时,将文件添加到临时 zip 文件中。
3. 在将临时 zip 文件保存到磁盘之前,删除现有文件。
4. 将临时 zip 文件保存到磁盘
5. 当调用 ZipArchive::close() 或在脚本结束时关闭活动存档

由于 PHP 不会在将 zip 存档保存到磁盘之前删除现有文件,因此如果您想压缩该文件包含的文件夹并将 zip 存档保存到该文件夹中,则应使用 unset() 删除它,否则每次刷新页面时,您都会得到一个越来越大的 zip 存档。
ohcc at 163 dot com
9年前
ZipArchive::open() 的返回值及其值和含义
ZipArchive::ER_SEEK 4 查找错误。
ZipArchive::ER_READ 5 读取错误。
ZipArchive::ER_NOENT 9 没有此文件。
ZipArchive::ER_OPEN 11 无法打开文件。
ZipArchive::ER_EXISTS 10 文件已存在。
ZipArchive::ER_MEMORY 14 内存分配失败。
ZipArchive::ER_INVAL 18 无效参数。
ZipArchive::ER_NOZIP 19 不是 Zip 存档。
ZipArchive::ER_INCONS 21 Zip 存档不一致
laacz at laacz dot lv
3 年前
如果在 PHP 8.0+ 上,您可以使用匹配表达式来解码状态代码

<?php
$archive
= new \ZipArchive();
$result = $archive->open('some.file.zip');

$message = match ($result) {
\ZipArchive::ER_MULTIDISK => '不支持多磁盘 zip 存档',
\ZipArchive::ER_RENAME => '重命名临时文件失败',
\ZipArchive::ER_CLOSE => '关闭 zip 存档失败',
\ZipArchive::ER_SEEK => '查找错误',
\ZipArchive::ER_READ => '读取错误',
\ZipArchive::ER_WRITE => '写入错误',
\ZipArchive::ER_CRC => 'CRC 错误',
\ZipArchive::ER_ZIPCLOSED => '包含的 zip 存档已关闭',
\ZipArchive::ER_NOENT => '没有此文件',
\ZipArchive::ER_EXISTS => '文件已存在',
\ZipArchive::ER_OPEN => '无法打开文件',
\ZipArchive::ER_TMPOPEN => '无法创建临时文件',
\ZipArchive::ER_ZLIB => 'Zlib 错误',
\ZipArchive::ER_MEMORY => '内存分配失败',
\ZipArchive::ER_CHANGED => '条目已更改',
\ZipArchive::ER_COMPNOTSUPP => '不支持的压缩方法',
\ZipArchive::ER_EOF => '文件过早结束',
\ZipArchive::ER_INVAL => '无效参数',
\ZipArchive::ER_NOZIP => '不是 Zip 存档',
\ZipArchive::ER_INTERNAL => '内部错误',
\ZipArchive::ER_INCONS => 'Zip 存档不一致',
\ZipArchive::ER_REMOVE => '无法删除文件',
\ZipArchive::ER_DELETED => '条目已删除',
// \ZipArchive::ER_OK => '没有错误',
default => '没有错误',
};
?>
Anonymous
3 年前
要读取 zip 文件内容,然后使用 $zip->numFiles 循环遍历 $zip->getNameIndex(i)

例如

$zipfilename=$dir.DIRECTORY_SEPARATOR."test.zip";
$zippedFile = new ZipArchive;
$zippedFile->open($zipfilename);

echo "<LI>".$zippedFile->getFromName("mpdf-8.0.7/.gitignore")."</LI><HR>";

echo "<LI>加载 $zipfilename ".$zippedFile->numFiles;
for($i = 0; $i < $zippedFile->numFiles; $i++) {
$fn=$zippedFile->getNameIndex($i);
echo "<LI>$i: ".$fn;

if ( strcmp(substr($fn, -1), DIRECTORY_SEPARATOR )==0 ) echo "... 目录";
else echo "... ".strlen($zippedFile->getFromIndex($i))." 字节";

}
$zippedFile->close();
YiiWanAB at hotmail dot com
13年前
大多数情况下,人们使用 'opendir' 或 'readdir' 迭代目录以将文件添加到 zip 中。例如…

while ($file = readdir($dir)) { ... $zip->addFile($file) }

请注意,如果您的位置在根目录,则 $zip->addFile($file) 仅在当前目录中有效。您需要将正确的路径添加到该 $file 字符串变量中以获得完整的文件名,例如…

$zip->addFile($dir . DIRECTORY_SEPARATOR . $file); 将起作用。

这可能会说明您在关闭文件时可能收到读取错误的原因。

享受。
sebwoolford at gmail dot com
15 年前
补充 rickky at gmail dot com 的说法,我在尝试缓存 zip 文件时遇到了这个问题,发现我必须将包含文件夹的权限设置为 777 才能使其工作。

因为如果在公共可查看文件夹中,这可能是一个潜在的安全漏洞,所以我建议移动该文件夹,使其不再位于 public_html 中。然后,您可以使用 readfile() 将存档输出到浏览器,并使用一些 HTTP 标头告诉浏览器它是一个 zip 文件。
Jonathan Baltazar
16年前
如果使用 tempnam() 创建,文件名不需要以 '.zip' 结尾。您只需要覆盖文件,而不是尝试读取它。

<?php
$file
= tempnam("tmp", "zip");

$zip = new ZipArchive();

// 压缩文件将打开并覆盖文件,而不是尝试读取它。
$zip->open($file, ZipArchive::OVERWRITE);

$zip->close();

// 将文件流传输到客户端
header("Content-Type: application/zip");
header("Content-Length: " . filesize($file));
header("Content-Disposition: attachment; filename=\"a_zip_file.zip\"");
readfile($file);

unlink($file);
?>
[email protected]
15 年前
对于任何人在执行
`$zip->open($zipfile)` 时遇到ZIPARCHIVE::ER_READ = 5 错误,且ZIP文件包含超过(大约)800个文件(即使它们位于子目录中)。

可能相关的错误 40873、8714

1. 这不是操作系统限制,因为当通过同一位置的同一文件的samba从Windows调用时,它可以工作

2. 它在32位Linux下无法工作

在PHP 5.3.0中,此问题似乎已解决。
[email protected]
16年前
<?php

/*
嗨!

我编写了一个关于检查内容和“安全重新打包”的小脚本
*/

$somefile = "zip.zip";
$someurl = "/some/url"
$zip = new ZipArchive;
$open = $zip->open($somefile, ZIPARCHIVE::CHECKCONS);
// 如果归档文件损坏(或只是另一个重命名为*.zip的文件),则该函数将在Windows下的httpd下返回错误,因此最好检查归档文件是否使用ZIPARCHIVE::CHECKCONS正常
if ($open === TRUE) {
if(!
$zip->extractTo($someurl)) {
die (
"Error during extracting");
}
$zip->close();
}
$new_archive_name = "new.zip";
$new_zip = new ZipArchive;
$new_open = $new_zip->open($new_archive_name, ZIPARCHIVE::CREATE);
if (
$new_open === TRUE) {
$dir = opendir($someurl);
while (
$file = readdir($dir)) {
if (
$file == "." || $file == "..") { } else {
// 我们不希望这些文件在新压缩文件中
if (!$new_zip->addFile($file)) {
print
$file."was not added!<br />";
}
}
}
}
$new_zip->close();
?>
To Top