PHPのお勉強!

PHP TOP

ZipArchive::open

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

ZipArchive::openZIP ファイルアーカイブをオープンする

説明

public ZipArchive::open(string $filename, int $flags = 0): bool|int

新しい、または既に存在する 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
'成功';
$zip->extractTo('test');
$zip->close();
} else {
echo
'失敗、コード:' . $res;
}
?>

例2 アーカイブの作成

<?php
$zip
= new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
if (
$res === TRUE) {
$zip->addFromString('test.txt', 'ここにファイルの内容を書きます');
$zip->addFile('data.txt', 'entryname.txt');
$zip->close();
echo
'成功';
} else {
echo
'失敗';
}
?>

例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
'成功';
} else {
echo
'失敗';
}
?>
add a note

User Contributed Notes 20 notes

up
98
eric at webdeveric dot com
15 years ago
With php 5.2.6, the following code created a new zip or replaced a existing zip.
Note that I am only using the ZIPARCHIVE::OVERWRITE flag.

<?php
$zip
= new ZipArchive();
$opened = $zip->open( $zipFileName, ZIPARCHIVE::OVERWRITE );
if(
$opened !== true ){
die(
"cannot open {$zipFileName} for writing.");
}
$zip->addFromString( $name, $contents );
$zip->close();
?>

Now, with php 5.2.8, it does not work and gives this warning:

Warning: ZipArchive::addFromString() [ziparchive.addfromstring]: Invalid or unitialized Zip object in [myfile] on line [myline]

To fix this, you must specify the flags as create or overwrite.

<?php
$zip
= new ZipArchive();
$opened = $zip->open( $zipFileName, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE );
if(
$opened !== true ){
die(
"cannot open {$zipFileName} for writing.");
}
$zip->addFromString( $name, $contents );
$zip->close();
?>

When googling for the error message I found a lot of people that had it but couldn't figure out why they were getting it.
I hope this helps someone.
up
41
abolfazl dot ziaratban at gmail dot com
9 years ago
<?php
#made by abolfazl ziaratban (c)
#license GPL

class zip extends ZipArchive
{
public function
message($code)
{
switch (
$code)
{
case
0:
return
'No error';

case
1:
return
'Multi-disk zip archives not supported';

case
2:
return
'Renaming temporary file failed';

case
3:
return
'Closing zip archive failed';

case
4:
return
'Seek error';

case
5:
return
'Read error';

case
6:
return
'Write error';

case
7:
return
'CRC error';

case
8:
return
'Containing zip archive was closed';

case
9:
return
'No such file';

case
10:
return
'File already exists';

case
11:
return
'Can\'t open file';

case
12:
return
'Failure to create temporary file';

case
13:
return
'Zlib error';

case
14:
return
'Malloc failure';

case
15:
return
'Entry has been changed';

case
16:
return
'Compression method not supported';

case
17:
return
'Premature EOF';

case
18:
return
'Invalid argument';

case
19:
return
'Not a zip archive';

case
20:
return
'Internal error';

case
21:
return
'Zip archive inconsistent';

case
22:
return
'Can\'t remove file';

case
23:
return
'Entry has been deleted';

default:
return
'An unknown error has occurred('.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;
}
}
?>
up
6
Fred Johnson
4 years ago
Note that ZipArchive does not support generating streaming ZIP file content (i.e. start sending data to the user as soon as you start generating it such as from a database). This means you have to write the entire file to disk first and then send the file to the user. Doing that can take a while depending on how much data there is, which could run up against server timeout limits.

There are a couple of PHP userland libraries available on GitHub that can stream ZIP file content out to the user as soon as any data is written to the relevant classes.

cubiclesoft/php-zipstreamwriter
maennchen/ZipStream-PHP

Maybe a future version of ZipArchive will offer something similar.
up
24
jj at icglink dot com
16 years ago
if you are echoing out the output and confused about the number...maybe this will help. i'm not totally sure it is accurate though.

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
up
5
jekillen at prodigy net
9 years ago
Calling ZipArchive->open() will not create an empty zip archive file.
I found this out the hard way. I wrote code that produced positive
results: I.E. the return value from the call to ZipArchive was TRUE
and the empty zip file was not created. So at least call
ZipArchive->addFromString(<filename.zip>, '<minimal content>')
when creating a new zip archive file.
up
12
ohcc at 163 dot com
9 years ago
<?php
// Use ZipArchive::OVERWRITE when the targetd file does not exist may lead you to an error like this
// Warning: ZipArchive::addFile(): Invalid or uninitialized Zip object
// try ZipArchive::OVERWRITE|ZipArchive::CREATE when you want to replace a zip archive that may not exist
$zip = new ZipArchive;
$rt=$zip->open('i.zip',ZipArchive::OVERWRITE);
echo
$rt;
// when i.zip does not exist, $rt is 9, ZipArchive::ER_NOENT, or "No such file."
$zip->addFile('wuxiancheng.cn.sql','db.sql');
// triggers an error with the message "Warning: ZipArchive::addFile(): Invalid or uninitialized Zip object ..."


// Use ZipArchive::OVERWRITE|ZipArchive::CREATE
$zip = new ZipArchive;
$zip->open('i.zip',ZipArchive::OVERWRITE|ZipArchive::CREATE);
$zip->addFile('wuxiancheng.cn.sql','db.sql');
?>
up
16
walter at clevertechie dot com
12 years ago
If you have archives that you want to overwrite just use:

ZIPARCHIVE::CREATE

It will overwrite existing archives and at the same time create new ones if they don't already exist.

ZIPARCHIVE::OVERWRITE won't work for both of these scenarios.

(PHP version 5.4.4)
up
3
Jan Vavra
13 years ago
As discussed in http://bugs.php.net/bug.php?id=54128 on Windows Server systems (2003, 2008) and IIS there is a problem when you want to unzip file stored in C:\Windows\Temp folder.
User of worker process IUSR_XXX has no directory listing right for C:\Windows\Temp and this is a reason why ZipArchive::open() fails with error 11 (error open). So it is not a good idea to store file for unzipping in folder defined by sys_get_temp_dir().
up
3
sunil dt bhave at gmail dt com
13 years ago
Even though the api specifies that the flags are optional I found that I had to specify the flag ZIPARCHIVE::CREATE for an archive to be opened.
This is on a Windows 7 system with PHP 5.3.0
up
5
rickky at gmail dot com
17 years ago
If the directory you are writing or saving into does not have the correct permissions set, you won't get any error messages and it will look like everything worked fine... except it won't have changed!

Instead make sure you collect the return value of ZipArchive::close(). If it is false... it didn't work.
up
3
Eric Langlois
10 years ago
<?PHP
$zip
= new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);

if (
$res === TRUE) {
//CODE GOES HERE

$zip->close();
} else {
switch(
$res){
case
ZipArchive::ER_EXISTS:
$ErrMsg = "File already exists.";
break;

case
ZipArchive::ER_INCONS:
$ErrMsg = "Zip archive inconsistent.";
break;

case
ZipArchive::ER_MEMORY:
$ErrMsg = "Malloc failure.";
break;

case
ZipArchive::ER_NOENT:
$ErrMsg = "No such file.";
break;

case
ZipArchive::ER_NOZIP:
$ErrMsg = "Not a zip archive.";
break;

case
ZipArchive::ER_OPEN:
$ErrMsg = "Can't open file.";
break;

case
ZipArchive::ER_READ:
$ErrMsg = "Read error.";
break;

case
ZipArchive::ER_SEEK:
$ErrMsg = "Seek error.";
break;

default:
$ErrMsg = "Unknow (Code $rOpen)";
break;


}
die(
'ZipArchive Error: ' . $ErrMsg);
}
?>
up
1
ohcc at 163 dot com
9 years ago
ZipArchive::OVERWRITE does NOT mean an existing file would be deleted when ZipArchive::open() is called.

In fact, the existing file will be deleted before PHP saves the zip archive on disk.

PHP takes these steps to finish zipping:

1. When ZipArchive::open('xx.zip') is called
If 'xx.zip' exists and is a zip archive, it will be opened and read as a temporary zip file,
If the file does not exist, and ZipArchive::CREATE is applied, php will create a temporary empty zip file
In these cases, ZipArchive::open() returns true, otherwise it returns an integer error code.
2. Adds file(s) to the temporary zip file when methods such as addFile(), addFromString() are called.
3. Deletes the existing file before saving the temporary zip file on disk.
4. Save the temporary zip file on disk
5. Closes the active archive when ZipArchive::close() is called or at the end of the script

Since PHP does NOT delete the existing file before saving the zip archive on disk, you should use unset() to delete it if you want to zip that file's containing folder and save the zip archive in that folder, otherwise you will get a larger and larger zip archive everytime you refresh the page.
up
1
ohcc at 163 dot com
9 years ago
return values of ZipArchive::open() and their values and meanings
ZipArchive::ER_SEEK 4 Seek error.
ZipArchive::ER_READ 5 Read error.
ZipArchive::ER_NOENT 9 No such file.
ZipArchive::ER_OPEN 11 Can't open file.
ZipArchive::ER_EXISTS 10 File already exists.
ZipArchive::ER_MEMORY 14 Malloc failure.
ZipArchive::ER_INVAL 18 Invalid argument.
ZipArchive::ER_NOZIP 19 Not a zip archive.
ZipArchive::ER_INCONS 21 Zip archive inconsistent
up
2
laacz at laacz dot lv
3 years ago
If on PHP 8.0+, you can use match expression to decode status code:

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

$message = match ($result) {
\ZipArchive::ER_MULTIDISK => 'Multi-disk zip archives not supported',
\ZipArchive::ER_RENAME => 'Renaming temporary file failed',
\ZipArchive::ER_CLOSE => 'Closing zip archive failed',
\ZipArchive::ER_SEEK => 'Seek error',
\ZipArchive::ER_READ => 'Read error',
\ZipArchive::ER_WRITE => 'Write error',
\ZipArchive::ER_CRC => 'CRC error',
\ZipArchive::ER_ZIPCLOSED => 'Containing zip archive was closed',
\ZipArchive::ER_NOENT => 'No such file',
\ZipArchive::ER_EXISTS => 'File already exists',
\ZipArchive::ER_OPEN => 'Can\'t open file',
\ZipArchive::ER_TMPOPEN => 'Failure to create temporary file',
\ZipArchive::ER_ZLIB => 'Zlib error',
\ZipArchive::ER_MEMORY => 'Malloc failure',
\ZipArchive::ER_CHANGED => 'Entry has been changed',
\ZipArchive::ER_COMPNOTSUPP => 'Compression method not supported',
\ZipArchive::ER_EOF => 'Premature EOF',
\ZipArchive::ER_INVAL => 'Invalid argument',
\ZipArchive::ER_NOZIP => 'Not a zip archive',
\ZipArchive::ER_INTERNAL => 'Internal error',
\ZipArchive::ER_INCONS => 'Zip archive inconsistent',
\ZipArchive::ER_REMOVE => 'Can\'t remove file',
\ZipArchive::ER_DELETED => 'Entry has been deleted',
// \ZipArchive::ER_OK => 'No error',
default => 'No error',
};
?>
up
1
Anonymous
3 years ago
To read a zip file contents then loop through $zip->numFiles using $zip->getNameIndex(i)

e.g.

$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>Loaded $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 "... directory";
else echo "... ".strlen($zippedFile->getFromIndex($i))." bytes";

}
$zippedFile->close();
up
0