PHP 內建 exif_imagetype() 與 getimagesize() 可快速判斷圖片類型,無需完整載入圖片資料。本文說明常用函數、回傳值常數、實戰範例與安全性注意事項。
| 函數 | 回傳值 | 特點 |
|---|---|---|
exif_imagetype(string $file) | int (IMAGETYPE_* 常數) | 僅讀取檔頭,極快,需 exif 擴充 |
getimagesize(string $file, array &$info) | array [width, height, type, attr] | 回傳尺寸與類型,標準擴充即可用 |
mime_content_type(string $file) | string (MIME type) | 基於 magic 資料庫,適用一般檔案 |
| 常數 | 值 | 格式 | MIME |
|---|---|---|---|
| IMAGETYPE_GIF | 1 | GIF | image/gif |
| IMAGETYPE_JPEG | 2 | JPEG | image/jpeg |
| IMAGETYPE_PNG | 3 | PNG | image/png |
| IMAGETYPE_SWF | 4 | Flash | application/x-shockwave-flash |
| IMAGETYPE_PSD | 5 | Photoshop | image/vnd.adobe.photoshop |
| IMAGETYPE_BMP | 6 | BMP | image/bmp |
| IMAGETYPE_TIFF_II / _MM | 7/8 | TIFF (little/big endian) | image/tiff |
| IMAGETYPE_JPC | 9 | JPEG 2000 | image/jp2 |
| IMAGETYPE_JP2 | 10 | JPEG 2000 | image/jp2 |
| IMAGETYPE_JPX | 11 | JPEG 2000 延伸 | image/jpx |
| IMAGETYPE_JB2 | 12 | JBIG2 | image/jb2 |
| IMAGETYPE_SWC | 13 | Flash (壓縮) | application/x-shockwave-flash |
| IMAGETYPE_IFF | 14 | IFF | image/iff |
| IMAGETYPE_WBMP | 15 | Wireless BMP | image/vnd.wap.wbmp |
| IMAGETYPE_XBM | 16 | XBM | image/x-xbm |
| IMAGETYPE_ICO | 17 | ICO | image/vnd.microsoft.icon |
| IMAGETYPE_WEBP | 18 | WebP | image/webp |
$allowed = [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF];
$type = exif_imagetype($_FILES['avatar']['tmp_name']);
if (!in_array($type, $allowed, true)) {
die('只允許上傳 JPG、PNG、GIF 圖片');
}
// 取得副檔名
$ext = image_type_to_extension($type, false); // ".jpeg", ".png", ".gif"
$saveName = 'avatar_' . time() . $ext;
move_uploaded_file($_FILES['avatar']['tmp_name'], $saveName);
$info = getimagesize('photo.jpg');
if ($info !== false) {
list($width, $height, $type, $attr) = $info;
$mime = $info['mime']; // image/jpeg
echo "{$width}x{$height}, {$mime}";
}
$url = 'https://example.com/banner.png';
$type = @exif_imagetype($url); // 需 allow_url_fopen=On
if ($type === false) {
// 可能非圖片、無法存取、或非支援格式
}
shell.php.jpg 實為 PHP 腳本 → 必須用檔頭判斷getimagesize() 可能觸發 XXE/SSRF(處理 SVG 等) → 禁止處理向量格式$_FILES['size']、設定 upload_max_filesizephoto.jpg.exe → 儲存時強制使用檔頭推斷副檔名// 1. 檢查檔案大小
if ($_FILES['img']['size'] > 5 * 1024 * 1024) die('檔案過大');
// 2. 檢查檔頭類型
$type = exif_imagetype($_FILES['img']['tmp_name']);
$allowed = [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_WEBP];
if (!in_array($type, $allowed, true)) die('不支援的圖片格式');
// 3. 取得安全副檔名
$ext = image_type_to_extension($type, false);
// 4. 重新命名儲存(避免覆蓋、路徑遍歷)
$dest = '/var/www/uploads/' . bin2hex(random_bytes(16)) . $ext;
move_uploaded_file($_FILES['img']['tmp_name'], $dest);
// 5. (可選) 重新壓縮/去除 EXIF,進一步降低風險
$img = imagecreatefromstring(file_get_contents($dest));
// ... 處理後存回
正確判斷圖片類型是檔案上傳安全的第一道防線。請務必使用 exif_imagetype() 或 getimagesize() 檢查檔頭,拒絕信任副檔名與瀏覽器回報的 MIME,並搭配重新命名、尺寸限制、權限隔離等纵深防禦措施。