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/Status.php (1 issue)

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
 * Generic operation result.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 */
22
23
/**
24
 * Generic operation result class
25
 * Has warning/error list, boolean status and arbitrary value
26
 *
27
 * "Good" means the operation was completed with no warnings or errors.
28
 *
29
 * "OK" means the operation was partially or wholly completed.
30
 *
31
 * An operation which is not OK should have errors so that the user can be
32
 * informed as to what went wrong. Calling the fatal() function sets an error
33
 * message and simultaneously switches off the OK flag.
34
 *
35
 * The recommended pattern for Status objects is to return a Status object
36
 * unconditionally, i.e. both on success and on failure -- so that the
37
 * developer of the calling code is reminded that the function can fail, and
38
 * so that a lack of error-handling will be explicit.
39
 */
40
class Status extends StatusValue {
41
	/** @var callable */
42
	public $cleanCallback = false;
43
44
	/**
45
	 * Succinct helper method to wrap a StatusValue
46
	 *
47
	 * This is is useful when formatting StatusValue objects:
48
	 * @code
49
	 *     $this->getOutput()->addHtml( Status::wrap( $sv )->getHTML() );
50
	 * @endcode
51
	 *
52
	 * @param StatusValue|Status $sv
53
	 * @return Status
54
	 */
55
	public static function wrap( $sv ) {
56
		if ( $sv instanceof static ) {
57
			return $sv;
58
		}
59
60
		$result = new static();
61
		$result->ok =& $sv->ok;
62
		$result->errors =& $sv->errors;
63
		$result->value =& $sv->value;
64
		$result->successCount =& $sv->successCount;
65
		$result->failCount =& $sv->failCount;
66
		$result->success =& $sv->success;
67
68
		return $result;
69
	}
70
71
	/**
72
	 * Backwards compatibility logic
73
	 *
74
	 * @param string $name
75
	 * @return mixed
76
	 * @throws RuntimeException
77
	 */
78
	function __get( $name ) {
79
		if ( $name === 'ok' ) {
80
			return $this->isOK();
81
		} elseif ( $name === 'errors' ) {
82
			return $this->getErrors();
83
		}
84
85
		throw new RuntimeException( "Cannot get '$name' property." );
86
	}
87
88
	/**
89
	 * Change operation result
90
	 * Backwards compatibility logic
91
	 *
92
	 * @param string $name
93
	 * @param mixed $value
94
	 * @throws RuntimeException
95
	 */
96
	function __set( $name, $value ) {
97
		if ( $name === 'ok' ) {
98
			$this->setOK( $value );
99
		} elseif ( !property_exists( $this, $name ) ) {
100
			// Caller is using undeclared ad-hoc properties
101
			$this->$name = $value;
102
		} else {
103
			throw new RuntimeException( "Cannot set '$name' property." );
104
		}
105
	}
106
107
	/**
108
	 * Splits this Status object into two new Status objects, one which contains only
109
	 * the error messages, and one that contains the warnings, only. The returned array is
110
	 * defined as:
111
	 * [
112
	 *     0 => object(Status) # the Status with error messages, only
113
	 *     1 => object(Status) # The Status with warning messages, only
114
	 * ]
115
	 *
116
	 * @return Status[]
117
	 */
118
	public function splitByErrorType() {
119
		list( $errorsOnlyStatus, $warningsOnlyStatus ) = parent::splitByErrorType();
120
		$errorsOnlyStatus->cleanCallback =
121
			$warningsOnlyStatus->cleanCallback = $this->cleanCallback;
122
123
		return [ $errorsOnlyStatus, $warningsOnlyStatus ];
124
	}
125
126
	/**
127
	 * Returns the wrapped StatusValue object
128
	 * @return StatusValue
129
	 * @since 1.27
130
	 */
131
	public function getStatusValue() {
132
		return $this;
133
	}
134
135
	/**
136
	 * @param array $params
137
	 * @return array
138
	 */
139
	protected function cleanParams( array $params ) {
140
		if ( !$this->cleanCallback ) {
141
			return $params;
142
		}
143
		$cleanParams = [];
144
		foreach ( $params as $i => $param ) {
145
			$cleanParams[$i] = call_user_func( $this->cleanCallback, $param );
146
		}
147
		return $cleanParams;
148
	}
149
150
	/**
151
	 * @param string|Language|null $lang Language to use for processing
152
	 *  messages, or null to default to the user language.
153
	 * @return Language
154
	 */
155
	protected function languageFromParam( $lang ) {
156
		global $wgLang;
157
158
		if ( $lang === null ) {
159
			// @todo: Use RequestContext::getMain()->getLanguage() instead
160
			return $wgLang;
161
		} elseif ( $lang instanceof Language || $lang instanceof StubUserLang ) {
162
			return $lang;
163
		} else {
164
			return Language::factory( $lang );
165
		}
166
	}
167
168
	/**
169
	 * Get the error list as a wikitext formatted list
170
	 *
171
	 * @param string|bool $shortContext A short enclosing context message name, to
172
	 *        be used when there is a single error
173
	 * @param string|bool $longContext A long enclosing context message name, for a list
174
	 * @param string|Language $lang Language to use for processing messages
175
	 * @return string
176
	 */
177
	public function getWikiText( $shortContext = false, $longContext = false, $lang = null ) {
178
		$lang = $this->languageFromParam( $lang );
179
180
		$rawErrors = $this->getErrors();
181 View Code Duplication
		if ( count( $rawErrors ) == 0 ) {
182
			if ( $this->isOK() ) {
183
				$this->fatal( 'internalerror_info',
184
					__METHOD__ . " called for a good result, this is incorrect\n" );
185
			} else {
186
				$this->fatal( 'internalerror_info',
187
					__METHOD__ . ": Invalid result object: no error text but not OK\n" );
188
			}
189
			$rawErrors = $this->getErrors(); // just added a fatal
190
		}
191
		if ( count( $rawErrors ) == 1 ) {
192
			$s = $this->getErrorMessage( $rawErrors[0], $lang )->plain();
193 View Code Duplication
			if ( $shortContext ) {
194
				$s = wfMessage( $shortContext, $s )->inLanguage( $lang )->plain();
195
			} elseif ( $longContext ) {
196
				$s = wfMessage( $longContext, "* $s\n" )->inLanguage( $lang )->plain();
197
			}
198
		} else {
199
			$errors = $this->getErrorMessageArray( $rawErrors, $lang );
200
			foreach ( $errors as &$error ) {
201
				$error = $error->plain();
202
			}
203
			$s = '* ' . implode( "\n* ", $errors ) . "\n";
204 View Code Duplication
			if ( $longContext ) {
205
				$s = wfMessage( $longContext, $s )->inLanguage( $lang )->plain();
206
			} elseif ( $shortContext ) {
207
				$s = wfMessage( $shortContext, "\n$s\n" )->inLanguage( $lang )->plain();
208
			}
209
		}
210
		return $s;
211
	}
212
213
	/**
214
	 * Get a bullet list of the errors as a Message object.
215
	 *
216
	 * $shortContext and $longContext can be used to wrap the error list in some text.
217
	 * $shortContext will be preferred when there is a single error; $longContext will be
218
	 * preferred when there are multiple ones. In either case, $1 will be replaced with
219
	 * the list of errors.
220
	 *
221
	 * $shortContext is assumed to use $1 as an inline parameter: if there is a single item,
222
	 * it will not be made into a list; if there are multiple items, newlines will be inserted
223
	 * around the list.
224
	 * $longContext is assumed to use $1 as a standalone parameter; it will always receive a list.
225
	 *
226
	 * If both parameters are missing, and there is only one error, no bullet will be added.
227
	 *
228
	 * @param string|string[]|bool $shortContext A message name or an array of message names.
229
	 * @param string|string[]|bool $longContext A message name or an array of message names.
230
	 * @param string|Language $lang Language to use for processing messages
231
	 * @return Message
232
	 */
233
	public function getMessage( $shortContext = false, $longContext = false, $lang = null ) {
234
		$lang = $this->languageFromParam( $lang );
235
236
		$rawErrors = $this->getErrors();
237 View Code Duplication
		if ( count( $rawErrors ) == 0 ) {
238
			if ( $this->isOK() ) {
239
				$this->fatal( 'internalerror_info',
240
					__METHOD__ . " called for a good result, this is incorrect\n" );
241
			} else {
242
				$this->fatal( 'internalerror_info',
243
					__METHOD__ . ": Invalid result object: no error text but not OK\n" );
244
			}
245
			$rawErrors = $this->getErrors(); // just added a fatal
246
		}
247
		if ( count( $rawErrors ) == 1 ) {
248
			$s = $this->getErrorMessage( $rawErrors[0], $lang );
249 View Code Duplication
			if ( $shortContext ) {
250
				$s = wfMessage( $shortContext, $s )->inLanguage( $lang );
251
			} elseif ( $longContext ) {
252
				$wrapper = new RawMessage( "* \$1\n" );
253
				$wrapper->params( $s )->parse();
254
				$s = wfMessage( $longContext, $wrapper )->inLanguage( $lang );
255
			}
256
		} else {
257
			$msgs = $this->getErrorMessageArray( $rawErrors, $lang );
258
			$msgCount = count( $msgs );
259
260
			$s = new RawMessage( '* $' . implode( "\n* \$", range( 1, $msgCount ) ) );
261
			$s->params( $msgs )->parse();
262
263 View Code Duplication
			if ( $longContext ) {
264
				$s = wfMessage( $longContext, $s )->inLanguage( $lang );
265
			} elseif ( $shortContext ) {
266
				$wrapper = new RawMessage( "\n\$1\n", [ $s ] );
267
				$wrapper->parse();
268
				$s = wfMessage( $shortContext, $wrapper )->inLanguage( $lang );
269
			}
270
		}
271
272
		return $s;
273
	}
274
275
	/**
276
	 * Return the message for a single error
277
	 *
278
	 * The code string can be used a message key with per-language versions.
279
	 * If $error is an array, the "params" field is a list of parameters for the message.
280
	 *
281
	 * @param array|string $error Code string or (key: code string, params: string[]) map
282
	 * @param string|Language $lang Language to use for processing messages
283
	 * @return Message
284
	 */
285
	protected function getErrorMessage( $error, $lang = null ) {
286
		if ( is_array( $error ) ) {
287
			if ( isset( $error['message'] ) && $error['message'] instanceof Message ) {
288
				$msg = $error['message'];
289
			} elseif ( isset( $error['message'] ) && isset( $error['params'] ) ) {
290
				$msg = wfMessage( $error['message'],
291
					array_map( 'wfEscapeWikiText', $this->cleanParams( $error['params'] ) ) );
292
			} else {
293
				$msgName = array_shift( $error );
0 ignored issues
show
Are you sure the assignment to $msgName is correct as array_shift($error) (which targets array_shift()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
294
				$msg = wfMessage( $msgName,
295
					array_map( 'wfEscapeWikiText', $this->cleanParams( $error ) ) );
296
			}
297
		} elseif ( is_string( $error ) ) {
298
			$msg = wfMessage( $error );
299
		} else {
300
			throw new UnexpectedValueException( "Got " . get_class( $error ) . " for key." );
301
		}
302
303
		$msg->inLanguage( $this->languageFromParam( $lang ) );
304
		return $msg;
305
	}
306
307
	/**
308
	 * Get the error message as HTML. This is done by parsing the wikitext error message
309
	 * @param string|bool $shortContext A short enclosing context message name, to
310
	 *        be used when there is a single error
311
	 * @param string|bool $longContext A long enclosing context message name, for a list
312
	 * @param string|Language|null $lang Language to use for processing messages
313
	 * @return string
314
	 */
315
	public function getHTML( $shortContext = false, $longContext = false, $lang = null ) {
316
		$lang = $this->languageFromParam( $lang );
317
		$text = $this->getWikiText( $shortContext, $longContext, $lang );
318
		$out = MessageCache::singleton()->parse( $text, null, true, true, $lang );
319
		return $out instanceof ParserOutput ? $out->getText() : $out;
320
	}
321
322
	/**
323
	 * Return an array with a Message object for each error.
324
	 * @param array $errors
325
	 * @param string|Language $lang Language to use for processing messages
326
	 * @return Message[]
327
	 */
328
	protected function getErrorMessageArray( $errors, $lang = null ) {
329
		$lang = $this->languageFromParam( $lang );
330
		return array_map( function ( $e ) use ( $lang ) {
331
			return $this->getErrorMessage( $e, $lang );
332
		}, $errors );
333
	}
334
335
	/**
336
	 * Get the list of errors (but not warnings)
337
	 *
338
	 * @return array A list in which each entry is an array with a message key as its first element.
339
	 *         The remaining array elements are the message parameters.
340
	 * @deprecated since 1.25
341
	 */
342
	public function getErrorsArray() {
343
		return $this->getStatusArray( 'error' );
344
	}
345
346
	/**
347
	 * Get the list of warnings (but not errors)
348
	 *
349
	 * @return array A list in which each entry is an array with a message key as its first element.
350
	 *         The remaining array elements are the message parameters.
351
	 * @deprecated since 1.25
352
	 */
353
	public function getWarningsArray() {
354
		return $this->getStatusArray( 'warning' );
355
	}
356
357
	/**
358
	 * Returns a list of status messages of the given type (or all if false)
359
	 *
360
	 * @note: this handles RawMessage poorly
361
	 *
362
	 * @param string|bool $type
363
	 * @return array
364
	 */
365
	protected function getStatusArray( $type = false ) {
366
		$result = [];
367
368
		foreach ( $this->getErrors() as $error ) {
369
			if ( $type === false || $error['type'] === $type ) {
370
				if ( $error['message'] instanceof MessageSpecifier ) {
371
					$result[] = array_merge(
372
						[ $error['message']->getKey() ],
373
						$error['message']->getParams()
374
					);
375
				} elseif ( $error['params'] ) {
376
					$result[] = array_merge( [ $error['message'] ], $error['params'] );
377
				} else {
378
					$result[] = [ $error['message'] ];
379
				}
380
			}
381
		}
382
383
		return $result;
384
	}
385
386
	/**
387
	 * Don't save the callback when serializing, because Closures can't be
388
	 * serialized and we're going to clear it in __wakeup anyway.
389
	 */
390
	function __sleep() {
391
		$keys = array_keys( get_object_vars( $this ) );
392
		return array_diff( $keys, [ 'cleanCallback' ] );
393
	}
394
395
	/**
396
	 * Sanitize the callback parameter on wakeup, to avoid arbitrary execution.
397
	 */
398
	function __wakeup() {
399
		$this->cleanCallback = false;
400
	}
401
}
402