Reputation: 43
This maybe a silly question to most, but I have the following folder, which I want to zip.
FolderI
Folder1
Folder2
Folder3
..
..
FolderN
Now, zipping up FolderI
into a zipFile.zip
is pretty easy because of so many resources online, specially here! But, I want to create zipFile.zip
, containing Folder1...FolderN
, such that when the file is unzipped, it would directly populate the current directory with Folder1...FolderN
,instead of creating FolderI
, which has Folder1...FolderN
in it.
Some of the things I've been trying are:
$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();
This was picked up from compress/archive folder using php script and I tried to change it around. Didn't work though - The FolderI is still zipped. But, when I unzip the my-archive.zip
, I get a FolderI
and then Folder1..FolderN
inside it. I also saw code from @Alix somewhere here, which did the same thing. But, didn't really follow much.
Any kind of help would be great. If not the code, at least point me to the right direction.
Thanks
****Anyone here knows how to do this? ****
@Mods and Admins: Is the solution too simple or PHP can't do this at all?
Upvotes: 4
Views: 3548
Reputation: 1971
The problem that is occuring here is that the $key
in the iterator is the full path (since the RecursiveDirectoryIterator::KEY_AS_PATHNAME
flag is used by default), which includes the relative part specified in the RecursiveDirectoryIterator constructor.
So for example we have the following hierarchy:
folderI
├─ folder1
│ ├─ item.php
│ └─ so.php
└─ folder2
└─ item.html
And an iterator created with new RecursiveDirectoryIterator("folderI")
.
When you echo out the $key
you will get the following for item.php
folderI/folder1/item.php
Similarly, if we did new RecursiveDirectoryIterator("../somewhere/folderI")
, then $key
would look like:
../somewhere/folderI/folder1/item.php
You wish to get the path to the file, without including the path used to create the iterator. Thankfully, the RecursiveDirectoryIterator has a method whose sole purpose in life is to do exactly this.
RecursiveDirectoryIterator::getSubPathname()
You can use the following which will be easier
$newKey = $iterator->getSubPathname();
This will return the following for item.php
, given the same folder structure shown above:
folder1/item.php
The method can be used like so:
foreach ($iterator as $key=>$value) {
$zip->addFile(realpath($key), $iterator->getSubPathname()) or die ("ERROR: Could not add file: $key");
}
Aside: we can use $iterator->getSubPathname()
here because the RecursiveIteratorIterator passes along any calls to unknown methods to the "inner iterator", which in this case is the RecursiveDirectoryIterator. Equally, you could do $iterator->getInnerIterator()->getSubPathname()
, both do the same job.
Upvotes: 2
Reputation: 8632
As far as directions go, I can offer this:
This looks a bit overcomplicated to me as it is, but you can pile on by adding a foreach loop to create those iterators like so:
foreach (glob('./*', GLOB_ONLYDIR) as $dir_name) {
// iterator
// add file
}
Glob could probably do a lot more for you, possibly eliminate those iterator objects in favour of just iterating over glob output.
Upvotes: 1