How do I remove a directory that is not empty? - php

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?

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
}

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

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.

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');

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

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

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

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

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

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

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

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

Related

I want to delete files from multiple directories expect an image

I want to delete files from multiple direcories in PHP. The problem is when the code is run it deletes everything. I have a main folder which has a lots of folders in it. Those folders have files that i want to delete except that file in $filesToKeep variable. I'm a beginner PHP developer, and i really don't know how could i find the problame. If there is an another easier way to delete those files could be helpful too.
Here is my code:
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);
}
}
$filesToKeep = array(
'partner-profil-480.jpg'
);
$dirList = glob('*');
foreach ($dirList as $file) {
if (!in_array($file, $filesToKeep)) {
if (is_dir($file)) {
rrmdir($file);
} else {
unlink($file);
}//END IF
}//END IF
}//END FOREACH LOOP
?>
I found the solution a while ago just i forgot to post it.
Here it is:
$path = "yourpath";
function dirToArray($dir) {
$filesToKeep = array(
'your-file-to-keep'
);
$contents = array();
foreach (scandir($dir) as $node) {
if ($node == '.' || $node == '..') continue;
if (is_dir($dir . '/' . $node)) {
$contents[$node] = dirToArray($dir . '/' . $node);
} else {
$contents[] = $node;
print_r(json_encode($node, JSON_PRETTY_PRINT));
if(!in_array($node, $filesToKeep)){
unlink($dir . '/' . $node);
}
}
rmdir($dir . '/' . $node);
}
}
$r = dirToArray($path);
print_r($r);

Include file PDF in folders with accents in PHP

I've tried several ways to include a PDF file using PHP on Linux, it works normally on Windows, but not on Linux.
I have several directories with accents and I need to include PDF files that are inside the directories.
I pass the name of the PDF files and include the PDF.
My problem is with the encoding and accentuation of the folders. The files doesn't have accents, only the folders.
Examples of folders / files:
files/ño/hash1.pdf
files/nó/hash2.pdf
files/ção/hash.pdf
function getFileInContents($dir, $filename)
{
$files = scandir($dir);
foreach ($files as $key => $value) {
$path = realpath($dir . '/' . $value);
if (!is_dir($path)) {
if ($filename == $value) {
return $path;
}
} elseif ($value != "." && $value != "..") {
getFileInContents($path, $filename);
}
}
return null;
}
if (!isset($_GET['f'])) {
echo 'File not found';
exit;
}
$local = 'files/';
$path = getFileInContents($local, $_GET['f']);
if (!$path) {
echo 'File not found';
exit;
}
$mime = mime_content_type($path);
header('Content-Type: ' . $mime);
include_once($path);
My answer adds on and expounds on the one offered up by #James, because you have additional issues:
As pointed out in the comment made by #Olivier, you should be using readfile() instead of include.
You should not include the final '/' in your declaration of $local since you will be concatenating a '/' to the passed $dir argument in function getFileInContents.
Presumably function getFileInContents is intended to recursively search subdirectories, but it is not doing this correctly; it only is searching the first subdirectory it finds and if the sought file is not present in that subdirectory it returns with a "not found" condition and never searches any other subdirectories that might be present in the directory.
function getFileInContents($dir, $filename)
{
$files = scandir($dir);
foreach ($files as $key => $value) {
$path = realpath($dir . '/' . $value);
if (!is_dir($path)) {
if ($filename == $value) {
return $path;
}
} elseif ($value != "." && $value != "..") {
$new_path = getFileInContents($path, $filename);
if ($new_path) {
return $new_path;
}
}
}
return null;
}
if (!isset($_GET['f'])) {
echo 'File not found';
exit;
}
$local = 'files';
$path = getFileInContents($local, $_GET['f']);
if (!$path) {
echo 'File not found';
exit;
}
$mime = mime_content_type($path);
header('Content-Type: ' . $mime);
readfile($path);
I don't think the problem is anything to do with the folder names. I think the problem is that your recursive function is not actually returning the value when it finds the file.
When you call getFileInContents($path, $filename); you then need to return the value, if it's not null, to break the loop.
function getFileInContents($dir, $filename)
{
$files = scandir($dir);
foreach ($files as $key => $value) {
$path = realpath($dir . '/' . $value);
if (!is_dir($path)) {
if ($filename == $value) {
return $path;
}
} elseif ($value != "." && $value != "..") {
$testValue = getFileInContents($path, $filename);
if ($testValue!=null){
return $testValue;
}
}
}
return null;
}

How to Delete all folder with file in server (cpanel) ? where is my Mistake?

This function execute successfully but it doesn't deleted any folder.
public function ulink(){
$path='/home/doman/public_html/projectname/';
function Delete($path)
{
if (is_dir($path) === true)
{
$files = array_diff(scandir($path), array('.', '..'));
foreach ($files as $file)
{
Delete(realpath($path) . '/' . $file);
}
return rmdir($path);
}
else if (is_file($path) === true)
{
return unlink($path);
}
return false; }
}
Try this code for remove all folder and sub folder also.
function viewDir($path) {
return is_file($path) ?
#unlink($path) :
array_map(__FUNCTION__, glob($path.'/*')) == #rmdir($path);
}
$dir=$_SERVER["DOCUMENT_ROOT"]."/xxxx/xxxx";
echo $dir;
viewDir($dir);
You can used this function and change $dirvalues for your needs.
it working fine for me..
function delfolder($path) {
$files = array_diff(scandir($path), array('.','..'));
foreach ($files as $file) {
(is_dir("$path/$file")) ? delfolder("$path/$file") : unlink("$path/$file");
}
return rmdir($path);
}
Try like this:
<?php
/**
* 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);
}
}
}
?>
for more info: http://in3.php.net/glob

How to flatten folder in php

In my server I have folders and sub-directory
I want to call a flatten methode to a directory to move every files at the same level and remove all empty folders
Here is what i've done so far:
public function flattenDir($dir, $destination=null) {
$files = $this->find($dir . '/*');
foreach ($files as $file) {
if(!$destination){
$destination = $dir . '/' . basename($file);
}
if (!$this->isDirectory($file)) {
$this->move($file, $destination);
}else{
$this->flattenDir($file, $destination);
}
}
foreach ($files as $file) {
$localdir = dirname($file);
if ($this->isDirectory($localdir) && $this->isEmptyDirectory($localdir) && ($localdir != $dir)) {
$this->remove($localdir);
}
}
}
public function find($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
$files = array_merge($files, $this->find($dir . '/' . basename($pattern), $flags));
}
return $files;
}
This code dont show any error on run, but the resukt is not as expected.
For exemple if I have /folder1/folder2/file I want to have /folder2/file as a result but here the folders still like they where ...
I finally make my code works, I post it here in case it help someone
I simplified it to make it more efficient. By the way this function is part of a filemanager classe I made, so I use function of my own class, but you can simply replace $this->move($file, $destination); by move($file, $destination);
public function flattenDir($dir, $destination = null) {
$files = $this->find($dir . '/*');
foreach ($files as $file) {
$localdir = dirname($file);
if (!$this->isDirectory($file)) {
$destination = $dir . '/' . basename($file);
$this->move($file, $destination);
}
if ($this->isDirectory($localdir) && $this->isEmptyDirectory($localdir) && ($localdir != $dir)) {
$this->remove($localdir);
}
}
}

Delete a directory not empty

rmdir("./uploads/temp/".$user."/");
I have many files in a directory I wish to remove in my PHP script, however these is no way for me to unlink() the file first. Is there a way I co do
unlink(* FROM (dir=)) // don't downvote the long shot
// delete all files from the dir first
// then delete that dir
Reference a directory has to be empty in order to delete it, see php.net/manual/en/function.rmdir.php
You can use the DirectoryIterator and unlink together.
use this
function delete_directory($dirname) {
if (is_dir($dirname))
$dir_handle = opendir($dirname);
if (!$dir_handle)
return false;
while($file = readdir($dir_handle)) {
if ($file != "." && $file != "..") {
if (!is_dir($dirname."/".$file))
unlink($dirname."/".$file);
else
delete_directory($dirname.'/'.$file);
}
}
closedir($dir_handle);
rmdir($dirname);
return true;
}
This code can easily be improved upon, as it's a quick hack, but it takes a directory as an argument and then uses functional recursion to delete all files and folders within, and then finally removes the directory. Nice and quick, too.
There is no other way except to delete all files first using one way or another and then remove directory.
public static function deleteDir($dirPath) {
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)) {
self::deleteDir($file);
} else {
unlink($file);
}
}
rmdir($dirPath);
}
Try using glob to loop over the files in the directory to delete
foreach (glob('/path/to/directory/*') as $file){
unlink('/path/to/directory/' . $file);
}
Check this http://lixlpixel.org/recursive_function/php/recursive_directory_delete/
function recursive_remove_directory($directory, $empty=FALSE)
{
if(substr($directory,-1) == '/')
{
$directory = substr($directory,0,-1);
}
if(!file_exists($directory) || !is_dir($directory))
{
return FALSE;
}elseif(is_readable($directory))
{
$handle = opendir($directory);
while (FALSE !== ($item = readdir($handle)))
{
if($item != '.' && $item != '..')
{
$path = $directory.'/'.$item;
if(is_dir($path))
{
recursive_remove_directory($path);
}else{
unlink($path);
}
}
}
closedir($handle);
if($empty == FALSE)
{
if(!rmdir($directory))
{
return FALSE;
}
}
}
return TRUE;
}
You can delete it recursively:
public function delete_folder ($path) {
$handle = opendir($path);
while ($file = readdir($handle)) {
if ($file != '..' && $file != '.') {
if (is_file($path . DS . $file))
unlink($path . DS . $file);
else
delete_folder($path . DS . $file);
}
}
closedir($handle);
rmdir($tmp_path);
}
delete_folder('path/to/folder');

Categories