Search code examples
phpphp-7php-ziparchive

Extract specific files in zip (include sub directories)


I want to extract only images from a zip file but i also want it to extract images that are found in subfolders as well.How can i achieve this based on my code below.Note: i am not trying to preserve directory structure here , just want to extract any image found in zip.

//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
    $file_name = $zip->getNameIndex($i);
    $file_info = pathinfo($file_name);
    //if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
    if (in_array($file_info['extension'], $this->config->getValidExtensions())) {
        //extract only images
        copy("zip://" . $zip_path . "#" . $file_name, $this->tmp_dir . '/images/' . $file_info['basename']);
    }
}
$zip->close();

Edit

My code works fine all i need to know is how to make ziparchive go in subdirectories as well


Solution

  • Your code is correct. I have created a.zip with files a/b/c.png, d.png:

    $ mkdir -p a/b
    $ zip -r a.zip d.png a
      adding: d.png (deflated 4%)
      adding: a/ (stored 0%)
      adding: a/b/ (stored 0%)
      adding: a/b/c.png (deflated 8%)
    
    $ unzip -l a.zip 
    Archive:  a.zip
      Length      Date    Time    Name
    ---------  ---------- -----   ----
       122280  11-05-2016 14:45   d.png
            0  11-05-2016 14:44   a/
            0  11-05-2016 14:44   a/b/
        36512  11-05-2016 14:44   a/b/c.png
    ---------                     -------
       158792                     4 files
    

    The code extracted both d.png and c.png from a.zip into the destination directory:

    $arch_filename = 'a.zip';
    $dest_dir = './dest';
    if (!is_dir($dest_dir)) {
      if (!mkdir($dest_dir, 0755, true))
        die("failed to make directory $dest_dir\n");
    }
    
    $zip = new ZipArchive;
    if (!$zip->open($arch_filename))
      die("failed to open $arch_filename");
    
    for ($i = 0; $i < $zip->numFiles; ++$i) {
      $path = $zip->getNameIndex($i);
      $ext = pathinfo($path, PATHINFO_EXTENSION);
      if (!preg_match('/(?:jpg|png)/i', $ext))
        continue;
      $dest_basename = pathinfo($path, PATHINFO_BASENAME);
      echo $path, PHP_EOL;
      copy("zip://{$arch_filename}#{$path}", "$dest_dir/{$dest_basename}");
    }
    
    $zip->close();
    

    Testing

    $ php script.php
    d.png
    a/b/c.png
    
    $ find ./dest -type f
    ./dest/d.png
    ./dest/c.png
    

    So the code is correct, and the issue must be somewhere else.