phpsortingscandirfilemtime

scandir subfolder gives errors when I try to sort images by filemtime in php (filemtime(): stat failed)


I wrote a php gallery some years ago, all works fine until I put in scandir a subfolder (foto), I have the following structure:

in folder foto there are all bigger photos, inside thumbs there are all miniatures, in thumbs_b there are all medium miniatures.

The code is working fine until I keep commented the sorting arrays:

#array_multisort(array_map('filemtime', $files), SORT_NUMERIC, SORT_DESC, $files);

if I remove the comment I get a lot of errors that sounds like a issue related to path of filemtime...

array_multisort(array_map('filemtime', $files), SORT_NUMERIC, SORT_DESC, $files);

This is the error I get when try to sort images by filemtime.

Warning: filemtime(): stat failed for Castellamare_Del_Golfo_16082016_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Cefalu_14082017_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Cefalu_14082017_002.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Charleston_Mondello_04062014_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Charleston_Mondello_15032010_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Concerto_Politeama_Palermo_25072015_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Foro_Italico_Magnolia_02022014_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Gattino_08092008_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Mondello_Lido_04062014_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Mondello_Passeggiata_10092007_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Riserva_Naturale_Capo_Gallo_02082016_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Riserva_Naturale_Capo_Gallo_02082016_002.jpg in D:\Web\test\www\gallery\gallery.php on line 84
Warning: filemtime(): stat failed for Terrasini_Scultura_23122018_001.jpg in D:\Web\test\www\gallery\gallery.php on line 84

and the images are not displayed anymore.

How to fix this error? Sounds me like a bug of Php. No error if I put in scandir($src_folder); without the additional path foto and if I move all images from root/gallery/foto/ to root/gallery/. The problem is sort images is not working if scandir is working on subfolder. I have php 8.1.11 64bit and apache 2.4.53 64bit.

This is a partial code, all full code is about 15 kb, this is a short version for testing purpose...

<?php
$pageText = 'Page ';
$pageOfText = ' of ';
$imageText1 = ' image';
$imageText2 = ' images';
$photoText = 'photo';
$comments = 'Comments';
$thumb_width = 120;  // width of thumbnails
$thumb_height = 85;  // height of thumbnails
$itemsPerPage = 5;  // number of images per page
$src_folder = '.';  // current folder images
$src_files = scandir("$src_folder/foto");  // files in current folder
$extensions = array(".jpeg",".jpg",".png",".gif");  // allowed extensions in photo gallery
//  display pagination
      
function print_pagination($pageText, $pageOfText, $numPages, $currentPage) 
{
    $page = 1;
    $page = (isset($_GET['page']) && is_numeric($_GET['page']) && $_GET['page'] > 0) 
                ? htmlspecialchars((int) $_GET['page'], ENT_QUOTES | ENT_HTML401, 'UTF-8') 
                : 1;
    $page = str_replace("\0", "", $page);
    $currentPage = (is_numeric($currentPage) && $currentPage > 0) 
                    ? htmlspecialchars((int) $currentPage, ENT_QUOTES | ENT_HTML401, 'UTF-8') 
                    : 1;
    $currentPage = str_replace("\0", "", $currentPage);
    echo $pageText . $currentPage . $pageOfText . $numPages;
    $naviPage = array();
    if ($numPages > 1) {
        $min = max($currentPage - 2, 2);
        $max = min($currentPage + 2, $numPages - 1);
        $naviPage[] = "1";
        if ($min > 2) {
            $naviPage[] = "...";
        }
        for ($i = $min; $i < $max + 1; $i++) {
            $naviPage[] = "$i";
        }
        if ($max < $numPages - 1) {
            $naviPage[] = "...";
        }
        $naviPage[] = "$numPages";
    } else {
        $naviPage = array("1");
    }
    if ($numPages > 1) {
        echo '&nbsp;&nbsp;';
        if ($currentPage > 1) {
            $prevPage = $currentPage - 1;
            echo '<a href="'. htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES | ENT_HTML401, 'UTF-8') .'?page='. $prevPage .'" class="direction">&#10096;&#10096;</a>';
        }
        foreach ($naviPage as $currentNaviPage) {
            if ($currentNaviPage == "...") {
                echo '<span class="paginate disabled">'. $currentNaviPage .'</span>';
            } elseif ($page == $currentNaviPage) {
                echo '<a class="current-paginate" href="'. htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES | ENT_HTML401, 'UTF-8') .'?page='. $currentNaviPage .'">'. $currentNaviPage .'</a>';
            } else {
                echo '<a class="paginate" href="'. htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES | ENT_HTML401, 'UTF-8') .'?page='. $currentNaviPage .'">'. $currentNaviPage .'</a>';
            }
        }
        if ($currentPage != $numPages) {
            $nextPage = $currentPage + 1;
            echo '<a href="'. htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES | ENT_HTML401, 'UTF-8') .'?page='. $nextPage .'" class="direction">&#10097;&#10097;</a>';
        }
    }
}


$files = array();
foreach ($src_files as $file) {
    $ext = strtolower(strrchr($file, '.'));
    if (in_array($ext, $extensions)) {
        array_push($files, $file);
    }
}
if (count($files) == 0) {
    echo 'No photos';
} else {
    $numPages = ceil(count($files)/$itemsPerPage);
    if (isset($_GET['page']) && is_numeric($_GET['page']) && $_GET['page'] > 0) {
        $currentPage = htmlspecialchars((int) $_GET['page'], ENT_QUOTES | ENT_HTML401, 'UTF-8');
        $currentPage = str_replace("\0", "", $currentPage);
        if ($currentPage > $numPages) {
            $currentPage = $numPages;
        }
    } else {
        $currentPage = 1;
    }
    $start = ($currentPage * $itemsPerPage) - $itemsPerPage;
    for ($i = $start; $i < $start + $itemsPerPage; $i++) {
        if (isset($files[$i]) && is_file($src_folder .'/foto/'. $files[$i])) {
            #array_multisort(array_map('filemtime', $files), SORT_NUMERIC, SORT_DESC, $files);
            echo '
<div class="thumb"><a href="'. $src_folder .'/foto/'. $files[$i] .'" data-fancybox data-caption="'. trim(pathinfo($files[$i], PATHINFO_FILENAME)) .'"><img src="'. $src_folder .'/thumbs/'. $files[$i] .'" width="'.$thumb_width.'" height="'.$thumb_height.'" alt="'.$photoText.'"></a><br><div class="srtgs" id="rt_'. $files[$i] .'"></div><br><div class="time">'. date("d-m-Y H:i:s", filemtime($src_folder .'/foto/'. $files[$i])) .'</div><div class="item"><a class="item" href="./comments.php?photo='. $files[$i] .'" target="_blank">'. $comments .'</a></div></div>';
        } else {
            if (isset($files[$i])) {
                echo $files[$i];
            }
        }
    }
    $counter = count($files);
    if ($counter <= 1) {
        $numImages = $imageText1;
    } else {
        $numImages = $imageText2;
    }
    print_pagination($pageText, $pageOfText, $numPages, $currentPage);
}
?>

from my dropbox all files for testing purpose:

test gallery 02.10.2022.zip

test gallery without folder foto 02.10.2022.zip


Solution

  • I solved by placing a function that supplies a full path for filemtime:

    function filetime_callback($a, $b) {
        global $src_folder;
        if (filemtime($src_folder.'/foto/'.$a) === filemtime($src_folder.'/foto/'.$b)) {
          return 0;
        }
        return filemtime($src_folder.'/foto/'.$a) > filemtime($src_folder.'/foto/'.$b) ? -1 : 1;
      }
    

    and finally I can sort my images by filemtime using a simply approach like this:

    usort($files, 'filetime_callback');
    

    The problem was that filemtime cannot find the images if are supplied in subfolder.

    Thanks.