1<?php 2/** 3 * PHP Exif Native Reader Adapter 4 * 5 * @link http://github.com/miljar/PHPExif for the canonical source repository 6 * @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be> 7 * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License 8 * @category PHPExif 9 * @package Reader 10 */ 11 12namespace PHPExif\Adapter; 13 14use PHPExif\Exif; 15use DateTime; 16 17/** 18 * PHP Exif Native Reader Adapter 19 * 20 * Uses native PHP functionality to read data from a file 21 * 22 * @category PHPExif 23 * @package Reader 24 */ 25class Native extends AdapterAbstract 26{ 27 const INCLUDE_THUMBNAIL = true; 28 const NO_THUMBNAIL = false; 29 30 const SECTIONS_AS_ARRAYS = true; 31 const SECTIONS_FLAT = false; 32 33 const SECTION_FILE = 'FILE'; 34 const SECTION_COMPUTED = 'COMPUTED'; 35 const SECTION_IFD0 = 'IFD0'; 36 const SECTION_THUMBNAIL = 'THUMBNAIL'; 37 const SECTION_COMMENT = 'COMMENT'; 38 const SECTION_EXIF = 'EXIF'; 39 const SECTION_ALL = 'ANY_TAG'; 40 const SECTION_IPTC = 'IPTC'; 41 42 /** 43 * List of EXIF sections 44 * 45 * @var array 46 */ 47 protected $requiredSections = array(); 48 49 /** 50 * Include the thumbnail in the EXIF data? 51 * 52 * @var boolean 53 */ 54 protected $includeThumbnail = self::NO_THUMBNAIL; 55 56 /** 57 * Parse the sections as arrays? 58 * 59 * @var boolean 60 */ 61 protected $sectionsAsArrays = self::SECTIONS_FLAT; 62 63 /** 64 * @var string 65 */ 66 protected $mapperClass = '\\PHPExif\\Mapper\\Native'; 67 68 /** 69 * Contains the mapping of names to IPTC field numbers 70 * 71 * @var array 72 */ 73 protected $iptcMapping = array( 74 'title' => '2#005', 75 'keywords' => '2#025', 76 'copyright' => '2#116', 77 'caption' => '2#120', 78 'headline' => '2#105', 79 'credit' => '2#110', 80 'source' => '2#115', 81 'jobtitle' => '2#085' 82 ); 83 84 85 /** 86 * Getter for the EXIF sections 87 * 88 * @return array 89 */ 90 public function getRequiredSections() 91 { 92 return $this->requiredSections; 93 } 94 95 /** 96 * Setter for the EXIF sections 97 * 98 * @param array $sections List of EXIF sections 99 * @return \PHPExif\Reader Current instance for chaining 100 */ 101 public function setRequiredSections(array $sections) 102 { 103 $this->requiredSections = $sections; 104 105 return $this; 106 } 107 108 /** 109 * Adds an EXIF section to the list 110 * 111 * @param string $section 112 * @return \PHPExif\Reader Current instance for chaining 113 */ 114 public function addRequiredSection($section) 115 { 116 if (!in_array($section, $this->requiredSections)) { 117 array_push($this->requiredSections, $section); 118 } 119 120 return $this; 121 } 122 123 /** 124 * Define if the thumbnail should be included into the EXIF data or not 125 * 126 * @param boolean $value 127 * @return \PHPExif\Reader Current instance for chaining 128 */ 129 public function setIncludeThumbnail($value) 130 { 131 $this->includeThumbnail = $value; 132 133 return $this; 134 } 135 136 /** 137 * Returns if the thumbnail should be included into the EXIF data or not 138 * 139 * @return boolean 140 */ 141 public function getIncludeThumbnail() 142 { 143 return $this->includeThumbnail; 144 } 145 146 /** 147 * Define if the sections should be parsed as arrays 148 * 149 * @param boolean $value 150 * @return \PHPExif\Reader Current instance for chaining 151 */ 152 public function setSectionsAsArrays($value) 153 { 154 $this->sectionsAsArrays = (bool) $value; 155 156 return $this; 157 } 158 159 /** 160 * Returns if the sections should be parsed as arrays 161 * 162 * @return boolean 163 */ 164 public function getSectionsAsArrays() 165 { 166 return $this->sectionsAsArrays; 167 } 168 169 /** 170 * Reads & parses the EXIF data from given file 171 * 172 * @param string $file 173 * @return \PHPExif\Exif|boolean Instance of Exif object with data 174 */ 175 public function getExifFromFile($file) 176 { 177 $sections = $this->getRequiredSections(); 178 $sections = implode(',', $sections); 179 $sections = (empty($sections)) ? null : $sections; 180 181 $data = @exif_read_data( 182 $file, 183 $sections, 184 $this->getSectionsAsArrays(), 185 $this->getIncludeThumbnail() 186 ); 187 188 if (false === $data) { 189 return false; 190 } 191 192 $xmpData = $this->getIptcData($file); 193 $data = array_merge($data, array(self::SECTION_IPTC => $xmpData)); 194 195 // map the data: 196 $mapper = $this->getMapper(); 197 $mappedData = $mapper->mapRawData($data); 198 199 // hydrate a new Exif object 200 $exif = new Exif(); 201 $hydrator = $this->getHydrator(); 202 $hydrator->hydrate($exif, $mappedData); 203 $exif->setRawData($data); 204 205 return $exif; 206 } 207 208 /** 209 * Returns an array of IPTC data 210 * 211 * @param string $file The file to read the IPTC data from 212 * @return array 213 */ 214 public function getIptcData($file) 215 { 216 getimagesize($file, $info); 217 $arrData = array(); 218 if (isset($info['APP13'])) { 219 $iptc = iptcparse($info['APP13']); 220 221 foreach ($this->iptcMapping as $name => $field) { 222 if (!isset($iptc[$field])) { 223 continue; 224 } 225 226 if (count($iptc[$field]) === 1) { 227 $arrData[$name] = reset($iptc[$field]); 228 } else { 229 $arrData[$name] = $iptc[$field]; 230 } 231 } 232 } 233 234 return $arrData; 235 } 236} 237