MediaWiki  1.23.13
ApiBase.php
Go to the documentation of this file.
1 <?php
42 abstract class ApiBase extends ContextSource {
43  // These constants allow modules to specify exactly how to treat incoming parameters.
44 
45  // Default value of the parameter
46  const PARAM_DFLT = 0;
47  // Boolean, do we accept more than one item for this parameter (e.g.: titles)?
48  const PARAM_ISMULTI = 1;
49  // Can be either a string type (e.g.: 'integer') or an array of allowed values
50  const PARAM_TYPE = 2;
51  // Max value allowed for a parameter. Only applies if TYPE='integer'
52  const PARAM_MAX = 3;
53  // Max value allowed for a parameter for bots and sysops. Only applies if TYPE='integer'
54  const PARAM_MAX2 = 4;
55  // Lowest value allowed for a parameter. Only applies if TYPE='integer'
56  const PARAM_MIN = 5;
57  // Boolean, do we allow the same value to be set more than once when ISMULTI=true
59  // Boolean, is the parameter deprecated (will show a warning)
60  const PARAM_DEPRECATED = 7;
62  const PARAM_REQUIRED = 8; // Boolean, is the parameter required?
64  // Boolean, if MIN/MAX are set, enforce (die) these?
65  // Only applies if TYPE='integer' Use with extreme caution
67 
68  // Name of property group that is on the root element of the result,
69  // i.e. not part of a list
70  const PROP_ROOT = 'ROOT';
71  // Boolean, is the result multiple items? Defaults to true for query modules,
72  // to false for other modules
73  const PROP_LIST = 'LIST';
74  const PROP_TYPE = 0; // Type of the property, uses same format as PARAM_TYPE
75  // Boolean, can the property be not included in the result? Defaults to false
76  const PROP_NULLABLE = 1;
77 
78  const LIMIT_BIG1 = 500; // Fast query, std user limit
79  const LIMIT_BIG2 = 5000; // Fast query, bot/sysop limit
80  const LIMIT_SML1 = 50; // Slow query, std user limit
81  const LIMIT_SML2 = 500; // Slow query, bot/sysop limit
82 
89 
91  private $mSlaveDB = null;
92  private $mParamCache = array();
93 
100  public function __construct( $mainModule, $moduleName, $modulePrefix = '' ) {
101  $this->mMainModule = $mainModule;
102  $this->mModuleName = $moduleName;
103  $this->mModulePrefix = $modulePrefix;
104 
105  if ( !$this->isMain() ) {
106  $this->setContext( $mainModule->getContext() );
107  }
108  }
109 
110  /*****************************************************************************
111  * ABSTRACT METHODS *
112  *****************************************************************************/
113 
130  abstract public function execute();
131 
139  public function getVersion() {
140  wfDeprecated( __METHOD__, '1.21' );
141 
142  return '';
143  }
144 
149  public function getModuleName() {
150  return $this->mModuleName;
151  }
152 
158  public function getModuleManager() {
159  return null;
160  }
161 
166  public function getModulePrefix() {
167  return $this->mModulePrefix;
168  }
169 
177  public function getModuleProfileName( $db = false ) {
178  if ( $db ) {
179  return 'API:' . $this->mModuleName . '-DB';
180  }
181 
182  return 'API:' . $this->mModuleName;
183  }
184 
189  public function getMain() {
190  return $this->mMainModule;
191  }
192 
198  public function isMain() {
199  return $this === $this->mMainModule;
200  }
201 
206  public function getResult() {
207  // Main module has getResult() method overridden
208  // Safety - avoid infinite loop:
209  if ( $this->isMain() ) {
210  ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
211  }
212 
213  return $this->getMain()->getResult();
214  }
215 
220  public function getResultData() {
221  return $this->getResult()->getData();
222  }
223 
233  public function createContext() {
234  wfDeprecated( __METHOD__, '1.19' );
235 
236  return new DerivativeContext( $this->getContext() );
237  }
238 
246  public function setWarning( $warning ) {
247  $result = $this->getResult();
248  $data = $result->getData();
249  $moduleName = $this->getModuleName();
250  if ( isset( $data['warnings'][$moduleName] ) ) {
251  // Don't add duplicate warnings
252  $oldWarning = $data['warnings'][$moduleName]['*'];
253  $warnPos = strpos( $oldWarning, $warning );
254  // If $warning was found in $oldWarning, check if it starts at 0 or after "\n"
255  if ( $warnPos !== false && ( $warnPos === 0 || $oldWarning[$warnPos - 1] === "\n" ) ) {
256  // Check if $warning is followed by "\n" or the end of the $oldWarning
257  $warnPos += strlen( $warning );
258  if ( strlen( $oldWarning ) <= $warnPos || $oldWarning[$warnPos] === "\n" ) {
259  return;
260  }
261  }
262  // If there is a warning already, append it to the existing one
263  $warning = "$oldWarning\n$warning";
264  }
265  $msg = array();
266  ApiResult::setContent( $msg, $warning );
267  $result->disableSizeCheck();
268  $result->addValue( 'warnings', $moduleName,
270  $result->enableSizeCheck();
271  }
272 
279  public function getCustomPrinter() {
280  return null;
281  }
282 
287  public function makeHelpMsg() {
288  static $lnPrfx = "\n ";
289 
290  $msg = $this->getFinalDescription();
291 
292  if ( $msg !== false ) {
293 
294  if ( !is_array( $msg ) ) {
295  $msg = array(
296  $msg
297  );
298  }
299  $msg = $lnPrfx . implode( $lnPrfx, $msg ) . "\n";
300 
301  $msg .= $this->makeHelpArrayToString( $lnPrfx, false, $this->getHelpUrls() );
302 
303  if ( $this->isReadMode() ) {
304  $msg .= "\nThis module requires read rights";
305  }
306  if ( $this->isWriteMode() ) {
307  $msg .= "\nThis module requires write rights";
308  }
309  if ( $this->mustBePosted() ) {
310  $msg .= "\nThis module only accepts POST requests";
311  }
312  if ( $this->isReadMode() || $this->isWriteMode() ||
313  $this->mustBePosted()
314  ) {
315  $msg .= "\n";
316  }
317 
318  // Parameters
319  $paramsMsg = $this->makeHelpMsgParameters();
320  if ( $paramsMsg !== false ) {
321  $msg .= "Parameters:\n$paramsMsg";
322  }
323 
324  $examples = $this->getExamples();
325  if ( $examples ) {
326  if ( !is_array( $examples ) ) {
327  $examples = array(
328  $examples
329  );
330  }
331  $msg .= "Example" . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
332  foreach ( $examples as $k => $v ) {
333  if ( is_numeric( $k ) ) {
334  $msg .= " $v\n";
335  } else {
336  if ( is_array( $v ) ) {
337  $msgExample = implode( "\n", array_map( array( $this, 'indentExampleText' ), $v ) );
338  } else {
339  $msgExample = " $v";
340  }
341  $msgExample .= ":";
342  $msg .= wordwrap( $msgExample, 100, "\n" ) . "\n $k\n";
343  }
344  }
345  }
346  }
347 
348  return $msg;
349  }
350 
355  private function indentExampleText( $item ) {
356  return " " . $item;
357  }
358 
365  protected function makeHelpArrayToString( $prefix, $title, $input ) {
366  if ( $input === false ) {
367  return '';
368  }
369  if ( !is_array( $input ) ) {
370  $input = array( $input );
371  }
372 
373  if ( count( $input ) > 0 ) {
374  if ( $title ) {
375  $msg = $title . ( count( $input ) > 1 ? 's' : '' ) . ":\n ";
376  } else {
377  $msg = ' ';
378  }
379  $msg .= implode( $prefix, $input ) . "\n";
380 
381  return $msg;
382  }
383 
384  return '';
385  }
386 
392  public function makeHelpMsgParameters() {
394  if ( $params ) {
395 
396  $paramsDescription = $this->getFinalParamDescription();
397  $msg = '';
398  $paramPrefix = "\n" . str_repeat( ' ', 24 );
399  $descWordwrap = "\n" . str_repeat( ' ', 28 );
400  foreach ( $params as $paramName => $paramSettings ) {
401  $desc = isset( $paramsDescription[$paramName] ) ? $paramsDescription[$paramName] : '';
402  if ( is_array( $desc ) ) {
403  $desc = implode( $paramPrefix, $desc );
404  }
405 
406  //handle shorthand
407  if ( !is_array( $paramSettings ) ) {
408  $paramSettings = array(
409  self::PARAM_DFLT => $paramSettings,
410  );
411  }
412 
413  //handle missing type
414  if ( !isset( $paramSettings[ApiBase::PARAM_TYPE] ) ) {
415  $dflt = isset( $paramSettings[ApiBase::PARAM_DFLT] )
416  ? $paramSettings[ApiBase::PARAM_DFLT]
417  : null;
418  if ( is_bool( $dflt ) ) {
419  $paramSettings[ApiBase::PARAM_TYPE] = 'boolean';
420  } elseif ( is_string( $dflt ) || is_null( $dflt ) ) {
421  $paramSettings[ApiBase::PARAM_TYPE] = 'string';
422  } elseif ( is_int( $dflt ) ) {
423  $paramSettings[ApiBase::PARAM_TYPE] = 'integer';
424  }
425  }
426 
427  if ( isset( $paramSettings[self::PARAM_DEPRECATED] )
428  && $paramSettings[self::PARAM_DEPRECATED]
429  ) {
430  $desc = "DEPRECATED! $desc";
431  }
432 
433  if ( isset( $paramSettings[self::PARAM_REQUIRED] )
434  && $paramSettings[self::PARAM_REQUIRED]
435  ) {
436  $desc .= $paramPrefix . "This parameter is required";
437  }
438 
439  $type = isset( $paramSettings[self::PARAM_TYPE] )
440  ? $paramSettings[self::PARAM_TYPE]
441  : null;
442  if ( isset( $type ) ) {
443  $hintPipeSeparated = true;
444  $multi = isset( $paramSettings[self::PARAM_ISMULTI] )
445  ? $paramSettings[self::PARAM_ISMULTI]
446  : false;
447  if ( $multi ) {
448  $prompt = 'Values (separate with \'|\'): ';
449  } else {
450  $prompt = 'One value: ';
451  }
452 
453  if ( is_array( $type ) ) {
454  $choices = array();
455  $nothingPrompt = '';
456  foreach ( $type as $t ) {
457  if ( $t === '' ) {
458  $nothingPrompt = 'Can be empty, or ';
459  } else {
460  $choices[] = $t;
461  }
462  }
463  $desc .= $paramPrefix . $nothingPrompt . $prompt;
464  $choicesstring = implode( ', ', $choices );
465  $desc .= wordwrap( $choicesstring, 100, $descWordwrap );
466  $hintPipeSeparated = false;
467  } else {
468  switch ( $type ) {
469  case 'namespace':
470  // Special handling because namespaces are
471  // type-limited, yet they are not given
472  $desc .= $paramPrefix . $prompt;
473  $desc .= wordwrap( implode( ', ', MWNamespace::getValidNamespaces() ),
474  100, $descWordwrap );
475  $hintPipeSeparated = false;
476  break;
477  case 'limit':
478  $desc .= $paramPrefix . "No more than {$paramSettings[self::PARAM_MAX]}";
479  if ( isset( $paramSettings[self::PARAM_MAX2] ) ) {
480  $desc .= " ({$paramSettings[self::PARAM_MAX2]} for bots)";
481  }
482  $desc .= ' allowed';
483  break;
484  case 'integer':
485  $s = $multi ? 's' : '';
486  $hasMin = isset( $paramSettings[self::PARAM_MIN] );
487  $hasMax = isset( $paramSettings[self::PARAM_MAX] );
488  if ( $hasMin || $hasMax ) {
489  if ( !$hasMax ) {
490  $intRangeStr = "The value$s must be no less than " .
491  "{$paramSettings[self::PARAM_MIN]}";
492  } elseif ( !$hasMin ) {
493  $intRangeStr = "The value$s must be no more than " .
494  "{$paramSettings[self::PARAM_MAX]}";
495  } else {
496  $intRangeStr = "The value$s must be between " .
497  "{$paramSettings[self::PARAM_MIN]} and {$paramSettings[self::PARAM_MAX]}";
498  }
499 
500  $desc .= $paramPrefix . $intRangeStr;
501  }
502  break;
503  case 'upload':
504  $desc .= $paramPrefix . "Must be posted as a file upload using multipart/form-data";
505  break;
506  }
507  }
508 
509  if ( $multi ) {
510  if ( $hintPipeSeparated ) {
511  $desc .= $paramPrefix . "Separate values with '|'";
512  }
513 
514  $isArray = is_array( $type );
515  if ( !$isArray
516  || $isArray && count( $type ) > self::LIMIT_SML1
517  ) {
518  $desc .= $paramPrefix . "Maximum number of values " .
519  self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)";
520  }
521  }
522  }
523 
524  $default = isset( $paramSettings[self::PARAM_DFLT] ) ? $paramSettings[self::PARAM_DFLT] : null;
525  if ( !is_null( $default ) && $default !== false ) {
526  $desc .= $paramPrefix . "Default: $default";
527  }
528 
529  $msg .= sprintf( " %-19s - %s\n", $this->encodeParamName( $paramName ), $desc );
530  }
531 
532  return $msg;
533  }
534 
535  return false;
536  }
537 
542  protected function getDescription() {
543  return false;
544  }
545 
550  protected function getExamples() {
551  return false;
552  }
553 
566  protected function getAllowedParams( /* $flags = 0 */ ) {
567  // int $flags is not declared because it causes "Strict standards"
568  // warning. Most derived classes do not implement it.
569  return false;
570  }
571 
578  protected function getParamDescription() {
579  return false;
580  }
581 
590  public function getFinalParams( $flags = 0 ) {
591  $params = $this->getAllowedParams( $flags );
592  wfRunHooks( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
593 
594  return $params;
595  }
596 
603  public function getFinalParamDescription() {
604  $desc = $this->getParamDescription();
605  wfRunHooks( 'APIGetParamDescription', array( &$this, &$desc ) );
606 
607  return $desc;
608  }
609 
626  protected function getResultProperties() {
627  return false;
628  }
629 
636  public function getFinalResultProperties() {
637  $properties = $this->getResultProperties();
638  wfRunHooks( 'APIGetResultProperties', array( $this, &$properties ) );
639 
640  return $properties;
641  }
642 
647  protected static function addTokenProperties( &$props, $tokenFunctions ) {
648  foreach ( array_keys( $tokenFunctions ) as $token ) {
649  $props[''][$token . 'token'] = array(
650  ApiBase::PROP_TYPE => 'string',
651  ApiBase::PROP_NULLABLE => true
652  );
653  }
654  }
655 
662  public function getFinalDescription() {
663  $desc = $this->getDescription();
664  wfRunHooks( 'APIGetDescription', array( &$this, &$desc ) );
665 
666  return $desc;
667  }
668 
675  public function encodeParamName( $paramName ) {
676  return $this->mModulePrefix . $paramName;
677  }
678 
688  public function extractRequestParams( $parseLimit = true ) {
689  // Cache parameters, for performance and to avoid bug 24564.
690  if ( !isset( $this->mParamCache[$parseLimit] ) ) {
691  $params = $this->getFinalParams();
692  $results = array();
693 
694  if ( $params ) { // getFinalParams() can return false
695  foreach ( $params as $paramName => $paramSettings ) {
696  $results[$paramName] = $this->getParameterFromSettings(
697  $paramName, $paramSettings, $parseLimit );
698  }
699  }
700  $this->mParamCache[$parseLimit] = $results;
701  }
702 
703  return $this->mParamCache[$parseLimit];
704  }
705 
712  protected function getParameter( $paramName, $parseLimit = true ) {
713  $params = $this->getFinalParams();
714  $paramSettings = $params[$paramName];
715 
716  return $this->getParameterFromSettings( $paramName, $paramSettings, $parseLimit );
717  }
718 
723  public function requireOnlyOneParameter( $params ) {
724  $required = func_get_args();
725  array_shift( $required );
726  $p = $this->getModulePrefix();
727 
728  $intersection = array_intersect( array_keys( array_filter( $params,
729  array( $this, "parameterNotEmpty" ) ) ), $required );
730 
731  if ( count( $intersection ) > 1 ) {
732  $this->dieUsage(
733  "The parameters {$p}" . implode( ", {$p}", $intersection ) . ' can not be used together',
734  'invalidparammix' );
735  } elseif ( count( $intersection ) == 0 ) {
736  $this->dieUsage(
737  "One of the parameters {$p}" . implode( ", {$p}", $required ) . ' is required',
738  'missingparam'
739  );
740  }
741  }
742 
750  $p = $this->getModulePrefix();
751  $params = implode( ", {$p}", $params );
752 
753  return array(
754  array(
755  'code' => "{$p}missingparam",
756  'info' => "One of the parameters {$p}{$params} is required"
757  ),
758  array(
759  'code' => "{$p}invalidparammix",
760  'info' => "The parameters {$p}{$params} can not be used together"
761  )
762  );
763  }
764 
770  public function requireMaxOneParameter( $params ) {
771  $required = func_get_args();
772  array_shift( $required );
773  $p = $this->getModulePrefix();
774 
775  $intersection = array_intersect( array_keys( array_filter( $params,
776  array( $this, "parameterNotEmpty" ) ) ), $required );
777 
778  if ( count( $intersection ) > 1 ) {
779  $this->dieUsage(
780  "The parameters {$p}" . implode( ", {$p}", $intersection ) . ' can not be used together',
781  'invalidparammix'
782  );
783  }
784  }
785 
793  $p = $this->getModulePrefix();
794  $params = implode( ", {$p}", $params );
795 
796  return array(
797  array(
798  'code' => "{$p}invalidparammix",
799  'info' => "The parameters {$p}{$params} can not be used together"
800  )
801  );
802  }
803 
811  public function requireAtLeastOneParameter( $params ) {
812  $required = func_get_args();
813  array_shift( $required );
814  $p = $this->getModulePrefix();
815 
816  $intersection = array_intersect(
817  array_keys( array_filter( $params, array( $this, "parameterNotEmpty" ) ) ),
818  $required
819  );
820 
821  if ( count( $intersection ) == 0 ) {
822  $this->dieUsage( "At least one of the parameters {$p}" .
823  implode( ", {$p}", $required ) . ' is required', "{$p}missingparam" );
824  }
825  }
826 
835  $p = $this->getModulePrefix();
836  $params = implode( ", {$p}", $params );
837 
838  return array(
839  array(
840  'code' => "{$p}missingparam",
841  'info' => "At least one of the parameters {$p}{$params} is required",
842  ),
843  );
844  }
845 
854  public function getTitleOrPageId( $params, $load = false ) {
855  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
856 
857  $pageObj = null;
858  if ( isset( $params['title'] ) ) {
859  $titleObj = Title::newFromText( $params['title'] );
860  if ( !$titleObj || $titleObj->isExternal() ) {
861  $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
862  }
863  if ( !$titleObj->canExist() ) {
864  $this->dieUsage( "Namespace doesn't allow actual pages", 'pagecannotexist' );
865  }
866  $pageObj = WikiPage::factory( $titleObj );
867  if ( $load !== false ) {
868  $pageObj->loadPageData( $load );
869  }
870  } elseif ( isset( $params['pageid'] ) ) {
871  if ( $load === false ) {
872  $load = 'fromdb';
873  }
874  $pageObj = WikiPage::newFromID( $params['pageid'], $load );
875  if ( !$pageObj ) {
876  $this->dieUsageMsg( array( 'nosuchpageid', $params['pageid'] ) );
877  }
878  }
879 
880  return $pageObj;
881  }
882 
886  public function getTitleOrPageIdErrorMessage() {
887  return array_merge(
888  $this->getRequireOnlyOneParameterErrorMessages( array( 'title', 'pageid' ) ),
889  array(
890  array( 'invalidtitle', 'title' ),
891  array( 'nosuchpageid', 'pageid' ),
892  )
893  );
894  }
895 
902  private function parameterNotEmpty( $x ) {
903  return !is_null( $x ) && $x !== false;
904  }
905 
914  protected function getWatchlistValue( $watchlist, $titleObj, $userOption = null ) {
915 
916  $userWatching = $this->getUser()->isWatched( $titleObj, WatchedItem::IGNORE_USER_RIGHTS );
917 
918  switch ( $watchlist ) {
919  case 'watch':
920  return true;
921 
922  case 'unwatch':
923  return false;
924 
925  case 'preferences':
926  # If the user is already watching, don't bother checking
927  if ( $userWatching ) {
928  return true;
929  }
930  # If no user option was passed, use watchdefault and watchcreations
931  if ( is_null( $userOption ) ) {
932  return $this->getUser()->getBoolOption( 'watchdefault' ) ||
933  $this->getUser()->getBoolOption( 'watchcreations' ) && !$titleObj->exists();
934  }
935 
936  # Watch the article based on the user preference
937  return $this->getUser()->getBoolOption( $userOption );
938 
939  case 'nochange':
940  return $userWatching;
941 
942  default:
943  return $userWatching;
944  }
945  }
946 
953  protected function setWatch( $watch, $titleObj, $userOption = null ) {
954  $value = $this->getWatchlistValue( $watch, $titleObj, $userOption );
955  if ( $value === null ) {
956  return;
957  }
958 
959  WatchAction::doWatchOrUnwatch( $value, $titleObj, $this->getUser() );
960  }
961 
971  protected function getParameterFromSettings( $paramName, $paramSettings, $parseLimit ) {
972  // Some classes may decide to change parameter names
973  $encParamName = $this->encodeParamName( $paramName );
974 
975  if ( !is_array( $paramSettings ) ) {
976  $default = $paramSettings;
977  $multi = false;
978  $type = gettype( $paramSettings );
979  $dupes = false;
980  $deprecated = false;
981  $required = false;
982  } else {
983  $default = isset( $paramSettings[self::PARAM_DFLT] )
984  ? $paramSettings[self::PARAM_DFLT]
985  : null;
986  $multi = isset( $paramSettings[self::PARAM_ISMULTI] )
987  ? $paramSettings[self::PARAM_ISMULTI]
988  : false;
989  $type = isset( $paramSettings[self::PARAM_TYPE] )
990  ? $paramSettings[self::PARAM_TYPE]
991  : null;
992  $dupes = isset( $paramSettings[self::PARAM_ALLOW_DUPLICATES] )
993  ? $paramSettings[self::PARAM_ALLOW_DUPLICATES]
994  : false;
995  $deprecated = isset( $paramSettings[self::PARAM_DEPRECATED] )
996  ? $paramSettings[self::PARAM_DEPRECATED]
997  : false;
998  $required = isset( $paramSettings[self::PARAM_REQUIRED] )
999  ? $paramSettings[self::PARAM_REQUIRED]
1000  : false;
1001 
1002  // When type is not given, and no choices, the type is the same as $default
1003  if ( !isset( $type ) ) {
1004  if ( isset( $default ) ) {
1005  $type = gettype( $default );
1006  } else {
1007  $type = 'NULL'; // allow everything
1008  }
1009  }
1010  }
1011 
1012  if ( $type == 'boolean' ) {
1013  if ( isset( $default ) && $default !== false ) {
1014  // Having a default value of anything other than 'false' is not allowed
1016  __METHOD__,
1017  "Boolean param $encParamName's default is set to '$default'. " .
1018  "Boolean parameters must default to false."
1019  );
1020  }
1021 
1022  $value = $this->getMain()->getCheck( $encParamName );
1023  } elseif ( $type == 'upload' ) {
1024  if ( isset( $default ) ) {
1025  // Having a default value is not allowed
1027  __METHOD__,
1028  "File upload param $encParamName's default is set to " .
1029  "'$default'. File upload parameters may not have a default." );
1030  }
1031  if ( $multi ) {
1032  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1033  }
1034  $value = $this->getMain()->getUpload( $encParamName );
1035  if ( !$value->exists() ) {
1036  // This will get the value without trying to normalize it
1037  // (because trying to normalize a large binary file
1038  // accidentally uploaded as a field fails spectacularly)
1039  $value = $this->getMain()->getRequest()->unsetVal( $encParamName );
1040  if ( $value !== null ) {
1041  $this->dieUsage(
1042  "File upload param $encParamName is not a file upload; " .
1043  "be sure to use multipart/form-data for your POST and include " .
1044  "a filename in the Content-Disposition header.",
1045  "badupload_{$encParamName}"
1046  );
1047  }
1048  }
1049  } else {
1050  $value = $this->getMain()->getVal( $encParamName, $default );
1051 
1052  if ( isset( $value ) && $type == 'namespace' ) {
1054  }
1055  }
1056 
1057  if ( isset( $value ) && ( $multi || is_array( $type ) ) ) {
1058  $value = $this->parseMultiValue(
1059  $encParamName,
1060  $value,
1061  $multi,
1062  is_array( $type ) ? $type : null
1063  );
1064  }
1065 
1066  // More validation only when choices were not given
1067  // choices were validated in parseMultiValue()
1068  if ( isset( $value ) ) {
1069  if ( !is_array( $type ) ) {
1070  switch ( $type ) {
1071  case 'NULL': // nothing to do
1072  break;
1073  case 'string':
1074  if ( $required && $value === '' ) {
1075  $this->dieUsageMsg( array( 'missingparam', $paramName ) );
1076  }
1077  break;
1078  case 'integer': // Force everything using intval() and optionally validate limits
1079  $min = isset( $paramSettings[self::PARAM_MIN] ) ? $paramSettings[self::PARAM_MIN] : null;
1080  $max = isset( $paramSettings[self::PARAM_MAX] ) ? $paramSettings[self::PARAM_MAX] : null;
1081  $enforceLimits = isset( $paramSettings[self::PARAM_RANGE_ENFORCE] )
1082  ? $paramSettings[self::PARAM_RANGE_ENFORCE] : false;
1083 
1084  if ( is_array( $value ) ) {
1085  $value = array_map( 'intval', $value );
1086  if ( !is_null( $min ) || !is_null( $max ) ) {
1087  foreach ( $value as &$v ) {
1088  $this->validateLimit( $paramName, $v, $min, $max, null, $enforceLimits );
1089  }
1090  }
1091  } else {
1092  $value = intval( $value );
1093  if ( !is_null( $min ) || !is_null( $max ) ) {
1094  $this->validateLimit( $paramName, $value, $min, $max, null, $enforceLimits );
1095  }
1096  }
1097  break;
1098  case 'limit':
1099  if ( !$parseLimit ) {
1100  // Don't do any validation whatsoever
1101  break;
1102  }
1103  if ( !isset( $paramSettings[self::PARAM_MAX] )
1104  || !isset( $paramSettings[self::PARAM_MAX2] )
1105  ) {
1107  __METHOD__,
1108  "MAX1 or MAX2 are not defined for the limit $encParamName"
1109  );
1110  }
1111  if ( $multi ) {
1112  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1113  }
1114  $min = isset( $paramSettings[self::PARAM_MIN] ) ? $paramSettings[self::PARAM_MIN] : 0;
1115  if ( $value == 'max' ) {
1116  $value = $this->getMain()->canApiHighLimits()
1117  ? $paramSettings[self::PARAM_MAX2]
1118  : $paramSettings[self::PARAM_MAX];
1119  $this->getResult()->setParsedLimit( $this->getModuleName(), $value );
1120  } else {
1121  $value = intval( $value );
1122  $this->validateLimit(
1123  $paramName,
1124  $value,
1125  $min,
1126  $paramSettings[self::PARAM_MAX],
1127  $paramSettings[self::PARAM_MAX2]
1128  );
1129  }
1130  break;
1131  case 'boolean':
1132  if ( $multi ) {
1133  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1134  }
1135  break;
1136  case 'timestamp':
1137  if ( is_array( $value ) ) {
1138  foreach ( $value as $key => $val ) {
1139  $value[$key] = $this->validateTimestamp( $val, $encParamName );
1140  }
1141  } else {
1142  $value = $this->validateTimestamp( $value, $encParamName );
1143  }
1144  break;
1145  case 'user':
1146  if ( is_array( $value ) ) {
1147  foreach ( $value as $key => $val ) {
1148  $value[$key] = $this->validateUser( $val, $encParamName );
1149  }
1150  } else {
1151  $value = $this->validateUser( $value, $encParamName );
1152  }
1153  break;
1154  case 'upload': // nothing to do
1155  break;
1156  default:
1157  ApiBase::dieDebug( __METHOD__, "Param $encParamName's type is unknown - $type" );
1158  }
1159  }
1160 
1161  // Throw out duplicates if requested
1162  if ( !$dupes && is_array( $value ) ) {
1163  $value = array_unique( $value );
1164  }
1165 
1166  // Set a warning if a deprecated parameter has been passed
1167  if ( $deprecated && $value !== false ) {
1168  $this->setWarning( "The $encParamName parameter has been deprecated." );
1169  }
1170  } elseif ( $required ) {
1171  $this->dieUsageMsg( array( 'missingparam', $paramName ) );
1172  }
1173 
1174  return $value;
1175  }
1176 
1190  protected function parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues ) {
1191  if ( trim( $value ) === '' && $allowMultiple ) {
1192  return array();
1193  }
1194 
1195  // This is a bit awkward, but we want to avoid calling canApiHighLimits()
1196  // because it unstubs $wgUser
1197  $valuesList = explode( '|', $value, self::LIMIT_SML2 + 1 );
1198  $sizeLimit = count( $valuesList ) > self::LIMIT_SML1 && $this->mMainModule->canApiHighLimits()
1200  : self::LIMIT_SML1;
1201 
1202  if ( self::truncateArray( $valuesList, $sizeLimit ) ) {
1203  $this->setWarning( "Too many values supplied for parameter '$valueName': " .
1204  "the limit is $sizeLimit" );
1205  }
1206 
1207  if ( !$allowMultiple && count( $valuesList ) != 1 ) {
1208  // Bug 33482 - Allow entries with | in them for non-multiple values
1209  if ( in_array( $value, $allowedValues, true ) ) {
1210  return $value;
1211  }
1212 
1213  $possibleValues = is_array( $allowedValues )
1214  ? "of '" . implode( "', '", $allowedValues ) . "'"
1215  : '';
1216  $this->dieUsage(
1217  "Only one $possibleValues is allowed for parameter '$valueName'",
1218  "multival_$valueName"
1219  );
1220  }
1221 
1222  if ( is_array( $allowedValues ) ) {
1223  // Check for unknown values
1224  $unknown = array_diff( $valuesList, $allowedValues );
1225  if ( count( $unknown ) ) {
1226  if ( $allowMultiple ) {
1227  $s = count( $unknown ) > 1 ? 's' : '';
1228  $vals = implode( ", ", $unknown );
1229  $this->setWarning( "Unrecognized value$s for parameter '$valueName': $vals" );
1230  } else {
1231  $this->dieUsage(
1232  "Unrecognized value for parameter '$valueName': {$valuesList[0]}",
1233  "unknown_$valueName"
1234  );
1235  }
1236  }
1237  // Now throw them out
1238  $valuesList = array_intersect( $valuesList, $allowedValues );
1239  }
1240 
1241  return $allowMultiple ? $valuesList : $valuesList[0];
1242  }
1243 
1254  function validateLimit( $paramName, &$value, $min, $max, $botMax = null, $enforceLimits = false ) {
1255  if ( !is_null( $min ) && $value < $min ) {
1256 
1257  $msg = $this->encodeParamName( $paramName ) . " may not be less than $min (set to $value)";
1258  $this->warnOrDie( $msg, $enforceLimits );
1259  $value = $min;
1260  }
1261 
1262  // Minimum is always validated, whereas maximum is checked only if not
1263  // running in internal call mode
1264  if ( $this->getMain()->isInternalMode() ) {
1265  return;
1266  }
1267 
1268  // Optimization: do not check user's bot status unless really needed -- skips db query
1269  // assumes $botMax >= $max
1270  if ( !is_null( $max ) && $value > $max ) {
1271  if ( !is_null( $botMax ) && $this->getMain()->canApiHighLimits() ) {
1272  if ( $value > $botMax ) {
1273  $msg = $this->encodeParamName( $paramName ) .
1274  " may not be over $botMax (set to $value) for bots or sysops";
1275  $this->warnOrDie( $msg, $enforceLimits );
1276  $value = $botMax;
1277  }
1278  } else {
1279  $msg = $this->encodeParamName( $paramName ) . " may not be over $max (set to $value) for users";
1280  $this->warnOrDie( $msg, $enforceLimits );
1281  $value = $max;
1282  }
1283  }
1284  }
1285 
1292  function validateTimestamp( $value, $encParamName ) {
1293  $unixTimestamp = wfTimestamp( TS_UNIX, $value );
1294  if ( $unixTimestamp === false ) {
1295  $this->dieUsage(
1296  "Invalid value '$value' for timestamp parameter $encParamName",
1297  "badtimestamp_{$encParamName}"
1298  );
1299  }
1300 
1301  return wfTimestamp( TS_MW, $unixTimestamp );
1302  }
1303 
1310  private function validateUser( $value, $encParamName ) {
1312  if ( $title === null ) {
1313  $this->dieUsage(
1314  "Invalid value '$value' for user parameter $encParamName",
1315  "baduser_{$encParamName}"
1316  );
1317  }
1318 
1319  return $title->getText();
1320  }
1321 
1328  private function warnOrDie( $msg, $enforceLimits = false ) {
1329  if ( $enforceLimits ) {
1330  $this->dieUsage( $msg, 'integeroutofrange' );
1331  }
1332 
1333  $this->setWarning( $msg );
1334  }
1335 
1342  public static function truncateArray( &$arr, $limit ) {
1343  $modified = false;
1344  while ( count( $arr ) > $limit ) {
1345  array_pop( $arr );
1346  $modified = true;
1347  }
1348 
1349  return $modified;
1350  }
1351 
1364  public function dieUsage( $description, $errorCode, $httpRespCode = 0, $extradata = null ) {
1365  Profiler::instance()->close();
1366  throw new UsageException(
1367  $description,
1368  $this->encodeParamName( $errorCode ),
1369  $httpRespCode,
1370  $extradata
1371  );
1372  }
1373 
1381  public function getErrorFromStatus( $status ) {
1382  if ( $status->isGood() ) {
1383  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
1384  }
1385 
1386  $errors = $status->getErrorsArray();
1387  if ( !$errors ) {
1388  // No errors? Assume the warnings should be treated as errors
1389  $errors = $status->getWarningsArray();
1390  }
1391  if ( !$errors ) {
1392  // Still no errors? Punt
1393  $errors = array( array( 'unknownerror-nocode' ) );
1394  }
1395 
1396  // Cannot use dieUsageMsg() because extensions might return custom
1397  // error messages.
1398  if ( $errors[0] instanceof Message ) {
1399  $msg = $errors[0];
1400  $code = $msg->getKey();
1401  } else {
1402  $code = array_shift( $errors[0] );
1403  $msg = wfMessage( $code, $errors[0] );
1404  }
1405  if ( isset( ApiBase::$messageMap[$code] ) ) {
1406  // Translate message to code, for backwards compatability
1407  $code = ApiBase::$messageMap[$code]['code'];
1408  }
1409 
1410  return array( $code, $msg->inLanguage( 'en' )->useDatabase( false )->plain() );
1411  }
1412 
1420  public function dieStatus( $status ) {
1421 
1422  list( $code, $msg ) = $this->getErrorFromStatus( $status );
1423  $this->dieUsage( $msg, $code );
1424  }
1425 
1426  // @codingStandardsIgnoreStart Allow long lines. Cannot split these.
1430  public static $messageMap = array(
1431  // This one MUST be present, or dieUsageMsg() will recurse infinitely
1432  'unknownerror' => array( 'code' => 'unknownerror', 'info' => "Unknown error: \"\$1\"" ),
1433  'unknownerror-nocode' => array( 'code' => 'unknownerror', 'info' => 'Unknown error' ),
1434 
1435  // Messages from Title::getUserPermissionsErrors()
1436  'ns-specialprotected' => array(
1437  'code' => 'unsupportednamespace',
1438  'info' => "Pages in the Special namespace can't be edited"
1439  ),
1440  'protectedinterface' => array(
1441  'code' => 'protectednamespace-interface',
1442  'info' => "You're not allowed to edit interface messages"
1443  ),
1444  'namespaceprotected' => array(
1445  'code' => 'protectednamespace',
1446  'info' => "You're not allowed to edit pages in the \"\$1\" namespace"
1447  ),
1448  'customcssprotected' => array(
1449  'code' => 'customcssprotected',
1450  'info' => "You're not allowed to edit custom CSS pages"
1451  ),
1452  'customjsprotected' => array(
1453  'code' => 'customjsprotected',
1454  'info' => "You're not allowed to edit custom JavaScript pages"
1455  ),
1456  'cascadeprotected' => array(
1457  'code' => 'cascadeprotected',
1458  'info' => "The page you're trying to edit is protected because it's included in a cascade-protected page"
1459  ),
1460  'protectedpagetext' => array(
1461  'code' => 'protectedpage',
1462  'info' => "The \"\$1\" right is required to edit this page"
1463  ),
1464  'protect-cantedit' => array(
1465  'code' => 'cantedit',
1466  'info' => "You can't protect this page because you can't edit it"
1467  ),
1468  'badaccess-group0' => array(
1469  'code' => 'permissiondenied',
1470  'info' => "Permission denied"
1471  ), // Generic permission denied message
1472  'badaccess-groups' => array(
1473  'code' => 'permissiondenied',
1474  'info' => "Permission denied"
1475  ),
1476  'titleprotected' => array(
1477  'code' => 'protectedtitle',
1478  'info' => "This title has been protected from creation"
1479  ),
1480  'nocreate-loggedin' => array(
1481  'code' => 'cantcreate',
1482  'info' => "You don't have permission to create new pages"
1483  ),
1484  'nocreatetext' => array(
1485  'code' => 'cantcreate-anon',
1486  'info' => "Anonymous users can't create new pages"
1487  ),
1488  'movenologintext' => array(
1489  'code' => 'cantmove-anon',
1490  'info' => "Anonymous users can't move pages"
1491  ),
1492  'movenotallowed' => array(
1493  'code' => 'cantmove',
1494  'info' => "You don't have permission to move pages"
1495  ),
1496  'confirmedittext' => array(
1497  'code' => 'confirmemail',
1498  'info' => "You must confirm your email address before you can edit"
1499  ),
1500  'blockedtext' => array(
1501  'code' => 'blocked',
1502  'info' => "You have been blocked from editing"
1503  ),
1504  'autoblockedtext' => array(
1505  'code' => 'autoblocked',
1506  'info' => "Your IP address has been blocked automatically, because it was used by a blocked user"
1507  ),
1508 
1509  // Miscellaneous interface messages
1510  'actionthrottledtext' => array(
1511  'code' => 'ratelimited',
1512  'info' => "You've exceeded your rate limit. Please wait some time and try again"
1513  ),
1514  'alreadyrolled' => array(
1515  'code' => 'alreadyrolled',
1516  'info' => "The page you tried to rollback was already rolled back"
1517  ),
1518  'cantrollback' => array(
1519  'code' => 'onlyauthor',
1520  'info' => "The page you tried to rollback only has one author"
1521  ),
1522  'readonlytext' => array(
1523  'code' => 'readonly',
1524  'info' => "The wiki is currently in read-only mode"
1525  ),
1526  'sessionfailure' => array(
1527  'code' => 'badtoken',
1528  'info' => "Invalid token" ),
1529  'cannotdelete' => array(
1530  'code' => 'cantdelete',
1531  'info' => "Couldn't delete \"\$1\". Maybe it was deleted already by someone else"
1532  ),
1533  'notanarticle' => array(
1534  'code' => 'missingtitle',
1535  'info' => "The page you requested doesn't exist"
1536  ),
1537  'selfmove' => array( 'code' => 'selfmove', 'info' => "Can't move a page to itself"
1538  ),
1539  'immobile_namespace' => array(
1540  'code' => 'immobilenamespace',
1541  'info' => "You tried to move pages from or to a namespace that is protected from moving"
1542  ),
1543  'articleexists' => array(
1544  'code' => 'articleexists',
1545  'info' => "The destination article already exists and is not a redirect to the source article"
1546  ),
1547  'protectedpage' => array(
1548  'code' => 'protectedpage',
1549  'info' => "You don't have permission to perform this move"
1550  ),
1551  'hookaborted' => array(
1552  'code' => 'hookaborted',
1553  'info' => "The modification you tried to make was aborted by an extension hook"
1554  ),
1555  'cantmove-titleprotected' => array(
1556  'code' => 'protectedtitle',
1557  'info' => "The destination article has been protected from creation"
1558  ),
1559  'imagenocrossnamespace' => array(
1560  'code' => 'nonfilenamespace',
1561  'info' => "Can't move a file to a non-file namespace"
1562  ),
1563  'imagetypemismatch' => array(
1564  'code' => 'filetypemismatch',
1565  'info' => "The new file extension doesn't match its type"
1566  ),
1567  // 'badarticleerror' => shouldn't happen
1568  // 'badtitletext' => shouldn't happen
1569  'ip_range_invalid' => array( 'code' => 'invalidrange', 'info' => "Invalid IP range" ),
1570  'range_block_disabled' => array(
1571  'code' => 'rangedisabled',
1572  'info' => "Blocking IP ranges has been disabled"
1573  ),
1574  'nosuchusershort' => array(
1575  'code' => 'nosuchuser',
1576  'info' => "The user you specified doesn't exist"
1577  ),
1578  'badipaddress' => array( 'code' => 'invalidip', 'info' => "Invalid IP address specified" ),
1579  'ipb_expiry_invalid' => array( 'code' => 'invalidexpiry', 'info' => "Invalid expiry time" ),
1580  'ipb_already_blocked' => array(
1581  'code' => 'alreadyblocked',
1582  'info' => "The user you tried to block was already blocked"
1583  ),
1584  'ipb_blocked_as_range' => array(
1585  'code' => 'blockedasrange',
1586  'info' => "IP address \"\$1\" was blocked as part of range \"\$2\". You can't unblock the IP individually, but you can unblock the range as a whole."
1587  ),
1588  'ipb_cant_unblock' => array(
1589  'code' => 'cantunblock',
1590  'info' => "The block you specified was not found. It may have been unblocked already"
1591  ),
1592  'mailnologin' => array(
1593  'code' => 'cantsend',
1594  'info' => "You are not logged in, you do not have a confirmed email address, or you are not allowed to send email to other users, so you cannot send email"
1595  ),
1596  'ipbblocked' => array(
1597  'code' => 'ipbblocked',
1598  'info' => 'You cannot block or unblock users while you are yourself blocked'
1599  ),
1600  'ipbnounblockself' => array(
1601  'code' => 'ipbnounblockself',
1602  'info' => 'You are not allowed to unblock yourself'
1603  ),
1604  'usermaildisabled' => array(
1605  'code' => 'usermaildisabled',
1606  'info' => "User email has been disabled"
1607  ),
1608  'blockedemailuser' => array(
1609  'code' => 'blockedfrommail',
1610  'info' => "You have been blocked from sending email"
1611  ),
1612  'notarget' => array(
1613  'code' => 'notarget',
1614  'info' => "You have not specified a valid target for this action"
1615  ),
1616  'noemail' => array(
1617  'code' => 'noemail',
1618  'info' => "The user has not specified a valid email address, or has chosen not to receive email from other users"
1619  ),
1620  'rcpatroldisabled' => array(
1621  'code' => 'patroldisabled',
1622  'info' => "Patrolling is disabled on this wiki"
1623  ),
1624  'markedaspatrollederror-noautopatrol' => array(
1625  'code' => 'noautopatrol',
1626  'info' => "You don't have permission to patrol your own changes"
1627  ),
1628  'delete-toobig' => array(
1629  'code' => 'bigdelete',
1630  'info' => "You can't delete this page because it has more than \$1 revisions"
1631  ),
1632  'movenotallowedfile' => array(
1633  'code' => 'cantmovefile',
1634  'info' => "You don't have permission to move files"
1635  ),
1636  'userrights-no-interwiki' => array(
1637  'code' => 'nointerwikiuserrights',
1638  'info' => "You don't have permission to change user rights on other wikis"
1639  ),
1640  'userrights-nodatabase' => array(
1641  'code' => 'nosuchdatabase',
1642  'info' => "Database \"\$1\" does not exist or is not local"
1643  ),
1644  'nouserspecified' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ),
1645  'noname' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ),
1646  'summaryrequired' => array( 'code' => 'summaryrequired', 'info' => 'Summary required' ),
1647  'import-rootpage-invalid' => array(
1648  'code' => 'import-rootpage-invalid',
1649  'info' => 'Root page is an invalid title'
1650  ),
1651  'import-rootpage-nosubpage' => array(
1652  'code' => 'import-rootpage-nosubpage',
1653  'info' => 'Namespace "$1" of the root page does not allow subpages'
1654  ),
1655 
1656  // API-specific messages
1657  'readrequired' => array(
1658  'code' => 'readapidenied',
1659  'info' => "You need read permission to use this module"
1660  ),
1661  'writedisabled' => array(
1662  'code' => 'noapiwrite',
1663  'info' => "Editing of this wiki through the API is disabled. Make sure the \$wgEnableWriteAPI=true; statement is included in the wiki's LocalSettings.php file"
1664  ),
1665  'writerequired' => array(
1666  'code' => 'writeapidenied',
1667  'info' => "You're not allowed to edit this wiki through the API"
1668  ),
1669  'missingparam' => array( 'code' => 'no$1', 'info' => "The \$1 parameter must be set" ),
1670  'invalidtitle' => array( 'code' => 'invalidtitle', 'info' => "Bad title \"\$1\"" ),
1671  'nosuchpageid' => array( 'code' => 'nosuchpageid', 'info' => "There is no page with ID \$1" ),
1672  'nosuchrevid' => array( 'code' => 'nosuchrevid', 'info' => "There is no revision with ID \$1" ),
1673  'nosuchuser' => array( 'code' => 'nosuchuser', 'info' => "User \"\$1\" doesn't exist" ),
1674  'invaliduser' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ),
1675  'invalidexpiry' => array( 'code' => 'invalidexpiry', 'info' => "Invalid expiry time \"\$1\"" ),
1676  'pastexpiry' => array( 'code' => 'pastexpiry', 'info' => "Expiry time \"\$1\" is in the past" ),
1677  'create-titleexists' => array(
1678  'code' => 'create-titleexists',
1679  'info' => "Existing titles can't be protected with 'create'"
1680  ),
1681  'missingtitle-createonly' => array(
1682  'code' => 'missingtitle-createonly',
1683  'info' => "Missing titles can only be protected with 'create'"
1684  ),
1685  'cantblock' => array( 'code' => 'cantblock',
1686  'info' => "You don't have permission to block users"
1687  ),
1688  'canthide' => array(
1689  'code' => 'canthide',
1690  'info' => "You don't have permission to hide user names from the block log"
1691  ),
1692  'cantblock-email' => array(
1693  'code' => 'cantblock-email',
1694  'info' => "You don't have permission to block users from sending email through the wiki"
1695  ),
1696  'unblock-notarget' => array(
1697  'code' => 'notarget',
1698  'info' => "Either the id or the user parameter must be set"
1699  ),
1700  'unblock-idanduser' => array(
1701  'code' => 'idanduser',
1702  'info' => "The id and user parameters can't be used together"
1703  ),
1704  'cantunblock' => array(
1705  'code' => 'permissiondenied',
1706  'info' => "You don't have permission to unblock users"
1707  ),
1708  'cannotundelete' => array(
1709  'code' => 'cantundelete',
1710  'info' => "Couldn't undelete: the requested revisions may not exist, or may have been undeleted already"
1711  ),
1712  'permdenied-undelete' => array(
1713  'code' => 'permissiondenied',
1714  'info' => "You don't have permission to restore deleted revisions"
1715  ),
1716  'createonly-exists' => array(
1717  'code' => 'articleexists',
1718  'info' => "The article you tried to create has been created already"
1719  ),
1720  'nocreate-missing' => array(
1721  'code' => 'missingtitle',
1722  'info' => "The article you tried to edit doesn't exist"
1723  ),
1724  'cantchangecontentmodel' => array(
1725  'code' => 'cantchangecontentmodel',
1726  'info' => "You don't have permission to change the content model of a page"
1727  ),
1728  'nosuchrcid' => array(
1729  'code' => 'nosuchrcid',
1730  'info' => "There is no change with rcid \"\$1\""
1731  ),
1732  'protect-invalidaction' => array(
1733  'code' => 'protect-invalidaction',
1734  'info' => "Invalid protection type \"\$1\""
1735  ),
1736  'protect-invalidlevel' => array(
1737  'code' => 'protect-invalidlevel',
1738  'info' => "Invalid protection level \"\$1\""
1739  ),
1740  'toofewexpiries' => array(
1741  'code' => 'toofewexpiries',
1742  'info' => "\$1 expiry timestamps were provided where \$2 were needed"
1743  ),
1744  'cantimport' => array(
1745  'code' => 'cantimport',
1746  'info' => "You don't have permission to import pages"
1747  ),
1748  'cantimport-upload' => array(
1749  'code' => 'cantimport-upload',
1750  'info' => "You don't have permission to import uploaded pages"
1751  ),
1752  'importnofile' => array( 'code' => 'nofile', 'info' => "You didn't upload a file" ),
1753  'importuploaderrorsize' => array(
1754  'code' => 'filetoobig',
1755  'info' => 'The file you uploaded is bigger than the maximum upload size'
1756  ),
1757  'importuploaderrorpartial' => array(
1758  'code' => 'partialupload',
1759  'info' => 'The file was only partially uploaded'
1760  ),
1761  'importuploaderrortemp' => array(
1762  'code' => 'notempdir',
1763  'info' => 'The temporary upload directory is missing'
1764  ),
1765  'importcantopen' => array(
1766  'code' => 'cantopenfile',
1767  'info' => "Couldn't open the uploaded file"
1768  ),
1769  'import-noarticle' => array(
1770  'code' => 'badinterwiki',
1771  'info' => 'Invalid interwiki title specified'
1772  ),
1773  'importbadinterwiki' => array(
1774  'code' => 'badinterwiki',
1775  'info' => 'Invalid interwiki title specified'
1776  ),
1777  'import-unknownerror' => array(
1778  'code' => 'import-unknownerror',
1779  'info' => "Unknown error on import: \"\$1\""
1780  ),
1781  'cantoverwrite-sharedfile' => array(
1782  'code' => 'cantoverwrite-sharedfile',
1783  'info' => 'The target file exists on a shared repository and you do not have permission to override it'
1784  ),
1785  'sharedfile-exists' => array(
1786  'code' => 'fileexists-sharedrepo-perm',
1787  'info' => 'The target file exists on a shared repository. Use the ignorewarnings parameter to override it.'
1788  ),
1789  'mustbeposted' => array(
1790  'code' => 'mustbeposted',
1791  'info' => "The \$1 module requires a POST request"
1792  ),
1793  'show' => array(
1794  'code' => 'show',
1795  'info' => 'Incorrect parameter - mutually exclusive values may not be supplied'
1796  ),
1797  'specialpage-cantexecute' => array(
1798  'code' => 'specialpage-cantexecute',
1799  'info' => "You don't have permission to view the results of this special page"
1800  ),
1801  'invalidoldimage' => array(
1802  'code' => 'invalidoldimage',
1803  'info' => 'The oldimage parameter has invalid format'
1804  ),
1805  'nodeleteablefile' => array(
1806  'code' => 'nodeleteablefile',
1807  'info' => 'No such old version of the file'
1808  ),
1809  'fileexists-forbidden' => array(
1810  'code' => 'fileexists-forbidden',
1811  'info' => 'A file with name "$1" already exists, and cannot be overwritten.'
1812  ),
1813  'fileexists-shared-forbidden' => array(
1814  'code' => 'fileexists-shared-forbidden',
1815  'info' => 'A file with name "$1" already exists in the shared file repository, and cannot be overwritten.'
1816  ),
1817  'filerevert-badversion' => array(
1818  'code' => 'filerevert-badversion',
1819  'info' => 'There is no previous local version of this file with the provided timestamp.'
1820  ),
1821 
1822  // ApiEditPage messages
1823  'noimageredirect-anon' => array(
1824  'code' => 'noimageredirect-anon',
1825  'info' => "Anonymous users can't create image redirects"
1826  ),
1827  'noimageredirect-logged' => array(
1828  'code' => 'noimageredirect',
1829  'info' => "You don't have permission to create image redirects"
1830  ),
1831  'spamdetected' => array(
1832  'code' => 'spamdetected',
1833  'info' => "Your edit was refused because it contained a spam fragment: \"\$1\""
1834  ),
1835  'contenttoobig' => array(
1836  'code' => 'contenttoobig',
1837  'info' => "The content you supplied exceeds the article size limit of \$1 kilobytes"
1838  ),
1839  'noedit-anon' => array( 'code' => 'noedit-anon', 'info' => "Anonymous users can't edit pages" ),
1840  'noedit' => array( 'code' => 'noedit', 'info' => "You don't have permission to edit pages" ),
1841  'wasdeleted' => array(
1842  'code' => 'pagedeleted',
1843  'info' => "The page has been deleted since you fetched its timestamp"
1844  ),
1845  'blankpage' => array(
1846  'code' => 'emptypage',
1847  'info' => "Creating new, empty pages is not allowed"
1848  ),
1849  'editconflict' => array( 'code' => 'editconflict', 'info' => "Edit conflict detected" ),
1850  'hashcheckfailed' => array( 'code' => 'badmd5', 'info' => "The supplied MD5 hash was incorrect" ),
1851  'missingtext' => array(
1852  'code' => 'notext',
1853  'info' => "One of the text, appendtext, prependtext and undo parameters must be set"
1854  ),
1855  'emptynewsection' => array(
1856  'code' => 'emptynewsection',
1857  'info' => 'Creating empty new sections is not possible.'
1858  ),
1859  'revwrongpage' => array(
1860  'code' => 'revwrongpage',
1861  'info' => "r\$1 is not a revision of \"\$2\""
1862  ),
1863  'undo-failure' => array(
1864  'code' => 'undofailure',
1865  'info' => 'Undo failed due to conflicting intermediate edits'
1866  ),
1867 
1868  // Messages from WikiPage::doEit()
1869  'edit-hook-aborted' => array(
1870  'code' => 'edit-hook-aborted',
1871  'info' => "Your edit was aborted by an ArticleSave hook"
1872  ),
1873  'edit-gone-missing' => array(
1874  'code' => 'edit-gone-missing',
1875  'info' => "The page you tried to edit doesn't seem to exist anymore"
1876  ),
1877  'edit-conflict' => array( 'code' => 'editconflict', 'info' => "Edit conflict detected" ),
1878  'edit-already-exists' => array(
1879  'code' => 'edit-already-exists',
1880  'info' => 'It seems the page you tried to create already exist'
1881  ),
1882 
1883  // uploadMsgs
1884  'invalid-file-key' => array( 'code' => 'invalid-file-key', 'info' => 'Not a valid file key' ),
1885  'nouploadmodule' => array( 'code' => 'nouploadmodule', 'info' => 'No upload module set' ),
1886  'uploaddisabled' => array(
1887  'code' => 'uploaddisabled',
1888  'info' => 'Uploads are not enabled. Make sure $wgEnableUploads is set to true in LocalSettings.php and the PHP ini setting file_uploads is true'
1889  ),
1890  'copyuploaddisabled' => array(
1891  'code' => 'copyuploaddisabled',
1892  'info' => 'Uploads by URL is not enabled. Make sure $wgAllowCopyUploads is set to true in LocalSettings.php.'
1893  ),
1894  'copyuploadbaddomain' => array(
1895  'code' => 'copyuploadbaddomain',
1896  'info' => 'Uploads by URL are not allowed from this domain.'
1897  ),
1898  'copyuploadbadurl' => array(
1899  'code' => 'copyuploadbadurl',
1900  'info' => 'Upload not allowed from this URL.'
1901  ),
1902 
1903  'filename-tooshort' => array(
1904  'code' => 'filename-tooshort',
1905  'info' => 'The filename is too short'
1906  ),
1907  'filename-toolong' => array( 'code' => 'filename-toolong', 'info' => 'The filename is too long' ),
1908  'illegal-filename' => array(
1909  'code' => 'illegal-filename',
1910  'info' => 'The filename is not allowed'
1911  ),
1912  'filetype-missing' => array(
1913  'code' => 'filetype-missing',
1914  'info' => 'The file is missing an extension'
1915  ),
1916 
1917  'mustbeloggedin' => array( 'code' => 'mustbeloggedin', 'info' => 'You must be logged in to $1.' )
1918  );
1919  // @codingStandardsIgnoreEnd
1920 
1924  public function dieReadOnly() {
1925  $parsed = $this->parseMsg( array( 'readonlytext' ) );
1926  $this->dieUsage( $parsed['info'], $parsed['code'], /* http error */ 0,
1927  array( 'readonlyreason' => wfReadOnlyReason() ) );
1928  }
1929 
1934  public function dieUsageMsg( $error ) {
1935  # most of the time we send a 1 element, so we might as well send it as
1936  # a string and make this an array here.
1937  if ( is_string( $error ) ) {
1938  $error = array( $error );
1939  }
1940  $parsed = $this->parseMsg( $error );
1941  $this->dieUsage( $parsed['info'], $parsed['code'] );
1942  }
1943 
1950  public function dieUsageMsgOrDebug( $error ) {
1951  global $wgDebugAPI;
1952  if ( $wgDebugAPI !== true ) {
1953  $this->dieUsageMsg( $error );
1954  }
1955 
1956  if ( is_string( $error ) ) {
1957  $error = array( $error );
1958  }
1959 
1960  $parsed = $this->parseMsg( $error );
1961  $this->setWarning( '$wgDebugAPI: ' . $parsed['code'] . ' - ' . $parsed['info'] );
1962  }
1963 
1970  protected function dieContinueUsageIf( $condition ) {
1971  if ( $condition ) {
1972  $this->dieUsage(
1973  'Invalid continue param. You should pass the original value returned by the previous query',
1974  'badcontinue' );
1975  }
1976  }
1977 
1983  public function parseMsg( $error ) {
1984  $error = (array)$error; // It seems strings sometimes make their way in here
1985  $key = array_shift( $error );
1986 
1987  // Check whether the error array was nested
1988  // array( array( <code>, <params> ), array( <another_code>, <params> ) )
1989  if ( is_array( $key ) ) {
1990  $error = $key;
1991  $key = array_shift( $error );
1992  }
1993 
1994  if ( isset( self::$messageMap[$key] ) ) {
1995  return array(
1996  'code' => wfMsgReplaceArgs( self::$messageMap[$key]['code'], $error ),
1997  'info' => wfMsgReplaceArgs( self::$messageMap[$key]['info'], $error )
1998  );
1999  }
2000 
2001  // If the key isn't present, throw an "unknown error"
2002  return $this->parseMsg( array( 'unknownerror', $key ) );
2003  }
2004 
2011  protected static function dieDebug( $method, $message ) {
2012  throw new MWException( "Internal error in $method: $message" );
2013  }
2014 
2019  public function shouldCheckMaxlag() {
2020  return true;
2021  }
2022 
2027  public function isReadMode() {
2028  return true;
2029  }
2030 
2035  public function isWriteMode() {
2036  return false;
2037  }
2038 
2043  public function mustBePosted() {
2044  return false;
2045  }
2046 
2053  public function needsToken() {
2054  return false;
2055  }
2056 
2065  public function getTokenSalt() {
2066  return false;
2067  }
2068 
2075  public function getWatchlistUser( $params ) {
2076  if ( !is_null( $params['owner'] ) && !is_null( $params['token'] ) ) {
2077  $user = User::newFromName( $params['owner'], false );
2078  if ( !( $user && $user->getId() ) ) {
2079  $this->dieUsage( 'Specified user does not exist', 'bad_wlowner' );
2080  }
2081  $token = $user->getOption( 'watchlisttoken' );
2082  if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
2083  $this->dieUsage(
2084  'Incorrect watchlist token provided -- please set a correct token in Special:Preferences',
2085  'bad_wltoken'
2086  );
2087  }
2088  } else {
2089  if ( !$this->getUser()->isLoggedIn() ) {
2090  $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
2091  }
2092  if ( !$this->getUser()->isAllowed( 'viewmywatchlist' ) ) {
2093  $this->dieUsage( 'You don\'t have permission to view your watchlist', 'permissiondenied' );
2094  }
2095  $user = $this->getUser();
2096  }
2097 
2098  return $user;
2099  }
2100 
2105  public function getHelpUrls() {
2106  return false;
2107  }
2108 
2118  public function getPossibleErrors() {
2119  $ret = array();
2120 
2121  $params = $this->getFinalParams();
2122  if ( $params ) {
2123  foreach ( $params as $paramName => $paramSettings ) {
2124  if ( isset( $paramSettings[ApiBase::PARAM_REQUIRED] )
2125  && $paramSettings[ApiBase::PARAM_REQUIRED]
2126  ) {
2127  $ret[] = array( 'missingparam', $paramName );
2128  }
2129  }
2130  if ( array_key_exists( 'continue', $params ) ) {
2131  $ret[] = array(
2132  'code' => 'badcontinue',
2133  'info' => 'Invalid continue param. You should pass the ' .
2134  'original value returned by the previous query'
2135  );
2136  }
2137  }
2138 
2139  if ( $this->mustBePosted() ) {
2140  $ret[] = array( 'mustbeposted', $this->getModuleName() );
2141  }
2142 
2143  if ( $this->isReadMode() ) {
2144  $ret[] = array( 'readrequired' );
2145  }
2146 
2147  if ( $this->isWriteMode() ) {
2148  $ret[] = array( 'writerequired' );
2149  $ret[] = array( 'writedisabled' );
2150  }
2151 
2152  if ( $this->needsToken() ) {
2153  if ( !isset( $params['token'][ApiBase::PARAM_REQUIRED] )
2154  || !$params['token'][ApiBase::PARAM_REQUIRED]
2155  ) {
2156  // Add token as possible missing parameter, if not already done
2157  $ret[] = array( 'missingparam', 'token' );
2158  }
2159  $ret[] = array( 'sessionfailure' );
2160  }
2161 
2162  return $ret;
2163  }
2164 
2172  public function getFinalPossibleErrors() {
2173  $possibleErrors = $this->getPossibleErrors();
2174  wfRunHooks( 'APIGetPossibleErrors', array( $this, &$possibleErrors ) );
2175 
2176  return $possibleErrors;
2177  }
2178 
2185  public function parseErrors( $errors ) {
2186  $ret = array();
2187 
2188  foreach ( $errors as $row ) {
2189  if ( isset( $row['code'] ) && isset( $row['info'] ) ) {
2190  $ret[] = $row;
2191  } else {
2192  $ret[] = $this->parseMsg( $row );
2193  }
2194  }
2195 
2196  return $ret;
2197  }
2198 
2202  private $mTimeIn = 0, $mModuleTime = 0;
2203 
2207  public function profileIn() {
2208  if ( $this->mTimeIn !== 0 ) {
2209  ApiBase::dieDebug( __METHOD__, 'Called twice without calling profileOut()' );
2210  }
2211  $this->mTimeIn = microtime( true );
2212  wfProfileIn( $this->getModuleProfileName() );
2213  }
2214 
2218  public function profileOut() {
2219  if ( $this->mTimeIn === 0 ) {
2220  ApiBase::dieDebug( __METHOD__, 'Called without calling profileIn() first' );
2221  }
2222  if ( $this->mDBTimeIn !== 0 ) {
2224  __METHOD__,
2225  'Must be called after database profiling is done with profileDBOut()'
2226  );
2227  }
2228 
2229  $this->mModuleTime += microtime( true ) - $this->mTimeIn;
2230  $this->mTimeIn = 0;
2231  wfProfileOut( $this->getModuleProfileName() );
2232  }
2233 
2238  public function safeProfileOut() {
2239  if ( $this->mTimeIn !== 0 ) {
2240  if ( $this->mDBTimeIn !== 0 ) {
2241  $this->profileDBOut();
2242  }
2243  $this->profileOut();
2244  }
2245  }
2246 
2251  public function getProfileTime() {
2252  if ( $this->mTimeIn !== 0 ) {
2253  ApiBase::dieDebug( __METHOD__, 'Called without calling profileOut() first' );
2254  }
2255 
2256  return $this->mModuleTime;
2257  }
2258 
2262  private $mDBTimeIn = 0, $mDBTime = 0;
2263 
2267  public function profileDBIn() {
2268  if ( $this->mTimeIn === 0 ) {
2270  __METHOD__,
2271  'Must be called while profiling the entire module with profileIn()'
2272  );
2273  }
2274  if ( $this->mDBTimeIn !== 0 ) {
2275  ApiBase::dieDebug( __METHOD__, 'Called twice without calling profileDBOut()' );
2276  }
2277  $this->mDBTimeIn = microtime( true );
2278  wfProfileIn( $this->getModuleProfileName( true ) );
2279  }
2280 
2284  public function profileDBOut() {
2285  if ( $this->mTimeIn === 0 ) {
2286  ApiBase::dieDebug( __METHOD__, 'Must be called while profiling ' .
2287  'the entire module with profileIn()' );
2288  }
2289  if ( $this->mDBTimeIn === 0 ) {
2290  ApiBase::dieDebug( __METHOD__, 'Called without calling profileDBIn() first' );
2291  }
2292 
2293  $time = microtime( true ) - $this->mDBTimeIn;
2294  $this->mDBTimeIn = 0;
2295 
2296  $this->mDBTime += $time;
2297  $this->getMain()->mDBTime += $time;
2298  wfProfileOut( $this->getModuleProfileName( true ) );
2299  }
2300 
2305  public function getProfileDBTime() {
2306  if ( $this->mDBTimeIn !== 0 ) {
2307  ApiBase::dieDebug( __METHOD__, 'Called without calling profileDBOut() first' );
2308  }
2309 
2310  return $this->mDBTime;
2311  }
2312 
2317  protected function getDB() {
2318  if ( !isset( $this->mSlaveDB ) ) {
2319  $this->profileDBIn();
2320  $this->mSlaveDB = wfGetDB( DB_SLAVE, 'api' );
2321  $this->profileDBOut();
2322  }
2323 
2324  return $this->mSlaveDB;
2325  }
2326 
2333  public static function debugPrint( $value, $name = 'unknown', $backtrace = false ) {
2334  print "\n\n<pre><b>Debugging value '$name':</b>\n\n";
2335  var_export( $value );
2336  if ( $backtrace ) {
2337  print "\n" . wfBacktrace();
2338  }
2339  print "\n</pre>\n";
2340  }
2341 }
ApiBase\createContext
createContext()
Create a new RequestContext object to use e.g.
Definition: ApiBase.php:232
ApiBase\dieUsageMsgOrDebug
dieUsageMsgOrDebug( $error)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
Definition: ApiBase.php:1949
ApiBase\makeHelpMsgParameters
makeHelpMsgParameters()
Generates the parameter descriptions for this module, to be displayed in the module's help.
Definition: ApiBase.php:391
ApiBase\dieStatus
dieStatus( $status)
Throw a UsageException based on the errors in the Status object.
Definition: ApiBase.php:1419
ApiBase\$mDBTimeIn
$mDBTimeIn
Profiling: database execution time.
Definition: ApiBase.php:2261
ApiBase\__construct
__construct( $mainModule, $moduleName, $modulePrefix='')
Constructor.
Definition: ApiBase.php:100
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:189
ContextSource\getContext
getContext()
Get the RequestContext object.
Definition: ContextSource.php:40
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
MWNamespace\getValidNamespaces
static getValidNamespaces()
Returns an array of the namespaces (by integer id) that exist on the wiki.
Definition: Namespace.php:273
ApiBase\getFinalParams
getFinalParams( $flags=0)
Get final list of parameters, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:589
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
Definition: ApiBase.php:62
Profiler\instance
static instance()
Singleton.
Definition: Profiler.php:127
ApiBase\getTokenSalt
getTokenSalt()
Returns the token salt if there is one, '' if the module doesn't require a salt, else false if the mo...
Definition: ApiBase.php:2064
ApiBase\$mModuleTime
$mModuleTime
Definition: ApiBase.php:2201
ApiBase\parseMsg
parseMsg( $error)
Return the error message related to a certain array.
Definition: ApiBase.php:1982
ApiBase\parameterNotEmpty
parameterNotEmpty( $x)
Callback function used in requireOnlyOneParameter to check whether required parameters are set.
Definition: ApiBase.php:901
ApiResult\setContent
static setContent(&$arr, $value, $subElemName=null)
Adds a content element to an array.
Definition: ApiResult.php:201
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3706
ApiBase\getProfileDBTime
getProfileDBTime()
Total time the module used the database.
Definition: ApiBase.php:2304
ApiBase\validateTimestamp
validateTimestamp( $value, $encParamName)
Validate and normalize of parameters of type 'timestamp'.
Definition: ApiBase.php:1291
ApiBase\dieUsageMsg
dieUsageMsg( $error)
Output the error message related to a certain array.
Definition: ApiBase.php:1933
ApiBase\indentExampleText
indentExampleText( $item)
Definition: ApiBase.php:354
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:2530
ApiBase\$mModulePrefix
$mModulePrefix
Definition: ApiBase.php:90
ApiBase\profileDBIn
profileDBIn()
Start module profiling.
Definition: ApiBase.php:2266
ApiBase\getTitleOrPageId
getTitleOrPageId( $params, $load=false)
Definition: ApiBase.php:853
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:50
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:205
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1530
ApiBase\profileDBOut
profileDBOut()
End database profiling.
Definition: ApiBase.php:2283
ApiBase\mustBePosted
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiBase.php:2042
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1358
ApiBase\shouldCheckMaxlag
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition: ApiBase.php:2018
$params
$params
Definition: styleTest.css.php:40
$limit
if( $sleep) $limit
Definition: importImages.php:99
wfMsgReplaceArgs
wfMsgReplaceArgs( $message, $args)
Replace message parameter keys on the given formatted output.
Definition: GlobalFunctions.php:1637
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:389
$s
$s
Definition: mergeMessageFileList.php:156
ApiBase\getDB
getDB()
Gets a default slave database connection object.
Definition: ApiBase.php:2316
ApiBase\$mSlaveDB
$mSlaveDB
Definition: ApiBase.php:91
ApiBase\makeHelpArrayToString
makeHelpArrayToString( $prefix, $title, $input)
Definition: ApiBase.php:364
ApiBase\PARAM_ALLOW_DUPLICATES
const PARAM_ALLOW_DUPLICATES
Definition: ApiBase.php:58
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2118
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:132
ApiBase\getModuleProfileName
getModuleProfileName( $db=false)
Get the name of the module as shown in the profiler log.
Definition: ApiBase.php:176
ApiBase\$mModuleName
$mModuleName
Definition: ApiBase.php:90
ApiBase\isMain
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition: ApiBase.php:197
ApiBase\isReadMode
isReadMode()
Indicates whether this module requires read rights.
Definition: ApiBase.php:2026
ApiBase\$mDBTime
$mDBTime
Definition: ApiBase.php:2261
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:42
ApiBase\getFinalParamDescription
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:602
ApiBase\$mTimeIn
$mTimeIn
Profiling: total module execution time.
Definition: ApiBase.php:2201
ApiBase\$messageMap
static $messageMap
Array that maps message keys to error messages.
Definition: ApiBase.php:1429
ApiBase\getParamDescription
getParamDescription()
Returns an array of parameter descriptions.
Definition: ApiBase.php:577
wfBacktrace
wfBacktrace()
Get a debug backtrace as a string.
Definition: GlobalFunctions.php:1933
ApiBase\profileOut
profileOut()
End module profiling.
Definition: ApiBase.php:2217
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
Definition: ApiBase.php:60
ApiBase\PROP_LIST
const PROP_LIST
Definition: ApiBase.php:73
ApiBase\PARAM_MIN
const PARAM_MIN
Definition: ApiBase.php:56
DerivativeContext
An IContextSource implementation which will inherit context from another source but allow individual ...
Definition: DerivativeContext.php:32
MWException
MediaWiki exception.
Definition: MWException.php:26
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:103
ApiBase\getFinalResultProperties
getFinalResultProperties()
Get final possible result properties, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:635
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1174
ApiBase\getFinalPossibleErrors
getFinalPossibleErrors()
Get final list of possible errors, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2171
ApiBase\getCustomPrinter
getCustomPrinter()
If the module may only be used with a certain format module, it should override this method to return...
Definition: ApiBase.php:278
ApiBase\$mMainModule
$mMainModule
Definition: ApiBase.php:90
ApiBase\getFinalDescription
getFinalDescription()
Get final module description, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:661
UsageException
This exception will be thrown when dieUsage is called to stop module execution.
Definition: ApiMain.php:1406
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Definition: ApiBase.php:78
ApiBase\getDescription
getDescription()
Returns the description string for this module.
Definition: ApiBase.php:541
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:30
WatchedItem\IGNORE_USER_RIGHTS
const IGNORE_USER_RIGHTS
Constant to specify that user rights 'editmywatchlist' and 'viewmywatchlist' should not be checked.
Definition: WatchedItem.php:35
ApiBase\getVersion
getVersion()
Returns a string that identifies the version of the extending class.
Definition: ApiBase.php:138
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
wfMessage
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
ApiBase\PARAM_MAX
const PARAM_MAX
Definition: ApiBase.php:52
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4058
WatchAction\doWatchOrUnwatch
static doWatchOrUnwatch( $watch, Title $title, User $user)
Watch or unwatch a page.
Definition: WatchAction.php:106
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
ApiBase\parseMultiValue
parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues)
Return an array of values that were given in a 'a|b|c' notation, after it optionally validates them a...
Definition: ApiBase.php:1189
ApiBase\getRequireOnlyOneParameterErrorMessages
getRequireOnlyOneParameterErrorMessages( $params)
Generates the possible errors requireOnlyOneParameter() can die with.
Definition: ApiBase.php:748
ContextSource\setContext
setContext(IContextSource $context)
Set the IContextSource object.
Definition: ContextSource.php:57
ApiBase\requireAtLeastOneParameter
requireAtLeastOneParameter( $params)
Die if none of a certain set of parameters is set and not false.
Definition: ApiBase.php:810
ApiBase\PROP_TYPE
const PROP_TYPE
Definition: ApiBase.php:74
ApiBase\getHelpUrls
getHelpUrls()
Definition: ApiBase.php:2104
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
ApiBase\validateUser
validateUser( $value, $encParamName)
Validate and normalize of parameters of type 'user'.
Definition: ApiBase.php:1309
ApiBase\getWatchlistValue
getWatchlistValue( $watchlist, $titleObj, $userOption=null)
Return true if we're to watch the page, false if not, null if no change.
Definition: ApiBase.php:913
ApiBase\needsToken
needsToken()
Returns whether this module requires a token to execute It is used to show possible errors in action=...
Definition: ApiBase.php:2052
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:165
ApiBase\setWatch
setWatch( $watch, $titleObj, $userOption=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
Definition: ApiBase.php:952
TS_MW
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition: GlobalFunctions.php:2478
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:422
ApiBase\extractRequestParams
extractRequestParams( $parseLimit=true)
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:687
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
ApiBase\getWatchlistUser
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition: ApiBase.php:2074
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
$value
$value
Definition: styleTest.css.php:45
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the $prefix.
Definition: ApiBase.php:1969
ApiBase\LIMIT_SML2
const LIMIT_SML2
Definition: ApiBase.php:81
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:674
ApiBase\dieUsage
dieUsage( $description, $errorCode, $httpRespCode=0, $extradata=null)
Throw a UsageException, which will (if uncaught) call the main module's error handler and die with an...
Definition: ApiBase.php:1363
ApiBase\dieReadOnly
dieReadOnly()
Helper function for readonly errors.
Definition: ApiBase.php:1923
ApiBase\requireOnlyOneParameter
requireOnlyOneParameter( $params)
Die if none or more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:722
ApiBase\GET_VALUES_FOR_HELP
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When set, the result could take longer to generate, but should be more thoro...
Definition: ApiBase.php:88
ApiBase\getResultData
getResultData()
Get the result data array (read-only)
Definition: ApiBase.php:219
ApiBase\addTokenProperties
static addTokenProperties(&$props, $tokenFunctions)
Add token properties to the array used by getResultProperties, based on a token functions mapping.
Definition: ApiBase.php:646
WikiPage\newFromID
static newFromID( $id, $from='fromdb')
Constructor from a page id.
Definition: WikiPage.php:136
ApiBase\getPossibleErrors
getPossibleErrors()
Returns a list of all possible errors returned by the module.
Definition: ApiBase.php:2117
ApiBase\isWriteMode
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiBase.php:2034
ApiBase\PROP_NULLABLE
const PROP_NULLABLE
Definition: ApiBase.php:76
ApiBase\getResultProperties
getResultProperties()
Returns possible properties in the result, grouped by the value of the prop parameter that shows them...
Definition: ApiBase.php:625
ApiBase\$mParamCache
$mParamCache
Definition: ApiBase.php:92
ApiBase\truncateArray
static truncateArray(&$arr, $limit)
Truncate an array to a certain length.
Definition: ApiBase.php:1341
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
ApiBase\profileIn
profileIn()
Start module profiling.
Definition: ApiBase.php:2206
ApiBase\PARAM_RANGE_ENFORCE
const PARAM_RANGE_ENFORCE
Definition: ApiBase.php:66
ApiBase\setWarning
setWarning( $warning)
Set warning section for this module.
Definition: ApiBase.php:245
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
ApiBase\getProfileTime
getProfileTime()
Total time the module was executed.
Definition: ApiBase.php:2250
ApiResult\ADD_ON_TOP
const ADD_ON_TOP
For addValue() and setElement(), if the value does not exist, add it as the first element.
Definition: ApiResult.php:57
ApiBase\getErrorFromStatus
getErrorFromStatus( $status)
Get error (as code, string) from a Status object.
Definition: ApiBase.php:1380
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Definition: ApiBase.php:79
wfReadOnlyReason
wfReadOnlyReason()
Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
Definition: GlobalFunctions.php:1369
ApiBase\getModuleManager
getModuleManager()
Get the module manager, or null if this module has no sub-modules.
Definition: ApiBase.php:157
TS_UNIX
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
Definition: GlobalFunctions.php:2473
ApiBase\validateLimit
validateLimit( $paramName, &$value, $min, $max, $botMax=null, $enforceLimits=false)
Validate the value against the minimum and user/bot maximum limits.
Definition: ApiBase.php:1253
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:46
ApiBase\getParameter
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition: ApiBase.php:711
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
ApiBase\safeProfileOut
safeProfileOut()
When modules crash, sometimes it is needed to do a profileOut() regardless of the profiling state the...
Definition: ApiBase.php:2237
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:148
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:48
ApiBase\warnOrDie
warnOrDie( $msg, $enforceLimits=false)
Adds a warning to the output, else dies.
Definition: ApiBase.php:1327
NS_USER
const NS_USER
Definition: Defines.php:81
ApiResult\OVERRIDE
const OVERRIDE
override existing value in addValue() and setElement()
Definition: ApiResult.php:50
ApiBase\PARAM_MAX2
const PARAM_MAX2
Definition: ApiBase.php:54
ApiBase\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiBase.php:565
ApiBase\debugPrint
static debugPrint( $value, $name='unknown', $backtrace=false)
Debugging function that prints a value and an optional backtrace.
Definition: ApiBase.php:2332
ApiBase\makeHelpMsg
makeHelpMsg()
Generates help message for this module, or false if there is no description.
Definition: ApiBase.php:286
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:188
ApiBase\getParameterFromSettings
getParameterFromSettings( $paramName, $paramSettings, $parseLimit)
Using the settings determine the value for the given parameter.
Definition: ApiBase.php:970
$t
$t
Definition: testCompression.php:65
ApiBase\getExamples
getExamples()
Returns usage examples for this module.
Definition: ApiBase.php:549
$error
usually copyright or history_copyright This message must be in HTML not wikitext $subpages will be ignored and the rest of subPageSubtitle() will run. 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink' whether MediaWiki currently thinks this is a CSS JS page Hooks may change this value to override the return value of Title::isCssOrJsPage(). 'TitleIsAlwaysKnown' whether MediaWiki currently thinks this page is known isMovable() always returns false. $title whether MediaWiki currently thinks this page is movable Hooks may change this value to override the return value of Title::isMovable(). 'TitleIsWikitextPage' whether MediaWiki currently thinks this is a wikitext page Hooks may change this value to override the return value of Title::isWikitextPage() 'TitleMove' use UploadVerification and UploadVerifyFile instead where the first element is the message key and the remaining elements are used as parameters to the message based on mime etc Preferred in most cases over UploadVerification object with all info about the upload string as detected by MediaWiki Handlers will typically only apply for specific mime types object & $error
Definition: hooks.txt:2578
ApiBase\getRequireMaxOneParameterErrorMessages
getRequireMaxOneParameterErrorMessages( $params)
Generates the possible error requireMaxOneParameter() can die with.
Definition: ApiBase.php:791
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:769
ApiBase\parseErrors
parseErrors( $errors)
Parses a list of errors into a standardised format.
Definition: ApiBase.php:2184
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:2010
ApiBase\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
ApiBase\PROP_ROOT
const PROP_ROOT
Definition: ApiBase.php:70
ApiBase\LIMIT_SML1
const LIMIT_SML1
Definition: ApiBase.php:80
ApiBase\getRequireAtLeastOneParameterErrorMessages
getRequireAtLeastOneParameterErrorMessages( $params)
Generates the possible errors requireAtLeastOneParameter() can die with.
Definition: ApiBase.php:833
$type
$type
Definition: testCompression.php:46
ApiBase\getTitleOrPageIdErrorMessage
getTitleOrPageIdErrorMessage()
Definition: ApiBase.php:885