info about link
: Javascript : PHP Index : MySQL :
list directory class
: Source : : Explanation : : Example : : Todo : : Feedback :

list_dir.class.php (v. 1.1)

This class facilitates listing the contents of directories (recursively)

Added: 2008-08-02 12:41:07

download

<?
/******
* You may use and/or modify this script as long as you:
* 1. Keep my name & webpage mentioned
* 2. Don't use it for commercial purposes
*
* If you want to use this script without complying to the rules above, please contact me first at: marty@excudo.net

* Author: Martijn Korse
* Website: http://devshed.excudo.net
*
* Date:  2008-08-02 12:41:07
***/


/**
 * This class facilitates listing the contents of directories.
 * It features:
 * - optional recursiveness
 * - sorting of output by
 * - + name
 * - + extension
 * - + size
 * - + time (of modification)
 * - output control
 * 
 * It has been written in PHP compatibel code, since PHP5 already provides an easier way (though
 * not as extensive as this one) to deal with directory-listing
 *
 * The final output will be an array (multidimensional when recursiveness is switched on) that looks like this:
 * array {
 *    "dirs"  => array()   // contains all the directories
 *   "files" => array()   // contains all the files
 *   }
 * When a directory has a subdirectory, this array will look the same and can be found under the 'list' key.
 * The complete array of files and directories look like this:
 *
 * dirs:
 *   array (
 *      "name"      => name of the directory
 *      "modified"   => unix-timestamp when it was last modified
 *      "accessed"   => unix-timestamp when it was last accessed
 *      "size"      => total size of the directory in bytes, which is a sum of all the files in it (not recursive!)
 *      "files"      => total amount of files in it
      "list"      => array( etc )
 *   )
 * files:
 *   array (
 *      "name"      => name of the directory
 *      "ext"      => file extension
 *      "modified"   => unix-timestamp when it was last modified
 *      "accessed"   => unix-timestamp when it was last accessed
 *      "size"      => total size of the directory in bytes, which is a sum of all the files in it (not recursive!)
 *   )
 *
 * @todo: support for multiple parameters
 * @todo: add size of subdirectories to size of own directory
 */
class ListDir
{
   
/**
    * Hold the path to the directory that we want to list
    * This value will change when we recurse!
    *
    * @access private
    * @var string
    */
   
var $root;
   
/**
    *
    * @access private
    * @var boolean
    */
   
var $rootIsDir;
   
/**
    *
    * @access public
    * @var boolean
    */
   
var $sane;
   
/**
    *
    * @access private
    * @var array
    */
   
var $content = array();   // array

   /**
    * PHP4 style constructor
    * 
    * @param string $path   the path to the directory we want to list
    */
   
function ListDir($path)
   {
      
// pointing the current root to the one given.
      
$this->setRoot($path);
   }

   
/**
    * Setter for the root-variable
    * 
    * @param string $path
    */
   
function setRoot($path)
   {
       
// check if the path exists
      
if (file_exists($path))
      {
         
$this->sane True;
         
$this->root $path;
         
$this->rootIsDir is_dir($path) ? True False;
      }
      else
      {
         
$this->sane False;
      }
   }

   
/**
    * Lists the content of the currently set root (@see constructor)
    *
    * @param string $params parameters indicating how to sort
    * @param bool $recursive indicates whether the function should recurse or not
    * @param array $parentDir a reference to the parent-dir. this shouldnt be set from
    *            outside. it will be filled during recursion so we
    *            can update the parentdir with info about the files
    * @see parseParams()
    * @return array
    */
   
function listContent($params ""$recursive true$parentDir null)
   {
      
$outputArr = array("dirs"=>array(), "files"=>array());
      if (!empty(
$params))
         
$order $this->parseParam($params);

      if (
$handle opendir($this->root))
      {
         
$dirIndex 0;
         
$fileIndex 0;
         while (
false !== ($file readdir($handle)))
         {
            if (
$file != "." && $file != "..")
            {
               if (
is_dir($this->root."/".$file))
               {
                  
$statArr stat($this->root."/".$file);
                  if (
$recursive)
                  {
                     
// advancing the root to the next dir
                     
$this->setRoot($this->root."/".$file);
                     
$outputArr['dirs'][$dirIndex] = array(
                        
"name"      => $file,
                        
"modified"   => $statArr['mtime'],
                        
"accessed"   => $statArr['atime'],
                        
"size"      => 0,
                        
"files"      => 0,
                        );
                     
$outputArr['dirs'][$dirIndex]['list'] = $this->listContent($params$recursive$outputArr['dirs'][$dirIndex]);
                     
$dirIndex++;
                     
// going back to the previous path, since we exited the recursion
                     
$this->setRoot($this->root."/../");
                  }
                  else
                  {
                     
$outputArr['dirs'][$dirIndex++] = array(
                        
"name"      => $file,
                        
"modified"   => $statArr['mtime'],
                        
"accessed"   => $statArr['atime'],
                        
"size"      => null,
                        
"files"      => null,
                        
"list"      => null
                        
);
                  }
               }
               else
               {
                  
// a file. we add it
                  
$this->addFile($file$outputArr['files'][]);
                  
// and update the dir it is in with some information
                  
$this->updateDir($parentDir$outputArr['files'][$fileIndex]);
                  
$fileIndex++;
               }
            }
         }
         
closedir($handle); 
      }
      if (!empty(
$params))
      {
         
// parameters were passed, so we sort the output
         
$this->sortArray($outputArr$params);
      }
      return 
$outputArr;
   }

   
/**
    * Adds a file to the stack and fills its properties
    *
    * @param string $file The name of the file
    * @param null $arrIndex  Reference to the place in the stack where the array of information about the file needs to be stored
    * @return void
    */
   
function addFile($file, &$arrIndex)
   {
      
$statArr stat($this->root."/".$file);
      
// root = $this->root
      
$arrIndex = array(
         
"name"      => $file,
         
"ext"      => substr(strrchr($file"."), 1),
         
"size"      => $statArr['size'],
         
"modified"   => $statArr['mtime'],
         
"accessed"   => $statArr['atime'],
         );
   }

   
/**
    * Updates a directory-array using a file-array for information
    *
    * @param array $dirArr The dir that we want to update (which is the directory in which the file (fileArr) is located
    * @param array $fileArr An array with information about a file
    * @return void
    */
   
function updateDir(&$dirArr$fileArr)
   {
      if (!
is_null($dirArr))
      {
         
$dirArr['size'] += $fileArr['size'];
         
$dirArr['files']++;
      }
   }

   
/**
    * Lists all the files in a directory (so, without directories)
    * Because directories are not considered, this is not recursive
    *
    * @param string $params Sorting parameters
    * @see parseParams()
    * @return array 
    */
   
function listFiles($params "")
   {
      
$content $this->listContent($paramsFalsenull);
      return 
$content['files'];
   }

   
/**
    * Lists all the directories in a directory (so, without files)
    * For uniformity, this method is also non-recursive (like listFiles). Use listContent
    * if you need recursiveness
    *
    * @param string $params Sorting parameters
    * @see parseParams()
    * @return array
    */
   
function listDirs($params "")
   {
      
$content $this->listContent($paramsFalsenull);
      return 
$content['dirs'];
   }

   
/**
    * Parses the parameter string that some methods (listContent(), listFiles(), listDirs(), sortArray()) (can) take
    * as argument.
    * The format should be "type direction [, type direction [, type direction]]"
    *   Example: NAME DESC, EXT ASC
    * Where 'type' can be:
    * - NAME   to sort by filename
    * - EXT   to sort by extension
    * - SIZE   to sort by filesize
    * - TIME   to sort by time of last modification
    * And 'direction' can be:
    * - ASC   to order ascending (default) (so, A->Z or 0->999)
    * - DESC   to order descending (so, Z->A or 999->0)
    *
    * NOTE: although this function can already parse multiple sorting options, the sortArray() function cannot handle them
    *       so, only use one 'type direction' for now.
    *
    * @param string $params The parameter string
    * @return array
    *
    * @see sortArray()
    * @see listContent()
    * @see listFiles()
    * @see listDirs()
    */
   
function parseParam($params)
   {
      if (
preg_match("/,/"$params))
         
$paramArr preg_split("/,( )*/"$params);
      else
         
$paramArr = array($params);
      foreach (
$paramArr AS $value)
      {
         if (
preg_match("/( )/"$value))
            list(
$orderType$orderDirection) = preg_split("/( )+/"$value);
         else
            list(
$orderType$orderDirection) = array(trim($value), "ASC");
         
$order[$orderType] = $orderDirection;
      }
      return 
$order;
   }

   
/**
    * Sorts an array according to parameters passed by the user
    *
    * NOTE: only 1 soting option can be given for the moment. But in case of equal occurences ...
    * - When sorting by name, it will automatically sort by extension too in the same direction (asc/desc)
    * - When sorting by ext, it will automatically sort by name too in the same direction (asc/desc)
    *
    * @param array $arr The array that needs to be sorted (containting files and/or dirs)
    * @param string $params
    * @return void
    *
    */
   
function sortArray(&$arr$params)
   {
      
$orderArray $this->parseParam($params);
      if (
count($orderArray) == 1)
      {
         foreach (
$orderArray AS $type => $direction)
         {
            
$direction strtoupper($direction);

            switch(
strtoupper($type))
            {
               case 
"NAME" :
                  
$this->sortBy($arr['files'], "name"$direction);
                  
$this->sortBy($arr['dirs'], "name"$direction);
                  break;
               case 
"EXT" :
                  
$this->sortBy($arr['files'], "ext"$direction);
                  
$this->sortBy($arr['dirs'], "name"$direction);
                  break;
               case 
"SIZE" :
                  
$this->sortBy($arr['files'], "size"$direction);
                  
$this->sortBy($arr['dirs'], "size"$direction);
                  break;
               case 
"TIME" :
                  
$this->sortBy($arr['files'], "modified"$direction);
                  
$this->sortBy($arr['dirs'], "modified"$direction);
                  break;
               default:
                  die(
"unsupported sort ".$type);
            }
         }
      }
      else
      {
         die(
"multiple sorts are not supported (yet)");
      }
   }

   
/**
    * Manages what kind of callback function for usort() to use
    *
    * @see sortArray()
    *
    * @param array $arr Array that needs to be sorted
    *
    */
   
function sortBy(&$arr$type$direction)
   {
      switch (
$type)
      {
         case 
"size" :
            
usort($arr, array(get_class($this), "fileCompareSize"));
            break;
         case 
"ext" :
            
usort($arr, array(get_class($this), "fileCompareExt"));
            break;
         case 
"modified" :
            
usort($arr, array(get_class($this), "fileCompareModified"));
            break;
         default :   
/* name */
            
usort($arr, array(get_class($this), "fileCompareName"));
            break;
      }
      
// if it is indicated the sorting has to be 'descending', we simply reverse the array
      
if ($direction == "DESC")
      {
         
$arr array_reverse($arrfalse);
      }
   }

   
/**
    * comparison functions
    * these all return 0, -1 or 1; this value is used by PHP's usort() to sort the array accordingly
    */

   /**
    * Compares the filename of two file-arrays
    * When two names are identical, they are further compared by extention
    *
    * @see compareArr()
    * @see sortBy()
    *
    * @return int (0 / -1 / 1)
    */
   
function fileCompareName($a$b)
   {
      if (isset(
$this) && is_object($this))
         
$result $this->compareArr($a$b"name");
      else
         
$result ListDir::compareArr($a$b"name");      
      if (
$result === 0)
      {
         
$result $this->compareArr($a$b"ext");
      }
      return 
$result;
   }

   
/**
    * Compares the file-extention time of two file-arrays
    * When two names are identical, they are further compared by filename
    *
    * @see compareArr()
    * @see sortBy()
    *
    * @return int (0 / -1 / 1)
    */
   
function fileCompareExt($a$b)
   {
      if (isset(
$this) && is_object($this))
         
$result $this->compareArr($a$b"ext");
      else
         
$result ListDir::compareArr($a$b"ext");
      if (
$result === 0)
      {
         
$result $this->compareArr($a$b"name");
      }
      return 
$result;
   }

   
/**
    * Compares the size of two file/dir-arrays
    *
    * @see compareInt()
    * @see sortBy()
    *
    * @return int (0 / -1 / 1)
    */
   
function fileCompareSize($a$b)
   {
      if (isset(
$this) && is_object($this))
         return 
$this->compareInt(intval($a['size']), intval($b['size']));
      else
         return 
ListDir::compareInt(intval($a['size']), intval($b['size']));
   }

   
/**
    * Compares the modification time of two file/dir-arrays
    *
    * @see compareInt()
    * @see sortBy()
    *
    * @return int (0 / -1 / 1)
    */
   
function fileCompareModified($a$b)
   {
      if (isset(
$this) && is_object($this))
         return 
$this->compareInt(intval($a['modified']), intval($b['modified']));
      else
         return 
ListDir::compareInt(intval($a['modified']), intval($b['modified']));
   }

   
/**
    * Compares two integers
    *
    * @see fileCompareSize()
    * @see fileCompareModified()
    *
    * @return int (0 / -1 / 1)
    */
   
function compareInt($x$y)
   {
      if (
$x == $y) {
         return 
0;
      }
      return (
$x $y) ? -1
   }


   
/**
    * Compares specific values (indicated by $key) of two arrays based on the alphabet
    *
    * @see fileCompareName()
    * @see fileCompareExt()
    *
    * @return int (0 / -1 / 1)
    */
   
function compareArr($x$y$key)
   {
      if (
$x[$key] == $y[$key]) {
         return 
0;
      }
      
$tempArr = array($y[$key], $x[$key]);
      
sort($tempArr);
      
reset($tempArr);
      
      return (
$x[$key] == $tempArr[0]) ? -1
   }

   
/**
    * You can pass a (sorted) array to this function (of the type that gets outputted by listContent()
    * You can pass different functions for handling the output of a file and a directory. Those functions will be passed 3 parameters:
    * 1. The file or directory array (as described at the top of this file)
    * 2. The current position of that array. Say, we are in a loop containing 5 file-arrays and we're passing the 2nd one to the custom
    *    function, this argument will have the value 2
    * 3. The total amount of arrays that will be passed during that loop. In the example of (2.) that would have been 5.
    * => 2. & 3. allow you to do something special, for example, at the beginning and end of the loop by comparing these numbers. That way you
    * can, for example, open and close an unsorted list (<ul></ul>)
    *
    * @param array      $arr      array, like the one outputted by listContent()
    * @param string|array   $dirFunc   string: the name of the function that should handle the output of a directory
    *               array: the name of the class and the (static) method that should handle the output of a directory
    * @param string|array   $fileFunc   string: the name of the function that should handle the output of a file
    *               array: the name of the class and the (static) method that should handle the output of a file
    *
    * @access public
    *
    * @see listContent()
    * 
    * @return void
    */   
   
function showOutput($arr$dirFunc$fileFunc)
   {
      if (isset(
$arr['dirs']))
      {
         
$totalDir count($arr['dirs']);
         
$cursorDir 1;
         foreach (
$arr['dirs'] AS $dirArr)
         {
            
call_user_func($dirFunc$dirArr$cursorDir++, $totalDir);
            if (
is_array($dirArr['list']) && count($dirArr['list']) > 0)
            {
               
$this->showOutput($dirArr['list'], $dirFunc$fileFunc);
            }
         }
      }
      else
      {
         
$totalDir 0;
      }
      if (isset(
$arr['files']))
      {
         
$totalFiles count($arr['files']);
         
$cursorFiles 1;
         foreach (
$arr['files'] AS $fileArr)
         {
            
call_user_func($fileFunc$fileArr$cursorFiles++, $totalFiles$totalDir);
         }
      }
   }
}
?>

download

=[Disclaimer]=     © 2005-2018 Excudo.net