function getExtendedData($metaObj) { //these properties can be accessed similarly for all image files and were set in the ImageFile class that this class extends $metadata['header'] = $this->header; $metadata['width'] = $this->width; $metadata['height'] = $this->height; $metadata['otherinfo'] = $this->otherinfo; //these types of metadata are also common to other types of files but may need to be accessed differently based on exact file type $metadata['exif'] = function_exists('exif_read_data') ? exif_read_data($metaObj->currname, 0, true) : false; $metadata['iptcraw'] = !empty($this->otherinfo['APP13']) ? iptcparse($this->otherinfo['APP13']) : false; if ($metadata['iptcraw']) { require_once 'lib/metadata/iptc.php'; $iptc = new Iptc(); $metadata['iptc'] = $iptc->addIptcTags($metadata['iptcraw']); } else { $metadata['iptc'] = false; } $metadata['xmp'] = isset($metaObj->content) ? $this->getXmp($metaObj->content) : false; $metadata['xmparray'] = $metadata['xmp'] ? $metaObj->xmpDomToArray($metadata['xmp']) : false; /* Check the stored checksum value for IPTC data against a current hash calculation * Affects how IPTC and XMP metadata within a file are reconciled according to the Metadata Working Group guidelines * (http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf) */ /* First check to see if there is a checksum stored for the iptc block * The IPTC block is within the APP13 (Photoshop) segment, which is at $this->otherinfo['APP13'] * The stored checksum is at the hex marker \x38\x42\x49\x4D\x04\x25\x00\x00\x00\x00 (resource ID 1061) */ $hashstored = $metaObj->getDataSegment($this->otherinfo['APP13'], "8BIM%", 10, 2); $metadata['iptc']['hashstored']['value']['display'] = bin2hex($hashstored); $metadata['iptc']['hashstored']['specs']['label'] = tra('Stored IPTC Digest'); //calculate current hash of the IPTC block, which starts at hex marker \x38\x42\x49\x4D\x04\x04\x00\x00\x00\x00 within the APP13 segment $iptcblock = $metaObj->getDataSegment($this->otherinfo['APP13'], "8BIM", 10, 2); $metadata['iptc']['hashcurrent']['value']['display'] = md5($iptcblock); $metadata['iptc']['hashcurrent']['specs']['label'] = tra('Calculated IPTC Digest'); /* * In case we needed to get the individual APP13 records, below are a couple of examples * each record starts with the tag marker of hex 1c (13), followed by record number and dataset number * * record number is 02 and dataset number is hex 74 (116), so this is IPTC field 2#116 (or 2:116) * $single = $metaObj->getDataSegment($this->otherinfo['APP13'], "\x1c\x02\x74", 3, 2); * * record number is 01 and dataset number is hex 5a (90), so this is IPTC field 1#090 (or 1:090) * $single2 = $metaObj->getDataSegment($this->otherinfo['APP13'], "\x1c\x01\x5a", 3, 2); * * next two bytes are the size of the dataset */ return $metadata; }
function addTagIntoFile($_fullPath, $_tag) { $iptc = new Iptc($_fullPath); $tags = $iptc->fetchAll(Iptc::KEYWORDS); $tags[] = $_tag; $iptc->set(Iptc::KEYWORDS, $tags); $iptc->write(); }
/** * @param object $metaObj Object from the FileMetadata class which calls this function * * @return array $metadata Returns an array of metadata */ function getExtendedData($metaObj) { /* * these properties can be accessed similarly for all image files and were set in the ImageFile class that * this class extends */ $metadata['header'] = $this->header; $metadata['width'] = $this->width; $metadata['height'] = $this->height; $metadata['otherinfo'] = $this->otherinfo; /* * these following types of metadata are also common to other types of files but may need to be accessed * differently based on file type */ //EXIF //get raw exif $metadata['exifraw'] = function_exists('exif_read_data') ? exif_read_data($metaObj->currname, 0, true) : false; //interpret and add tags if ($metadata['exifraw']) { require_once 'lib/metadata/datatypes/exif.php'; $exif = new Exif(); $metadata['exif'] = $exif->processRawData($metadata['exifraw']); //add EXIF to combined metadata array that is not reconciled $metadata['combined']['exif'] = $metadata['exif']; } else { $metadata['exif'] = false; } //IPTC //get raw iptc and place in an iptc key so that iptc array has same number of levels as exif and xmp //and to distinguish from digest key added later $metadata['iptcraw']['iptc'] = !empty($this->otherinfo['APP13']) ? iptcparse($this->otherinfo['APP13']) : false; //process raw iptc if (is_array($metadata['iptcraw']['iptc'])) { //first prepare for processing foreach ($metadata['iptcraw']['iptc'] as $fieldname => $value) { if (count($value) > 1) { $metadata['iptcraw']['iptc'][$fieldname] = $value; } else { $metadata['iptcraw']['iptc'][$fieldname] = $value[0]; } } //process raw data require_once 'lib/metadata/datatypes/iptc.php'; $iptc = new Iptc(); $metadata['iptc'] = $iptc->processRawData($metadata['iptcraw']); //add IPTC to combined metadata array that is not reconciled $metadata['combined']['iptc'] = $metadata['iptc']; //check stored and create current hash /* * add stored iptc hash if it exists * The IPTC block is within the APP13 (Photoshop) segment, which is at $this->otherinfo['APP13'] * The stored checksum is at hex marker \x38\x42\x49\x4D\x04\x25\x00\x00\x00\x00 (resource ID 1061) */ $hashstored = $metaObj->getDataSegment($this->otherinfo['APP13'], "8BIM%", 10, 2); if (!empty($hashstored)) { $metadata['iptc']['digest']['iptchashstored'] = array('newval' => bin2hex($hashstored), 'label' => 'Stored IPTC Hash'); } /* * add calculated current hash of the IPTC block, * which starts at hex marker \x38\x42\x49\x4D\x04\x04\x00\x00\x00\x00 within the APP13 segment */ $iptcblock = $metaObj->getDataSegment($this->otherinfo['APP13'], "8BIM", 10, 2); if (!empty($iptcblock)) { $metadata['iptc']['digest']['iptchashcurrent'] = array('newval' => md5($iptcblock), 'label' => 'Computed IPTC Hash'); } if (!isset($metadata['iptc']['digest']['iptchashstored']['newval']) || strlen($metadata['iptc']['digest']['iptchashstored']['newval']) > 0 && $metadata['iptc']['digest']['iptchashstored']['newval'] == $metadata['iptc']['digest']['iptchashcurrent']['newval']) { if (isset($metadata['iptc']['digest']['iptchashstored']['newval'])) { $metadata['iptc']['digest']['match']['newval'] = ''; //place text in suffix so it can be translated $metadata['iptc']['digest']['match']['suffix'] = 'IPTC stored and actual hash match - indication that metadata editors were compliant'; $metadata['iptc']['digest']['match']['label'] = 'Note'; } } else { $metadata['iptc']['digest']['mismatch']['newval'] = ''; $metadata['iptc']['digest']['mismatch']['suffix'] = 'Metadata has been edited by a noncompliant editor - IPTC stored and actual hash do not match'; $metadata['iptc']['digest']['mismatch']['label'] = 'Warning'; } /* * In case we needed to get the individual APP13 records, below are a couple of examples * each record starts with the tag marker of hex 1c (13), followed by record number and dataset number * * Example: record number is 02 and dataset number is hex 74 (116), so this is IPTC field 2#116 (or 2:116) * $single = $metaObj->getDataSegment($this->otherinfo['APP13'], "\x1c\x02\x74", 3, 2); * * Example2: record number is 01 and dataset number is hex 5a (90), so this is IPTC field 1#090 (or 1:090) * $single2 = $metaObj->getDataSegment($this->otherinfo['APP13'], "\x1c\x01\x5a", 3, 2); * * next two bytes after the record and dataset number are the size of the dataset */ } else { $metadata['iptc'] = false; } //XMP //get raw xmp DOM, convert to an array add tags and interpret if (!empty($metaObj->content)) { require_once 'lib/metadata/datatypes/xmp.php'; $xmp = new Xmp(); $metadata['xmpraw'] = $xmp->getXmp($metaObj->content, $metaObj->basicraw['type']); $metadata['xmp'] = $xmp->processRawData($metadata['xmpraw']); } else { $metadata['xmpraw'] = false; $metadata['xmp'] = false; } //add XMP to combined unreconciled metadata array if ($metadata['xmp'] !== false) { $metadata['combined']['xmp'] = $metadata['xmp']; } //Reconcile extended metadata in accordance with the Metadata Working Group standards require_once 'lib/metadata/reconcile.php'; $rec = new ReconcileExifIptcXmp(); $metadata['reconciled'] = $rec->reconcileAllMeta($metadata); //Add basic info $metadata = $metaObj->mergeBasicInfo($metaObj, $metadata); return $metadata; }