PHPでアップロードするファイルのMIMEをチェックするサンプル

とアップロード関連のお話ばかりですが、今回も続きです。

前回はJavaScriptを真似て、PHPでもファイルの拡張子をチェックする例を紹介しましたが、ファイルのアップロード処理において、それだけではちょっとマズイです。

善良な人しかインターネットを使わないのであれば平和なのですが、残念ながらハッキング被害はそこら中に転がっていますし、「うちのような個人サイトがアタック受けるわけないでしょw」と楽観視していた過去のぼくはものの見事に不正スクリプトを仕込まれる被害に会いました。

そういうハッキング処理は通常botが自動で実行しており、むこう側に人がいるとは限らないのです。つまり、それらは24時間365日自動でハッキングを行っているので、有名/無名サイトなんて関係ないんですよね。セキュリティの甘いサイトに侵入して、画像ファイルのふりしたスクリプトを仕込み、そこを踏み台にして、また別のサイトへ、というのをずぅーっと繰り返しているわけですから。こわいこわい。

セキュリティ対策はイタチごっこの側面もあり、すべてに対処するのは難しいとは思いますが、それでもわかりきっていることには対応すべきです。ということで、今回はMIMEをチェックする例。

PHPでファイルのMIMEタイプをチェックする例

■mime_content_typeを使う例
//許可するMIME
$cfg['ALLOW_MIME'] = array('image/jpeg', 'image/png');

//ファイルのMIMEタイプが許可されているかチェックする関数
function checkMIME($filename)
{
	global $cfg;
	$mime = mime_content_type($tmp_name);
	return in_array($mime, $cfg['ALLOW_MIME']);
}

但し、PHP 5.3以降の場合、デフォルトではmime_content_typeが使えなくなり、finfoの拡張モジュールが必要となりました。Windowsの場合は

「;extension=fileinfo」

のコメントアウトを外すだけですが、レンタルサーバーの場合だとそうもいかないケースもあるかも知れません。

その場合は代用手段を取るしかないのですが、対象が画像ファイルならこんな方法もあります。

■mime_content_typeの代わりにimage_type_to_mime_typeを使う例
//ファイルのMIMEタイプを返す関数(画像ファイルのみ)
function mime_content_type_image($filename)
{
	list($w, $h, $type) = getimagesize($filename);
	if (!$type) {
		return '';
	} else {
		return image_type_to_mime_type($type);
	}
}

mime_content_typeの代わりに、getimagesize関数とimage_type_to_mime_type関数を使う例です。画像ファイル以外が指定された場合は空文字が返ります。

ただ、無理にMIMEで判定せずとも、下記のように定数でチェックするのもアリです。

function checkMIME($filename)
{
	list($w, $h, $type) = getimagesize($filename);
	switch ($type) {
		case IMG_JPG:
		case IMG_PNG:
			return true;
		default:
			return false;
	}
}

いずれにせよ、拡張子だけ見て判断するよりも信頼性があがります。

アップロード処理の全体像

HTMLまで含めると長くなってきたので、[アップロード]ボタンを押下した際の処理部分のみ掲載しておきます。

//許可するMIME
$cfg['ALLOW_MIME'] = array('image/jpeg', 'image/png');

//[アップロード]ボタンの押下確認
if (isset($_POST['_upload'])) {
	foreach ($_FILES['file']['tmp_name'] as $no => $tmp_name) {
		try {
			$filename = $_FILES['file']['name'][$no];
			//アップロードされたファイルのMIMEタイプをチェックする
			if (checkMIME($tmp_name)) {
				//ファイルをテンポラリから保存場所へ移動
				if (move_uploaded_file($tmp_name, './'.$filename)) {
					echo $filename.'をアップロードしました<br>';
				} else {
					throw new RuntimeException('アップロードエラー');
				}
			} else {
				throw new RuntimeException($filename.'はアップロードできません');
			}
		} catch (RuntimeException $e) {
			echo $e->getMessage().'<br>';
		}
	}
}
//ファイルのMIMEタイプが許可されているかチェックする関数
function checkMIME($filename)
{
	global $cfg;
	$mime = mime_content_type($filename);
	return in_array($mime, $cfg['ALLOW_MIME']);
}

まとめ

  • PHPでファイルの種類を判定するにはmime_content_type関数を使うとらくちん
  • mime_content_type関数が使えない、あるいは画像だけで良い場合はgetimagesize関数で判断すると良い

簡単ですが、こんなところですかね。

PHP5.3くらいまでは拡張モジュールなしでもmime_content_type関数使えたハズなんですけど、なんでPHP7では使えなくなっちゃったんでしょうね。ぼくの場合getimagesize関数でコト足りるケースがほとんどなので実害はないですが…今回記事にするにあたって念の為レンタルサーバーでも動作確認したら、mime_content_type関数が使えないところばかりで驚きました。

adsbygoogle

フォロー