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 | * Created on Oct 3, 2014 |
||
4 | * |
||
5 | * Copyright © 2014 Brad Jorsch "[email protected]" |
||
6 | * |
||
7 | * Heavily based on ApiQueryDeletedrevs, |
||
8 | * Copyright © 2007 Roan Kattouw "<Firstname>.<Lastname>@gmail.com" |
||
9 | * |
||
10 | * This program is free software; you can redistribute it and/or modify |
||
11 | * it under the terms of the GNU General Public License as published by |
||
12 | * the Free Software Foundation; either version 2 of the License, or |
||
13 | * (at your option) any later version. |
||
14 | * |
||
15 | * This program is distributed in the hope that it will be useful, |
||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 | * GNU General Public License for more details. |
||
19 | * |
||
20 | * You should have received a copy of the GNU General Public License along |
||
21 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
23 | * http://www.gnu.org/copyleft/gpl.html |
||
24 | * |
||
25 | * @file |
||
26 | */ |
||
27 | |||
28 | /** |
||
29 | * Query module to enumerate all deleted revisions. |
||
30 | * |
||
31 | * @ingroup API |
||
32 | */ |
||
33 | class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase { |
||
34 | |||
35 | public function __construct( ApiQuery $query, $moduleName ) { |
||
36 | parent::__construct( $query, $moduleName, 'adr' ); |
||
37 | } |
||
38 | |||
39 | /** |
||
40 | * @param ApiPageSet $resultPageSet |
||
41 | * @return void |
||
42 | */ |
||
43 | protected function run( ApiPageSet $resultPageSet = null ) { |
||
44 | $user = $this->getUser(); |
||
45 | // Before doing anything at all, let's check permissions |
||
46 | if ( !$user->isAllowed( 'deletedhistory' ) ) { |
||
47 | $this->dieUsage( |
||
48 | 'You don\'t have permission to view deleted revision information', |
||
49 | 'permissiondenied' |
||
50 | ); |
||
51 | } |
||
52 | |||
53 | $db = $this->getDB(); |
||
54 | $params = $this->extractRequestParams( false ); |
||
55 | |||
56 | $result = $this->getResult(); |
||
57 | |||
58 | // If the user wants no namespaces, they get no pages. |
||
59 | if ( $params['namespace'] === [] ) { |
||
60 | if ( $resultPageSet === null ) { |
||
61 | $result->addValue( 'query', $this->getModuleName(), [] ); |
||
62 | } |
||
63 | return; |
||
64 | } |
||
65 | |||
66 | // This module operates in two modes: |
||
67 | // 'user': List deleted revs by a certain user |
||
68 | // 'all': List all deleted revs in NS |
||
69 | $mode = 'all'; |
||
70 | if ( !is_null( $params['user'] ) ) { |
||
71 | $mode = 'user'; |
||
72 | } |
||
73 | |||
74 | if ( $mode == 'user' ) { |
||
75 | View Code Duplication | foreach ( [ 'from', 'to', 'prefix', 'excludeuser' ] as $param ) { |
|
76 | if ( !is_null( $params[$param] ) ) { |
||
77 | $p = $this->getModulePrefix(); |
||
78 | $this->dieUsage( "The '{$p}{$param}' parameter cannot be used with '{$p}user'", |
||
79 | 'badparams' ); |
||
80 | } |
||
81 | } |
||
82 | } else { |
||
83 | View Code Duplication | foreach ( [ 'start', 'end' ] as $param ) { |
|
84 | if ( !is_null( $params[$param] ) ) { |
||
85 | $p = $this->getModulePrefix(); |
||
86 | $this->dieUsage( "The '{$p}{$param}' parameter may only be used with '{$p}user'", |
||
87 | 'badparams' ); |
||
88 | } |
||
89 | } |
||
90 | } |
||
91 | |||
92 | // If we're generating titles only, we can use DISTINCT for a better |
||
93 | // query. But we can't do that in 'user' mode (wrong index), and we can |
||
94 | // only do it when sorting ASC (because MySQL apparently can't use an |
||
95 | // index backwards for grouping even though it can for ORDER BY, WTF?) |
||
96 | $dir = $params['dir']; |
||
97 | $optimizeGenerateTitles = false; |
||
98 | if ( $mode === 'all' && $params['generatetitles'] && $resultPageSet !== null ) { |
||
99 | if ( $dir === 'newer' ) { |
||
100 | $optimizeGenerateTitles = true; |
||
101 | } else { |
||
102 | $p = $this->getModulePrefix(); |
||
103 | $this->setWarning( "For better performance when generating titles, set {$p}dir=newer" ); |
||
104 | } |
||
105 | } |
||
106 | |||
107 | $this->addTables( 'archive' ); |
||
108 | if ( $resultPageSet === null ) { |
||
109 | $this->parseParameters( $params ); |
||
110 | $this->addFields( Revision::selectArchiveFields() ); |
||
111 | $this->addFields( [ 'ar_title', 'ar_namespace' ] ); |
||
112 | } else { |
||
113 | $this->limit = $this->getParameter( 'limit' ) ?: 10; |
||
114 | $this->addFields( [ 'ar_title', 'ar_namespace' ] ); |
||
115 | if ( $optimizeGenerateTitles ) { |
||
116 | $this->addOption( 'DISTINCT' ); |
||
117 | } else { |
||
118 | $this->addFields( [ 'ar_timestamp', 'ar_rev_id', 'ar_id' ] ); |
||
119 | } |
||
120 | } |
||
121 | |||
122 | View Code Duplication | if ( $this->fld_tags ) { |
|
123 | $this->addTables( 'tag_summary' ); |
||
124 | $this->addJoinConds( |
||
125 | [ 'tag_summary' => [ 'LEFT JOIN', [ 'ar_rev_id=ts_rev_id' ] ] ] |
||
126 | ); |
||
127 | $this->addFields( 'ts_tags' ); |
||
128 | } |
||
129 | |||
130 | View Code Duplication | if ( !is_null( $params['tag'] ) ) { |
|
131 | $this->addTables( 'change_tag' ); |
||
132 | $this->addJoinConds( |
||
133 | [ 'change_tag' => [ 'INNER JOIN', [ 'ar_rev_id=ct_rev_id' ] ] ] |
||
134 | ); |
||
135 | $this->addWhereFld( 'ct_tag', $params['tag'] ); |
||
136 | } |
||
137 | |||
138 | View Code Duplication | if ( $this->fetchContent ) { |
|
139 | // Modern MediaWiki has the content for deleted revs in the 'text' |
||
140 | // table using fields old_text and old_flags. But revisions deleted |
||
141 | // pre-1.5 store the content in the 'archive' table directly using |
||
142 | // fields ar_text and ar_flags, and no corresponding 'text' row. So |
||
143 | // we have to LEFT JOIN and fetch all four fields. |
||
144 | $this->addTables( 'text' ); |
||
145 | $this->addJoinConds( |
||
146 | [ 'text' => [ 'LEFT JOIN', [ 'ar_text_id=old_id' ] ] ] |
||
147 | ); |
||
148 | $this->addFields( [ 'ar_text', 'ar_flags', 'old_text', 'old_flags' ] ); |
||
149 | |||
150 | // This also means stricter restrictions |
||
151 | if ( !$user->isAllowedAny( 'undelete', 'deletedtext' ) ) { |
||
152 | $this->dieUsage( |
||
153 | 'You don\'t have permission to view deleted revision content', |
||
154 | 'permissiondenied' |
||
155 | ); |
||
156 | } |
||
157 | } |
||
158 | |||
159 | $miser_ns = null; |
||
160 | |||
161 | if ( $mode == 'all' ) { |
||
162 | if ( $params['namespace'] !== null ) { |
||
163 | $namespaces = $params['namespace']; |
||
164 | } else { |
||
165 | $namespaces = MWNamespace::getValidNamespaces(); |
||
166 | } |
||
167 | $this->addWhereFld( 'ar_namespace', $namespaces ); |
||
168 | |||
169 | // For from/to/prefix, we have to consider the potential |
||
170 | // transformations of the title in all specified namespaces. |
||
171 | // Generally there will be only one transformation, but wikis with |
||
172 | // some namespaces case-sensitive could have two. |
||
173 | if ( $params['from'] !== null || $params['to'] !== null ) { |
||
174 | $isDirNewer = ( $dir === 'newer' ); |
||
175 | $after = ( $isDirNewer ? '>=' : '<=' ); |
||
176 | $before = ( $isDirNewer ? '<=' : '>=' ); |
||
177 | $where = []; |
||
178 | foreach ( $namespaces as $ns ) { |
||
179 | $w = []; |
||
180 | View Code Duplication | if ( $params['from'] !== null ) { |
|
181 | $w[] = 'ar_title' . $after . |
||
182 | $db->addQuotes( $this->titlePartToKey( $params['from'], $ns ) ); |
||
183 | } |
||
184 | View Code Duplication | if ( $params['to'] !== null ) { |
|
185 | $w[] = 'ar_title' . $before . |
||
186 | $db->addQuotes( $this->titlePartToKey( $params['to'], $ns ) ); |
||
187 | } |
||
188 | $w = $db->makeList( $w, LIST_AND ); |
||
189 | $where[$w][] = $ns; |
||
190 | } |
||
191 | View Code Duplication | if ( count( $where ) == 1 ) { |
|
192 | $where = key( $where ); |
||
193 | $this->addWhere( $where ); |
||
194 | } else { |
||
195 | $where2 = []; |
||
196 | foreach ( $where as $w => $ns ) { |
||
197 | $where2[] = $db->makeList( [ $w, 'ar_namespace' => $ns ], LIST_AND ); |
||
198 | } |
||
199 | $this->addWhere( $db->makeList( $where2, LIST_OR ) ); |
||
200 | } |
||
201 | } |
||
202 | |||
203 | if ( isset( $params['prefix'] ) ) { |
||
204 | $where = []; |
||
205 | foreach ( $namespaces as $ns ) { |
||
206 | $w = 'ar_title' . $db->buildLike( |
||
207 | $this->titlePartToKey( $params['prefix'], $ns ), |
||
208 | $db->anyString() ); |
||
209 | $where[$w][] = $ns; |
||
210 | } |
||
211 | View Code Duplication | if ( count( $where ) == 1 ) { |
|
212 | $where = key( $where ); |
||
213 | $this->addWhere( $where ); |
||
214 | } else { |
||
215 | $where2 = []; |
||
216 | foreach ( $where as $w => $ns ) { |
||
217 | $where2[] = $db->makeList( [ $w, 'ar_namespace' => $ns ], LIST_AND ); |
||
218 | } |
||
219 | $this->addWhere( $db->makeList( $where2, LIST_OR ) ); |
||
220 | } |
||
221 | } |
||
222 | } else { |
||
223 | if ( $this->getConfig()->get( 'MiserMode' ) ) { |
||
224 | $miser_ns = $params['namespace']; |
||
225 | } else { |
||
226 | $this->addWhereFld( 'ar_namespace', $params['namespace'] ); |
||
227 | } |
||
228 | $this->addTimestampWhereRange( 'ar_timestamp', $dir, $params['start'], $params['end'] ); |
||
229 | } |
||
230 | |||
231 | View Code Duplication | if ( !is_null( $params['user'] ) ) { |
|
232 | $this->addWhereFld( 'ar_user_text', $params['user'] ); |
||
233 | } elseif ( !is_null( $params['excludeuser'] ) ) { |
||
234 | $this->addWhere( 'ar_user_text != ' . |
||
235 | $db->addQuotes( $params['excludeuser'] ) ); |
||
236 | } |
||
237 | |||
238 | View Code Duplication | if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) { |
|
239 | // Paranoia: avoid brute force searches (bug 17342) |
||
240 | // (shouldn't be able to get here without 'deletedhistory', but |
||
241 | // check it again just in case) |
||
242 | if ( !$user->isAllowed( 'deletedhistory' ) ) { |
||
243 | $bitmask = Revision::DELETED_USER; |
||
244 | } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { |
||
245 | $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED; |
||
246 | } else { |
||
247 | $bitmask = 0; |
||
248 | } |
||
249 | if ( $bitmask ) { |
||
250 | $this->addWhere( $db->bitAnd( 'ar_deleted', $bitmask ) . " != $bitmask" ); |
||
251 | } |
||
252 | } |
||
253 | |||
254 | if ( !is_null( $params['continue'] ) ) { |
||
255 | $cont = explode( '|', $params['continue'] ); |
||
256 | $op = ( $dir == 'newer' ? '>' : '<' ); |
||
257 | if ( $optimizeGenerateTitles ) { |
||
258 | $this->dieContinueUsageIf( count( $cont ) != 2 ); |
||
259 | $ns = intval( $cont[0] ); |
||
260 | $this->dieContinueUsageIf( strval( $ns ) !== $cont[0] ); |
||
261 | $title = $db->addQuotes( $cont[1] ); |
||
262 | $this->addWhere( "ar_namespace $op $ns OR " . |
||
263 | "(ar_namespace = $ns AND ar_title $op= $title)" ); |
||
264 | View Code Duplication | } elseif ( $mode == 'all' ) { |
|
265 | $this->dieContinueUsageIf( count( $cont ) != 4 ); |
||
266 | $ns = intval( $cont[0] ); |
||
267 | $this->dieContinueUsageIf( strval( $ns ) !== $cont[0] ); |
||
268 | $title = $db->addQuotes( $cont[1] ); |
||
269 | $ts = $db->addQuotes( $db->timestamp( $cont[2] ) ); |
||
270 | $ar_id = (int)$cont[3]; |
||
271 | $this->dieContinueUsageIf( strval( $ar_id ) !== $cont[3] ); |
||
272 | $this->addWhere( "ar_namespace $op $ns OR " . |
||
273 | "(ar_namespace = $ns AND " . |
||
274 | "(ar_title $op $title OR " . |
||
275 | "(ar_title = $title AND " . |
||
276 | "(ar_timestamp $op $ts OR " . |
||
277 | "(ar_timestamp = $ts AND " . |
||
278 | "ar_id $op= $ar_id)))))" ); |
||
279 | } else { |
||
280 | $this->dieContinueUsageIf( count( $cont ) != 2 ); |
||
281 | $ts = $db->addQuotes( $db->timestamp( $cont[0] ) ); |
||
282 | $ar_id = (int)$cont[1]; |
||
283 | $this->dieContinueUsageIf( strval( $ar_id ) !== $cont[1] ); |
||
284 | $this->addWhere( "ar_timestamp $op $ts OR " . |
||
285 | "(ar_timestamp = $ts AND " . |
||
286 | "ar_id $op= $ar_id)" ); |
||
287 | } |
||
288 | } |
||
289 | |||
290 | $this->addOption( 'LIMIT', $this->limit + 1 ); |
||
291 | |||
292 | $sort = ( $dir == 'newer' ? '' : ' DESC' ); |
||
293 | $orderby = []; |
||
294 | if ( $optimizeGenerateTitles ) { |
||
295 | // Targeting index name_title_timestamp |
||
296 | View Code Duplication | if ( $params['namespace'] === null || count( array_unique( $params['namespace'] ) ) > 1 ) { |
|
297 | $orderby[] = "ar_namespace $sort"; |
||
298 | } |
||
299 | $orderby[] = "ar_title $sort"; |
||
300 | } elseif ( $mode == 'all' ) { |
||
301 | // Targeting index name_title_timestamp |
||
302 | View Code Duplication | if ( $params['namespace'] === null || count( array_unique( $params['namespace'] ) ) > 1 ) { |
|
303 | $orderby[] = "ar_namespace $sort"; |
||
304 | } |
||
305 | $orderby[] = "ar_title $sort"; |
||
306 | $orderby[] = "ar_timestamp $sort"; |
||
307 | $orderby[] = "ar_id $sort"; |
||
308 | } else { |
||
309 | // Targeting index usertext_timestamp |
||
310 | // 'user' is always constant. |
||
311 | $orderby[] = "ar_timestamp $sort"; |
||
312 | $orderby[] = "ar_id $sort"; |
||
313 | } |
||
314 | $this->addOption( 'ORDER BY', $orderby ); |
||
315 | |||
316 | $res = $this->select( __METHOD__ ); |
||
317 | $pageMap = []; // Maps ns&title to array index |
||
318 | $count = 0; |
||
319 | $nextIndex = 0; |
||
320 | $generated = []; |
||
321 | foreach ( $res as $row ) { |
||
322 | if ( ++$count > $this->limit ) { |
||
323 | // We've had enough |
||
324 | if ( $optimizeGenerateTitles ) { |
||
325 | $this->setContinueEnumParameter( 'continue', "$row->ar_namespace|$row->ar_title" ); |
||
326 | } elseif ( $mode == 'all' ) { |
||
327 | $this->setContinueEnumParameter( 'continue', |
||
328 | "$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id" |
||
329 | ); |
||
330 | } else { |
||
331 | $this->setContinueEnumParameter( 'continue', "$row->ar_timestamp|$row->ar_id" ); |
||
332 | } |
||
333 | break; |
||
334 | } |
||
335 | |||
336 | // Miser mode namespace check |
||
337 | if ( $miser_ns !== null && !in_array( $row->ar_namespace, $miser_ns ) ) { |
||
338 | continue; |
||
339 | } |
||
340 | |||
341 | if ( $resultPageSet !== null ) { |
||
342 | if ( $params['generatetitles'] ) { |
||
343 | $key = "{$row->ar_namespace}:{$row->ar_title}"; |
||
344 | if ( !isset( $generated[$key] ) ) { |
||
345 | $generated[$key] = Title::makeTitle( $row->ar_namespace, $row->ar_title ); |
||
346 | } |
||
347 | } else { |
||
348 | $generated[] = $row->ar_rev_id; |
||
349 | } |
||
350 | } else { |
||
351 | $revision = Revision::newFromArchiveRow( $row ); |
||
0 ignored issues
–
show
|
|||
352 | $rev = $this->extractRevisionInfo( $revision, $row ); |
||
0 ignored issues
–
show
It seems like
$row defined by $row on line 321 can be null ; however, ApiQueryRevisionsBase::extractRevisionInfo() 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);
}
}
![]() |
|||
353 | |||
354 | if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) { |
||
355 | $index = $nextIndex++; |
||
356 | $pageMap[$row->ar_namespace][$row->ar_title] = $index; |
||
357 | $title = $revision->getTitle(); |
||
358 | $a = [ |
||
359 | 'pageid' => $title->getArticleID(), |
||
360 | 'revisions' => [ $rev ], |
||
361 | ]; |
||
362 | ApiResult::setIndexedTagName( $a['revisions'], 'rev' ); |
||
363 | ApiQueryBase::addTitleInfo( $a, $title ); |
||
0 ignored issues
–
show
It seems like
$title defined by $revision->getTitle() on line 357 can be null ; however, ApiQueryBase::addTitleInfo() 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);
}
}
![]() |
|||
364 | $fit = $result->addValue( [ 'query', $this->getModuleName() ], $index, $a ); |
||
365 | View Code Duplication | } else { |
|
366 | $index = $pageMap[$row->ar_namespace][$row->ar_title]; |
||
367 | $fit = $result->addValue( |
||
368 | [ 'query', $this->getModuleName(), $index, 'revisions' ], |
||
369 | null, $rev ); |
||
370 | } |
||
371 | if ( !$fit ) { |
||
372 | if ( $mode == 'all' ) { |
||
373 | $this->setContinueEnumParameter( 'continue', |
||
374 | "$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id" |
||
375 | ); |
||
376 | } else { |
||
377 | $this->setContinueEnumParameter( 'continue', "$row->ar_timestamp|$row->ar_id" ); |
||
378 | } |
||
379 | break; |
||
380 | } |
||
381 | } |
||
382 | } |
||
383 | |||
384 | if ( $resultPageSet !== null ) { |
||
385 | if ( $params['generatetitles'] ) { |
||
386 | $resultPageSet->populateFromTitles( $generated ); |
||
387 | } else { |
||
388 | $resultPageSet->populateFromRevisionIDs( $generated ); |
||
389 | } |
||
390 | } else { |
||
391 | $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'page' ); |
||
392 | } |
||
393 | } |
||
394 | |||
395 | public function getAllowedParams() { |
||
396 | $ret = parent::getAllowedParams() + [ |
||
397 | 'user' => [ |
||
398 | ApiBase::PARAM_TYPE => 'user' |
||
399 | ], |
||
400 | 'namespace' => [ |
||
401 | ApiBase::PARAM_ISMULTI => true, |
||
402 | ApiBase::PARAM_TYPE => 'namespace', |
||
403 | ], |
||
404 | 'start' => [ |
||
405 | ApiBase::PARAM_TYPE => 'timestamp', |
||
406 | ApiBase::PARAM_HELP_MSG_INFO => [ [ 'useronly' ] ], |
||
407 | ], |
||
408 | 'end' => [ |
||
409 | ApiBase::PARAM_TYPE => 'timestamp', |
||
410 | ApiBase::PARAM_HELP_MSG_INFO => [ [ 'useronly' ] ], |
||
411 | ], |
||
412 | 'dir' => [ |
||
413 | ApiBase::PARAM_TYPE => [ |
||
414 | 'newer', |
||
415 | 'older' |
||
416 | ], |
||
417 | ApiBase::PARAM_DFLT => 'older', |
||
418 | ApiBase::PARAM_HELP_MSG => 'api-help-param-direction', |
||
419 | ], |
||
420 | 'from' => [ |
||
421 | ApiBase::PARAM_HELP_MSG_INFO => [ [ 'nonuseronly' ] ], |
||
422 | ], |
||
423 | 'to' => [ |
||
424 | ApiBase::PARAM_HELP_MSG_INFO => [ [ 'nonuseronly' ] ], |
||
425 | ], |
||
426 | 'prefix' => [ |
||
427 | ApiBase::PARAM_HELP_MSG_INFO => [ [ 'nonuseronly' ] ], |
||
428 | ], |
||
429 | 'excludeuser' => [ |
||
430 | ApiBase::PARAM_TYPE => 'user', |
||
431 | ApiBase::PARAM_HELP_MSG_INFO => [ [ 'nonuseronly' ] ], |
||
432 | ], |
||
433 | 'tag' => null, |
||
434 | 'continue' => [ |
||
435 | ApiBase::PARAM_HELP_MSG => 'api-help-param-continue', |
||
436 | ], |
||
437 | 'generatetitles' => [ |
||
438 | ApiBase::PARAM_DFLT => false |
||
439 | ], |
||
440 | ]; |
||
441 | |||
442 | if ( $this->getConfig()->get( 'MiserMode' ) ) { |
||
443 | $ret['user'][ApiBase::PARAM_HELP_MSG_APPEND] = [ |
||
444 | 'apihelp-query+alldeletedrevisions-param-miser-user-namespace', |
||
445 | ]; |
||
446 | $ret['namespace'][ApiBase::PARAM_HELP_MSG_APPEND] = [ |
||
447 | 'apihelp-query+alldeletedrevisions-param-miser-user-namespace', |
||
448 | ]; |
||
449 | } |
||
450 | |||
451 | return $ret; |
||
452 | } |
||
453 | |||
454 | protected function getExamplesMessages() { |
||
455 | return [ |
||
456 | 'action=query&list=alldeletedrevisions&adruser=Example&adrlimit=50' |
||
457 | => 'apihelp-query+alldeletedrevisions-example-user', |
||
458 | 'action=query&list=alldeletedrevisions&adrdir=newer&adrnamespace=0&adrlimit=50' |
||
459 | => 'apihelp-query+alldeletedrevisions-example-ns-main', |
||
460 | ]; |
||
461 | } |
||
462 | |||
463 | public function getHelpUrls() { |
||
464 | return 'https://www.mediawiki.org/wiki/API:Alldeletedrevisions'; |
||
465 | } |
||
466 | } |
||
467 |
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: