36 private static $transformCount = 0;
42 private $contentLanguage;
45 private $badFileLookup;
58 $prefixOrRepoGroup =
null,
59 $repoGroupOrContentLanguage =
null,
60 $contentLanguageOrBadFileLookup =
null,
61 $badFileLookupOrUnused =
null
65 if ( !is_string( $prefixOrRepoGroup ) ) {
67 $repoGroup = $prefixOrRepoGroup;
68 $contentLanguage = $repoGroupOrContentLanguage;
69 $badFileLookup = $contentLanguageOrBadFileLookup;
72 $prefix = $prefixOrRepoGroup;
73 $repoGroup = $repoGroupOrContentLanguage;
74 $contentLanguage = $contentLanguageOrBadFileLookup;
75 $badFileLookup = $badFileLookupOrUnused;
77 parent::__construct( $query, $moduleName, $prefix );
79 $services = MediaWikiServices::getInstance();
80 $this->repoGroup = $repoGroup ?? $services->getRepoGroup();
81 $this->contentLanguage = $contentLanguage ?? $services->getContentLanguage();
82 $this->badFileLookup = $badFileLookup ?? $services->getBadFileLookup();
88 $prop = array_fill_keys( $params[
'prop'],
true );
93 'version' => $params[
'metadataversion'],
94 'language' => $params[
'extmetadatalanguage'],
95 'multilang' => $params[
'extmetadatamultilang'],
96 'extmetadatafilter' => $params[
'extmetadatafilter'],
100 if ( isset( $params[
'badfilecontexttitle'] ) ) {
101 $badFileContextTitle = Title::newFromText( $params[
'badfilecontexttitle'] );
102 if ( !$badFileContextTitle || $badFileContextTitle->isExternal() ) {
104 $this->
dieWithError( [
'apierror-bad-badfilecontexttitle', $p ],
'invalid-title' );
107 $badFileContextTitle =
null;
110 $pageIds = $this->
getPageSet()->getGoodAndMissingTitlesByNamespace();
111 if ( !empty( $pageIds[
NS_FILE] ) ) {
112 $titles = array_keys( $pageIds[
NS_FILE] );
116 if ( $params[
'continue'] !==
null ) {
117 $cont = explode(
'|', $params[
'continue'] );
119 $fromTitle = strval( $cont[0] );
120 $fromTimestamp = $cont[1];
122 foreach ( $titles as $key =>
$title ) {
123 if (
$title < $fromTitle ) {
124 unset( $titles[$key] );
132 $findTitles = array_map(
static function (
$title ) use ( $performer ) {
135 'private' => $performer,
139 if ( $params[
'localonly'] ) {
140 $images = $this->repoGroup->getLocalRepo()->findFiles( $findTitles );
142 $images = $this->repoGroup->findFiles( $findTitles );
146 foreach ( $titles as
$title ) {
151 $start =
$title === $fromTitle ? $fromTimestamp : $params[
'start'];
153 if ( !isset( $images[
$title] ) ) {
154 if ( isset( $prop[
'uploadwarning'] ) || isset( $prop[
'badfile'] ) ) {
156 $images[
$title] = $this->repoGroup->getLocalRepo()->newFile(
$title );
158 $info[
'imagerepository'] =
'';
161 [
'query',
'pages', (
int)$pageId ],
162 'imagerepository',
''
172 if ( self::getTransformCount() >= self::TRANSFORM_LIMIT ) {
173 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
176 $start ??
wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
185 if ( !isset( $info[
'imagerepository'] ) ) {
186 $info[
'imagerepository'] = $img->getRepoName();
188 if ( isset( $prop[
'badfile'] ) ) {
189 $info[
'badfile'] = (bool)$this->badFileLookup->isBadFile(
$title, $badFileContextTitle );
192 $fit = $result->addValue( [
'query',
'pages' ], (
int)$pageId, $info );
194 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
201 $start ??
wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
211 $finalThumbParams = $this->
mergeThumbParams( $img, $scale, $params[
'urlparam'] );
217 if ( $badFileContextTitle && $finalThumbParams ) {
218 $finalThumbParams[
'targetlang'] = $badFileContextTitle->getPageLanguage()->getCode();
225 ( $start ===
null || $img->getTimestamp() <= $start ) &&
226 ( $params[
'end'] ===
null || $img->getTimestamp() >= $params[
'end'] )
231 static::getInfo( $img, $prop, $result,
232 $finalThumbParams, $opts
236 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
239 wfTimestamp( TS_ISO_8601, $img->getTimestamp() ) );
250 $count = ( $gotOne ? 1 : 0 );
251 $oldies = $img->getHistory( $params[
'limit'] - $count + 1, $start, $params[
'end'] );
253 foreach ( $oldies as $oldie ) {
254 if ( ++$count > $params[
'limit'] ) {
258 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
260 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
266 static::getInfo( $oldie, $prop, $result,
267 $finalThumbParams, $opts
271 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
273 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
294 if ( $params[
'urlwidth'] != -1 ) {
296 $scale[
'width'] = $params[
'urlwidth'];
297 $scale[
'height'] = $params[
'urlheight'];
298 } elseif ( $params[
'urlheight'] != -1 ) {
302 $scale[
'height'] = $params[
'urlheight'];
303 } elseif ( $params[
'urlparam'] ) {
323 if ( $thumbParams ===
null ) {
327 if ( !isset( $thumbParams[
'width'] ) && isset( $thumbParams[
'height'] ) ) {
332 if ( $image->getWidth() <= 0 ) {
333 $thumbParams[
'width'] =
334 max( $this->
getConfig()->
get( MainConfigNames::ThumbLimits ) );
336 $thumbParams[
'width'] = $image->getWidth();
340 if ( !$otherParams ) {
346 $h = $image->getHandler();
353 $paramList = $h->parseParamString( $otherParams );
365 isset( $paramList[
'width'] ) && isset( $thumbParams[
'width'] ) &&
366 (
int)$paramList[
'width'] != (
int)$thumbParams[
'width']
369 [
'apiwarn-urlparamwidth', $p, $paramList[
'width'], $thumbParams[
'width'] ]
373 foreach ( $paramList as $name => $value ) {
374 if ( !$h->validateParam( $name, $value ) ) {
381 $finalParams = $thumbParams + $paramList;
398 $h = $image->getHandler();
405 if ( !$h->normaliseParams( $image, $finalParams ) ) {
425 public static function getInfo(
$file, $prop, $result, $thumbParams =
null, $opts =
false ) {
428 if ( !$opts || is_string( $opts ) ) {
430 'version' => $opts ?:
'latest',
431 'language' => MediaWikiServices::getInstance()->getContentLanguage(),
432 'multilang' =>
false,
433 'extmetadatafilter' => [],
434 'revdelUser' =>
null,
437 $version = $opts[
'version'];
439 ApiResult::META_TYPE =>
'assoc',
443 $exists =
$file->exists();
447 if ( isset( $prop[
'timestamp'] ) && $exists ) {
452 if ( isset( $opts[
'revdelUser'] ) && $opts[
'revdelUser'] ) {
453 $revdelUser = $opts[
'revdelUser'];
454 $canShowField =
static function ( $field ) use (
$file, $revdelUser ) {
455 return $file->userCan( $field, $revdelUser );
458 $canShowField =
static function ( $field ) use (
$file ) {
459 return !
$file->isDeleted( $field );
463 $user = isset( $prop[
'user'] );
464 $userid = isset( $prop[
'userid'] );
466 if ( ( $user || $userid ) && $exists ) {
467 if (
$file->isDeleted( File::DELETED_USER ) ) {
468 $vals[
'userhidden'] =
true;
471 if ( $canShowField( File::DELETED_USER ) ) {
473 $uploader =
$file->getUploader( File::RAW );
475 $vals[
'user'] = $uploader ? $uploader->getName() :
'';
478 $vals[
'userid'] = $uploader ? $uploader->getId() : 0;
480 if ( $uploader && !$uploader->isRegistered() ) {
481 $vals[
'anon'] =
true;
488 if ( ( isset( $prop[
'size'] ) || isset( $prop[
'dimensions'] ) ) && $exists ) {
489 $vals[
'size'] = (int)
$file->getSize();
490 $vals[
'width'] = (int)
$file->getWidth();
491 $vals[
'height'] = (int)
$file->getHeight();
493 $pageCount =
$file->pageCount();
494 if ( $pageCount !==
false ) {
495 $vals[
'pagecount'] = $pageCount;
499 $length =
$file->getLength();
502 $vals[
'duration'] = (float)$length;
506 $pcomment = isset( $prop[
'parsedcomment'] );
507 $comment = isset( $prop[
'comment'] );
509 if ( ( $pcomment || $comment ) && $exists ) {
510 if (
$file->isDeleted( File::DELETED_COMMENT ) ) {
511 $vals[
'commenthidden'] =
true;
514 if ( $canShowField( File::DELETED_COMMENT ) ) {
517 $file->getDescription( File::RAW ),
$file->getTitle() );
520 $vals[
'comment'] =
$file->getDescription( File::RAW );
525 $canonicaltitle = isset( $prop[
'canonicaltitle'] );
526 $url = isset( $prop[
'url'] );
527 $sha1 = isset( $prop[
'sha1'] );
528 $meta = isset( $prop[
'metadata'] );
529 $extmetadata = isset( $prop[
'extmetadata'] );
530 $commonmeta = isset( $prop[
'commonmetadata'] );
531 $mime = isset( $prop[
'mime'] );
532 $mediatype = isset( $prop[
'mediatype'] );
533 $archive = isset( $prop[
'archivename'] );
534 $bitdepth = isset( $prop[
'bitdepth'] );
535 $uploadwarning = isset( $prop[
'uploadwarning'] );
537 if ( $uploadwarning ) {
538 $vals[
'html'] = SpecialUpload::getExistsWarning( UploadBase::getExistsWarning(
$file ) );
541 if (
$file->isDeleted( File::DELETED_FILE ) ) {
542 $vals[
'filehidden'] =
true;
546 if ( $anyHidden &&
$file->isDeleted( File::DELETED_RESTRICTED ) ) {
547 $vals[
'suppressed'] =
true;
551 if ( isset( $opts[
'revdelUser'] ) && $opts[
'revdelUser']
552 && !
$file->userCan( File::DELETED_FILE, $opts[
'revdelUser'] )
555 } elseif (
$file->isDeleted( File::DELETED_FILE ) ) {
559 if ( $canonicaltitle ) {
560 $vals[
'canonicaltitle'] =
$file->getTitle()->getPrefixedText();
565 if ( $thumbParams !==
null ) {
566 $mto =
$file->transform( $thumbParams );
567 self::$transformCount++;
568 if ( $mto && !$mto->isError() ) {
573 if ( $mto->getUrl() !==
$file->getUrl() ) {
574 $vals[
'thumbwidth'] = (int)$mto->getWidth();
575 $vals[
'thumbheight'] = (int)$mto->getHeight();
577 $vals[
'thumbwidth'] = (int)
$file->getWidth();
578 $vals[
'thumbheight'] = (int)
$file->getHeight();
581 if ( isset( $prop[
'thumbmime'] ) &&
$file->getHandler() ) {
582 list( ,
$mime ) =
$file->getHandler()->getThumbType(
583 $mto->getExtension(),
$file->getMimeType(), $thumbParams );
584 $vals[
'thumbmime'] =
$mime;
588 'width' => $vals[
'thumbwidth'],
589 'height' => $vals[
'thumbheight']
591 foreach ( $mto->responsiveUrls as $density => $url ) {
594 } elseif ( $mto && $mto->isError() ) {
596 '@phan-var MediaTransformError $mto';
597 $vals[
'thumberror'] = $mto->toText();
604 $shortDescriptionUrl =
$file->getDescriptionShortUrl();
605 if ( $shortDescriptionUrl !==
null ) {
611 $vals[
'filemissing'] =
true;
614 if ( $sha1 && $exists ) {
615 $vals[
'sha1'] = Wikimedia\base_convert(
$file->getSha1(), 36, 16, 40 );
618 if ( $meta && $exists ) {
619 $metadata =
$file->getMetadataArray();
620 if ( $metadata && $version !==
'latest' ) {
621 $metadata =
$file->convertMetadataVersion( $metadata, $version );
623 $vals[
'metadata'] = $metadata ? static::processMetaData( $metadata, $result ) :
null;
625 if ( $commonmeta && $exists ) {
626 $metaArray =
$file->getCommonMetaArray();
627 $vals[
'commonmetadata'] = $metaArray ? static::processMetaData( $metaArray, $result ) : [];
630 if ( $extmetadata && $exists ) {
637 $format->getContext()->setLanguage( $opts[
'language'] );
638 $extmetaArray = $format->fetchExtendedMetadata(
$file );
639 if ( $opts[
'extmetadatafilter'] ) {
640 $extmetaArray = array_intersect_key(
641 $extmetaArray, array_fill_keys( $opts[
'extmetadatafilter'],
true )
644 $vals[
'extmetadata'] = $extmetaArray;
647 if (
$mime && $exists ) {
648 $vals[
'mime'] =
$file->getMimeType();
651 if ( $mediatype && $exists ) {
652 $vals[
'mediatype'] =
$file->getMediaType();
655 if ( $archive &&
$file->isOld() ) {
657 '@phan-var OldLocalFile $file';
658 $vals[
'archivename'] =
$file->getArchiveName();
661 if ( $bitdepth && $exists ) {
662 $vals[
'bitdepth'] =
$file->getBitDepth();
676 return self::$transformCount;
686 if ( is_array( $metadata ) ) {
687 foreach ( $metadata as $key => $value ) {
690 ApiResult::META_BC_BOOLS => [
'value' ],
692 if ( is_array( $value ) ) {
693 $r[
'value'] = static::processMetaData( $value, $result );
695 $r[
'value'] = $value;
700 ApiResult::setIndexedTagName( $retval,
'metadata' );
719 if ( $start ===
null ) {
720 $start = $img->getTimestamp();
723 return $img->getOriginalTitle()->getDBkey() .
'|' . $start;
729 ParamValidator::PARAM_ISMULTI =>
true,
730 ParamValidator::PARAM_DEFAULT =>
'timestamp|user',
731 ParamValidator::PARAM_TYPE => static::getPropertyNames(),
735 ParamValidator::PARAM_TYPE =>
'limit',
736 ParamValidator::PARAM_DEFAULT => 1,
737 IntegerDef::PARAM_MIN => 1,
742 ParamValidator::PARAM_TYPE =>
'timestamp'
745 ParamValidator::PARAM_TYPE =>
'timestamp'
748 ParamValidator::PARAM_TYPE =>
'integer',
749 ParamValidator::PARAM_DEFAULT => -1,
751 'apihelp-query+imageinfo-param-urlwidth',
756 ParamValidator::PARAM_TYPE =>
'integer',
757 ParamValidator::PARAM_DEFAULT => -1
759 'metadataversion' => [
760 ParamValidator::PARAM_TYPE =>
'string',
761 ParamValidator::PARAM_DEFAULT =>
'1',
763 'extmetadatalanguage' => [
764 ParamValidator::PARAM_TYPE =>
'string',
765 ParamValidator::PARAM_DEFAULT =>
766 $this->contentLanguage->getCode(),
768 'extmetadatamultilang' => [
769 ParamValidator::PARAM_TYPE =>
'boolean',
770 ParamValidator::PARAM_DEFAULT =>
false,
772 'extmetadatafilter' => [
773 ParamValidator::PARAM_TYPE =>
'string',
774 ParamValidator::PARAM_ISMULTI =>
true,
777 ParamValidator::PARAM_DEFAULT =>
'',
778 ParamValidator::PARAM_TYPE =>
'string',
780 'badfilecontexttitle' => [
781 ParamValidator::PARAM_TYPE =>
'string',
787 ParamValidator::PARAM_TYPE =>
'boolean',
788 ParamValidator::PARAM_DEFAULT =>
false,
800 return array_keys( static::getPropertyMessages( $filter ) );
810 return array_diff_key(
812 'timestamp' =>
'apihelp-query+imageinfo-paramvalue-prop-timestamp',
813 'user' =>
'apihelp-query+imageinfo-paramvalue-prop-user',
814 'userid' =>
'apihelp-query+imageinfo-paramvalue-prop-userid',
815 'comment' =>
'apihelp-query+imageinfo-paramvalue-prop-comment',
816 'parsedcomment' =>
'apihelp-query+imageinfo-paramvalue-prop-parsedcomment',
817 'canonicaltitle' =>
'apihelp-query+imageinfo-paramvalue-prop-canonicaltitle',
818 'url' =>
'apihelp-query+imageinfo-paramvalue-prop-url',
819 'size' =>
'apihelp-query+imageinfo-paramvalue-prop-size',
820 'dimensions' =>
'apihelp-query+imageinfo-paramvalue-prop-dimensions',
821 'sha1' =>
'apihelp-query+imageinfo-paramvalue-prop-sha1',
822 'mime' =>
'apihelp-query+imageinfo-paramvalue-prop-mime',
823 'thumbmime' =>
'apihelp-query+imageinfo-paramvalue-prop-thumbmime',
824 'mediatype' =>
'apihelp-query+imageinfo-paramvalue-prop-mediatype',
825 'metadata' =>
'apihelp-query+imageinfo-paramvalue-prop-metadata',
826 'commonmetadata' =>
'apihelp-query+imageinfo-paramvalue-prop-commonmetadata',
827 'extmetadata' =>
'apihelp-query+imageinfo-paramvalue-prop-extmetadata',
828 'archivename' =>
'apihelp-query+imageinfo-paramvalue-prop-archivename',
829 'bitdepth' =>
'apihelp-query+imageinfo-paramvalue-prop-bitdepth',
830 'uploadwarning' =>
'apihelp-query+imageinfo-paramvalue-prop-uploadwarning',
831 'badfile' =>
'apihelp-query+imageinfo-paramvalue-prop-badfile',
833 array_fill_keys( $filter,
true )
839 'action=query&titles=File:Albert%20Einstein%20Head.jpg&prop=imageinfo'
840 =>
'apihelp-query+imageinfo-example-simple',
841 'action=query&titles=File:Test.jpg&prop=imageinfo&iilimit=50&' .
842 'iiend=2007-12-31T23:59:59Z&iiprop=timestamp|user|url'
843 =>
'apihelp-query+imageinfo-example-dated',
848 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Imageinfo';
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
const LIMIT_BIG1
Fast query, standard limit.
getResult()
Get the result object.
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
const LIMIT_BIG2
Fast query, apihighlimits limit.
This is a base class for all Query modules.
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
addPageSubItem( $pageId, $item, $elemname=null)
Same as addPageSubItems(), but one element of $data at a time.
getPageSet()
Get the PageSet object to work on.
userCanSeeRevDel()
Check whether the current user has permission to view revision-deleted fields.
A query action to get image information and upload history.
checkParameterNormalise( $image, $finalParams)
Verify that the final image parameters can be normalised.
mergeThumbParams( $image, $thumbParams, $otherParams)
Validate and merge scale parameters with handler thumb parameters, give error if invalid.
getCacheMode( $params)
Get the cache mode for the data generated by this module.
getScale( $params)
From parameters, construct a 'scale' array.
__construct(ApiQuery $query, $moduleName, $prefixOrRepoGroup=null, $repoGroupOrContentLanguage=null, $contentLanguageOrBadFileLookup=null, $badFileLookupOrUnused=null)
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getHelpUrls()
Return links to more detailed help pages about the module.
static getPropertyNames( $filter=[])
Returns all possible parameters to iiprop.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getContinueStr( $img, $start=null)
static getInfo( $file, $prop, $result, $thumbParams=null, $opts=false)
Get result information for an image revision.
static getTransformCount()
Get the count of image transformations performed.
static getPropertyMessages( $filter=[])
Returns messages for all possible parameters to iiprop.
static processMetaData( $metadata, $result)
getExamplesMessages()
Returns usage examples for this module.
This is the main query class.
Implements some public methods and some protected utility functions which are required by multiple ch...
Base class for language-specific code.
static processResponsiveImages( $file, $thumb, $hp)
Process responsive images: add 1.5x and 2x subimages to the thumbnail, where applicable.
static formatComment( $comment, $title=null, $local=false, $wikiId=null)
This function is called by all recent changes variants, by the page history, and by the user contribu...
A class containing constants representing the names of configuration variables.
Prioritized list of file repositories.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.