0

I have an directory tree which has been passed to array.

I would like to there empty folders inside this array.

How can I determine empty folders like /wp-content/uploads/2014/02/ and /wp-content/uploads/2014/. How can I delete them recursively.

Here is my array

array (
  0 => './do-update.php',
  5 => './wp-config.php',
  6 => './wp-content/',
  7 => './wp-content/uploads/',
  8 => './wp-content/uploads/2013/',
  9 => './wp-content/uploads/2013/05/',
  10 => './wp-content/uploads/2013/05/kabeduvarkad-1024x768.jpg',
  26 => './wp-content/uploads/2013/05/kabeduvarkad2.jpg',
  27 => './wp-content/uploads/2013/10/',
  28 => './wp-content/uploads/2014/',
  29 => './wp-content/uploads/2014/02/',
  30 => './wp-content/uploads/de.php',
  31 => './wp-update.tar.gz',
  32 => './wp-update/',
  33 => './wp-update/wp-update.tar',
)

Thank you very much to Andresch Serj for him effords. Who wants to delete empty folders recursively with performance, you can use this solution.

function list_directory($dir) {
   $file_list = array();
   $stack[] = $dir;

   while ($stack) {
        $current_dir = array_pop($stack);
        if ($dh = opendir($current_dir)){
            while (($file = readdir($dh)) !== false) {
                if ($file !== '.' AND $file !== '..') {
                    $current_file = "{$current_dir}/{$file}";
                    $report = array();
                    if (is_file($current_file)) {
                        $file_list[] = "{$current_dir}/{$file}";
                    } elseif (is_dir($current_file)) {
                        $stack[] = $current_file;
                        $file_list[] = "{$current_dir}/{$file}/";
                    }
                }
            }
        }
    }
    sort($file_list, SORT_LOCALE_STRING);
    return $file_list;
}

function remove_emptyfolders($array_filelist){
    $files = array();
    $folders = array();
    foreach($array_filelist as $path){
        // better performance for is_dir function
        if ($path[strlen($path)-1] == '/'){ // check for last character if it is / which is a folder.
            $folders[] = $path;
        }
        else{
            $files[] = $path;
        }
    }

    // bos olmayan klasorleri buluyoruz.
    // eger klasor ismi dosya isimlerinin icerisinde gecmiyorsa bos demektir? right?
    $folders_notempty = array();
    foreach($files as $file){
        foreach($folders as $folder){
            if(strpos($file,$folder) !== false){
                // dublicate olmasin diye key isimlerinin ismine yazdırdık.
                $folders_notempty[$folder] = $folder;
            }
        }
    }

    // bos olmayanla klasorleri, digerlerinden cikariyoruz.
    $folders_empty = array();
    foreach($folders as $folder){
        // eger bos olmayanlarin icerisinde bu dosya yoksa
        if(!in_array($folder, $folders_notempty)){
            $folders_empty[] = $folder;
        }
    }

    // once en uzaktan silmeye baslamaliyiz. kisaca tersten.
    $folders_empty = array_reverse($folders_empty);
    $folders_deleted = array();

    foreach($folders_empty as $k){
        try{
            $folders_deleted[$k] = 'NOT Succesfull';
            if(rmdir($k)){ $folders_deleted[$k] = 'Deleted'; continue; }
            chmod($k, 0777); 
            if(rmdir($k)){ $folders_deleted[$k] = 'Deleted after chmod'; }
        }catch (Exception $e) {
            print_r($e);
        }
    }

    return $folders_deleted;

}

$files = list_directory(getcwd());
//print_r($files);
$files_deleted = remove_emptyfolders($files);

print_r($files_deleted);
Deniz Porsuk
  • 492
  • 1
  • 6
  • 20
  • 1. just check the folders one by one using phps file system functions and 2. you don't have to delete recursively, since the folders to be deleted should be empty, shouldn't they be? – arkascha May 05 '14 at 09:12
  • Duplicate of http://stackoverflow.com/questions/1833518/remove-empty-subfolders-with-php – Vincent Decaux May 05 '14 at 09:13
  • Vincent is right, Small difference was the problem of recognizing folder for this case. Andresch Serj has solved this with is_dir. Now problem is how to delete them? Because when we try to delete empty1 before empty2 / empty1 can not be deleted it is not free (empty1/empty2) – Deniz Porsuk May 05 '14 at 09:43
  • @DenizPorsuk I made an EDIT to my Answer having two recursive functions that solve your problem. Please accept the answer if it suits your problem or clarify if it still doesn't. Also, since a lot of effort has been put into answering your question by now, consider upvoting to show some appreciation. – Andresch Serj May 05 '14 at 11:16

1 Answers1

0

Simply iterate over your array using foreach.

foreach ($filesArray as $file) {

Then for each file, check if it is a folder using is_dir like this

if (is_dir ($file)) {

If it is a folder/directory, read the directory, for instanse using scandir.

$directoryContent = scandir($file);

If the result of scandir is empty, you have an empty folder that you can delete with unlink.

if (count($directoryContent) <= 2) { // checkig if there is moire than . and ..
  unlink($file);

If you have trouble with unlink, you may have to set file permissions accordingly.

If instead you need a function that recursively deletes empty subfolders given some paht, you should consider reading the SO question that was linkes in the comments.

EDIT

After taking into consideration your comments, what you do want is a function that deletes parent folders as well. So for a geiven level1/level2/level3 where level3 is empty and the only folder/file in level2 you want level2 to be deleted as well.

So from your example array, you want ./wp-content/uploads/2014/ deleted and not just ./wp-content/uploads/2014/10, but only if ./wp-content/uploads/2014/10 has no content or subfolders with content.

So how to do that?

Simle: Extend your check for weather that folder is empty. If it is empty, manipoulate the given file/path string to get the parent folder. By now you should outsource this to a recursive functions indeed.

function doesDirectoryOnlyContainEmptyFolders($path) {
  if(is_dir($path) {
    $directoryContent = scandir($path);
    if (count($directoryContent) <= 2) {
      return true;
    }
    else {
      foreach ($directoryContent as $subPath) {
        if($filePath !== '.' && $filePath !== '..' && !doesDirectoryOnlyContainEmptyFolders($subPath)) {
          return false;
        }
      }
      return true;
    }
  }
  return false;
}

So this function checks recursively if a path has only empty folders or folders containing empty folders - recursively. Now you want to check your paths and maybe delete them, recursively downwards and upwards.

function deleteEmptyFoldersRecursivelyUpAndDown($path) {
  if (is_dir($path)) {
    if(doesDirectoryOnlyContainEmptyFolders($path)) {
      unlink($path);
      $parentFolder = substr($path, 0, strripos ($path, '/'));
      deleteEmptyFoldersRecursivelyUpAndDown($parentFolder);
    }
    else {
      $directoryContent = scandir($path);
      foreach ($directoryContent as $subPath) {
        deleteEmptyFoldersRecursivelyUpAndDown($subPath);
      }
    }
  }
}

If the given path is a directory, we check if it is empty using our recursive function. If it is, we delete it and recursively check the parent directory. If it is not, we iterate over its content to find empty folders, again calling the function itself recursively.

With these two function you have all you need. Simply iterate over your path array and use deleteEmptyFoldersRecursivelyUpAndDownon all entries. If they are faulty, you'll manage to debug them i presume.

Community
  • 1
  • 1
Andresch Serj
  • 35,217
  • 15
  • 59
  • 101
  • I will check your function for recursive empty directories.. Probably for empt3/empt2/empt3 ($directoryContent) will not return 0 – Deniz Porsuk May 05 '14 at 09:32
  • Probably scandir counts . and .. thats why $directoryContent never turns 0. When I use like count($directoryContent) == 2 this case does not recognize folders like /empty/empty2/empty3 it founds only /empty3 – Deniz Porsuk May 05 '14 at 09:40
  • @DenizPorsuk True. As the documentation states in the example, it does return `.` and `..`. I made an edit. You should accept my answer if it works. – Andresch Serj May 05 '14 at 09:47
  • does not work for empty1/empty2/empty3 / are there any solution for empty subdirectories – Deniz Porsuk May 05 '14 at 09:51
  • How does it not work for `empty1/empty2/empty3`? `empty1` is not empty since it has the folder `empty2` in it right? It seems it is unclear what you where asking for in the first place. You have an array of files and folders and you want to delete the empty folders. That is what my code does. Somehow you thing you need recursion. Do you want to check "not empty" folder for empty subfolders? – Andresch Serj May 05 '14 at 09:54
  • Dear @AndreschSerj your approach deletes empty3 but not empty2 but when I delete empty3 I'm having another empty directory which is empty2. But question was "Finding empty folders from array list and delete them" I'm looking for deleting all of them. – Deniz Porsuk May 05 '14 at 10:49
  • @DenizPorsuk I see. So you DO want a recursice function deleting parent folders, not subfolders. SAo for a given `var/www/project1` you want the `var` folder deleted if `proejct1` is empty and the only file/folder in `www` and `www` is the only folder in `var` right? – Andresch Serj May 05 '14 at 10:53
  • Actually I want to delete all folders which does not have a file. – Deniz Porsuk May 05 '14 at 12:20
  • I got that now. See my Edit and consider closing this question by accepting my answer. – Andresch Serj May 05 '14 at 12:44
  • Thank you very much for your helps. I appreciated. I have another question if you are interested. Is it possible to find empty folders recursively directly from array list. Without using glob / scandir. (Because for big amount of data it will have too much process) I mean is it possible to have an approach like merge folders to longest tree and if last character of file path is "/" this is empty.. I will be glad if you answer.. – Deniz Porsuk May 05 '14 at 13:06
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/52036/discussion-between-andresch-serj-and-deniz-porsuk) – Andresch Serj May 05 '14 at 13:07
  • Please provide me your opinions about my solution.. Deniz. – Deniz Porsuk May 05 '14 at 15:17