PHP Directory List Group and Sort

onetoomany
onetoomany used Ask the Experts™
on
There are many solutions on the web for PHP directory listing howwver the ones I found either didn't have all the functions or I couldn't make all the functions work together. would appreciate help with the following for a beginner:

Relative path = 'files/'

Get all directories and files under this path and output in unordered list as follows:

 - Directory Name (sort ascending)
   -  "Date Group" by File Created Date Descending.
      -  <a href="path/filename">File name</a>  | File Size | Created Date (sort descending: m/d/Y H:i:s)

so an example output might look something like this:

 * Folder-A
       + Files created on 02/03/2010
            > file01212.txt | 352 kb | 02/03/2010 17:30:01
            > file01112.txt | 352 kb | 02/03/2010 17:30:00
       + Files created on 02/02/2010
            > file08212.txt | 152 kb | 02/02/2010 10:30:25
            > file01118.txt | 302 kb | 02/02/2010 07:30:24
 * Folder-B
       + Files created on 03/07/2010
            > file0121.txt | 1352 kb | 03/07/2010 09:00:01
            > file0000.txt | 6352 kb | 03/07/2010 08:30:00

Thanks in advance.

 



Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Here you go. This should do most of what you want.
<?php
 
ini_set('display_errors',1); error_reporting(E_ALL);

class FileData {

     public $fileDate;
     public $fileName;
     public $filePath;
     public $fileSize;

     function __construct( $p, $n, $d, $s ) {
          $this->filePath = $p;
          $this->fileName = $n;
          $this->size = $s;
          $this->fileDate = $d;
     }


     function FileCompareSort( $a, $b ) {
     
          // Build composite keys for sorting
          //
          $aKey = sprintf("%255s%010d%s", $a->filePath, $a->fileDate, $a->fileName );
          $bKey = sprintf("%255s%010d%s", $b->filePath, $b->fileDate, $b->fileName );

          // Compare
          //
          if ( $a < $b )
               return -1;
          else
               if ( $a > $b )
                    return 1;

          return 0;
     }
}


 
     function searchDir( $pathToDirectory, & $results ) {

          // Make sure the directory has a trailing slash
          //
          if ( substr( $pathToDirectory, -1, 1 ) != "/" )
               $pathToDirectory .= "/";
               
          // Get list of files in directory
          //
          if ( $fileList = opendir( $pathToDirectory ) ) {
               while ( $aFile = readdir( $fileList ) ) {
                    
                    if ( $aFile == "." || $aFile == ".." )
                         continue;
                    
                    // if a directory is encountered then process it first
                    //
                    if ( filetype( $pathToDirectory . $aFile ) == "dir" )
                         searchDir( $pathToDirectory . $aFile, $results );
                    
                    if ( filetype( $pathToDirectory . $aFile ) != "file" )
                         continue;
                    
                    // Get attributes and store in array
                    //
                    $dateCreated = filectime( $pathToDirectory . $aFile );
                    $size = filesize( $pathToDirectory . $aFile );

                    $results [] = new FileData( $pathToDirectory, $aFile, $dateCreated, $size );
               }
     
               closedir( $fileList );
          }
 
          return $results;
     }
 




     
$arr = array();
$pathToStartAt = "/path/to/folder";

// Gather data
//
searchDir($pathToStartAt, $arr);

// Sort into sequence
//
uasort( $arr, array( 'Filedata','FileCompareSort') );

// Display as a simple list
//
foreach( $arr as $aFile )  {
     echo $aFile->filePath . " " . date("m/d/Y", $aFile->fileDate ) . " " . $aFile->size . " " . $aFile->fileName . "<br/>";
}


?>

Open in new window

Author

Commented:
bportlock,

Thanks for the response, this is good however my key problem is the grouping and sorting per the spec I have provided above... I have been able to do scandirs and get attributes before but don't know how to group and sort the output.

Not sure if your code can do this or if you can modify to required output?

Thanks.
The code already returns the entries sorted by folder / date / name. Is that not the correct sequence?

Author

Commented:
bportlock,

Yes, thats the right sequence but doesn't appear to output that way, and I don't see any grouping. Please review the description above and compare. Sort on folder should be ascending by name, sort on date should be on date time descending, sort on name should be on name ascending.
Please let me know if error on my side but I tested with 3 folders each with 3 files.

Thanks.

If we need date time descending then we need to change the sort function because I did it the lazy way and it does everything in ascending sequence.

Replace the sort function with the following code and the date & time will be descending with the other fields in ascending order.
Would help if I attached the function.....
function FileCompareSort( $a, $b ) {
     
          if ( $a->filePath < $b->filePath )
               return -1;
          else
               if ( $a->filePath > $b->filePath )
                    return 1;
               else 
                    if ( $a->fileDate < $b->fileDate )
                         return 1;
                    else
                         if ( $a->fileDate > $b->fileDate )
                              return -1;
                         else
                              if ( $a->fileName < $b->fileName )
                                   return -1;
                              else
                                   if ( $a->fileName > $b->fileName )
                                        return 1;

          return 0;
     }

Open in new window

Author

Commented:
bportlock,

Very nice. Happy to accept solution. Any way you can help me with 2nd part of this request which is grouping?

If you refer to the above, I'd like to output these in groups:

- Folder Name (a)
- - File Date x Group
- - - File (Created Date x)
- - - File (Created Date x)
- - - File (Created Date x)
- - File Date y Group
- - - File (Created Date y)
- - - File (Created Date y)
- - - File (Created Date y)
- Folder Name (b)
- - File Date x Group
- - - File (Created Date x)
- - - File (Created Date x)
- - - File (Created Date x)
- - File Date y Group
- - - File (Created Date y)
- - - File (Created Date y)
- - - File (Created Date y)


Thanks again, especially for quick responses.
Try adding this
function listData( & $arr ) {

          $t = "";
          $currentDate = "";
          $currentPath = "";

          foreach( $arr as $aFile ) {
               
               $readableDate = date("m/d/Y", $aFile->fileDate);


               // Change of date?
               //
               if ( $aFile->filePath != $currentPath ) {
                    $t .= "- Folder name {$aFile->filePath}<br/>";
                    $currentPath = $aFile->filePath;
                    $currentDate = ""; // New folder means any dates are invalid
               }

               if ( $readableDate != $currentDate) {
                    $t .= "- - File date $readableDate group<br/>";
                    $currentDate = $readableDate;
               }


               $t .= "- - - {$aFile->fileName} (Created date $readableDate)<br/>";
          }

          return $t;
     }




     
$arr = array();
$pathToStartAt = "/path/to/folder";

// Gather data
//
searchDir($pathToStartAt, $arr);

// Sort into sequence
//
uasort( $arr, array( 'Filedata','FileCompareSort') );

// Display list
//
echo listData( $arr );

Open in new window

Author

Commented:
thank you bportlock
You're welcome. Hope it all goes OK.

Author

Commented:
bportlock,

Could you provide an error handler for this script if the $pathToStartAt  was not found.. $alertmessage = 'Path not found'; ... not sure where to terminate the script and put that.

Thanks.
There are a number of ways to handle this and they largely depend on how your script interacts with other scripts. One simple method is to use file_exists on the folder and then issue a DIE message

if ( ! file_exists( $pathToFolder ) )
     die("Sorry - $pathToFolder does not exist");

See http://www.php.net/file_exists


There are more elegant ways to solve this but they depend on how the code I gave you is integrated into the system in question, how it is called and how any results are returned.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial