PHP exif_read_data() 可深度解析 JPEG/TIFF 影像內嵌的 EXIF 標籤,本文提供完整封裝函式,涵蓋檔案資訊、影像屬性、拍攝參數、版權資訊、縮略圖提取等 60+ 欄位,並處理編碼轉換與缺失值預設。
<?php
function GetImageInfo(string $imgPath): array {
// 1. 定義所有枚舉對照表(節選關鍵項)
$imgType = ['', 'GIF', 'JPG', 'PNG', 'SWF', 'PSD', 'BMP', 'TIFF(II)', 'TIFF(MM)', 'JPC', 'JP2', 'JPX'];
$orientation = ['', '左上', '右上', '右下', '左下', '左上(旋轉)', '右上(旋轉)', '右下(旋轉)', '左下(旋轉)'];
$resolutionUnit = ['', '', '英吋', '公分'];
$exposureProgram = ['未定義', '手動', '標準程式', '光圈優先', '快門優先', '景深優先', '運動', '人像', '風景'];
$meteringMode = ['0'=>'未知','1'=>'平均','2'=>'中央重點','3'=>'點測','4'=>'分區','5'=>'評估','6'=>'局部','255'=>'其他'];
$lightSource = ['0'=>'未知','1'=>'日光','2'=>'螢光燈','3'=>'鎢絲燈','10'=>'閃光燈','17'=>'標準A','18'=>'標準B','19'=>'標準C','255'=>'其他'];
$flash = ['0'=>'未閃光','1'=>'閃光','5'=>'閃光但無回波','7'=>'閃光且有回波'];
// 2. 讀取 EXIF 資料
$exif = @exif_read_data($imgPath, 0, true); // 0=所有區塊, true=關聯陣列
if ($exif === false) {
return ['錯誤' => '無 EXIF 資料或非支援格式'];
}
// 3. 結構化輸出陣列
$info = [
'檔案資訊' => '---------------------------',
'檔名' => $exif['FILE']['FileName'] ?? '未知',
'檔案類型' => $imgType[$exif['FILE']['FileType'] ?? 0] ?? '未知',
'MIME型別' => $exif['FILE']['MimeType'] ?? '未知',
'檔案大小' => ($exif['FILE']['FileSize'] ?? 0) . ' bytes',
'修改時間' => isset($exif['FILE']['FileDateTime']) ? date('Y-m-d H:i:s', $exif['FILE']['FileDateTime']) : '未知',
'影像資訊' => '---------------------------',
'圖片說明' => $exif['IFD0']['ImageDescription'] ?? '',
'製造廠' => $exif['IFD0']['Make'] ?? '',
'型號' => $exif['IFD0']['Model'] ?? '',
'方向' => $orientation[$exif['IFD0']['Orientation'] ?? 0] ?? '未知',
'水平解析度' => ($exif['IFD0']['XResolution'] ?? '') . ($resolutionUnit[$exif['IFD0']['ResolutionUnit'] ?? 0] ?? ''),
'垂直解析度' => ($exif['IFD0']['YResolution'] ?? '') . ($resolutionUnit[$exif['IFD0']['ResolutionUnit'] ?? 0] ?? ''),
'建立軟體' => $exif['IFD0']['Software'] ?? '',
'拍攝時間' => $exif['IFD0']['DateTime'] ?? '',
'作者' => $exif['IFD0']['Artist'] ?? '',
'版權' => $exif['IFD0']['Copyright'] ?? '',
'拍攝參數' => '---------------------------',
'Exif版本' => $exif['EXIF']['ExifVersion'] ?? '',
'原始拍攝時間' => $exif['EXIF']['DateTimeOriginal'] ?? '',
'數位化時間' => $exif['EXIF']['DateTimeDigitized'] ?? '',
'影像寬度' => $exif['COMPUTED']['Width'] ?? '',
'影像高度' => $exif['COMPUTED']['Height'] ?? '',
'光圈值 (APEX)' => $exif['EXIF']['ApertureValue'] ?? '',
'快門速度 (APEX)' => $exif['EXIF']['ShutterSpeedValue'] ?? '',
'實際F值' => $exif['COMPUTED']['ApertureFNumber'] ?? '',
'最大光圈' => 'F' . ($exif['EXIF']['MaxApertureValue'] ?? ''),
'曝光時間' => $exif['EXIF']['ExposureTime'] ?? '',
'F-Number' => $exif['EXIF']['FNumber'] ?? '',
'測光模式' => $meteringMode[$exif['EXIF']['MeteringMode'] ?? '0'] ?? '未知',
'光源' => $lightSource[$exif['EXIF']['LightSource'] ?? '0'] ?? '未知',
'閃光燈' => $flash[$exif['EXIF']['Flash'] ?? '0'] ?? '未知',
'曝光模式' => ($exif['EXIF']['ExposureMode'] ?? 0) == 1 ? '手動' : '自動',
'白平衡' => ($exif['EXIF']['WhiteBalance'] ?? 0) == 1 ? '手動' : '自動',
'曝光程式' => $exposureProgram[$exif['EXIF']['ExposureProgram'] ?? 0] ?? '未知',
'曝光補償' => ($exif['EXIF']['ExposureBiasValue'] ?? 0) . ' EV',
'ISO感光度' => $exif['EXIF']['ISOSpeedRatings'] ?? '',
'色彩空間' => ($exif['EXIF']['ColorSpace'] ?? 0) == 1 ? 'sRGB' : 'Uncalibrated',
'焦距' => ($exif['EXIF']['FocalLength'] ?? 0) . ' mm',
'35mm等效焦距' => ($exif['EXIF']['FocalLengthIn35mmFilm'] ?? 0) . ' mm',
'對焦距離' => ($exif['COMPUTED']['FocusDistance'] ?? 0) . ' m',
];
// 4. 縮略圖資訊
if (!empty($exif['COMPUTED']['Thumbnail.FileType'])) {
$info['縮略圖格式'] = $exif['COMPUTED']['Thumbnail.FileType'];
$info['縮略圖MIME'] = $exif['COMPUTED']['Thumbnail.MimeType'];
}
return $info;
}
?>
<?php
$img = $_GET['img'] ?? '';
if ($img && file_exists($img)) {
$exif = GetImageInfo($img);
echo '<table border="1" cellpadding="4" style="border-collapse:collapse;">';
foreach ($exif as $k => $v) {
echo "<tr><th style='background:#f0f0f0;'>$k</th><td>$v</td></tr>";
}
// 縮略圖輸出
$thumb = @exif_thumbnail($img);
if ($thumb !== false) {
echo '<tr><td colspan="2"><img src="data:' . $exif['縮略圖MIME'] . ';base64,' . base64_encode($thumb) . '" /></td></tr>';
}
echo '</table>';
} else {
echo '請提供有效圖片路徑參數 ?img=path/to.jpg';
}
?>
| 議題 | 處理方式 |
|---|---|
| APEX 單位換算 | 光圈 F值 = 2^(ApertureValue/2);快門秒數 = 2^(-ShutterSpeedValue) |
| 亮度值 (BV) 換算 EV | EV = BV + SV,SV = log2(ISO/3.125),ISO100→SV=5 |
| 元件配置解碼 | bin2hex(ComponentsConfiguration) == '01020300' → YCbCr,否則 RGB |
| 使用者註釋編碼 | 前 8 bytes 識別編碼:ASCII/JIS/Unicode/Undefined |
| 檔案來源判斷 | FileSource == 0x03 → 數位靜態相機 |
--enable-exif,且檔案為 JPEG/TIFF 格式(PNG/GIF 不支援 EXIF)。mb_convert_encoding()。exif_read_data 會完整載入檔案,超大圖建議先縮圖再讀取。此實作可直接整合至相簿系統、攝影社群、資產管理平台,完整保留影像背後的技術與創作脈絡。