wikimedia /
mediawiki
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 | * 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
|
|||
| 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 |
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
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.