[PHP]画像処理:exif_read_data関数の完全ガイド – 画像メタデータの読み取り方法

PHP

こんにちは!今回は、PHPのexif_read_data関数を使用して画像のEXIFデータを読み取る方法について詳しく解説します。

目次

  1. exif_read_data関数とは
  2. 基本的な使い方
  3. 取得できるEXIF情報
  4. 実践的な使用例
  5. エラーハンドリング
  6. セキュリティ考慮事項

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関数使用のポイント:

  1. エラーハンドリングを適切に行う
  2. プライバシーに関わる情報の取り扱いに注意
  3. ファイルの存在確認と読み取り権限の確認
  4. サポートされているファイル形式の確認
  5. 返値のnullチェックを忘れずに

これらの点に注意を払うことで、安全で効果的なEXIF情報の取り扱いが可能になります。

タイトルとURLをコピーしました