Search code examples
phpsortingdatetimeglobusort

How to sort files with more than one month in PHP?


Files on Disk to be sorted.

        'data/tsm/seasonal/tsm-2012-Apr-May-Jun.png', 
        'data/tsm/seasonal/tsm-2012-Jan-Feb-Mar.png', 
        'data/tsm/seasonal/tsm-2012-Jul-Aug-Sep.png', 
        'data/tsm/seasonal/tsm-2012-Oct-Nov-Dec.png', 
        'data/tsm/seasonal/tsm-2013-Apr-May-Jun.png', 
        'data/tsm/seasonal/tsm-2013-Jan-Feb-Mar.png'

I want to the files to be sorted first by year then by the first month eg. Apr for 'tsm-2012-Apr-May-Jun.tif', I want it to be sorted using 2012-Apr.

        <?php
function filesInRange($datadir, $parameter, $start_date, $end_date, $format, $patternval{
    $matches=array();
    $good_files = array();
       if (is_Dir($datadir)) {    
           foreach (new DirectoryIterator($datadir) as $fileInfo) {
               $matches=array(); 
               if ( !$fileInfo->isDot() && $fileInfo->isFile() ) {
               //  create a date by parsing the file name
                   preg_match($patternval, $fileInfo->getFileName(), $matches);
                   if ($matches) { 
                        $filedate = DateTime::createFromFormat($format, $matches[0]);
                   }//  determine if it's between start and end date
                   if ($filedate >= $start_date && $filedate <= $end_date) {
                     $good_files[] = $datadir.$fileInfo->getFileName();
                   }
               }

            }
        }
        asort($good_files);
        return $good_files;  
}
function startend($timeper1, $timeper2, $formatse) {
    global $start; 
    global $end; 
    $start = DateTime::createFromFormat( $formatse,$timeper1);
    $end   = DateTime::createFromFormat( $formatse,$timeper2);
}

To call the functions I do this.

$season = substr('2012-Jan-Feb-Mar', 0, -8); 
$season2 = substr('2013-Apr-May-Jun', 0, -8); 
startend($season, $season2, 'Y-M');
$allfiles = filesInRange( "data/tsm/seasonal/" , 'tsm', $start, $end, 'Y-M', '/(?<year>\d{4})-(?<month>\w{3})/' );

Then I get the directories echoed using foreach.

foreach ($allfiles as $filesfound) {
    echo '<a href="'. $filesfound.'">'. basename($filesfound). '</a>';
}
?>

Unfortunately the come unsorted.

sean9999 shared me this http://3v4l.org/WSaS3 page but it didn't help but it gives idea.

I guess, I have to use substr() to trim the other months but it is an array. Thank you for the help!


Solution

  • Alternatively, since you already got the values but unsorted, you could just use a custom sorting using usort(). You need to convert those months into month numbers first.

    Rough example:

    $allfiles = ['data/tsm/seasonal/tsm-2012-Apr-May-Jun.png', 'data/tsm/seasonal/tsm-2012-Jan-Feb-Mar.png', 'data/tsm/seasonal/tsm-2012-Jul-Aug-Sep.png', 'data/tsm/seasonal/tsm-2012-Oct-Nov-Dec.png', 'data/tsm/seasonal/tsm-2013-Apr-May-Jun.png', 'data/tsm/seasonal/tsm-2013-Jan-Feb-Mar.png'];
    usort($allfiles, function($a, $b){
        $a_base = explode('-', ltrim(basename($a, '.png'), 'tsm-')); // trim those uneeded string parts
        $b_base = explode('-', ltrim(basename($b, '.png'), 'tsm-'));
        array_walk($a_base, 'change_months');
        array_walk($b_base, 'change_months'); // convert months to month number
        $a_base = (int) implode($a_base);
        $b_base = (int) implode($b_base); // glue them back again
    
        return $a_base - $b_base;
    });
    
    function change_months(&$val) {
        if(!is_numeric($val)) { // no need to convert the year
            $date_month = date_parse($val);
            $val = $date_month['month']; // get month number
            $val = ((strlen($val) == 1) ? '0'.$val : $val);
        }
    }
    
    echo '<pre>';
    print_r($allfiles);
    

    Should result into:

    Array
    (
        [0] => data/tsm/seasonal/tsm-2012-Jan-Feb-Mar.png
        [1] => data/tsm/seasonal/tsm-2012-Apr-May-Jun.png
        [2] => data/tsm/seasonal/tsm-2012-Jul-Aug-Sep.png
        [3] => data/tsm/seasonal/tsm-2012-Oct-Nov-Dec.png
        [4] => data/tsm/seasonal/tsm-2013-Jan-Feb-Mar.png
        [5] => data/tsm/seasonal/tsm-2013-Apr-May-Jun.png
    )