Exif 信息读取
PHP 的 Exif 扩展用于读取 JPEG 和 TIFF 图像文件中的 EXIF 元数据。EXIF 数据由数码相机拍摄时自动嵌入,包含拍摄时间、相机型号、光圈、快门速度、GPS 坐标等信息,广泛应用于照片管理和地理标记。
前置知识
阅读本节前,建议先了解:GD 图像处理
基础概念
安装
bash
# 编译安装
./configure --enable-exif
# Ubuntu/Debian
sudo apt-get install php-exif
// php.ini
// exif.encode_unicode = ISO-8859-15
// exif.decode_unicode_motorola = UCS-2BE
// exif.decode_unicode_intel = UCS-2LE
// exif.decode_jis_motorola = JIS
// exif.decode_jis_intel = JIS读取 EXIF 数据
基本读取
php
<?php
declare(strict_types=1);
/**
* 读取 JPEG 文件的 EXIF 信息
*/
function readExif(string $filePath): array
{
if (!file_exists($filePath)) {
throw new RuntimeException("文件不存在: {$filePath}");
}
// exif_read_data 读取 EXIF
$exif = @exif_read_data($filePath, 'ANY_TAG', true);
if ($exif === false) {
throw new RuntimeException("无法读取 EXIF 数据");
}
return $exif;
}
// 使用示例
// $exif = readExif('/path/to/photo.jpg');
// print_r($exif);常用 EXIF 字段
php
<?php
declare(strict_types=1);
function getPhotoInfo(string $filePath): array
{
$exif = @exif_read_data($filePath, 'ANY_TAG', true);
if ($exif === false) {
return [];
}
return [
// 文件信息
'file_name' => basename($filePath),
'file_type' => $exif['FILE']['MimeType'] ?? '',
'file_size' => filesize($filePath),
'file_width' => $exif['COMPUTED']['Width'] ?? 0,
'file_height' => $exif['COMPUTED']['Height'] ?? 0,
// 拍摄信息
'camera' => ($exif['IFD0']['Make'] ?? '') . ' ' . ($exif['IFD0']['Model'] ?? ''),
'date_time' => $exif['EXIF']['DateTimeOriginal'] ?? ($exif['IFD0']['DateTime'] ?? ''),
// 拍摄参数
'exposure' => $exif['EXIF']['ExposureTime'] ?? '',
'f_number' => $exif['COMPUTED']['ApertureFNumber'] ?? '',
'iso' => $exif['EXIF']['ISOSpeedRatings'] ?? '',
'focal_length' => $exif['EXIF']['FocalLength'] ?? '',
'shutter' => $exif['EXIF']['ExposureTime'] ?? '',
// 方向
'orientation' => $exif['IFD0']['Orientation'] ?? 1,
// 软件
'software' => $exif['IFD0']['Software'] ?? '',
// GPS
'gps_latitude' => $exif['GPS']['GPSLatitude'] ?? null,
'gps_longitude' => $exif['GPS']['GPSLongitude'] ?? null,
];
}
// 使用示例
// $info = getPhotoInfo('/path/to/photo.jpg');
// echo "相机: {$info['camera']}" . PHP_EOL;
// echo "拍摄时间: {$info['date_time']}" . PHP_EOL;
// echo "ISO: {$info['iso']}" . PHP_EOL;GPS 坐标提取
php
<?php
declare(strict_types=1);
/**
* 从 EXIF GPS 数据中提取经纬度
*/
function getGpsCoordinates(string $filePath): ?array
{
$exif = @exif_read_data($filePath, 'ANY_TAG', true);
if (!isset($exif['GPS']['GPSLatitude'], $exif['GPS']['GPSLongitude'])) {
return null;
}
$latDms = $exif['GPS']['GPSLatitude'];
$lngDms = $exif['GPS']['GPSLongitude'];
$latRef = $exif['GPS']['GPSLatitudeRef'] ?? 'N';
$lngRef = $exif['GPS']['GPSLongitudeRef'] ?? 'E';
// 转换 DMS(度分秒)为十进制
$latitude = $this->dmsToDecimal($latDms[0], $latDms[1], $latDms[2]);
$longitude = $this->dmsToDecimal($lngDms[0], $lngDms[1], $lngDms[2]);
if ($latRef === 'S') {
$latitude = -$latitude;
}
if ($lngRef === 'W') {
$longitude = -$longitude;
}
return [
'latitude' => $latitude,
'longitude' => $longitude,
];
}
function dmsToDecimal(float $degrees, float $minutes, float $seconds): float
{
return $degrees + ($minutes / 60) + ($seconds / 3600);
}
// 使用示例
// $coords = getGpsCoordinates('/path/to/photo.jpg');
// if ($coords !== null) {
// echo "纬度: {$coords['latitude']}" . PHP_EOL;
// echo "经度: {$coords['longitude']}" . PHP_EOL;
// }图像方向修正
php
<?php
declare(strict_types=1);
/**
* 根据 EXIF 方向信息旋转图片
*/
function fixOrientation(string $filePath, string $outputPath): void
{
$exif = @exif_read_data($filePath);
if ($exif === false) {
return;
}
$orientation = $exif['IFD0']['Orientation'] ?? 1;
$image = imagecreatefromjpeg($filePath);
match ($orientation) {
3 => imagerotate($image, 180, 0),
6 => imagerotate($image, -90, 0),
8 => imagerotate($image, 90, 0),
default => null,
};
imagejpeg($image, $outputPath, 90);
imagedestroy($image);
}注意事项
exif_read_data()仅支持 JPEG 和 TIFF 格式- 需要
mbstring扩展处理 Unicode 字符 - 读取用户上传的 EXIF 数据时注意隐私保护
下一节
继续学习:intl 扩展