28 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
31 use Wikimedia\Timestamp\TimestampException;
55 use ProtectedHookAccessorTrait;
71 $this->singleLang = $val;
93 return $obj->makeFormattedData( $tags );
108 $resolutionunit = !isset( $tags[
'ResolutionUnit'] ) || $tags[
'ResolutionUnit'] == 2 ? 2 : 3;
109 unset( $tags[
'ResolutionUnit'] );
112 unset( $tags[
'HasExtendedXMP'] );
113 unset( $tags[
'AuthorsPosition'] );
114 unset( $tags[
'LocationCreated'] );
115 unset( $tags[
'LocationShown'] );
116 unset( $tags[
'GPSAltitudeRef'] );
118 foreach ( $tags as $tag => &$vals ) {
121 if ( !is_array( $vals ) ) {
126 if ( isset( $vals[
'_type'] ) ) {
127 $type = $vals[
'_type'];
128 unset( $vals[
'_type'] );
135 if ( isset( $tags[$tag][
'_formatted'] ) ) {
137 $tags[$tag][
'_formatted'],
$type
143 if ( $tag ==
'GPSTimeStamp' && count( $vals ) === 3 ) {
146 $h = explode(
'/', $vals[0], 2 );
147 $m = explode(
'/', $vals[1], 2 );
148 $s = explode(
'/', $vals[2], 2 );
163 $vals = str_pad( (
string)( (
int)$h[0] / (
int)$h[1] ), 2,
'0', STR_PAD_LEFT )
164 .
':' . str_pad( (
string)( (
int)$m[0] / (
int)$m[1] ), 2,
'0', STR_PAD_LEFT )
165 .
':' . str_pad( (
string)( (
int)
$s[0] / (
int)
$s[1] ), 2,
'0', STR_PAD_LEFT );
168 $time =
wfTimestamp( TS_MW,
'1971:01:01 ' . $vals );
170 if ( $time && intval( $time ) > 0 ) {
173 }
catch ( TimestampException $e ) {
184 if ( $tag ===
'Contact' || $tag ===
'CreatorContactInfo' ) {
189 foreach ( $vals as &$val ) {
204 $val = $this->exifMsg( $tag, $val );
213 case 'PhotometricInterpretation':
227 $val = $this->exifMsg( $tag, $val );
246 $val = $this->exifMsg( $tag, $val );
255 case 'PlanarConfiguration':
259 $val = $this->exifMsg( $tag, $val );
269 case 'YCbCrPositioning':
273 $val = $this->exifMsg( $tag, $val );
284 switch ( $resolutionunit ) {
286 $val = $this->exifMsg(
'XYResolution',
'i', $this->formatNum( $val ) );
289 $val = $this->exifMsg(
'XYResolution',
'c', $this->formatNum( $val ) );
305 case 'FlashPixVersion':
308 case 'FlashpixVersion':
309 $val = $this->
literal( (
int)$val / 100 );
316 $val = $this->exifMsg( $tag, $val );
325 case 'ComponentsConfiguration':
334 $val = $this->exifMsg( $tag, $val );
344 case 'DateTimeOriginal':
345 case 'DateTimeDigitized':
346 case 'DateTimeReleased':
347 case 'DateTimeExpires':
350 case 'DateTimeMetadata':
351 case 'FirstPhotoDate':
352 case 'LastPhotoDate':
353 if ( $val ==
'0000:00:00 00:00:00' || $val ==
' : : : : ' ) {
354 $val = $this->
msg(
'exif-unknowndate' )->text();
356 } elseif ( preg_match(
357 '/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d):(?:\d\d)$/D',
362 if ( $time && intval( $time ) > 0 ) {
366 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d)$/D', $val ) ) {
371 if ( $time && intval( $time ) > 0 ) {
375 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d)$/D', $val ) ) {
378 . substr( $val, 5, 2 )
379 . substr( $val, 8, 2 )
381 if ( $time && intval( $time ) > 0 ) {
390 case 'ExposureProgram':
401 $val = $this->exifMsg( $tag, $val );
410 case 'SubjectDistance':
411 $val = $this->exifMsg( $tag,
'', $this->formatNum( $val ) );
425 $val = $this->exifMsg( $tag, $val );
457 $val = $this->exifMsg( $tag, $val );
468 'fired' => $val & 0b00000001,
469 'return' => ( $val & 0b00000110 ) >> 1,
470 'mode' => ( $val & 0b00011000 ) >> 3,
471 'function' => ( $val & 0b00100000 ) >> 5,
472 'redeye' => ( $val & 0b01000000 ) >> 6,
476 # We do not need to handle unknown values since all are used.
477 foreach ( $flashDecode as $subTag => $subValue ) {
478 # We do not need any message for zeroed values.
479 if ( $subTag !=
'fired' && $subValue == 0 ) {
482 $fullTag = $tag .
'-' . $subTag;
483 $flashMsgs[] = $this->exifMsg( $fullTag, $subValue );
485 $val = $this->
getLanguage()->commaList( $flashMsgs );
488 case 'FocalPlaneResolutionUnit':
491 $val = $this->exifMsg( $tag, $val );
500 case 'SensingMethod':
509 $val = $this->exifMsg( $tag, $val );
521 $val = $this->exifMsg( $tag, $val );
533 $val = $this->exifMsg( $tag, $val );
542 case 'CustomRendered':
554 $val = $this->exifMsg( $tag, $val );
568 $val = $this->exifMsg( $tag, $val );
580 $val = $this->exifMsg( $tag, $val );
589 case 'SceneCaptureType':
595 $val = $this->exifMsg( $tag, $val );
611 $val = $this->exifMsg( $tag, $val );
625 $val = $this->exifMsg( $tag, $val );
639 $val = $this->exifMsg( $tag, $val );
653 $val = $this->exifMsg( $tag, $val );
662 case 'SubjectDistanceRange':
668 $val = $this->exifMsg( $tag, $val );
678 case 'GPSLatitudeRef':
679 case 'GPSDestLatitudeRef':
683 $val = $this->exifMsg(
'GPSLatitude', $val );
692 case 'GPSLongitudeRef':
693 case 'GPSDestLongitudeRef':
697 $val = $this->exifMsg(
'GPSLongitude', $val );
708 $val = $this->exifMsg(
'GPSAltitude',
'below-sealevel', $this->formatNum( -$val, 3 ) );
710 $val = $this->exifMsg(
'GPSAltitude',
'above-sealevel', $this->formatNum( $val, 3 ) );
718 $val = $this->exifMsg( $tag, $val );
727 case 'GPSMeasureMode':
731 $val = $this->exifMsg( $tag, $val );
741 case 'GPSImgDirectionRef':
742 case 'GPSDestBearingRef':
746 $val = $this->exifMsg(
'GPSDirection', $val );
756 case 'GPSDestLatitude':
757 $val = $this->formatCoords( $val,
'latitude' );
760 case 'GPSDestLongitude':
761 $val = $this->formatCoords( $val,
'longitude' );
769 $val = $this->exifMsg(
'GPSSpeed', $val );
778 case 'GPSDestDistanceRef':
783 $val = $this->exifMsg(
'GPSDestDistance', $val );
795 $val = $this->exifMsg( $tag,
'excellent', $this->formatNum( $val ) );
796 } elseif ( $val <= 5 ) {
797 $val = $this->exifMsg( $tag,
'good', $this->formatNum( $val ) );
798 } elseif ( $val <= 10 ) {
799 $val = $this->exifMsg( $tag,
'moderate', $this->formatNum( $val ) );
800 } elseif ( $val <= 20 ) {
801 $val = $this->exifMsg( $tag,
'fair', $this->formatNum( $val ) );
803 $val = $this->exifMsg( $tag,
'poor', $this->formatNum( $val ) );
812 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
816 if ( is_array( $val ) ) {
817 if ( count( $val ) > 1 ) {
820 'exif-software-version-value',
826 $val = $this->exifMsg( $tag,
'', $this->
literal( $val[0] ) );
829 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
835 $val = $this->
msg(
'exif-exposuretime-format',
836 $this->formatFraction( $val ), $this->formatNum( $val ) )->text();
838 case 'ISOSpeedRatings':
842 if ( $val ==
'65535' ) {
843 $val = $this->exifMsg( $tag,
'overflow' );
845 $val = $this->formatNum( $val );
849 $val = $this->
msg(
'exif-fnumber-format',
850 $this->formatNum( $val ) )->text();
854 case 'FocalLengthIn35mmFilm':
855 $val = $this->
msg(
'exif-focallength-format',
856 $this->formatNum( $val ) )->text();
859 case 'MaxApertureValue':
860 if ( strpos( $val,
'/' ) !==
false ) {
862 [ $n, $d ] = explode(
'/', $val, 2 );
863 if ( is_numeric( $n ) && is_numeric( $d ) ) {
864 $val = (int)$n / (
int)$d;
867 if ( is_numeric( $val ) ) {
868 $fNumber = 2 ** ( $val / 2 );
869 if ( is_finite( $fNumber ) ) {
870 $val = $this->
msg(
'exif-maxaperturevalue-value',
871 $this->formatNum( $val ),
872 $this->formatNum( $fNumber, 2 )
881 switch ( strtolower( $val ) ) {
901 $val = $this->exifMsg(
910 case 'SubjectNewsCode':
916 $val = $this->convertNewsCode( $val );
922 if ( $val == 0 || $val == 9 ) {
924 } elseif ( $val < 5 && $val > 1 ) {
926 } elseif ( $val == 5 ) {
928 } elseif ( $val <= 8 && $val > 5 ) {
932 if ( $urgency !==
'' ) {
933 $val = $this->exifMsg(
'urgency',
934 $urgency, $this->
literal( $val )
942 case 'OriginalImageHeight':
943 case 'OriginalImageWidth':
944 case 'PixelXDimension':
945 case 'PixelYDimension':
948 $val = $this->formatNum( $val ) .
' ' . $this->
msg(
'unit-pixel' )->text();
958 case 'ImageDescription':
962 case 'RelatedSoundFile':
963 case 'ImageUniqueID':
964 case 'SpectralSensitivity':
965 case 'GPSSatellites':
969 case 'WorldRegionDest':
971 case 'CountryCodeDest':
972 case 'ProvinceOrStateDest':
974 case 'SublocationDest':
975 case 'WorldRegionCreated':
976 case 'CountryCreated':
977 case 'CountryCodeCreated':
978 case 'ProvinceOrStateCreated':
980 case 'SublocationCreated':
982 case 'SpecialInstructions':
987 case 'FixtureIdentifier':
989 case 'LocationDestCode':
991 case 'JPEGFileComment':
992 case 'iimSupplementalCategory':
993 case 'OriginalTransmissionRef':
995 case 'dc-contributor':
1003 case 'SerialNumber':
1004 case 'CameraOwnerName':
1007 case 'RightsCertificate':
1008 case 'CopyrightOwner':
1010 case 'WebStatement':
1011 case 'OriginalDocumentID':
1013 case 'MorePermissionsUrl':
1014 case 'AttributionUrl':
1015 case 'PreferredAttributionName':
1016 case 'PNGFileComment':
1018 case 'ContentWarning':
1019 case 'GIFFileComment':
1021 case 'IntellectualGenre':
1023 case 'OrganisationInImage':
1024 case 'PersonInImage':
1025 case 'CaptureSoftware':
1026 case 'GPSAreaInformation':
1027 case 'GPSProcessingMethod':
1028 case 'StitchingSoftware':
1030 case 'SubSecTimeOriginal':
1031 case 'SubSecTimeDigitized':
1032 $val = $this->
literal( $val );
1035 case 'ProjectionType':
1037 case 'equirectangular':
1038 $val = $this->exifMsg( $tag, $val );
1041 $val = $this->
literal( $val );
1050 $val = $this->exifMsg( $tag, $val );
1053 $val = $this->
literal( $val );
1058 case 'UsePanoramaViewer':
1059 case 'ExposureLockUsed':
1063 $val = $this->exifMsg( $tag, $val );
1066 $val = $this->
literal( $val );
1071 if ( $val ==
'-1' ) {
1072 $val = $this->exifMsg( $tag,
'rejected' );
1074 $val = $this->formatNum( $val );
1078 case 'LanguageCode':
1079 $lang = MediaWikiServices::getInstance()
1080 ->getLanguageNameUtils()
1081 ->getLanguageName( strtolower( $val ), $this->
getLanguage()->getCode() );
1086 $val = $this->formatNum( $val,
false, $tag );
1115 if ( !is_array( $vals ) ) {
1119 if ( isset( $vals[
'_type'] ) ) {
1120 $type = $vals[
'_type'];
1121 unset( $vals[
'_type'] );
1124 if ( count( $vals ) === 1 &&
$type !==
'lang' && isset( $vals[0] ) ) {
1126 } elseif ( count( $vals ) === 0 ) {
1127 wfDebug( __METHOD__ .
" metadata array with 0 elements!" );
1132 $containsNestedArrays = in_array(
true, array_map(
'is_array', $vals ),
true );
1133 if ( $containsNestedArrays ) {
1134 wfLogWarning( __METHOD__ .
': Invalid $vals, contains nested arrays: ' . json_encode( $vals ) );
1151 $defaultItem =
false;
1152 $defaultLang =
false;
1158 if ( isset( $vals[
'x-default'] ) ) {
1159 $defaultItem = $vals[
'x-default'];
1160 unset( $vals[
'x-default'] );
1162 foreach ( $priorityLanguages as $pLang ) {
1163 if ( isset( $vals[$pLang] ) ) {
1165 if ( $vals[$pLang] === $defaultItem ) {
1166 $defaultItem =
false;
1169 $content .= $this->langItem( $vals[$pLang], $pLang, $isDefault, $noHtml );
1171 unset( $vals[$pLang] );
1173 if ( $this->singleLang ) {
1180 foreach ( $vals as
$lang => $item ) {
1181 if ( $item === $defaultItem ) {
1182 $defaultLang =
$lang;
1185 $content .= $this->langItem( $item,
$lang,
false, $noHtml );
1186 if ( $this->singleLang ) {
1190 if ( $defaultItem !==
false ) {
1191 $content = $this->langItem( $defaultItem, $defaultLang,
true, $noHtml ) .
$content;
1192 if ( $this->singleLang ) {
1193 return $defaultItem;
1200 return '<ul class="metadata-langlist">' .
$content .
'</ul>';
1203 return "\n#" . implode(
"\n#", $vals );
1206 return "<ol><li>" . implode(
"</li>\n<li>", $vals ) .
'</li></ol>';
1210 return "\n*" . implode(
"\n*", $vals );
1213 return "<ul><li>" . implode(
"</li>\n<li>", $vals ) .
'</li></ul>';
1228 private function langItem( $value,
$lang, $default =
false, $noHtml =
false ) {
1229 if (
$lang ===
false && $default ===
false ) {
1230 throw new MWException(
'$lang and $default cannot both be false.' );
1234 $wrappedValue = $this->
literal( $value );
1236 $wrappedValue =
'<span class="mw-metadata-lang-value">' . $this->
literal( $value ) .
'</span>';
1239 if (
$lang ===
false ) {
1240 $msg = $this->
msg(
'metadata-langitem-default', $wrappedValue );
1242 return $msg->text() .
"\n\n";
1245 return '<li class="mw-metadata-lang-default">' . $msg->text() .
"</li>\n";
1248 $lowLang = strtolower(
$lang );
1249 $languageNameUtils = MediaWikiServices::getInstance()->getLanguageNameUtils();
1250 $langName = $languageNameUtils->getLanguageName( $lowLang );
1251 if ( $langName ===
'' ) {
1253 $langPrefix = explode(
'-', $lowLang, 2 )[0];
1254 $langName = $languageNameUtils->getLanguageName( $langPrefix );
1255 if ( $langName ===
'' ) {
1262 $msg = $this->
msg(
'metadata-langitem', $wrappedValue, $langName,
$lang );
1264 return '*' . $msg->text();
1267 $item =
'<li class="mw-metadata-lang-code-' .
$lang;
1269 $item .=
' mw-metadata-lang-default';
1271 $item .=
'" lang="' .
$lang .
'">';
1272 $item .= $msg->text();
1286 if ( $val === null ) {
1293 return htmlspecialchars( $val );
1305 private function exifMsg( $tag, $val, $arg =
null, $arg2 =
null ) {
1306 if ( $val ===
'' ) {
1311 MediaWikiServices::getInstance()->getContentLanguage()->lc(
"exif-$tag-$val" ),
1326 private function formatNum( $num, $round =
false, $tagName =
null ) {
1328 if ( is_array( $num ) ) {
1330 foreach ( $num as $number ) {
1331 $out[] = $this->formatNum( $number, $round, $tagName );
1334 return $this->getLanguage()->commaList( $out );
1336 if ( is_numeric( $num ) ) {
1337 if ( $round !==
false ) {
1338 $num = round( $num, $round );
1340 return $this->getLanguage()->formatNum( $num );
1343 if ( preg_match(
'/^(-?\d+)\/(\d+)$/', $num, $m ) ) {
1345 $newNum = (int)$m[1] / (
int)$m[2];
1346 if ( $round !==
false ) {
1347 $newNum = round( $newNum, $round );
1353 return $this->getLanguage()->formatNum( $newNum );
1355 # T267370: there are a lot of strange EXIF tags floating around.
1356 LoggerFactory::getInstance(
'formatnum' )->warning(
1357 'FormatMetadata::formatNum with non-numeric value',
1363 return $this->literal( $num );
1372 private function formatFraction( $num ) {
1374 if ( preg_match(
'/^(-?\d+)\/(\d+)$/', $num, $m ) ) {
1375 $numerator = intval( $m[1] );
1376 $denominator = intval( $m[2] );
1377 $gcd = $this->gcd( abs( $numerator ), $denominator );
1380 return $this->formatNum( $numerator / $gcd ) .
'/' . $this->formatNum( $denominator / $gcd );
1384 return $this->formatNum( $num );
1394 private function gcd( $a, $b ) {
1404 $remainder = $a % $b;
1426 private function convertNewsCode( $val ) {
1427 if ( !preg_match(
'/^\d{8}$/D', $val ) ) {
1432 switch ( substr( $val, 0, 2 ) ) {
1485 if ( $cat !==
'' ) {
1486 $catMsg = $this->exifMsg(
'iimcategory', $cat );
1487 $val = $this->exifMsg(
'subjectnewscode',
'', $this->literal( $val ), $catMsg );
1501 private function formatCoords( $coord,
string $type ) {
1502 if ( !is_numeric( $coord ) ) {
1503 wfDebugLog(
'exif', __METHOD__ .
": \"$coord\" is not a number" );
1504 return $this->literal( (
string)$coord );
1510 if (
$type ===
'latitude' ) {
1512 } elseif (
$type ===
'longitude' ) {
1516 $nCoord = (float)$coord;
1517 if (
$type ===
'latitude' ) {
1519 } elseif (
$type ===
'longitude' ) {
1524 $deg = floor( $nCoord );
1525 $min = floor( ( $nCoord - $deg ) * 60 );
1526 $sec = round( ( ( $nCoord - $deg ) * 60 - $min ) * 60, 2 );
1528 $deg = $this->formatNum( $deg );
1529 $min = $this->formatNum( $min );
1530 $sec = $this->formatNum( $sec );
1533 return $this->msg(
'exif-coordinate-format', $deg, $min, $sec, $ref, $this->literal( $coord ) )->text();
1551 if ( !( isset( $vals[
'CiAdrExtadr'] )
1552 || isset( $vals[
'CiAdrCity'] )
1553 || isset( $vals[
'CiAdrCtry'] )
1554 || isset( $vals[
'CiEmailWork'] )
1555 || isset( $vals[
'CiTelWork'] )
1556 || isset( $vals[
'CiAdrPcode'] )
1557 || isset( $vals[
'CiAdrRegion'] )
1558 || isset( $vals[
'CiUrlWork'] )
1567 foreach ( $vals as &$val ) {
1568 $val = $this->literal( $val );
1571 return $this->flattenArrayReal( $vals );
1576 $url = $tel = $street = $city = $country =
'';
1577 $email = $postal = $region =
'';
1586 if ( isset( $vals[
'CiAdrExtadr'] ) ) {
1589 $street =
'<span class="extended-address">'
1591 $vals[
'CiAdrExtadr'] )
1594 if ( isset( $vals[
'CiAdrCity'] ) ) {
1595 $city =
'<span class="locality">'
1596 . $this->literal( $vals[
'CiAdrCity'] )
1599 if ( isset( $vals[
'CiAdrCtry'] ) ) {
1600 $country =
'<span class="country-name">'
1601 . $this->literal( $vals[
'CiAdrCtry'] )
1604 if ( isset( $vals[
'CiEmailWork'] ) ) {
1607 $splitEmails = explode(
"\n", $vals[
'CiEmailWork'] );
1608 foreach ( $splitEmails as $e1 ) {
1610 foreach ( explode(
',', $e1 ) as $e2 ) {
1611 $finalEmail = trim( $e2 );
1612 if ( $finalEmail ==
',' || $finalEmail ==
'' ) {
1615 if ( strpos( $finalEmail,
'<' ) !==
false ) {
1618 $emails[] = $this->literal( $finalEmail );
1620 $emails[] =
'[mailto:'
1622 .
' <span class="email">'
1623 . $this->literal( $finalEmail )
1628 $email = implode(
', ', $emails );
1630 if ( isset( $vals[
'CiTelWork'] ) ) {
1631 $tel =
'<span class="tel">'
1632 . $this->literal( $vals[
'CiTelWork'] )
1635 if ( isset( $vals[
'CiAdrPcode'] ) ) {
1636 $postal =
'<span class="postal-code">'
1637 . $this->literal( $vals[
'CiAdrPcode'] )
1640 if ( isset( $vals[
'CiAdrRegion'] ) ) {
1642 $region =
'<span class="region">'
1643 . $this->literal( $vals[
'CiAdrRegion'] )
1646 if ( isset( $vals[
'CiUrlWork'] ) ) {
1647 $url =
'<span class="url">'
1648 . $this->literal( $vals[
'CiUrlWork'] )
1652 return $this->msg(
'exif-contact-value', $email, $url,
1653 $street, $city, $region, $postal, $country, $tel )->text();
1665 $lines = explode(
"\n",
wfMessage(
'metadata-fields' )->inContentLanguage()->text() );
1666 foreach (
$lines as $line ) {
1668 if ( preg_match(
'/^\\*\s*(.*?)\s*$/', $line,
$matches ) ) {
1672 $fields = array_map(
'strtolower', $fields );
1685 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1692 $cacheKey = $cache->makeKey(
1693 'getExtendedMetadata',
1694 $this->getLanguage()->getCode(),
1695 (
int)$this->singleLang,
1699 $cachedValue = $cache->get( $cacheKey );
1702 && $this->getHookRunner()->onValidateExtendedMetadataCache( $cachedValue[
'timestamp'],
$file )
1704 $extendedMetadata = $cachedValue[
'data'];
1707 $fileMetadata = $this->getExtendedMetadataFromFile(
$file );
1708 $extendedMetadata = $this->getExtendedMetadataFromHook(
$file, $fileMetadata, $maxCacheTime );
1709 if ( $this->singleLang ) {
1710 $this->resolveMultilangMetadata( $extendedMetadata );
1712 $this->discardMultipleValues( $extendedMetadata );
1717 $this->sanitizeArrayForAPI( $extendedMetadata );
1718 $valueToCache = [
'data' => $extendedMetadata,
'timestamp' =>
wfTimestampNow() ];
1719 $cache->set( $cacheKey, $valueToCache, $maxCacheTime );
1722 return $extendedMetadata;
1740 return $file->getExtendedMetadata() ?: [];
1748 'value' => $uploadDate,
1749 'source' =>
'mediawiki-metadata',
1755 $text =
$title->getText();
1756 $pos = strrpos( $text,
'.' );
1759 $name = substr( $text, 0, $pos );
1764 $fileMetadata[
'ObjectName'] = [
1766 'source' =>
'mediawiki-metadata',
1770 return $fileMetadata;
1786 $this->getHookRunner()->onGetExtendedMetadata(
1794 $visible = array_fill_keys( self::getVisibleFields(),
true );
1795 foreach ( $extendedMetadata as $key => $value ) {
1796 if ( !isset( $visible[strtolower( $key )] ) ) {
1797 $extendedMetadata[$key][
'hidden'] =
'';
1801 return $extendedMetadata;
1815 || !isset( $value[
'_type'] )
1816 || $value[
'_type'] !=
'lang'
1822 $priorityLanguages = $this->getPriorityLanguages();
1823 foreach ( $priorityLanguages as
$lang ) {
1824 if ( isset( $value[
$lang] ) ) {
1825 return $value[
$lang];
1830 if ( isset( $value[
'x-default'] ) ) {
1831 return $value[
'x-default'];
1835 unset( $value[
'_type'] );
1836 if ( !empty( $value ) ) {
1837 return reset( $value );
1854 if ( !is_array( $value ) ) {
1856 } elseif ( isset( $value[
'_type'] ) && $value[
'_type'] ===
'lang' ) {
1859 foreach ( $value as $k => $v ) {
1860 $newValue[$k] = $this->resolveMultivalueValue( $v );
1864 $v = reset( $value );
1865 if ( key( $value ) ===
'_type' ) {
1866 $v = next( $value );
1879 if ( !is_array( $metadata ) ) {
1882 foreach ( $metadata as &$field ) {
1883 if ( isset( $field[
'value'] ) ) {
1884 $field[
'value'] = $this->resolveMultilangValue( $field[
'value'] );
1896 if ( !is_array( $metadata ) ) {
1899 foreach ( $metadata as $key => &$field ) {
1900 if ( $key ===
'Software' || $key ===
'Contact' ) {
1905 if ( isset( $field[
'value'] ) ) {
1906 $field[
'value'] = $this->resolveMultivalueValue( $field[
'value'] );
1916 if ( !is_array( $arr ) ) {
1921 foreach ( $arr as $key => &$value ) {
1922 $sanitizedKey = $this->sanitizeKeyForAPI( $key );
1923 if ( $sanitizedKey !== $key ) {
1924 if ( isset( $arr[$sanitizedKey] ) ) {
1929 $sanitizedKey .= $counter;
1932 $arr[$sanitizedKey] = $arr[$key];
1933 unset( $arr[$key] );
1935 if ( is_array( $value ) ) {
1936 $this->sanitizeArrayForAPI( $value );
1941 $keys = array_filter( array_keys( $arr ), [ ApiResult::class,
'isMetadataKey' ] );
1957 $key = preg_replace(
'/[^a-zA-z0-9_:.\-]/',
'', $key );
1959 $key = preg_replace(
'/^[\d\-.]+/',
'', $key );
1961 if ( $key ===
'' ) {
1964 } elseif ( $key ===
'_element' ) {
1978 $priorityLanguages = MediaWikiServices::getInstance()
1979 ->getLanguageFallback()
1980 ->getAllIncludingSiteLanguage( $this->getLanguage()->getCode() );
1981 $priorityLanguages = array_merge(
1982 (array)$this->getLanguage()->getCode(),
1983 $priorityLanguages[0],
1984 $priorityLanguages[1]
1987 return $priorityLanguages;
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
static setPreserveKeysList(array &$arr, $names)
Preserve specified keys.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
setContext(IContextSource $context)
Implements some public methods and some protected utility functions which are required by multiple ch...
Foreign file accessible through api.php requests.
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
if(!isset( $args[0])) $lang
if(!file_exists( $CREDITS)) $lines