【问题标题】:Zipping files in a folder without a parent folder in the zipped file将文件压缩到压缩文件中没有父文件夹的文件夹中
【发布时间】:2013-03-14 21:34:07
【问题描述】:

这对大多数人来说可能是一个愚蠢的问题,但我有以下文件夹,我想压缩它。

FolderI
   Folder1
   Folder2
   Folder3
   ..
   ..
   FolderN

现在,将FolderI 压缩成zipFile.zip 非常容易,因为网上有很多资源,特别是这里!但是,我想创建包含Folder1...FolderNzipFile.zip,这样当文件解压缩时,它会直接用Folder1...FolderN 填充当前目录,而不是创建FolderI,其中包含Folder1...FolderN

我一直在尝试的一些事情是:

$zip = new ZipArchive();

// open archive 
if ($zip->open('my-archive.zip', ZIPARCHIVE::CREATE) !== TRUE) {
    die ("Could not open archive");
}

// initialize an iterator
// pass it the directory to be processed
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("FolderI/"));

// iterate over the directory
// add each file found to the archive
foreach ($iterator as $key=>$value) {
    $zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
}

// close and save archive
$zip->close();

这是从compress/archive folder using php script 获取的,我试图改变它。不过没用 - FolderI 仍然是压缩的。但是,当我解压缩 my-archive.zip 时,我会在其中得到一个 FolderIFolder1..FolderN。我还在这里某处看到了来自@Alix 的代码,它做了同样的事情。但是,并没有真正关注太多。

任何形式的帮助都会很棒。如果不是代码,至少指出我正确的方向。

谢谢

****这里有人知道怎么做吗? ****

@Mods and Admins:是解决方案太简单还是 PHP 根本无法做到这一点?

【问题讨论】:

  • 好问题。希望你能得到答案。如果你在几天内没有,提醒我,我可能会悬赏。
  • 谢谢,@deceze!我很确定这很棘手。从昨天开始,我就在谷歌上大发雷霆。感谢您的有用评论! :)
  • 您能否添加对它当前功能的描述(解释“虽然没有工作”?比如,您当前的代码是否仍然压缩FolderI?跨度>
  • @UnholyRanger:已编辑!希望这能让它更清楚。 :)
  • 您的代码和描述将做两件截然不同的事情。该代码将所有文件放入 zip 中,没有任何目录结构(由于使用基本名称)。您的描述说 zip 包含文件夹:您的代码不能这样做。附:要获取当前文件的相对路径而不迭代基目录的路径,请使用 RecursiveDirectoryIterator 的getSubPathname() 方法。

标签: php zip


【解决方案1】:

这里出现的问题是迭代器中的$key是完整路径(因为默认使用RecursiveDirectoryIterator::KEY_AS_PATHNAME标志),其中包括RecursiveDirectoryIterator构造函数中指定的相对部分。

例如,我们有以下层次结构:

folderI
├─ folder1
│  ├─ item.php
│  └─ so.php
└─ folder2
   └─ item.html

还有一个使用new RecursiveDirectoryIterator("folderI") 创建的迭代器。

当您回显$key 时,您将获得item.php 的以下内容

folderI/folder1/item.php

类似地,如果我们使用new RecursiveDirectoryIterator("../somewhere/folderI"),那么$key 将如下所示:

../somewhere/folderI/folder1/item.php

您希望获取文件的路径,但不包括用于创建迭代器的路径。值得庆幸的是,RecursiveDirectoryIterator 有一个方法,其生命中的唯一目的就是做到这一点。

RecursiveDirectoryIterator::getSubPathname()

你可以使用下面的会更容易

$newKey = $iterator->getSubPathname();

这将返回 item.php 的以下内容,给定与上图相同的文件夹结构:

folder1/item.php

方法可以这样使用:

foreach ($iterator as $key=>$value) {
    $zip->addFile(realpath($key), $iterator->getSubPathname()) or die ("ERROR: Could not add file: $key");
}

旁白:我们可以在这里使用$iterator->getSubPathname(),因为 RecursiveIteratorIterator 将对未知方法的任何调用传递给“内部迭代器”,在本例中是 RecursiveDirectoryIterator。同样,您可以使用$iterator->getInnerIterator()->getSubPathname(),两者都做同样的工作。

【讨论】:

  • 提示:getSubPathname()
  • @Unholy Ranger:我试过这个,它和我的updated 代码完全一样。我错误地插入了我正在尝试的代码之一。但是在@salathe 指出这一点之后,我已经更新了代码。你提供的代码做同样的事情。在我解压缩my-archive.zip 后,我仍然得到包含子文件夹的父文件夹
  • @UnholyRanger:代码对exactly 的作用与之前相同。解压缩my-archive.zip 后,我得到一个文件夹FolderI,然后是其中的所有子文件夹。我需要的是脚本在我解压缩文件后直接显示所有子文件夹。不能这样做吗?
  • @Bruner 是的,它可以。但是,我不知道我还能解释多少。我的整个回答涵盖了为什么 folderI 在 zip 中以及如何删除它。请仔细阅读并了解$zip->addFile 函数的工作原理。我已经亲自测试过这段代码,它可以工作
  • 如果您正在解压缩文件,有时系统会将其解压缩到以 zip 文件命名的本地文件夹中。我相信这就是 Mac 在打开 ZIP 时所做的事情。如果你解压缩内容,你会看到它正在做你想做的事情。
【解决方案2】:

就方向而言,我可以提供这个:

这对我来说看起来有点过于复杂,但您可以通过添加一个 foreach 循环来创建这些迭代器,如下所示:

foreach (glob('./*', GLOB_ONLYDIR) as $dir_name) {
   // iterator
   // add file
}

Glob 可能会为您做更多事情,可能会消除那些迭代器对象以支持仅迭代 glob 输出。

【讨论】:

  • 在 foreach 中添加迭代器不会有问题!我确实尝试过,它似乎爆炸了。我在您的建议中使用$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("FolderI/")); 代替迭代器。