Bruner
Bruner

Reputation: 43

Zipping files in a folder without a parent folder in the zipped file

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

Answers (2)

UnholyRanger
UnholyRanger

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

guessimtoolate
guessimtoolate

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

Related Questions