PHP Conference Japan 2024

ZipArchive::extractTo

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

ZipArchive::extractTo解压归档内容

描述

public ZipArchive::extractTo(string $pathto, array|string|null $files = null): bool

将完整的归档文件或给定的文件解压到指定的目的地。

警告

解压的文件和目录的默认权限赋予了最广泛的访问权限。这可以通过设置当前umask来限制,可以使用umask()更改。

出于安全原因,不会恢复原始权限。有关如何恢复它们的示例,请参见ZipArchive::getExternalAttributesIndex()页面上的代码示例

参数

pathto

解压文件的目标位置。

files

要解压的条目。它接受单个条目名称或名称数组。

返回值

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

示例

示例 #1 解压所有条目

<?php
$zip
= new ZipArchive;
if (
$zip->open('test.zip') === TRUE) {
$zip->extractTo('/my/destination/dir/');
$zip->close();
echo
'ok';
} else {
echo
'failed';
}
?>

示例 #2 解压两个条目

<?php
$zip
= new ZipArchive;
$res = $zip->open('test_im.zip');
if (
$res === TRUE) {
$zip->extractTo('/my/destination/dir/', array('pear_item.gif', 'testfromfile.php'));
$zip->close();
echo
'ok';
} else {
echo
'failed';
}
?>

注释

注意:

Windows NTFS文件系统不支持文件名中的某些字符,即<|>*?":。也不支持结尾带点的文件名。与某些解压工具相反,此方法不会用下划线替换这些字符,而是无法解压此类文件。

添加注释

用户贡献的注释 15 条注释

php-dev at proneticas dot net
14 年前
如果您想一次复制一个文件并删除ZIP文件中存储的文件夹名称,这样您就不必从ZIP本身创建目录,那么可以使用此代码片段(基本上将ZIP文件压缩到一个文件夹中)。

<?php

$path
= 'zipfile.zip'

$zip = new ZipArchive;
if (
$zip->open($path) === true) {
for(
$i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
$fileinfo = pathinfo($filename);
copy("zip://".$path."#".$filename, "/your/new/destination/".$fileinfo['basename']);
}
$zip->close();
}

?>

* 顺便说一句,您也可以使用 $_FILES['userfile']['tmp_name'] 作为上传的 ZIP 的 $path,这样您就不必移动它或解压上传的 zip 文件。

干杯!

ProNeticas 开发团队
匿名
6 年前
如果您只想将文件解压到当前文件夹,只需使用
$zip->extractTo(".");

我花了几个小时才弄清楚这一点。
stanislav dot eckert at vizson dot de
9 年前
extractTo() 方法不提供任何参数来允许从ZIP归档文件中的另一个(父)文件夹递归地解压文件和文件夹。使用以下方法可以实现

<?php
class my_ZipArchive extends ZipArchive
{
public function
extractSubdirTo($destination, $subdir)
{
$errors = array();

// 准备目录
$destination = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $destination);
$subdir = str_replace(array("/", "\\"), "/", $subdir);

if (
substr($destination, mb_strlen(DIRECTORY_SEPARATOR, "UTF-8") * -1) != DIRECTORY_SEPARATOR)
$destination .= DIRECTORY_SEPARATOR;

if (
substr($subdir, -1) != "/")
$subdir .= "/";

// 解压文件
for ($i = 0; $i < $this->numFiles; $i++)
{
$filename = $this->getNameIndex($i);

if (
substr($filename, 0, mb_strlen($subdir, "UTF-8")) == $subdir)
{
$relativePath = substr($filename, mb_strlen($subdir, "UTF-8"));
$relativePath = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $relativePath);

if (
mb_strlen($relativePath, "UTF-8") > 0)
{
if (
substr($filename, -1) == "/") // 目录
{
// 新建目录
if (!is_dir($destination . $relativePath))
if (!@
mkdir($destination . $relativePath, 0755, true))
$errors[$i] = $filename;
}
else
{
if (
dirname($relativePath) != ".")
{
if (!
is_dir($destination . dirname($relativePath)))
{
// 新建目录 (用于文件)
@mkdir($destination . dirname($relativePath), 0755, true);
}
}

// 新建文件
if (@file_put_contents($destination . $relativePath, $this->getFromIndex($i)) === false)
$errors[$i] = $filename;
}
}
}
}

return
$errors;
}
}
?>

示例
<?php
echo "<pre>";

$zip = new my_ZipArchive();
if (
$zip->open("test.zip") === TRUE)
{
$errors = $zip->extractSubdirTo("C:/output", "folder/subfolder/");
$zip->close();

echo
'ok, 错误: ' . count($errors);
}
else
{
echo
'失败';
}
?>
quake2005 at gmail dot com
14 年前
如果你想一次解压一个文件,可以使用这个方法

<?php

$path
= 'zipfile.zip'

$zip = new ZipArchive;
if (
$zip->open($path) === true) {

for(
$i = 0; $i < $zip->numFiles; $i++) {

$zip->extractTo('path/to/extraction/', array($zip->getNameIndex($i)));

// 在这里你可以为特定解压文件运行自定义函数

}

$zip->close();

}

?>
kawzaki at yahoo dot com
15年前
请注意,使用此函数时,覆盖设置为TRUE。

如果压缩文件包含与旧文件名匹配的文件,则旧文件将被覆盖。

压缩文件中没有匹配项的旧文件将保持不变。

希望有人能解释如何避免覆盖旧文件。
cory dot mawhorter at ephective dot com
14 年前
此函数将使用ZipArchive类展平zip文件。

它将解压zip文件中的所有文件并将它们存储到单个目标目录中。也就是说,不会创建子目录。

如果有人知道更好的方法来确定条目是否为目录,请参与讨论。我觉得检查尾部斜杠的做法不太好。

<?php
// 目标目录不应该以斜杠结尾
function zip_flatten ( $zipfile, $dest='.' )
{
$zip = new ZipArchive;
if (
$zip->open( $zipfile ) )
{
for (
$i=0; $i < $zip->numFiles; $i++ )
{
$entry = $zip->getNameIndex($i);
if (
substr( $entry, -1 ) == '/' ) continue; // 跳过目录

$fp = $zip->getStream( $entry );
$ofp = fopen( $dest.'/'.basename($entry), 'w' );

if ( !
$fp )
throw new
Exception('无法解压文件。');

while ( !
feof( $fp ) )
fwrite( $ofp, fread($fp, 8192) );

fclose($fp);
fclose($ofp);
}

$zip->close();
}
else
return
false;

return
$zip;
}

/*
示例用法:

zip_flatten( 'test.zip', 'my/path' );
*/
?>

[由 php DOT net 的 danbrown 编辑:根据原发帖人在 2010 年 4 月 18 日的后续说明添加了 $zip->close()。]
cucurella at gmail dot com
3年前
//逐个文件处理错误!!

<?php

$ERROR_UNZIP
= false;
$dest = "../";
$zipfile = "test.zip";

$zip = new ZipArchive;

if (
$zip->open("$zipfile") === true) {

for (
$i = 0; $i < $zip -> numFiles; $i++) {
$RETVAL = false;

$filename = $zip->getNameIndex($i);

$RETVAL = $zip->extractTo($dest,$filename);

if (
$RETVAL) {
print
"$filename ... [ OK ]<br>";
} else {
print
"$filename ... [ ERROR ]<br>";
$ERROR_UNZIP = true;
}
}

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

// 返回值
if ($ERROR_UNZIP) {
print
"<p>解压 ${zipfile} 发生错误</p>";
} else {
print
"<p>解压成功</p>";
}
} else {
print
"<p>打开 ${zipfile} 发生错误</p>";
}

?>
skrzypecki at gmail dot com
7年前
请注意,路径不能太长!我不确定最大长度是多少,没有找到任何相关信息。但是当我使用 extractTo() 时,一直出现问题。

然后在谷歌上搜索后,我找到了这个小评论:https://github.com/composer/composer/issues/2824#issuecomment-308201902

复制粘贴的评论
===
我的机器上有这条路径

C:/xampp5.0/htdocs/project-recordando-symfony/project-recordando-symfony
然后我运行 composer install 或/和 composer update,它返回了这个错误

ErrorException ZipArchive::extractTo...

出现该错误是因为路径太长,我将其更改为

C:/xampp5.0/htdocs/p-symfony/*
然后就成功了!
===
synnus at gmail dot com
7年前
<?php

// 此版本允许查看将要解压缩的文件,并跟踪解压缩过程
// 跟踪解压缩进度

define( 'FILEPATH', dirname(__FILE__) . '\\' );
define( 'TEST', FILEPATH . 'test\\' );

$za = new ZipArchive();

$za->open(FILEPATH . 'test.zip');
print_r($za);
var_dump($za);
echo
"文件数量: " . $za->numFiles . "\n";
echo
"状态: " . $za->status . "\n";
echo
"系统状态: " . $za->statusSys . "\n";
echo
"文件名: " . $za->filename . "\n";
echo
"注释: " . $za->comment . "\n";

/* 在 $za->statIndex($i) 中

[name] => data/x.luac
[index] => 451
[crc] => -1266183263
[size] => 2936
[mtime] => 1464790482
[comp_size] => 976
[comp_method] => 8
*/

for ($i=0; $i<$za->numFiles;$i++) {
echo
"索引: $i\n";
$name = $za->statIndex($i)['name'];
$size = $za->statIndex($i)['size'];
$comp_size = $za->statIndex($i)['comp_size'];
print_r($name . ' [ ' . $size . '>' . $comp_size . ']' );
$za->extractTo(TEST,$name);
}
echo
"文件数量:" . $za->numFiles . "\n";

?>
sachinyadav at live dot com
14 年前
这段脚本将在 test.zip 压缩包内搜索“.txt”文件(任何文件名)。假设找到了名为 'example.txt' 的文件,则脚本会将 'example.txt' 复制到 "txt_files" 目录,并将其重命名为 'test.zip.txt',然后删除 'test.zip.txt' 中的所有空行,重新保存,并退出循环,不再搜索其余条目。
此脚本可用于提取 .DIZ 和 GIF 文件,以便在您的脚本中显示 ZIP 压缩包详细信息。
<?php
$value
="test.zip";
$filename="zip_files/$value";
$zip = new ZipArchive;
if (
$zip->open($filename) === true) {
echo
"正在生成 TEXT 文件。";
for(
$i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
if(
preg_match('#\.(txt)$#i', $entry))
{
////此复制函数会将条目移动到 "txt_files" 的根目录,不会像 "ZIP->EXTRACTO" 函数那样创建任何子文件夹。
copy('zip://'.dirname(__FILE__).'/zip_files/'.$value.'#'.$entry, 'txt_files/'.$value.'.txt');
$content = file_get_contents("txt_files/$value.txt");
$newcontent = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $content);
file_put_contents("txt_files/$value.txt", "$newcontent");
break;
}
}
$zip->close();
}
else{
echo
"ZIP 压缩包打开失败";
}
?>

享受 PHP 编程的乐趣。
Sachin Yadav
tBone
16 年前
根据我的经验,此函数至少能够保持/强制 ZIP 文件中的目录结构。

例如,如果您在 zip 文件中拥有 FOLDER1/File1.txt,并且您使用
$zip->extractTo('/extract', 'FOLDER1/File1.txt');
则解压文件的路径将是
/extract/FOLDER1/File1.txt
ben dot tyger at tygerclan dot net
8 年前
注意,在 Linux(可能还有其他 *nix 平台)中,无法从 Zip 压缩包中提取隐藏文件(即文件名以“.”开头的文件)。
ohcc at 163 dot com
7年前
警告!

如果您在 Apache 下运行 php,则 zip 文件内的 .htaccess 文件可能会导致 extractTo() 方法失败。
匿名用户
15年前
我发现将其添加到函数中很有用。

<?php
/**
* 将 ZIP 压缩包解压到指定的解压路径
*
* @param string $file 要解压的 ZIP 压缩包(包括路径)
* @param string $extractPath 解压 ZIP 压缩包到的路径
*
* @return boolean 如果 ZIP 压缩包成功解压,则返回 TRUE;如果发生错误,则返回 FALSE
*
*/
function zip_extract($file, $extractPath) {

$zip = new ZipArchive;
$res = $zip->open($file);
if (
$res === TRUE) {
$zip->extractTo($extractPath);
$zip->close();
return
TRUE;
} else {
return
FALSE;
}

}
// 函数结束
?>
icixtec at gmail dot com
4 年前
对于需要解压文件且不知道文件名是大写还是小写的情况

$zip = new ZipArchive;
if ($zip->open('myfile.zip') === TRUE) {
// 不起作用
//$zip->extractTo('./', array( 'file1.XML', 'file1.xml'));
// 起作用
$zip->extractTo('./', 'file1.XML' );
$zip->extractTo('./', 'file1.xml' );
$zip->close();
}
To Top