Ne-Lexa / php-zip

PhpZip is a php-library for extended work with ZIP-archives.
MIT License
491 stars 60 forks source link

Iterating entries throws an exception when ->addEmptyDir() has been used #69

Open benswinburne opened 3 years ago

benswinburne commented 3 years ago
Q A
Library version(s) affected: ^3.3
PHP version(s): 7.4.10
OS (with bit depth): ProductName: macOS ProductVersion: 11.1 BuildVersion: 20C5048k

Description
Iterating entries throws an exception when ->addEmptyDir() has been used

How to reproduce

    $zipFile = (new ZipFile())
        ->addEmptyDir('images/')
        ->addFromString('images/cheese.jpg', 'brie');

    foreach ($zipFile as $filename) {
        echo $filename;
    }

No data for zip entry images/

Possible Solution

I can't wrap the foreach in a try catch because it doesn't continue iterating. Is this a bug or am I approaching this wrong? I'd expect it to iterate over the file list and $contents be null (as thats how the empty dirs are created) where it is a directory as opposed to throwing an exception.

Additional context

I am creating some zips in tests and I would like to create zips in similar formats to those i'm occasionally processing. For example, I'd tested various scenarios but then as soon as i used a real zip which had a file structure like the below it failed (for reasons unrelated to this library).

images/
images/foo.jpg
images/bar.jpg

I'd obviously like to write a test which simulates this scenario so I tried adding an empty dir which works, and i can see the images/ dir there if I $zipFile->getListFiles().

$zipFile->addEmptyDir('images/');

However, some of my other code uses

foreach ($zipFile as $filename => $contents) {
   // ...
}

Which then throws an exception

No data for zip entry images/

Thanks very much for your time.

Edit:

I also just tried using an ArrayIterator

    $zipFile = (new ZipFile())
        ->addEmptyDir('images/')
        ->addFromString('images/cheese.jpg', 'brie');

    $iterator = new \ArrayIterator($zipFile);
    echo $iterator->count(); // 0

Edit2:

I can iterate and catch like this as a workaround.

    foreach ($zip->getListFiles() as $filename) {
        try {
            $contents = $zip->getEntryContents($filename);

            dump($filename);
        } catch (ZipException $e) {
        }
    }