Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Exif Laravel Package

miljar/php-exif

PHPExif is a PHP library for reading image metadata (EXIF/IPTC) through a clean, standard API. It wraps native PHP functions like exif_read_data and iptcparse, and supports the ExifTool CLI adapter for broader metadata extraction.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require miljar/php-exif
    

    Publish the config (if needed):

    php artisan vendor:publish --tag=exif-config
    
  2. Basic Usage:

    use Miljar\PhpExif\Exif;
    
    $exif = new Exif(storage_path('app/image.jpg'));
    $data = $exif->getData();
    
    // Check if EXIF data exists
    if ($data !== false) {
        dd($data['EXIF']['DateTimeOriginal']); // Output: "2023:05:15 14:30:00"
    }
    
  3. First Use Case: Extract GPS coordinates from an uploaded image:

    $exif = new Exif($request->file('photo')->path());
    $gps = $exif->getGPS();
    if ($gps) {
        $latitude = $gps['Latitude'];
        $longitude = $gps['Longitude'];
        // Store in database or use for geocoding
    }
    

Where to Look First

  • Config File: config/exif.php (check fallback_to_exiftool and exiftool_path).
  • Documentation: v0.3.0+ Usage Guide (covers data structure and normalization).
  • Examples: Review the unit tests for real-world usage patterns.

Implementation Patterns

Core Workflows

1. Single Image Processing

// In a controller or service
public function processImage($imagePath)
{
    $exif = new Exif($imagePath);
    $metadata = $exif->getData();

    if ($metadata !== false) {
        // Normalized data (e.g., ExposureTime in seconds)
        $exposureTime = $metadata['EXIF']['ExposureTime'] ?? null;
        $this->saveMetadata($exposureTime);
    }
}

2. Batch Processing with Queues

// app/Jobs/ExtractExifJob.php
public function handle()
{
    $image = Image::find($this->imageId);
    $exif = new Exif($image->path);
    $data = $exif->getData();

    if ($data !== false) {
        $image->update(['exif_data' => json_encode($data)]);
    }
}

// Dispatch job
ExtractExifJob::dispatch($image);

3. Fallback to Exiftool

Configure in config/exif.php:

'fallback_to_exiftool' => env('EXIF_USE_EXIFTOOL', true),
'exiftool_path' => '/usr/local/bin/exiftool',

Usage remains identical—library handles the fallback automatically.


Integration Tips

Laravel-Specific Patterns

  1. Service Provider:

    // app/Providers/ExifServiceProvider.php
    public function register()
    {
        $this->app->singleton(Exif::class, function ($app) {
            return new Exif(config('exif.default_path'));
        });
    }
    
  2. Model Observers:

    // app/Observers/ImageObserver.php
    public function saved(Image $image)
    {
        $exif = app(Exif::class)->setPath($image->path)->getData();
        if ($exif) $image->exif_data = json_encode($exif);
    }
    
  3. Artisan Command:

    // app/Console/Commands/ExtractAllExif.php
    public function handle()
    {
        $images = Image::all();
        foreach ($images as $image) {
            $exif = new Exif($image->path);
            $image->update(['exif_data' => $exif->getData()]);
        }
    }
    

Data Normalization

Leverage the library’s built-in normalization (e.g., ExposureTime converted to seconds):

$data = $exif->getData();
$normalizedExposure = $data['EXIF']['ExposureTime'] ?? 0; // Returns float (e.g., 0.004 for 1/250s)

GPS Handling

Extract and parse GPS coordinates:

$gps = $exif->getGPS();
if ($gps) {
    $latitude = $gps['Latitude'] . ' ' . $gps['LatitudeRef'];
    $longitude = $gps['Longitude'] . ' ' . $gps['LongitudeRef'];
    // Use with Laravel Geocoding or Google Maps API
}

Gotchas and Tips

Pitfalls

  1. False Positives/Negatives:

    • getData() returns false if no EXIF data exists (not null or an empty array).
    • Fix: Always check if ($data !== false).
    • Example:
      $data = $exif->getData();
      if ($data === false) {
          Log::warning('No EXIF data found in', ['path' => $imagePath]);
      }
      
  2. Exiftool Dependency:

    • If fallback_to_exiftool is true but exiftool is missing, the library throws a RuntimeException.
    • Fix: Set fallback_to_exiftool to false or ensure exiftool is installed/accessible.
    • Docker Tip: Add exiftool to your Dockerfile:
      RUN apt-get update && apt-get install -y libimage-exiftool-perl
      
  3. Encoding Issues:

    • Older versions (pre-v0.6.0) had encoding bugs with non-ASCII metadata.
    • Fix: Update to v0.6.0+ or manually decode strings:
      $rawData = $exif->getRawData();
      $decoded = mb_convert_encoding($rawData, 'UTF-8', 'auto');
      
  4. GPS Zero-Degree Coordinates:

    • Some cameras store 0/1 for GPS coordinates (e.g., Latitude=0/1 means 0° 0' 0").
    • Fix: Use the library’s built-in getGPS() method, which normalizes this.
  5. Memory Limits:

    • Processing large batches (e.g., 1000+ images) may hit memory limits.
    • Fix: Process in chunks or use queues:
      foreach (Image::chunk(100) as $chunk) {
          foreach ($chunk as $image) {
              $exif = new Exif($image->path);
              // ...
          }
      }
      

Debugging Tips

  1. Inspect Raw Data:

    $rawData = $exif->getRawData();
    dd($rawData); // Debug unnormalized EXIF/IPTC data
    
  2. Check Exiftool Output: Run manually to compare:

    exiftool -json image.jpg
    
  3. Log Fallbacks:

    try {
        $data = $exif->getData();
    } catch (\RuntimeException $e) {
        Log::error('EXIF fallback failed: ' . $e->getMessage());
        // Fallback to native PHP
        $data = exif_read_data($imagePath);
    }
    
  4. Validate GPS: Ensure GPS data is valid before processing:

    $gps = $exif->getGPS();
    if (!$gps || empty($gps['Latitude'])) {
        Log::warning('Invalid GPS data in', ['path' => $imagePath]);
    }
    

Extension Points

  1. Custom Data Mappers: Extend the library’s mapping logic (see v0.4.0 changes):

    // app/Services/CustomExifMapper.php
    use Miljar\PhpExif\Mapping\ExifMapper;
    
    class CustomExifMapper extends ExifMapper
    {
        protected function mapExposureTime($value)
        {
            return (float) $value; // Custom normalization
        }
    }
    
  2. Add New Tag Support: Extend the Exif class to handle unsupported tags:

    // app/Services/ExtendedExif.php
    class ExtendedExif extends \Miljar\PhpExif\Exif
    {
        public function getCustomTag($tagName)
        {
            $raw = $this->getRawData();
            return $raw['CustomTags'][$tagName] ?? null;
        }
    }
    
  3. Queue Job for Async Processing:

    // app/Jobs/ExtractEx
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours