fileperms

Returns a file's permission bits and type as a numeric mode integer.

Signature
fileperms(string $filename): int|false
  • Added in PHP 4.0.0

Parameters

ParameterTypeDescription
$filenamestringPath to the file.

Return value

int|falseThe file's mode as an integer — permission bits plus file-type bits — or false on failure.

Errors

Emits an E_WARNING and returns false if the stat call fails, for example when the file does not exist.

fileperms returns the raw st_mode value from the operating system's stat() call. That single integer carries two different things: the low 12 bits are the permission bits you would pass to chmod, and the high bits encode the file type.

When to reach for it

  • Auditing that config files are not world-readable before an app boots.
  • Reporting the current mode in an installer or diagnostics page.
  • Comparing a deployed file's mode against an expected value.

What trips people up

The number does not look like 0644 because it is decimal and includes type bits — a regular 0644 file returns 33188. To get the familiar four-digit octal, use substr(sprintf('%o', fileperms($f)), -4). Dropping the substr leaves the type prefix in place, so you see 100644.

To test one permission, mask it: fileperms($f) & 0200 is non-zero when the owner can write. To test the type, mask with 0170000 and compare — 0100000 is a regular file, 0040000 a directory.

Windows does not have a Unix permission model; the values it returns are an approximation and should not drive security decisions. Results are also stat-cached, so call clearstatcache() after a chmod.

If you only want to know whether your process can read or write the path, is_readable() and is_writable() answer that directly and account for the effective user.

Example

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

When to use it

  • Warn during startup if a secrets file is readable by group or other.
  • Show the current octal mode of upload directories in a health-check endpoint.
  • Verify a deploy script left executable bits on the right scripts.

Frequently asked questions

Why does fileperms return 33188 instead of 644?

33188 is the full `st_mode` in decimal: the permission bits plus the regular-file type marker. Convert it with `substr(sprintf('%o', fileperms($f)), -4)` to get `0644`.

How do I check if a file is writable with fileperms?

Mask the owner-write bit with `fileperms($f) & 0200`, but for a real answer use `is_writable($f)` — it accounts for which user the PHP process is running as, which the raw bits do not.

Does fileperms work on Windows?

It returns a value, but Windows uses ACLs rather than Unix permission bits, so the result is a rough approximation and should not be used for security checks.

More examples

Why the number looks wrong

The full octal starts with `100`, the regular-file type marker, followed by the permission digits. Trimming to the last four characters is what turns the stat value into the `0644`-style mode people expect.

Example · php
<?php
file_put_contents('modes.txt', 'x');
clearstatcache();
$p = fileperms('modes.txt');

echo "decimal:        $p\n";
echo "full octal:     ", sprintf('%o', $p), "\n";
echo "just the mode:  ", substr(sprintf('%o', $p), -4), "\n";
echo "just the type:  ", sprintf('%o', $p & 0170000), "\n";

unlink('modes.txt');

Flagging a world-readable secrets file

The bitmasks 0040 and 0004 isolate the group-read and other-read bits. On a typical umask the file is created 0644, so both checks report that others can read it and the warning fires.

Example · php
<?php
file_put_contents('secrets.env', "API_KEY=abc123\n");
clearstatcache();

$perms = fileperms('secrets.env');
$group = ($perms & 0040) !== 0;
$other = ($perms & 0004) !== 0;

echo "mode: ", substr(sprintf('%o', $perms), -4), "\n";
echo "group readable: ", var_export($group, true), "\n";
echo "other readable: ", var_export($other, true), "\n";
echo ($group || $other) ? "WARNING: tighten this file\n" : "looks fine\n";

unlink('secrets.env');

Decoding the file type from the mode

Masking with 0170000 strips the permission bits and leaves only the type field, printing `directory`, `regular file`, `directory`. For readable type names, `filetype()` does the same job without the bit twiddling.

Example · php
<?php
mkdir('perm-dir');
file_put_contents('perm-file.txt', 'x');
clearstatcache();

foreach (['perm-dir', 'perm-file.txt', '.'] as $path) {
    $type = fileperms($path) & 0170000;
    $name = match ($type) {
        0040000 => 'directory',
        0100000 => 'regular file',
        default => 'other',
    };
    echo str_pad($path, 16), $name, "\n";
}

unlink('perm-file.txt');
rmdir('perm-dir');

Discussion

  • Be the first to comment on this lesson.