function convertMetadataVersion($metadata, $version = 1) { // basically flattens arrays. $version = explode(';', $version, 2); $version = intval($version[0]); if ($version < 1 || $version >= 2) { return $metadata; } $avoidHtml = true; if (!is_array($metadata)) { $metadata = unserialize($metadata); } if (!isset($metadata['MEDIAWIKI_EXIF_VERSION']) || $metadata['MEDIAWIKI_EXIF_VERSION'] != 2) { return $metadata; } // Treat Software as a special case because in can contain // an array of (SoftwareName, Version). if (isset($metadata['Software']) && is_array($metadata['Software']) && is_array($metadata['Software'][0]) && isset($metadata['Software'][0][0]) && isset($metadata['Software'][0][1])) { $metadata['Software'] = $metadata['Software'][0][0] . ' (Version ' . $metadata['Software'][0][1] . ')'; } $formatter = new FormatMetadata(); // ContactInfo also has to be dealt with specially if (isset($metadata['Contact'])) { $metadata['Contact'] = $formatter->collapseContactInfo($metadata['Contact']); } foreach ($metadata as &$val) { if (is_array($val)) { $val = $formatter->flattenArrayReal($val, 'ul', $avoidHtml); } } $metadata['MEDIAWIKI_EXIF_VERSION'] = 1; return $metadata; }
/** * Get a list of metadata items which should be displayed when * the metadata table is collapsed. * * @return array Array of strings */ protected function visibleMetadataFields() { return FormatMetadata::getVisibleFields(); }
/** * Get result information for an image revision * * @param File $file * @param array $prop Array of properties to get (in the keys) * @param ApiResult $result * @param array $thumbParams Containing 'width' and 'height' items, or null * @param array|bool|string $opts Options for data fetching. * This is an array consisting of the keys: * 'version': The metadata version for the metadata option * 'language': The language for extmetadata property * 'multilang': Return all translations in extmetadata property * 'revdelUser': User to use when checking whether to show revision-deleted fields. * @return array Result array */ static function getInfo($file, $prop, $result, $thumbParams = null, $opts = false) { global $wgContLang; $anyHidden = false; if (!$opts || is_string($opts)) { $opts = array('version' => $opts ?: 'latest', 'language' => $wgContLang, 'multilang' => false, 'extmetadatafilter' => array(), 'revdelUser' => null); } $version = $opts['version']; $vals = array(ApiResult::META_TYPE => 'assoc'); // Timestamp is shown even if the file is revdelete'd in interface // so do same here. if (isset($prop['timestamp'])) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $file->getTimestamp()); } // Handle external callers who don't pass revdelUser if (isset($opts['revdelUser']) && $opts['revdelUser']) { $revdelUser = $opts['revdelUser']; $canShowField = function ($field) use($file, $revdelUser) { return $file->userCan($field, $revdelUser); }; } else { $canShowField = function ($field) use($file) { return !$file->isDeleted($field); }; } $user = isset($prop['user']); $userid = isset($prop['userid']); if ($user || $userid) { if ($file->isDeleted(File::DELETED_USER)) { $vals['userhidden'] = true; $anyHidden = true; } if ($canShowField(File::DELETED_USER)) { if ($user) { $vals['user'] = $file->getUser(); } if ($userid) { $vals['userid'] = $file->getUser('id'); } if (!$file->getUser('id')) { $vals['anon'] = true; } } } // This is shown even if the file is revdelete'd in interface // so do same here. if (isset($prop['size']) || isset($prop['dimensions'])) { $vals['size'] = intval($file->getSize()); $vals['width'] = intval($file->getWidth()); $vals['height'] = intval($file->getHeight()); $pageCount = $file->pageCount(); if ($pageCount !== false) { $vals['pagecount'] = $pageCount; } // length as in how many seconds long a video is. $length = $file->getLength(); if ($length) { // Call it duration, because "length" can be ambiguous. $vals['duration'] = (double) $length; } } $pcomment = isset($prop['parsedcomment']); $comment = isset($prop['comment']); if ($pcomment || $comment) { if ($file->isDeleted(File::DELETED_COMMENT)) { $vals['commenthidden'] = true; $anyHidden = true; } if ($canShowField(File::DELETED_COMMENT)) { if ($pcomment) { $vals['parsedcomment'] = Linker::formatComment($file->getDescription(File::RAW), $file->getTitle()); } if ($comment) { $vals['comment'] = $file->getDescription(File::RAW); } } } $canonicaltitle = isset($prop['canonicaltitle']); $url = isset($prop['url']); $sha1 = isset($prop['sha1']); $meta = isset($prop['metadata']); $extmetadata = isset($prop['extmetadata']); $commonmeta = isset($prop['commonmetadata']); $mime = isset($prop['mime']); $mediatype = isset($prop['mediatype']); $archive = isset($prop['archivename']); $bitdepth = isset($prop['bitdepth']); $uploadwarning = isset($prop['uploadwarning']); if ($uploadwarning) { $vals['html'] = SpecialUpload::getExistsWarning(UploadBase::getExistsWarning($file)); } if ($file->isDeleted(File::DELETED_FILE)) { $vals['filehidden'] = true; $anyHidden = true; } if ($anyHidden && $file->isDeleted(File::DELETED_RESTRICTED)) { $vals['suppressed'] = true; } if (!$canShowField(File::DELETED_FILE)) { //Early return, tidier than indenting all following things one level return $vals; } if ($canonicaltitle) { $vals['canonicaltitle'] = $file->getTitle()->getPrefixedText(); } if ($url) { if (!is_null($thumbParams)) { $mto = $file->transform($thumbParams); self::$transformCount++; if ($mto && !$mto->isError()) { $vals['thumburl'] = wfExpandUrl($mto->getUrl(), PROTO_CURRENT); // bug 23834 - If the URL's are the same, we haven't resized it, so shouldn't give the wanted // thumbnail sizes for the thumbnail actual size if ($mto->getUrl() !== $file->getUrl()) { $vals['thumbwidth'] = intval($mto->getWidth()); $vals['thumbheight'] = intval($mto->getHeight()); } else { $vals['thumbwidth'] = intval($file->getWidth()); $vals['thumbheight'] = intval($file->getHeight()); } if (isset($prop['thumbmime']) && $file->getHandler()) { list(, $mime) = $file->getHandler()->getThumbType($mto->getExtension(), $file->getMimeType(), $thumbParams); $vals['thumbmime'] = $mime; } } elseif ($mto && $mto->isError()) { $vals['thumberror'] = $mto->toText(); } } $vals['url'] = wfExpandUrl($file->getFullURL(), PROTO_CURRENT); $vals['descriptionurl'] = wfExpandUrl($file->getDescriptionUrl(), PROTO_CURRENT); } if ($sha1) { $vals['sha1'] = wfBaseConvert($file->getSha1(), 36, 16, 40); } if ($meta) { wfSuppressWarnings(); $metadata = unserialize($file->getMetadata()); wfRestoreWarnings(); if ($metadata && $version !== 'latest') { $metadata = $file->convertMetadataVersion($metadata, $version); } $vals['metadata'] = $metadata ? self::processMetaData($metadata, $result) : null; } if ($commonmeta) { $metaArray = $file->getCommonMetaArray(); $vals['commonmetadata'] = $metaArray ? self::processMetaData($metaArray, $result) : array(); } if ($extmetadata) { // Note, this should return an array where all the keys // start with a letter, and all the values are strings. // Thus there should be no issue with format=xml. $format = new FormatMetadata(); $format->setSingleLanguage(!$opts['multilang']); $format->getContext()->setLanguage($opts['language']); $extmetaArray = $format->fetchExtendedMetadata($file); if ($opts['extmetadatafilter']) { $extmetaArray = array_intersect_key($extmetaArray, array_flip($opts['extmetadatafilter'])); } $vals['extmetadata'] = $extmetaArray; } if ($mime) { $vals['mime'] = $file->getMimeType(); } if ($mediatype) { $vals['mediatype'] = $file->getMediaType(); } if ($archive && $file->isOld()) { $vals['archivename'] = $file->getArchiveName(); } if ($bitdepth) { $vals['bitdepth'] = $file->getBitDepth(); } return $vals; }
/** * @return array */ function getFormattedData() { return FormatMetadata::getFormattedData($this->meta); }
/** sorts the visible/invisible field. * Split off from ImageHandler::formatMetadata, as used by more than * one type of handler. * * This is used by the media handlers that use the FormatMetadata class * * @param $metadataArray Array metadata array * @return array for use displaying metadata. */ function formatMetadataHelper($metadataArray) { $result = array('visible' => array(), 'collapsed' => array()); $formatted = FormatMetadata::getFormattedData($metadataArray); // Sort fields into visible and collapsed $visibleFields = $this->visibleMetadataFields(); foreach ($formatted as $name => $value) { $tag = strtolower($name); self::addMeta($result, in_array($tag, $visibleFields) ? 'visible' : 'collapsed', 'exif', $tag, $value); } return $result; }
/** * Use FormatMetadata to create formatted values for display to user * (is this ever used?) * * @deprecated since 1.18 */ function makeFormattedData() { wfDeprecated(__METHOD__, '1.18'); $this->mFormattedExifData = FormatMetadata::getFormattedData($this->mFilteredExifData); }
/** * Flatten an array, using the content language for any messages. * * @param array $vals Array of values * @param string $type Type of array (either lang, ul, ol). * lang = language assoc array with keys being the lang code * ul = unordered list, ol = ordered list * type can also come from the '_type' member of $vals. * @param bool $noHtml If to avoid returning anything resembling HTML. * (Ugly hack for backwards compatibility with old MediaWiki). * @param bool|IContextSource $context * @return string Single value (in wiki-syntax). * @since 1.23 */ public static function flattenArrayContentLang($vals, $type = 'ul', $noHtml = false, $context = false) { global $wgContLang; $obj = new FormatMetadata(); if ($context) { $obj->setContext($context); } $context = new DerivativeContext($obj->getContext()); $context->setLanguage($wgContLang); $obj->setContext($context); return $obj->flattenArrayReal($vals, $type, $noHtml); }
/** * @param $filename String * @param $expected Integer Total image area * @dataProvider provideFlattenArray * @covers FormatMetadata::flattenArray */ public function testFlattenArray($vals, $type, $noHtml, $ctx, $expected) { $actual = FormatMetadata::flattenArray($vals, $type, $noHtml, $ctx); $this->assertEquals($expected, $actual); }
/** * Flatten an array, using the user language for any messages. * * @param array $vals Array of values * @param string $type Type of array (either lang, ul, ol). * lang = language assoc array with keys being the lang code * ul = unordered list, ol = ordered list * type can also come from the '_type' member of $vals. * @param bool $noHtml If to avoid returning anything resembling HTML. * (Ugly hack for backwards compatibility with old MediaWiki). * @param bool|IContextSource $context * @return string Single value (in wiki-syntax). */ public static function flattenArray($vals, $type = 'ul', $noHtml = false, $context = false) { $obj = new FormatMetadata(); if ($context) { $obj->setContext($context); } return $obj->flattenArrayReal($vals, $type, $noHtml); }
/** * Get an array structure that looks like this: * * array( * 'visible' => array( * 'Human-readable name' => 'Human readable value', * ... * ), * 'collapsed' => array( * 'Human-readable name' => 'Human readable value', * ... * ) * ) * The UI will format this into a table where the visible fields are always * visible, and the collapsed fields are optionally visible. * * The function should return false if there is no metadata to display. */ function formatMetadata( $image ) { $result = array( 'visible' => array(), 'collapsed' => array() ); $metadata = $image->getMetadata(); if ( !$metadata ) { return false; } $exif = unserialize( $metadata ); $exif = $exif['exif']; if ( !$exif ) { return false; } unset( $exif['MEDIAWIKI_EXIF_VERSION'] ); if ( class_exists( 'FormatMetadata' ) ) { // 1.18+ $formatted = FormatMetadata::getFormattedData( $exif ); } else { // 1.17 and earlier. $format = new FormatExif( $exif ); $formatted = $format->getFormattedData(); } // Sort fields into visible and collapsed $visibleFields = $this->visibleMetadataFields(); foreach ( $formatted as $name => $value ) { $tag = strtolower( $name ); self::addMeta( $result, in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed', 'exif', $tag, $value ); } $meta = unserialize( $metadata ); $errors_raw = PagedTiffHandler::getMetadataErrors( $meta ); if ( $errors_raw ) { $errors = PagedTiffHandler::joinMessages( $errors_raw ); self::addMeta( $result, 'collapsed', 'metadata', 'error', $errors ); // XXX: need translation for <metadata-error> } if ( !empty( $meta['warnings'] ) ) { $warnings = PagedTiffHandler::joinMessages( $meta['warnings'] ); self::addMeta( $result, 'collapsed', 'metadata', 'warning', $warnings ); // XXX: need translation for <metadata-warning> } return $result; }