【问题标题】:Extract specific files in zip (include sub directories)提取 zip 中的特定文件(包括子目录)
【发布时间】:2016-11-02 06:17:31
【问题描述】:

我只想从 zip 文件中提取图像,但我也希望它也提取在子文件夹中找到的图像。如何根据下面的代码实现这一点。注意:我不是试图保留目录结构在这里,只是想提取在 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();

编辑

我的代码运行良好,我只需要知道如何让 ziparchive 也进入子目录

【问题讨论】:

  • 为什么你认为你的代码没有进入子目录?我用文件a/b/c.pngd.png 创建了a.zip。您的代码将d.pngc.pnga.zip 提取到目标目录中。然后不清楚预期的行为是什么。
  • @Ruslan Osmanov 你是对的,代码工作正常......我得到的错误完全不相关
  • @Ruslan Osmanov 作为答案发布,以便我接受

标签: php php-7 ziparchive


【解决方案1】:

您的代码是正确的。我创建了a.zip 和文件a/b/c.pngd.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

代码将d.pngc.pnga.zip 提取到目标目录中:

$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();

测试

$ php script.php
d.png
a/b/c.png

$ find ./dest -type f
./dest/d.png
./dest/c.png

所以代码是正确的,问题一定出在其他地方。

【讨论】:

    【解决方案2】:

    根据文件扩展名(不一定是最可靠的方法),您可能会发现以下内容很有帮助。

    /* source zip file and target location for extracted files */
    $file='c:/temp2/experimental.zip';
    $destination='c:/temp2/extracted/';
    
    /* Image file extensions to allow */
    $exts=array('jpg','jpeg','png','gif','JPG','JPEG','PNG','GIF');
    $files=array();
    
    /* create the ZipArchive object */
    $zip = new ZipArchive();
    $status = $zip->open( $file, ZIPARCHIVE::FL_COMPRESSED );
    
    
    if( $status  ){
    
        /* how many files are in the archive */
        $count = $zip->numFiles;
    
        for( $i=0; $i < $count; $i++ ){
            try{
    
                $name = $zip->getNameIndex( $i );
                $ext = pathinfo( $name, PATHINFO_EXTENSION );
                $basename = pathinfo( $name, PATHINFO_BASENAME );
    
                /* store a reference to the file name for extraction or copy */
                if( in_array( $ext, $exts ) ) {
                    $files[]=$name;
    
                    /* To extract files and ignore directory structure */
                    $res = copy( 'zip://'.$file.'#'.$name, $destination . $basename );
                    echo ( $res ? 'Copied: '.$basename : 'unable to copy '.$basename ) . '<br />';
                }
    
            }catch( Exception $e ){
                echo $e->getMessage();
                continue;
            }
        }
        /* To extract files, with original directory structure, uncomment below */
        if( !empty( $files ) ){
            #$zip->extractTo( $destination, $files );
        }
        $zip->close();
    
    } else {
        echo $zip->getStatusString();
    }
    

    【讨论】:

    • 我的代码运行良好,我只需要知道如何让 ziparchive 也进入子目录
    【解决方案3】:

    这将允许您遍历路径中的所有目录,并搜索任何图像/具有您定义的扩展名的内容。由于您告诉其他用途您已完成 ziparchive 部分,因此我省略了...

    <?php
    
    function traverse($path, $images = [])
    {
        $files = array_diff(scandir($path), ['.', '..']);
    
        foreach ($files as $file) {
            // check if the file is an image
            if (in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), ['jpg', 'jpeg', 'png', 'gif'])) {
                $images[] = $file;
            }
    
            if (is_dir($path . '/' . $file)) {
                $images = traverse($path . '/' . $file, $images);
            }
        }
    
        return $images;
    }
    
    $images = traverse('/Users/kyle/Downloads');
    

    你想遵循这个过程:

    1. 获取当前工作目录下的所有文件
    2. 如果 CWD 中的文件是图像,则将其添加到图像数组中
    3. 如果CWD中的文件是目录,递归调用traverse函数,在目录中查找图片
    4. 在新的 CWD 中查找图像,如果文件是目录递归等...

    跟踪当前路径很重要,这样您就可以在文件上调用 is_dir。另外,您要确保不要搜索“。”或“..”,否则您将永远不会遇到基本递归情况/它将是无限的。

    这也不会保留图像的目录路径!如果你想这样做,你应该这样做$image[] = $path . '/' . $file;。您可能希望这样做,然后获取函数完成运行所需的所有文件内容。我不建议对 $image 数组中的内容进行排序,因为它可能会占用大量内存。

    【讨论】:

      【解决方案4】:

      关注文件夹的第一件事就是看它——你的代码不会这样做。

      ZIP 中没有文件夹(事实上,即使在文件系统中,“文件夹”也是一个文件,只是一个特殊的文件)。文件(数据)有一个名称,可能包含一个路径(很可能是一个相对路径)。如果“进入子目录”意味着您希望文件系统中的压缩文件具有相同的相对文件夹结构,则必须编写代码来创建这些文件夹。我认为副本不会自动为您执行此操作。

      我修改了您的代码并添加了文件夹的创建。请注意我必须添加以使其可运行的配置变量,将其配置到您的环境中。我还把我所有的调试输出都留在了里面。代码适用于我在 Windows 7、PHP 5.6 上独立运行

      error_reporting(-1 );
      ini_set('display_errors', 1);
      $zip_path = './test/cgiwsour.zip';
      $write_dir = './test'; // base path for output
      
      $zip = new ZipArchive();
      if (!$zip->open($zip_path))
          die('could not open zip file '.PHP_EOL);
      $valid_extensions = ['cpp'];
      $create_subfolders = true;
      
      //extract files in zip
      for ($i = 0; $i < $zip->numFiles; $i++) {
          $file_name = $zip->getNameIndex($i);var_dump($file_name, $i);
          $file_info = pathinfo($file_name);//print_r($file_info);
          //if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
          if (isset($file_info['extension']) && in_array(strtolower($file_info['extension']), $valid_extensions)) {
      
              $tmp_dir = $write_dir;
              if ($create_subfolders) {
                  $dir_parts = explode('/', $file_info['dirname']);
                  print_r($dir_parts);
                  foreach($dir_parts as $folder) {
                      $tmp_dir = $tmp_dir . '/' . $folder;
                      var_dump($tmp_dir);
                      if (!file_exists($tmp_dir)) { 
                          $res = mkdir($tmp_dir);
                          var_dump($res);
                          echo 'created '.$tmp_dir.PHP_EOL;
                      }
                  }
              }
              else {
                  $tmp_dir .= '/' . $file_info['dirname']; 
              }
              //extract only images
      
              $res = copy("zip://" . $zip_path . "#" . $file_name,  $tmp_dir . '/' . $file_info['basename']);
              echo 'match : '.$file_name.PHP_EOL;
              var_dump($res);
          }
      }
      $zip->close();
      

      值得注意的是,由于访问/权限限制,mkdir() 调用可能无法在所有系统上完美运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-30
        • 2023-02-09
        • 2016-07-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多