導入
Webアプリケーションを運用していると、ログファイル、一時的なアップロードファイル、キャッシュなどがサーバーのディスクを圧迫することがあります。これらを放置すると、ディスクフルによるシステム停止を引き起こすリスクがあります。本記事では、PHPを使って「一定期間経過した古いファイル」をディレクトリから抽出し、安全に削除するテクニックを解説します。
基礎知識
PHPでファイル操作を行う際、主に以下の関数とクラスを使用します。
filemtime(): ファイルの最終更新日時をUnixタイムスタンプで取得します。
unlink(): 指定したファイルを削除します。
strtotime(): 「24 hours ago」のような文字列をUnixタイムスタンプに変換します。これにより、「現在から◯時間前」という基準値を簡単に作成できます。
Iterator系クラス: ディレクトリを再帰的に走査するために、PHPの標準ライブラリであるSPL(Standard PHP Library)のRecursiveDirectoryIteratorなどを使用します。これにより、多階層のディレクトリ構造も効率的に処理可能です。
実装/解決策
単純なディレクトリ走査であればscandir()で十分ですが、サブディレクトリが深く入り組んでいる場合は、RecursiveIteratorIteratorを使用するのが一般的です。さらに、特定のファイルやディレクトリを除外したい場合は、RecursiveCallbackFilterIteratorを組み合わせることで、柔軟なフィルタリングが可能になります。
サンプルプログラム
以下は、指定したディレクトリ以下のファイルを走査し、24時間以上更新がないファイルを削除する実用的なコードです。
hasChildren()) {
return true;
}
// 最終更新日時が期限より古い場合のみtrue(削除対象)を返す
return $file->isFile() && $file->getMTime() < $expire;
};
try {
$directory = new RecursiveDirectoryIterator($targetDir, FilesystemIterator::SKIP_DOTS);
$iterator = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator($directory, $filter)
);
foreach ($iterator as $file) {
// 念のためパスを出力して確認する(運用時はログ出力に変更推奨)
echo "削除対象: " . $file->getPathname() . PHP_EOL;
// 実際に削除を実行
// unlink($file->getPathname());
}
} catch (Exception $e) {
echo “エラー: ” . $e->getMessage();
}
?>
応用・注意点
1. ドライラン(Dry Run)の徹底:
いきなりunlink()を実行せず、まずはechoで削除予定のファイル名を表示し、意図しないファイルまで含まれていないか必ず確認してください。
2. 権限(Permission)の確認:
PHPを実行しているユーザー(Webサーバーのwww-data等)が、対象ファイルに対する書き込み権限と、親ディレクトリに対する実行権限を持っている必要があります。削除できない場合は、まず対象ファイルのパーミッションを確認してください。
3. 大規模なディレクトリへの対応:
ファイル数が数万件を超えるようなディレクトリで実行する場合、メモリ消費や処理時間に注意が必要です。その場合は、PHPのスクリプトで処理するよりも、Linuxの標準コマンドである「find」コマンド(find /path/to/dir -type f -mtime +1 -delete)をCronで実行する方がシステム負荷が少なく、推奨される場合が多いです。