IT系おじさんのチラシの裏
2018年10月~
当サイトの記事にはアフィリエイト広告のリンクが含まれる場合があります

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関数が使えないところばかりで驚きました。

関連記事

Windows環境にphpmyadminをインストールする

最近のレンタルサーバーなら管理ページでポチっとボタンひとつでphpmyadminのインストールくらい完了しますし、手動でやるとしても公式サイトからZIPをダウンロードして解凍してアップロードする程度で

Windows版PHPでSFTP接続するにはphp_ssh2.dllが必要

Web運営のメンテナンス作業(ローカルへのバックアップ作業とか)を自動化する方法について4回にわけて記事にしてきました。 WSHでブラウザを自動操作する PHPでファイルとDB(Postgre

コメント

新しいコメントを投稿する

[新規投稿]
 
TOP