file_exists() returns false, but the file DOES exist

Viewed 75967

I'm having a very weird issue with file_exists(). I'm using this function to check if 2 different files in the same folders do exist. I've double-checked, they BOTH do exist.

echo $relative . $url['path'] . '/' . $path['filename'] . '.jpg';
Result: ../../images/example/001-001.jpg

echo $relative . $url['path'] . '/' . $path['filename'] . '.' . $path['extension'];
Result: ../../images/example/001-001.PNG

Now let's use file_exists() on these:

var_dump(file_exists($relative . $url['path'] . '/' . $path['filename'] . '.jpg'));
Result: bool(false)

var_dump(file_exists($relative . $url['path'] . '/' . $path['filename'] . '.' . $path['extension']));
Result: bool(true)

I don't get it - both of these files do exist. I'm running Windows, so it's not related to a case-sensitive issue. Safe Mode is off.

What might be worth mentioning though is that the .png one is uploaded by a user via FTP, while the .jpg one is created using a script. But as far as I know, that shouldn't make a difference.

Any tips?

Thanks

15 Answers

I have a new reason this happens - I am using PHP inside a Docker container with a mounted volume for the codebase which resides on my local host machine.

I was getting file_exists == FALSE (inside Composer autoload), but if I copied the filepath into terminal - it did exist! I tried the clearstatche(), checked safe-mode was OFF.

Then I remembered the Docker volume mapping: the absolute path on my local host machine certainly doesn't exist inside the Docker container - which is PHP's perspective on the world.

(I keep forgetting I'm using Docker, because I've made shell functions which wrap the docker run commands so nicely...)

In my case, the problem was a misconception of how file_exists() behaves with symbolic links and .. ("dotdot" or double period) parent dir references. In that regard, it differs from functions like require, include or even mkdir().

Given this directory structure:

/home/me/work/example/
  www/
/var/www/example.local/
  tmp/
  public_html -> /home/me/work/example/www/

file_exists('/var/www/example.local/public_html/../tmp/'); would return FALSE even though the subdir exists as we see, because the function traversed up into /home/me/work/example/ which does not have that subdir.


For this reason, I have created this function:

/**
 * Resolve any ".." ("dotdots" or double periods) in a given path.
 *
 * This is especially useful for avoiding the confusing behavior `file_exists()`
 * shows with symbolic links.
 *
 * @param string $path
 *
 * @return string
 */
function resolve_dotdots( string $path ) {

    if (empty($path)) {
        return $path;
    }

    $source = array_reverse(explode(DIRECTORY_SEPARATOR, $path));
    $balance = 0;
    $parts = array();

    // going backwards through the path, keep track of the dotdots and "work
    // them off" by skipping a part. Only take over the respective part if the
    // balance is at zero.
    foreach ($source as $part) {
        if ($part === '..') {
            $balance++;

        } else if ($balance > 0) {
            $balance--;

        } else {
            array_push($parts, $part);
        }
    }

    // special case: path begins with too many dotdots, references "outside
    // knowledge".
    if ($balance > 0) {
        for ($i = 0; $i < $balance; $i++) {
            array_push($parts, '..');
        }
    }

    $parts = array_reverse($parts);
    return implode(DIRECTORY_SEPARATOR, $parts);
}

I just encountered this same problem and I solved it in a mysterious way. After inserting a a filepath I copied from Windows File explorer. file_exists() keeps returning false continuously, but if I copy same path from VSCode editor it works perfectly.

After dumping variables with var_dump($path); I noticed something mysterious. For path I copied from file explorer it shows length 94. For path I copied from VSCode Editor it shows length 88.

Both path look same length on my code Editor.

My suggestion: if string contain hidden characters, it may fail and not work.

Related