md5_file():ファイルの md5 を求める(PHP)

PHP

md5_file() は、ファイルの中身から md5(32 けたの 16 進数の値)を求める PHP の関数です。ファイルが 1 文字でも違えば別の値になるので、配られているファイルと同じかどうか、書き換えられていないかを確認するときに使います。

書き方

md5_file( string $filename, bool $binary = false ): string|false
  • $filename:md5 を求めるファイルのパス
  • $binary:true なら、32 けたの文字ではなく、16 バイトのバイナリで返す。ふつうは false(書かない)
  • 戻り値:md5 の文字列。ファイルが読めないときは false
関数 使い分け
md5_file( $file ) ファイルの md5。ファイルを少しずつ読みながら求める
md5( $string ) 文字列の md5。ファイルに使うと、先に file_get_contents() で丸ごと読むことになる

使い方の例

作業環境(PHP 8.3・WordPress 7.1.3)で試した結果を、コメントに書いています。

大きなファイルでもメモリを食わない

50MB のファイルで、md5_file() と md5( file_get_contents() ) を比べました。値は同じですが、メモリの使う量が大きく違います。

<?php
$file = __DIR__ . '/big.bin'; // 50MB のファイル

echo md5_file( $file );                // 25e317773f308e446cc84c503a6d1f85
echo md5( file_get_contents( $file ) ); // 25e317773f308e446cc84c503a6d1f85(同じ値)

// メモリの使う量(memory_get_peak_usage( true ) を、それぞれ別の実行で測った)
// md5_file()                   → 2.0MB
// md5( file_get_contents() )   → 54.0MB(ファイルを丸ごと読むので、ファイルの大きさの分が増える)

読めないときは false

<?php
$hash = md5_file( __DIR__ . '/no-such-file.txt' );
var_dump( $hash ); // bool(false)(PHP の警告も出る)

// false と、中身が空のファイルの md5 を取り違えないよう、=== で比べる
if ( false === $hash ) {
	error_log( 'ファイルが読めない' );
}

echo md5_file( __DIR__ . '/empty.txt' ); // d41d8cd98f00b204e9800998ecf8427e(空のファイル。md5( '' ) と同じ)

ファイルが書き換えられていないかを確認する

WordPress.org は、本体とプラグインのファイルごとの md5 を配っています。その値と比べると、ファイルが配られたものと同じかが分かります。作業環境で、プラグインの readme.txt に 1 行足して試しました(試したあとは、元のファイルに戻して md5 が同じになったことを確認しています)。

<?php
// WordPress.org が配っている md5 と比べて、ファイルが書き換えられていないかを確かめる
$want = '5027401feb911a5db99e2ca0bce73319'; // チェックサムの JSON にある md5
$file = WP_PLUGIN_DIR . '/my-org-plugin/readme.txt';

echo md5_file( $file ) === $want ? '同じ' : '変わった'; // 同じ

file_put_contents( $file, "\n# test line\n", FILE_APPEND ); // わざと 1 行足すと
echo md5_file( $file ) === $want ? '同じ' : '変わった'; // 変わった(9e6782b8d470404fb4e055b4eee0786d)

バイナリで受け取る

<?php
// $binary を true にすると、16 バイトのバイナリで返る
echo strlen( md5_file( __DIR__ . '/big.bin' ) );       // 32
echo strlen( md5_file( __DIR__ . '/big.bin', true ) ); // 16
echo bin2hex( md5_file( __DIR__ . '/big.bin', true ) ); // 25e317773f308e446cc84c503a6d1f85

気をつけること

  • ファイルが読めないと false が返り、PHP の警告も出ます。戻り値は === で比べてください。== で比べると、思わぬ値と等しいと見なされることがあります。
  • md5 は、わざと同じ値になる別のファイルを作る方法が知られています。配られたファイルと同じかを確認する使い方には十分ですが、パスワードの保存や署名には使わず、パスワードは password_hash()、より強いチェックには hash_file( 'sha256', $file ) を使ってください。
  • 多くのファイルに使うと、ファイルを全部読むので時間がかかります。作業環境では、WordPress の本体(4,000 ほどのファイル)を比べるのに、WordPress の読み込みを含めて 1 秒ほどかかりました。サーバーではもっとかかることがあるので、管理画面のページを開くたびに動かすのではなく、WP-Cron などで裏で動かしてください。
  • 改行の形(LF と CRLF)や文字コードが違うだけでも、別の値になります。FTP のソフトがテキストのファイルの改行を替えてアップロードしていると、中身は同じでも「変わった」と見えることがあります。

逆引きリファレンスの一覧へ