ZipArchive::addFile
(PHP 5 >= 5.2.0, PHP 7, PHP 8, PECL zip >= 1.1.0)
ZipArchive::addFile — 指定したパスからファイルを ZIP アーカイブに追加する
説明
string
$filepath
,string
$entryname
= "",int
$start
= 0,int
$length
= ZipArchive::LENGTH_TO_END,int
$flags
= ZipArchive::FL_OVERWRITE): bool
指定したパスから、ファイルを ZIP アーカイブに追加します。
注意: ポータビリティを考慮して、ZIP ファイル名のディレクトリ区切り文字には常にスラッシュ (
/
) を使うことを推奨します。
パラメータ
filepath
-
追加するファイルへのパス。
entryname
-
空でない値を指定した場合は ZIP アーカイブ内部での名前となり、
filepath
を上書きします。 start
-
ファイルを一部コピーする場合の開始位置。
length
-
ファイルを一部コピーする場合の、コピーする長さ。
ZipArchive::LENGTH_TO_END
(0) を指定すると、 ファイルサイズのぶんだけコピーします。ZipArchive::LENGTH_UNCHECKED
を指定すると、start
の位置から)ファイル全体をコピーします。 flags
-
以下のビットマスクの組み合わせ:
ZipArchive::FL_OVERWRITE
,ZipArchive::FL_ENC_GUESS
,ZipArchive::FL_ENC_UTF_8
,ZipArchive::FL_ENC_CP437
,ZipArchive::FL_OPEN_FILE_NOW
。 これらの定数の振る舞いは、定義済みの定数 で説明しています。
変更履歴
バージョン | 説明 |
---|---|
8.0.0, PECL zip 1.18.0 |
flags が追加されました。
|
8.3.0, PECL zip 1.22.1 |
ZipArchive::FL_OPEN_FILE_NOW が追加されました。
|
8.3.0, PECL zip 1.22.2 |
ZipArchive::LENGTH_TO_END
と
ZipArchive::LENGTH_UNCHECKED が追加されました。
|
例
この例は、ZIP ファイルアーカイブ test.zip をオープンし、ファイル /path/to/index.txt を newname.txt という名前で追加します。
例1 オープンおよび追加
<?php
$zip = new ZipArchive;
if ($zip->open('test.zip') === TRUE) {
$zip->addFile('/path/to/index.txt', 'newname.txt');
$zip->close();
echo '成功';
} else {
echo '失敗';
}
?>
注意
注意:
アーカイブにファイルを追加するよう設定すると、PHP はそのファイルをロックします。 ロックが解除されるのは、ZipArchive::close() を呼ぶなり ZipArchive オブジェクトを破棄するなりして ZipArchive オブジェクトが閉じられたときだけです。 そのため、追加しようとしているファイルがロックが解除される前に削除されるようなことは起こりません。
User Contributed Notes 34 notes
It is not obvious, since there are no noticeable examples around, but you can use $localname (second parameter) to define and control file/directory structure inside the zip. Use it if you do not want files to be included with their absolute directory tree.
<?php
$zip->addFile($abs_path, $relative_path);
?>
Beware: calling $zip->addFile() on a file that doesn't exist will succeed and return TRUE, delaying the failure until you make the final $zip->close() call, which will return FALSE and potentially leave you scratching your head.
If you're adding multiple files to a zip and your $zip->close() call is returning FALSE, ensure that all the files you added actually exist.
It's also a good idea to check each file with file_exists() or is_readable() before calling $zip->addFile() on it.
When adding a file to your zip, the file is opened and stays open.
When adding over 1024 files (depending on your open files limit) the server stops adding files, resulting in a status 11 in your zip Archive. There is no warning when exceeding this open files limit with addFiles.
Check your open files with ulimit -a
This kept me busy for some time.
The manual is lying.
"In short, it means you can first delete an added file after the archive is closed. "
Thats true but not by locking the file...
Warning! This method works asynchronous!
It seems that addFile() will return TRUE if the file stat command returns correctly, but the operation itself will not happen yet.
Instead, deleting a file is always possible. I have discovered this behaviour by using a temporary file and deleting it immediately after addFile() returns. The result was that no archive was created nor any file was added although every operation (creating,open(),addFile()) returned true before. The operation silenty fails.
If you have problem with windows explorer reading zipfile created by linux, try:
$oZip->addFile ( $file_name, " " . basename ( $file_name ) )
That space " " should solve.
there are some points can be more clear, it take me some time to figure out. hope it can help you.
1.use addFile() ,method to add the file with path to zip. if the directory not exist, addFile() would auto create it.
<?php
....
//addFile would help you create the directory named not_exist_director before add the filename.txt file.
$zip->addFile($fileToAdd, '/not_exist_directory/filename.txt');
...
?>
2. addFile() would overwrite the old file if exist in default.
<?php
....
//if the filename.txt is exist in the zip, addFile() would overwrite it. because the the addFile fifth param is ZipArchive::FL_OVERWRITE by default.
$zip->addFile($fileToAdd, '/filename.txt');
...
?>
2 tips:
- The example in on this page is a bit misleading for new programmers. It works only if the ZIP archive file exists already. Don't forget to use ZipArchive::CREATE and optionally ZipArchive::OVERWRITE in the second optional parameter in the open() function.
- If you want to add files and directories recursively (see some examples from other comments here on this page) use scandir() instead of blob() because blob() does not list hidden files like ".htaccess" for example.
In some versions of this library you NEED to add the "localfile" parameter or the file will not show in the Zip folder.
The workaround above (file_get_contents) is very dangerous if you pack large files. (see memory limit).
Close/open the zip archive periodically instead of using file_get_contents().
If you add files that have an absolut path, like for example:
/mnt/repository/my_file.pdf
the standard windows zip utility will not be able to extract the files. The first slash trips the zip utility. You have to add relative file paths or use a symbolic link.
work 4 me
$zip = new ZipArchive;
$zip_name = ('name.zip');
$path_zip = ($config['path'].'/zip/'.$zip_name);
$zip->open($path_zip,ZipArchive::CREATE);
$zip->addFile($path1.'/'.$nam1,$nam1);
$zip->addFile($path2.'/'.$nam2,$nam2);
$zip->close();
ciao
GioMBG
On my system (Windows), I found that ZipArchive uses IBM850 encoding for filenames (localname). For filenames with special characters such as (é) é which appears at 0xE9 in the ISO-8859-1, it is at 0x82 in IBM850. I had to call iconv('ISO-8859-1', 'IBM850', 'Québec') to get correct file names.
Note that using addFile() will change the order of the files within the zip, in fact within the index of the zip. Does not matter much, except if you loop the index and use addFile() within that loop : it will likely give messy results.
Example :
<?php
$zip = new ZipArchive;
if ($zip->open('somefile.zip') === TRUE) {
for ($i = 0; $i < $zip->numFiles; $i++) {
if (forsomereason()) {
addFile('./somenewfile.ext', $zip->getNameIndex($i));
}
}
}
$zip->close();
?>
This code may loop for ever, depending on your forsomereason() function, or at least you're at risk.
Try something like this instead :
<?php
$zip = new ZipArchive;
if ($zip->open('somefile.zip') === TRUE) {
for ($i = 0; $i < $zip->numFiles; $i++) {
if (forsomereason()) {
$couples[]=array('filename'=>'./somenewfile.ext','localname'=>$zip->getNameIndex($i));
}
}
}
foreach ($couples as $couple) $zip->addFile($couple['filename'],$couple['localname']);
$zip->close();
?>
Hope it helps ;-)
I had a huge number of files and folders that I needed to zip on a linux web server. I was running into timeout problems and file enumerator issues, as well as file handler limit issues (ulimit). I used a script to solve u limit offered by Farzad Ghanei first (ZipArchiveImproved), but closing and reopening his way didn't do the trick for me.
I eventually did a simple call to a $filelimit variable I created that records file handler limit I want my script to hit before it closes and reopens the file.
<?php
$filelimit = 255;
if ($zip->numFiles == $filelimit) {$zip->close(); $zip->open($file) or die ("Error: Could not reopen Zip");}
?>
This made some progress for me, timeouts were gone, but when calling
<?php $zip->addFile($filepath, $archivefilepath); ?>
after the reopening of the Zip, I got an error. I echoed the <?php $zip->numFiles; ?> and found that after reopening, the numFile enum reset to '0'.
A few more goose-chases later, I tried addFromString with some better results, but did not get it working 100% until I actually coupled addFromString with addFile! My working scripting for the add files function on massive file-folder structures looks like so:
<?php
$sourcefolder = /rel/path/to/source/folder/on/server/
$dirlist = new RecursiveDirectoryIterator($sourcefolder);
$filelist = new RecursiveIteratorIterator($dirlist);
//how many file can be added before a reopen is forced?
$filelimit = 245;
// Defines the action
$file = tempnam("tmp", "zip");
$zip = new ZipArchive();
// This creates and then gives the option to save the zip file
if ($zip->open($file, ZipArchive::OVERWRITE) !== TRUE) {
die ("Could not open archive");
}
// adds files to the file list
foreach ($filelist as $key=>$value) {
//fix archive paths
$path = str_replace($sourcefolder, "", $key); //remove the source path from the $key to return only the file-folder structure from the root of the source folder
if (!file_exists($key)) { die($key.' does not exist. Please contact your administrator or try again later.'); }
if (!is_readable($key)) { die($key.' not readable. Please contact your administrator or try again later.'); }
if ($zip->numFiles == $filelimit) {$zip->close(); $zip->open($file) or die ("Error: Could not reopen Zip");}
$zip->addFromString($path, $key) or die ("ERROR: Could not add file: $key </br> numFile:".$zip->numFiles);
$zip->addFile(realpath($key), $path) or die ("ERROR: Could not add file: $key </br> numFile:".$zip->numFiles);
}
// closes the archive
$zip->close();
//make local temp file a .zip, rename, and move to output dir
rename ($file, "./" . $outputfolder . "/" . $zipfilename);
?>
I hope this may help someone else.
Here's a little extension to ZipArchive that handles directories recursively:
<?php
class Zipper extends ZipArchive {
public function addDir($path) {
print 'adding ' . $path . '<br>';
$this->addEmptyDir($path);
$nodes = glob($path . '/*');
foreach ($nodes as $node) {
print $node . '<br>';
if (is_dir($node)) {
$this->addDir($node);
} else if (is_file($node)) {
$this->addFile($node);
}
}
}
} // class Zipper
?>