[PHP]ディレクトリ内の一定時間が経過した古いファイルだけを削除する

Pocket

フォルダ内の古くなったファイルだけを消すには、
filemtime() で最終更新日を取得し、unlink() で削除します。

最終更新日は Unix 時間で取得されるので削除期限の指定には strtotime() を使いました。
「24 hours ago」であれば 24 時間前より古いファイルが削除されます。
単純に 「time() – (60 * 60 * 24)」としたり、mktime() を使ったりするのも良いでしょう。

【注意】
このスクリプトを実行するとファイルが削除されます。
実行前に必ず echo などで削除対象のファイルが適切に指定されているか確認して下さい。

<?php
date_default_timezone_set('Asia/Tokyo');

//削除期限
$expire = strtotime("24 hours ago");

//ディレクトリ
$dir = dirname(__FILE__) . '/dir/';

$list = scandir($dir);
foreach($list as $value){
	$file = $dir . $value;
	if(!is_file($file)) continue;
	$mod = filemtime( $file );
	if($mod < $expire){
		//chmod($file, 0666);
		unlink($file);
	}
}

削除にパーミッションの変更が必要な場合は chmod() で適切な権限に変更して下さい。
それでも削除できない場合はディレクトリのパーミッションや所有者を確認して下さい。

ディレクトリが多階層になっていて、指定したディレクトリ以下の全てのファイルを再帰的に探索して削除するには次のようにします。

<?php
date_default_timezone_set('Asia/Tokyo');

//削除期限
$expire = strtotime("24 hours ago");

//ディレクトリ
$dir = dirname(__FILE__) . '/dir/';

remove_old_files($dir, $expire);
 
function remove_old_files($dir, $timestamp){
	$iterator = new RecursiveIteratorIterator(
		new RecursiveDirectoryIterator(
			$dir,
			 FilesystemIterator::CURRENT_AS_FILEINFO
			|FilesystemIterator::SKIP_DOTS
			|FilesystemIterator::KEY_AS_PATHNAME
		), RecursiveIteratorIterator::LEAVES_ONLY
	);

	foreach($iterator as $pathname => $info){
		if($info->getMTime() < $timestamp){
			//chmod($pathname, 0666);
			unlink($pathname);
		}
	}
}

RecursiveCallbackFilterIterator を利用すると除外項目をより詳細に設定できます。
下の例では 指定した時間より古く、指定した項目名でないもの を条件に処理をしています。

<?php
date_default_timezone_set('Asia/Tokyo');

//削除期限
$expire = strtotime("24 hours ago");

//ディレクトリ
$dir = dirname(__FILE__) . '/dir/';

// 除外項目
$ignores = [
    $dir . 'example'
];

remove_old_files($dir, $expire, $ignores);

function remove_old_files($dir, $timestamp, $ignores = [])
{
	// フィルター処理
    $filter = function ($file, $key, $iterator) use ($timestamp, $ignores) {
        if ($iterator->hasChildren()) {
            return true;
        }

		// 除外対象を正規表現で選別
        foreach ($ignores as $ignore) {
            $pattern = '/^' . preg_quote($ignore, '/') . '/';
            if (preg_match($pattern, $file)) {
                return false;
            }
        };

		// 古くない項目は除外
        if ($file->getMTime() >= $timestamp)  return false;

        return true;
    };

    $dirIterator = new RecursiveDirectoryIterator(
        $dir,
         FilesystemIterator::CURRENT_AS_FILEINFO
        |FilesystemIterator::SKIP_DOTS
        |FilesystemIterator::KEY_AS_PATHNAME
    );

    $iterator = new RecursiveIteratorIterator(
       new RecursiveCallbackFilterIterator($dirIterator, $filter),
        RecursiveIteratorIterator::LEAVES_ONLY
    );

    foreach ($iterator as $pathname => $info) {
        //chmod($pathname, 0666);
        unlink($pathname);
    }
}

Similar Posts:




  1. こんにちは。
    こちら、指定したディレクトリ以下の全てのファイルを消す際に、あるディレクトリだけ除外するにはどのように記述すれば良いでしょうか…?
    宜しくお願いします。

  2. RecursiveCallbackFilterIterator を使って前方一致で除外する例を追加しました。
    このクラスを使うと自分で作ったフィルターで除外処理を行うことができます。

  3. 参考にさせていただきました。1点だけ教えてください。

    サンプルをそのまま実行すると、サブフォルダのファイルが消えませんでした。
    20行目の下に以下のロジックを入れるとうまくいきました。

    if ($iterator->hasChildren()) {
    return TRUE;
    };

    公式サイトを参考にしました。
    http://php.net/manual/ja/class.recursivecallbackfilteriterator.php#recursivecallbackfilteriterator.examples

    単なる誤りなのか、環境等の問題なのかもし分かれば教えていただけると幸いです。
    (最後に機能強化されているので、ディグレードなのかな?と思いました)

  4. コメントありがとうございます。
    ファイルを更新するとフォルダの更新日時も書き換わるのでそのせいですね。
    ソースコードを修正しました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です