Share via:

Recursively Delete Directories

In this tutorial I show how to create a simple_delete() function in PHP to automatically delete whatever you ask it, and also handle errors.

294 views
d

By. Jacob

Edited: 2018-03-06 23:46

wow PHP, server-sided scripting language.

The rmdir function of PHP is a bit unintuitive, since it does not work the way most users expect. Deleting directories is unnecessarily complicated. Personally, I would prefer a single function to delete both files and directories, as well as non-empty directories. Deleting a directory with content should be handled automatically. Currently, it is not. So, we have to come up with our own complex solution.

In Linux, you can at least use the rm -rf [some_directory] to forcefully remove a directory that is not empty, but in PHP there is no equivalent and it also will not work in Windows. So, we have to code our own function.

Luckily, such tasks are not impossibly hard, and they serve as nice learning exercises. Before you just copy and paste the solution in this article, you may want to try and come up with your own :-)

The solution is to create a looping mechanism, which will recursively delete any files and subdirectories within the main directory. Since it is possible for a function to call itself, someone suggested to do something similar to the below, and I simply tried to improve it by handling errors:

function simple_delete($file_or_dir) {
  if (is_writable($file_or_dir)) { // Check for write permissions
    if (is_dir($file_or_dir)) { // Do this if we are dealing with a directory
      $objects = scandir($file_or_dir); // Handle subdirectories (if any)
      foreach ($objects as $object) {
        if(($object !== '.') && ($object !== '..')) {
          if (is_dir($file_or_dir.'/'.$object)) {
            simple_delete($file_or_dir.'/'.$object); // If dealing with a subdirectory, perform another simple_delete()
          } else {
            if (is_writable($file_or_dir.'/'.$object)) { // Check for write permissions
              unlink($file_or_dir.'/'.$object); // Delete file
            } else {return false;}
          }
        }
      }
      rmdir($file_or_dir); // Delete directory
      return true; // Return true on success
    } else {
      unlink($file_or_dir); // simple_delete() also works on single files
    }
  } else {return false;} 
}

To call the function, and handle errors in a general manner, simply perform a if check, like this:

define('BASE_PATH', rtrim(realpath(dirname(__FILE__)), "/") . '/');

$dir = BASE_PATH . 'test/';

header('Content-type: text/txt');

if(simple_delete($dir)) {
  echo 'Deleted - Ok!';
} else {
  echo 'Error: unable to perform delete. This may be a problem with permissions.';
}

rmdir and Directory not empty

Typically using rmdir on a non-empty directory will not work as we intuitively expect, and instead it will result in an error like the below:

Warning: rmdir(dirname): Directory not empty in /var/www/mysite/some_file.php on line 12

The problem likely is that some functions in PHP is derived from the C programming language, which is very old. Maybe people back then simply did not think about making a universal delete function to save time. Who knows? In any case, I think the fine control that unlink and rmdir provides still have its place in some cases. However, most the time, I just want to delete whatever I want to delete and move on.

This is why the function in this article is called simple_delete(). I wanted a function that would delete whatever I was feeding it, regardless of whether it is a directory, file, or a directory with content in it.

Error handling

I have made error handling an important part of my coding. Not because there is anything wrong with the build in errors shown by PHP, but because I wanted to create my own custom errors, and sometimes you might not want to have errors turned on, or you want to show more descriptive errors, and have the ability to also translate error messages.

So, I quickly made this other delete function, which you may use for inspiration. However, for my own projects, I would still go with simple_delete() from earlier, since this one will not handle directories with content or subdirectories.

function just_delete_it($file_or_dir) {
  if (is_writable($file_or_dir)) {
    if (is_dir($file_or_dir)) {
      rmdir($file_or_dir);
      return true;
    } else {
      unlink($file_or_dir); // Delete file
      return true;
    }
  } else {return false;}
}

Comments