DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

PHP Recursive Directory Traversal

04.14.2006
| 23979 views |
  • submit to reddit
        This an unstyled script which is useful for viewing directories and sub-directories. It's easy to style making it a nice script. I tried to comment things out as clearly as I could. This script should work as is, but if you are reading a remote directory the $start_dir variable should be edited. 
<?
#############################################
#This codes holds no license.               #
#Created in part by harkey of harkeyahh.com #
#############################################
/* Edited from PHPBuilder.com */
function readpath($dir,$level,$last,&$dirs,&$files){
	//print $dir." (DIR)<br/>\n";
	$dp=opendir($dir);
	while (false!=($file=readdir($dp)) && $level == $last){
		if ($file!="." && $file!="..")
                {
			if (is_dir($dir."/".$file))
			{
				readpath($dir."/".$file,$level+1,$last,$dirs,$files); // uses recursion
				$dirs[] = "$dir/$file";  // reads the dir into an array
			}
			else{
				$files[] = "$dir/$file"; // reads the file into an array
			}
		}
	}
}
/* From PHP.NET */
function get_size($path)
   {
       if(!is_dir($path))return filesize($path);
       $dir = opendir($path);
       while($file = readdir($dir))
       {
           if(is_file($path."/".$file))$size+=filesize($path."/".$file);
           if(is_dir($path."/".$file) && $file!="." && $file !="..")$size +=get_size($path."/".$file);
          
       }
       return $size;
   }
#####################
/* BEGIN MAIN CODE */
#####################
if(isset($_GET['i'])){
$start_dir = $_GET['i']; // this fetches the i or directory name through a link specified via the url.
}
else{    // else if no name is specified by link, then use the default
$start_dir = ".";   // . means the current directory or whatever name you specify
}

$level=1;  // level is the first level started at
$last=1; //this is set the same as level so the script does not read all directories, and only one at a time
$dirs = array();  // SET dirs as an ARRAY so it can be read
$files = array(); //SET files as an ARRAY so it can be read

readpath($start_dir,$level, $last, $dirs,$files);
?>

<strong>Sub Directories in <?=$start_dir?></strong><br/>
<?php
sort($dirs);

if(empty($dirs))   // checks if the dirs array is empty. if so, then display "empty"
{
echo"empty";
}
/* SHOWS THE DIRECTORIES FROM ARRAY */
foreach($dirs as $dir)
{
echo "<a href=\"$PHP_SELF?i=$dir\">$dir</a><br/>\n";//Creates a link to the dir through the script so it will be shown.
}
?>

<?php
/* SHOWS FILES FROM ARRAY*/
$tf = count($files);
echo "Local Files Total: $tf"; /* Display total in directory*/

sort($files);   // Sort the files alphabetically

foreach($files as $file)
{     //Below PHP functions are used to display file stats such as creation time, permissions etc.
echo "<br/><a href=\"$file\">$file</a> <strong>mtime:</strong>".date("U",@filemtime($file))." || ".date("(F)m.d.y",@filemtime($file));
echo " <strong>size:</strong>".get_size($file);
echo " <strong>mode:</strong>".substr(sprintf('%o', @fileperms($file)), -3);
echo "<br/>\n";
}
?>
    

Comments

Snippets Manager replied on Fri, 2007/04/20 - 4:56am

Problem was with my connect file, Sorry about that.

Snippets Manager replied on Fri, 2007/04/20 - 4:56am

Hey, I'm actually trying to figure out how to use this to update an sql database... the issue being, when I try to add an include to my connect.php file, it seems to kill the rest of the script. I was wondering if you guys would have any idea as to why. I know a fair share of PHP, but the traversal script is a bit out of my league.

Snippets Manager replied on Sun, 2006/05/28 - 1:58am

So here's that again with the code tag (sorry, my first comment :P) var stack = [] current_directory = '/this/dir' loop { entry = current_directory.get_next_file_entry if (entry_is_empty and no_more_entries) { break if stack.size < 1 current_directory = stack.pop next } if (entry_is_directory and need_recurse) { stack.push current_directory current_directory = entry next } }

Snippets Manager replied on Sun, 2006/05/28 - 1:58am

It's been such a long time since I used PHP I can't remember if recursive function calls are costly. In some languages (i.e. my beloved Ruby) the program will even crash if a method call itself recursively too many times (I discovered this first when parsing HTML). Directory recursion would not normally be deep enough to cause problems like this, but it could be. It's worth remembering that anywhere you use recursion you can often instead use a loop and an array as a stack, in this example (pseudo code): var stack = [] current_directory = '/this/dir' loop { entry = get_next_file_entry if entry_is_empty and no_more_entries break if stack.size < 1 current_directory = stack.pop next end if entry_is_directory and need recurse stack.push current_directory current_directory = entry next end } On the other hand, if I was using ruby I could just do Dir['/this/dir/**/*'] to do all of that instead :) This is just here incase someone uses this for deep recursion and it gives them problems as a simple work-around. And to plug Ruby because so many poor PHP developers have yet to try it and don't know what they're missing ;)

Snippets Manager replied on Fri, 2006/04/14 - 6:30pm

True probably should have done that seeing as the is data appropriate for tables. I found it easier using divs and floating them, since tables get such a bad rap. Thanks for the improvement, ~Hark

Snippets Manager replied on Fri, 2006/04/14 - 11:05pm

nice code, but this version has a neater output. <? ############################################# #This codes holds no license. # #Created in part by harkey of harkeyahh.com # ############################################# /* Edited from PHPBuilder.com */ function readpath($dir,$level,$last,&$dirs,&$files){ //print $dir." (DIR) \n"; $dp=opendir($dir); while (false!=($file=readdir($dp)) && $level == $last){ if ($file!="." && $file!="..") { if (is_dir($dir."/".$file)) { readpath($dir."/".$file,$level+1,$last,$dirs,$files); // uses recursion $dirs[] = "$dir/$file"; // reads the dir into an array } else{ $files[] = "$dir/$file"; // reads the file into an array } } } } /* From PHP.NET */ function get_size($path) { if(!is_dir($path))return filesize($path); $dir = opendir($path); while($file = readdir($dir)) { if(is_file($path."/".$file))$size+=filesize($path."/".$file); if(is_dir($path."/".$file) && $file!="." && $file !="..")$size +=get_size($path."/".$file); } return $size; } ##################### /* BEGIN MAIN CODE */ ##################### if(isset($_GET['i'])){ $start_dir = $_GET['i']; // this fetches the i or directory name through a link specified via the url. } else{ // else if no name is specified by link, then use the default $start_dir = "."; // . means the current directory or whatever name you specify } $level=1; // level is the first level started at $last=1; //this is set the same as level so the script does not read all directories, and only one at a time $dirs = array(); // SET dirs as an ARRAY so it can be read $files = array(); //SET files as an ARRAY so it can be read readpath($start_dir,$level, $last, $dirs,$files); ?> Sub Directories:
<? sort($dirs); if(empty($dirs)) // checks if the dirs array is empty. if so, then display "empty" { echo"empty"; } /* SHOWS THE DIRECTORIES FROM ARRAY */ foreach($dirs as $dir) { echo "$dir
\n";//Creates a link to the dir through the script so it will be shown. } /* SHOWS FILES FROM ARRAY*/ $tf = count($files); echo "
Local Files Total: $tf
"; /* Display total in directory*/ sort($files); // Sort the files alphabetically echo(""); echo ""; foreach($files as $file) { //Below PHP functions are used to display file stats such as creation time, permissions etc. echo "\n"; } echo("
namedatesizemode
". str_replace('./','',$file)." ".date("d.m.y",@filemtime($file)); echo "".get_size($file); echo "".substr(sprintf('%o', @fileperms($file)), -3); echo "
"); ?>