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