Wednesday, 13 Feb 2008 7:02PM EST

PHP Recursive Directory Traversal

A recursive function, simply put, is a function that calls itself. Certain functional languages, such as LISP and Scheme, are designed with recursion in mind; and recursive functions are often required to complete a program. PHP, on the other hand, focuses on iteration. Recursion is often very costly in PHP and not usually your best option. In the case of traversing a file system, though, recursion is the best and most efficient option.

The basic idea behind this code is that you have a single function which scans a given directory and stores the name of each file in an array. The function will call itself each time a sub directory is found, passing the name of that sub directory to the function. This will put the first function call on hold while the second function call is evaluated. The second function call will scan the sub directory, putting each filename into a sub array. The function will call itself again if a third level directory is found, and so on. This will continue on until all directories have been scanned. Assuming the following directory structure:
root/html
root/html/index.php
root/html/about.php
root/html/archives.php
root/html/images/logo.png
root/html/images/photo.png
root/html/images/icons/arrow.png
root/html/images/icons/pencil.png
root/html/images/icons/paper.png
root/html/style/style.css
Then calling scanFilesystem() as follows:
$dir = "root/html";
$dirStructure = scanFilesystem($dir);
print_r($dirStructure);
Will give this output:
Array
(
    [0] => about.php
    [1] => archives.php
    [2] => index.php
    [images] => Array
        (
            [0] => logo.png
            [1] => photo.png
            [icons] => Array
                (
                    [0] => arrow.png
                    [1] => pencil.png
                    [2] => paper.png
                )

        )

    [style] => Array
        (
            [0] => style.css
        )

)
We can accomplish this by creating a scanFilesystem function, which takes a single parameter; $dir. The directory, $dir, is scanned using scandir() and the result is stored in itemArray[]. Item array only contains the names of files and folders in the specified directory; scandir() does not scan sub directories. We then iterate through the array with a for loop (here I initiate $i to 2 because the first two items in each directory of my filesystem are evaluated as "." and "..". You should test this value on your server before implementing). We then check each item in the array with is_dir() to see if it is a directory. If not, we add the filename to $tempArray[]. If it is a directory, then let the recursion begin.

We call scanFilesystem() again, from within the function itself, passing it the path of the sub directory that we've found and storing the result in $tempArray[$item]; where $item is the name of the sub directory. This process will continue until a directory with no sub directories is reached. In that case, the function goes back to the next higher directory and continues that scan, and so on until every directory has been scanned. After each directory scan has finished, we sort the files and sub directories in the resulting array with asort(). Each function call returns $tempArray[], which is now a sorted array of all files and directories (including those contained in sub directories) within a particular directory.
function scanFilesystem($dir) {
  $itemArray = scandir($dir);

  for($i=2; $i<count($itemArray); $i++) {
    $item = $itemArray[$i];
    $newDir = $dir . "/" . $item;

    if(is_dir($newDir)) {
      $tempArray[$item] = scanFilesystem($newDir);
      asort($tempArray);
    }
    else {
      $tempArray[] = $item;
    }

  }

  return $tempArray;
}

Still not quite getting the concept of recursion? Don't worry, we've all been there. Check out Wikipedia for a much better explanation of the concept.

As always, if you have a technique that you think is better or a tweak that improves on this code, please share it in the comments. If you have a tip, trick or an idea for my next post, please don't hesitate to contact me.
Bookmark and Share

1 Comments So Far

Priya
Friday, 05 September 2008 7:43
Your code is good but i have saved this code in test.php and there is an error like:Notice: Undefined variable: tempArray in .../test.php on line 26 can u solve this

Post a comment


If you are seeing this message, you are either using a screen reader or you have disabled CSS. Please do not fill in the following form field, titled "lastname", or your comment will not be saved. This field is only used to help prevent spam comments.


Welcome

JustinSpegele.com is where I share projects that I'm working on, php tutorials, web development tips and tricks, and random thoughts.

#MLS has a very odd notion of an all-star game. MLS all-stars vs. an EPL team? Still, should be very fun to watch. MLS 3 - Man United 2 1:41 PM Jul 28th from web
The New Digg And The Future Of Social News http://bit.ly/cM7Guq 10:44 AM Jun 29th from TweetMeme
so as of right now, the Big 10 has 12 teams and the Big 12 has 10 teams? http://sports.espn.go.com/ncaa/news/story?id=5276668 7:59 PM Jun 11th from web
heading to Las Vegas for #caworld in the morning 7:12 PM May 12th from web
Found out from CNN that I went to high school with a convicted terrorist who worked with Al-Qaeda. Not what I expected to see on the news 9:49 PM May 10th from web
View all posts on Twitter »

Friend me

Twitter Digg Facebook FriendFeed Del.icio.us iFanboy Last.fm Squidoo

Login

Username:

Password: