Never been to DZone Snippets before?

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

PHP Recursive Directory Traversal (See related posts)

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.
   1  
   2  <?
   3  #############################################
   4  #This codes holds no license.               #
   5  #Created in part by harkey of harkeyahh.com #
   6  #############################################
   7  /* Edited from PHPBuilder.com */
   8  function readpath($dir,$level,$last,&$dirs,&$files){
   9  	//print $dir." (DIR)<br/>\n";
  10  	$dp=opendir($dir);
  11  	while (false!=($file=readdir($dp)) && $level == $last){
  12  		if ($file!="." && $file!="..")
  13                  {
  14  			if (is_dir($dir."/".$file))
  15  			{
  16  				readpath($dir."/".$file,$level+1,$last,$dirs,$files); // uses recursion
  17  				$dirs[] = "$dir/$file";  // reads the dir into an array
  18  			}
  19  			else{
  20  				$files[] = "$dir/$file"; // reads the file into an array
  21  			}
  22  		}
  23  	}
  24  }
  25  /* From PHP.NET */
  26  function get_size($path)
  27     {
  28         if(!is_dir($path))return filesize($path);
  29         $dir = opendir($path);
  30         while($file = readdir($dir))
  31         {
  32             if(is_file($path."/".$file))$size+=filesize($path."/".$file);
  33             if(is_dir($path."/".$file) && $file!="." && $file !="..")$size +=get_size($path."/".$file);
  34            
  35         }
  36         return $size;
  37     }
  38  #####################
  39  /* BEGIN MAIN CODE */
  40  #####################
  41  if(isset($_GET['i'])){
  42  $start_dir = $_GET['i']; // this fetches the i or directory name through a link specified via the url.
  43  }
  44  else{    // else if no name is specified by link, then use the default
  45  $start_dir = ".";   // . means the current directory or whatever name you specify
  46  }
  47  
  48  $level=1;  // level is the first level started at
  49  $last=1; //this is set the same as level so the script does not read all directories, and only one at a time
  50  $dirs = array();  // SET dirs as an ARRAY so it can be read
  51  $files = array(); //SET files as an ARRAY so it can be read
  52  
  53  readpath($start_dir,$level, $last, $dirs,$files);
  54  ?>
  55  
  56  <strong>Sub Directories in <?=$start_dir?></strong><br/>
  57  <?php
  58  sort($dirs);
  59  
  60  if(empty($dirs))   // checks if the dirs array is empty. if so, then display "empty"
  61  {
  62  echo"empty";
  63  }
  64  /* SHOWS THE DIRECTORIES FROM ARRAY */
  65  foreach($dirs as $dir)
  66  {
  67  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.
  68  }
  69  ?>
  70  
  71  <?php
  72  /* SHOWS FILES FROM ARRAY*/
  73  $tf = count($files);
  74  echo "Local Files Total: $tf"; /* Display total in directory*/
  75  
  76  sort($files);   // Sort the files alphabetically
  77  
  78  foreach($files as $file)
  79  {     //Below PHP functions are used to display file stats such as creation time, permissions etc.
  80  echo "<br/><a href=\"$file\">$file</a> <strong>mtime:</strong>".date("U",@filemtime($file))." || ".date("(F)m.d.y",@filemtime($file));
  81  echo " <strong>size:</strong>".get_size($file);
  82  echo " <strong>mode:</strong>".substr(sprintf('%o', @fileperms($file)), -3);
  83  echo "<br/>\n";
  84  }
  85  ?>

Comments on this post

microbe posts on Apr 14, 2006 at 23:06
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("<table border='0' cellpadding='3'>");
echo "<tr><td>
name</td><td>date</td><td>size</td><td>mode</td></tr>";
foreach($files as $file)

{ //Below PHP functions are used to display file stats such as creation time, permissions etc.
echo "<tr><td>".
str_replace('./','',$file)."</td><td> ".date("d.m.y",@filemtime($file));
echo "</td><td>".get_size($file);
echo "</td><td>".substr(sprintf('%o', @fileperms($file)), -3);
echo "
</td></td>\n";
}
echo("</table>");
?>
harkey posts on Apr 27, 2006 at 22:41
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
itchybeard posts on May 28, 2006 at 02:26
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 ;)
itchybeard posts on May 28, 2006 at 02:28
So here's that again with the code tag (sorry, my first comment :P)

   1  
   2  var stack = []
   3  
   4  current_directory = '/this/dir'
   5  
   6  loop {
   7    entry = current_directory.get_next_file_entry
   8    if (entry_is_empty and no_more_entries) {
   9      break if stack.size < 1
  10      current_directory = stack.pop
  11      next
  12    }
  13    if (entry_is_directory and need_recurse) {
  14      stack.push current_directory
  15      current_directory = entry
  16      next
  17    }
  18  }
wardrich posts on Apr 20, 2007 at 04:58
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.
wardrich posts on Apr 20, 2007 at 05:17
Problem was with my connect file, Sorry about that.

You need to create an account or log in to post comments to this site.


Click here to browse all 5829 code snippets

Related Posts