【PHP】画像ファイルの種類(拡張子やMIMEタイプ)を取得する方法
プログラムでは画像を扱うことも多いかと思いますが、その画像の種類(jpgなのかpngなのかgifなのか)を取得したい時があります。
ここでは画像の拡張子やMIMEタイプを取得する方法をまとめています。
pathinfo関数で拡張子を取得
pathinfo関数を使えば、画像のファイル名から拡張子やディレクトリ名などが取得できます。
pathinfo(画像までのパスやURLを指定);
引数に画像までのパスやURLを指定することで、以下の4つの戻り値が得られます。また、第2引数を指定することもできます。
Array ( [dirname] => ./img(URLを指定した場合は「http://ysklog.net/img」のようになる) [basename] => 20140123.jpg [extension] => jpg [filename] => 20140123 )
ということで、pathinfo関数を使うとこのように画像の拡張子が取得できます。
<?php //画像ファイルの指定 $img_file = "画像ファイルのパスやURL"; //拡張子の取得 $file_info = pathinfo($img_file); $img_extension = strtolower($file_info['extension']); //出力 echo $img_extension; ?>
※strtolower関数は英文字をすべて小文字にします。
finfo_open、finfo_file、finfo_buffer関数でMIMEタイプを取得
pathinfo関数を使えば画像のファイル名から拡張子を簡単に取得できますが、シンプル故に欠点があります。
それは、第三者からアップロードされた画像の拡張子が偽装されていたり、そもそも拡張子がなかったりすると対応できないことです。
そこで、別手段として画像ファイルのMIMEタイプを取得する方法があります。
これは、finfo_open関数、finfo_file関数、finfo_buffer関数を使います。
<?php //画像ファイルの指定 $img_file = "画像ファイルまでのパス(URL不可)"; //MIMEタイプの取得 $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_file($finfo, $img_file); finfo_close($finfo); //出力 echo $mime_type; ?>
もしくは
<?php //画像ファイルの指定 $img_file = "画像ファイルのパスやURL"; //画像ファイルデータを取得 $img_data = file_get_contents($img_file); //MIMEタイプの取得 $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_buffer($finfo, $img_data); finfo_close($finfo); //出力 echo $mime_type; ?>
PHPのバージョンが5.3以降であれば、以下も使用可能です。
<?php //画像ファイルの指定 $img_file = "画像ファイルまでのパス(URL不可)"; //MIMEタイプの取得 $finfo = new finfo(FILEINFO_MIME_TYPE); $mime_type = $finfo->file($img_file); //出力 echo $mime_type; ?>
これで拡張子がない画像や偽装された画像でもファイルのデータそのものからMIMEタイプを判断するので、正しいファイル情報を取得できるようになります。
なお、MIMEタイプを取得する方法はファイルをオープンするため、その分処理が遅くなります。
MIMEタイプから拡張子を取得する
画像のファイル名から拡張子を取得するのは偽装に対応できない弱点があるので、やはり画像のMIMEタイプを調べるのが最も良いと思います。
ということで、上のプログラムをもとにMIMEタイプを取得して、MIMEタイプからさらに拡張子を決定するプログラムを作成してみました。
<?php //画像ファイルの指定 $img_file = "画像ファイルのパスやURL"; //画像ファイルデータを取得 $img_data = file_get_contents($img_file); //MIMEタイプの取得 $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_buffer($finfo, $img_data); finfo_close($finfo); //MIMEタイプの出力 echo $mime_type; //拡張子の配列(拡張子の種類を増やせば、画像以外のファイルでもOKです) $extension_array = array( 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'png' => 'image/png' ); //MIMEタイプから拡張子を出力 if($img_extension = array_search($mime_type, $extension_array,true)){ //拡張子の出力 echo $img_extension; } ?>
getimagesize関数を使えば楽チン
【追記】上のプログラムはややこしくてセンスがないなーと思っていたのですが、getimagesize関数を使えばスマートかつ楽チンに画像の種類(MIMEタイプと拡張子)を取得できることに気づきました。
この関数がどういう関数かは画像のサイズ(縦横)や種類(MIMEタイプ)を取得するに書いているのですが、次のようにするとスッキリとしたコードで欲しい情報が取得できます。
<?php //getimagesize関数で画像情報を取得する list($img_width, $img_height, $mime_type, $attr) = getimagesize(画像ファイルのパスやURL); //list関数の第3引数にはgetimagesize関数で取得した画像のMIMEタイプが格納されているので条件分岐で拡張子を決定する switch($mime_type){ //jpegの場合 case IMAGETYPE_JPEG: //拡張子の設定 $img_extension = "jpg"; break; //pngの場合 case IMAGETYPE_PNG: //拡張子の設定 $img_extension = "png"; break; //gifの場合 case IMAGETYPE_GIF: //拡張子の設定 $img_extension = "gif"; break; } //拡張子の出力 echo $img_extension; ?>
今のところこれが最も自分が気に入っている方法です。
あわせて読んでほしい!
コメント
2:管理人:2015/02/19 22:28:42
貴重な情報提供ありがとうございます。
getimagesize関数によるMIMEタイプ判別の挙動は詳しく考えていませんでした。
マジックバイトからMIMEタイプを判別するなら、拡張子の偽造は防げてもマジックバイトを偽装されていたら意味がなくなりますね。
画像の横縦サイズだけでなくMIMEタイプを取得できるgetimagesize関数便利!と思ってましたが、やはり画像サイズを取得する関数は大人しく画像サイズの取得のみに使った方が無難ですね。
今後MIMEタイプの判別にはfinfo関数を使いたいと思います。
ありがとうございました。
3:名無しさん:2018/05/28 9:50:44
IMAGETYPE_JPEGやIMAGETYPE_PNGが得られるのはfile_existsでは?
getimagesizeってIMAGETYPE_JPEGとか返しましたっけ?
サイズやチャンネル、MIMETYPE(image/gifなど)を返すだけだと思うけど。
4:名無しさん:2018/05/28 9:52:36
失敬、exif_imagetypeでしたね
1:名無しさん:2015/02/19 19:26:25
getimagesize() はファイル先頭のマジックバイトからファイル形式を判定している(ような)動きをします。
ファイル先頭が"GIF"の三文字で始まるなら、中身がHTMLでも"image/gif"と返してきたからです。
しかし、そのようなファイルでも、 finfo() はきちんと"text/plain"と判定してくれました。
厳密にMIMEチェックを行うなら、どうやら finfo() などを使わざるをえないようです。。。