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 文件系统不支持文件名中的某些字符,即 <|>*?":。带有尾随点的文件名也不支持。与某些提取工具相反,此方法不会用下划线替换这些字符,而是无法提取此类文件。

添加注释

用户贡献的注释 16 个注释

46
php-dev at proneticas dot net
13 年前
如果您想一次复制一个文件并删除存储在 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 开发团队
15
匿名
6 年前
如果您想将文件提取到当前文件夹,只需使用
$zip->extractTo(".");

我花了几个小时才弄明白这一点。
8
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, errors: ' . count($errors);
}
else
{
echo
'failed';
}
?>
7
quake2005 at gmail dot com
13 年前
如果你想要一次提取一个文件,你可以使用这个

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

}

?>
5
kawzaki at yahoo dot com
15 年前
请注意,使用此函数会导致覆盖为真。

如果存档(压缩文件)包含与旧文件名匹配的文件,则会覆盖旧文件。

压缩包中没有匹配项的旧文件将保持原样。

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

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

如果有人知道更好的方法来确定条目是否为目录,请加入。我觉得检查尾部斜杠很脏。

<?php
// dest 不应该有尾部斜杠
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' );
*/
?>

[由 danbrown AT php DOT net 编辑:根据原始发布者在 2010 年 4 月 18 日的后续说明添加了 $zip-close()。]
0
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;
}
}

// close
$zip -> close();

// retval
if ($ERROR_UNZIP) {
print
"<p>ERROR unziping ${zipfile}</p>";
} else {
print
"<p>Unzip OK</p>";
}
} else {
print
"<p>ERROR opening ${zipfile}</p>";
}

?>
0
skrzypecki at gmail dot com
6 年前
请注意,路径不能太长!我不确定最大长度是多少,没有找到任何相关信息。但我在使用 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/*
就成功了!
===
0
synnus at gmail dot com
6 年前
<?php

// 此版本允许查看将要解压缩的文件,并跟踪解压缩过程
// a follow-up on decompression

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

$za = new ZipArchive();

$za->open(FILEPATH . 'test.zip');
print_r($za);
var_dump($za);
echo
"Nombre de fichiers : " . $za->numFiles . "\n";
echo
"Statut : " . $za->status . "\n";
echo
"Statut du système : " . $za->statusSys . "\n";
echo
"Nom du fichier : " . $za->filename . "\n";
echo
"Commentaire : " . $za->comment . "\n";

/* in $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
"index : $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
"Nombre de fichiers :" . $za->numFiles . "\n";

?>
0
sachinyadav at live dot com
13 年前
此脚本将在 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
"Generating TEXT file.";
for(
$i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
if(
preg_match('#\.(txt)$#i', $entry))
{
////This copy function will move the entry to the root of "txt_files" without creating any sub-folders unlike "ZIP->EXTRACTO" function.
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 archive failed";
}
?>

享受 PHP 编程。
Sachin Yadav
0
tBone
16 年前
至少根据我的经验,此函数会维护/强制 ZIP 文件中的目录结构。

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

如果您在 Apache 下运行 php,则 ZIP 文件中的 .htaccess 文件可能会导致 extractTo() 方法失败。
-7
Anonymous
14 年前
我正在使用此函数从 ZIP 文件中提取特定的文件夹及其内容

<?php
function extractDir($zipfile, $path) {
if (
file_exists($zipfile)) {
$files = array();
$zip = new ZipArchive;
if (
$zip->open($zipfile) === TRUE) {
for(
$i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
// 使用 strpos() 检查条目名称是否包含要提取的目录
if (strpos($entry, "/MyFolder/")) {
// 如果条目在目标目录中,则将其添加到数组中
$files[] = $entry;
}
}
// 将 $files 数组传递给 extractTo() 以获取我们想要的特定文件
if ($zip->extractTo($path, $files) === TRUE) {
return
TRUE;
} else {
return
FALSE;
}
$zip->close();
} else {
return
FALSE;
}
} else {
return
FALSE;
}
}

// 运行函数
if (extractDir($zipfile, $path)) {
$extracted = "YES! :-D";
} else {
$extracted = "NO! :*(";
}

echo
$extracted;
?>
-5
匿名
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;
}

}
// 结束函数
?>
-5
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