60

I am trying to remove a directory with rmdir, but I received the 'Directory not empty' message, because it still has files in it.

What function can I use to remove a directory with all the files in it as well?

SharpC
  • 6,974
  • 4
  • 45
  • 40
zeckdude
  • 15,877
  • 43
  • 139
  • 187
  • Possible duplicate of [How do I recursively delete a directory and its entire contents (files + sub dirs) in PHP?](http://stackoverflow.com/questions/3338123/how-do-i-recursively-delete-a-directory-and-its-entire-contents-files-sub-dir) – MaxiWheat Jan 29 '16 at 13:19

13 Answers13

140

There is no built-in function to do this, but see the comments at the bottom of http://us3.php.net/rmdir. A number of commenters posted their own recursive directory deletion functions. You can take your pick from those.

Here's one that looks decent:

function deleteDirectory($dir) {
    if (!file_exists($dir)) {
        return true;
    }

    if (!is_dir($dir)) {
        return unlink($dir);
    }

    foreach (scandir($dir) as $item) {
        if ($item == '.' || $item == '..') {
            continue;
        }

        if (!deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) {
            return false;
        }

    }

    return rmdir($dir);
}

You could just invoke rm -rf if you want to keep things simple. That does make your script UNIX-only, so beware of that. If you go that route I would try something like:

function deleteDirectory($dir) {
    system('rm -rf -- ' . escapeshellarg($dir), $retval);
    return $retval == 0; // UNIX commands return zero on success
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 7
    this is extremely dangerous, please add checks to make sure you're not deleting something important like `/` for example.. – John Hunt Mar 10 '20 at 15:00
12
function rrmdir($dir)
{
 if (is_dir($dir))
 {
  $objects = scandir($dir);

  foreach ($objects as $object)
  {
   if ($object != '.' && $object != '..')
   {
    if (filetype($dir.'/'.$object) == 'dir') {rrmdir($dir.'/'.$object);}
    else {unlink($dir.'/'.$object);}
   }
  }

  reset($objects);
  rmdir($dir);
 }
}
John
  • 1
  • 13
  • 98
  • 177
Abhay
  • 225
  • 2
  • 6
7

You could always try to use system commands.

If on linux use: rm -rf /dir If on windows use: rd c:\dir /S /Q

In the post above (John Kugelman) I suppose the PHP parser will optimize that scandir in the foreach but it just seems wrong to me to have the scandir in the foreach condition statement.
You could also just do two array_shift commands to remove the . and .. instead of always checking in the loop.

Community
  • 1
  • 1
AntonioCS
  • 8,335
  • 18
  • 63
  • 92
6

Can't think of an easier and more efficient way to do that than this

function removeDir($dirname) {
    if (is_dir($dirname)) {
        $dir = new RecursiveDirectoryIterator($dirname, RecursiveDirectoryIterator::SKIP_DOTS);
        foreach (new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST) as $object) {
            if ($object->isFile()) {
                unlink($object);
            } elseif($object->isDir()) {
                rmdir($object);
            } else {
                throw new Exception('Unknown object type: '. $object->getFileName());
            }
        }
        rmdir($dirname); // Now remove myfolder
    } else {
        throw new Exception('This is not a directory');
    }
}


removeDir('./myfolder');
Rain
  • 3,416
  • 3
  • 24
  • 40
4

My case had quite a few tricky directories (names containing special characters, deep nesting, etc) and hidden files that produced "Directory not empty" errors with other suggested solutions. Since a Unix-only solution was unacceptable, I tested until I arrived at the following solution (which worked well in my case):

function removeDirectory($path) {
    // The preg_replace is necessary in order to traverse certain types of folder paths (such as /dir/[[dir2]]/dir3.abc#/)
    // The {,.}* with GLOB_BRACE is necessary to pull all hidden files (have to remove or get "Directory not empty" errors)
    $files = glob(preg_replace('/(\*|\?|\[)/', '[$1]', $path).'/{,.}*', GLOB_BRACE);
    foreach ($files as $file) {
        if ($file == $path.'/.' || $file == $path.'/..') { continue; } // skip special dir entries
        is_dir($file) ? removeDirectory($file) : unlink($file);
    }
    rmdir($path);
    return;
}
  • To expand on the need for the preg_replace, it was necessary because some directories (with special characters) would omit subdirectories that clearly existed. I found the preg_replace note from a comment in the php.net documentation for glob(), where someone else struggled for hours with the same issue. – Brandon Elliott May 09 '16 at 20:46
  • This is the only one that could solve my problem too +1, thanks – Franco Jun 20 '16 at 10:46
4

There are plenty of solutions already, still another possibility with less code using PHP arrow function:

function rrmdir(string $directory): bool
{
    array_map(fn (string $file) => is_dir($file) ? rrmdir($file) : unlink($file), glob($directory . '/' . '*'));

    return rmdir($directory);
}
Thiago Cordeiro
  • 589
  • 3
  • 9
3

Here what I used:

function emptyDir($dir) {
    if (is_dir($dir)) {
        $scn = scandir($dir);
        foreach ($scn as $files) {
            if ($files !== '.') {
                if ($files !== '..') {
                    if (!is_dir($dir . '/' . $files)) {
                        unlink($dir . '/' . $files);
                    } else {
                        emptyDir($dir . '/' . $files);
                        rmdir($dir . '/' . $files);
                    }
                }
            }
        }
    }
}

$dir = 'link/to/your/dir';
emptyDir($dir);
rmdir($dir);
Naman
  • 31
  • 1
3

From http://php.net/manual/en/function.rmdir.php#91797

Glob function doesn't return the hidden files, therefore scandir can be more useful, when trying to delete recursively a tree.

<?php 
public static function delTree($dir) { 
   $files = array_diff(scandir($dir), array('.','..')); 
    foreach ($files as $file) { 
      (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); 
    } 
    return rmdir($dir); 
  } 
?>
Mykola Veryha
  • 473
  • 1
  • 4
  • 11
2

Try the following handy function:

/**
 * Removes directory and its contents
 *
 * @param string $path Path to the directory.
 */
function _delete_dir($path) {
  if (!is_dir($path)) {
    throw new InvalidArgumentException("$path must be a directory");
  }
  if (substr($path, strlen($path) - 1, 1) != DIRECTORY_SEPARATOR) {
    $path .= DIRECTORY_SEPARATOR;
  }
  $files = glob($path . '*', GLOB_MARK);
  foreach ($files as $file) {
    if (is_dir($file)) {
      _delete_dir($file);
    } else {
      unlink($file);
    }
  }
  rmdir($path);
}
kenorb
  • 155,785
  • 88
  • 678
  • 743
2

I didn't arrive to delete a folder because PHP said me it was not empty. But it was. The function by Naman was the good solution to complete mine. So this is what I use :

function emptyDir($dir) {
    if (is_dir($dir)) {
        $scn = scandir($dir);
        foreach ($scn as $files) {
            if ($files !== '.') {
                if ($files !== '..') {
                    if (!is_dir($dir . '/' . $files)) {
                        unlink($dir . '/' . $files);
                    } else {
                        emptyDir($dir . '/' . $files);
                        rmdir($dir . '/' . $files);
                    }
                }
            }
        }
    }
}

function deleteDir($dir) {

    foreach(glob($dir . '/' . '*') as $file) {
        if(is_dir($file)){


            deleteDir($file);
        } else {

          unlink($file);
        }
    }
    emptyDir($dir);
    rmdir($dir);
}

So, to delete a directory and recursively its content :

deleteDir($dir);
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
francoisV
  • 79
  • 3
1

With this function, you will be able to delete any file or folder

function deleteDir($dirPath)
{
    if (!is_dir($dirPath)) {
        if (file_exists($dirPath) !== false) {
            unlink($dirPath);
        }
        return;
    }

    if ($dirPath[strlen($dirPath) - 1] != '/') {
        $dirPath .= '/';
    }

    $files = glob($dirPath . '*', GLOB_MARK);
    foreach ($files as $file) {
        if (is_dir($file)) {
            deleteDir($file);
        } else {
            unlink($file);
        }
    }

    rmdir($dirPath);
}
Chris Forrence
  • 10,042
  • 11
  • 48
  • 64
0
function delTree($dir) { 
    $files = array_diff(scandir($dir), array('.','..')); 
     foreach ($files as $file) 
       (is_dir("$dir/$file")) ? delTree("$dir/$file") : @unlink("$dir/$file"); 
     return @rmdir($dir); 
} 
0
array_map('unlink', glob("your/path/*.*"));
rmdir("your/path");
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
japetko
  • 354
  • 4
  • 14