PHPで大きなファイルを処理するとき、私たちはしばしば過度のメモリ使用の問題に直面します。特に、ファイルのハッシュ値(MD5、SHA1など)のハッシュ値を計算する必要がある場合、ファイル全体が一度にメモリにロードされている場合、メモリ消費量が大きくなるか、メモリ制限を超えてプログラムをクラッシュさせます。これを回避するために、PHPはhash_update_stream関数を提供します。これにより、ファイルを読み取り、ブロックごとにハッシュブロックを計算できるため、メモリの使用量を効果的に削減できます。
HASH_UPDATE_STREAMは、ハッシュ計算を更新するためのPHPの関数です。オープンファイルストリーム(ストリーム)を受け入れ、ブロックごとにファイルコンテンツブロックのハッシュを更新します。ファイルの内容をメモリに直接ロードするのと比較して、 hash_update_streamは大きなファイルを段階的に処理し、メモリフットプリントを大幅に削減できます。
関数の署名は次のとおりです。
bool hash_update_stream ( resource $context , resource $file_handle [, int $length = 1024 ] )
$コンテキスト:これは、hash_init関数によって作成されたハッシュコンテキストです。
$ file_handle :通常はFopen関数を介して取得されるファイルのリソースハンドル。
$ length :時間ごとに読み取られるバイト数、デフォルトは1024バイト(1kb)です。
大きなファイルがあり、MD5ハッシュを計算する必要があるとします。従来のアプローチは、ファイル全体をメモリに読み取り、ハッシュ値を計算することです。ただし、大きなファイルの場合、このプラクティスはメモリオーバーフローにつながる可能性があります。
$file = 'path/to/largefile.txt'; // 実際のファイルパスに置き換えます
$context = hash_init('md5');
$handle = fopen($file, 'rb');
if ($handle) {
while (!feof($handle)) {
$buffer = fread($handle, 1024); // 読む1KBデータ
hash_update($context, $buffer);
}
fclose($handle);
}
$hash = hash_final($context);
echo "File MD5 hash: " . $hash;
上記のように、チャンクでファイルを読み取り、 Hash_Updateを使用してハッシュ値を更新します。ここのHASH_UPDATEは、より小さなブロックに対して計算されますが、メモリの使用量はブロックのサイズに基づいて決定されます。
hash_updateを直接使用するのとは異なり、 hash_update_stream関数を使用すると、ファイルのコンテンツを手動で読み取ることなくファイルストリームを直接処理できます。これにより、メモリの消費を減らしながらハッシュ値を徐々に更新しやすくなります。
最適化されたコードは次のとおりです。
$file = 'path/to/largefile.txt'; // 実際のファイルパスに置き換えます
$context = hash_init('md5');
$handle = fopen($file, 'rb');
if ($handle) {
while (!feof($handle)) {
// 每次从文件流中読む1024バイトと更新ハッシュ
hash_update_stream($context, $handle, 1024);
}
fclose($handle);
}
$hash = hash_final($context);
echo "File MD5 hash: " . $hash;
hash_update_streamの利点は、ファイルのすべての部分を手動で読み取ることなく、ファイルストリームを直接処理できることです。この方法により、プログラムはハッシュ値を計算するときにメモリ使用量を効果的に削減できます。
ブロックごとにブロックを読み取ります: hash_update_streamは、ファイル全体を一度にメモリにロードする代わりに、ブロックごとにファイルブロックからデータを読み取ります。
低メモリ消費:ストリーミング操作を通じて、メモリフットプリントは非常に低く、現在処理されているファイルブロックのみを保存する必要があります。
大規模なファイルに適しています:非常に大きなファイル(数GB以上など)の場合、 hash_update_streamが理想的です。
実際のアプリケーションでは、リモートファイルのハッシュ値を計算する必要があるシナリオに遭遇する場合があります。 URLアドレスによって指されたファイルのハッシュ値を計算する必要があると仮定すると、同様の方法を使用できます。
$url = 'http://example.com/largefile.txt'; // 例 URL
$file = fopen($url, 'rb');
if ($file) {
$context = hash_init('md5');
while (!feof($file)) {
hash_update_stream($context, $file, 1024);
}
fclose($file);
$hash = hash_final($context);
echo "File MD5 hash: " . $hash;
}
ただし、URLドメイン名m66.netを交換するように依頼するため、上記のURLを次のように変更できます。