MediaWiki  master
ApiQueryAllImages.php
Go to the documentation of this file.
1 <?php
2 
30 
37  protected $mRepo;
38 
39  public function __construct( ApiQuery $query, $moduleName ) {
40  parent::__construct( $query, $moduleName, 'ai' );
41  $this->mRepo = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo();
42  }
43 
51  protected function getDB() {
52  return $this->mRepo->getReplicaDB();
53  }
54 
55  public function execute() {
56  $this->run();
57  }
58 
59  public function getCacheMode( $params ) {
60  return 'public';
61  }
62 
67  public function executeGenerator( $resultPageSet ) {
68  if ( $resultPageSet->isResolvingRedirects() ) {
69  $this->dieWithError( 'apierror-allimages-redirect', 'invalidparammix' );
70  }
71 
72  $this->run( $resultPageSet );
73  }
74 
79  private function run( $resultPageSet = null ) {
80  $repo = $this->mRepo;
81  if ( !$repo instanceof LocalRepo ) {
82  $this->dieWithError( 'apierror-unsupportedrepo' );
83  }
84 
85  $prefix = $this->getModulePrefix();
86 
87  $db = $this->getDB();
88 
89  $params = $this->extractRequestParams();
90 
91  // Table and return fields
92  $prop = array_flip( $params['prop'] );
93 
94  $fileQuery = LocalFile::getQueryInfo();
95  $this->addTables( $fileQuery['tables'] );
96  $this->addFields( $fileQuery['fields'] );
97  $this->addJoinConds( $fileQuery['joins'] );
98 
99  $ascendingOrder = true;
100  if ( $params['dir'] == 'descending' || $params['dir'] == 'older' ) {
101  $ascendingOrder = false;
102  }
103 
104  if ( $params['sort'] == 'name' ) {
105  // Check mutually exclusive params
106  $disallowed = [ 'start', 'end', 'user' ];
107  foreach ( $disallowed as $pname ) {
108  if ( isset( $params[$pname] ) ) {
109  $this->dieWithError(
110  [
111  'apierror-invalidparammix-mustusewith',
112  "{$prefix}{$pname}",
113  "{$prefix}sort=timestamp"
114  ],
115  'invalidparammix'
116  );
117  }
118  }
119  if ( $params['filterbots'] != 'all' ) {
120  $this->dieWithError(
121  [
122  'apierror-invalidparammix-mustusewith',
123  "{$prefix}filterbots",
124  "{$prefix}sort=timestamp"
125  ],
126  'invalidparammix'
127  );
128  }
129 
130  // Pagination
131  if ( $params['continue'] !== null ) {
132  $cont = explode( '|', $params['continue'] );
133  $this->dieContinueUsageIf( count( $cont ) != 1 );
134  $op = $ascendingOrder ? '>' : '<';
135  $continueFrom = $db->addQuotes( $cont[0] );
136  $this->addWhere( "img_name $op= $continueFrom" );
137  }
138 
139  // Image filters
140  $from = $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_FILE );
141  $to = $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_FILE );
142  $this->addWhereRange( 'img_name', $ascendingOrder ? 'newer' : 'older', $from, $to );
143 
144  if ( isset( $params['prefix'] ) ) {
145  $this->addWhere( 'img_name' . $db->buildLike(
146  $this->titlePartToKey( $params['prefix'], NS_FILE ),
147  $db->anyString() ) );
148  }
149  } else {
150  // Check mutually exclusive params
151  $disallowed = [ 'from', 'to', 'prefix' ];
152  foreach ( $disallowed as $pname ) {
153  if ( isset( $params[$pname] ) ) {
154  $this->dieWithError(
155  [
156  'apierror-invalidparammix-mustusewith',
157  "{$prefix}{$pname}",
158  "{$prefix}sort=name"
159  ],
160  'invalidparammix'
161  );
162  }
163  }
164  if ( $params['user'] !== null && $params['filterbots'] != 'all' ) {
165  // Since filterbots checks if each user has the bot right, it
166  // doesn't make sense to use it with user
167  $this->dieWithError(
168  [ 'apierror-invalidparammix-cannotusewith', "{$prefix}user", "{$prefix}filterbots" ]
169  );
170  }
171 
172  // Pagination
173  $this->addTimestampWhereRange(
174  'img_timestamp',
175  $ascendingOrder ? 'newer' : 'older',
176  $params['start'],
177  $params['end']
178  );
179  // Include in ORDER BY for uniqueness
180  $this->addWhereRange( 'img_name', $ascendingOrder ? 'newer' : 'older', null, null );
181 
182  if ( $params['continue'] !== null ) {
183  $cont = explode( '|', $params['continue'] );
184  $this->dieContinueUsageIf( count( $cont ) != 2 );
185  $op = ( $ascendingOrder ? '>' : '<' );
186  $continueTimestamp = $db->addQuotes( $db->timestamp( $cont[0] ) );
187  $continueName = $db->addQuotes( $cont[1] );
188  $this->addWhere( "img_timestamp $op $continueTimestamp OR " .
189  "(img_timestamp = $continueTimestamp AND " .
190  "img_name $op= $continueName)"
191  );
192  }
193 
194  // Image filters
195  if ( $params['user'] !== null ) {
196  $actorQuery = ActorMigration::newMigration()
197  ->getWhere( $db, 'img_user', $params['user'] );
198  $this->addTables( $actorQuery['tables'] );
199  $this->addJoinConds( $actorQuery['joins'] );
200  $this->addWhere( $actorQuery['conds'] );
201  }
202  if ( $params['filterbots'] != 'all' ) {
203  $actorQuery = ActorMigration::newMigration()->getJoin( 'img_user' );
204  $this->addTables( $actorQuery['tables'] );
205  $this->addTables( 'user_groups' );
206  $this->addJoinConds( $actorQuery['joins'] );
207  $this->addJoinConds( [ 'user_groups' => [
208  'LEFT JOIN',
209  [
210  'ug_group' => $this->getPermissionManager()->getGroupsWithPermission( 'bot' ),
211  'ug_user = ' . $actorQuery['fields']['img_user'],
212  'ug_expiry IS NULL OR ug_expiry >= ' . $db->addQuotes( $db->timestamp() )
213  ]
214  ] ] );
215  $groupCond = $params['filterbots'] == 'nobots' ? 'NULL' : 'NOT NULL';
216  $this->addWhere( "ug_group IS $groupCond" );
217  }
218  }
219 
220  // Filters not depending on sort
221  if ( isset( $params['minsize'] ) ) {
222  $this->addWhere( 'img_size>=' . (int)$params['minsize'] );
223  }
224 
225  if ( isset( $params['maxsize'] ) ) {
226  $this->addWhere( 'img_size<=' . (int)$params['maxsize'] );
227  }
228 
229  $sha1 = false;
230  if ( isset( $params['sha1'] ) ) {
231  $sha1 = strtolower( $params['sha1'] );
232  if ( !$this->validateSha1Hash( $sha1 ) ) {
233  $this->dieWithError( 'apierror-invalidsha1hash' );
234  }
235  $sha1 = Wikimedia\base_convert( $sha1, 16, 36, 31 );
236  } elseif ( isset( $params['sha1base36'] ) ) {
237  $sha1 = strtolower( $params['sha1base36'] );
238  if ( !$this->validateSha1Base36Hash( $sha1 ) ) {
239  $this->dieWithError( 'apierror-invalidsha1base36hash' );
240  }
241  }
242  if ( $sha1 ) {
243  $this->addWhereFld( 'img_sha1', $sha1 );
244  }
245 
246  if ( $params['mime'] !== null ) {
247  if ( $this->getConfig()->get( 'MiserMode' ) ) {
248  $this->dieWithError( 'apierror-mimesearchdisabled' );
249  }
250 
251  $mimeConds = [];
252  foreach ( $params['mime'] as $mime ) {
253  list( $major, $minor ) = File::splitMime( $mime );
254  $mimeConds[] = $db->makeList(
255  [
256  'img_major_mime' => $major,
257  'img_minor_mime' => $minor,
258  ],
259  LIST_AND
260  );
261  }
262  // safeguard against internal_api_error_DBQueryError
263  if ( count( $mimeConds ) > 0 ) {
264  $this->addWhere( $db->makeList( $mimeConds, LIST_OR ) );
265  } else {
266  // no MIME types, no files
267  $this->getResult()->addValue( 'query', $this->getModuleName(), [] );
268  return;
269  }
270  }
271 
272  $limit = $params['limit'];
273  $this->addOption( 'LIMIT', $limit + 1 );
274  $sortFlag = '';
275  if ( !$ascendingOrder ) {
276  $sortFlag = ' DESC';
277  }
278  if ( $params['sort'] == 'timestamp' ) {
279  $this->addOption( 'ORDER BY', 'img_timestamp' . $sortFlag );
280  } else {
281  $this->addOption( 'ORDER BY', 'img_name' . $sortFlag );
282  }
283 
284  $res = $this->select( __METHOD__ );
285 
286  $titles = [];
287  $count = 0;
288  $result = $this->getResult();
289  foreach ( $res as $row ) {
290  if ( ++$count > $limit ) {
291  // We've reached the one extra which shows that there are
292  // additional pages to be had. Stop here...
293  if ( $params['sort'] == 'name' ) {
294  $this->setContinueEnumParameter( 'continue', $row->img_name );
295  } else {
296  $this->setContinueEnumParameter( 'continue', "$row->img_timestamp|$row->img_name" );
297  }
298  break;
299  }
300 
301  if ( $resultPageSet === null ) {
302  $file = $repo->newFileFromRow( $row );
303  $info = array_merge( [ 'name' => $row->img_name ],
304  ApiQueryImageInfo::getInfo( $file, $prop, $result ) );
305  self::addTitleInfo( $info, $file->getTitle() );
306 
307  $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $info );
308  if ( !$fit ) {
309  if ( $params['sort'] == 'name' ) {
310  $this->setContinueEnumParameter( 'continue', $row->img_name );
311  } else {
312  $this->setContinueEnumParameter( 'continue', "$row->img_timestamp|$row->img_name" );
313  }
314  break;
315  }
316  } else {
317  $titles[] = Title::makeTitle( NS_FILE, $row->img_name );
318  }
319  }
320 
321  if ( $resultPageSet === null ) {
322  $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'img' );
323  } else {
324  $resultPageSet->populateFromTitles( $titles );
325  }
326  }
327 
328  public function getAllowedParams() {
329  $ret = [
330  'sort' => [
331  ApiBase::PARAM_DFLT => 'name',
333  'name',
334  'timestamp'
335  ]
336  ],
337  'dir' => [
338  ApiBase::PARAM_DFLT => 'ascending',
340  // sort=name
341  'ascending',
342  'descending',
343  // sort=timestamp
344  'newer',
345  'older'
346  ]
347  ],
348  'from' => null,
349  'to' => null,
350  'continue' => [
351  ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
352  ],
353  'start' => [
354  ApiBase::PARAM_TYPE => 'timestamp'
355  ],
356  'end' => [
357  ApiBase::PARAM_TYPE => 'timestamp'
358  ],
359  'prop' => [
360  ApiBase::PARAM_TYPE => ApiQueryImageInfo::getPropertyNames( $this->propertyFilter ),
361  ApiBase::PARAM_DFLT => 'timestamp|url',
362  ApiBase::PARAM_ISMULTI => true,
363  ApiBase::PARAM_HELP_MSG => 'apihelp-query+imageinfo-param-prop',
365  ApiQueryImageInfo::getPropertyMessages( $this->propertyFilter ),
366  ],
367  'prefix' => null,
368  'minsize' => [
369  ApiBase::PARAM_TYPE => 'integer',
370  ],
371  'maxsize' => [
372  ApiBase::PARAM_TYPE => 'integer',
373  ],
374  'sha1' => null,
375  'sha1base36' => null,
376  'user' => [
377  ApiBase::PARAM_TYPE => 'user',
378  UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'id', 'interwiki' ],
379  UserDef::PARAM_RETURN_OBJECT => true,
380  ],
381  'filterbots' => [
382  ApiBase::PARAM_DFLT => 'all',
384  'all',
385  'bots',
386  'nobots'
387  ]
388  ],
389  'mime' => [
390  ApiBase::PARAM_ISMULTI => true,
391  ],
392  'limit' => [
393  ApiBase::PARAM_DFLT => 10,
394  ApiBase::PARAM_TYPE => 'limit',
395  ApiBase::PARAM_MIN => 1,
398  ],
399  ];
400 
401  if ( $this->getConfig()->get( 'MiserMode' ) ) {
402  $ret['mime'][ApiBase::PARAM_HELP_MSG] = 'api-help-param-disabled-in-miser-mode';
403  }
404 
405  return $ret;
406  }
407 
408  private $propertyFilter = [ 'archivename', 'thumbmime', 'uploadwarning' ];
409 
410  protected function getExamplesMessages() {
411  return [
412  'action=query&list=allimages&aifrom=B'
413  => 'apihelp-query+allimages-example-b',
414  'action=query&list=allimages&aiprop=user|timestamp|url&' .
415  'aisort=timestamp&aidir=older'
416  => 'apihelp-query+allimages-example-recent',
417  'action=query&list=allimages&aimime=image/png|image/gif'
418  => 'apihelp-query+allimages-example-mimetypes',
419  'action=query&generator=allimages&gailimit=4&' .
420  'gaifrom=T&prop=imageinfo'
421  => 'apihelp-query+allimages-example-generator',
422  ];
423  }
424 
425  public function getHelpUrls() {
426  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allimages';
427  }
428 }
ApiQueryBase\validateSha1Base36Hash
validateSha1Base36Hash( $hash)
Definition: ApiQueryBase.php:595
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:63
ApiQueryImageInfo\getPropertyNames
static getPropertyNames( $filter=[])
Returns all possible parameters to iiprop.
Definition: ApiQueryImageInfo.php:734
ApiQueryBase\addFields
addFields( $value)
Add a set of fields to select to the internal array.
Definition: ApiQueryBase.php:208
ApiQuery
This is the main query class.
Definition: ApiQuery.php:37
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:146
ApiQueryAllImages\__construct
__construct(ApiQuery $query, $moduleName)
Definition: ApiQueryAllImages.php:39
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1415
ApiQueryBase\addTimestampWhereRange
addTimestampWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, similar to addWhereRange, but converts $start and $end t...
Definition: ApiQueryBase.php:362
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:104
ApiBase\PARAM_TYPE
const PARAM_TYPE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:68
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:546
ApiQueryAllImages\getDB
getDB()
Override parent method to make sure the repo's DB is used which may not necessarily be the same as th...
Definition: ApiQueryAllImages.php:51
NS_FILE
const NS_FILE
Definition: Defines.php:75
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
File\splitMime
static splitMime( $mime)
Split an internet media type into its two components; if not a two-part name, set the minor type to '...
Definition: File.php:286
ApiQueryBase\addOption
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
Definition: ApiQueryBase.php:374
$res
$res
Definition: testCompression.php:57
ApiQueryImageInfo\getInfo
static getInfo( $file, $prop, $result, $thumbParams=null, $opts=false)
Get result information for an image revision.
Definition: ApiQueryImageInfo.php:375
ActorMigration\newMigration
static newMigration()
Static constructor.
Definition: ActorMigration.php:139
LIST_AND
const LIST_AND
Definition: Defines.php:48
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
Wikimedia\ParamValidator\ParamValidator::TypeDef\UserDef
Type definition for user types.
Definition: UserDef.php:23
ApiQueryGeneratorBase\setContinueEnumParameter
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
Definition: ApiQueryGeneratorBase.php:84
ApiBase\PARAM_MIN
const PARAM_MIN
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:71
LIST_OR
const LIST_OR
Definition: Defines.php:51
ApiQueryAllImages\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiQueryAllImages.php:425
ApiQueryAllImages\executeGenerator
executeGenerator( $resultPageSet)
Definition: ApiQueryAllImages.php:67
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:162
ApiBase\PARAM_MAX
const PARAM_MAX
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:69
ApiQueryBase\addTables
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
Definition: ApiQueryBase.php:178
ApiQueryBase\select
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
Definition: ApiQueryBase.php:395
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:695
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:595
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:434
ApiQueryBase\addWhereRange
addWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, and an ORDER BY clause to sort in the right direction.
Definition: ApiQueryBase.php:333
ApiQueryAllImages\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiQueryAllImages.php:328
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1595
ApiBase\getPermissionManager
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition: ApiBase.php:616
ApiQueryBase\addJoinConds
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
Definition: ApiQueryBase.php:197
ApiQueryBase\addWhereFld
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
Definition: ApiQueryBase.php:278
ApiQueryAllImages\$mRepo
$mRepo
Definition: ApiQueryAllImages.php:37
ApiQueryAllImages\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiQueryAllImages.php:55
ApiQueryAllImages\getCacheMode
getCacheMode( $params)
Get the cache mode for the data generated by this module.
Definition: ApiQueryAllImages.php:59
ApiQueryGeneratorBase
Definition: ApiQueryGeneratorBase.php:26
LocalFile\getQueryInfo
static getQueryInfo(array $options=[])
Return the tables, fields, and join conditions to be selected to create a new localfile object.
Definition: LocalFile.php:216
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:164
ApiQueryAllImages
Query module to enumerate all available pages.
Definition: ApiQueryAllImages.php:36
ApiQueryAllImages\run
run( $resultPageSet=null)
Definition: ApiQueryAllImages.php:79
ApiBase\PARAM_DFLT
const PARAM_DFLT
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:66
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:426
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:67
ApiBase\PARAM_MAX2
const PARAM_MAX2
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:70
ApiQueryBase\addWhere
addWhere( $value)
Add a set of WHERE clauses to the internal array.
Definition: ApiQueryBase.php:241
ApiQueryAllImages\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiQueryAllImages.php:410
$mime
$mime
Definition: router.php:60
ApiQueryImageInfo\getPropertyMessages
static getPropertyMessages( $filter=[])
Returns messages for all possible parameters to iiprop.
Definition: ApiQueryImageInfo.php:744
ApiBase\PARAM_HELP_MSG_PER_VALUE
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:137
ApiQueryBase\titlePartToKey
titlePartToKey( $titlePart, $namespace=NS_MAIN)
Convert an input title or title prefix into a dbkey.
Definition: ApiQueryBase.php:526
ApiQueryAllImages\$propertyFilter
$propertyFilter
Definition: ApiQueryAllImages.php:408
LocalRepo
A repository that stores files in the local filesystem and registers them in the wiki's own database.
Definition: LocalRepo.php:37
ApiQueryBase\addTitleInfo
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
Definition: ApiQueryBase.php:463
ApiQueryBase\validateSha1Hash
validateSha1Hash( $hash)
Definition: ApiQueryBase.php:587