Esempio n. 1
0
 /**
  * @param SplFileInfo $file
  * @return bool
  */
 private function load(SplFileInfo $file)
 {
     try {
         $this->exifData = $this->exif->read($file->getRealPath());
         $this->date = $this->exifData->getCreationDate();
     } catch (\RuntimeException $e) {
         // do nothing
     }
 }
Esempio n. 2
0
 /**
  * @return ExifReader
  */
 private static function instance()
 {
     if (self::$instance === null) {
         self::$instance = ExifReader::factory(ExifReader::TYPE_NATIVE);
     }
     return self::$instance;
 }
 /**
  * @return ReaderInterface
  */
 protected function getInstance()
 {
     if (!isset($this->instance)) {
         $this->instance = Reader::factory($this->type);
     }
     return $this->instance;
 }
Esempio n. 4
0
 public function boot()
 {
     FileBase::extend(function ($model) {
         $model->hasOne['exif'] = ['Hambern\\Exify\\Models\\Exif', 'delete' => true];
     });
     FileBase::extend(function ($model) {
         $model->bindEvent('model.afterCreate', function () use($model) {
             if (strpos($model->content_type, 'image') !== false) {
                 $reader = Reader::factory(Reader::TYPE_NATIVE);
                 $path = 'http://' . $_SERVER['SERVER_NAME'] . $model->path;
                 $data = $reader->read($path)->getData();
                 foreach ($data as $k => $v) {
                     $fill[snake_case($k)] = $v;
                 }
                 $exif = Exif::make($fill);
                 $model->exif()->save($exif);
             }
         });
         $model->bindEvent('model.beforeDelete', function () use($model) {
             if (strpos($model->content_type, 'image') !== false) {
                 $model->exif()->delete();
             }
         });
     });
 }
 /**
  * Crops avatar image to square and corrects orientation.
  *
  * @return void
  */
 private function cropAvatar()
 {
     // Image manipulation class part of codesleeve/laravel-stapler.
     $imagine = new Imagine();
     // Gets full path of uploaded avatar, creates Imagine object to manipulate image.
     $avatarPath = \Auth::user()->avatar->url();
     $image = $imagine->open(public_path() . $avatarPath);
     // Reads EXIF data with a wrapper around native exif_read_data() PHP function.
     $reader = Reader::factory(Reader::TYPE_NATIVE);
     $exifData = $reader->getExifFromFile(public_path() . $avatarPath)->getRawData();
     $width = NULL;
     $height = NULL;
     if (array_key_exists('ExifImageWidth', $exifData) && array_key_exists('ExifImageLength')) {
         $width = $exifData['ExifImageWidth'];
         $height = $exifData['ExifImageLength'];
     } else {
         if (array_key_exists('COMPUTED', $exifData)) {
             $width = $exifData['COMPUTED']['Width'];
             $height = $exifData['COMPUTED']['Height'];
         } else {
             return false;
         }
     }
     // Crops off top and  bottom for tall images.
     if ($height > $width) {
         $start = ($height - $width) / 2;
         $image->crop(new Point(0, $start), new Box($width, $width));
     } else {
         $start = ($width - $height) / 2;
         $image->crop(new Point($start, 0), new Box($height, $height));
     }
     // In case image does not have all EXIF data, including orientation.
     // Setting EXIF orientation to 1 stores the image as it is originally
     // oriented.
     if (!array_key_exists('Orientation', $exifData)) {
         $exifData['Orientation'] = 1;
     }
     // Adjusts orientation depending on EXIF orientation data.
     switch ($exifData['Orientation']) {
         // Rotates image if it is upside down.
         case 3:
             $image->rotate(180);
             break;
             // Rotates image 90 degrees to the right.
         // Rotates image 90 degrees to the right.
         case 6:
             $image->rotate(90);
             break;
             // Rotates image 90 degrees to the left.
         // Rotates image 90 degrees to the left.
         case 8:
             $image->rotate(-90);
             break;
     }
     // Replaces original avatar and ensures previous image is deleted.
     File::delete(public_path() . $avatarPath);
     $image->save(public_path() . $avatarPath);
     return true;
 }
Esempio n. 6
0
 /**
  * Get an array with the dimensions of an image, together with its
  * aspectratio and some other info.
  *
  * @param string  $filename
  * @param boolean $safe
  *
  * @return array Specifics
  */
 public function imageInfo($filename, $safe)
 {
     // This function is vulnerable to path traversal, so blocking it in
     // safe mode for now.
     if ($safe) {
         return null;
     }
     $fullpath = sprintf('%s/%s', $this->app['resources']->getPath('filespath'), $filename);
     if (!is_readable($fullpath) || !is_file($fullpath)) {
         return false;
     }
     $types = array(0 => 'unknown', 1 => 'gif', 2 => 'jpeg', 3 => 'png', 4 => 'swf', 5 => 'psd', 6 => 'bmp');
     // Get the dimensions of the image
     $imagesize = getimagesize($fullpath);
     // Get the aspectratio
     if ($imagesize[1] > 0) {
         $ar = $imagesize[0] / $imagesize[1];
     } else {
         $ar = 0;
     }
     $info = array('width' => $imagesize[0], 'height' => $imagesize[1], 'type' => $types[$imagesize[2]], 'mime' => $imagesize['mime'], 'aspectratio' => $ar, 'filename' => $filename, 'fullpath' => realpath($fullpath), 'url' => str_replace('//', '/', $this->app['resources']->getUrl('files') . $filename));
     /** @var $reader \PHPExif\Reader\Reader */
     $reader = ExifReader::factory(ExifReader::TYPE_NATIVE);
     try {
         // Get the EXIF data of the image
         $exif = $reader->read($fullpath);
     } catch (\RuntimeException $e) {
         // No EXIF data… create an empty object.
         $exif = new Exif();
     }
     // GPS coordinates
     $gps = $exif->getGPS();
     $gps = explode(',', $gps);
     // If the picture is turned by exif, ouput the turned aspectratio
     if (in_array($exif->getOrientation(), array(6, 7, 8))) {
         $exifturned = $imagesize[1] / $imagesize[0];
     } else {
         $exifturned = $ar;
     }
     // Output the relevant EXIF info
     $info['exif'] = array('latitude' => isset($gps[0]) ? $gps[0] : false, 'longitude' => isset($gps[1]) ? $gps[1] : false, 'datetime' => $exif->getCreationDate(), 'orientation' => $exif->getOrientation(), 'aspectratio' => $exifturned ?: false);
     // Landscape if aspectratio > 5:4
     $info['landscape'] = $ar >= 1.25 ? true : false;
     // Portrait if aspectratio < 4:5
     $info['portrait'] = $ar <= 0.8 ? true : false;
     // Square-ish, if neither portrait or landscape
     $info['square'] = !$info['landscape'] && !$info['portrait'];
     return $info;
 }
Esempio n. 7
0
 /**
  * Get an EXIF object.
  *
  * @return \PHPExif\Exif
  */
 protected function getExif()
 {
     /** @var $reader \PHPExif\Reader\Reader */
     $reader = ExifReader::factory(ExifReader::TYPE_NATIVE);
     try {
         // Get the EXIF data of the image
         $exif = $reader->read($this->fullpath);
     } catch (\RuntimeException $e) {
         // No EXIF data… create an empty object.
         $exif = new Exif();
     }
     return $exif;
 }
 /**
  * Execute the console command.
  *
  * @return mixed
  */
 public function handle()
 {
     //for reporting
     $reporting = [];
     $reporting['photo-but-no-metadata-date'] = 0;
     $reporting['photo-but-corrupt-metadata-date'] = 0;
     $reporting['probably-not-a-photo'] = 0;
     $reporting['photos-renamed-for-copy-to-destination'] = 0;
     $reporting['photos-clobbered-for-copy-to-destination'] = 0;
     //get the inputs
     $sourceFolder = $this->argument('sourcefolder');
     $destinationFolder = $this->argument('destinationfolder');
     $createOnlyContentfulFolders = $this->option('create-only-contentful-folders');
     //support for this is TODO
     $createDayFolders = $this->option('create-day-folders');
     $priorityDateForSort = $this->option('priority-date-for-sort');
     $onDuplicate = $this->option('on-duplicate');
     $separateVideosAndPhotos = $this->option('separate-videos-and-photos');
     //----input sanity checks----------------------------------------------
     //set allowed options for --priority-date-for-sort (-p)
     $allowedPriorityDateForSort = ['metadata', 'filemodified'];
     //check option passed for --priority-date-for-sort (-p) is allowed
     if (!in_array($priorityDateForSort, $allowedPriorityDateForSort)) {
         $this->error('--priority-date-for-sort (-p) must be one of ' . implode(', ', $allowedPriorityDateForSort));
         exit(1);
         //non-zero
     }
     //set allowed options for --on-duplicate (-o)
     $allowedOnDuplicate = ['rename', 'clobber'];
     //check option passed for --on-duplicate (-o) is allowed
     if (!in_array($onDuplicate, $allowedOnDuplicate)) {
         $this->error('--on-duplicate (-o) must be one of ' . implode(', ', $allowedOnDuplicate));
         exit(1);
         //non-zero
     }
     //check $sourceFolder and $destinationFolder look and smell like folders
     //if(!is_dir($sourceFolder) or !is_dir($destinationFolder))
     if (!Storage::has($sourceFolder) or !Storage::has($destinationFolder)) {
         $this->error('Please ensure that sourcefolder and destinationfolder are actually folders');
         exit(1);
         //non-zero
     }
     //----/end input sanity checks-----------------------------------------
     // reader with Native adapter
     $reader = \PHPExif\Reader\Reader::factory(\PHPExif\Reader\Reader::TYPE_NATIVE);
     // reader with Exiftool adapter
     //$reader = \PHPExif\Reader\Reader::factory(\PHPExif\Reader\Reader::TYPE_EXIFTOOL);
     //$exif = $reader->read('/path/to/file');
     $files = Storage::allFiles($sourceFolder);
     $bar = $this->output->createProgressBar(count($files));
     //$counter = 1;
     foreach ($files as $file) {
         //DUMP($counter . '] ' . $file);	//string filepath
         //DUMP($file . '---' . pathinfo(storage_path('app') . '/' . $file, PATHINFO_EXTENSION) . '----' . Storage::getMimetype($file));
         //$counter++;
         //CONTINUE;
         try {
             $exif = $reader->read(storage_path('app') . '/' . $file);
             //what a good Storage:: way to do this (get the full path)?
             //date from metadata
             $metadataDate = $exif->getCreationdate();
             //will be false or a DateTime (can be a goofy, invalid DateTime if date is missing or corrupt in the metadata)
             //just for reporting
             if (!$metadataDate) {
                 $reporting['photo-but-no-metadata-date']++;
             }
         } catch (Exception $e) {
             $metadataDate = false;
             $reporting['probably-not-a-photo']++;
         }
         $metadataDateValid = false;
         if ($metadataDate instanceof DateTime) {
             $metadataDateValid = checkdate($metadataDate->format('m'), $metadataDate->format('d'), $metadataDate->format('Y'));
             if (!$metadataDateValid) {
                 $this->error("Got a DateTime from {$file} metadata but it wasn't valid [{$metadataDate->format('Y-m-d')}]. Using filemodified date instead.");
                 $reporting['photo-but-corrupt-metadata-date']++;
             }
         }
         //DUMP($metadataDate);
         //date from filemodified
         $filemodifiedDate = new DateTime();
         $filemodifiedDate->setTimestamp(Storage::lastModified($file));
         //we assume lastModified timestamp is always present on a file
         //DUMP($metadataDate);
         //DUMP($filemodifiedDate);
         //DUMP();
         //DUMP(date('Y m d', Storage::lastModified($file)));	//a timestamp
         //DUMP('a time: ' . date('Y m d', fileatime(storage_path('app') . '/' . $file)));
         //DUMP('c time: ' . date('Y m d', filectime(storage_path('app') . '/' . $file)));
         //DUMP('m time: ' . date('Y m d', filemtime(storage_path('app') . '/' . $file)));
         //DUMP('----');
         //we are good to go from here
         $dateToUse = '';
         if ($priorityDateForSort == 'metadata') {
             $dateToUse = $metadataDate;
             if (!$metadataDate or !$metadataDateValid) {
                 $dateToUse = $filemodifiedDate;
             }
         } elseif ($priorityDateForSort == 'filemodified') {
             $dateToUse = $filemodifiedDate;
         }
         //create folder for this date in the (already existing) destinationfolder
         //and copy the file over
         $year = $dateToUse->format('Y');
         $month = $dateToUse->format('m');
         $day = $dateToUse->format('d');
         $targetSubfolder = "{$year}/{$month}/";
         //support --create-day-folders
         if ($createDayFolders) {
             $targetSubfolder = "{$year}/{$month}/{$day}/";
         }
         //support --separate-videos-and-photos
         if ($separateVideosAndPhotos) {
             $mimetype = Storage::getMimetype($file);
             if (str_contains($mimetype, 'video') or strtolower(pathinfo(storage_path('app') . '/' . $file, PATHINFO_EXTENSION)) == 'mts') {
                 $targetSubfolder = "videos/{$targetSubfolder}";
             } else {
                 $targetSubfolder = "photos/{$targetSubfolder}";
             }
         }
         $targetFolder = "{$destinationFolder}/{$targetSubfolder}";
         $finalDestination = $targetFolder . pathinfo($file, PATHINFO_BASENAME);
         try {
             Storage::makeDirectory($targetFolder);
             Storage::copy($file, $finalDestination);
         } catch (\League\Flysystem\FileExistsException $exception) {
             if ($onDuplicate == 'rename') {
                 $reporting['photos-renamed-for-copy-to-destination']++;
                 $pathParts = pathinfo($file);
                 //will not contain 'extension' index if file has no extension
                 if (!array_key_exists('extension', $pathParts)) {
                     $pathParts['extension'] = '';
                 }
                 $newFinalDestination = $targetFolder . $pathParts['filename'] . '_alt_' . mt_rand(1111, 9999) . '.' . $pathParts['extension'];
                 $this->error("{$finalDestination} already exists in destinationfolder. Renaming to {$newFinalDestination}");
                 Storage::copy($file, $newFinalDestination);
             } elseif ($onDuplicate == 'clobber') {
                 //NOTE this is more of a NOP than an actual overwrite clobber (ie. first one is kept)
                 $reporting['photos-clobbered-for-copy-to-destination']++;
             }
         }
         $bar->advance();
     }
     $bar->finish();
     //summary report
     $dataRows = [];
     foreach ($reporting as $key => $value) {
         $dataRows[] = [$key, $value];
     }
     $this->table(['Entity', 'Count'], $dataRows);
 }
Esempio n. 9
0
 /**
  * @param string $file
  *
  * @return Exif
  */
 protected static function readExif($file)
 {
     if (static::$exifReader === null) {
         static::$exifReader = Reader::factory(Reader::TYPE_NATIVE);
     }
     try {
         $exif = static::$exifReader->read($file);
         return Exif::cast($exif);
     } catch (\RuntimeException $e) {
         return new Exif();
     }
 }
Esempio n. 10
0
 /**
  * @group reader
  * @covers \PHPExif\Reader\Reader::factory
  */
 public function testFactoryAdapterTypeExiftool()
 {
     $reader = \PHPExif\Reader\Reader::factory(\PHPExif\Reader\Reader::TYPE_EXIFTOOL);
     $reflProperty = new \ReflectionProperty('\\PHPExif\\Reader\\Reader', 'adapter');
     $reflProperty->setAccessible(true);
     $adapter = $reflProperty->getValue($reader);
     $this->assertInstanceOf('\\PHPExif\\Adapter\\Exiftool', $adapter);
 }