1

I have a specific directory which may contain zip files.

I would like to loop through each sub-element of my directory to check if this is a zip. And unzip that. Then process the others files.

I'm using flysystem to work with my files.

So I went for this

$contents = $this->manager->listContents('local://my_directory , true);

foreach ($contents as $file) {
  if( $file['extension'] == 'zip')
    //Unzip in same location
}

The problem is that the files unziped are not in the loop and if the zip file, contain another zip. The second one will be never be unziped.

So I thought about it

function loopAndUnzip(){
    
    $contents = $this->manager->listContents('local_process://' . $dir['path'] , true);

    foreach ($contents as $file) {
      if( $file['extension'] == 'zip')
        //Unzip and after call loopAndUnzip()
    }
}

But the initial function will never be finished and be called over and over if there are zip inside zip. Isn't it a performance issue?

How to manage this kind of thing?

1
  • There is a syntax error in the very first line. Missing quote. The highlighter gives it away. By the looks of it, this error doesn't exist in your actual code, but you may want to fix it, to prevent answers about it. Commented May 7, 2018 at 11:52

2 Answers 2

1

You can use glob to find them, and make the function recursive. You can do this by starting at a certain dir, unzip all the files into it & check if there are new zips.
I recommend using recursive directories as well. If A.zip and B.zip both have a file called example.txt, it overwrites. With dirs it wont:

function unzipAll(string $dirToScan = "/someDir", $depth=0):void {
    if($depth >10 ){
        throw new Exception("Maximum zip depth reached");
    }
    $zipfiles = glob($dirToScan."*.zip");
    // Unzip all zips found this round:
    foreach ($zipfiles as $zipfile) {
        $zipLocation = "/".$zipname;
        // unzip here to $zipLocation

        // and now check if in the zip dir there is stuff to unzip:
        unzipAll($dirToScan.$zipLocation, ++$depth);
    }
}

The $depth is optional, but this way you cant zipbomb yourself to death.

Sign up to request clarification or add additional context in comments.

6 Comments

May work, if you unpack each zipfile in a subfolder, but OP said same location.
I've added the reason why I used subdirs :)
Yes. A good reason. If the requirements allow this, it's indeed safer.
I just had to set $depth++; before the function call otherwise depth is alway 0. Otherwise it's working very well, thanks you!
Fairly certain the $depth++ should've worked. Changed it to +1, no need to do it outside the loop.
|
1

loopAndUnzip will do all files again, so you will just again unpack the same zipfile and start over with the entire folder, ad infinitum.

Some possibilities:

  1. Keep a list of items that was already processed or skipped and don't process those again, so while iterating over $contents, keep a separate array, and have something like:

PHP:

foreach ($contents as $file) {
  if (!array_search($processedFiles, $file) {
    if( $file['extension'] == 'zip')
      //Unzip in same location
  }

  $processedFiles[] = $file;
}
  1. Use an unzipper that returns a list of files/folders created, so you can explicitly process those instead of the full directory contents.

  2. If the unzipper can't do it, you could fake it by extracting to a separate location, get a listing of that location, then move all the files in the original location, and process the list you got.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.