Search code examples
phpzipphp-stream-wrappers

Is it possible to use glob pattern for matching zip contents?


I thought I conveniently could list any contents in a zip file using a glob pattern. But that didn't seem to work. Is there a way?

<?php

  $contents = glob('zip://path/to/archive.zip#subdir/*.ext');
  var_dump($contents);

The zip:// stream wrapper doesn't seem to return directory contents at all.

scandir('zip://path/to/archive.zip#subdir/');  // array(0){}

The documentation is not too helpful: https://www.php.net/manual/en/wrappers.compression.php


Solution

  • There are multiple problems here. glob() does not support stream wrappers. And the stream wrapper for zip:// does not have an implementation for listing directory contents.

    So both the stream wrapper and glob() implementation would need a replacement.

    What might be more convenient is to write a function that extracts data from a ZIPArchive() object and filter it using fnmatch():

      function globzip($archive, $pattern, $flags = 0) {
    
        $zip = new ZipArchive();
        $zip->open($archive, ZipArchive::RDONLY);
    
        $results = [];
        for ($i = 0; $i < $zip->numFiles; $i++) {
          $file = $zip->getNameIndex($i);
          if (fnmatch($pattern, $file, $flags)) {
            $results[] = $file;
          }
        }
    
        return $results;
      }
    

    Can be used like this:

    $files = globzip('/path/to/.zip', 'subdirectory/*.ext'));
    

    https://www.php.net/manual/en/function.fnmatch.php https://www.php.net/manual/en/class.ziparchive