PHPに保存されている一時ファイルをクリーンアップする正しい方法は何ですか?

Dec 01 2020

phpを使用して一時ストレージスペースをクリーンアップする方法を見つけようとしています。cronジョブをセットアップできることは知っていますが、php自体からセットアップする方法はありますか?

ユーザーがダウンロードできるように生成されたPDFファイルを保存するために一時ストレージフォルダーを使用します。ファイルの有効期限を強制することができたので、3分後には一般公開でアクセスできなくなります。今問題。ファイルは公開されていませんが、サーバーに保存されています。ストレージをクリーンアップするために、このようなコードを作成しました。

/** from the main thread */
if (rand(1, 100) <= 5) {
    Reports::clean();
}

/** the clean function */
public static function clean()
{
    $path = static::getStoragePath(); if($dir_handle = opendir($path)) { while (($fileName = readdir($dir_handle)) !== false) { $file = $path . '/' . $fileName;
            
            if (!is_file($file)) continue; // If file is older that 3 minutes delete it if (time() - filemtime($file) > static::$expires) { unlink($file);
            }
        }
        closedir($dir_handle);
    }
}

したがって、これによりストレージがランダムにクリーンアップされます。ほとんどこれは問題ありません。しかし、問題は、ストレージのクリーンアップが開始されると、タートルのようにその要求が遅くなることです。

そこで、cronジョブを作成することを考えました。しかし、php自体からこれを行う正しい方法はありますか?

注:私はslim-4を使用していますが、cronジョブの設定に関する専門知識もあまりありません。したがって、どのリソースも役立ちます

回答

3 MarcinJóźwikowski Dec 01 2020 at 17:04

簡単な答え:いいえ。

PHPには、アクションを自己トリガーする方法がありません。

スクリプト(またはフレームワークの場合はコマンド)を作成し、cronjobでトリガーします。

2 MarkusAO Dec 01 2020 at 17:23

実装では、クリーンアップルーチンがメインスレッドに到達するたびに、PDFディレクトリ内のファイルの量によっては、応答に大幅な遅延が生じる可能性があります。

他のコメント/回答で述べたように、cronジョブは確かにこれを処理するための「標準的な」方法です。ただし、cronジョブにアクセスできない場合、または単に純粋なPHPソリューションを好む場合は、すでに行っていることとは別に、いくつかの可能なアプローチがあります。

  1. 作成されたファイルのログを作成タイムスタンプとともに保持します。クリーンルーチンが呼び出されたら、変更された時間チェックを使用してディレクトリ全体をスキャンする代わりに、レコードに基づいて削除し、削除されたエントリをレコードから削除します。レコードをJSONファイルまたはCSV / TSVなどとして保存します。これにより、ファイルシステムへのアクセスが減少するため、ファイルの量が多い場合に大幅な速度向上が実現します。

  2. クリーンアップの遅れでユーザーを煩わせたくない場合は、ルーチンをユーザー向けファイルから管理者専用ファイルに移動するか、管理者ユーザーチェックを実行して、クリーンアップ頻度トリガーを調整します(OPで1:20)管理者の使用頻度に合わせます。もちろん、これによりクリーンアップの頻度が減る可能性がありますが(管理者がいない場合)、一般の人々の負担は軽減されます。

  3. 最後に、明らかに、Cron氏になり、時々、毎日、またはサーバーの容量が不足する前に、手動でクリーンアップをトリガーします。一般に、スペースが非常に限られている場合を除いて、20ページの呼び出しごとにクリーンアップする必要はないようです。生成されたPDFの量、発生したトラフィック、またはサーバーリソースがわからないため、クリーンアップの頻度に関する推奨値を思い付くのは困難です。

TomiL Dec 01 2020 at 21:55

これは悪い概念です。このジョブにはcronjobスケジューラを使用してください。フォルダの内容が10MBを超える場合にフォルダ/ tmp / some_path内のすべてのファイルを削除するbashonelinerは次のとおりです(必要に応じて変更してください)。

SIZE=$(du -bs --block-size=1M /tmp/some_path | cut -f1); if [[ $SIZE -gt 10 ]];then echo "Folder '/tmp/some_path' has size ($SIZE MB)."; rm -r /tmp/some_path/*; fi

このコードをscript.shに貼り付けることができます(たとえば、bashの上部にshebangを含め#!/bin/bash、ファイルを実行可能にしますchmod +x script.sh)。次に、cronjobスケジューラ(たとえばcrontab -e)に新しい行を追加して、1時間ごとにフォルダサイズ確認します

0 * * * * <path_to_the_script>/script.sh

cronjobの詳細については、次を参照してください。 https://crontab.guru