[php] How do I recursively delete a directory and its entire contents (files + sub dirs) in PHP?

How do I delete a directory and its entire contents (files and subdirectories) in PHP?

This question is related to php recursion delete-directory

The answer is


There is another thread with more examples here: A recursive remove directory function for PHP?

If you are using Yii then you can leave it to the framework:

CFileHelper::removeDirectory($my_directory);

The 100% working solution

public static function rmdir_recursive($directory, $delete_parent = null)
  {
    $files = glob($directory . '/{,.}[!.,!..]*',GLOB_MARK|GLOB_BRACE);
    foreach ($files as $file) {
      if (is_dir($file)) {
        self::rmdir_recursive($file, 1);
      } else {
        unlink($file);
      }
    }
    if ($delete_parent) {
      rmdir($directory);
    }
  }

Something like this?

function delete_folder($folder) {
    $glob = glob($folder);
    foreach ($glob as $g) {
        if (!is_dir($g)) {
            unlink($g);
        } else {
            delete_folder("$g/*");
            rmdir($g);
        }
    }
}

Deletes all files and folders in the path.

function recurseRmdir($dir) {
  $files = array_diff(scandir($dir), array('.','..'));
  foreach ($files as $file) {
    (is_dir("$dir/$file")) ? recurseRmdir("$dir/$file") : unlink("$dir/$file");
  }
  return rmdir($dir);
}

Modified variant of @XzaR solution. It does remove empty folders, when all files are deleted from them and it throws exceptions instead of returning false on errors.

function recursivelyRemoveDirectory($source, $removeOnlyChildren = true)
{
    if (empty($source) || file_exists($source) === false) {
        throw new Exception("File does not exist: '$source'");
    }

    if (is_file($source) || is_link($source)) {
        if (false === unlink($source)) {
            throw new Exception("Cannot delete file '$source'");
        }
    }

    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );

    foreach ($files as $fileInfo) {
        /** @var SplFileInfo $fileInfo */
        if ($fileInfo->isDir()) {
            if ($this->recursivelyRemoveDirectory($fileInfo->getRealPath()) === false) {
                throw new Exception("Failed to remove directory '{$fileInfo->getRealPath()}'");
            }
            if (false === rmdir($fileInfo->getRealPath())) {
                throw new Exception("Failed to remove empty directory '{$fileInfo->getRealPath()}'");
            }
        } else {
            if (unlink($fileInfo->getRealPath()) === false) {
                throw new Exception("Failed to remove file '{$fileInfo->getRealPath()}'");
            }
        }
    }

    if ($removeOnlyChildren === false) {
        if (false === rmdir($source)) {
            throw new Exception("Cannot remove directory '$source'");
        }
    }
}

Using DirectoryIterator and recursion correctly:

function deleteFilesThenSelf($folder) {
    foreach(new DirectoryIterator($folder) as $f) {
        if($f->isDot()) continue; // skip . and ..
        if ($f->isFile()) {
            unlink($f->getPathname());
        } else if($f->isDir()) {
            deleteFilesThenSelf($f->getPathname());
        }
    }
    rmdir($folder);
}

<?php

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;

# http://stackoverflow.com/a/3352564/283851
# https://gist.github.com/XzaR90/48c6b615be12fa765898

# Forked from https://gist.github.com/mindplay-dk/a4aad91f5a4f1283a5e2

/**
 * Recursively delete a directory and all of it's contents - e.g.the equivalent of `rm -r` on the command-line.
 * Consistent with `rmdir()` and `unlink()`, an E_WARNING level error will be generated on failure.
 *
 * @param string $source absolute path to directory or file to delete.
 * @param bool   $removeOnlyChildren set to true will only remove content inside directory.
 *
 * @return bool true on success; false on failure
 */
function rrmdir($source, $removeOnlyChildren = false)
{
    if(empty($source) || file_exists($source) === false)
    {
        return false;
    }

    if(is_file($source) || is_link($source))
    {
        return unlink($source);
    }

    $files = new RecursiveIteratorIterator
    (
        new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );

    //$fileinfo as SplFileInfo
    foreach($files as $fileinfo)
    {
        if($fileinfo->isDir())
        {
            if(rrmdir($fileinfo->getRealPath()) === false)
            {
                return false;
            }
        }
        else
        {
            if(unlink($fileinfo->getRealPath()) === false)
            {
                return false;
            }
        }
    }

    if($removeOnlyChildren === false)
    {
        return rmdir($source);
    }

    return true;
}

<?php

/**
 * code by Nk ([email protected])
 */

class filesystem
{
    public static function remove($path)
    {
        return is_dir($path) ? rmdir($path) : unlink($path);
    }

    public static function normalizePath($path)
    {
        return $path.(is_dir($path) && !preg_match('@/$@', $path) ? '/' : '');      
    }

    public static function rscandir($dir, $sort = SCANDIR_SORT_ASCENDING)
    {
        $results = array();

        if(!is_dir($dir))
        return $results;

        $dir = self::normalizePath($dir);

        $objects = scandir($dir, $sort);

        foreach($objects as $object)
        if($object != '.' && $object != '..')
        {
            if(is_dir($dir.$object))
            $results = array_merge($results, self::rscandir($dir.$object, $sort));
            else
            array_push($results, $dir.$object);
        }

        array_push($results, $dir);

        return $results;
    }

    public static function rrmdir($dir)
    {
        $files = self::rscandir($dir);

        foreach($files as $file)
        self::remove($file);

        return !file_exists($dir);
    }
}

?>

cleanup.php :

<?php

/* include.. */

filesystem::rrmdir('/var/log');
filesystem::rrmdir('./cache');

?>

Enhanced @Artefacto 's solution - corrected typos and simplified code, working for both - empty && non-empty directories .

  function recursive_rmdir($dir) { 
    if( is_dir($dir) ) { 
      $objects = array_diff( scandir($dir), array('..', '.') );
      foreach ($objects as $object) { 
        $objectPath = $dir."/".$object;
        if( is_dir($objectPath) )
          recursive_rmdir($objectPath);
        else
          unlink($objectPath); 
      } 
      rmdir($dir); 
    } 
  }

'simple' code that works and can be read by a ten year old:

function deleteNonEmptyDir($dir) 
{
   if (is_dir($dir)) 
   {
        $objects = scandir($dir);

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

        reset($objects);
        rmdir($dir);
    }
}

Please note that all I did was expand/simplify and fix (didn't work for non empty dir) the solution here: In PHP how do I recursively remove all folders that aren't empty?


It seems that all other answers assume the path given to the function is always a directory. This variant works to remove directories as well as single files:

/**
 * Recursively delete a file or directory.  Use with care!
 *
 * @param string $path
 */
function recursiveRemove($path) {
    if (is_dir($path)) {
        foreach (scandir($path) as $entry) {
            if (!in_array($entry, ['.', '..'])) {
                recursiveRemove($path . DIRECTORY_SEPARATOR . $entry);
            }
        }
        rmdir($path);
    } else {
        unlink($path);
    }
}

Once you finish running tests , just remove # from the #unlink and #rmdir in the class .

<?php 
class RMRFiles {

        function __construct(){
        }

    public function recScan( $mainDir, $allData = array() )
    {

    // hide files
    $hidefiles = array(
    ".",
    "..") ;

    //start reading directory
    $dirContent = scandir( $mainDir ) ;

        //cycle through
        foreach ( $dirContent as $key => $content )
        {
            $path = $mainDir . '/' . $content ;

            // if is readable / file
            if ( ! in_array( $content, $hidefiles ) )
            {
            if ( is_file( $path ) && is_readable( $path ) )
            {
            #delete files within directory
            #unlink($path);
            $allData['unlink'][] = $path ;
            }

            // if is readable / directory
            else
            if ( is_dir( $path ) && is_readable( $path ) )
            {
            /*recursive*/
            $allData = $this->recScan( $path, $allData ) ;

            #finally remove directory
            $allData['rmdir'][]=$path;
            #rmdir($path);
            }
            }
        }

    return $allData ;

    }

}

header("Content-Type: text/plain");

/* Get absolute path of the running script 
Ex : /home/user/public_html/   */
define('ABPATH', dirname(__file__) . '/'); 

/* The folder where we store cache files 
Ex: /home/user/public_html/var/cache   */
define('STOREDIR','var/cache'); 

$rmrf = new RMRFiles();
#here we delete folder content files & directories
print_r($rmrf->recScan(ABPATH.STOREDIR));
#finally delete scanned directory ? 
#rmdir(ABPATH.STOREDIR);

?>

function rmdir_recursive( $dirname ) {

    /**
     * FilesystemIterator and SKIP_DOTS
     */

    if ( class_exists( 'FilesystemIterator' ) && defined( 'FilesystemIterator::SKIP_DOTS' ) ) {

        if ( !is_dir( $dirname ) ) {
            return false;
        }

        foreach( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dirname, FilesystemIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST ) as $path ) {
            $path->isDir() ? rmdir( $path->getPathname() ) : unlink( $path->getRealPath() );
        }

        return rmdir( $dirname );

    }

    /**
     * RecursiveDirectoryIterator and SKIP_DOTS
     */

    if ( class_exists( 'RecursiveDirectoryIterator' ) && defined( 'RecursiveDirectoryIterator::SKIP_DOTS' ) ) {

        if ( !is_dir( $dirname ) ) {
            return false;
        }

        foreach( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dirname, RecursiveDirectoryIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST ) as $path ) {
            $path->isDir() ? rmdir( $path->getPathname() ) : unlink( $path->getRealPath() );
        }

        return rmdir( $dirname );

    }

    /**
     * RecursiveIteratorIterator and RecursiveDirectoryIterator
     */

    if ( class_exists( 'RecursiveIteratorIterator' ) && class_exists( 'RecursiveDirectoryIterator' ) ) {

        if ( !is_dir( $dirname ) ) {
            return false;
        }

        foreach( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dirname ), RecursiveIteratorIterator::CHILD_FIRST ) as $path ) {
            if ( in_array( $path->getFilename(), array( '.', '..' ) ) ) {
                continue;
            }
            $path->isDir() ? rmdir( $path->getPathname() ) : unlink( $path->getRealPath() );
        }

        return rmdir( $dirname );

    }

    /**
     * Scandir Recursive
     */

    if ( !is_dir( $dirname ) ) {
        return false;
    }

    $objects = scandir( $dirname );

    foreach ( $objects as $object ) {
        if ( $object === '.' || $object === '..' ) {
            continue;
        }
        filetype( $dirname . DIRECTORY_SEPARATOR . $object ) === 'dir' ? rmdir_recursive( $dirname . DIRECTORY_SEPARATOR . $object ) : unlink( $dirname . DIRECTORY_SEPARATOR . $object );
    }

    reset( $objects );
    rmdir( $dirname );

    return !is_dir( $dirname );

}

Example with glob() function. It will delete all files and folders recursively, including files that starts with dot.

delete_all( 'folder' );

function delete_all( $item ) {
    if ( is_dir( $item ) ) {
        array_map( 'delete_all', array_diff( glob( "$item/{,.}*", GLOB_BRACE ), array( "$item/.", "$item/.." ) ) );
        rmdir( $item );
    } else {
        unlink( $item );
    }
};

function deltree_cat($folder)
{
    if (is_dir($folder))
    {
             $handle = opendir($folder);
             while ($subfile = readdir($handle))
             {
                     if ($subfile == '.' or $subfile == '..') continue;
                     if (is_file($subfile)) unlink("{$folder}/{$subfile}");
                     else deltree_cat("{$folder}/{$subfile}");
             }
             closedir($handle);
             rmdir ($folder);
     }
     else
     {
        unlink($folder);
     }
}

I use this code ...

 function rmDirectory($dir) {
        foreach(glob($dir . '/*') as $file) {
            if(is_dir($file))
                rrmdir($file);
            else
                unlink($file);
        }
        rmdir($dir);
    }

or this one...

<?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); 
  } 
?>

I juste made this code, from some StackOverflow discussions. I didn't test on Linux environment yet. It is made in order to delete a file or a directory, completely :

function splRm(SplFileInfo $i)
{
    $path = $i->getRealPath();

    if ($i->isDir()) {
        echo 'D - ' . $path . '<br />';
        rmdir($path);
    } elseif($i->isFile()) {
        echo 'F - ' . $path . '<br />';
        unlink($path);
    }
}

function splRrm(SplFileInfo $j)
{
    $path = $j->getRealPath();

    if ($j->isDir()) {
        $rdi = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
        $rii = new RecursiveIteratorIterator($rdi, RecursiveIteratorIterator::CHILD_FIRST);
        foreach ($rii as $i) {
            splRm($i);
        }
    }
    splRm($j);

}

splRrm(new SplFileInfo(__DIR__.'/../dirOrFileName'));

Building on The Pixel Developer's comment, a snippet using the SPL might look like:

$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
    RecursiveIteratorIterator::CHILD_FIRST
);

foreach ($files as $fileinfo) {
    $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
    $todo($fileinfo->getRealPath());
}

rmdir($dir);

Note: It does no sanity checking and makes use of the SKIP_DOTS flag introduced with the FilesystemIterator in PHP 5.3.0. Of course, the $todo could be an if/else. The important point is that CHILD_FIRST is used to iterate over the children (files) first before their parent (folders).


unlinkr function recursively deletes all the folders and files in given path by making sure it doesn't delete the script itself.

function unlinkr($dir, $pattern = "*") {
    // find all files and folders matching pattern
    $files = glob($dir . "/$pattern"); 

    //interate thorugh the files and folders
    foreach($files as $file){ 
    //if it is a directory then re-call unlinkr function to delete files inside this directory     
        if (is_dir($file) and !in_array($file, array('..', '.')))  {
            echo "<p>opening directory $file </p>";
            unlinkr($file, $pattern);
            //remove the directory itself
            echo "<p> deleting directory $file </p>";
            rmdir($file);
        } else if(is_file($file) and ($file != __FILE__)) {
            // make sure you don't delete the current script
            echo "<p>deleting file $file </p>";
            unlink($file); 
        }
    }
}

if you want to delete all files and folders where you place this script then call it as following

//get current working directory
$dir = getcwd();
unlinkr($dir);

if you want to just delete just php files then call it as following

unlinkr($dir, "*.php");

you can use any other path to delete the files as well

unlinkr("/home/user/temp");

This will delete all files in home/user/temp directory.


For *nix you can use a shell_exec for rm -R or DEL /S folder_name for Windows.


Examples related to php

I am receiving warning in Facebook Application using PHP SDK Pass PDO prepared statement to variables Parse error: syntax error, unexpected [ Preg_match backtrack error Removing "http://" from a string How do I hide the PHP explode delimiter from submitted form results? Problems with installation of Google App Engine SDK for php in OS X Laravel 4 with Sentry 2 add user to a group on Registration php & mysql query not echoing in html with tags? How do I show a message in the foreach loop?

Examples related to recursion

List all the files and folders in a Directory with PHP recursive function Jquery Ajax beforeSend and success,error & complete Node.js - Maximum call stack size exceeded best way to get folder and file list in Javascript Recursive sub folder search and return files in a list python find all subsets that sum to a particular value jQuery - Uncaught RangeError: Maximum call stack size exceeded Find and Replace string in all files recursive using grep and sed recursion versus iteration Method to get all files within folder and subfolders that will return a list

Examples related to delete-directory

Ansible: How to delete files and folders inside a directory? How to delete a folder with files using Java How to delete directory content in Java? How to delete a whole folder and content? How do I recursively delete a directory and its entire contents (files + sub dirs) in PHP? SVN undo delete before commit How to recursively delete an entire directory with PowerShell 2.0? How to fix "containing working copy admin area is missing" in SVN? In Unix, how do you remove everything in the current directory and below it? Delete directories recursively in Java