This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * API for MediaWiki 1.12+ |
||
5 | * |
||
6 | * Created on Mar 16, 2008 |
||
7 | * |
||
8 | * Copyright © 2008 Vasiliev Victor [email protected], |
||
9 | * based on ApiQueryAllPages.php |
||
10 | * |
||
11 | * This program is free software; you can redistribute it and/or modify |
||
12 | * it under the terms of the GNU General Public License as published by |
||
13 | * the Free Software Foundation; either version 2 of the License, or |
||
14 | * (at your option) any later version. |
||
15 | * |
||
16 | * This program is distributed in the hope that it will be useful, |
||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
19 | * GNU General Public License for more details. |
||
20 | * |
||
21 | * You should have received a copy of the GNU General Public License along |
||
22 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
24 | * http://www.gnu.org/copyleft/gpl.html |
||
25 | * |
||
26 | * @file |
||
27 | */ |
||
28 | |||
29 | /** |
||
30 | * Query module to enumerate all available pages. |
||
31 | * |
||
32 | * @ingroup API |
||
33 | */ |
||
34 | class ApiQueryAllImages extends ApiQueryGeneratorBase { |
||
35 | protected $mRepo; |
||
36 | |||
37 | public function __construct( ApiQuery $query, $moduleName ) { |
||
38 | parent::__construct( $query, $moduleName, 'ai' ); |
||
39 | $this->mRepo = RepoGroup::singleton()->getLocalRepo(); |
||
40 | } |
||
41 | |||
42 | /** |
||
43 | * Override parent method to make sure the repo's DB is used |
||
44 | * which may not necessarily be the same as the local DB. |
||
45 | * |
||
46 | * TODO: allow querying non-local repos. |
||
47 | * @return Database |
||
48 | */ |
||
49 | protected function getDB() { |
||
50 | return $this->mRepo->getSlaveDB(); |
||
51 | } |
||
52 | |||
53 | public function execute() { |
||
54 | $this->run(); |
||
55 | } |
||
56 | |||
57 | public function getCacheMode( $params ) { |
||
58 | return 'public'; |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * @param ApiPageSet $resultPageSet |
||
63 | * @return void |
||
64 | */ |
||
65 | public function executeGenerator( $resultPageSet ) { |
||
66 | if ( $resultPageSet->isResolvingRedirects() ) { |
||
67 | $this->dieUsage( |
||
68 | 'Use "gaifilterredir=nonredirects" option instead of "redirects" ' . |
||
69 | 'when using allimages as a generator', |
||
70 | 'params' |
||
71 | ); |
||
72 | } |
||
73 | |||
74 | $this->run( $resultPageSet ); |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * @param ApiPageSet $resultPageSet |
||
79 | * @return void |
||
80 | */ |
||
81 | private function run( $resultPageSet = null ) { |
||
82 | $repo = $this->mRepo; |
||
83 | if ( !$repo instanceof LocalRepo ) { |
||
84 | $this->dieUsage( |
||
85 | 'Local file repository does not support querying all images', |
||
86 | 'unsupportedrepo' |
||
87 | ); |
||
88 | } |
||
89 | |||
90 | $prefix = $this->getModulePrefix(); |
||
91 | |||
92 | $db = $this->getDB(); |
||
93 | |||
94 | $params = $this->extractRequestParams(); |
||
95 | |||
96 | // Table and return fields |
||
97 | $this->addTables( 'image' ); |
||
98 | |||
99 | $prop = array_flip( $params['prop'] ); |
||
100 | $this->addFields( LocalFile::selectFields() ); |
||
101 | |||
102 | $ascendingOrder = true; |
||
103 | if ( $params['dir'] == 'descending' || $params['dir'] == 'older' ) { |
||
104 | $ascendingOrder = false; |
||
105 | } |
||
106 | |||
107 | if ( $params['sort'] == 'name' ) { |
||
108 | // Check mutually exclusive params |
||
109 | $disallowed = [ 'start', 'end', 'user' ]; |
||
110 | foreach ( $disallowed as $pname ) { |
||
111 | if ( isset( $params[$pname] ) ) { |
||
112 | $this->dieUsage( |
||
113 | "Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=timestamp", |
||
114 | 'badparams' |
||
115 | ); |
||
116 | } |
||
117 | } |
||
118 | if ( $params['filterbots'] != 'all' ) { |
||
119 | $this->dieUsage( |
||
120 | "Parameter '{$prefix}filterbots' can only be used with {$prefix}sort=timestamp", |
||
121 | 'badparams' |
||
122 | ); |
||
123 | } |
||
124 | |||
125 | // Pagination |
||
126 | View Code Duplication | if ( !is_null( $params['continue'] ) ) { |
|
127 | $cont = explode( '|', $params['continue'] ); |
||
128 | $this->dieContinueUsageIf( count( $cont ) != 1 ); |
||
129 | $op = ( $ascendingOrder ? '>' : '<' ); |
||
130 | $continueFrom = $db->addQuotes( $cont[0] ); |
||
131 | $this->addWhere( "img_name $op= $continueFrom" ); |
||
132 | } |
||
133 | |||
134 | // Image filters |
||
135 | $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_FILE ) ); |
||
136 | $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_FILE ) ); |
||
137 | $this->addWhereRange( 'img_name', ( $ascendingOrder ? 'newer' : 'older' ), $from, $to ); |
||
138 | |||
139 | View Code Duplication | if ( isset( $params['prefix'] ) ) { |
|
140 | $this->addWhere( 'img_name' . $db->buildLike( |
||
141 | $this->titlePartToKey( $params['prefix'], NS_FILE ), |
||
142 | $db->anyString() ) ); |
||
143 | } |
||
144 | } else { |
||
145 | // Check mutually exclusive params |
||
146 | $disallowed = [ 'from', 'to', 'prefix' ]; |
||
147 | foreach ( $disallowed as $pname ) { |
||
148 | if ( isset( $params[$pname] ) ) { |
||
149 | $this->dieUsage( |
||
150 | "Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=name", |
||
151 | 'badparams' |
||
152 | ); |
||
153 | } |
||
154 | } |
||
155 | if ( !is_null( $params['user'] ) && $params['filterbots'] != 'all' ) { |
||
156 | // Since filterbots checks if each user has the bot right, it |
||
157 | // doesn't make sense to use it with user |
||
158 | $this->dieUsage( |
||
159 | "Parameters '{$prefix}user' and '{$prefix}filterbots' cannot be used together", |
||
160 | 'badparams' |
||
161 | ); |
||
162 | } |
||
163 | |||
164 | // Pagination |
||
165 | $this->addTimestampWhereRange( |
||
166 | 'img_timestamp', |
||
167 | $ascendingOrder ? 'newer' : 'older', |
||
168 | $params['start'], |
||
169 | $params['end'] |
||
170 | ); |
||
171 | // Include in ORDER BY for uniqueness |
||
172 | $this->addWhereRange( 'img_name', $ascendingOrder ? 'newer' : 'older', null, null ); |
||
173 | |||
174 | if ( !is_null( $params['continue'] ) ) { |
||
175 | $cont = explode( '|', $params['continue'] ); |
||
176 | $this->dieContinueUsageIf( count( $cont ) != 2 ); |
||
177 | $op = ( $ascendingOrder ? '>' : '<' ); |
||
178 | $continueTimestamp = $db->addQuotes( $db->timestamp( $cont[0] ) ); |
||
179 | $continueName = $db->addQuotes( $cont[1] ); |
||
180 | $this->addWhere( "img_timestamp $op $continueTimestamp OR " . |
||
181 | "(img_timestamp = $continueTimestamp AND " . |
||
182 | "img_name $op= $continueName)" |
||
183 | ); |
||
184 | } |
||
185 | |||
186 | // Image filters |
||
187 | if ( !is_null( $params['user'] ) ) { |
||
188 | $this->addWhereFld( 'img_user_text', $params['user'] ); |
||
189 | } |
||
190 | if ( $params['filterbots'] != 'all' ) { |
||
191 | $this->addTables( 'user_groups' ); |
||
192 | $this->addJoinConds( [ 'user_groups' => [ |
||
193 | 'LEFT JOIN', |
||
194 | [ |
||
195 | 'ug_group' => User::getGroupsWithPermission( 'bot' ), |
||
196 | 'ug_user = img_user' |
||
197 | ] |
||
198 | ] ] ); |
||
199 | $groupCond = ( $params['filterbots'] == 'nobots' ? 'NULL' : 'NOT NULL' ); |
||
200 | $this->addWhere( "ug_group IS $groupCond" ); |
||
201 | } |
||
202 | } |
||
203 | |||
204 | // Filters not depending on sort |
||
205 | if ( isset( $params['minsize'] ) ) { |
||
206 | $this->addWhere( 'img_size>=' . intval( $params['minsize'] ) ); |
||
207 | } |
||
208 | |||
209 | if ( isset( $params['maxsize'] ) ) { |
||
210 | $this->addWhere( 'img_size<=' . intval( $params['maxsize'] ) ); |
||
211 | } |
||
212 | |||
213 | $sha1 = false; |
||
214 | if ( isset( $params['sha1'] ) ) { |
||
215 | $sha1 = strtolower( $params['sha1'] ); |
||
216 | if ( !$this->validateSha1Hash( $sha1 ) ) { |
||
217 | $this->dieUsage( 'The SHA1 hash provided is not valid', 'invalidsha1hash' ); |
||
218 | } |
||
219 | $sha1 = Wikimedia\base_convert( $sha1, 16, 36, 31 ); |
||
220 | View Code Duplication | } elseif ( isset( $params['sha1base36'] ) ) { |
|
221 | $sha1 = strtolower( $params['sha1base36'] ); |
||
222 | if ( !$this->validateSha1Base36Hash( $sha1 ) ) { |
||
223 | $this->dieUsage( 'The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash' ); |
||
224 | } |
||
225 | } |
||
226 | if ( $sha1 ) { |
||
0 ignored issues
–
show
|
|||
227 | $this->addWhereFld( 'img_sha1', $sha1 ); |
||
228 | } |
||
229 | |||
230 | if ( !is_null( $params['mime'] ) ) { |
||
231 | if ( $this->getConfig()->get( 'MiserMode' ) ) { |
||
232 | $this->dieUsage( 'MIME search disabled in Miser Mode', 'mimesearchdisabled' ); |
||
233 | } |
||
234 | |||
235 | $mimeConds = []; |
||
236 | foreach ( $params['mime'] as $mime ) { |
||
237 | list( $major, $minor ) = File::splitMime( $mime ); |
||
238 | $mimeConds[] = $db->makeList( |
||
239 | [ |
||
240 | 'img_major_mime' => $major, |
||
241 | 'img_minor_mime' => $minor, |
||
242 | ], |
||
243 | LIST_AND |
||
244 | ); |
||
245 | } |
||
246 | // safeguard against internal_api_error_DBQueryError |
||
247 | if ( count( $mimeConds ) > 0 ) { |
||
248 | $this->addWhere( $db->makeList( $mimeConds, LIST_OR ) ); |
||
249 | } else { |
||
250 | // no MIME types, no files |
||
251 | $this->getResult()->addValue( 'query', $this->getModuleName(), [] ); |
||
252 | return; |
||
253 | } |
||
254 | } |
||
255 | |||
256 | $limit = $params['limit']; |
||
257 | $this->addOption( 'LIMIT', $limit + 1 ); |
||
258 | $sortFlag = ''; |
||
259 | if ( !$ascendingOrder ) { |
||
260 | $sortFlag = ' DESC'; |
||
261 | } |
||
262 | if ( $params['sort'] == 'timestamp' ) { |
||
263 | $this->addOption( 'ORDER BY', 'img_timestamp' . $sortFlag ); |
||
264 | if ( !is_null( $params['user'] ) ) { |
||
265 | $this->addOption( 'USE INDEX', [ 'image' => 'img_usertext_timestamp' ] ); |
||
266 | } else { |
||
267 | $this->addOption( 'USE INDEX', [ 'image' => 'img_timestamp' ] ); |
||
268 | } |
||
269 | } else { |
||
270 | $this->addOption( 'ORDER BY', 'img_name' . $sortFlag ); |
||
271 | } |
||
272 | |||
273 | $res = $this->select( __METHOD__ ); |
||
274 | |||
275 | $titles = []; |
||
276 | $count = 0; |
||
277 | $result = $this->getResult(); |
||
278 | foreach ( $res as $row ) { |
||
279 | View Code Duplication | if ( ++$count > $limit ) { |
|
280 | // We've reached the one extra which shows that there are |
||
281 | // additional pages to be had. Stop here... |
||
282 | if ( $params['sort'] == 'name' ) { |
||
283 | $this->setContinueEnumParameter( 'continue', $row->img_name ); |
||
284 | } else { |
||
285 | $this->setContinueEnumParameter( 'continue', "$row->img_timestamp|$row->img_name" ); |
||
286 | } |
||
287 | break; |
||
288 | } |
||
289 | |||
290 | if ( is_null( $resultPageSet ) ) { |
||
291 | $file = $repo->newFileFromRow( $row ); |
||
0 ignored issues
–
show
It seems like
$row defined by $row on line 278 can be null ; however, LocalRepo::newFileFromRow() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
292 | $info = array_merge( [ 'name' => $row->img_name ], |
||
293 | ApiQueryImageInfo::getInfo( $file, $prop, $result ) ); |
||
294 | self::addTitleInfo( $info, $file->getTitle() ); |
||
295 | |||
296 | $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $info ); |
||
297 | View Code Duplication | if ( !$fit ) { |
|
298 | if ( $params['sort'] == 'name' ) { |
||
299 | $this->setContinueEnumParameter( 'continue', $row->img_name ); |
||
300 | } else { |
||
301 | $this->setContinueEnumParameter( 'continue', "$row->img_timestamp|$row->img_name" ); |
||
302 | } |
||
303 | break; |
||
304 | } |
||
305 | } else { |
||
306 | $titles[] = Title::makeTitle( NS_FILE, $row->img_name ); |
||
307 | } |
||
308 | } |
||
309 | |||
310 | View Code Duplication | if ( is_null( $resultPageSet ) ) { |
|
311 | $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'img' ); |
||
312 | } else { |
||
313 | $resultPageSet->populateFromTitles( $titles ); |
||
314 | } |
||
315 | } |
||
316 | |||
317 | public function getAllowedParams() { |
||
318 | $ret = [ |
||
319 | 'sort' => [ |
||
320 | ApiBase::PARAM_DFLT => 'name', |
||
321 | ApiBase::PARAM_TYPE => [ |
||
322 | 'name', |
||
323 | 'timestamp' |
||
324 | ] |
||
325 | ], |
||
326 | 'dir' => [ |
||
327 | ApiBase::PARAM_DFLT => 'ascending', |
||
328 | ApiBase::PARAM_TYPE => [ |
||
329 | // sort=name |
||
330 | 'ascending', |
||
331 | 'descending', |
||
332 | // sort=timestamp |
||
333 | 'newer', |
||
334 | 'older' |
||
335 | ] |
||
336 | ], |
||
337 | 'from' => null, |
||
338 | 'to' => null, |
||
339 | 'continue' => [ |
||
340 | ApiBase::PARAM_HELP_MSG => 'api-help-param-continue', |
||
341 | ], |
||
342 | 'start' => [ |
||
343 | ApiBase::PARAM_TYPE => 'timestamp' |
||
344 | ], |
||
345 | 'end' => [ |
||
346 | ApiBase::PARAM_TYPE => 'timestamp' |
||
347 | ], |
||
348 | 'prop' => [ |
||
349 | ApiBase::PARAM_TYPE => ApiQueryImageInfo::getPropertyNames( $this->propertyFilter ), |
||
350 | ApiBase::PARAM_DFLT => 'timestamp|url', |
||
351 | ApiBase::PARAM_ISMULTI => true, |
||
352 | ApiBase::PARAM_HELP_MSG => 'apihelp-query+imageinfo-param-prop', |
||
353 | ApiBase::PARAM_HELP_MSG_PER_VALUE => |
||
354 | ApiQueryImageInfo::getPropertyMessages( $this->propertyFilter ), |
||
355 | ], |
||
356 | 'prefix' => null, |
||
357 | 'minsize' => [ |
||
358 | ApiBase::PARAM_TYPE => 'integer', |
||
359 | ], |
||
360 | 'maxsize' => [ |
||
361 | ApiBase::PARAM_TYPE => 'integer', |
||
362 | ], |
||
363 | 'sha1' => null, |
||
364 | 'sha1base36' => null, |
||
365 | 'user' => [ |
||
366 | ApiBase::PARAM_TYPE => 'user' |
||
367 | ], |
||
368 | 'filterbots' => [ |
||
369 | ApiBase::PARAM_DFLT => 'all', |
||
370 | ApiBase::PARAM_TYPE => [ |
||
371 | 'all', |
||
372 | 'bots', |
||
373 | 'nobots' |
||
374 | ] |
||
375 | ], |
||
376 | 'mime' => [ |
||
377 | ApiBase::PARAM_ISMULTI => true, |
||
378 | ], |
||
379 | 'limit' => [ |
||
380 | ApiBase::PARAM_DFLT => 10, |
||
381 | ApiBase::PARAM_TYPE => 'limit', |
||
382 | ApiBase::PARAM_MIN => 1, |
||
383 | ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1, |
||
384 | ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2 |
||
385 | ], |
||
386 | ]; |
||
387 | |||
388 | if ( $this->getConfig()->get( 'MiserMode' ) ) { |
||
389 | $ret['mime'][ApiBase::PARAM_HELP_MSG] = 'api-help-param-disabled-in-miser-mode'; |
||
390 | } |
||
391 | |||
392 | return $ret; |
||
393 | } |
||
394 | |||
395 | private $propertyFilter = [ 'archivename', 'thumbmime', 'uploadwarning' ]; |
||
396 | |||
397 | View Code Duplication | protected function getExamplesMessages() { |
|
398 | return [ |
||
399 | 'action=query&list=allimages&aifrom=B' |
||
400 | => 'apihelp-query+allimages-example-B', |
||
401 | 'action=query&list=allimages&aiprop=user|timestamp|url&' . |
||
402 | 'aisort=timestamp&aidir=older' |
||
403 | => 'apihelp-query+allimages-example-recent', |
||
404 | 'action=query&list=allimages&aimime=image/png|image/gif' |
||
405 | => 'apihelp-query+allimages-example-mimetypes', |
||
406 | 'action=query&generator=allimages&gailimit=4&' . |
||
407 | 'gaifrom=T&prop=imageinfo' |
||
408 | => 'apihelp-query+allimages-example-generator', |
||
409 | ]; |
||
410 | } |
||
411 | |||
412 | public function getHelpUrls() { |
||
413 | return 'https://www.mediawiki.org/wiki/API:Allimages'; |
||
414 | } |
||
415 | } |
||
416 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: