当它被命名为'original.jpg'时,PHP无法在DIR中找到第一个文件

I have a simple function that returns a valid image path to display. It is passed the URL that's stored for a particular row in my DB. The basic functionality is:

  • If the URL has a trailing slash it's a directory; return the first file in that directory. If there aren't any, return the "default image"
  • If the URL is an image, see that it exists, otherwise use the first rule.

It works perfectly, except if the folder only contains a file named 'original.jpg', it displays the default image. If I add another file, it can use 'original.jpg'. If I rename it to 'original.jpeg' or 'ori.jpg' (or shorter) it works. This is the only filename I've encountered that behaves this way.

function displayFile($file){
    $imgPath = "./img/path/";

    // If folder was specified or file doesn't exists; use first available file
    if( substr($file, -1) == '/' || !file_exists($imgPath . $file) ){
        // Extract base path
        $file = strstr( $file, '/', true );
        $handle = opendir($imgPath . $file);
        $entry = readdir($handle);
        $firstFile = '';
        while (false !== ($entry = readdir($handle))) {
            if( substr($entry, 0, 1) != '.' ){
                $firstFile = $entry;
                break; // This break isn't the problem
            }
        }
        // No file found; use default
        if( $firstFile == '' ){ return $imgPath . "paw.png"; }
        // Found a file to use
        else{ return $imgPath . $file . '/' . $firstFile; }
    } else {
        // File name is valid; use it
        return $imgPath . $file;
    }
    closedir($imgPath);
}

You're calling readdir twice, essentially always skipping the first entry.

$entry = readdir($handle);

Remove that line and you should be good to go.

You do many unnecessary operations to retrieve a file.

Here is modified version of Your function, it should work as expected and it's short:

function displayFile($entry) {
    $imgPath = "./img/path/";
    $entry = implode('/', explode('../', $entry));
    $path = $imgPath.$entry;

    switch(true) {
        case is_file($path) : 
         return $path;
         break;

        case (is_dir($path) AND !is_file($path)) :
         $files = array_filter(glob($path."/*"), 'is_file');
         if(!empty($files)) {
             return $path . basename(array_values($files)[0]);
         }
         break;
    }

    return $imgPath . 'paw.png';
}

@knrdk was absolutely right, but to explain the seemingly erratic behaviour: The reason it works sometimes and not others is because of sorting. Narrowing function down to:

function displayFile($file){
  $imgPath = "./img/path/";
  $file = strstr( $file, '/', true );
    $handle = opendir($imgPath . $file);
    $entry = readdir($handle);
    while (false !== ($entry = readdir($handle))) {
        echo $entry . ' ';    
    }

closedir($imgPath);

To illustrate the behaviour

/* folder/[1.jpg] */
displayFile('folder'); // Output: . 1.jpg

/* folder/[original.jpg] */
displayFile('folder'); // Output: . ..

/* folder/[original.jpeg] */
displayFile('folder'); // Output: original.jpg .
// Not entirely sure why that's different, but there it is

/* folder/[1.jpg, original.jpg] */
displayFile('folder'); // Output: original.jpg .. .