ZipArchive::addFile

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

ZipArchive::addFile从给定路径添加文件到 ZIP 档案

描述

public ZipArchive::addFile(
    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_OVERWRITEZipArchive::FL_ENC_GUESSZipArchive::FL_ENC_UTF_8ZipArchive::FL_ENC_CP437ZipArchive::FL_OPEN_FILE_NOW 构成的位掩码。这些常量的行为在 ZIP 常量 页面上描述。

返回值

成功时返回 true,失败时返回 false

变更日志

版本 描述
8.0.0 / 1.18.0 添加了 flags
8.3.0 / 1.22.1 添加了 ZipArchive::FL_OPEN_FILE_NOW
8.3.0 / 1.22.2 添加了 ZipArchive::LENGTH_TO_ENDZipArchive::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
'ok';
} else {
echo
'failed';
}
?>

备注

注意:

当一个文件被设置为添加到档案时,PHP 将锁定该文件。只有在 ZipArchive 对象被关闭后,无论是通过 ZipArchive::close() 还是 ZipArchive 对象被销毁,锁才会被释放。这可能会阻止您在锁被释放之前删除正在添加的文件。

参见

添加注释

用户贡献注释 34 条注释

jayarjo
14 年前
这并不明显,因为周围没有明显的例子,但你可以使用 $localname(第二个参数)来定义和控制 zip 内部的文件/目录结构。如果不想将文件包含在它们的绝对目录树中,请使用它。

<?php

$zip
->addFile($abs_path, $relative_path);

?>
john factorial
13 年前
注意:对不存在的文件调用 $zip->addFile() 会成功并返回 TRUE,直到你进行最终的 $zip->close() 调用,它将返回 FALSE,并可能让你一头雾水。

如果你向 zip 中添加多个文件,并且你的 $zip->close() 调用返回 FALSE,请确保你添加的所有文件都实际存在。

在对文件调用 $zip->addFile() 之前,最好使用 file_exists() 或 is_readable() 检查每个文件。
aartdebruijn at gmail dot com
13 年前
将文件添加到你的 zip 时,该文件会被打开并保持打开状态。
当添加超过 1024 个文件(取决于你的打开文件限制)时,服务器将停止添加文件,导致你的 zip 档案中出现状态 11。使用 addFiles 超出此打开文件限制时没有警告。

使用 ulimit -a 检查你的打开文件。

这让我忙了好一阵子。
frame86 at live dot com
10 年前
手册是错的。

"简而言之,这意味着你可以在档案关闭后先删除添加的文件。"

这是真的,但不是通过锁定文件......
警告!此方法异步工作!

似乎 addFile() 如果文件 stat 命令返回正确,则会返回 TRUE,但操作本身不会立即发生。

相反,删除文件总是可能的。我通过使用临时文件并在 addFile() 返回后立即将其删除,发现了这种行为。结果是,虽然每个操作(创建、open()、addFile())在之前都返回 true,但没有创建档案,也没有添加任何文件。操作静默失败。
romuloum at hotmail dot com
10 年前
如果你在 Windows 资源管理器读取 Linux 创建的 zip 文件时遇到问题,请尝试
$oZip->addFile ( $file_name, " " . basename ( $file_name ) )
这个空格 " " 应该能解决问题。
610010559 at qq dot com
2 年前
有些地方可以更清楚,我花了一些时间才弄明白。希望这可以帮助你。
1.使用 addFile() 方法将带路径的文件添加到 zip 中。如果目录不存在,addFile() 会自动创建它。
<?php
....
//addFile 会帮助你创建名为 not_exist_director 的目录,然后再添加 filename.txt 文件。
$zip->addFile($fileToAdd, '/not_exist_directory/filename.txt');
...
?>

2.addFile() 会默认覆盖旧文件(如果存在)。
<?php
....
//如果 filename.txt 存在于 zip 中,addFile() 会覆盖它。因为 addFile 的第五个参数默认情况下为 ZipArchive::FL_OVERWRITE。
$zip->addFile($fileToAdd, '/filename.txt');
...
?>
stanislav dot eckert at vizson dot de
9 年前
2 个提示

- 此页面上的示例对新手程序员来说有点误导。 它只在 ZIP 存档文件已存在的情况下才有效。 不要忘记在 open() 函数的第二个可选参数中使用 ZipArchive::CREATE 以及可选的 ZipArchive::OVERWRITE。

- 如果你想递归地添加文件和目录(请参阅此页面上其他评论中的一些示例),请使用 scandir() 而不是 blob(),因为 blob() 不会列出隐藏文件,例如 ".htaccess"。
camuc at camuc dot net
14 年前
在这个库的某些版本中,你需要添加 "localfile" 参数,否则文件将不会显示在 Zip 文件夹中。
wacher at freemail dot hu
16 年前
上面的解决方法(file_get_contents)对于打包大型文件非常危险。(见内存限制)。
定期关闭/打开 zip 存档,而不是使用 file_get_contents()。
garcia at no_span dot krautzer-lynn dot com
15 年前
如果你添加具有绝对路径的文件,例如
/mnt/repository/my_file.pdf
标准的 Windows zip 实用程序将无法提取这些文件。 第一个斜杠会使 zip 实用程序停止工作。 你必须添加相对文件路径或使用符号链接。
gio AT giombg dot com
6 年前
对我有用

$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
Anonymous
14 年前
在我的系统(Windows)上,我发现 ZipArchive 使用 IBM850 编码作为文件名(本地名)。 对于包含特殊字符的文件名,例如 (é) &eacute;,它在 ISO-8859-1 中的编码是 0xE9,在 IBM850 中的编码是 0x82。 我必须调用 iconv('ISO-8859-1', 'IBM850', 'Québec') 来获得正确的文件名。
sp at read dot eu
12 年前
注意,使用 addFile() 会更改 zip 文件中文件的顺序,实际上是 zip 文件的索引中的顺序。 这并不重要,除非你循环遍历索引并在循环中使用 addFile():这很可能会导致混乱的结果。

示例
<?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();
?>

这段代码可能会无限循环,具体取决于你的 forsomereason() 函数,或者至少你存在风险。

尝试以下代码

<?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();
?>

希望对您有所帮助 ;-)
kris at blacksuitmedia [do/t/] c0m
11 年前
我需要在一个 Linux 服务器上压缩大量文件和文件夹。 我遇到了超时问题、文件枚举问题以及文件句柄限制问题(ulimit)。 我使用 Farzad Ghanei 提供的脚本(ZipArchiveImproved)来解决 u limit 问题,但以他的方式关闭和重新打开并没有解决我的问题。

我最终创建了一个名为 $filelimit 的简单变量,它记录我想要脚本在关闭和重新打开文件之前达到的文件句柄限制。
<?php
$filelimit
= 255;

if (
$zip->numFiles == $filelimit) {$zip->close(); $zip->open($file) or die ("Error: Could not reopen Zip");}
?>

这让我取得了一些进展,超时问题消失了,但是当我调用
<?php $zip->addFile($filepath, $archivefilepath); ?>
重新打开 Zip 之后,我遇到了错误。 我回显了 <?php $zip->numFiles; ?>,发现重新打开后,numFile 枚举重置为 '0'。

经过更多尝试后,我尝试使用 addFromString,结果好了一些,但直到我真正将 addFromString 与 addFile 结合使用才使其完全正常工作! 我用于处理大量文件和文件夹结构的添加文件函数的脚本如下

<?php
$sourcefolder
= /rel/path/to/source/folder/on/server/

$dirlist = new RecursiveDirectoryIterator($sourcefolder);

$filelist = new RecursiveIteratorIterator($dirlist);

// 在强制重新打开之前可以添加多少个文件?
$filelimit = 245;

// 定义操作
$file = tempnam("tmp", "zip");
$zip = new ZipArchive();

// 这将创建并提供保存 zip 文件的选项

if ($zip->open($file, ZipArchive::OVERWRITE) !== TRUE) {

die (
"Could not open archive");

}

// 将文件添加到文件列表
foreach ($filelist as $key=>$value) {

// 修复存档路径
$path = str_replace($sourcefolder, "", $key); // 从 $key 中删除源路径,以仅返回从源文件夹根目录开始的文件和文件夹结构
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);

}

// 关闭存档
$zip->close();

// 将本地临时文件设为 .zip,重命名并移动到输出目录
rename ($file, "./" . $outputfolder . "/" . $zipfilename);
?>
希望这能帮助其他人。
peter at boring dot ch
14 年前
这是 ZipArchive 的一个小扩展,可以递归地处理目录

<?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

?>
ohcc at 163 dot com
8 年前
不要使用 ZipArchive::addFile() 来追加文件夹。

当文件夹的路径传递给 ZipArchive::addFile() 时,该方法会返回 true,但 ZipArchive 既不能创建 zip 存档,也不能对现有文件进行任何更改。

<?php
$z
= new ZipArchive();
if(
true === ($z->open('./foo.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE))){
$z->setArchiveComment('Interesting!');
$z->addFromString('domain.txt', 'wuxiancheng.cn');
$folder = './test';
!
is_dir($folder) && mkdir($folder); // 创建一个用于测试的文件夹
if(true === $z->addFile($folder)){
echo
'success'; // !!!
}
rmdir($folder);
$z->close();
// foo.zip 不会保存在磁盘上。
// 如果 foo.zip 在运行此脚本之前已经存在,则文件将保持不变。
}
?>
theking2(at)king.ma
1 个月前
正如其他人所指出的,ZipArchive::addFile() 是异步的。如果你想限制添加大量文件的时间,这就是方法。

<?php
//$files 是一个包含大量文件名的数组。
//$fileCount 是 $files 中文件的总数,例如 count($files)
//$fileIndex 是要开始的文件索引
for(
$fileIndex = 1, $start = hrtime( true );
$fileIndex < $fileCount and $secondsElapsed < 5.0;
$fileIndex++
) {
$currentfile = $files[ $fileIndex ];

if(
file_exists( $currentfile ) ) {
$zip->addFile( $currentfile );
usleep(1);
$secondsElapsed = ( hrtime( true ) - $start ) / 1e+9;
}

}
?>

这将不断添加文件,直到超时(5.0 秒)出现。没有 usleep(1) 它将一直持续到达到 max_excecution_time 为止。
raja at rsdisk dot com
5 年前
zip->addfile 函数不会立即将文件添加到存档。它是排队的,并在 zip->close() 时执行。

我有一个目录中的备份文件,使用 foreach 语句,我将文件添加到存档,然后立即将文件移动到转储目录。

这会导致错误。

<?php
$dir
= getcwd().'/';
$dirContent = scandir('./');
foreach(
$dirContent as $file)
if(
strpos($file, '.sql')!==false)
{
echo
"adding $file ......";
$zip->addFile($file);
$newFileName = $dir."done/$file";
rename($dir.$file, $newFileName);
echo(
"; file added\n");
}
$zip->close();
?>

需要在移动文件之前执行 $zip->close()。
<?php
foreach($dirContent as $file)
if(
strpos($file, '.sql')!==false)
{
echo
"adding $file ......";
$zip->addFile($file);
echo(
"; file added\n");
}
$zip->close();
foreach(
$dirContent as $file)
if(
strpos($file, '.sql')!==false)
{
$newFileName = $dir."done/$file";
rename($dir.$file, $newFileName);
echo(
"$file moved\n");
}
?>
christophe dot braud at aquafadas dot com
15 年前
如果你在最近的 Ubuntu 更新后遇到了一些与 ZipArchiveImproved 相关的警告,请在 reopen 函数中将 "self::CREATE" 替换为 "self::CREATE | self::OVERWRITE"。

christophe
Farzad Ghanei
15 年前
这是一个扩展 ZipArchive 的基本类,它:
* 添加了一个功能来报告 ZIP 文件地址(我需要它,但在 ZipArchive 文档中找不到如何实现)。
* 解决由于文件描述符限制而导致向存档添加太多文件的问题。ZipArchiveImproved::addFile() 处理了这个问题。

<?php
/**
* ZipArchiveImproved 扩展了 ZipArchive,添加了一些关于 zip 文件的信息和一些功能。
*
*
*
* @author Farzad Ghanei
* @uses ZipArchive
* @version 1.0.0 2009-01-18
*/

class ZipArchiveImproved extends ZipArchive {
protected
$_archiveFileName = null;
protected
$_newAddedFilesCounter = 0;
protected
$_newAddedFilesSize = 100;

/**
* 返回存档文件的名称。
*
* @return string
*/
public function getArchiveFileName() {
return
$this->_archiveFileName;
}

/**
* 返回将要添加到 ZIP 中的文件数量
* 而不重新打开文件流。
*
* @return int
*/
public function getNewAddedFilesSize() {
return
$this->_newAddedFilesSize;
}

/**
* 设置将要添加到 ZIP 中的文件数量
* 而不重新打开文件流。 如果没有指定大小,则默认值为 100。
*
* @param int
* @return ZipArchiveImproved 自引用
*/
public function setNewlAddedFilesSize($size=100) {
if ( empty(
$size) || !is_int($size) || $size < 1) {
$size = 100;
}
$this->_newAddedFilesSize = $size;
return
$this;
}

/**
* 打开到 ZIP 存档文件的流。 在内部调用 ZipArchive::open()。
* 覆盖 ZipArchive::open() 以添加 archiveFileName 功能。
*
* @param string $fileName
* @param int $flags
* return mixed
*/
public function open($fileName, $flags) {
$this->_archiveFileName = $fileName;
$this->_newAddedFilesCounter = 0;
return
parent::open($fileName,$flags);
}

/**
* 关闭到 ZIP 存档文件的流。 在内部调用 ZipArchive::close()。
* 覆盖 ZipArchive::close() 以添加 archiveFileName 功能。
*
* @return bool
*/
public function close() {
$this->_archiveFileName = null;
$this->_newAddedFilesCounter = 0;
return
parent::close();
}

/**
* 关闭与 ZIP 文件的连接,然后重新打开连接。
*
* @return bool
*/
public function reopen() {
$archiveFileName = $this->_archiveFileName;
if ( !
$this->close() ) {
return
false;
}
return
$this->open($archiveFileName,self::CREATE);
}

/**
* 从给定路径将文件添加到 ZIP 存档。 在内部调用 ZipArchive::addFile()。
* 覆盖 ZipArchive::addFile() 以处理操作系统中的最大文件连接。
*
* @param string $fileName 要添加到存档的文件路径
* @param string [可选] $localname 存档中文件的名称
* @return bool
*/
public function addFile( $fileName ) {
if (
$this->_newAddedFilesCounter >= $this->_newAddedFilesSize) {
$this->reopen();
}
if (
func_num_args() > 1 ) {
$flags = func_get_arg(1);
$added = parent::addFile($fileName,$flags);
if (
$added) {
$this->_newAddedFilesCounter++;
}
return
$added;
}
$added = parent::addFile($fileName);
if (
$added) {
$this->_newAddedFilesCounter++;
}
return
$added;
}
// public function addFile()
}
?>
todd at toddwiggins dot com dot au
10 年前
addFile() 方法不支持 "file://" 协议。 请去除 "file://" 并使用绝对路径代替。

我假设它也不支持其他协议,我在尝试添加文件时遇到了问题,我在构建的应用程序中的其他功能需要使用协议。

另外需要注意的是,返回的状态码与任何预定义的错误码都不匹配,而且状态码从不相同。 我的猜测是变量溢出,因为状态码大约在最小值和最大值 INT 值附近。
s dot eckert dot spam at gmx dot com
10 年前
请注意,ZIP 文件没有“文件夹”的概念。 如果您需要将数据存储到文件夹中,请在 $localname 中使用正斜杠(“/”)来分隔文件夹和文件名。

示例
$zip->addFile("test.txt", "mainfolder/subfolder/test.txt");
Dean Rather
11 年前
此添加目录功能不需要您创建新的包装类,也不会将整个文件目录树添加到您的 zip 文件中。

<?php

public function addDirectoryToZip($zip, $dir, $base)
{
$newFolder = str_replace($base, '', $dir);
$zip->addEmptyDir($newFolder);
foreach(
glob($dir . '/*') as $file)
{
if(
is_dir($file))
{
$zip = $this->addDirectoryToZip($zip, $file, $base);
}
else
{
$newFile = str_replace($base, '', $file);
$zip->addFile($file, $newFile);
}
}
return
$zip;
}

?>
shano
12 年前
希望它能派上用场
递归地添加目录中所有目录和文件

class zip extends ZipArchive {

public function addDirectory($dir) { // 添加目录
foreach(glob($dir . '/*') as $file) {
if(is_dir($file))
$this->addDirectory($file);
else
$this->addFile($file);
}
}
}
Andreas R. newsgroups2005 at geekmail de
17 年前
目前,可以使用 addFile 添加到 ZIP 存档中的文件数量(直到关闭它)受文件描述符限制的限制。 这是一个简单的解决方法(在下面的错误链接中,您可以找到其他解决方法)
<?php
/** 解决文件描述符数量限制问题(避免在添加超过 253 或 1024 个文件时失败
* 到 ZIP) */
function addFileToZip( $zip, $path, $zipEntryName ) {
// 这将导致状态 ZIPARCHIVE::ER_OPEN 失败
// 在添加一定数量的文件后,因为
// ZipArchive 在内部存储所有已添加文件的描述符,并且只有在关闭时才将内容写入 ZIP 文件
// 查看: http://bugs.php.net/bug.php?id=40494
// 和: http://pecl.php.net/bugs/bug.php?id=9443
// return $zip->addFile( $path, $zipEntryName );

$contents = file_get_contents( $path );
if (
$contents === false ) {
return
false;
}
return
$zip->addFromString( $zipEntryName, $contents );
}
?>
ptipti at gala dot net
12 年前
另一个意外发现,花费了很多麻烦。 因此,在您将文件添加到存档后,可以安全地将其删除,利用了这种结构

if (!is_file ($archive))
$result = $zip->open ($archive, ZipArchive::CREATE);
else
$result = $zip->open ($archive);
endif;
if ($result === TRUE)
if (($zip->addFile ($file, $filename)) === TRUE)
$theoreticaly_added = TRUE;
endif;
if ((($zip->close ()) === TRUE) && $theoreticaly_added)
unlink ($file);
endif;
endif;

现在文件不会消失。但也许有一个更简单的解决方案,可以100%保证?
javierseixas at gmail dt com
16 年前
我在尝试添加文件时遇到了几个问题,因为路径问题。错误提示如下

ZipArchive::addFile() [function.ZipArchive-addFile]: Unable to access <path>

我使用了以“/”开头的绝对根路径,但没有用。尝试使用“./”作为路径的开头(引用你的网站根目录)。
mike at thetroubleshooters dot dk
16 年前
更糟糕的是,当你用完文件描述符时,它似乎会静默失败,我在任何日志文件中都没有找到任何错误。
ohcc at 163 dot com
8 年前
如果文件名包含汉字,ZIPARCHIVE::addFile()会导致无法将文件压缩到压缩包中,或者压缩后文件名乱码。

可以使用ZipArchive::addFromString()来实现。

注意:如果操作系统是Windows,文件系统编码是gbk.
如果php文件的文件编码是utf-8,需要相应转码。

如果文件名包含中文字符,ZipArchive::addFile()将失败。

建议使用ZipArchive::addFromString()代替。

<?php

$z
= new ZipArchive;

$file = '吴先成.txt';

if(
$z->open(ZIPARCHIVE::CREATE)===true){
$z->addFromString($file, file_get_contents($file));
//for windows
//$z->addFromString($file, file_get_contents(iconv('utf-8', 'gbk//ignore', $file)));
}
// ...
stanleyshilov {} gmail.com
16 年前
需要注意的是,上面提供的示例并不准确。

与extractTo不同,zip_open不会返回布尔值结果,因此上面的示例将始终失败。
arrtedone at gmail dot com
10 年前
注意,ZipArchive::open()不返回布尔值,而是整数,例如
$zip = new ZipArchive();
$filename = '/tmp/test.zip';
var_dum($zip->open($filename)); // 返回: int (11)
ss at littlerain dot com
15 年前
注意,直到调用$zip->close()方法,文件才会真正添加到存档中。我花了很长时间试图弄清楚为什么在通过$zip->addFile()添加大型文件后,没有时间过去了,但随后会超时脚本。
pelpet at ic dot cz
14 年前
<?php
$zip
=new ZipArchive;
$zip->addFile('path to the file', 'new name of the file');
?>

当我想要在压缩存档中使用它之前的文件名时,我该怎么做?
(对不起,我来自捷克共和国,英语不太好,如果我在任何地方犯了错误,请忽略它 :-)
marco at maranao dot ca
15 年前
这是我通过定期关闭/打开存档文件来解决文件描述符限制的变通方法。

<?php
if($backup = new ZipArchive()) {
if(
$backup->open($zip, ZIPARCHIVE::OVERWRITE) === true) {
$backup->addFile($file['realpath'], $file['path']);
if((
$count++) == 200) { // 文件描述符限制
$backup->close();
if(
$backup = new ZipArchive()) {
$backup->open($zip);
$count = 0;
}
}
}
$backup->close();
}
?>

希望它能帮助到一些人。
To Top