Reputation: 44293
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
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
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
Reputation: 8520
There are at least two options available nowadays.
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);
}
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
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
Reputation: 157828
what's the easiest way to delete a directory with all its files in it?
system("rm -rf ".escapeshellarg($dir));
Upvotes: 111
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
Reputation: 242
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
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
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
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
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
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
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
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
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
Reputation: 2088
Example for the Linux server: exec('rm -f -r ' . $cache_folder . '/*');
Upvotes: 5
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
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
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
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
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
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
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
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
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
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
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
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
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
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