《PHP8上級試験対策》mime_content_type()が拡張子を無視する理由

  • URLをコピーしました!

はじめに

PHPのファイル操作でたびたび登場する mime_content_type() 関数。
一見すると「拡張子で判定しているのでは?」と思いがちですが、実際はファイルの中身(バイナリ)からMIMEタイプを推定しています。
そのため、image.gif にリネームしたJPEGファイルを読み込んでも、結果は "image/jpeg" になります。
この挙動の理由を、実際のコードとマジックナンバーの仕組みを交えて解説します。

キーワード: mime_content_type / fileinfo / MIMEタイプ / マジックナンバー / 拡張子の影響

目次

📘 mime_content_type() の基本仕様

mime_content_type(resource|string $filename): string|false

指定したファイルの MIME Content-Type を返します。
たとえば JPEG 画像なら "image/jpeg", PNG なら "image/png" が返ります。

🧪 実験:JPEGファイルを「image.gif」にリネームして判定

<?php
declare(strict_types=1);
error_reporting(-1);

var_dump(mime_content_type(__DIR__ . '/image.gif'));

この image.gif は実際には JPEG ファイルです。
実行結果は次のとおり:

string(10) "image/jpeg"

👀 結果は「image/jpeg」!

⚙️ なぜ拡張子を無視して正しく判定できるのか?

mime_content_type() は内部的に ファイルの先頭バイト(マジックナンバー) を読み取り、そこからファイル種別を推定します。

🧩 マジックナンバーの仕組み(図解)

+------------------------------------------------------+
| ファイルの先頭部分(バイナリデータ)                       |
+------------------------------------------------------+
| FF D8 FF E0 ...  → JPEG (image/jpeg)                 |
| 89 50 4E 47 ...  → PNG  (image/png)                  |
| 47 49 46 38 ...  → GIF  (image/gif)                  |
+------------------------------------------------------+

拡張子をいくら変えても、中身のマジックナンバーがJPEGであれば 「image/jpeg」 と判定されます。

💡 より強力な代替:finfo_file()

同じ仕組みをより正確に扱えるのが finfo ファミリの関数です。

$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, __DIR__ . '/image.gif'); // image/jpeg
finfo_close($finfo);

こちらのほうが、文字コード情報なども取得でき、上位互換的な使い方ができます。

❌ よくある誤解

誤解正しい理解
mime_content_type() は拡張子を見て判断しているファイルの中身を見て判断している
ファイル名を変えれば MIME タイプも変わる中身が変わらなければ MIME タイプは変わらない

✅ まとめ

項目内容
関数mime_content_type()
判定基準ファイルの中身(マジックナンバー)
拡張子変更の影響なし
実行結果 "image/jpeg"正しい挙動!

🧠 試験ポイントメモ

  • mime_content_type()fileinfo拡張に依存している
  • 拡張子ではなく中身で判定する
  • finfo_file() が後継として推奨されている

この記事が気に入ったら
いいねしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次