Search code examples
phparraysziprecursive-query

Exclude directories & files from RecursiveDirectoryIterator


I'm trying to ZIP a folder and all its files and subfolder EXCEPT some files and folders. I have an array of files and folders to exclude. Works for the files, but folders in the exclude array are not excluded... here is the code :

if(isset($_POST['tourpath'])){
$source = $_POST['tourpath'];
$cache_name = $_POST['cache_name'];
$destination = $cache_name.'.zip';

if (!extension_loaded('zip') || !file_exists($source) || file_exists($destination)) {
    return false;
}

$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
    return false;
}

$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true)
{
    $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
    
    $exclude_files = array('zipmytour.php','krpano_sworker.js','cache_settings.js','lib','b','d','f','l','r','u');

        
    foreach ($files as $file)
    {   
        if (!in_array($file->getFilename(),$exclude_files)) {
        $file = str_replace('\\', '/', $file);

        // Ignore "." and ".." folders
        if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) )
            continue;

        $file = realpath($file);

        if (is_dir($file) === true)
        {
            $zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
        }
        else if (is_file($file) === true)
        {
            $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
        }
    }}
    
    
}
else if (is_file($source) === true)
{
    $zip->addFromString(basename($source), file_get_contents($source));
}

return $zip->close();

}

How to also exclude folders ? Many thx !!!


Solution

  • A function is useful that checks whether a directory name from an array is present in a path:

    function isDirInPath(array $dirs, $path) {
      $path = str_replace('\\', '/', $path);
      foreach($dirs as $dir){
        if(strpos($path,'/'.trim($dir,"/").'/') !== false){
          return true;
        }
      }
      return false;
    }
    

    example for the use of the function:

    $files = new RecursiveIteratorIterator(
               new RecursiveDirectoryIterator($source,FilesystemIterator::SKIP_DOTS), 
               RecursiveIteratorIterator::SELF_FIRST
    );
    $excludeDir = ['dir1','dir2'];
    
    foreach($files as $path => $file){
      if(!$file->isDir() AND !isDirInPath($excludeDir,$path)){
         echo $file->getFileName(), '<br>';
      }
    }
    

    Note: The entire path does not have to be in the $ excludeDir array. 'dir1' is sufficient to hide everything under '/foo/dir1/bar/'.