PHP streams — stream wrappers, filters, context
Advanced5 min read·php-13-004
Concept
PHP provides functions to inspect file metadata — existence, size, modification time, type, and permissions. These are important for validation, caching strategies, and conditional file operations.
Existence and type checks:
file_exists(string $path): Returns true if path exists (file or directory).is_file(string $path): True only for regular files (not directories or symlinks to directories).is_dir(string $path): True for directories.is_link(string $path): True for symbolic links.is_readable(string $path)/is_writable()/is_executable(): Check permissions for the current process user.
File metadata:
filesize(string $path): File size in bytes. Returnsint(or false). Note: on 32-bit PHP, files > 2GB need special handling.filemtime(string $path): Last modification timestamp (Unix timestamp). Useful for cache invalidation.fileatime(string $path): Last access time. Often disabled on modern filesystems for performance.filectime(string $path): Inode change time (not creation time on POSIX).stat(string $path): Returns an array of detailed file info: size, inode, owner UID/GID, permissions, atime, mtime, ctime, block count.lstat(string $path): Likestat()but doesn't follow symlinks (returns symlink's own info).
clearstatcache(): PHP caches stat() results for performance. If you modify a file and then call filesize() or filemtime() on it, you might get stale values. Call clearstatcache() to force a fresh stat. Or pass clearstatcache(true, $path) to clear only a specific file.
Code Example
php
<?php
declare(strict_types=1);
// Check before acting
$path = '/var/www/uploads/photo.jpg';
if (!file_exists($path)) {
throw new \RuntimeException("File not found: $path");
}
if (!is_readable($path)) {
throw new \RuntimeException("File not readable: $path");
}
// File metadata
$size = filesize($path); // bytes: 204800
$modified = filemtime($path); // Unix timestamp
$type = mime_content_type($path); // "image/jpeg"
echo "Size: " . number_format($size / 1024, 1) . " KB\n";
echo "Modified: " . date('Y-m-d H:i:s', $modified) . "\n";
echo "Type: $type\n";
// Cache invalidation based on file modification time
function getCachedOrFresh(string $file, string $cacheKey, callable $generate): mixed
{
$lastModified = filemtime($file);
$cacheVersion = cache()->get("$cacheKey:version");
if ($cacheVersion === $lastModified) {
return cache()->get($cacheKey);
}
$data = $generate();
cache()->put($cacheKey, $data);
cache()->put("$cacheKey:version", $lastModified);
return $data;
}
// Full stat array
$info = stat($path);
// [
// 'dev' => device number,
// 'ino' => inode number,
// 'mode' => permissions (octal),
// 'nlink' => number of hard links,
// 'uid' => owner UID,
// 'gid' => owner GID,
// 'size' => size in bytes,
// 'atime' => last access timestamp,
// 'mtime' => last modification timestamp,
// 'ctime' => inode change timestamp,
// 'blksize' => filesystem block size,
// 'blocks' => number of 512-byte blocks,
// ]
echo "Owner UID: " . $info['uid'] . "\n";
echo "Permissions: " . decoct($info['mode'] & 0777) . "\n"; // e.g., "644"
// clearstatcache after modifying file
file_put_contents($path, "new content");
clearstatcache(true, $path);
echo filesize($path); // now returns updated size
// SplFileInfo — OOP stat wrapper
$info = new \SplFileInfo($path);
echo $info->getSize() . "\n";
echo $info->getMTime() . "\n";
echo $info->isReadable() ? "readable\n" : "not readable\n";
echo $info->getExtension() . "\n"; // "jpg"