简体   繁体   中英

PHP - ZipArchive() permission issues with clean up

I keep having - I think permission issues - with unzipping a file (this part goes OK) and moving content to write folder.

I am running simple code:

$zip  = new ZipArchive( );
$x    = $zip->open( $file );
if ( $x === true ) {

  $zip->extractTo( $target );
  $zip->close( );
  unlink( $file );

  rmove( __DIR__ . '/' . $target . '/dist', __DIR__ );
} else {

  die( "There was a problem. Please try again!" );
}

where rmove() is a simple recursive function that iterates thru content and applies rename() to each file.

Problem is that unzipping goes well, files are copied, but not moved - delete from a temporary folder. I read so far that could be caused by not having a write permission to unzipped files at the time of renaming.

How to control those permissions at the time of unzipping?

Update: content of rmove():

function rmove( $src, $dest ) {

    // If source is not a directory stop processing
    if ( ! is_dir( $src ) ) return false;

    // If the destination directory does not exist create it
    if ( ! is_dir( $dest ) ) {

      if ( ! mkdir( $dest ) ) {
        // If the destination directory could not be created stop processing
        return false;
      }
    }

    // Open the source directory to read in files
    $i = new DirectoryIterator( $src );
    foreach( $i as $f ) {

      if ( $f->isFile( ) ) {

        echo $f->getRealPath( ) . '<br/>';
        rename( $f->getRealPath( ), "$dest/" . $f->getFilename( ) );
      } else if ( ! $f->isDot( ) && $f->isDir( ) ) {

        rmove( $f->getRealPath( ), "$dest/$f" );
        unlink( $f->getRealPath( ) );
      }
    }
    unlink( $src );
}

As far as I'm aware ZipArchive::extractTo doesn't set any special write/delete permissions, so you should have full access to the extracted files.

The issue with your code is the rmove function. You're trying to remove directories with unlink , but unlink removes files. You should use rmdir to remove directories.

If we fix that issue, your rmove function works fine.

function rmove($src, $dest) {
    // If source is not a directory stop processing
    if (!is_dir($src)) {
        return false;
    }
    // If the destination directory does not exist create it
    if (!is_dir($dest) && !mkdir($dest)) {
        return false;
    }
    // Open the source directory to read in files
    $contents = new DirectoryIterator($src);
    foreach ($contents as $f) {
        if ($f->isFile()) {
            echo $f->getRealPath() . '<br/>';
            rename($f->getRealPath(), "$dest/" . $f->getFilename());
        } else if (!$f->isDot() && $f->isDir()) {
            rmove($f->getRealPath(), "$dest/$f");
        }
    }
    rmdir($src);
}

You don't have to remove every subfolder in the loop, the rmdir at the end will remove all folders, since this is a recursive function.

If you still can't remove the contents of the folder, then you may not have sufficient permissions. I don't think that's very likely, but in that case you could try chmod .

I just wonder about the $target.'/dist' directory. I assume that the 'dist' directory is coming from the archive. Having pointed out that I can see the 'rmove' function is prone to copy a file to a destination directory before it is created. Your code assumes that the directory will supersede the files in the iterator. If the file path supersedes the directory the destination directory won't exist to copy the file.

I would suggest you an alternative function to your custom written recursive 'rmove' function, which is the RecursiveDirectoryIterator.

http://php.net/manual/en/class.recursivedirectoryiterator.php

Let me simplify your code with RecursiveDirectoryIterator as follows

$directory = new \RecursiveDirectoryIterator( __DIR__ . '/' . $target . '/dist', RecursiveDirectoryIterator::SKIP_DOTS);
$iterator = new \RecursiveIteratorIterator($directory);

foreach ($iterator as $f) {

    if($f->isFile()){
        if(!empty($iterator->getSubpath())) 
              @mkdir(__DIR__."/" . $iterator->getSubpath(),0755,true);

        rename($f->getPathname(), __DIR__."/" . $iterator->getSubPathName());

    }

}

Please check to see whether you still get the permission error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM