file_exists

Checks whether a file or directory exists at the given path.

Signature
file_exists(string $filename): bool
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$filenamestringPath to the file or directory. On Windows, network shares can be checked with //computername/share/filename.

Return value

booltrue if the file or directory specified by filename exists, false otherwise.

Errors

Does not throw. Returns false and may emit E_WARNING when the path cannot be checked, for example because of open_basedir restrictions.

file_exists() answers one narrow question: does something live at this path? It returns true for directories as well as files, so it is not the check to use when you mean "is there a readable file here" — that is is_file(), optionally with is_readable().

What it does not tell you

Existence is not permission. A file you cannot open still exists. And a path can appear not to exist simply because your process cannot traverse a parent directory — the answer is false either way, which makes debugging permission problems confusing.

It follows symlinks, so a link pointing at a deleted target returns false. Use is_link() or lstat() when you care about the link itself.

The race condition

Checking and then acting is two operations with a gap between them. Between your file_exists() and your fopen(), another process can create or delete the file. For reads, just attempt the operation and handle the failure — @file_get_contents() returning false is one syscall and cannot be raced. Reserve file_exists() for cases where you genuinely need the answer as information, such as deciding whether to build a cache entry.

Caching

Results are stored in PHP's stat cache for the rest of the request. A miss is never cached, but a hit is — including after the file is deleted.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Decide whether a generated thumbnail already exists before rebuilding it
  • Fall back to a default template when a per-tenant override file is absent
  • Verify that an optional .env or local config file is present at boot
  • Report a clear error when a configured upload directory has not been created

Frequently asked questions

Does file_exists work for directories?

Yes — it returns true for both files and directories. Use is_file() when you specifically need a regular file, or is_dir() for a directory.

Why does file_exists return false for a file I can see on disk?

Usually a permissions problem on a parent directory, an open_basedir restriction, or a relative path resolved against a different working directory than you expect. A broken symlink also returns false, because the function follows links.

Should I call file_exists before fopen or file_get_contents?

Generally no. The file can change between the two calls, and the read already reports failure, so just attempt the read and handle a false return. Use file_exists() when the existence answer itself is what you need.

More examples

Telling files and directories apart

The directory and the file both report exists=1, which is why file_exists() alone is a poor guard before fopen() — passing a directory path to fopen() fails. is_file() is the check that distinguishes them, and the missing path is 0 across the board.

Example · php
<?php
mkdir("uploads");
file_put_contents("uploads/avatar.png", "PNG");

foreach (["uploads", "uploads/avatar.png", "uploads/missing.png"] as $path) {
    printf("%-22s exists=%d file=%d dir=%d\n",
        $path, file_exists($path), is_file($path), is_dir($path));
}

unlink("uploads/avatar.png");
rmdir("uploads");

Skip the check and handle the failure

The false return from file_get_contents() carries the same information as file_exists() would have, in one syscall instead of two, and nothing can change on disk in between. Check-then-open is only worth the extra call when you need the existence answer for its own sake.

Example · php
<?php
$path = "maybe-config.json";

var_dump(file_exists($path));
$data = @file_get_contents($path);   // one operation, no race
var_dump($data);

file_put_contents($path, '{"debug":true}');
$data = @file_get_contents($path);
var_dump($data);

$config = json_decode($data === false ? "{}" : $data, true);
print_r($config);

unlink($path);

A cache-or-build guard

The first pass builds the file and the second finds it, which is the legitimate use of file_exists(): the answer itself drives a decision rather than merely guarding a read. clearstatcache() is called each iteration because the loop both checks and changes the same path within one request.

Example · php
<?php
$cache = "page-42.html";

for ($i = 1; $i <= 2; $i++) {
    clearstatcache();
    if (file_exists($cache)) {
        echo "run $i: cache hit\n";
    } else {
        echo "run $i: building\n";
        file_put_contents($cache, "<h1>page 42</h1>");
    }
}

echo file_get_contents($cache), "\n";
unlink($cache);

Discussion

  • Be the first to comment on this lesson.