PHPでは、ファイルハッシュ計算は通常、データの整合性検証、ファイル重複排除、デジタル署名などのシナリオで使用されます。 2つは同様の機能を持っていますが、パフォーマンスにはいくつかの違いがあります。この記事では、大規模なファイルを処理する際のこれら2つの方法のパフォーマンスの違いを比較し、開発者が適切な機能をより適切に選択してアプリケーションの効率を向上させることができます。
HASH_FILE()関数は、指定されたファイルのハッシュ値を直接計算するために使用されます。構文は次のとおりです。
string hash_file ( string $algo , string $filename [, bool $binary = false ] )
$ algo : MD5 、 SHA256など、使用するハッシュアルゴリズムを指定します。
$ filename :ファイルパス。ハッシュ値を計算するファイルを示します。
$ binary : trueの場合、バイナリハッシュ値を返します。 falseの場合は、16進のハッシュ値を返します。
たとえば、ファイルのSHA256ハッシュ値を計算します。
$fileHash = hash_file('sha256', 'largefile.txt');
Hash_file()は、ファイル全体を自動的に読み取り、ハッシュ値を計算するため、非常に簡単な方法です。ただし、大規模なファイルを処理する場合、ファイル全体を直接読み取ると、特にメモリリソースが限られている環境では、メモリ消費量が高くなる可能性があります。
hash_file()とは異なり、 hash_update_stream()は、セグメントのハッシュ値を計算する方法であり、ハッシュを計算するときにファイルコンテンツを段階的に読み取ることができます。これは、ファイル全体を一度にメモリにロードする必要はないが、ブロックごとにチャンクを処理できないため、大きなファイルに特に便利です。
bool hash_update_stream ( resource $context , string $data [, int $length = 0 ] )
$ context : hash_init()を介して作成されたハッシュコンテキストです。
$データ:計算するデータの一部。
$ length :オプションのパラメーター、読み取るデータの長さを指定します。
大きなファイルハッシュを計算するための基本的な手順は次のとおりです。
$hashContext = hash_init('sha256'); // ハッシュコンテキストを初期化します
$handle = fopen('largefile.txt', 'rb'); // ファイルを開きます
while (!feof($handle)) {
$data = fread($handle, 8192); // チャンクでファイルを読み取ります
hash_update_stream($hashContext, $data); // ハッシュを更新します
}
$hash = hash_final($hashContext); // 最終的なハッシュ値を取得します
fclose($handle);
チャンクでファイルを読み取り、ハッシュ値を徐々に更新することにより、この方法はメモリをより効果的に管理でき、大きなファイルの処理に適しています。
hash_file() :この関数は、ファイルサイズが中程度の状況に適したハッシュ計算のために、一度にファイル全体をメモリにロードします。ファイルが非常に大きい場合(複数のGBなど)、メモリ使用量が過剰になり、メモリオーバーフローエラーさえ引き起こします。
hash_update_stream() :このメソッドはファイルを段階的に読み取り、ハッシュ値を更新するため、メモリの使用量が低くなります。大きなファイルの場合、 hash_update_stream()には、各読み取りファイルブロックにデータを保存するため、ファイル全体のロードの高いメモリ要件を回避するため、より多くの利点があります。
速度に関しては、 Hash_file()は通常、追加のメモリ割り当てや処理を必要とせずにオペレーティングシステムのファイル読み取り機能を直接呼び出す根本的な関数であるため、パフォーマンスが高くなります。ただし、ファイルサイズが増加すると、そのパフォーマンスはメモリの制限の影響を受ける可能性があります。
対照的に、 hash_update_stream()には、より多くのコード実行ロジック(ハッシュの段階的な読み取りや段階的更新など)が必要ですが、大きなファイルを扱う場合、より効率的なメモリ管理により全体的なパフォーマンスが向上する傾向があります。
hash_update_stream()は、より柔軟性を提供します。開発者は、各読み取りファイルのサイズ( Fread()で指定)を制御して、メモリフットプリントと速度のバランスを見つけることができます。大きなファイルの場合、読み取りブロックのサイズをサーバーのメモリに従って調整して、パフォーマンスを最適化できます。
hash_file()を使用:処理されたファイルが小さく、システムメモリが十分である場合、 hash_file()はより簡潔で効率的です。
hash_update_stream()を使用:処理されたファイルが非常に大きい場合、またはメモリ制限環境で、 hash_update_stream()は、チャンク読み取りを通じてメモリの使用量を減らすことができるため、より適しています。
2つのパフォーマンスの違いをさらに検証するために、簡単なコードでテストできます。
$start = microtime(true);
$hash = hash_file('sha256', 'largefile.txt');
$end = microtime(true);
echo "hash_file took: " . ($end - $start) . " seconds.\n";
$start = microtime(true);
$hashContext = hash_init('sha256');
$handle = fopen('largefile.txt', 'rb');
while (!feof($handle)) {
$data = fread($handle, 8192);
hash_update_stream($hashContext, $data);
}
$hash = hash_final($hashContext);
fclose($handle);
$end = microtime(true);
echo "hash_update_stream took: " . ($end - $start) . " seconds.\n";
2つのコードの実行時間を比較することにより、実際のシナリオの2つの方法のパフォーマンスの違いを直感的に理解できます。
中規模のファイルの場合、 hash_file()はシンプルで使いやすく、より速く、ほとんどのニーズを満たすのに十分です。
大きなファイルの場合、 hash_update_stream()はより良いメモリコントロールを提供し、メモリ制約の環境での使用に適しています。
適切なハッシュメソッドを選択すると、パフォーマンスを改善するだけでなく、リソースの無駄を避けることもできます。大規模なファイル処理の場合、メモリフットプリントが低く、より安定したパフォーマンスがあるため、 hash_update_stream()を使用することをお勧めします。