Merge "startup.js: log current time as global 'mediaWikiLoadStart'"
[lhc/web/wiklou.git] / includes / api / ApiQueryImageInfo.php
1 <?php
2 /**
3 *
4 *
5 * Created on July 6, 2007
6 *
7 * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
23 *
24 * @file
25 */
26
27 /**
28 * A query action to get image information and upload history.
29 *
30 * @ingroup API
31 */
32 class ApiQueryImageInfo extends ApiQueryBase {
33 const TRANSFORM_LIMIT = 50;
34 private static $transformCount = 0;
35
36 public function __construct( $query, $moduleName, $prefix = 'ii' ) {
37 // We allow a subclass to override the prefix, to create a related API
38 // module. Some other parts of MediaWiki construct this with a null
39 // $prefix, which used to be ignored when this only took two arguments
40 if ( is_null( $prefix ) ) {
41 $prefix = 'ii';
42 }
43 parent::__construct( $query, $moduleName, $prefix );
44 }
45
46 public function execute() {
47 $params = $this->extractRequestParams();
48
49 $prop = array_flip( $params['prop'] );
50
51 $scale = $this->getScale( $params );
52
53 $metadataOpts = array(
54 'version' => $params['metadataversion'],
55 'language' => $params['extmetadatalanguage'],
56 'multilang' => $params['extmetadatamultilang'],
57 'extmetadatafilter' => $params['extmetadatafilter'],
58 );
59
60 $pageIds = $this->getPageSet()->getAllTitlesByNamespace();
61 if ( !empty( $pageIds[NS_FILE] ) ) {
62 $titles = array_keys( $pageIds[NS_FILE] );
63 asort( $titles ); // Ensure the order is always the same
64
65 $fromTitle = null;
66 if ( !is_null( $params['continue'] ) ) {
67 $cont = explode( '|', $params['continue'] );
68 $this->dieContinueUsageIf( count( $cont ) != 2 );
69 $fromTitle = strval( $cont[0] );
70 $fromTimestamp = $cont[1];
71 // Filter out any titles before $fromTitle
72 foreach ( $titles as $key => $title ) {
73 if ( $title < $fromTitle ) {
74 unset( $titles[$key] );
75 } else {
76 break;
77 }
78 }
79 }
80
81 $result = $this->getResult();
82 //search only inside the local repo
83 if ( $params['localonly'] ) {
84 $images = RepoGroup::singleton()->getLocalRepo()->findFiles( $titles );
85 } else {
86 $images = RepoGroup::singleton()->findFiles( $titles );
87 }
88 foreach ( $titles as $title ) {
89 $pageId = $pageIds[NS_FILE][$title];
90 $start = $title === $fromTitle ? $fromTimestamp : $params['start'];
91
92 if ( !isset( $images[$title] ) ) {
93 if ( isset( $prop['uploadwarning'] ) ) {
94 // Uploadwarning needs info about non-existing files
95 $images[$title] = wfLocalFile( $title );
96 } else {
97 $result->addValue(
98 array( 'query', 'pages', intval( $pageId ) ),
99 'imagerepository', ''
100 );
101 // The above can't fail because it doesn't increase the result size
102 continue;
103 }
104 }
105
106 /** @var $img File */
107 $img = $images[$title];
108
109 if ( self::getTransformCount() >= self::TRANSFORM_LIMIT ) {
110 if ( count( $pageIds[NS_FILE] ) == 1 ) {
111 // See the 'the user is screwed' comment below
112 $this->setContinueEnumParameter( 'start',
113 $start !== null ? $start : wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
114 );
115 } else {
116 $this->setContinueEnumParameter( 'continue',
117 $this->getContinueStr( $img, $start ) );
118 }
119 break;
120 }
121
122 $fit = $result->addValue(
123 array( 'query', 'pages', intval( $pageId ) ),
124 'imagerepository', $img->getRepoName()
125 );
126 if ( !$fit ) {
127 if ( count( $pageIds[NS_FILE] ) == 1 ) {
128 // The user is screwed. imageinfo can't be solely
129 // responsible for exceeding the limit in this case,
130 // so set a query-continue that just returns the same
131 // thing again. When the violating queries have been
132 // out-continued, the result will get through
133 $this->setContinueEnumParameter( 'start',
134 $start !== null ? $start : wfTimestamp( TS_ISO_8601, $img->getTimestamp() )
135 );
136 } else {
137 $this->setContinueEnumParameter( 'continue',
138 $this->getContinueStr( $img, $start ) );
139 }
140 break;
141 }
142
143 // Check if we can make the requested thumbnail, and get transform parameters.
144 $finalThumbParams = $this->mergeThumbParams( $img, $scale, $params['urlparam'] );
145
146 // Get information about the current version first
147 // Check that the current version is within the start-end boundaries
148 $gotOne = false;
149 if (
150 ( is_null( $start ) || $img->getTimestamp() <= $start ) &&
151 ( is_null( $params['end'] ) || $img->getTimestamp() >= $params['end'] )
152 ) {
153 $gotOne = true;
154
155 $fit = $this->addPageSubItem( $pageId,
156 self::getInfo( $img, $prop, $result,
157 $finalThumbParams, $metadataOpts
158 )
159 );
160 if ( !$fit ) {
161 if ( count( $pageIds[NS_FILE] ) == 1 ) {
162 // See the 'the user is screwed' comment above
163 $this->setContinueEnumParameter( 'start',
164 wfTimestamp( TS_ISO_8601, $img->getTimestamp() ) );
165 } else {
166 $this->setContinueEnumParameter( 'continue',
167 $this->getContinueStr( $img ) );
168 }
169 break;
170 }
171 }
172
173 // Now get the old revisions
174 // Get one more to facilitate query-continue functionality
175 $count = ( $gotOne ? 1 : 0 );
176 $oldies = $img->getHistory( $params['limit'] - $count + 1, $start, $params['end'] );
177 /** @var $oldie File */
178 foreach ( $oldies as $oldie ) {
179 if ( ++$count > $params['limit'] ) {
180 // We've reached the extra one which shows that there are
181 // additional pages to be had. Stop here...
182 // Only set a query-continue if there was only one title
183 if ( count( $pageIds[NS_FILE] ) == 1 ) {
184 $this->setContinueEnumParameter( 'start',
185 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
186 }
187 break;
188 }
189 $fit = self::getTransformCount() < self::TRANSFORM_LIMIT &&
190 $this->addPageSubItem( $pageId,
191 self::getInfo( $oldie, $prop, $result,
192 $finalThumbParams, $metadataOpts
193 )
194 );
195 if ( !$fit ) {
196 if ( count( $pageIds[NS_FILE] ) == 1 ) {
197 $this->setContinueEnumParameter( 'start',
198 wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
199 } else {
200 $this->setContinueEnumParameter( 'continue',
201 $this->getContinueStr( $oldie ) );
202 }
203 break;
204 }
205 }
206 if ( !$fit ) {
207 break;
208 }
209 }
210 }
211 }
212
213 /**
214 * From parameters, construct a 'scale' array
215 * @param array $params Parameters passed to api.
216 * @return Array or Null: key-val array of 'width' and 'height', or null
217 */
218 public function getScale( $params ) {
219 $p = $this->getModulePrefix();
220
221 if ( $params['urlwidth'] != -1 ) {
222 $scale = array();
223 $scale['width'] = $params['urlwidth'];
224 $scale['height'] = $params['urlheight'];
225 } elseif ( $params['urlheight'] != -1 ) {
226 // Height is specified but width isn't
227 // Don't set $scale['width']; this signals mergeThumbParams() to fill it with the image's width
228 $scale = array();
229 $scale['height'] = $params['urlheight'];
230 } else {
231 $scale = null;
232 if ( $params['urlparam'] ) {
233 $this->dieUsage( "{$p}urlparam requires {$p}urlwidth", "urlparam_no_width" );
234 }
235 }
236
237 return $scale;
238 }
239
240 /** Validate and merge scale parameters with handler thumb parameters, give error if invalid.
241 *
242 * We do this later than getScale, since we need the image
243 * to know which handler, since handlers can make their own parameters.
244 * @param File $image Image that params are for.
245 * @param array $thumbParams thumbnail parameters from getScale
246 * @param string $otherParams of otherParams (iiurlparam).
247 * @return Array of parameters for transform.
248 */
249 protected function mergeThumbParams( $image, $thumbParams, $otherParams ) {
250 global $wgThumbLimits;
251
252 if ( !isset( $thumbParams['width'] ) && isset( $thumbParams['height'] ) ) {
253 // We want to limit only by height in this situation, so pass the
254 // image's full width as the limiting width. But some file types
255 // don't have a width of their own, so pick something arbitrary so
256 // thumbnailing the default icon works.
257 if ( $image->getWidth() <= 0 ) {
258 $thumbParams['width'] = max( $wgThumbLimits );
259 } else {
260 $thumbParams['width'] = $image->getWidth();
261 }
262 }
263
264 if ( !$otherParams ) {
265 return $thumbParams;
266 }
267 $p = $this->getModulePrefix();
268
269 $h = $image->getHandler();
270 if ( !$h ) {
271 $this->setWarning( 'Could not create thumbnail because ' .
272 $image->getName() . ' does not have an associated image handler' );
273
274 return $thumbParams;
275 }
276
277 $paramList = $h->parseParamString( $otherParams );
278 if ( !$paramList ) {
279 // Just set a warning (instead of dieUsage), as in many cases
280 // we could still render the image using width and height parameters,
281 // and this type of thing could happen between different versions of
282 // handlers.
283 $this->setWarning( "Could not parse {$p}urlparam for " . $image->getName()
284 . '. Using only width and height' );
285
286 return $thumbParams;
287 }
288
289 if ( isset( $paramList['width'] ) ) {
290 if ( intval( $paramList['width'] ) != intval( $thumbParams['width'] ) ) {
291 $this->setWarning( "Ignoring width value set in {$p}urlparam ({$paramList['width']}) "
292 . "in favor of width value derived from {$p}urlwidth/{$p}urlheight "
293 . "({$thumbParams['width']})" );
294 }
295 }
296
297 foreach ( $paramList as $name => $value ) {
298 if ( !$h->validateParam( $name, $value ) ) {
299 $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", "urlparam" );
300 }
301 }
302
303 return $thumbParams + $paramList;
304 }
305
306 /**
307 * Get result information for an image revision
308 *
309 * @param $file File object
310 * @param array $prop of properties to get (in the keys)
311 * @param $result ApiResult object
312 * @param array $thumbParams containing 'width' and 'height' items, or null
313 * @param array|bool|string $metadataOpts Options for metadata fetching.
314 * This is an array consisting of the keys:
315 * 'version': The metadata version for the metadata option
316 * 'language': The language for extmetadata property
317 * 'multilang': Return all translations in extmetadata property
318 * @return Array: result array
319 */
320 static function getInfo( $file, $prop, $result, $thumbParams = null, $metadataOpts = false ) {
321 global $wgContLang;
322
323 if ( !$metadataOpts || is_string( $metadataOpts ) ) {
324 $metadataOpts = array(
325 'version' => $metadataOpts ?: 'latest',
326 'language' => $wgContLang,
327 'multilang' => false,
328 'extmetadatafilter' => array(),
329 );
330 }
331 $version = $metadataOpts['version'];
332 $vals = array();
333 // Timestamp is shown even if the file is revdelete'd in interface
334 // so do same here.
335 if ( isset( $prop['timestamp'] ) ) {
336 $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $file->getTimestamp() );
337 }
338
339 $user = isset( $prop['user'] );
340 $userid = isset( $prop['userid'] );
341
342 if ( $user || $userid ) {
343 if ( $file->isDeleted( File::DELETED_USER ) ) {
344 $vals['userhidden'] = '';
345 } else {
346 if ( $user ) {
347 $vals['user'] = $file->getUser();
348 }
349 if ( $userid ) {
350 $vals['userid'] = $file->getUser( 'id' );
351 }
352 if ( !$file->getUser( 'id' ) ) {
353 $vals['anon'] = '';
354 }
355 }
356 }
357
358 // This is shown even if the file is revdelete'd in interface
359 // so do same here.
360 if ( isset( $prop['size'] ) || isset( $prop['dimensions'] ) ) {
361 $vals['size'] = intval( $file->getSize() );
362 $vals['width'] = intval( $file->getWidth() );
363 $vals['height'] = intval( $file->getHeight() );
364
365 $pageCount = $file->pageCount();
366 if ( $pageCount !== false ) {
367 $vals['pagecount'] = $pageCount;
368 }
369 }
370
371 $pcomment = isset( $prop['parsedcomment'] );
372 $comment = isset( $prop['comment'] );
373
374 if ( $pcomment || $comment ) {
375 if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
376 $vals['commenthidden'] = '';
377 } else {
378 if ( $pcomment ) {
379 $vals['parsedcomment'] = Linker::formatComment(
380 $file->getDescription(), $file->getTitle() );
381 }
382 if ( $comment ) {
383 $vals['comment'] = $file->getDescription();
384 }
385 }
386 }
387
388 $canonicaltitle = isset( $prop['canonicaltitle'] );
389 $url = isset( $prop['url'] );
390 $sha1 = isset( $prop['sha1'] );
391 $meta = isset( $prop['metadata'] );
392 $extmetadata = isset( $prop['extmetadata'] );
393 $mime = isset( $prop['mime'] );
394 $mediatype = isset( $prop['mediatype'] );
395 $archive = isset( $prop['archivename'] );
396 $bitdepth = isset( $prop['bitdepth'] );
397 $uploadwarning = isset( $prop['uploadwarning'] );
398
399 if ( ( $canonicaltitle || $url || $sha1 || $meta || $mime || $mediatype || $archive || $bitdepth )
400 && $file->isDeleted( File::DELETED_FILE )
401 ) {
402 $vals['filehidden'] = '';
403
404 //Early return, tidier than indenting all following things one level
405 return $vals;
406 }
407
408 if ( $canonicaltitle ) {
409 $vals['canonicaltitle'] = $file->getTitle()->getPrefixedText();
410 }
411
412 if ( $url ) {
413 if ( !is_null( $thumbParams ) ) {
414 $mto = $file->transform( $thumbParams );
415 self::$transformCount++;
416 if ( $mto && !$mto->isError() ) {
417 $vals['thumburl'] = wfExpandUrl( $mto->getUrl(), PROTO_CURRENT );
418
419 // bug 23834 - If the URL's are the same, we haven't resized it, so shouldn't give the wanted
420 // thumbnail sizes for the thumbnail actual size
421 if ( $mto->getUrl() !== $file->getUrl() ) {
422 $vals['thumbwidth'] = intval( $mto->getWidth() );
423 $vals['thumbheight'] = intval( $mto->getHeight() );
424 } else {
425 $vals['thumbwidth'] = intval( $file->getWidth() );
426 $vals['thumbheight'] = intval( $file->getHeight() );
427 }
428
429 if ( isset( $prop['thumbmime'] ) && $file->getHandler() ) {
430 list( , $mime ) = $file->getHandler()->getThumbType(
431 $mto->getExtension(), $file->getMimeType(), $thumbParams );
432 $vals['thumbmime'] = $mime;
433 }
434 } elseif ( $mto && $mto->isError() ) {
435 $vals['thumberror'] = $mto->toText();
436 }
437 }
438 $vals['url'] = wfExpandUrl( $file->getFullURL(), PROTO_CURRENT );
439 $vals['descriptionurl'] = wfExpandUrl( $file->getDescriptionUrl(), PROTO_CURRENT );
440 }
441
442 if ( $sha1 ) {
443 $vals['sha1'] = wfBaseConvert( $file->getSha1(), 36, 16, 40 );
444 }
445
446 if ( $meta ) {
447 wfSuppressWarnings();
448 $metadata = unserialize( $file->getMetadata() );
449 wfRestoreWarnings();
450 if ( $metadata && $version !== 'latest' ) {
451 $metadata = $file->convertMetadataVersion( $metadata, $version );
452 }
453 $vals['metadata'] = $metadata ? self::processMetaData( $metadata, $result ) : null;
454 }
455
456 if ( $extmetadata ) {
457 // Note, this should return an array where all the keys
458 // start with a letter, and all the values are strings.
459 // Thus there should be no issue with format=xml.
460 $format = new FormatMetadata;
461 $format->setSingleLanguage( !$metadataOpts['multilang'] );
462 $format->getContext()->setLanguage( $metadataOpts['language'] );
463 $extmetaArray = $format->fetchExtendedMetadata( $file );
464 if ( $metadataOpts['extmetadatafilter'] ) {
465 $extmetaArray = array_intersect_key(
466 $extmetaArray, array_flip( $metadataOpts['extmetadatafilter'] )
467 );
468 }
469 $vals['extmetadata'] = $extmetaArray;
470 }
471
472 if ( $mime ) {
473 $vals['mime'] = $file->getMimeType();
474 }
475
476 if ( $mediatype ) {
477 $vals['mediatype'] = $file->getMediaType();
478 }
479
480 if ( $archive && $file->isOld() ) {
481 $vals['archivename'] = $file->getArchiveName();
482 }
483
484 if ( $bitdepth ) {
485 $vals['bitdepth'] = $file->getBitDepth();
486 }
487
488 if ( $uploadwarning ) {
489 $vals['html'] = SpecialUpload::getExistsWarning( UploadBase::getExistsWarning( $file ) );
490 }
491
492 return $vals;
493 }
494
495 /**
496 * Get the count of image transformations performed
497 *
498 * If this is >= TRANSFORM_LIMIT, you should probably stop processing images.
499 *
500 * @return integer count
501 */
502 static function getTransformCount() {
503 return self::$transformCount;
504 }
505
506 /**
507 *
508 * @param $metadata Array
509 * @param $result ApiResult
510 * @return Array
511 */
512 public static function processMetaData( $metadata, $result ) {
513 $retval = array();
514 if ( is_array( $metadata ) ) {
515 foreach ( $metadata as $key => $value ) {
516 $r = array( 'name' => $key );
517 if ( is_array( $value ) ) {
518 $r['value'] = self::processMetaData( $value, $result );
519 } else {
520 $r['value'] = $value;
521 }
522 $retval[] = $r;
523 }
524 }
525 $result->setIndexedTagName( $retval, 'metadata' );
526
527 return $retval;
528 }
529
530 public function getCacheMode( $params ) {
531 return 'public';
532 }
533
534 /**
535 * @param $img File
536 * @param null|string $start
537 * @return string
538 */
539 protected function getContinueStr( $img, $start = null ) {
540 if ( $start === null ) {
541 $start = $img->getTimestamp();
542 }
543
544 return $img->getOriginalTitle()->getDBkey() . '|' . $start;
545 }
546
547 public function getAllowedParams() {
548 global $wgContLang;
549
550 return array(
551 'prop' => array(
552 ApiBase::PARAM_ISMULTI => true,
553 ApiBase::PARAM_DFLT => 'timestamp|user',
554 ApiBase::PARAM_TYPE => self::getPropertyNames()
555 ),
556 'limit' => array(
557 ApiBase::PARAM_TYPE => 'limit',
558 ApiBase::PARAM_DFLT => 1,
559 ApiBase::PARAM_MIN => 1,
560 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
561 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
562 ),
563 'start' => array(
564 ApiBase::PARAM_TYPE => 'timestamp'
565 ),
566 'end' => array(
567 ApiBase::PARAM_TYPE => 'timestamp'
568 ),
569 'urlwidth' => array(
570 ApiBase::PARAM_TYPE => 'integer',
571 ApiBase::PARAM_DFLT => -1
572 ),
573 'urlheight' => array(
574 ApiBase::PARAM_TYPE => 'integer',
575 ApiBase::PARAM_DFLT => -1
576 ),
577 'metadataversion' => array(
578 ApiBase::PARAM_TYPE => 'string',
579 ApiBase::PARAM_DFLT => '1',
580 ),
581 'extmetadatalanguage' => array(
582 ApiBase::PARAM_TYPE => 'string',
583 ApiBase::PARAM_DFLT => $wgContLang->getCode(),
584 ),
585 'extmetadatamultilang' => array(
586 ApiBase::PARAM_TYPE => 'boolean',
587 ApiBase::PARAM_DFLT => false,
588 ),
589 'extmetadatafilter' => array(
590 ApiBase::PARAM_TYPE => 'string',
591 ApiBase::PARAM_ISMULTI => true,
592 ),
593 'urlparam' => array(
594 ApiBase::PARAM_DFLT => '',
595 ApiBase::PARAM_TYPE => 'string',
596 ),
597 'continue' => null,
598 'localonly' => false,
599 );
600 }
601
602 /**
603 * Returns all possible parameters to iiprop
604 *
605 * @param array $filter List of properties to filter out
606 *
607 * @return Array
608 */
609 public static function getPropertyNames( $filter = array() ) {
610 return array_diff( array_keys( self::getProperties() ), $filter );
611 }
612
613 /**
614 * Returns array key value pairs of properties and their descriptions
615 *
616 * @param string $modulePrefix
617 * @return array
618 */
619 private static function getProperties( $modulePrefix = '' ) {
620 return array(
621 'timestamp' => ' timestamp - Adds timestamp for the uploaded version',
622 'user' => ' user - Adds the user who uploaded the image version',
623 'userid' => ' userid - Add the user ID that uploaded the image version',
624 'comment' => ' comment - Comment on the version',
625 'parsedcomment' => ' parsedcomment - Parse the comment on the version',
626 'canonicaltitle' => ' canonicaltitle - Adds the canonical title of the image file',
627 'url' => ' url - Gives URL to the image and the description page',
628 'size' => ' size - Adds the size of the image in bytes ' .
629 'and the height, width and page count (if applicable)',
630 'dimensions' => ' dimensions - Alias for size', // B/C with Allimages
631 'sha1' => ' sha1 - Adds SHA-1 hash for the image',
632 'mime' => ' mime - Adds MIME type of the image',
633 'thumbmime' => ' thumbmime - Adds MIME type of the image thumbnail' .
634 ' (requires url and param ' . $modulePrefix . 'urlwidth)',
635 'mediatype' => ' mediatype - Adds the media type of the image',
636 'metadata' => ' metadata - Lists Exif metadata for the version of the image',
637 'extmetadata' => ' extmetadata - Lists formatted metadata combined ' .
638 'from multiple sources. Results are HTML formatted.',
639 'archivename' => ' archivename - Adds the file name of the archive ' .
640 'version for non-latest versions',
641 'bitdepth' => ' bitdepth - Adds the bit depth of the version',
642 'uploadwarning' => ' uploadwarning - Used by the Special:Upload page to ' .
643 'get information about an existing file. Not intended for use outside MediaWiki core',
644 );
645 }
646
647 /**
648 * Returns the descriptions for the properties provided by getPropertyNames()
649 *
650 * @param array $filter List of properties to filter out
651 * @param string $modulePrefix
652 * @return array
653 */
654 public static function getPropertyDescriptions( $filter = array(), $modulePrefix = '' ) {
655 return array_merge(
656 array( 'What image information to get:' ),
657 array_values( array_diff_key( self::getProperties( $modulePrefix ), array_flip( $filter ) ) )
658 );
659 }
660
661 /**
662 * Return the API documentation for the parameters.
663 * @return Array parameter documentation.
664 */
665 public function getParamDescription() {
666 $p = $this->getModulePrefix();
667
668 return array(
669 'prop' => self::getPropertyDescriptions( array(), $p ),
670 'urlwidth' => array(
671 "If {$p}prop=url is set, a URL to an image scaled to this width will be returned.",
672 'For performance reasons if this option is used, ' .
673 'no more than ' . self::TRANSFORM_LIMIT . ' scaled images will be returned.'
674 ),
675 'urlheight' => "Similar to {$p}urlwidth.",
676 'urlparam' => array( "A handler specific parameter string. For example, pdf's ",
677 "might use 'page15-100px'. {$p}urlwidth must be used and be consistent with {$p}urlparam" ),
678 'limit' => 'How many image revisions to return per image',
679 'start' => 'Timestamp to start listing from',
680 'end' => 'Timestamp to stop listing at',
681 'metadataversion'
682 => array( "Version of metadata to use. if 'latest' is specified, use latest version.",
683 "Defaults to '1' for backwards compatibility" ),
684 'extmetadatalanguage' => array(
685 'What language to fetch extmetadata in. This affects both which',
686 'translation to fetch, if multiple are available, as well as how things',
687 'like numbers and various values are formatted.'
688 ),
689 'extmetadatamultilang'
690 =>'If translations for extmetadata property are available, fetch all of them.',
691 'extmetadatafilter'
692 => "If specified and non-empty, only these keys will be returned for {$p}prop=extmetadata",
693 'continue' => 'If the query response includes a continue value, ' .
694 'use it here to get another page of results',
695 'localonly' => 'Look only for files in the local repository',
696 );
697 }
698
699 public static function getResultPropertiesFiltered( $filter = array() ) {
700 $props = array(
701 'timestamp' => array(
702 'timestamp' => 'timestamp'
703 ),
704 'user' => array(
705 'userhidden' => 'boolean',
706 'user' => 'string',
707 'anon' => 'boolean'
708 ),
709 'userid' => array(
710 'userhidden' => 'boolean',
711 'userid' => 'integer',
712 'anon' => 'boolean'
713 ),
714 'size' => array(
715 'size' => 'integer',
716 'width' => 'integer',
717 'height' => 'integer',
718 'pagecount' => array(
719 ApiBase::PROP_TYPE => 'integer',
720 ApiBase::PROP_NULLABLE => true
721 )
722 ),
723 'dimensions' => array(
724 'size' => 'integer',
725 'width' => 'integer',
726 'height' => 'integer',
727 'pagecount' => array(
728 ApiBase::PROP_TYPE => 'integer',
729 ApiBase::PROP_NULLABLE => true
730 )
731 ),
732 'comment' => array(
733 'commenthidden' => 'boolean',
734 'comment' => array(
735 ApiBase::PROP_TYPE => 'string',
736 ApiBase::PROP_NULLABLE => true
737 )
738 ),
739 'parsedcomment' => array(
740 'commenthidden' => 'boolean',
741 'parsedcomment' => array(
742 ApiBase::PROP_TYPE => 'string',
743 ApiBase::PROP_NULLABLE => true
744 )
745 ),
746 'canonicaltitle' => array(
747 'canonicaltitle' => array(
748 ApiBase::PROP_TYPE => 'string',
749 ApiBase::PROP_NULLABLE => true
750 )
751 ),
752 'url' => array(
753 'filehidden' => 'boolean',
754 'thumburl' => array(
755 ApiBase::PROP_TYPE => 'string',
756 ApiBase::PROP_NULLABLE => true
757 ),
758 'thumbwidth' => array(
759 ApiBase::PROP_TYPE => 'integer',
760 ApiBase::PROP_NULLABLE => true
761 ),
762 'thumbheight' => array(
763 ApiBase::PROP_TYPE => 'integer',
764 ApiBase::PROP_NULLABLE => true
765 ),
766 'thumberror' => array(
767 ApiBase::PROP_TYPE => 'string',
768 ApiBase::PROP_NULLABLE => true
769 ),
770 'url' => array(
771 ApiBase::PROP_TYPE => 'string',
772 ApiBase::PROP_NULLABLE => true
773 ),
774 'descriptionurl' => array(
775 ApiBase::PROP_TYPE => 'string',
776 ApiBase::PROP_NULLABLE => true
777 )
778 ),
779 'sha1' => array(
780 'filehidden' => 'boolean',
781 'sha1' => array(
782 ApiBase::PROP_TYPE => 'string',
783 ApiBase::PROP_NULLABLE => true
784 )
785 ),
786 'mime' => array(
787 'filehidden' => 'boolean',
788 'mime' => array(
789 ApiBase::PROP_TYPE => 'string',
790 ApiBase::PROP_NULLABLE => true
791 )
792 ),
793 'thumbmime' => array(
794 'filehidden' => 'boolean',
795 'thumbmime' => array(
796 ApiBase::PROP_TYPE => 'string',
797 ApiBase::PROP_NULLABLE => true
798 )
799 ),
800 'mediatype' => array(
801 'filehidden' => 'boolean',
802 'mediatype' => array(
803 ApiBase::PROP_TYPE => 'string',
804 ApiBase::PROP_NULLABLE => true
805 )
806 ),
807 'archivename' => array(
808 'filehidden' => 'boolean',
809 'archivename' => array(
810 ApiBase::PROP_TYPE => 'string',
811 ApiBase::PROP_NULLABLE => true
812 )
813 ),
814 'bitdepth' => array(
815 'filehidden' => 'boolean',
816 'bitdepth' => array(
817 ApiBase::PROP_TYPE => 'integer',
818 ApiBase::PROP_NULLABLE => true
819 )
820 ),
821 );
822
823 return array_diff_key( $props, array_flip( $filter ) );
824 }
825
826 public function getResultProperties() {
827 return self::getResultPropertiesFiltered();
828 }
829
830 public function getDescription() {
831 return 'Returns image information and upload history';
832 }
833
834 public function getPossibleErrors() {
835 $p = $this->getModulePrefix();
836
837 return array_merge( parent::getPossibleErrors(), array(
838 array( 'code' => "{$p}urlwidth", 'info' => "{$p}urlheight cannot be used without {$p}urlwidth" ),
839 array( 'code' => 'urlparam', 'info' => "Invalid value for {$p}urlparam" ),
840 array( 'code' => 'urlparam_no_width', 'info' => "{$p}urlparam requires {$p}urlwidth" ),
841 ) );
842 }
843
844 public function getExamples() {
845 return array(
846 'api.php?action=query&titles=File:Albert%20Einstein%20Head.jpg&prop=imageinfo',
847 'api.php?action=query&titles=File:Test.jpg&prop=imageinfo&iilimit=50&' .
848 'iiend=20071231235959&iiprop=timestamp|user|url',
849 );
850 }
851
852 public function getHelpUrls() {
853 return 'https://www.mediawiki.org/wiki/API:Properties#imageinfo_.2F_ii';
854 }
855 }