is_executable
Tells whether a path exists and is executable by the current process user.
is_executable(string $filename): bool- Added in PHP 4
Parameters
| Parameter | Type | Description |
|---|---|---|
$filename | string | Path to the file to check. Relative paths are resolved against the current working directory and symbolic links are followed. |
Return value
booltrue if the path exists and is executable, false otherwise.
Errors
Throws a ValueError if the path contains a null byte; emits E_WARNING when the path cannot be checked, for example under an open_basedir restriction.
Changelog
- PHP 7.4.0On Windows a file is now considered executable only if GetBinaryType() reports a real executable (plus .bat and .cmd for compatibility); previously any non-empty .exe or .com file qualified.
is_executable reports whether the operating system would let the current process run the named file. On POSIX systems that means the execute bit is set for the user PHP runs as; on Windows it means the file is a real binary as reported by GetBinaryType(), plus .bat and .cmd for backwards compatibility.
When to reach for it
Use it before invoking an external tool so you can produce a clear "ffmpeg is present but not executable" message instead of a cryptic exit code. Use it in installers and health checks that verify a bundled script or hook is runnable. And use it in a deploy script to confirm that permissions survived an unzip, which strips the execute bit on many platforms.
What trips people up
It answers for PHP's user, not for you. Under php-fpm or Apache that is www-data or similar, so a file you can run from your shell may report false from the web.
Directories are executable too. On POSIX the execute bit on a directory means "may be traversed", so is_executable('/var/www') is normally true. Combine it with is_file when you specifically mean a program.
Results are cached in the stat cache, so a permission change made during the same request needs clearstatcache() before it shows up.
Finally, on Windows PATHEXT is irrelevant here — the extension alone does not make a file executable.
Example
When to use it
- Verify a bundled shell hook is still runnable after a deploy that unzipped the release.
- Check that an external binary such as ffmpeg or wkhtmltopdf can actually be run before shelling out to it.
- Confirm in a health-check endpoint that a cron script has kept its execute bit.
Frequently asked questions
Why does is_executable return true for a directory?
On POSIX systems the execute bit on a directory grants permission to traverse it, so directories you can enter are reported as executable. Add an is_file() check when you mean an actual program.
Why does is_executable return false for a file I can run in my terminal?
The check uses the user PHP runs as, which under php-fpm or Apache is typically www-data rather than your login. Verify the permissions for that user, and call clearstatcache() if you changed them during the same request.
Does is_executable work on Windows?
Yes, but it asks GetBinaryType() whether the file is a genuine executable image, with .bat and .cmd accepted for compatibility. Since PHP 7.4 a mere .exe or .com extension is no longer enough, and PATHEXT is not consulted.
More examples
Distinguishing a program from a directory
The directory reports exec=true because its execute bit means "can be entered", while the script reports exec=false because it was created without the bit. This is why a runnable-program check must be is_file($p) && is_executable($p).
<?php
mkdir("bin_demo");
file_put_contents("bin_demo/tool", "#!/bin/sh\n");
foreach (["bin_demo", "bin_demo/tool"] as $path) {
printf("%-14s exec=%s file=%s\n",
$path,
var_export(is_executable($path), true),
var_export(is_file($path), true));
}
unlink("bin_demo/tool");
rmdir("bin_demo");A reusable preflight check
Checking existence, type and permission separately turns one useless false into three distinct messages: "present but not executable", "missing" and "not a regular file". That difference is what makes a deployment failure debuggable.
<?php
function canRun(string $path): string {
if (!file_exists($path)) { return "missing"; }
if (!is_file($path)) { return "not a regular file"; }
if (!is_executable($path)) { return "present but not executable"; }
return "ok";
}
file_put_contents("deploy.sh", "#!/bin/sh\n");
echo canRun("deploy.sh"), "\n";
echo canRun("nope.sh"), "\n";
echo canRun("."), "\n";
unlink("deploy.sh");Reading the permission bits yourself
fileperms() exposes the raw mode so you can test individual bits: 0100 is owner execute, 0010 group, 0001 other. is_executable() collapses all of that into the single answer that matters — whether the running user in particular may execute it.
<?php
file_put_contents("probe.sh", "#!/bin/sh\n");
$perms = fileperms("probe.sh");
printf("octal: %04o\n", $perms & 0777);
printf("owner +x: %s\n", var_export((bool) ($perms & 0100), true));
printf("is_executable: %s\n", var_export(is_executable("probe.sh"), true));
unlink("probe.sh");
Discussion