こんにちは!今回は、PHPの標準関数であるstat()について詳しく解説していきます。ファイルやディレクトリの詳細情報を取得できる、ファイルシステム操作に欠かせない関数です!
stat関数とは?
stat()関数は、ファイルやディレクトリの詳細情報を取得する関数です。
ファイルサイズ、パーミッション、所有者、タイムスタンプ、inode番号など、ファイルに関する13種類の情報を配列で返します。ファイル管理、監視、バックアップシステムなどで重要な役割を果たします!
基本的な構文
stat(string $filename): array|false
- $filename: 情報を取得するファイルまたはディレクトリのパス
- 戻り値: ファイル情報の配列、失敗時は
false
戻り値の配列構造
$info = stat('file.txt');
/*
配列のインデックス:
[0] または ['dev'] => デバイス番号
[1] または ['ino'] => inode番号
[2] または ['mode'] => inode保護モード
[3] または ['nlink'] => リンク数
[4] または ['uid'] => 所有者のユーザーID
[5] または ['gid'] => 所有者のグループID
[6] または ['rdev'] => デバイスタイプ(inode デバイスの場合)
[7] または ['size'] => バイト単位のサイズ
[8] または ['atime'] => 最終アクセス時刻(Unixタイムスタンプ)
[9] または ['mtime'] => 最終更新時刻(Unixタイムスタンプ)
[10] または ['ctime'] => 最終変更時刻(Unixタイムスタンプ)
[11] または ['blksize'] => ファイルシステムI/Oのブロックサイズ
[12] または ['blocks'] => 割り当てられた512バイトブロックの数
*/
基本的な使用例
シンプルな情報取得
$file = 'test.txt';
$info = stat($file);
if ($info === false) {
echo "ファイル情報の取得に失敗しました\n";
} else {
echo "ファイルサイズ: {$info['size']} bytes\n";
echo "最終更新: " . date('Y-m-d H:i:s', $info['mtime']) . "\n";
echo "最終アクセス: " . date('Y-m-d H:i:s', $info['atime']) . "\n";
}
数値インデックスと文字列キー
$info = stat('file.txt');
// 数値インデックスでアクセス
echo "サイズ(数値): {$info[7]}\n";
// 文字列キーでアクセス(推奨)
echo "サイズ(文字列): {$info['size']}\n";
// 両方とも同じ値
var_dump($info[7] === $info['size']); // true
パーミッションの取得
$info = stat('file.txt');
// モード(パーミッション)
$mode = $info['mode'];
// 8進数で表示
echo "パーミッション(8進数): " . decoct($mode & 0777) . "\n";
// ファイルタイプとパーミッションを分離
$perms = $mode & 0777;
echo "パーミッション: " . sprintf('%o', $perms) . "\n";
タイムスタンプの取得
$info = stat('file.txt');
// アクセス時刻
echo "最終アクセス: " . date('Y-m-d H:i:s', $info['atime']) . "\n";
// 更新時刻(内容の変更)
echo "最終更新: " . date('Y-m-d H:i:s', $info['mtime']) . "\n";
// 変更時刻(メタデータの変更)
echo "最終変更: " . date('Y-m-d H:i:s', $info['ctime']) . "\n";
// 現在時刻との差分
$now = time();
$age = $now - $info['mtime'];
echo "最終更新からの経過時間: {$age}秒\n";
ファイルタイプの判定
$info = stat('file.txt');
$mode = $info['mode'];
// ファイルタイプの判定
if (($mode & 0170000) === 0100000) {
echo "通常のファイル\n";
} elseif (($mode & 0170000) === 0040000) {
echo "ディレクトリ\n";
} elseif (($mode & 0170000) === 0120000) {
echo "シンボリックリンク\n";
}
// または関数を使用
if (is_file('file.txt')) {
echo "通常のファイル\n";
} elseif (is_dir('file.txt')) {
echo "ディレクトリ\n";
} elseif (is_link('file.txt')) {
echo "シンボリックリンク\n";
}
実践的な使用例
例1: ファイル情報解析ツール
class FileInfoAnalyzer {
/**
* ファイルの詳細情報を取得
*/
public static function getInfo($file) {
$stat = stat($file);
if ($stat === false) {
return null;
}
return [
'path' => $file,
'name' => basename($file),
'size' => $stat['size'],
'size_formatted' => self::formatBytes($stat['size']),
'permissions' => self::formatPermissions($stat['mode']),
'permissions_octal' => sprintf('%o', $stat['mode'] & 0777),
'owner_uid' => $stat['uid'],
'owner_gid' => $stat['gid'],
'type' => self::getFileType($stat['mode']),
'inode' => $stat['ino'],
'links' => $stat['nlink'],
'accessed' => $stat['atime'],
'modified' => $stat['mtime'],
'changed' => $stat['ctime'],
'accessed_formatted' => date('Y-m-d H:i:s', $stat['atime']),
'modified_formatted' => date('Y-m-d H:i:s', $stat['mtime']),
'changed_formatted' => date('Y-m-d H:i:s', $stat['ctime'])
];
}
/**
* バイトを人間が読みやすい形式に変換
*/
private static function formatBytes($bytes) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
/**
* パーミッションを文字列形式に変換
*/
private static function formatPermissions($mode) {
$perms = '';
// ファイルタイプ
if (($mode & 0170000) === 0040000) $perms .= 'd';
elseif (($mode & 0170000) === 0120000) $perms .= 'l';
else $perms .= '-';
// 所有者
$perms .= ($mode & 0400) ? 'r' : '-';
$perms .= ($mode & 0200) ? 'w' : '-';
$perms .= ($mode & 0100) ? 'x' : '-';
// グループ
$perms .= ($mode & 040) ? 'r' : '-';
$perms .= ($mode & 020) ? 'w' : '-';
$perms .= ($mode & 010) ? 'x' : '-';
// その他
$perms .= ($mode & 04) ? 'r' : '-';
$perms .= ($mode & 02) ? 'w' : '-';
$perms .= ($mode & 01) ? 'x' : '-';
return $perms;
}
/**
* ファイルタイプを取得
*/
private static function getFileType($mode) {
$type = $mode & 0170000;
switch ($type) {
case 0040000: return 'directory';
case 0100000: return 'file';
case 0120000: return 'symlink';
case 0060000: return 'block_device';
case 0020000: return 'character_device';
case 0010000: return 'fifo';
case 0140000: return 'socket';
default: return 'unknown';
}
}
/**
* 複数ファイルの情報を取得
*/
public static function analyzeMultiple($files) {
$results = [];
foreach ($files as $file) {
$info = self::getInfo($file);
if ($info !== null) {
$results[] = $info;
}
}
return $results;
}
/**
* ファイル情報を表形式で表示
*/
public static function displayInfo($file) {
$info = self::getInfo($file);
if ($info === null) {
echo "ファイル情報の取得に失敗しました\n";
return;
}
echo "=== ファイル情報: {$info['name']} ===\n";
echo "パス: {$info['path']}\n";
echo "タイプ: {$info['type']}\n";
echo "サイズ: {$info['size_formatted']} ({$info['size']} bytes)\n";
echo "パーミッション: {$info['permissions']} ({$info['permissions_octal']})\n";
echo "所有者: UID {$info['owner_uid']}, GID {$info['owner_gid']}\n";
echo "inode: {$info['inode']}\n";
echo "リンク数: {$info['links']}\n";
echo "最終アクセス: {$info['accessed_formatted']}\n";
echo "最終更新: {$info['modified_formatted']}\n";
echo "最終変更: {$info['changed_formatted']}\n";
}
}
// 使用例
echo "=== ファイル情報解析 ===\n";
$file = '/tmp/test.txt';
// 詳細情報を表示
FileInfoAnalyzer::displayInfo($file);
// 情報を配列で取得
$info = FileInfoAnalyzer::getInfo($file);
if ($info) {
echo "\nサイズ: {$info['size_formatted']}\n";
echo "パーミッション: {$info['permissions']}\n";
}
例2: ファイル監視システム
class FileMonitor {
private $watchList = [];
/**
* 監視対象にファイルを追加
*/
public function addFile($file) {
if (!file_exists($file)) {
return false;
}
$stat = stat($file);
$this->watchList[$file] = [
'size' => $stat['size'],
'mtime' => $stat['mtime'],
'ctime' => $stat['ctime'],
'mode' => $stat['mode'],
'last_check' => time()
];
return true;
}
/**
* 変更をチェック
*/
public function checkChanges() {
$changes = [];
foreach ($this->watchList as $file => $oldInfo) {
if (!file_exists($file)) {
$changes[$file] = ['type' => 'deleted'];
continue;
}
$stat = stat($file);
$fileChanges = [];
// サイズの変更
if ($stat['size'] !== $oldInfo['size']) {
$fileChanges['size'] = [
'old' => $oldInfo['size'],
'new' => $stat['size']
];
}
// 内容の変更
if ($stat['mtime'] !== $oldInfo['mtime']) {
$fileChanges['modified'] = [
'old' => date('Y-m-d H:i:s', $oldInfo['mtime']),
'new' => date('Y-m-d H:i:s', $stat['mtime'])
];
}
// メタデータの変更
if ($stat['ctime'] !== $oldInfo['ctime']) {
$fileChanges['metadata'] = [
'old' => date('Y-m-d H:i:s', $oldInfo['ctime']),
'new' => date('Y-m-d H:i:s', $stat['ctime'])
];
}
// パーミッションの変更
if ($stat['mode'] !== $oldInfo['mode']) {
$fileChanges['permissions'] = [
'old' => sprintf('%o', $oldInfo['mode'] & 0777),
'new' => sprintf('%o', $stat['mode'] & 0777)
];
}
if (!empty($fileChanges)) {
$changes[$file] = $fileChanges;
// 情報を更新
$this->watchList[$file] = [
'size' => $stat['size'],
'mtime' => $stat['mtime'],
'ctime' => $stat['ctime'],
'mode' => $stat['mode'],
'last_check' => time()
];
}
}
return $changes;
}
/**
* 監視中のファイル一覧を取得
*/
public function getWatchList() {
return array_keys($this->watchList);
}
/**
* 監視からファイルを削除
*/
public function removeFile($file) {
unset($this->watchList[$file]);
}
}
// 使用例
echo "=== ファイル監視システム ===\n";
$monitor = new FileMonitor();
// 監視対象を追加
$monitor->addFile('/tmp/test.txt');
$monitor->addFile('/tmp/config.php');
echo "監視中のファイル:\n";
foreach ($monitor->getWatchList() as $file) {
echo " - {$file}\n";
}
// 少し待機してから変更をチェック
sleep(1);
// ファイルを変更(テスト用)
// file_put_contents('/tmp/test.txt', 'new content');
// 変更をチェック
$changes = $monitor->checkChanges();
if (empty($changes)) {
echo "\n変更はありません\n";
} else {
echo "\n検出された変更:\n";
foreach ($changes as $file => $fileChanges) {
echo "\n{$file}:\n";
foreach ($fileChanges as $type => $change) {
if ($type === 'deleted') {
echo " - ファイルが削除されました\n";
} else {
echo " - {$type}: {$change['old']} → {$change['new']}\n";
}
}
}
}
例3: ファイル比較ツール
class FileComparator {
/**
* 2つのファイルの統計情報を比較
*/
public static function compare($file1, $file2) {
$stat1 = stat($file1);
$stat2 = stat($file2);
if ($stat1 === false || $stat2 === false) {
return null;
}
return [
'same_size' => $stat1['size'] === $stat2['size'],
'same_mtime' => $stat1['mtime'] === $stat2['mtime'],
'same_mode' => ($stat1['mode'] & 0777) === ($stat2['mode'] & 0777),
'same_owner' => $stat1['uid'] === $stat2['uid'],
'same_group' => $stat1['gid'] === $stat2['gid'],
'size_diff' => $stat1['size'] - $stat2['size'],
'time_diff' => $stat1['mtime'] - $stat2['mtime'],
'file1' => [
'size' => $stat1['size'],
'mtime' => $stat1['mtime'],
'mode' => sprintf('%o', $stat1['mode'] & 0777)
],
'file2' => [
'size' => $stat2['size'],
'mtime' => $stat2['mtime'],
'mode' => sprintf('%o', $stat2['mode'] & 0777)
]
];
}
/**
* ファイルが同一かチェック
*/
public static function areIdentical($file1, $file2) {
$comparison = self::compare($file1, $file2);
if ($comparison === null) {
return false;
}
// サイズと更新時刻が同じならば同一の可能性が高い
if ($comparison['same_size'] && $comparison['same_mtime']) {
// さらにハッシュで確認
return md5_file($file1) === md5_file($file2);
}
return false;
}
/**
* どちらのファイルが新しいか判定
*/
public static function whichIsNewer($file1, $file2) {
$stat1 = stat($file1);
$stat2 = stat($file2);
if ($stat1 === false || $stat2 === false) {
return null;
}
if ($stat1['mtime'] > $stat2['mtime']) {
return $file1;
} elseif ($stat2['mtime'] > $stat1['mtime']) {
return $file2;
} else {
return null; // 同じ更新時刻
}
}
/**
* ファイルの年齢(最終更新からの経過時間)を比較
*/
public static function compareAge($file1, $file2) {
$stat1 = stat($file1);
$stat2 = stat($file2);
if ($stat1 === false || $stat2 === false) {
return null;
}
$now = time();
return [
'file1_age' => $now - $stat1['mtime'],
'file2_age' => $now - $stat2['mtime'],
'age_diff' => abs($stat1['mtime'] - $stat2['mtime'])
];
}
}
// 使用例
echo "=== ファイル比較 ===\n";
$file1 = '/tmp/file1.txt';
$file2 = '/tmp/file2.txt';
// 詳細比較
$comparison = FileComparator::compare($file1, $file2);
if ($comparison) {
echo "サイズが同じ: " . ($comparison['same_size'] ? 'Yes' : 'No') . "\n";
echo "更新時刻が同じ: " . ($comparison['same_mtime'] ? 'Yes' : 'No') . "\n";
echo "パーミッションが同じ: " . ($comparison['same_mode'] ? 'Yes' : 'No') . "\n";
echo "サイズ差: {$comparison['size_diff']} bytes\n";
}
// 同一性チェック
$identical = FileComparator::areIdentical($file1, $file2);
echo "\nファイルが同一: " . ($identical ? 'Yes' : 'No') . "\n";
// どちらが新しいか
$newer = FileComparator::whichIsNewer($file1, $file2);
if ($newer) {
echo "新しいファイル: {$newer}\n";
} else {
echo "両ファイルの更新時刻は同じ\n";
}
例4: パーミッションチェッカー
class PermissionChecker {
/**
* ファイルのパーミッションを取得
*/
public static function getPermissions($file) {
$stat = stat($file);
if ($stat === false) {
return null;
}
$mode = $stat['mode'];
$perms = $mode & 0777;
return [
'octal' => sprintf('%o', $perms),
'symbolic' => self::toSymbolic($mode),
'owner_read' => (bool)($perms & 0400),
'owner_write' => (bool)($perms & 0200),
'owner_execute' => (bool)($perms & 0100),
'group_read' => (bool)($perms & 040),
'group_write' => (bool)($perms & 020),
'group_execute' => (bool)($perms & 010),
'other_read' => (bool)($perms & 04),
'other_write' => (bool)($perms & 02),
'other_execute' => (bool)($perms & 01)
];
}
/**
* シンボリック形式に変換
*/
private static function toSymbolic($mode) {
$perms = '';
// ファイルタイプ
if (($mode & 0170000) === 0040000) $perms .= 'd';
elseif (($mode & 0170000) === 0120000) $perms .= 'l';
else $perms .= '-';
// 所有者
$perms .= ($mode & 0400) ? 'r' : '-';
$perms .= ($mode & 0200) ? 'w' : '-';
$perms .= ($mode & 0100) ? 'x' : '-';
// グループ
$perms .= ($mode & 040) ? 'r' : '-';
$perms .= ($mode & 020) ? 'w' : '-';
$perms .= ($mode & 010) ? 'x' : '-';
// その他
$perms .= ($mode & 04) ? 'r' : '-';
$perms .= ($mode & 02) ? 'w' : '-';
$perms .= ($mode & 01) ? 'x' : '-';
return $perms;
}
/**
* 読み取り可能かチェック
*/
public static function isReadable($file) {
return is_readable($file);
}
/**
* 書き込み可能かチェック
*/
public static function isWritable($file) {
return is_writable($file);
}
/**
* 実行可能かチェック
*/
public static function isExecutable($file) {
return is_executable($file);
}
/**
* 安全なパーミッションかチェック
*/
public static function isSafe($file) {
$perms = self::getPermissions($file);
if ($perms === null) {
return false;
}
// ワールドライタブルでないことを確認
if ($perms['other_write']) {
return false;
}
return true;
}
/**
* 推奨パーミッションと比較
*/
public static function checkRecommended($file, $recommended = '0644') {
$perms = self::getPermissions($file);
if ($perms === null) {
return null;
}
return [
'current' => $perms['octal'],
'recommended' => $recommended,
'matches' => $perms['octal'] === $recommended
];
}
}
// 使用例
echo "=== パーミッションチェック ===\n";
$file = '/tmp/test.txt';
// パーミッション取得
$perms = PermissionChecker::getPermissions($file);
if ($perms) {
echo "8進数: {$perms['octal']}\n";
echo "シンボリック: {$perms['symbolic']}\n";
echo "所有者: " . ($perms['owner_read'] ? 'r' : '-') .
($perms['owner_write'] ? 'w' : '-') .
($perms['owner_execute'] ? 'x' : '-') . "\n";
}
// アクセス権チェック
echo "\n読み取り可能: " . (PermissionChecker::isReadable($file) ? 'Yes' : 'No') . "\n";
echo "書き込み可能: " . (PermissionChecker::isWritable($file) ? 'Yes' : 'No') . "\n";
echo "実行可能: " . (PermissionChecker::isExecutable($file) ? 'Yes' : 'No') . "\n";
// 安全性チェック
echo "\n安全なパーミッション: " . (PermissionChecker::isSafe($file) ? 'Yes' : 'No') . "\n";
// 推奨パーミッションと比較
$check = PermissionChecker::checkRecommended($file, '0644');
if ($check) {
echo "\n現在: {$check['current']}\n";
echo "推奨: {$check['recommended']}\n";
echo "一致: " . ($check['matches'] ? 'Yes' : 'No') . "\n";
}
例5: ディスク使用量解析
class DiskUsageAnalyzer {
/**
* ディレクトリのサイズを計算
*/
public static function getDirectorySize($directory) {
if (!is_dir($directory)) {
return 0;
}
$size = 0;
$items = scandir($directory);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$path = $directory . DIRECTORY_SEPARATOR . $item;
if (is_file($path)) {
$stat = stat($path);
if ($stat !== false) {
$size += $stat['size'];
}
} elseif (is_dir($path)) {
$size += self::getDirectorySize($path);
}
}
return $size;
}
/**
* ファイル数を取得
*/
public static function countFiles($directory) {
if (!is_dir($directory)) {
return 0;
}
$count = 0;
$items = scandir($directory);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$path = $directory . DIRECTORY_SEPARATOR . $item;
if (is_file($path)) {
$count++;
} elseif (is_dir($path)) {
$count += self::countFiles($path);
}
}
return $count;
}
/**
* 最大ファイルサイズを取得
*/
public static function getLargestFile($directory) {
if (!is_dir($directory)) {
return null;
}
$largest = null;
$items = scandir($directory);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$path = $directory . DIRECTORY_SEPARATOR . $item;
if (is_file($path)) {
$stat = stat($path);
if ($stat !== false) {
if ($largest === null || $stat['size'] > $largest['size']) {
$largest = [
'path' => $path,
'name' => $item,
'size' => $stat['size']
];
}
}
} elseif (is_dir($path)) {
$subLargest = self::getLargestFile($path);
if ($subLargest && ($largest === null || $subLargest['size'] > $largest['size'])) {
$largest = $subLargest;
}
}
}
return $largest;
}
/**
* 統計情報を取得
*/
public static function getStats($directory) {
return [
'total_size' => self::getDirectorySize($directory),
'file_count' => self::countFiles($directory),
'largest_file' => self::getLargestFile($directory)
];
}
/**
* サイズを人間が読みやすい形式に変換
*/
private static function formatBytes($bytes) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
}
// 使用例
echo "=== ディスク使用量解析 ===\n";
$directory = '/tmp';
$stats = DiskUsageAnalyzer::getStats($directory);
echo "総サイズ: " . DiskUsageAnalyzer::formatBytes($stats['total_size']) . "\n";
echo "ファイル数: {$stats['file_count']}\n";
if ($stats['largest_file']) {
echo "\n最大ファイル:\n";
echo " 名前: {$stats['largest_file']['name']}\n";
echo " サイズ: " . DiskUsageAnalyzer::formatBytes($stats['largest_file']['size']) . "\n";
}
例6: 変更検出システム
class FileChangeDetector {
private $baseline = [];
/**
* ベースラインを作成
*/
public function createBaseline($directory) {
$this->baseline = [];
$this->scanDirectory($directory);
}
/**
* ディレクトリをスキャン
*/
private function scanDirectory($directory) {
if (!is_dir($directory)) {
return;
}
$items = scandir($directory);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$path = $directory . DIRECTORY_SEPARATOR . $item;
if (is_file($path)) {
$stat = stat($path);
if ($stat !== false) {
$this->baseline[$path] = [
'size' => $stat['size'],
'mtime' => $stat['mtime'],
'mode' => $stat['mode'],
'hash' => md5_file($path)
];
}
} elseif (is_dir($path)) {
$this->scanDirectory($path);
}
}
}
/**
* 変更を検出
*/
public function detectChanges($directory) {
$changes = [
'added' => [],
'modified' => [],
'deleted' => [],
'unchanged' => []
];
$current = [];
$this->getCurrentState($directory, $current);
// 追加されたファイル
foreach ($current as $path => $info) {
if (!isset($this->baseline[$path])) {
$changes['added'][] = $path;
}
}
// 削除されたファイル
foreach ($this->baseline as $path => $info) {
if (!isset($current[$path])) {
$changes['deleted'][] = $path;
}
}
// 変更されたファイル
foreach ($current as $path => $info) {
if (isset($this->baseline[$path])) {
$baseline = $this->baseline[$path];
if ($info['hash'] !== $baseline['hash']) {
$changes['modified'][] = [
'path' => $path,
'size_changed' => $info['size'] !== $baseline['size'],
'time_changed' => $info['mtime'] !== $baseline['mtime'],
'mode_changed' => $info['mode'] !== $baseline['mode']
];
} else {
$changes['unchanged'][] = $path;
}
}
}
return $changes;
}
/**
* 現在の状態を取得
*/
private function getCurrentState($directory, &$current) {
if (!is_dir($directory)) {
return;
}
$items = scandir($directory);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$path = $directory . DIRECTORY_SEPARATOR . $item;
if (is_file($path)) {
$stat = stat($path);
if ($stat !== false) {
$current[$path] = [
'size' => $stat['size'],
'mtime' => $stat['mtime'],
'mode' => $stat['mode'],
'hash' => md5_file($path)
];
}
} elseif (is_dir($path)) {
$this->getCurrentState($path, $current);
}
}
}
}
// 使用例
echo "=== 変更検出システム ===\n";
$detector = new FileChangeDetector();
$directory = '/tmp/watch';
// ベースライン作成
$detector->createBaseline($directory);
echo "ベースラインを作成しました\n";
// 少し待機
sleep(1);
// 変更を検出
$changes = $detector->detectChanges($directory);
echo "\n検出結果:\n";
echo "追加: " . count($changes['added']) . "ファイル\n";
echo "変更: " . count($changes['modified']) . "ファイル\n";
echo "削除: " . count($changes['deleted']) . "ファイル\n";
echo "未変更: " . count($changes['unchanged']) . "ファイル\n";
if (!empty($changes['modified'])) {
echo "\n変更されたファイル:\n";
foreach ($changes['modified'] as $mod) {
echo " {$mod['path']}\n";
echo " サイズ変更: " . ($mod['size_changed'] ? 'Yes' : 'No') . "\n";
echo " 時刻変更: " . ($mod['time_changed'] ? 'Yes' : 'No') . "\n";
}
}
lstat()との違い
// シンボリックリンクの場合の違い
// リンクを作成(例)
// symlink('/tmp/original.txt', '/tmp/link.txt');
// stat() - リンク先の情報を取得
$stat_info = stat('/tmp/link.txt');
echo "stat()のサイズ: {$stat_info['size']}\n";
// lstat() - リンク自体の情報を取得
$lstat_info = lstat('/tmp/link.txt');
echo "lstat()のサイズ: {$lstat_info['size']}\n";
// 通常のファイルでは同じ結果
$file = '/tmp/normal.txt';
var_dump(stat($file) === lstat($file)); // true(シンボリックリンクでない場合)
個別関数との関係
$file = 'test.txt';
$stat = stat($file);
// stat()で取得できる情報は個別関数でも取得可能
echo filesize($file); // $stat['size']と同じ
echo filemtime($file); // $stat['mtime']と同じ
echo fileatime($file); // $stat['atime']と同じ
echo filectime($file); // $stat['ctime']と同じ
echo fileperms($file); // $stat['mode']と同じ
echo fileinode($file); // $stat['ino']と同じ
echo fileowner($file); // $stat['uid']と同じ
echo filegroup($file); // $stat['gid']と同じ
// 複数の情報が必要な場合はstat()の方が効率的
// 1回のシステムコールですべての情報を取得
まとめ
stat()関数の特徴をまとめると:
できること:
- ファイル/ディレクトリの詳細情報を取得
- サイズ、タイムスタンプ、パーミッション等
- 13種類の情報を一度に取得
戻り値:
- 13要素の配列
- 数値インデックスと文字列キーの両方
- 失敗時は
false
推奨される使用場面:
- ファイル情報の解析
- ファイル監視システム
- バックアップシステム
- パーミッション管理
- ディスク使用量分析
主要な情報:
size: ファイルサイズmtime: 最終更新時刻atime: 最終アクセス時刻ctime: 最終変更時刻mode: パーミッションuid/gid: 所有者情報ino: inode番号
関連関数:
lstat(): シンボリックリンク自体の情報filesize(): サイズのみ取得filemtime(): 更新時刻のみ取得fileperms(): パーミッションのみ取得file_exists(): 存在確認is_file()/is_dir(): タイプ確認
よく使うパターン:
// ファイル情報を一度に取得
$info = stat($file);
$size = $info['size'];
$mtime = $info['mtime'];
// パーミッション確認
$mode = $info['mode'] & 0777;
$perms = sprintf('%o', $mode);
// 更新時刻の確認
$age = time() - $info['mtime'];
stat()は、ファイルシステムの詳細情報を取得する強力な関数です。ファイル監視、バックアップ、セキュリティチェックなど、様々な場面で活躍します!
