マジックバイトとは
多くのファイル形式は、ファイルの先頭部分に固定のバイト列(シグネチャ)を持ちます。このバイト列を「マジックバイト」または「ファイルシグネチャ」と呼びます。OSやアプリケーションはこのシグネチャを見てファイルの種類を判定します。拡張子は容易に偽装できますが、マジックバイトはバイナリレベルの識別子のため、ファイルバリデーションの信頼性が高まります。
Linuxの file コマンドや、PHPの finfo クラスはこの仕組みを使ってMIMEタイプを判定しています。
画像ファイル
| 形式 | 拡張子 | マジックバイト(16進数) | ASCII表現 | オフセット |
| PNG | .png | 89 50 4E 47 0D 0A 1A 0A | ‰PNG\r\n\x1a\n | 0 |
| JPEG | .jpg/.jpeg | FF D8 FF | — | 0 |
| GIF87a | .gif | 47 49 46 38 37 61 | GIF87a | 0 |
| GIF89a | .gif | 47 49 46 38 39 61 | GIF89a | 0 |
| WebP | .webp | 52 49 46 46 ?? ?? ?? ?? 57 45 42 50 | RIFF????WEBP | 0 |
| BMP | .bmp | 42 4D | BM | 0 |
| TIFF(リトルエンディアン) | .tiff/.tif | 49 49 2A 00 | II*\0 | 0 |
| TIFF(ビッグエンディアン) | .tiff/.tif | 4D 4D 00 2A | MM\0* | 0 |
| AVIF / HEIF | .avif/.heif | 66 74 79 70 | ftyp | 4 |
| ICO | .ico | 00 00 01 00 | — | 0 |
| SVG | .svg | <?xml または <svg | テキスト | 0(BOMなし) |
ドキュメント・アーカイブ
| 形式 | 拡張子 | マジックバイト(16進数) | 備考 |
| PDF | .pdf | 25 50 44 46 2D | %PDF- |
| ZIP | .zip | 50 4B 03 04 | PK\x03\x04 |
| ZIP(空ファイル) | .zip | 50 4B 05 06 | — |
| GZIP | .gz | 1F 8B | — |
| 7-Zip | .7z | 37 7A BC AF 27 1C | 7z\xBC\xAF'\x1C |
| RAR4 | .rar | 52 61 72 21 1A 07 00 | Rar!\x1A\x07\x00 |
| RAR5 | .rar | 52 61 72 21 1A 07 01 00 | — |
| TAR | .tar | 75 73 74 61 72 | ustar(オフセット257) |
| DOCX / XLSX / PPTX | .docx等 | 50 4B 03 04 | ZIPベース(拡張子で区別) |
| XLS(旧形式) | .xls | D0 CF 11 E0 A1 B1 1A E1 | OLE2 コンテナ |
| DOC(旧形式) | .doc | D0 CF 11 E0 A1 B1 1A E1 | OLE2 コンテナ |
テキスト・データ形式
| 形式 | 拡張子 | マジックバイト / BOM | 備考 |
| UTF-8 BOM付き | .txt/.csv等 | EF BB BF | BOM(Byte Order Mark) |
| UTF-16 LE BOM | .txt等 | FF FE | リトルエンディアン |
| UTF-16 BE BOM | .txt等 | FE FF | ビッグエンディアン |
| UTF-32 LE BOM | .txt等 | FF FE 00 00 | — |
| JSON(通常) | .json | 7B または 5B | { または [ |
| CSV(通常) | .csv | テキスト(BOMなし) | シグネチャなし |
| XML | .xml | 3C 3F 78 6D 6C | <?xml |
音声・動画
| 形式 | 拡張子 | マジックバイト(16進数) | 備考 |
| MP3 | .mp3 | FF FB / FF F3 / FF F2 | またはID3タグ: 49 44 33 |
| MP4 / M4A / M4V | .mp4等 | 66 74 79 70 | ftyp(オフセット4) |
| WAV | .wav | 52 49 46 46 ?? ?? ?? ?? 57 41 56 45 | RIFF????WAVE |
| OGG | .ogg/.ogv | 4F 67 67 53 | OggS |
| FLAC | .flac | 66 4C 61 43 | fLaC |
| AVI | .avi | 52 49 46 46 ?? ?? ?? ?? 41 56 49 20 | RIFF????AVI |
| MKV / WebM | .mkv/.webm | 1A 45 DF A3 | EBML ヘッダー |
実行ファイル・その他
| 形式 | 拡張子 | マジックバイト(16進数) | 備考 |
| ELF(Linux実行ファイル) | なし/.elf | 7F 45 4C 46 | \x7FELF |
| PE(Windows実行ファイル) | .exe/.dll | 4D 5A | MZ |
| Mach-O(macOS実行ファイル) | なし | CF FA ED FE | 64bit |
| PHP スクリプト | .php | 3C 3F 70 68 70 | <?php |
| SQLite | .sqlite/.db | 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00 | SQLite format 3\0 |
| ISO | .iso | 43 44 30 30 31 | オフセット32769: CD001 |
PHP でのマジックバイト検証の実装例
['offset' => 0, 'bytes' => "\x89PNG\r\n\x1a\n", 'length' => 8],
'jpg' => ['offset' => 0, 'bytes' => "\xFF\xD8\xFF", 'length' => 3],
'gif' => ['offset' => 0, 'bytes' => "GIF8", 'length' => 4],
'pdf' => ['offset' => 0, 'bytes' => "%PDF-", 'length' => 5],
'zip' => ['offset' => 0, 'bytes' => "PK\x03\x04", 'length' => 4],
'exe' => ['offset' => 0, 'bytes' => "MZ", 'length' => 2],
];
if (!isset($signatures[$expectedType])) {
throw new \InvalidArgumentException("未知のファイルタイプ: $expectedType");
}
$sig = $signatures[$expectedType];
$handle = fopen($filePath, 'rb');
if ($sig['offset'] > 0) fseek($handle, $sig['offset']);
$header = fread($handle, $sig['length']);
fclose($handle);
if (substr($header, 0, $sig['length']) !== $sig['bytes']) {
throw new \RuntimeException("マジックバイトが一致しません(期待: $expectedType)");
}
}
// 使用例
validateMagicBytes($_FILES['upload']['tmp_name'], 'png');
echo "正当なPNGファイルです";
関連リソース