Home Page
  • March 28, 2024, 08:01:51 am *
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Official site launch very soon, hurrah!


Author Topic: Outputting directory contents in PHP  (Read 8104 times)

Dakusan

  • Programmer Person
  • Administrator
  • Hero Member
  • *****
  • Posts: 535
    • View Profile
    • Dakusan's Domain
Outputting directory contents in PHP
« on: September 28, 2009, 05:31:17 am »


A friend just asked me to write a PHP function to list all the contents of a directory and its sub-directories.
Nothing special here... just a simple example piece of code and boredom...

function ListContents($DirName)
{
   print '<ul>';
   $dir=opendir($DirName);
   while($file=readdir($dir))
      if($file!='.' && $file!='..')
      {
         $FilePath="$DirName/$file";
         $IsDir=is_dir($FilePath);
         print "<li>$file [".($IsDir ? 'D' : number_format(filesize($FilePath), 0, '.', ',')).']';
         if($IsDir)
            ListContents($FilePath);
         print '</li>';
      }
   closedir($dir);
   print '</ul>';
}
It wouldn’t be a bad idea to turn off PHP’s “output buffering” and on “implicit flush” when running something like this for larger directories.
Example output for “ListContents('c:\\temp');”:
  • A.BMP [230]
  • Dir1 [D]
    • codeblocks-1.0rc2_mingw.exe [13,597,181]
    • Dir1a [D]
      • DEBUGUI.C [25,546]
  • Dir2 [D]
    • Dir3 [D]
      • HW.C [12,009]
      • INIFILE.C [9,436]
    • NTDETECT.COM [47,564]


    I decided to make it a little nicer afterwards by bolding the directories, adding their total size, and changing sizes to a human readable format. This function is a lot more memory intensive because it holds data in strings instead of immediately outputting.

    function HumanReadableSize($Size)
    {
       $MetricSizes=Array('Bytes', 'KB', 'MB', 'GB', 'TB');
       for($SizeOn=0;$Size>=1024 && $SizeOn<count($MetricSizes)-1;$SizeOn++) //Loops until Size is < a binary thousand (1,024) or we have run out of listed Metric Sizes
          $Size/=1024;
       return preg_replace('/\\.?0+$/', '', number_format($Size, 2, '.', ',')).' '.$MetricSizes[$SizeOn]; //Forces to a maximum of 2 decimal places, adds comma at thousands place, appends metric size
    }

    function ListContents2($DirName, &$RetSize)
    {
       $Output='<ul>';
       $dir=opendir($DirName);
       $TotalSize=0;
       while($file=readdir($dir))
          if($file!='.' && $file!='..')
          {
             $FilePath="$DirName/$file";
             if(is_dir($FilePath)) //Is directory
             {
                $DirContents=ListContents2($FilePath, $DirSize);
                $Output.="<li>$file [".HumanReadableSize($DirSize)."]$DirContents</li>";
                $TotalSize+=$DirSize;
             }
             else //Is file
             {
                $FileSize=filesize($FilePath);
                $Output.="<li>$file [".HumanReadableSize($FileSize).']</li>';
                $TotalSize+=$FileSize;
             }
          }
       closedir($dir);
       $RetSize=$TotalSize;
       $Output.='</ul>';
       return $Output;
    }
    Example output for “print ListContents2('c:\\temp', $Dummy);”:
    • A.BMP [230 Bytes]
    • Dir1 [12.99 MB]
      • codeblocks-1.0rc2_mingw.exe [12.97 MB]
      • Dir1a [24.95 KB]
        • DEBUGUI.C [24.95 KB]
    • Dir2 [0 Bytes]
      • Dir3 [20.94 KB]
        • HW.C [11.73 KB]
        • INIFILE.C [9.21 KB]
      • NTDETECT.COM [46.45 KB]


      The memory problem can be rectified through a little extra IO by calculating the size of a directory before its contents is listed, thereby not needing to keep everything in a string.

      function CalcDirSize($DirName)
      {
         $dir=opendir($DirName);
         $TotalSize=0;
         while($file=readdir($dir))
            if($file!='.' && $file!='..')
               $TotalSize+=(is_dir($FilePath="$DirName/$file") ? CalcDirSize($FilePath) :  filesize($FilePath));
         closedir($dir);
         return $TotalSize;
      }

      function ListContents3($DirName)
      {
         print '<ul>';
         $dir=opendir($DirName);
         $TotalSize=0;
         while($file=readdir($dir))
            if($file!='.' && $file!='..')
            {
               $FilePath="$DirName/$file";
               $IsDir=is_dir($FilePath);
               $FileSize=($IsDir ? CalcDirSize($FilePath) : filesize($FilePath));
               $TotalSize+=$FileSize;
               print '<li>'.($IsDir ? '' : '').$file.($IsDir ? '' : '').' ['.HumanReadableSize($FileSize).']';
               if($IsDir) //Is directory
                  $TotalSize+=ListContents3($FilePath);
               print '</li>';
            }
         closedir($dir);
         print '</ul>';
      }
      Example output: for “ListContents3('c:\\temp');”:
      • A.BMP [230 Bytes]
      • Dir1 [12.99 MB]
        • codeblocks-1.0rc2_mingw.exe [12.97 MB]
        • Dir1a [24.95 KB]
          • DEBUGUI.C [24.95 KB]
      • Dir2 [0 Bytes]
        • Dir3 [20.94 KB]
          • HW.C [11.73 KB]
          • INIFILE.C [9.21 KB]
        • NTDETECT.COM [46.45 KB]


        Of course, after all this, my friend took the original advice I gave him before writing any of this code, which was that using bash commands might get him to his original goal much easier.
        Logged