matt
matt

Reputation: 44293

Delete directory with files in it?

I wonder, what's the easiest way to delete a directory with all its files in it?

I'm using rmdir(PATH . '/' . $value); to delete a folder, however, if there are files inside of it, I simply can't delete it.

Upvotes: 323

Views: 485843

Answers (30)

Praise Dare
Praise Dare

Reputation: 530

If you happen to be using laravel, then you can simply use the File facade:

use Illuminate\Support\Facades\File;

File::deleteDirectory($pathToDirectory);

Upvotes: 0

David Clews
David Clews

Reputation: 906

A nicely formatted helper function that can be used with a framework like Laravel

if(!function_exists("remove_directory")){
    
   /**
    * remove_directory
    * 
    * Removes all contained files and folders in the directory, then removes
    * itself
    * 
    * 
    * @param {string} $directory
    * 
    */
    function remove_directory(string $directory){

    

        if (!is_dir($directory)) {

            throw new InvalidArgumentException("{$directory} must be a directory");

        }

        if (substr($directory, strlen($directory) - 1, 1) != '/') {

            $directory .= '/';

        }


        $files = glob($directory . '*', GLOB_MARK);


        foreach ($files as $file) {

            if (is_dir($file)) {

                remove_directory($file);

            } else {

                unlink($file);

            }

        }


        rmdir($directory);


    }

}

Upvotes: 0

alcuadrado
alcuadrado

Reputation: 8520

There are at least two options available nowadays.

  1. Before deleting the folder, delete all its files and folders (and this means recursion!). Here is an example:

    function deleteDir(string $dirPath): void {
        if (! is_dir($dirPath)) {
            throw new InvalidArgumentException("$dirPath must be a directory");
        }
        if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
            $dirPath .= '/';
        }
        $files = glob($dirPath . '*', GLOB_MARK);
        foreach ($files as $file) {
            if (is_dir($file)) {
                deleteDir($file);
            } else {
                unlink($file);
            }
        }
        rmdir($dirPath);
    }
    
  2. And if you are using 5.2+ you can use a RecursiveIterator to do it without implementing the recursion yourself:

    function removeDir(string $dir): void {
        $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
        $files = new RecursiveIteratorIterator($it,
                     RecursiveIteratorIterator::CHILD_FIRST);
        foreach($files as $file) {
            if ($file->isDir()){
                rmdir($file->getPathname());
            } else {
                unlink($file->getPathname());
            }
        }
        rmdir($dir);
    }
    

Upvotes: 454

T.Todua
T.Todua

Reputation: 56341

The Best Solution for me

my_folder_delete("../path/folder");

code:

function my_folder_delete($path) {
    if (in_array($path, ['.', '/'])) return; // ensure to avoid accidents
    if(!empty($path) && is_dir($path) ){
        $dir  = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS); //upper dirs are not included,otherwise DISASTER HAPPENS :)
        $files = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST);
        foreach ($files as $f) {if (is_file($f)) {unlink($f);} else {$empty_dirs[] = $f;} } if (!empty($empty_dirs)) {foreach ($empty_dirs as $eachDir) {rmdir($eachDir);}} rmdir($path);
    }
}

p.s. REMEMBER!
dont pass EMPTY VALUES to any Directory deleting functions!!! (backup them always, otherwise one day you might get DISASTER!!)

Upvotes: 8

Your Common Sense
Your Common Sense

Reputation: 157828

what's the easiest way to delete a directory with all its files in it?

system("rm -rf ".escapeshellarg($dir));

Upvotes: 111

WebTigers
WebTigers

Reputation: 311

I can't believe there are 30+ answers for this. Recursively deleting a folder in PHP could take minutes depending on the depth of the directory and the number of files in it! You can do this with one line of code ...

shell_exec("rm -rf " . $dir);

If you're concerned with deleting the entire filesystem, make sure your $dir path is exactly what you want first. NEVER allow a user to input something that can directly delete files without first heavily validating the input. That's essential coding practice.

Upvotes: 14

You could copy the YII helpers

$directory (string) - to be deleted recursively.

$options (array) - for the directory removal. Valid options are: traverseSymlinks: boolean, whether symlinks to the directories should be traversed too. Defaults to false, meaning that the content of the symlinked directory would not be deleted. Only symlink would be removed in that default case.

public static function removeDirectory($directory,$options=array())
{
    if(!isset($options['traverseSymlinks']))
        $options['traverseSymlinks']=false;
    $items=glob($directory.DIRECTORY_SEPARATOR.'{,.}*',GLOB_MARK | GLOB_BRACE);
    foreach($items as $item)
    {
        if(basename($item)=='.' || basename($item)=='..')
            continue;
        if(substr($item,-1)==DIRECTORY_SEPARATOR)
        {
            if(!$options['traverseSymlinks'] && is_link(rtrim($item,DIRECTORY_SEPARATOR)))
                unlink(rtrim($item,DIRECTORY_SEPARATOR));
            else
                self::removeDirectory($item,$options);
        }
        else
            unlink($item);
    }
    if(is_dir($directory=rtrim($directory,'\\/')))
    {
        if(is_link($directory))
            unlink($directory);
        else
            rmdir($directory);
    }
}

Upvotes: 1

Adeel Ahmed Baloch
Adeel Ahmed Baloch

Reputation: 800

you can try this simple 12 line of code for delete folder or folder files... happy coding... ;) :)

function deleteAll($str) {
    if (is_file($str)) {
        return unlink($str);
    }
    elseif (is_dir($str)) {
        $scan = glob(rtrim($str,'/').'/*');
        foreach($scan as $index=>$path) {
            $this->deleteAll($path);
        }            
        return @rmdir($str);
    }
}

Upvotes: 3

Bablu Ahmed
Bablu Ahmed

Reputation: 5010

You can try as follows:

/*
 * Remove the directory and its content (all files and subdirectories).
 * @param string $dir the directory name
 */
function rmrf($dir) {
    foreach (glob($dir) as $file) {
        if (is_dir($file)) { 
            rmrf("$file/*");
            rmdir($file);
        } else {
            unlink($file);
        }
    }
}

Upvotes: 15

jay padaliya
jay padaliya

Reputation: 704

If you are not sure, Given path is directory or file then you can use this function to delete path

function deletePath($path) {
        if(is_file($path)){
            unlink($path);
        } elseif(is_dir($path)){
            $path = (substr($path, -1) !== DIRECTORY_SEPARATOR) ? $path . DIRECTORY_SEPARATOR : $path;
            $files = glob($path . '*');
            foreach ($files as $file) {
                deleteDirPath($file);
            }
            rmdir($path);
        } else {
            return false;
        }
}

Upvotes: 0

Christopher Smit
Christopher Smit

Reputation: 959

This one works for me:

function removeDirectory($path) {
    $files = glob($path . '/*');
    foreach ($files as $file) {
        is_dir($file) ? removeDirectory($file) : unlink($file);
    }
    rmdir($path);
    return;
}

Upvotes: 12

Alan Trewartha
Alan Trewartha

Reputation: 160

Using DirectoryIterator an equivalent of a previous answer…

function deleteFolder($rootPath)
{   
    foreach(new DirectoryIterator($rootPath) as $fileToDelete)
    {
        if($fileToDelete->isDot()) continue;
        if ($fileToDelete->isFile())
            unlink($fileToDelete->getPathName());
        if ($fileToDelete->isDir())
            deleteFolder($fileToDelete->getPathName());
    }

    rmdir($rootPath);
}

Upvotes: 3

Mohamad Hamouday
Mohamad Hamouday

Reputation: 2743

What about this?

function Delete_Directory($Dir) 
{
  if(is_dir($Dir))
  {
      $files = glob( $Dir . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned

      foreach( $files as $file )
      {
          Delete_Directory( $file );      
      }
      if(file_exists($Dir))
      {
          rmdir($Dir);
      }
  } 
  elseif(is_file($Dir)) 
  {
     unlink( $Dir );  
  }
}

Refrence: https://paulund.co.uk/php-delete-directory-and-files-in-directory

Upvotes: 1

Tarik
Tarik

Reputation: 4536

Here is the solution that works perfect:

function unlink_r($from) {
    if (!file_exists($from)) {return false;}
    $dir = opendir($from);
    while (false !== ($file = readdir($dir))) {
        if ($file == '.' OR $file == '..') {continue;}

        if (is_dir($from . DIRECTORY_SEPARATOR . $file)) {
            unlink_r($from . DIRECTORY_SEPARATOR . $file);
        }
        else {
            unlink($from . DIRECTORY_SEPARATOR . $file);
        }
    }
    rmdir($from);
    closedir($dir);
    return true;
}

Upvotes: 1

Gras Double
Gras Double

Reputation: 16373

You may use Symfony's Filesystem (code):

// composer require symfony/filesystem

use Symfony\Component\Filesystem\Filesystem;

(new Filesystem)->remove($dir);

However I couldn't delete some complex directory structures with this method, so first you should try it to ensure it's working properly.


I could delete the said directory structure using a Windows specific implementation:

$dir = strtr($dir, '/', '\\');
// quotes are important, otherwise one could
// delete "foo" instead of "foo bar"
system('RMDIR /S /Q "'.$dir.'"');


And just for the sake of completeness, here is an old code of mine:

function xrmdir($dir) {
    $items = scandir($dir);
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }
        $path = $dir.'/'.$item;
        if (is_dir($path)) {
            xrmdir($path);
        } else {
            unlink($path);
        }
    }
    rmdir($dir);
}

Upvotes: 25

realmag777
realmag777

Reputation: 2088

Example for the Linux server: exec('rm -f -r ' . $cache_folder . '/*');

Upvotes: 5

user701152
user701152

Reputation: 51

I want to expand on the answer by @alcuadrado with the comment by @Vijit for handling symlinks. Firstly, use getRealPath(). But then, if you have any symlinks that are folders it will fail as it will try and call rmdir on a link - so you need an extra check.

$it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
foreach($files as $file) {
    if ($file->isLink()) {
        unlink($file->getPathname());
    } else if ($file->isDir()){
        rmdir($file->getPathname());
    } else {
        unlink($file->getPathname());
    }
}
rmdir($dir);

Upvotes: 4

candlejack
candlejack

Reputation: 1209

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

Upvotes: 5

Phil Meadows
Phil Meadows

Reputation: 23

2 cents to add to THIS answer above, which is great BTW

After your glob (or similar) function has scanned/read the directory, add a conditional to check the response is not empty, or an invalid argument supplied for foreach() warning will be thrown. So...

if( ! empty( $files ) )
{
    foreach( $files as $file )
    {
        // do your stuff here...
    }
}

My full function (as an object method):

    private function recursiveRemoveDirectory( $directory )
    {
        if( ! is_dir( $directory ) )
        {
            throw new InvalidArgumentException( "$directory must be a directory" );
        }

        if( substr( $directory, strlen( $directory ) - 1, 1 ) != '/' )
        {
            $directory .= '/';
        }

        $files = glob( $directory . "*" );

        if( ! empty( $files ) )
        {
            foreach( $files as $file )
            {
                if( is_dir( $file ) )
                {
                    $this->recursiveRemoveDirectory( $file );
                }
                else
                {
                    unlink( $file );
                }
            }               
        }
        rmdir( $directory );

    } // END recursiveRemoveDirectory()

Upvotes: 1

Newtron
Newtron

Reputation: 170

Simple and Easy...

$dir ='pathtodir';
if (is_dir($dir)) {
  foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) {
    if ($filename->isDir()) continue;
    unlink($filename);
  }
  rmdir($dir);
}

Upvotes: 1

mysticmo
mysticmo

Reputation: 87

Platform independent code.

Took the answer from PHP.net

if(PHP_OS === 'Windows')
{
 exec("rd /s /q {$path}");
}
else
{
 exec("rm -rf {$path}");
}

Upvotes: -4

adrian
adrian

Reputation: 121

What about this:

function recursiveDelete($dirPath, $deleteParent = true){
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirPath, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) {
        $path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname());
    }
    if($deleteParent) rmdir($dirPath);
}

Upvotes: 4

dav
dav

Reputation: 9267

I do not remember from where I copied this function, but it looks like it is not listed and it is working for me

function rm_rf($path) {
    if (@is_dir($path) && is_writable($path)) {
        $dp = opendir($path);
        while ($ent = readdir($dp)) {
            if ($ent == '.' || $ent == '..') {
                continue;
            }
            $file = $path . DIRECTORY_SEPARATOR . $ent;
            if (@is_dir($file)) {
                rm_rf($file);
            } elseif (is_writable($file)) {
                unlink($file);
            } else {
                echo $file . "is not writable and cannot be removed. Please fix the permission or select a new path.\n";
            }
        }
        closedir($dp);
        return rmdir($path);
    } else {
        return @unlink($path);
    }
}

Upvotes: 0

PP2000
PP2000

Reputation: 11

Delete all files in Folder
array_map('unlink', glob("$directory/*.*"));
Delete all .*-Files in Folder (without: "." and "..")
array_map('unlink', array_diff(glob("$directory/.*),array("$directory/.","$directory/..")))
Now delete the Folder itself
rmdir($directory)

Upvotes: 1

Tommz
Tommz

Reputation: 3453

Here you have one nice and simple recursion for deleting all files in source directory including that directory:

function delete_dir($src) { 
    $dir = opendir($src);
    while(false !== ( $file = readdir($dir)) ) { 
        if (( $file != '.' ) && ( $file != '..' )) { 
            if ( is_dir($src . '/' . $file) ) { 
                delete_dir($src . '/' . $file); 
            } 
            else { 
                unlink($src . '/' . $file); 
            } 
        } 
    } 
    closedir($dir); 
    rmdir($src);

}

Function is based on recursion made for copying directory. You can find that function here: Copy entire contents of a directory to another using php

Upvotes: 10

German Latorre
German Latorre

Reputation: 11128

As seen in most voted comment on PHP manual page about rmdir() (see http://php.net/manual/es/function.rmdir.php), glob() function does not return hidden files. scandir() is provided as an alternative that solves that issue.

Algorithm described there (which worked like a charm in my case) is:

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

Upvotes: 41

Matthew Slyman
Matthew Slyman

Reputation: 356

Like Playnox's solution, but with the elegant built-in DirectoryIterator:

function delete_directory($dirPath){
 if(is_dir($dirPath)){
  $objects=new DirectoryIterator($dirPath);
   foreach ($objects as $object){
    if(!$object->isDot()){
     if($object->isDir()){
      delete_directory($object->getPathname());
     }else{
      unlink($object->getPathname());
     }
    }
   }
   rmdir($dirPath);
  }else{
   throw new Exception(__FUNCTION__.'(dirPath): dirPath is not a directory!');
  }
 }

Upvotes: 0

Blaise
Blaise

Reputation: 13479

Short function that does the job:

function deleteDir($path) {
    return is_file($path) ?
            @unlink($path) :
            array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
}

I use it in a Utils class like this:

class Utils {
    public static function deleteDir($path) {
        $class_func = array(__CLASS__, __FUNCTION__);
        return is_file($path) ?
                @unlink($path) :
                array_map($class_func, glob($path.'/*')) == @rmdir($path);
    }
}

With great power comes great responsibility: When you call this function with an empty value, it will delete files starting in root (/). As a safeguard you can check if path is empty:

function deleteDir($path) {
    if (empty($path)) { 
        return false;
    }
    return is_file($path) ?
            @unlink($path) :
            array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
}

Upvotes: 56

user3033886
user3033886

Reputation: 2883

I generally use this to delete all files in a folder:

array_map('unlink', glob("$dirname/*.*"));

And then you can do

rmdir($dirname);

Upvotes: 270

karma_police
karma_police

Reputation: 352

Litle bit modify of alcuadrado's code - glob don't see files with name from points like .htaccess so I use scandir and script deletes itself - check __FILE__.

function deleteDir($dirPath) {
    if (!is_dir($dirPath)) {
        throw new InvalidArgumentException("$dirPath must be a directory");
    }
    if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
        $dirPath .= '/';
    }
    $files = scandir($dirPath); 
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        if (is_dir($dirPath.$file)) {
            deleteDir($dirPath.$file);
        } else {
            if ($dirPath.$file !== __FILE__) {
                unlink($dirPath.$file);
            }
        }
    }
    rmdir($dirPath);
}

Upvotes: 5

Related Questions