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