is_readable

Checks whether a file or directory exists and can be opened for reading by the current process.

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

Parameters

ParameterTypeDescription
$filenamestringPath to the file or directory to test. Stream wrapper URLs are supported if the wrapper implements a stat handler.

Return value

booltrue if the path exists and is readable by the running process, false otherwise.

Errors

Does not throw. It returns false rather than warning when the path is missing, but an open_basedir violation emits an E_WARNING.

is_readable() asks the operating system whether the process running PHP — typically the web server user such as www-data, not your login account — could open the given path for reading. It answers true for directories as well as regular files, and false when the path does not exist, so it also works as an existence check.

When to reach for it

Reach for it when you want to skip or report a file gracefully instead of letting a warning leak into the output: walking a directory of config fragments where some may be locked down, or turning a missing template into a clear message like "templates/mail.html is not readable by the web server". It is also useful in health-check scripts that verify deployment permissions before the application starts serving traffic.

What trips people up

The check is advisory, not a lock. Between is_readable() returning true and your fopen() call, the file can be deleted or its permissions changed — a TOCTOU race. In code that is about to read the file anyway, calling fopen() (or file_get_contents()) with @ and testing the return value is both faster and correct. Results also come from PHP's stat cache; if something else in the same request changed permissions, call clearstatcache() first.

Example

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

When to use it

  • Skip config fragments in a conf.d directory that the web server user cannot open, instead of emitting warnings.
  • Produce a readable deployment error when an .env or credentials file was uploaded with the wrong owner.
  • Validate a user-supplied template path (after realpath() containment) before including it.

Frequently asked questions

What is the difference between is_readable and file_exists?

file_exists() only reports that the path is there; is_readable() additionally checks that the current process has permission to open it. A file owned by root with mode 0600 makes file_exists() return true and is_readable() return false.

Why does is_readable return false for a file I can clearly read?

PHP runs as the web server user, not as you, so the relevant permissions are the server's. open_basedir restrictions, SELinux or AppArmor policies, and a missing execute bit on a parent directory will all produce false even when the file itself is world-readable.

Does is_readable work on directories?

Yes, and it returns true for any directory the process can list. If you want to reject directories, test is_file() as well.

More examples

Prefer opening over checking

The output is the file's first line. When you are going to read the file immediately, opening it and testing the handle avoids the gap between the permission check and the read, and costs one syscall instead of two.

Example · php
<?php
file_put_contents('config.json', '{"debug":true}');

$fh = @fopen('config.json', 'r');
if ($fh === false) {
    echo "cannot read config.json\n";
} else {
    echo fgets($fh);
    fclose($fh);
}

unlink('config.json');

Report which paths a script can actually read

The current directory and the running script report as readable, the missing file does not. This is the shape of a deployment health check: list the paths the app needs and print a verdict for each.

Example · php
<?php
$paths = ['.', __FILE__, 'no-such-file.txt', 'php://memory'];

foreach ($paths as $p) {
    printf("%-20s %s\n", $p, is_readable($p) ? 'readable' : 'NOT readable');
}

Require a readable regular file

The first call prints the log line; the second throws because '.' is a directory. Pairing is_file() with is_readable() is what most callers actually mean.

Example · php
<?php
function requireReadableFile(string $path): string {
    if (!is_file($path) || !is_readable($path)) {
        throw new RuntimeException("Not a readable file: $path");
    }
    return file_get_contents($path);
}

file_put_contents('app.log', "started\n");
echo requireReadableFile('app.log');
try { requireReadableFile('.'); } catch (RuntimeException $e) { echo $e->getMessage(), "\n"; }
unlink('app.log');

Discussion

  • Be the first to comment on this lesson.