こんにちは!今回は、PHPのexif_read_data
関数を使用して画像のEXIFデータを読み取る方法について詳しく解説します。
目次
- exif_read_data関数とは
- 基本的な使い方
- 取得できるEXIF情報
- 実践的な使用例
- エラーハンドリング
- セキュリティ考慮事項
1. exif_read_data関数とは
array exif_read_data ( string $filename [, string $sections = NULL
[, bool $arrays = false [, bool $thumbnail = false ]]] )
EXIFは画像ファイルに含まれるメタデータで、撮影日時、カメラの設定、位置情報などの情報が含まれています。
2. 基本的な使い方
シンプルな例
// 基本的な使用方法
$exif = exif_read_data('image.jpg');
if ($exif !== false) {
print_r($exif);
}
セクションを指定して読み取り
// 特定のセクションのみ読み取り
$exif = exif_read_data('image.jpg', 'IFD0');
3. 取得できるEXIF情報
主要な情報の取得
class ExifReader {
private $filename;
public function __construct($filename) {
$this->filename = $filename;
}
public function getBasicInfo() {
$exif = @exif_read_data($this->filename);
if ($exif === false) {
return null;
}
return [
'make' => $exif['Make'] ?? null,
'model' => $exif['Model'] ?? null,
'datetime' => $exif['DateTime'] ?? null,
'exposure' => $exif['ExposureTime'] ?? null,
'aperture' => $exif['FNumber'] ?? null,
'iso' => $exif['ISOSpeedRatings'] ?? null
];
}
public function getGPSInfo() {
$exif = @exif_read_data($this->filename, 'GPS');
if ($exif === false || !isset($exif['GPSLatitude'])) {
return null;
}
return [
'latitude' => $this->convertGPSToDecimal(
$exif['GPSLatitude'],
$exif['GPSLatitudeRef']
),
'longitude' => $this->convertGPSToDecimal(
$exif['GPSLongitude'],
$exif['GPSLongitudeRef']
)
];
}
private function convertGPSToDecimal($coord, $ref) {
$degrees = $this->convertToNumber($coord[0]);
$minutes = $this->convertToNumber($coord[1]);
$seconds = $this->convertToNumber($coord[2]);
$decimal = $degrees + $minutes/60 + $seconds/3600;
return ($ref == 'S' || $ref == 'W') ? -$decimal : $decimal;
}
private function convertToNumber($value) {
if (is_string($value)) {
$parts = explode('/', $value);
return count($parts) == 2 ? $parts[0] / $parts[1] : 0;
}
return $value;
}
}
4. 実践的な使用例
画像ギャラリーでの使用
class ImageGallery {
public function getImageMetadata($imagePath) {
try {
if (!file_exists($imagePath)) {
throw new Exception('ファイルが存在しません');
}
$exif = @exif_read_data($imagePath);
if ($exif === false) {
return [
'datetime' => null,
'camera' => null,
'settings' => null
];
}
return [
'datetime' => $exif['DateTime'] ?? null,
'camera' => [
'make' => $exif['Make'] ?? null,
'model' => $exif['Model'] ?? null
],
'settings' => [
'iso' => $exif['ISOSpeedRatings'] ?? null,
'aperture' => $exif['FNumber'] ?? null,
'exposure' => $exif['ExposureTime'] ?? null,
'focal_length' => $exif['FocalLength'] ?? null
]
];
} catch (Exception $e) {
error_log($e->getMessage());
return null;
}
}
}
位置情報を使用した例
class PhotoMapper {
public function getPhotoLocation($imagePath) {
$exif = @exif_read_data($imagePath, 'GPS');
if ($exif === false || empty($exif['GPSLatitude'])) {
return null;
}
// GPS座標を変換
$lat = $this->convertGPSCoordinate(
$exif['GPSLatitude'],
$exif['GPSLatitudeRef']
);
$lng = $this->convertGPSCoordinate(
$exif['GPSLongitude'],
$exif['GPSLongitudeRef']
);
return [
'latitude' => $lat,
'longitude' => $lng,
'maps_url' => "https://maps.google.com/?q={$lat},{$lng}"
];
}
private function convertGPSCoordinate($coord, $ref) {
// GPS座標変換ロジック
// ...
}
}
5. エラーハンドリング
class ExifHandler {
public function safeReadExif($filename) {
try {
if (!file_exists($filename)) {
throw new Exception('ファイルが存在しません');
}
if (!is_readable($filename)) {
throw new Exception('ファイルを読み取れません');
}
$exif = @exif_read_data($filename);
if ($exif === false) {
throw new Exception('EXIFデータを読み取れません');
}
return $exif;
} catch (Exception $e) {
error_log("EXIF読み取りエラー: " . $e->getMessage());
return null;
}
}
}
6. セキュリティ考慮事項
プライバシー保護
class PrivacyAwareExifReader {
private $sensitiveKeys = [
'GPSLatitude',
'GPSLongitude',
'GPSLatitudeRef',
'GPSLongitudeRef'
];
public function getPublicExif($filename) {
$exif = exif_read_data($filename);
if ($exif === false) {
return null;
}
// センシティブな情報を削除
foreach ($this->sensitiveKeys as $key) {
if (isset($exif[$key])) {
unset($exif[$key]);
}
}
return $exif;
}
}
ファイルタイプの検証
class SecureExifReader {
private $allowedTypes = [
IMAGETYPE_JPEG,
IMAGETYPE_TIFF_II,
IMAGETYPE_TIFF_MM
];
public function readExif($filename) {
$type = @exif_imagetype($filename);
if (!in_array($type, $this->allowedTypes)) {
throw new Exception('サポートされていないファイル形式です');
}
return exif_read_data($filename);
}
}
まとめ
exif_read_data関数使用のポイント:
- エラーハンドリングを適切に行う
- プライバシーに関わる情報の取り扱いに注意
- ファイルの存在確認と読み取り権限の確認
- サポートされているファイル形式の確認
- 返値のnullチェックを忘れずに
これらの点に注意を払うことで、安全で効果的なEXIF情報の取り扱いが可能になります。