39 private static $transformCount = 0;
56 $prefixOrRepoGroup =
null,
57 $repoGroupOrContentLanguage =
null,
58 $contentLanguageOrBadFileLookup =
null,
59 $badFileLookupOrUnused =
null
63 if ( !is_string( $prefixOrRepoGroup ) ) {
65 $repoGroup = $prefixOrRepoGroup;
66 $contentLanguage = $repoGroupOrContentLanguage;
67 $badFileLookup = $contentLanguageOrBadFileLookup;
70 $prefix = $prefixOrRepoGroup;
71 $repoGroup = $repoGroupOrContentLanguage;
72 $contentLanguage = $contentLanguageOrBadFileLookup;
73 $badFileLookup = $badFileLookupOrUnused;
75 parent::__construct( $query, $moduleName, $prefix );
77 $services = MediaWikiServices::getInstance();
78 $this->repoGroup = $repoGroup ?? $services->getRepoGroup();
79 $this->contentLanguage = $contentLanguage ?? $services->getContentLanguage();
80 $this->badFileLookup = $badFileLookup ?? $services->getBadFileLookup();
86 $prop = array_fill_keys( $params[
'prop'],
true );
91 'version' => $params[
'metadataversion'],
92 'language' => $params[
'extmetadatalanguage'],
93 'multilang' => $params[
'extmetadatamultilang'],
94 'extmetadatafilter' => $params[
'extmetadatafilter'],
98 if ( isset( $params[
'badfilecontexttitle'] ) ) {
99 $badFileContextTitle = Title::newFromText( $params[
'badfilecontexttitle'] );
100 if ( !$badFileContextTitle || $badFileContextTitle->isExternal() ) {
102 $this->
dieWithError( [
'apierror-bad-badfilecontexttitle', $p ],
'invalid-title' );
105 $badFileContextTitle =
null;
108 $pageIds = $this->
getPageSet()->getGoodAndMissingTitlesByNamespace();
109 if ( !empty( $pageIds[
NS_FILE] ) ) {
110 $titles = array_keys( $pageIds[
NS_FILE] );
114 if ( $params[
'continue'] !==
null ) {
116 $fromTitle = $cont[0];
117 $fromTimestamp = $cont[1];
119 foreach ( $titles as $key => $title ) {
120 if ( $title < $fromTitle ) {
121 unset( $titles[$key] );
129 $findTitles = array_map(
static function ( $title ) use ( $performer ) {
132 'private' => $performer,
136 if ( $params[
'localonly'] ) {
137 $images = $this->repoGroup->getLocalRepo()->findFiles( $findTitles );
139 $images = $this->repoGroup->findFiles( $findTitles );
143 foreach ( $titles as $title ) {
145 $pageId = $pageIds[
NS_FILE][$title];
148 $start = $title === $fromTitle ? $fromTimestamp : $params[
'start'];
150 if ( !isset( $images[$title] ) ) {
151 if ( isset( $prop[
'uploadwarning'] ) || isset( $prop[
'badfile'] ) ) {
153 $images[$title] = $this->repoGroup->getLocalRepo()->newFile( $title );
155 $info[
'imagerepository'] =
'';
158 [
'query',
'pages', (
int)$pageId ],
159 'imagerepository',
''
167 $img = $images[$title];
169 if ( self::getTransformCount() >= self::TRANSFORM_LIMIT ) {
170 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
173 $start ??
wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
182 if ( !isset( $info[
'imagerepository'] ) ) {
183 $info[
'imagerepository'] = $img->getRepoName();
185 if ( isset( $prop[
'badfile'] ) ) {
186 $info[
'badfile'] = (bool)$this->badFileLookup->isBadFile( $title, $badFileContextTitle );
189 $fit = $result->addValue( [
'query',
'pages' ], (
int)$pageId, $info );
191 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
198 $start ??
wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
208 $finalThumbParams = $this->
mergeThumbParams( $img, $scale, $params[
'urlparam'] );
214 if ( $badFileContextTitle && $finalThumbParams ) {
215 $finalThumbParams[
'targetlang'] = $badFileContextTitle->getPageLanguage()->getCode();
222 ( $start ===
null || $img->getTimestamp() <= $start ) &&
223 ( $params[
'end'] ===
null || $img->getTimestamp() >= $params[
'end'] )
228 static::getInfo( $img, $prop, $result,
229 $finalThumbParams, $opts
233 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
236 wfTimestamp( TS_ISO_8601, $img->getTimestamp() ) );
247 $count = ( $gotOne ? 1 : 0 );
248 $oldies = $img->getHistory( $params[
'limit'] - $count + 1, $start, $params[
'end'] );
250 foreach ( $oldies as $oldie ) {
251 if ( ++$count > $params[
'limit'] ) {
255 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
257 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
263 static::getInfo( $oldie, $prop, $result,
264 $finalThumbParams, $opts
268 if ( count( $pageIds[
NS_FILE] ) == 1 ) {
270 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
291 if ( $params[
'urlwidth'] != -1 ) {
293 $scale[
'width'] = $params[
'urlwidth'];
294 $scale[
'height'] = $params[
'urlheight'];
295 } elseif ( $params[
'urlheight'] != -1 ) {
299 $scale[
'height'] = $params[
'urlheight'];
300 } elseif ( $params[
'urlparam'] ) {
320 if ( $thumbParams ===
null ) {
324 if ( !isset( $thumbParams[
'width'] ) && isset( $thumbParams[
'height'] ) ) {
329 if ( $image->getWidth() <= 0 ) {
330 $thumbParams[
'width'] =
331 max( $this->
getConfig()->
get( MainConfigNames::ThumbLimits ) );
333 $thumbParams[
'width'] = $image->getWidth();
337 if ( !$otherParams ) {
343 $h = $image->getHandler();
350 $paramList = $h->parseParamString( $otherParams );
362 isset( $paramList[
'width'] ) && isset( $thumbParams[
'width'] ) &&
363 (
int)$paramList[
'width'] != (
int)$thumbParams[
'width']
366 [
'apiwarn-urlparamwidth', $p, $paramList[
'width'], $thumbParams[
'width'] ]
370 foreach ( $paramList as $name => $value ) {
371 if ( !$h->validateParam( $name, $value ) ) {
378 $finalParams = $thumbParams + $paramList;
395 $h = $image->getHandler();
402 if ( !$h->normaliseParams( $image, $finalParams ) ) {
422 public static function getInfo(
$file, $prop, $result, $thumbParams =
null, $opts =
false ) {
425 $services = MediaWikiServices::getInstance();
427 if ( !$opts || is_string( $opts ) ) {
429 'version' => $opts ?:
'latest',
430 'language' => $services->getContentLanguage(),
431 'multilang' =>
false,
432 'extmetadatafilter' => [],
433 'revdelUser' =>
null,
436 $version = $opts[
'version'];
438 ApiResult::META_TYPE =>
'assoc',
442 $exists =
$file->exists();
446 if ( isset( $prop[
'timestamp'] ) && $exists ) {
451 if ( isset( $opts[
'revdelUser'] ) && $opts[
'revdelUser'] ) {
452 $revdelUser = $opts[
'revdelUser'];
453 $canShowField =
static function ( $field ) use (
$file, $revdelUser ) {
454 return $file->userCan( $field, $revdelUser );
457 $canShowField =
static function ( $field ) use (
$file ) {
458 return !
$file->isDeleted( $field );
462 $user = isset( $prop[
'user'] );
463 $userid = isset( $prop[
'userid'] );
465 if ( ( $user || $userid ) && $exists ) {
466 if (
$file->isDeleted( File::DELETED_USER ) ) {
467 $vals[
'userhidden'] =
true;
470 if ( $canShowField( File::DELETED_USER ) ) {
472 $uploader =
$file->getUploader( File::RAW );
474 $vals[
'user'] = $uploader ? $uploader->getName() :
'';
477 $vals[
'userid'] = $uploader ? $uploader->getId() : 0;
479 if ( $uploader && !$uploader->isRegistered() ) {
480 $vals[
'anon'] =
true;
487 if ( ( isset( $prop[
'size'] ) || isset( $prop[
'dimensions'] ) ) && $exists ) {
488 $vals[
'size'] = (int)
$file->getSize();
489 $vals[
'width'] = (int)
$file->getWidth();
490 $vals[
'height'] = (int)
$file->getHeight();
492 $pageCount =
$file->pageCount();
493 if ( $pageCount !==
false ) {
494 $vals[
'pagecount'] = $pageCount;
498 $length =
$file->getLength();
501 $vals[
'duration'] = (float)$length;
505 $pcomment = isset( $prop[
'parsedcomment'] );
506 $comment = isset( $prop[
'comment'] );
508 if ( ( $pcomment || $comment ) && $exists ) {
509 if (
$file->isDeleted( File::DELETED_COMMENT ) ) {
510 $vals[
'commenthidden'] =
true;
513 if ( $canShowField( File::DELETED_COMMENT ) ) {
515 $vals[
'parsedcomment'] = $services->getCommentFormatter()->format(
516 $file->getDescription( File::RAW ),
$file->getTitle() );
519 $vals[
'comment'] =
$file->getDescription( File::RAW );
524 $canonicaltitle = isset( $prop[
'canonicaltitle'] );
525 $url = isset( $prop[
'url'] );
526 $sha1 = isset( $prop[
'sha1'] );
527 $meta = isset( $prop[
'metadata'] );
528 $extmetadata = isset( $prop[
'extmetadata'] );
529 $commonmeta = isset( $prop[
'commonmetadata'] );
530 $mime = isset( $prop[
'mime'] );
531 $mediatype = isset( $prop[
'mediatype'] );
532 $archive = isset( $prop[
'archivename'] );
533 $bitdepth = isset( $prop[
'bitdepth'] );
534 $uploadwarning = isset( $prop[
'uploadwarning'] );
536 if ( $uploadwarning ) {
537 $vals[
'html'] = SpecialUpload::getExistsWarning( UploadBase::getExistsWarning(
$file ) );
540 if (
$file->isDeleted( File::DELETED_FILE ) ) {
541 $vals[
'filehidden'] =
true;
545 if ( $anyHidden &&
$file->isDeleted( File::DELETED_RESTRICTED ) ) {
546 $vals[
'suppressed'] =
true;
550 if ( isset( $opts[
'revdelUser'] ) && $opts[
'revdelUser']
551 && !
$file->userCan( File::DELETED_FILE, $opts[
'revdelUser'] )
554 } elseif (
$file->isDeleted( File::DELETED_FILE ) ) {
558 if ( $canonicaltitle ) {
559 $vals[
'canonicaltitle'] =
$file->getTitle()->getPrefixedText();
563 $urlUtils = $services->getUrlUtils();
566 if ( $thumbParams !==
null ) {
567 $mto =
$file->transform( $thumbParams );
568 self::$transformCount++;
569 if ( $mto && !$mto->isError() ) {
570 $vals[
'thumburl'] = (string)$urlUtils->expand( $mto->getUrl(),
PROTO_CURRENT );
574 if ( $mto->getUrl() !==
$file->getUrl() ) {
575 $vals[
'thumbwidth'] = (int)$mto->getWidth();
576 $vals[
'thumbheight'] = (int)$mto->getHeight();
578 $vals[
'thumbwidth'] = (int)
$file->getWidth();
579 $vals[
'thumbheight'] = (int)
$file->getHeight();
582 if ( isset( $prop[
'thumbmime'] ) &&
$file->getHandler() ) {
583 [ ,
$mime ] =
$file->getHandler()->getThumbType(
584 $mto->getExtension(),
$file->getMimeType(), $thumbParams );
585 $vals[
'thumbmime'] =
$mime;
588 Linker::processResponsiveImages(
$file, $mto, [
589 'width' => $vals[
'thumbwidth'],
590 'height' => $vals[
'thumbheight']
592 foreach ( $mto->responsiveUrls as $density => $url ) {
593 $vals[
'responsiveUrls'][$density] = (string)$urlUtils->expand( $url,
PROTO_CURRENT );
595 } elseif ( $mto && $mto->isError() ) {
597 '@phan-var MediaTransformError $mto';
598 $vals[
'thumberror'] = $mto->toText();
603 $vals[
'descriptionurl'] = (string)$urlUtils->expand(
$file->getDescriptionUrl(),
PROTO_CURRENT );
605 $shortDescriptionUrl =
$file->getDescriptionShortUrl();
606 if ( $shortDescriptionUrl !==
null ) {
607 $vals[
'descriptionshorturl'] = (string)$urlUtils->expand( $shortDescriptionUrl,
PROTO_CURRENT );
612 $vals[
'filemissing'] =
true;
615 if ( $sha1 && $exists ) {
616 $vals[
'sha1'] = Wikimedia\base_convert(
$file->getSha1(), 36, 16, 40 );
619 if ( $meta && $exists ) {
620 $metadata =
$file->getMetadataArray();
621 if ( $metadata && $version !==
'latest' ) {
622 $metadata =
$file->convertMetadataVersion( $metadata, $version );
624 $vals[
'metadata'] = $metadata ? static::processMetaData( $metadata, $result ) :
null;
626 if ( $commonmeta && $exists ) {
627 $metaArray =
$file->getCommonMetaArray();
628 $vals[
'commonmetadata'] = $metaArray ? static::processMetaData( $metaArray, $result ) : [];
631 if ( $extmetadata && $exists ) {
638 $format->getContext()->setLanguage( $opts[
'language'] );
639 $extmetaArray = $format->fetchExtendedMetadata(
$file );
640 if ( $opts[
'extmetadatafilter'] ) {
641 $extmetaArray = array_intersect_key(
642 $extmetaArray, array_fill_keys( $opts[
'extmetadatafilter'],
true )
645 $vals[
'extmetadata'] = $extmetaArray;
648 if (
$mime && $exists ) {
649 $vals[
'mime'] =
$file->getMimeType();
652 if ( $mediatype && $exists ) {
653 $vals[
'mediatype'] =
$file->getMediaType();
656 if ( $archive &&
$file->isOld() ) {
658 '@phan-var OldLocalFile $file';
659 $vals[
'archivename'] =
$file->getArchiveName();
662 if ( $bitdepth && $exists ) {
663 $vals[
'bitdepth'] =
$file->getBitDepth();
677 return self::$transformCount;
687 if ( is_array( $metadata ) ) {
688 foreach ( $metadata as $key => $value ) {
691 ApiResult::META_BC_BOOLS => [
'value' ],
693 if ( is_array( $value ) ) {
694 $r[
'value'] = static::processMetaData( $value, $result );
696 $r[
'value'] = $value;
701 ApiResult::setIndexedTagName( $retval,
'metadata' );
720 return $img->getOriginalTitle()->getDBkey() .
'|' . ( $start ?? $img->getTimestamp() );
726 ParamValidator::PARAM_ISMULTI =>
true,
727 ParamValidator::PARAM_DEFAULT =>
'timestamp|user',
728 ParamValidator::PARAM_TYPE => static::getPropertyNames(),
732 ParamValidator::PARAM_TYPE =>
'limit',
733 ParamValidator::PARAM_DEFAULT => 1,
734 IntegerDef::PARAM_MIN => 1,
739 ParamValidator::PARAM_TYPE =>
'timestamp'
742 ParamValidator::PARAM_TYPE =>
'timestamp'
745 ParamValidator::PARAM_TYPE =>
'integer',
746 ParamValidator::PARAM_DEFAULT => -1,
748 'apihelp-query+imageinfo-param-urlwidth',
753 ParamValidator::PARAM_TYPE =>
'integer',
754 ParamValidator::PARAM_DEFAULT => -1
756 'metadataversion' => [
757 ParamValidator::PARAM_TYPE =>
'string',
758 ParamValidator::PARAM_DEFAULT =>
'1',
760 'extmetadatalanguage' => [
761 ParamValidator::PARAM_TYPE =>
'string',
762 ParamValidator::PARAM_DEFAULT =>
763 $this->contentLanguage->getCode(),
765 'extmetadatamultilang' => [
766 ParamValidator::PARAM_TYPE =>
'boolean',
767 ParamValidator::PARAM_DEFAULT =>
false,
769 'extmetadatafilter' => [
770 ParamValidator::PARAM_TYPE =>
'string',
771 ParamValidator::PARAM_ISMULTI =>
true,
774 ParamValidator::PARAM_DEFAULT =>
'',
775 ParamValidator::PARAM_TYPE =>
'string',
777 'badfilecontexttitle' => [
778 ParamValidator::PARAM_TYPE =>
'string',
784 ParamValidator::PARAM_TYPE =>
'boolean',
785 ParamValidator::PARAM_DEFAULT =>
false,
797 return array_keys( static::getPropertyMessages( $filter ) );
807 return array_diff_key(
809 'timestamp' =>
'apihelp-query+imageinfo-paramvalue-prop-timestamp',
810 'user' =>
'apihelp-query+imageinfo-paramvalue-prop-user',
811 'userid' =>
'apihelp-query+imageinfo-paramvalue-prop-userid',
812 'comment' =>
'apihelp-query+imageinfo-paramvalue-prop-comment',
813 'parsedcomment' =>
'apihelp-query+imageinfo-paramvalue-prop-parsedcomment',
814 'canonicaltitle' =>
'apihelp-query+imageinfo-paramvalue-prop-canonicaltitle',
815 'url' =>
'apihelp-query+imageinfo-paramvalue-prop-url',
816 'size' =>
'apihelp-query+imageinfo-paramvalue-prop-size',
817 'dimensions' =>
'apihelp-query+imageinfo-paramvalue-prop-dimensions',
818 'sha1' =>
'apihelp-query+imageinfo-paramvalue-prop-sha1',
819 'mime' =>
'apihelp-query+imageinfo-paramvalue-prop-mime',
820 'thumbmime' =>
'apihelp-query+imageinfo-paramvalue-prop-thumbmime',
821 'mediatype' =>
'apihelp-query+imageinfo-paramvalue-prop-mediatype',
822 'metadata' =>
'apihelp-query+imageinfo-paramvalue-prop-metadata',
823 'commonmetadata' =>
'apihelp-query+imageinfo-paramvalue-prop-commonmetadata',
824 'extmetadata' =>
'apihelp-query+imageinfo-paramvalue-prop-extmetadata',
825 'archivename' =>
'apihelp-query+imageinfo-paramvalue-prop-archivename',
826 'bitdepth' =>
'apihelp-query+imageinfo-paramvalue-prop-bitdepth',
827 'uploadwarning' =>
'apihelp-query+imageinfo-paramvalue-prop-uploadwarning',
828 'badfile' =>
'apihelp-query+imageinfo-paramvalue-prop-badfile',
830 array_fill_keys( $filter,
true )
836 'action=query&titles=File:Albert%20Einstein%20Head.jpg&prop=imageinfo'
837 =>
'apihelp-query+imageinfo-example-simple',
838 'action=query&titles=File:Test.jpg&prop=imageinfo&iilimit=50&' .
839 'iiend=2007-12-31T23:59:59Z&iiprop=timestamp|user|url'
840 =>
'apihelp-query+imageinfo-example-dated',
845 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Imageinfo';
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).
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
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.
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.