Page 1 of 1

Recursive Unlinking: Understanding

Posted: Mon Jul 27, 2009 12:00 am
by captcadaver
Hi, I've constructed a recursive unlinking function from various sources. I'm trying to comment it for understanding.

Do you see anything in my comments that I could improve on? Hopefully I built it and understood it currently...

I'm also a bit new to the opendir(), readdir(), closedir() functions. I'm guessing I want to use opendir() on the top level directory that I want to use before I call this function? Thanks!

Code: Select all

 
<?php
 
// inspired by:
// http://us2.php.net/manual/en/function.unlink.php#87045
// viewtopic.php?f=1&t=25543&hilit=recursive+unlink
// delete all files, directories within given directory.
// even deletes given top-level directory ($dir).
function recursive_unlink($dir)
    {
    // base case: if the given directory isn't the top-level directory, do nothing
    if(!$dir_handle = opendir($dir))
        {
            return;
        }
    // otherwise, go through contents of top-level directory
    while(($file = readdir($dir_handle)) !== false)
        {
        // skip the folder if it's empty
        if($file == '.' || $file == '..')
            {
                continue;
            }
        // if there's anything in the folder, kill it
        if (!unlink($dir.'/'.$file))
            {
                recursive_unlink($dir.'/'.$file);
            }
        }
    closedir($dir_handle);  // close the top-level directory
    rmdir($dir); // remove the top-level directory
    return;
    }
 
?>
 

Re: Recursive Unlinking: Understanding

Posted: Mon Jul 27, 2009 12:16 am
by requinix
A couple issues with the comments.

Code: Select all

// base case: if the given directory isn't the top-level directory, do nothing
if(!$dir_handle = opendir($dir))
For one, $dir is not necessarily the "top-level" directory. It is simply a directory somewhere. All you know is that you are supposed to delete everything inside.
But the main issue with this one is that if the opendir() call fails then it only means the directory could not be opened for reading. Nothing more: no "isn't the top-level" or anything.

Code: Select all

// skip the folder if it's empty
if($file == '.' || $file == '..')
. and .. show up in every single directory. On Windows, Linux, Unix, and Mac. . is a reference to this current directory so you want to skip it (otherwise you try to delete this directory over and over again). .. is a reference to the parent: you don't want to delete that because (a) this is the top-most directory and you don't want to delete the parent, or (b) another call to recursive_unlink is already processing it.

Then I have a complaint about this code:

Code: Select all

// if there's anything in the folder, kill it
if (!unlink($dir.'/'.$file))
    {
        recursive_unlink($dir.'/'.$file);
    }
If $dir/$file is a file that just can't be deleted it'll try to recursive_unlink it. Which won't work.

Don't rely on a failure to delete as the indication that something is a directory.

Code: Select all

// if there's anything in the folder, kill it
if (is_file($dir.'/'.$file))
    {
        unlink($dir.'/'.$file);
    }
else if (is_dir($dir.'/'.$file))
    {
        recursive_unlink($dir.'/'.$file);
    }

Re: Recursive Unlinking: Understanding

Posted: Mon Jul 27, 2009 10:55 am
by pickle
I would make sure only some directories can be deleted. For example, you wouldn't want to accidentally pass "/" to this function.

Re: Recursive Unlinking: Understanding

Posted: Mon Jul 27, 2009 11:10 am
by jackpf
I think as long as you have open basdir restriction in effect you'd be pretty safe?