Issues (4122)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/api/ApiQueryDeletedrevs.php (4 issues)

Upgrade to new PHP Analysis Engine

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
 *
5
 * Created on Jul 2, 2007
6
 *
7
 * Copyright © 2007 Roan Kattouw "<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
 * Query module to enumerate all deleted revisions.
29
 *
30
 * @ingroup API
31
 * @deprecated since 1.25
32
 */
33
class ApiQueryDeletedrevs extends ApiQueryBase {
34
35
	public function __construct( ApiQuery $query, $moduleName ) {
36
		parent::__construct( $query, $moduleName, 'dr' );
37
	}
38
39
	public function execute() {
40
		$user = $this->getUser();
41
		// Before doing anything at all, let's check permissions
42
		if ( !$user->isAllowed( 'deletedhistory' ) ) {
43
			$this->dieUsage(
44
				'You don\'t have permission to view deleted revision information',
45
				'permissiondenied'
46
			);
47
		}
48
49
		$this->setWarning(
50
			'list=deletedrevs has been deprecated. Please use prop=deletedrevisions or ' .
51
			'list=alldeletedrevisions instead.'
52
		);
53
		$this->logFeatureUsage( 'action=query&list=deletedrevs' );
54
55
		$db = $this->getDB();
56
		$params = $this->extractRequestParams( false );
57
		$prop = array_flip( $params['prop'] );
58
		$fld_parentid = isset( $prop['parentid'] );
59
		$fld_revid = isset( $prop['revid'] );
60
		$fld_user = isset( $prop['user'] );
61
		$fld_userid = isset( $prop['userid'] );
62
		$fld_comment = isset( $prop['comment'] );
63
		$fld_parsedcomment = isset( $prop['parsedcomment'] );
64
		$fld_minor = isset( $prop['minor'] );
65
		$fld_len = isset( $prop['len'] );
66
		$fld_sha1 = isset( $prop['sha1'] );
67
		$fld_content = isset( $prop['content'] );
68
		$fld_token = isset( $prop['token'] );
69
		$fld_tags = isset( $prop['tags'] );
70
71
		if ( isset( $prop['token'] ) ) {
72
			$p = $this->getModulePrefix();
73
			$this->setWarning(
74
				"{$p}prop=token has been deprecated. Please use action=query&meta=tokens instead."
75
			);
76
		}
77
78
		// If we're in a mode that breaks the same-origin policy, no tokens can
79
		// be obtained
80
		if ( $this->lacksSameOriginSecurity() ) {
81
			$fld_token = false;
82
		}
83
84
		// If user can't undelete, no tokens
85
		if ( !$user->isAllowed( 'undelete' ) ) {
86
			$fld_token = false;
87
		}
88
89
		$result = $this->getResult();
90
		$pageSet = $this->getPageSet();
91
		$titles = $pageSet->getTitles();
92
93
		// This module operates in three modes:
94
		// 'revs': List deleted revs for certain titles (1)
95
		// 'user': List deleted revs by a certain user (2)
96
		// 'all': List all deleted revs in NS (3)
97
		$mode = 'all';
98
		if ( count( $titles ) > 0 ) {
99
			$mode = 'revs';
100
		} elseif ( !is_null( $params['user'] ) ) {
101
			$mode = 'user';
102
		}
103
104
		if ( $mode == 'revs' || $mode == 'user' ) {
105
			// Ignore namespace and unique due to inability to know whether they were purposely set
106
			foreach ( [ 'from', 'to', 'prefix', /*'namespace', 'unique'*/ ] as $p ) {
107
				if ( !is_null( $params[$p] ) ) {
108
					$this->dieUsage( "The '{$p}' parameter cannot be used in modes 1 or 2", 'badparams' );
109
				}
110
			}
111
		} else {
112
			foreach ( [ 'start', 'end' ] as $p ) {
113
				if ( !is_null( $params[$p] ) ) {
114
					$this->dieUsage( "The {$p} parameter cannot be used in mode 3", 'badparams' );
115
				}
116
			}
117
		}
118
119 View Code Duplication
		if ( !is_null( $params['user'] ) && !is_null( $params['excludeuser'] ) ) {
120
			$this->dieUsage( 'user and excludeuser cannot be used together', 'badparams' );
121
		}
122
123
		$this->addTables( 'archive' );
124
		$this->addFields( [ 'ar_title', 'ar_namespace', 'ar_timestamp', 'ar_deleted', 'ar_id' ] );
125
126
		$this->addFieldsIf( 'ar_parent_id', $fld_parentid );
127
		$this->addFieldsIf( 'ar_rev_id', $fld_revid );
128
		$this->addFieldsIf( 'ar_user_text', $fld_user );
129
		$this->addFieldsIf( 'ar_user', $fld_userid );
130
		$this->addFieldsIf( 'ar_comment', $fld_comment || $fld_parsedcomment );
131
		$this->addFieldsIf( 'ar_minor_edit', $fld_minor );
132
		$this->addFieldsIf( 'ar_len', $fld_len );
133
		$this->addFieldsIf( 'ar_sha1', $fld_sha1 );
134
135 View Code Duplication
		if ( $fld_tags ) {
136
			$this->addTables( 'tag_summary' );
137
			$this->addJoinConds(
138
				[ 'tag_summary' => [ 'LEFT JOIN', [ 'ar_rev_id=ts_rev_id' ] ] ]
139
			);
140
			$this->addFields( 'ts_tags' );
141
		}
142
143 View Code Duplication
		if ( !is_null( $params['tag'] ) ) {
144
			$this->addTables( 'change_tag' );
145
			$this->addJoinConds(
146
				[ 'change_tag' => [ 'INNER JOIN', [ 'ar_rev_id=ct_rev_id' ] ] ]
147
			);
148
			$this->addWhereFld( 'ct_tag', $params['tag'] );
149
		}
150
151 View Code Duplication
		if ( $fld_content ) {
152
			// Modern MediaWiki has the content for deleted revs in the 'text'
153
			// table using fields old_text and old_flags. But revisions deleted
154
			// pre-1.5 store the content in the 'archive' table directly using
155
			// fields ar_text and ar_flags, and no corresponding 'text' row. So
156
			// we have to LEFT JOIN and fetch all four fields, plus ar_text_id
157
			// to be able to tell the difference.
158
			$this->addTables( 'text' );
159
			$this->addJoinConds(
160
				[ 'text' => [ 'LEFT JOIN', [ 'ar_text_id=old_id' ] ] ]
161
			);
162
			$this->addFields( [ 'ar_text', 'ar_flags', 'ar_text_id', 'old_text', 'old_flags' ] );
163
164
			// This also means stricter restrictions
165
			if ( !$user->isAllowedAny( 'undelete', 'deletedtext' ) ) {
166
				$this->dieUsage(
167
					'You don\'t have permission to view deleted revision content',
168
					'permissiondenied'
169
				);
170
			}
171
		}
172
		// Check limits
173
		$userMax = $fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1;
174
		$botMax = $fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2;
175
176
		$limit = $params['limit'];
177
178
		if ( $limit == 'max' ) {
179
			$limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
180
			$this->getResult()->addParsedLimit( $this->getModuleName(), $limit );
181
		}
182
183
		$this->validateLimit( 'limit', $limit, 1, $userMax, $botMax );
184
185
		if ( $fld_token ) {
186
			// Undelete tokens are identical for all pages, so we cache one here
187
			$token = $user->getEditToken( '', $this->getMain()->getRequest() );
188
		}
189
190
		$dir = $params['dir'];
191
192
		// We need a custom WHERE clause that matches all titles.
193
		if ( $mode == 'revs' ) {
194
			$lb = new LinkBatch( $titles );
195
			$where = $lb->constructSet( 'ar', $db );
196
			$this->addWhere( $where );
0 ignored issues
show
It seems like $where defined by $lb->constructSet('ar', $db) on line 195 can also be of type boolean; however, ApiQueryBase::addWhere() does only seem to accept string|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
197
		} elseif ( $mode == 'all' ) {
198
			$this->addWhereFld( 'ar_namespace', $params['namespace'] );
199
200
			$from = $params['from'] === null
201
				? null
202
				: $this->titlePartToKey( $params['from'], $params['namespace'] );
203
			$to = $params['to'] === null
204
				? null
205
				: $this->titlePartToKey( $params['to'], $params['namespace'] );
206
			$this->addWhereRange( 'ar_title', $dir, $from, $to );
207
208 View Code Duplication
			if ( isset( $params['prefix'] ) ) {
209
				$this->addWhere( 'ar_title' . $db->buildLike(
210
					$this->titlePartToKey( $params['prefix'], $params['namespace'] ),
211
					$db->anyString() ) );
212
			}
213
		}
214
215 View Code Duplication
		if ( !is_null( $params['user'] ) ) {
216
			$this->addWhereFld( 'ar_user_text', $params['user'] );
217
		} elseif ( !is_null( $params['excludeuser'] ) ) {
218
			$this->addWhere( 'ar_user_text != ' .
219
				$db->addQuotes( $params['excludeuser'] ) );
220
		}
221
222 View Code Duplication
		if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) {
223
			// Paranoia: avoid brute force searches (bug 17342)
224
			// (shouldn't be able to get here without 'deletedhistory', but
225
			// check it again just in case)
226
			if ( !$user->isAllowed( 'deletedhistory' ) ) {
227
				$bitmask = Revision::DELETED_USER;
228
			} elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
229
				$bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
230
			} else {
231
				$bitmask = 0;
232
			}
233
			if ( $bitmask ) {
234
				$this->addWhere( $db->bitAnd( 'ar_deleted', $bitmask ) . " != $bitmask" );
235
			}
236
		}
237
238
		if ( !is_null( $params['continue'] ) ) {
239
			$cont = explode( '|', $params['continue'] );
240
			$op = ( $dir == 'newer' ? '>' : '<' );
241
			if ( $mode == 'all' || $mode == 'revs' ) {
242
				$this->dieContinueUsageIf( count( $cont ) != 4 );
243
				$ns = intval( $cont[0] );
244
				$this->dieContinueUsageIf( strval( $ns ) !== $cont[0] );
245
				$title = $db->addQuotes( $cont[1] );
246
				$ts = $db->addQuotes( $db->timestamp( $cont[2] ) );
247
				$ar_id = (int)$cont[3];
248
				$this->dieContinueUsageIf( strval( $ar_id ) !== $cont[3] );
249
				$this->addWhere( "ar_namespace $op $ns OR " .
250
					"(ar_namespace = $ns AND " .
251
					"(ar_title $op $title OR " .
252
					"(ar_title = $title AND " .
253
					"(ar_timestamp $op $ts OR " .
254
					"(ar_timestamp = $ts AND " .
255
					"ar_id $op= $ar_id)))))" );
256
			} else {
257
				$this->dieContinueUsageIf( count( $cont ) != 2 );
258
				$ts = $db->addQuotes( $db->timestamp( $cont[0] ) );
259
				$ar_id = (int)$cont[1];
260
				$this->dieContinueUsageIf( strval( $ar_id ) !== $cont[1] );
261
				$this->addWhere( "ar_timestamp $op $ts OR " .
262
					"(ar_timestamp = $ts AND " .
263
					"ar_id $op= $ar_id)" );
264
			}
265
		}
266
267
		$this->addOption( 'LIMIT', $limit + 1 );
268
		$this->addOption(
269
			'USE INDEX',
270
			[ 'archive' => ( $mode == 'user' ? 'usertext_timestamp' : 'name_title_timestamp' ) ]
271
		);
272
		if ( $mode == 'all' ) {
273
			if ( $params['unique'] ) {
274
				// @todo Does this work on non-MySQL?
275
				$this->addOption( 'GROUP BY', 'ar_title' );
276
			} else {
277
				$sort = ( $dir == 'newer' ? '' : ' DESC' );
278
				$this->addOption( 'ORDER BY', [
279
					'ar_title' . $sort,
280
					'ar_timestamp' . $sort,
281
					'ar_id' . $sort,
282
				] );
283
			}
284
		} else {
285
			if ( $mode == 'revs' ) {
286
				// Sort by ns and title in the same order as timestamp for efficiency
287
				$this->addWhereRange( 'ar_namespace', $dir, null, null );
288
				$this->addWhereRange( 'ar_title', $dir, null, null );
289
			}
290
			$this->addTimestampWhereRange( 'ar_timestamp', $dir, $params['start'], $params['end'] );
291
			// Include in ORDER BY for uniqueness
292
			$this->addWhereRange( 'ar_id', $dir, null, null );
293
		}
294
		$res = $this->select( __METHOD__ );
295
		$pageMap = []; // Maps ns&title to (fake) pageid
296
		$count = 0;
297
		$newPageID = 0;
298
		foreach ( $res as $row ) {
299 View Code Duplication
			if ( ++$count > $limit ) {
300
				// We've had enough
301
				if ( $mode == 'all' || $mode == 'revs' ) {
302
					$this->setContinueEnumParameter( 'continue',
303
						"$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id"
304
					);
305
				} else {
306
					$this->setContinueEnumParameter( 'continue', "$row->ar_timestamp|$row->ar_id" );
307
				}
308
				break;
309
			}
310
311
			$rev = [];
312
			$anyHidden = false;
313
314
			$rev['timestamp'] = wfTimestamp( TS_ISO_8601, $row->ar_timestamp );
315
			if ( $fld_revid ) {
316
				$rev['revid'] = intval( $row->ar_rev_id );
317
			}
318
			if ( $fld_parentid && !is_null( $row->ar_parent_id ) ) {
319
				$rev['parentid'] = intval( $row->ar_parent_id );
320
			}
321
			if ( $fld_user || $fld_userid ) {
322
				if ( $row->ar_deleted & Revision::DELETED_USER ) {
323
					$rev['userhidden'] = true;
324
					$anyHidden = true;
325
				}
326
				if ( Revision::userCanBitfield( $row->ar_deleted, Revision::DELETED_USER, $user ) ) {
327
					if ( $fld_user ) {
328
						$rev['user'] = $row->ar_user_text;
329
					}
330
					if ( $fld_userid ) {
331
						$rev['userid'] = (int)$row->ar_user;
332
					}
333
				}
334
			}
335
336
			if ( $fld_comment || $fld_parsedcomment ) {
337
				if ( $row->ar_deleted & Revision::DELETED_COMMENT ) {
338
					$rev['commenthidden'] = true;
339
					$anyHidden = true;
340
				}
341
				if ( Revision::userCanBitfield( $row->ar_deleted, Revision::DELETED_COMMENT, $user ) ) {
342
					if ( $fld_comment ) {
343
						$rev['comment'] = $row->ar_comment;
344
					}
345
					if ( $fld_parsedcomment ) {
346
						$title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
347
						$rev['parsedcomment'] = Linker::formatComment( $row->ar_comment, $title );
348
					}
349
				}
350
			}
351
352
			if ( $fld_minor ) {
353
				$rev['minor'] = $row->ar_minor_edit == 1;
354
			}
355
			if ( $fld_len ) {
356
				$rev['len'] = $row->ar_len;
357
			}
358
			if ( $fld_sha1 ) {
359
				if ( $row->ar_deleted & Revision::DELETED_TEXT ) {
360
					$rev['sha1hidden'] = true;
361
					$anyHidden = true;
362
				}
363 View Code Duplication
				if ( Revision::userCanBitfield( $row->ar_deleted, Revision::DELETED_TEXT, $user ) ) {
364
					if ( $row->ar_sha1 != '' ) {
365
						$rev['sha1'] = Wikimedia\base_convert( $row->ar_sha1, 36, 16, 40 );
366
					} else {
367
						$rev['sha1'] = '';
368
					}
369
				}
370
			}
371
			if ( $fld_content ) {
372
				if ( $row->ar_deleted & Revision::DELETED_TEXT ) {
373
					$rev['texthidden'] = true;
374
					$anyHidden = true;
375
				}
376
				if ( Revision::userCanBitfield( $row->ar_deleted, Revision::DELETED_TEXT, $user ) ) {
377
					if ( isset( $row->ar_text ) && !$row->ar_text_id ) {
378
						// Pre-1.5 ar_text row (if condition from Revision::newFromArchiveRow)
379
						ApiResult::setContentValue( $rev, 'text', Revision::getRevisionText( $row, 'ar_' ) );
380
					} else {
381
						ApiResult::setContentValue( $rev, 'text', Revision::getRevisionText( $row ) );
382
					}
383
				}
384
			}
385
386 View Code Duplication
			if ( $fld_tags ) {
387
				if ( $row->ts_tags ) {
388
					$tags = explode( ',', $row->ts_tags );
389
					ApiResult::setIndexedTagName( $tags, 'tag' );
390
					$rev['tags'] = $tags;
391
				} else {
392
					$rev['tags'] = [];
393
				}
394
			}
395
396
			if ( $anyHidden && ( $row->ar_deleted & Revision::DELETED_RESTRICTED ) ) {
397
				$rev['suppressed'] = true;
398
			}
399
400
			if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
401
				$pageID = $newPageID++;
402
				$pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
403
				$a['revisions'] = [ $rev ];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$a was never initialized. Although not strictly required by PHP, it is generally a good practice to add $a = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
404
				ApiResult::setIndexedTagName( $a['revisions'], 'rev' );
0 ignored issues
show
The variable $a does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
405
				$title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
406
				ApiQueryBase::addTitleInfo( $a, $title );
407
				if ( $fld_token ) {
408
					$a['token'] = $token;
0 ignored issues
show
The variable $token does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
409
				}
410
				$fit = $result->addValue( [ 'query', $this->getModuleName() ], $pageID, $a );
411 View Code Duplication
			} else {
412
				$pageID = $pageMap[$row->ar_namespace][$row->ar_title];
413
				$fit = $result->addValue(
414
					[ 'query', $this->getModuleName(), $pageID, 'revisions' ],
415
					null, $rev );
416
			}
417 View Code Duplication
			if ( !$fit ) {
418
				if ( $mode == 'all' || $mode == 'revs' ) {
419
					$this->setContinueEnumParameter( 'continue',
420
						"$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id"
421
					);
422
				} else {
423
					$this->setContinueEnumParameter( 'continue', "$row->ar_timestamp|$row->ar_id" );
424
				}
425
				break;
426
			}
427
		}
428
		$result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'page' );
429
	}
430
431
	public function isDeprecated() {
432
		return true;
433
	}
434
435
	public function getAllowedParams() {
436
		return [
437
			'start' => [
438
				ApiBase::PARAM_TYPE => 'timestamp',
439
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 1, 2 ] ],
440
			],
441
			'end' => [
442
				ApiBase::PARAM_TYPE => 'timestamp',
443
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 1, 2 ] ],
444
			],
445
			'dir' => [
446
				ApiBase::PARAM_TYPE => [
447
					'newer',
448
					'older'
449
				],
450
				ApiBase::PARAM_DFLT => 'older',
451
				ApiBase::PARAM_HELP_MSG => 'api-help-param-direction',
452
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 1, 3 ] ],
453
			],
454
			'from' => [
455
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
456
			],
457
			'to' => [
458
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
459
			],
460
			'prefix' => [
461
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
462
			],
463
			'unique' => [
464
				ApiBase::PARAM_DFLT => false,
465
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
466
			],
467
			'namespace' => [
468
				ApiBase::PARAM_TYPE => 'namespace',
469
				ApiBase::PARAM_DFLT => NS_MAIN,
470
				ApiBase::PARAM_HELP_MSG_INFO => [ [ 'modes', 3 ] ],
471
			],
472
			'tag' => null,
473
			'user' => [
474
				ApiBase::PARAM_TYPE => 'user'
475
			],
476
			'excludeuser' => [
477
				ApiBase::PARAM_TYPE => 'user'
478
			],
479
			'prop' => [
480
				ApiBase::PARAM_DFLT => 'user|comment',
481
				ApiBase::PARAM_TYPE => [
482
					'revid',
483
					'parentid',
484
					'user',
485
					'userid',
486
					'comment',
487
					'parsedcomment',
488
					'minor',
489
					'len',
490
					'sha1',
491
					'content',
492
					'token',
493
					'tags'
494
				],
495
				ApiBase::PARAM_ISMULTI => true
496
			],
497
			'limit' => [
498
				ApiBase::PARAM_DFLT => 10,
499
				ApiBase::PARAM_TYPE => 'limit',
500
				ApiBase::PARAM_MIN => 1,
501
				ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
502
				ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
503
			],
504
			'continue' => [
505
				ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
506
			],
507
		];
508
	}
509
510 View Code Duplication
	protected function getExamplesMessages() {
511
		return [
512
			'action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&' .
513
				'drprop=user|comment|content'
514
				=> 'apihelp-query+deletedrevs-example-mode1',
515
			'action=query&list=deletedrevs&druser=Bob&drlimit=50'
516
				=> 'apihelp-query+deletedrevs-example-mode2',
517
			'action=query&list=deletedrevs&drdir=newer&drlimit=50'
518
				=> 'apihelp-query+deletedrevs-example-mode3-main',
519
			'action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=1&drunique='
520
				=> 'apihelp-query+deletedrevs-example-mode3-talk',
521
		];
522
	}
523
524
	public function getHelpUrls() {
525
		return 'https://www.mediawiki.org/wiki/API:Deletedrevs';
526
	}
527
}
528