MediaWiki  1.29.2
ApiBase.php
Go to the documentation of this file.
1 <?php
28 
41 abstract class ApiBase extends ContextSource {
42 
52  const PARAM_DFLT = 0;
53 
55  const PARAM_ISMULTI = 1;
56 
91  const PARAM_TYPE = 2;
92 
94  const PARAM_MAX = 3;
95 
100  const PARAM_MAX2 = 4;
101 
103  const PARAM_MIN = 5;
104 
107 
109  const PARAM_DEPRECATED = 7;
110 
115  const PARAM_REQUIRED = 8;
116 
122 
128  const PARAM_HELP_MSG = 10;
129 
136 
146 
152  const PARAM_VALUE_LINKS = 13;
153 
161 
169 
176 
183  const PARAM_ALL = 17;
184 
190 
191  /*
192  * (boolean) Is the parameter sensitive? Note 'password'-type fields are
193  * always sensitive regardless of the value of this field.
194  * @since 1.29
195  */
196  const PARAM_SENSITIVE = 19;
197 
200  const ALL_DEFAULT_STRING = '*';
201 
203  const LIMIT_BIG1 = 500;
205  const LIMIT_BIG2 = 5000;
207  const LIMIT_SML1 = 50;
209  const LIMIT_SML2 = 500;
210 
217 
219  private static $extensionInfo = null;
220 
222  private $mMainModule;
225  private $mSlaveDB = null;
226  private $mParamCache = [];
228  private $mModuleSource = false;
229 
235  public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
236  $this->mMainModule = $mainModule;
237  $this->mModuleName = $moduleName;
238  $this->mModulePrefix = $modulePrefix;
239 
240  if ( !$this->isMain() ) {
241  $this->setContext( $mainModule->getContext() );
242  }
243  }
244 
245  /************************************************************************/
266  abstract public function execute();
267 
273  public function getModuleManager() {
274  return null;
275  }
276 
286  public function getCustomPrinter() {
287  return null;
288  }
289 
301  protected function getExamplesMessages() {
302  // Fall back to old non-localised method
303  $ret = [];
304 
305  $examples = $this->getExamples();
306  if ( $examples ) {
307  if ( !is_array( $examples ) ) {
308  $examples = [ $examples ];
309  } elseif ( $examples && ( count( $examples ) & 1 ) == 0 &&
310  array_keys( $examples ) === range( 0, count( $examples ) - 1 ) &&
311  !preg_match( '/^\s*api\.php\?/', $examples[0] )
312  ) {
313  // Fix up the ugly "even numbered elements are description, odd
314  // numbered elemts are the link" format (see doc for self::getExamples)
315  $tmp = [];
316  $examplesCount = count( $examples );
317  for ( $i = 0; $i < $examplesCount; $i += 2 ) {
318  $tmp[$examples[$i + 1]] = $examples[$i];
319  }
320  $examples = $tmp;
321  }
322 
323  foreach ( $examples as $k => $v ) {
324  if ( is_numeric( $k ) ) {
325  $qs = $v;
326  $msg = '';
327  } else {
328  $qs = $k;
329  $msg = self::escapeWikiText( $v );
330  if ( is_array( $msg ) ) {
331  $msg = implode( ' ', $msg );
332  }
333  }
334 
335  $qs = preg_replace( '/^\s*api\.php\?/', '', $qs );
336  $ret[$qs] = $this->msg( 'api-help-fallback-example', [ $msg ] );
337  }
338  }
339 
340  return $ret;
341  }
342 
348  public function getHelpUrls() {
349  return [];
350  }
351 
364  protected function getAllowedParams( /* $flags = 0 */ ) {
365  // int $flags is not declared because it causes "Strict standards"
366  // warning. Most derived classes do not implement it.
367  return [];
368  }
369 
374  public function shouldCheckMaxlag() {
375  return true;
376  }
377 
382  public function isReadMode() {
383  return true;
384  }
385 
397  public function isWriteMode() {
398  return false;
399  }
400 
405  public function mustBePosted() {
406  return $this->needsToken() !== false;
407  }
408 
414  public function isDeprecated() {
415  return false;
416  }
417 
424  public function isInternal() {
425  return false;
426  }
427 
446  public function needsToken() {
447  return false;
448  }
449 
459  protected function getWebUITokenSalt( array $params ) {
460  return null;
461  }
462 
475  public function getConditionalRequestData( $condition ) {
476  return null;
477  }
478 
481  /************************************************************************/
490  public function getModuleName() {
491  return $this->mModuleName;
492  }
493 
498  public function getModulePrefix() {
499  return $this->mModulePrefix;
500  }
501 
506  public function getMain() {
507  return $this->mMainModule;
508  }
509 
515  public function isMain() {
516  return $this === $this->mMainModule;
517  }
518 
524  public function getParent() {
525  return $this->isMain() ? null : $this->getMain();
526  }
527 
538  public function lacksSameOriginSecurity() {
539  // Main module has this method overridden
540  // Safety - avoid infinite loop:
541  if ( $this->isMain() ) {
542  ApiBase::dieDebug( __METHOD__, 'base method was called on main module.' );
543  }
544 
545  return $this->getMain()->lacksSameOriginSecurity();
546  }
547 
554  public function getModulePath() {
555  if ( $this->isMain() ) {
556  return 'main';
557  } elseif ( $this->getParent()->isMain() ) {
558  return $this->getModuleName();
559  } else {
560  return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
561  }
562  }
563 
572  public function getModuleFromPath( $path ) {
573  $module = $this->getMain();
574  if ( $path === 'main' ) {
575  return $module;
576  }
577 
578  $parts = explode( '+', $path );
579  if ( count( $parts ) === 1 ) {
580  // In case the '+' was typed into URL, it resolves as a space
581  $parts = explode( ' ', $path );
582  }
583 
584  $count = count( $parts );
585  for ( $i = 0; $i < $count; $i++ ) {
586  $parent = $module;
587  $manager = $parent->getModuleManager();
588  if ( $manager === null ) {
589  $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
590  $this->dieWithError( [ 'apierror-badmodule-nosubmodules', $errorPath ], 'badmodule' );
591  }
592  $module = $manager->getModule( $parts[$i] );
593 
594  if ( $module === null ) {
595  $errorPath = $i ? implode( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
596  $this->dieWithError(
597  [ 'apierror-badmodule-badsubmodule', $errorPath, wfEscapeWikiText( $parts[$i] ) ],
598  'badmodule'
599  );
600  }
601  }
602 
603  return $module;
604  }
605 
610  public function getResult() {
611  // Main module has getResult() method overridden
612  // Safety - avoid infinite loop:
613  if ( $this->isMain() ) {
614  ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
615  }
616 
617  return $this->getMain()->getResult();
618  }
619 
624  public function getErrorFormatter() {
625  // Main module has getErrorFormatter() method overridden
626  // Safety - avoid infinite loop:
627  if ( $this->isMain() ) {
628  ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
629  }
630 
631  return $this->getMain()->getErrorFormatter();
632  }
633 
638  protected function getDB() {
639  if ( !isset( $this->mSlaveDB ) ) {
640  $this->mSlaveDB = wfGetDB( DB_REPLICA, 'api' );
641  }
642 
643  return $this->mSlaveDB;
644  }
645 
650  public function getContinuationManager() {
651  // Main module has getContinuationManager() method overridden
652  // Safety - avoid infinite loop:
653  if ( $this->isMain() ) {
654  ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
655  }
656 
657  return $this->getMain()->getContinuationManager();
658  }
659 
664  public function setContinuationManager( $manager ) {
665  // Main module has setContinuationManager() method overridden
666  // Safety - avoid infinite loop:
667  if ( $this->isMain() ) {
668  ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
669  }
670 
671  $this->getMain()->setContinuationManager( $manager );
672  }
673 
676  /************************************************************************/
688  public function dynamicParameterDocumentation() {
689  return null;
690  }
691 
699  public function encodeParamName( $paramName ) {
700  if ( is_array( $paramName ) ) {
701  return array_map( function ( $name ) {
702  return $this->mModulePrefix . $name;
703  }, $paramName );
704  } else {
705  return $this->mModulePrefix . $paramName;
706  }
707  }
708 
718  public function extractRequestParams( $parseLimit = true ) {
719  // Cache parameters, for performance and to avoid T26564.
720  if ( !isset( $this->mParamCache[$parseLimit] ) ) {
721  $params = $this->getFinalParams();
722  $results = [];
723 
724  if ( $params ) { // getFinalParams() can return false
725  foreach ( $params as $paramName => $paramSettings ) {
726  $results[$paramName] = $this->getParameterFromSettings(
727  $paramName, $paramSettings, $parseLimit );
728  }
729  }
730  $this->mParamCache[$parseLimit] = $results;
731  }
732 
733  return $this->mParamCache[$parseLimit];
734  }
735 
742  protected function getParameter( $paramName, $parseLimit = true ) {
743  $paramSettings = $this->getFinalParams()[$paramName];
744 
745  return $this->getParameterFromSettings( $paramName, $paramSettings, $parseLimit );
746  }
747 
754  public function requireOnlyOneParameter( $params, $required /*...*/ ) {
755  $required = func_get_args();
756  array_shift( $required );
757 
758  $intersection = array_intersect( array_keys( array_filter( $params,
759  [ $this, 'parameterNotEmpty' ] ) ), $required );
760 
761  if ( count( $intersection ) > 1 ) {
762  $this->dieWithError( [
763  'apierror-invalidparammix',
764  Message::listParam( array_map(
765  function ( $p ) {
766  return '<var>' . $this->encodeParamName( $p ) . '</var>';
767  },
768  array_values( $intersection )
769  ) ),
770  count( $intersection ),
771  ] );
772  } elseif ( count( $intersection ) == 0 ) {
773  $this->dieWithError( [
774  'apierror-missingparam-one-of',
775  Message::listParam( array_map(
776  function ( $p ) {
777  return '<var>' . $this->encodeParamName( $p ) . '</var>';
778  },
779  array_values( $required )
780  ) ),
781  count( $required ),
782  ], 'missingparam' );
783  }
784  }
785 
792  public function requireMaxOneParameter( $params, $required /*...*/ ) {
793  $required = func_get_args();
794  array_shift( $required );
795 
796  $intersection = array_intersect( array_keys( array_filter( $params,
797  [ $this, 'parameterNotEmpty' ] ) ), $required );
798 
799  if ( count( $intersection ) > 1 ) {
800  $this->dieWithError( [
801  'apierror-invalidparammix',
802  Message::listParam( array_map(
803  function ( $p ) {
804  return '<var>' . $this->encodeParamName( $p ) . '</var>';
805  },
806  array_values( $intersection )
807  ) ),
808  count( $intersection ),
809  ] );
810  }
811  }
812 
820  public function requireAtLeastOneParameter( $params, $required /*...*/ ) {
821  $required = func_get_args();
822  array_shift( $required );
823 
824  $intersection = array_intersect(
825  array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
826  $required
827  );
828 
829  if ( count( $intersection ) == 0 ) {
830  $this->dieWithError( [
831  'apierror-missingparam-at-least-one-of',
832  Message::listParam( array_map(
833  function ( $p ) {
834  return '<var>' . $this->encodeParamName( $p ) . '</var>';
835  },
836  array_values( $required )
837  ) ),
838  count( $required ),
839  ], 'missingparam' );
840  }
841  }
842 
850  public function requirePostedParameters( $params, $prefix = 'prefix' ) {
851  // Skip if $wgDebugAPI is set or we're in internal mode
852  if ( $this->getConfig()->get( 'DebugAPI' ) || $this->getMain()->isInternalMode() ) {
853  return;
854  }
855 
856  $queryValues = $this->getRequest()->getQueryValues();
857  $badParams = [];
858  foreach ( $params as $param ) {
859  if ( $prefix !== 'noprefix' ) {
860  $param = $this->encodeParamName( $param );
861  }
862  if ( array_key_exists( $param, $queryValues ) ) {
863  $badParams[] = $param;
864  }
865  }
866 
867  if ( $badParams ) {
868  $this->dieWithError(
869  [ 'apierror-mustpostparams', join( ', ', $badParams ), count( $badParams ) ]
870  );
871  }
872  }
873 
880  private function parameterNotEmpty( $x ) {
881  return !is_null( $x ) && $x !== false;
882  }
883 
895  public function getTitleOrPageId( $params, $load = false ) {
896  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
897 
898  $pageObj = null;
899  if ( isset( $params['title'] ) ) {
900  $titleObj = Title::newFromText( $params['title'] );
901  if ( !$titleObj || $titleObj->isExternal() ) {
902  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
903  }
904  if ( !$titleObj->canExist() ) {
905  $this->dieWithError( 'apierror-pagecannotexist' );
906  }
907  $pageObj = WikiPage::factory( $titleObj );
908  if ( $load !== false ) {
909  $pageObj->loadPageData( $load );
910  }
911  } elseif ( isset( $params['pageid'] ) ) {
912  if ( $load === false ) {
913  $load = 'fromdb';
914  }
915  $pageObj = WikiPage::newFromID( $params['pageid'], $load );
916  if ( !$pageObj ) {
917  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
918  }
919  }
920 
921  return $pageObj;
922  }
923 
932  public function getTitleFromTitleOrPageId( $params ) {
933  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
934 
935  $titleObj = null;
936  if ( isset( $params['title'] ) ) {
937  $titleObj = Title::newFromText( $params['title'] );
938  if ( !$titleObj || $titleObj->isExternal() ) {
939  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
940  }
941  return $titleObj;
942  } elseif ( isset( $params['pageid'] ) ) {
943  $titleObj = Title::newFromID( $params['pageid'] );
944  if ( !$titleObj ) {
945  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
946  }
947  }
948 
949  return $titleObj;
950  }
951 
960  protected function getWatchlistValue( $watchlist, $titleObj, $userOption = null ) {
961 
962  $userWatching = $this->getUser()->isWatched( $titleObj, User::IGNORE_USER_RIGHTS );
963 
964  switch ( $watchlist ) {
965  case 'watch':
966  return true;
967 
968  case 'unwatch':
969  return false;
970 
971  case 'preferences':
972  # If the user is already watching, don't bother checking
973  if ( $userWatching ) {
974  return true;
975  }
976  # If no user option was passed, use watchdefault and watchcreations
977  if ( is_null( $userOption ) ) {
978  return $this->getUser()->getBoolOption( 'watchdefault' ) ||
979  $this->getUser()->getBoolOption( 'watchcreations' ) && !$titleObj->exists();
980  }
981 
982  # Watch the article based on the user preference
983  return $this->getUser()->getBoolOption( $userOption );
984 
985  case 'nochange':
986  return $userWatching;
987 
988  default:
989  return $userWatching;
990  }
991  }
992 
1002  protected function getParameterFromSettings( $paramName, $paramSettings, $parseLimit ) {
1003  // Some classes may decide to change parameter names
1004  $encParamName = $this->encodeParamName( $paramName );
1005 
1006  // Shorthand
1007  if ( !is_array( $paramSettings ) ) {
1008  $paramSettings = [
1009  self::PARAM_DFLT => $paramSettings,
1010  ];
1011  }
1012 
1013  $default = isset( $paramSettings[self::PARAM_DFLT] )
1014  ? $paramSettings[self::PARAM_DFLT]
1015  : null;
1016  $multi = isset( $paramSettings[self::PARAM_ISMULTI] )
1017  ? $paramSettings[self::PARAM_ISMULTI]
1018  : false;
1019  $type = isset( $paramSettings[self::PARAM_TYPE] )
1020  ? $paramSettings[self::PARAM_TYPE]
1021  : null;
1022  $dupes = isset( $paramSettings[self::PARAM_ALLOW_DUPLICATES] )
1023  ? $paramSettings[self::PARAM_ALLOW_DUPLICATES]
1024  : false;
1025  $deprecated = isset( $paramSettings[self::PARAM_DEPRECATED] )
1026  ? $paramSettings[self::PARAM_DEPRECATED]
1027  : false;
1028  $required = isset( $paramSettings[self::PARAM_REQUIRED] )
1029  ? $paramSettings[self::PARAM_REQUIRED]
1030  : false;
1031  $allowAll = isset( $paramSettings[self::PARAM_ALL] )
1032  ? $paramSettings[self::PARAM_ALL]
1033  : false;
1034 
1035  // When type is not given, and no choices, the type is the same as $default
1036  if ( !isset( $type ) ) {
1037  if ( isset( $default ) ) {
1038  $type = gettype( $default );
1039  } else {
1040  $type = 'NULL'; // allow everything
1041  }
1042  }
1043 
1044  if ( $type == 'password' || !empty( $paramSettings[self::PARAM_SENSITIVE] ) ) {
1045  $this->getMain()->markParamsSensitive( $encParamName );
1046  }
1047 
1048  if ( $type == 'boolean' ) {
1049  if ( isset( $default ) && $default !== false ) {
1050  // Having a default value of anything other than 'false' is not allowed
1052  __METHOD__,
1053  "Boolean param $encParamName's default is set to '$default'. " .
1054  'Boolean parameters must default to false.'
1055  );
1056  }
1057 
1058  $value = $this->getMain()->getCheck( $encParamName );
1059  } elseif ( $type == 'upload' ) {
1060  if ( isset( $default ) ) {
1061  // Having a default value is not allowed
1063  __METHOD__,
1064  "File upload param $encParamName's default is set to " .
1065  "'$default'. File upload parameters may not have a default." );
1066  }
1067  if ( $multi ) {
1068  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1069  }
1070  $value = $this->getMain()->getUpload( $encParamName );
1071  if ( !$value->exists() ) {
1072  // This will get the value without trying to normalize it
1073  // (because trying to normalize a large binary file
1074  // accidentally uploaded as a field fails spectacularly)
1075  $value = $this->getMain()->getRequest()->unsetVal( $encParamName );
1076  if ( $value !== null ) {
1077  $this->dieWithError(
1078  [ 'apierror-badupload', $encParamName ],
1079  "badupload_{$encParamName}"
1080  );
1081  }
1082  }
1083  } else {
1084  $value = $this->getMain()->getVal( $encParamName, $default );
1085 
1086  if ( isset( $value ) && $type == 'namespace' ) {
1088  if ( isset( $paramSettings[self::PARAM_EXTRA_NAMESPACES] ) &&
1089  is_array( $paramSettings[self::PARAM_EXTRA_NAMESPACES] )
1090  ) {
1091  $type = array_merge( $type, $paramSettings[self::PARAM_EXTRA_NAMESPACES] );
1092  }
1093  // By default, namespace parameters allow ALL_DEFAULT_STRING to be used to specify
1094  // all namespaces.
1095  $allowAll = true;
1096  }
1097  if ( isset( $value ) && $type == 'submodule' ) {
1098  if ( isset( $paramSettings[self::PARAM_SUBMODULE_MAP] ) ) {
1099  $type = array_keys( $paramSettings[self::PARAM_SUBMODULE_MAP] );
1100  } else {
1101  $type = $this->getModuleManager()->getNames( $paramName );
1102  }
1103  }
1104 
1105  $request = $this->getMain()->getRequest();
1106  $rawValue = $request->getRawVal( $encParamName );
1107  if ( $rawValue === null ) {
1108  $rawValue = $default;
1109  }
1110 
1111  // Preserve U+001F for self::parseMultiValue(), or error out if that won't be called
1112  if ( isset( $value ) && substr( $rawValue, 0, 1 ) === "\x1f" ) {
1113  if ( $multi ) {
1114  // This loses the potential $wgContLang->checkTitleEncoding() transformation
1115  // done by WebRequest for $_GET. Let's call that a feature.
1116  $value = join( "\x1f", $request->normalizeUnicode( explode( "\x1f", $rawValue ) ) );
1117  } else {
1118  $this->dieWithError( 'apierror-badvalue-notmultivalue', 'badvalue_notmultivalue' );
1119  }
1120  }
1121 
1122  // Check for NFC normalization, and warn
1123  if ( $rawValue !== $value ) {
1124  $this->handleParamNormalization( $paramName, $value, $rawValue );
1125  }
1126  }
1127 
1128  $allSpecifier = ( is_string( $allowAll ) ? $allowAll : self::ALL_DEFAULT_STRING );
1129  if ( $allowAll && $multi && is_array( $type ) && in_array( $allSpecifier, $type, true ) ) {
1131  __METHOD__,
1132  "For param $encParamName, PARAM_ALL collides with a possible value" );
1133  }
1134  if ( isset( $value ) && ( $multi || is_array( $type ) ) ) {
1135  $value = $this->parseMultiValue(
1136  $encParamName,
1137  $value,
1138  $multi,
1139  is_array( $type ) ? $type : null,
1140  $allowAll ? $allSpecifier : null
1141  );
1142  }
1143 
1144  // More validation only when choices were not given
1145  // choices were validated in parseMultiValue()
1146  if ( isset( $value ) ) {
1147  if ( !is_array( $type ) ) {
1148  switch ( $type ) {
1149  case 'NULL': // nothing to do
1150  break;
1151  case 'string':
1152  case 'text':
1153  case 'password':
1154  if ( $required && $value === '' ) {
1155  $this->dieWithError( [ 'apierror-missingparam', $paramName ] );
1156  }
1157  break;
1158  case 'integer': // Force everything using intval() and optionally validate limits
1159  $min = isset( $paramSettings[self::PARAM_MIN] ) ? $paramSettings[self::PARAM_MIN] : null;
1160  $max = isset( $paramSettings[self::PARAM_MAX] ) ? $paramSettings[self::PARAM_MAX] : null;
1161  $enforceLimits = isset( $paramSettings[self::PARAM_RANGE_ENFORCE] )
1162  ? $paramSettings[self::PARAM_RANGE_ENFORCE] : false;
1163 
1164  if ( is_array( $value ) ) {
1165  $value = array_map( 'intval', $value );
1166  if ( !is_null( $min ) || !is_null( $max ) ) {
1167  foreach ( $value as &$v ) {
1168  $this->validateLimit( $paramName, $v, $min, $max, null, $enforceLimits );
1169  }
1170  }
1171  } else {
1172  $value = intval( $value );
1173  if ( !is_null( $min ) || !is_null( $max ) ) {
1174  $this->validateLimit( $paramName, $value, $min, $max, null, $enforceLimits );
1175  }
1176  }
1177  break;
1178  case 'limit':
1179  if ( !$parseLimit ) {
1180  // Don't do any validation whatsoever
1181  break;
1182  }
1183  if ( !isset( $paramSettings[self::PARAM_MAX] )
1184  || !isset( $paramSettings[self::PARAM_MAX2] )
1185  ) {
1187  __METHOD__,
1188  "MAX1 or MAX2 are not defined for the limit $encParamName"
1189  );
1190  }
1191  if ( $multi ) {
1192  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1193  }
1194  $min = isset( $paramSettings[self::PARAM_MIN] ) ? $paramSettings[self::PARAM_MIN] : 0;
1195  if ( $value == 'max' ) {
1196  $value = $this->getMain()->canApiHighLimits()
1197  ? $paramSettings[self::PARAM_MAX2]
1198  : $paramSettings[self::PARAM_MAX];
1199  $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1200  } else {
1201  $value = intval( $value );
1202  $this->validateLimit(
1203  $paramName,
1204  $value,
1205  $min,
1206  $paramSettings[self::PARAM_MAX],
1207  $paramSettings[self::PARAM_MAX2]
1208  );
1209  }
1210  break;
1211  case 'boolean':
1212  if ( $multi ) {
1213  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1214  }
1215  break;
1216  case 'timestamp':
1217  if ( is_array( $value ) ) {
1218  foreach ( $value as $key => $val ) {
1219  $value[$key] = $this->validateTimestamp( $val, $encParamName );
1220  }
1221  } else {
1222  $value = $this->validateTimestamp( $value, $encParamName );
1223  }
1224  break;
1225  case 'user':
1226  if ( is_array( $value ) ) {
1227  foreach ( $value as $key => $val ) {
1228  $value[$key] = $this->validateUser( $val, $encParamName );
1229  }
1230  } else {
1231  $value = $this->validateUser( $value, $encParamName );
1232  }
1233  break;
1234  case 'upload': // nothing to do
1235  break;
1236  case 'tags':
1237  // If change tagging was requested, check that the tags are valid.
1238  if ( !is_array( $value ) && !$multi ) {
1239  $value = [ $value ];
1240  }
1242  if ( !$tagsStatus->isGood() ) {
1243  $this->dieStatus( $tagsStatus );
1244  }
1245  break;
1246  default:
1247  ApiBase::dieDebug( __METHOD__, "Param $encParamName's type is unknown - $type" );
1248  }
1249  }
1250 
1251  // Throw out duplicates if requested
1252  if ( !$dupes && is_array( $value ) ) {
1253  $value = array_unique( $value );
1254  }
1255 
1256  // Set a warning if a deprecated parameter has been passed
1257  if ( $deprecated && $value !== false ) {
1258  $feature = $encParamName;
1259  $m = $this;
1260  while ( !$m->isMain() ) {
1261  $p = $m->getParent();
1262  $name = $m->getModuleName();
1263  $param = $p->encodeParamName( $p->getModuleManager()->getModuleGroup( $name ) );
1264  $feature = "{$param}={$name}&{$feature}";
1265  $m = $p;
1266  }
1267  $this->addDeprecation( [ 'apiwarn-deprecation-parameter', $encParamName ], $feature );
1268  }
1269  } elseif ( $required ) {
1270  $this->dieWithError( [ 'apierror-missingparam', $paramName ] );
1271  }
1272 
1273  return $value;
1274  }
1275 
1283  protected function handleParamNormalization( $paramName, $value, $rawValue ) {
1284  $encParamName = $this->encodeParamName( $paramName );
1285  $this->addWarning( [ 'apiwarn-badutf8', $encParamName ] );
1286  }
1287 
1295  protected function explodeMultiValue( $value, $limit ) {
1296  if ( substr( $value, 0, 1 ) === "\x1f" ) {
1297  $sep = "\x1f";
1298  $value = substr( $value, 1 );
1299  } else {
1300  $sep = '|';
1301  }
1302 
1303  return explode( $sep, $value, $limit );
1304  }
1305 
1321  protected function parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues,
1322  $allSpecifier = null
1323  ) {
1324  if ( ( trim( $value ) === '' || trim( $value ) === "\x1f" ) && $allowMultiple ) {
1325  return [];
1326  }
1327 
1328  // This is a bit awkward, but we want to avoid calling canApiHighLimits()
1329  // because it unstubs $wgUser
1330  $valuesList = $this->explodeMultiValue( $value, self::LIMIT_SML2 + 1 );
1331  $sizeLimit = count( $valuesList ) > self::LIMIT_SML1 && $this->mMainModule->canApiHighLimits()
1333  : self::LIMIT_SML1;
1334 
1335  if ( $allowMultiple && is_array( $allowedValues ) && $allSpecifier &&
1336  count( $valuesList ) === 1 && $valuesList[0] === $allSpecifier
1337  ) {
1338  return $allowedValues;
1339  }
1340 
1341  if ( self::truncateArray( $valuesList, $sizeLimit ) ) {
1342  $this->addDeprecation(
1343  [ 'apiwarn-toomanyvalues', $valueName, $sizeLimit ],
1344  "too-many-$valueName-for-{$this->getModulePath()}"
1345  );
1346  }
1347 
1348  if ( !$allowMultiple && count( $valuesList ) != 1 ) {
1349  // T35482 - Allow entries with | in them for non-multiple values
1350  if ( in_array( $value, $allowedValues, true ) ) {
1351  return $value;
1352  }
1353 
1354  if ( is_array( $allowedValues ) ) {
1355  $values = array_map( function ( $v ) {
1356  return '<kbd>' . wfEscapeWikiText( $v ) . '</kbd>';
1357  }, $allowedValues );
1358  $this->dieWithError( [
1359  'apierror-multival-only-one-of',
1360  $valueName,
1361  Message::listParam( $values ),
1362  count( $values ),
1363  ], "multival_$valueName" );
1364  } else {
1365  $this->dieWithError( [
1366  'apierror-multival-only-one',
1367  $valueName,
1368  ], "multival_$valueName" );
1369  }
1370  }
1371 
1372  if ( is_array( $allowedValues ) ) {
1373  // Check for unknown values
1374  $unknown = array_map( 'wfEscapeWikiText', array_diff( $valuesList, $allowedValues ) );
1375  if ( count( $unknown ) ) {
1376  if ( $allowMultiple ) {
1377  $this->addWarning( [
1378  'apiwarn-unrecognizedvalues',
1379  $valueName,
1380  Message::listParam( $unknown, 'comma' ),
1381  count( $unknown ),
1382  ] );
1383  } else {
1384  $this->dieWithError(
1385  [ 'apierror-unrecognizedvalue', $valueName, wfEscapeWikiText( $valuesList[0] ) ],
1386  "unknown_$valueName"
1387  );
1388  }
1389  }
1390  // Now throw them out
1391  $valuesList = array_intersect( $valuesList, $allowedValues );
1392  }
1393 
1394  return $allowMultiple ? $valuesList : $valuesList[0];
1395  }
1396 
1407  protected function validateLimit( $paramName, &$value, $min, $max, $botMax = null,
1408  $enforceLimits = false
1409  ) {
1410  if ( !is_null( $min ) && $value < $min ) {
1411  $msg = ApiMessage::create(
1412  [ 'apierror-integeroutofrange-belowminimum',
1413  $this->encodeParamName( $paramName ), $min, $value ],
1414  'integeroutofrange',
1415  [ 'min' => $min, 'max' => $max, 'botMax' => $botMax ?: $max ]
1416  );
1417  $this->warnOrDie( $msg, $enforceLimits );
1418  $value = $min;
1419  }
1420 
1421  // Minimum is always validated, whereas maximum is checked only if not
1422  // running in internal call mode
1423  if ( $this->getMain()->isInternalMode() ) {
1424  return;
1425  }
1426 
1427  // Optimization: do not check user's bot status unless really needed -- skips db query
1428  // assumes $botMax >= $max
1429  if ( !is_null( $max ) && $value > $max ) {
1430  if ( !is_null( $botMax ) && $this->getMain()->canApiHighLimits() ) {
1431  if ( $value > $botMax ) {
1432  $msg = ApiMessage::create(
1433  [ 'apierror-integeroutofrange-abovebotmax',
1434  $this->encodeParamName( $paramName ), $botMax, $value ],
1435  'integeroutofrange',
1436  [ 'min' => $min, 'max' => $max, 'botMax' => $botMax ?: $max ]
1437  );
1438  $this->warnOrDie( $msg, $enforceLimits );
1439  $value = $botMax;
1440  }
1441  } else {
1442  $msg = ApiMessage::create(
1443  [ 'apierror-integeroutofrange-abovemax',
1444  $this->encodeParamName( $paramName ), $max, $value ],
1445  'integeroutofrange',
1446  [ 'min' => $min, 'max' => $max, 'botMax' => $botMax ?: $max ]
1447  );
1448  $this->warnOrDie( $msg, $enforceLimits );
1449  $value = $max;
1450  }
1451  }
1452  }
1453 
1460  protected function validateTimestamp( $value, $encParamName ) {
1461  // Confusing synonyms for the current time accepted by wfTimestamp()
1462  // (wfTimestamp() also accepts various non-strings and the string of 14
1463  // ASCII NUL bytes, but those can't get here)
1464  if ( !$value ) {
1465  $this->addDeprecation(
1466  [ 'apiwarn-unclearnowtimestamp', $encParamName, wfEscapeWikiText( $value ) ],
1467  'unclear-"now"-timestamp'
1468  );
1469  return wfTimestamp( TS_MW );
1470  }
1471 
1472  // Explicit synonym for the current time
1473  if ( $value === 'now' ) {
1474  return wfTimestamp( TS_MW );
1475  }
1476 
1477  $unixTimestamp = wfTimestamp( TS_UNIX, $value );
1478  if ( $unixTimestamp === false ) {
1479  $this->dieWithError(
1480  [ 'apierror-badtimestamp', $encParamName, wfEscapeWikiText( $value ) ],
1481  "badtimestamp_{$encParamName}"
1482  );
1483  }
1484 
1485  return wfTimestamp( TS_MW, $unixTimestamp );
1486  }
1487 
1497  final public function validateToken( $token, array $params ) {
1498  $tokenType = $this->needsToken();
1500  if ( !isset( $salts[$tokenType] ) ) {
1501  throw new MWException(
1502  "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1503  'without registering it'
1504  );
1505  }
1506 
1507  $tokenObj = ApiQueryTokens::getToken(
1508  $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1509  );
1510  if ( $tokenObj->match( $token ) ) {
1511  return true;
1512  }
1513 
1514  $webUiSalt = $this->getWebUITokenSalt( $params );
1515  if ( $webUiSalt !== null && $this->getUser()->matchEditToken(
1516  $token,
1517  $webUiSalt,
1518  $this->getRequest()
1519  ) ) {
1520  return true;
1521  }
1522 
1523  return false;
1524  }
1525 
1532  private function validateUser( $value, $encParamName ) {
1534  if ( $title === null || $title->hasFragment() ) {
1535  $this->dieWithError(
1536  [ 'apierror-baduser', $encParamName, wfEscapeWikiText( $value ) ],
1537  "baduser_{$encParamName}"
1538  );
1539  }
1540 
1541  return $title->getText();
1542  }
1543 
1546  /************************************************************************/
1557  protected function setWatch( $watch, $titleObj, $userOption = null ) {
1558  $value = $this->getWatchlistValue( $watch, $titleObj, $userOption );
1559  if ( $value === null ) {
1560  return;
1561  }
1562 
1563  WatchAction::doWatchOrUnwatch( $value, $titleObj, $this->getUser() );
1564  }
1565 
1572  public static function truncateArray( &$arr, $limit ) {
1573  $modified = false;
1574  while ( count( $arr ) > $limit ) {
1575  array_pop( $arr );
1576  $modified = true;
1577  }
1578 
1579  return $modified;
1580  }
1581 
1588  public function getWatchlistUser( $params ) {
1589  if ( !is_null( $params['owner'] ) && !is_null( $params['token'] ) ) {
1590  $user = User::newFromName( $params['owner'], false );
1591  if ( !( $user && $user->getId() ) ) {
1592  $this->dieWithError(
1593  [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1594  );
1595  }
1596  $token = $user->getOption( 'watchlisttoken' );
1597  if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1598  $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1599  }
1600  } else {
1601  if ( !$this->getUser()->isLoggedIn() ) {
1602  $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1603  }
1604  $this->checkUserRightsAny( 'viewmywatchlist' );
1605  $user = $this->getUser();
1606  }
1607 
1608  return $user;
1609  }
1610 
1618  private static function escapeWikiText( $v ) {
1619  if ( is_array( $v ) ) {
1620  return array_map( 'self::escapeWikiText', $v );
1621  } else {
1622  return strtr( $v, [
1623  '__' => '_&#95;', '{' => '&#123;', '}' => '&#125;',
1624  '[[Category:' => '[[:Category:',
1625  '[[File:' => '[[:File:', '[[Image:' => '[[:Image:',
1626  ] );
1627  }
1628  }
1629 
1642  public static function makeMessage( $msg, IContextSource $context, array $params = null ) {
1643  if ( is_string( $msg ) ) {
1644  $msg = wfMessage( $msg );
1645  } elseif ( is_array( $msg ) ) {
1646  $msg = call_user_func_array( 'wfMessage', $msg );
1647  }
1648  if ( !$msg instanceof Message ) {
1649  return null;
1650  }
1651 
1652  $msg->setContext( $context );
1653  if ( $params ) {
1654  $msg->params( $params );
1655  }
1656 
1657  return $msg;
1658  }
1659 
1667  public function errorArrayToStatus( array $errors, User $user = null ) {
1668  if ( $user === null ) {
1669  $user = $this->getUser();
1670  }
1671 
1673  foreach ( $errors as $error ) {
1674  if ( is_array( $error ) && $error[0] === 'blockedtext' && $user->getBlock() ) {
1675  $status->fatal( ApiMessage::create(
1676  'apierror-blocked',
1677  'blocked',
1678  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
1679  ) );
1680  } elseif ( is_array( $error ) && $error[0] === 'autoblockedtext' && $user->getBlock() ) {
1681  $status->fatal( ApiMessage::create(
1682  'apierror-autoblocked',
1683  'autoblocked',
1684  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
1685  ) );
1686  } elseif ( is_array( $error ) && $error[0] === 'systemblockedtext' && $user->getBlock() ) {
1687  $status->fatal( ApiMessage::create(
1688  'apierror-systemblocked',
1689  'blocked',
1690  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
1691  ) );
1692  } else {
1693  call_user_func_array( [ $status, 'fatal' ], (array)$error );
1694  }
1695  }
1696  return $status;
1697  }
1698 
1701  /************************************************************************/
1720  public function addWarning( $msg, $code = null, $data = null ) {
1721  $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1722  }
1723 
1734  public function addDeprecation( $msg, $feature, $data = [] ) {
1735  $data = (array)$data;
1736  if ( $feature !== null ) {
1737  $data['feature'] = $feature;
1738  $this->logFeatureUsage( $feature );
1739  }
1740  $this->addWarning( $msg, 'deprecation', $data );
1741 
1742  // No real need to deduplicate here, ApiErrorFormatter does that for
1743  // us (assuming the hook is deterministic).
1744  $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1745  Hooks::run( 'ApiDeprecationHelp', [ &$msgs ] );
1746  if ( count( $msgs ) > 1 ) {
1747  $key = '$' . join( ' $', range( 1, count( $msgs ) ) );
1748  $msg = ( new RawMessage( $key ) )->params( $msgs );
1749  } else {
1750  $msg = reset( $msgs );
1751  }
1752  $this->getMain()->addWarning( $msg, 'deprecation-help' );
1753  }
1754 
1767  public function addError( $msg, $code = null, $data = null ) {
1768  $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1769  }
1770 
1779  public function addMessagesFromStatus( StatusValue $status, $types = [ 'warning', 'error' ] ) {
1780  $this->getErrorFormatter()->addMessagesFromStatus( $this->getModulePath(), $status, $types );
1781  }
1782 
1796  public function dieWithError( $msg, $code = null, $data = null, $httpCode = null ) {
1797  throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1798  }
1799 
1808  public function dieWithException( $exception, array $options = [] ) {
1809  $this->dieWithError(
1810  $this->getErrorFormatter()->getMessageFromException( $exception, $options )
1811  );
1812  }
1813 
1820  private function warnOrDie( ApiMessage $msg, $enforceLimits = false ) {
1821  if ( $enforceLimits ) {
1822  $this->dieWithError( $msg );
1823  } else {
1824  $this->addWarning( $msg );
1825  }
1826  }
1827 
1836  public function dieBlocked( Block $block ) {
1837  // Die using the appropriate message depending on block type
1838  if ( $block->getType() == Block::TYPE_AUTO ) {
1839  $this->dieWithError(
1840  'apierror-autoblocked',
1841  'autoblocked',
1842  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
1843  );
1844  } else {
1845  $this->dieWithError(
1846  'apierror-blocked',
1847  'blocked',
1848  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
1849  );
1850  }
1851  }
1852 
1861  public function dieStatus( StatusValue $status ) {
1862  if ( $status->isGood() ) {
1863  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
1864  }
1865 
1866  throw new ApiUsageException( $this, $status );
1867  }
1868 
1874  public function dieReadOnly() {
1875  $this->dieWithError(
1876  'apierror-readonly',
1877  'readonly',
1878  [ 'readonlyreason' => wfReadOnlyReason() ]
1879  );
1880  }
1881 
1890  public function checkUserRightsAny( $rights, $user = null ) {
1891  if ( !$user ) {
1892  $user = $this->getUser();
1893  }
1894  $rights = (array)$rights;
1895  if ( !call_user_func_array( [ $user, 'isAllowedAny' ], $rights ) ) {
1896  $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
1897  }
1898  }
1899 
1908  public function checkTitleUserPermissions( Title $title, $actions, $user = null ) {
1909  if ( !$user ) {
1910  $user = $this->getUser();
1911  }
1912 
1913  $errors = [];
1914  foreach ( (array)$actions as $action ) {
1915  $errors = array_merge( $errors, $title->getUserPermissionsErrors( $action, $user ) );
1916  }
1917  if ( $errors ) {
1918  $this->dieStatus( $this->errorArrayToStatus( $errors, $user ) );
1919  }
1920  }
1921 
1933  public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
1934  if ( $this->getConfig()->get( 'DebugAPI' ) !== true ) {
1935  $this->dieWithError( $msg, $code, $data, $httpCode );
1936  } else {
1937  $this->addWarning( $msg, $code, $data );
1938  }
1939  }
1940 
1950  protected function dieContinueUsageIf( $condition ) {
1951  if ( $condition ) {
1952  $this->dieWithError( 'apierror-badcontinue' );
1953  }
1954  }
1955 
1962  protected static function dieDebug( $method, $message ) {
1963  throw new MWException( "Internal error in $method: $message" );
1964  }
1965 
1972  public function logFeatureUsage( $feature ) {
1973  $request = $this->getRequest();
1974  $s = '"' . addslashes( $feature ) . '"' .
1975  ' "' . wfUrlencode( str_replace( ' ', '_', $this->getUser()->getName() ) ) . '"' .
1976  ' "' . $request->getIP() . '"' .
1977  ' "' . addslashes( $request->getHeader( 'Referer' ) ) . '"' .
1978  ' "' . addslashes( $this->getMain()->getUserAgent() ) . '"';
1979  wfDebugLog( 'api-feature-usage', $s, 'private' );
1980  }
1981 
1984  /************************************************************************/
1994  protected function getDescriptionMessage() {
1995  return "apihelp-{$this->getModulePath()}-description";
1996  }
1997 
2005  public function getFinalDescription() {
2006  $desc = $this->getDescription();
2007 
2008  // Avoid PHP 7.1 warning of passing $this by reference
2009  $apiModule = $this;
2010  Hooks::run( 'APIGetDescription', [ &$apiModule, &$desc ] );
2011  $desc = self::escapeWikiText( $desc );
2012  if ( is_array( $desc ) ) {
2013  $desc = implode( "\n", $desc );
2014  } else {
2015  $desc = (string)$desc;
2016  }
2017 
2018  $msg = ApiBase::makeMessage( $this->getDescriptionMessage(), $this->getContext(), [
2019  $this->getModulePrefix(),
2020  $this->getModuleName(),
2021  $this->getModulePath(),
2022  ] );
2023  if ( !$msg->exists() ) {
2024  $msg = $this->msg( 'api-help-fallback-description', $desc );
2025  }
2026  $msgs = [ $msg ];
2027 
2028  Hooks::run( 'APIGetDescriptionMessages', [ $this, &$msgs ] );
2029 
2030  return $msgs;
2031  }
2032 
2041  public function getFinalParams( $flags = 0 ) {
2042  $params = $this->getAllowedParams( $flags );
2043  if ( !$params ) {
2044  $params = [];
2045  }
2046 
2047  if ( $this->needsToken() ) {
2048  $params['token'] = [
2049  ApiBase::PARAM_TYPE => 'string',
2050  ApiBase::PARAM_REQUIRED => true,
2051  ApiBase::PARAM_SENSITIVE => true,
2053  'api-help-param-token',
2054  $this->needsToken(),
2055  ],
2056  ] + ( isset( $params['token'] ) ? $params['token'] : [] );
2057  }
2058 
2059  // Avoid PHP 7.1 warning of passing $this by reference
2060  $apiModule = $this;
2061  Hooks::run( 'APIGetAllowedParams', [ &$apiModule, &$params, $flags ] );
2062 
2063  return $params;
2064  }
2065 
2073  public function getFinalParamDescription() {
2074  $prefix = $this->getModulePrefix();
2075  $name = $this->getModuleName();
2076  $path = $this->getModulePath();
2077 
2078  $desc = $this->getParamDescription();
2079 
2080  // Avoid PHP 7.1 warning of passing $this by reference
2081  $apiModule = $this;
2082  Hooks::run( 'APIGetParamDescription', [ &$apiModule, &$desc ] );
2083 
2084  if ( !$desc ) {
2085  $desc = [];
2086  }
2087  $desc = self::escapeWikiText( $desc );
2088 
2090  $msgs = [];
2091  foreach ( $params as $param => $settings ) {
2092  if ( !is_array( $settings ) ) {
2093  $settings = [];
2094  }
2095 
2096  $d = isset( $desc[$param] ) ? $desc[$param] : '';
2097  if ( is_array( $d ) ) {
2098  // Special handling for prop parameters
2099  $d = array_map( function ( $line ) {
2100  if ( preg_match( '/^\s+(\S+)\s+-\s+(.+)$/', $line, $m ) ) {
2101  $line = "\n;{$m[1]}:{$m[2]}";
2102  }
2103  return $line;
2104  }, $d );
2105  $d = implode( ' ', $d );
2106  }
2107 
2108  if ( isset( $settings[ApiBase::PARAM_HELP_MSG] ) ) {
2109  $msg = $settings[ApiBase::PARAM_HELP_MSG];
2110  } else {
2111  $msg = $this->msg( "apihelp-{$path}-param-{$param}" );
2112  if ( !$msg->exists() ) {
2113  $msg = $this->msg( 'api-help-fallback-parameter', $d );
2114  }
2115  }
2116  $msg = ApiBase::makeMessage( $msg, $this->getContext(),
2117  [ $prefix, $param, $name, $path ] );
2118  if ( !$msg ) {
2119  self::dieDebug( __METHOD__,
2120  'Value in ApiBase::PARAM_HELP_MSG is not valid' );
2121  }
2122  $msgs[$param] = [ $msg ];
2123 
2124  if ( isset( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
2125  if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
2126  self::dieDebug( __METHOD__,
2127  'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
2128  }
2129  if ( !is_array( $settings[ApiBase::PARAM_TYPE] ) ) {
2130  self::dieDebug( __METHOD__,
2131  'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
2132  'ApiBase::PARAM_TYPE is an array' );
2133  }
2134 
2135  $valueMsgs = $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE];
2136  foreach ( $settings[ApiBase::PARAM_TYPE] as $value ) {
2137  if ( isset( $valueMsgs[$value] ) ) {
2138  $msg = $valueMsgs[$value];
2139  } else {
2140  $msg = "apihelp-{$path}-paramvalue-{$param}-{$value}";
2141  }
2142  $m = ApiBase::makeMessage( $msg, $this->getContext(),
2143  [ $prefix, $param, $name, $path, $value ] );
2144  if ( $m ) {
2145  $m = new ApiHelpParamValueMessage(
2146  $value,
2147  [ $m->getKey(), 'api-help-param-no-description' ],
2148  $m->getParams()
2149  );
2150  $msgs[$param][] = $m->setContext( $this->getContext() );
2151  } else {
2152  self::dieDebug( __METHOD__,
2153  "Value in ApiBase::PARAM_HELP_MSG_PER_VALUE for $value is not valid" );
2154  }
2155  }
2156  }
2157 
2158  if ( isset( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
2159  if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
2160  self::dieDebug( __METHOD__,
2161  'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
2162  }
2163  foreach ( $settings[ApiBase::PARAM_HELP_MSG_APPEND] as $m ) {
2164  $m = ApiBase::makeMessage( $m, $this->getContext(),
2165  [ $prefix, $param, $name, $path ] );
2166  if ( $m ) {
2167  $msgs[$param][] = $m;
2168  } else {
2169  self::dieDebug( __METHOD__,
2170  'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
2171  }
2172  }
2173  }
2174  }
2175 
2176  Hooks::run( 'APIGetParamDescriptionMessages', [ $this, &$msgs ] );
2177 
2178  return $msgs;
2179  }
2180 
2190  protected function getHelpFlags() {
2191  $flags = [];
2192 
2193  if ( $this->isDeprecated() ) {
2194  $flags[] = 'deprecated';
2195  }
2196  if ( $this->isInternal() ) {
2197  $flags[] = 'internal';
2198  }
2199  if ( $this->isReadMode() ) {
2200  $flags[] = 'readrights';
2201  }
2202  if ( $this->isWriteMode() ) {
2203  $flags[] = 'writerights';
2204  }
2205  if ( $this->mustBePosted() ) {
2206  $flags[] = 'mustbeposted';
2207  }
2208 
2209  return $flags;
2210  }
2211 
2223  protected function getModuleSourceInfo() {
2224  global $IP;
2225 
2226  if ( $this->mModuleSource !== false ) {
2227  return $this->mModuleSource;
2228  }
2229 
2230  // First, try to find where the module comes from...
2231  $rClass = new ReflectionClass( $this );
2232  $path = $rClass->getFileName();
2233  if ( !$path ) {
2234  // No path known?
2235  $this->mModuleSource = null;
2236  return null;
2237  }
2238  $path = realpath( $path ) ?: $path;
2239 
2240  // Build map of extension directories to extension info
2241  if ( self::$extensionInfo === null ) {
2242  $extDir = $this->getConfig()->get( 'ExtensionDirectory' );
2243  self::$extensionInfo = [
2244  realpath( __DIR__ ) ?: __DIR__ => [
2245  'path' => $IP,
2246  'name' => 'MediaWiki',
2247  'license-name' => 'GPL-2.0+',
2248  ],
2249  realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
2250  realpath( $extDir ) ?: $extDir => null,
2251  ];
2252  $keep = [
2253  'path' => null,
2254  'name' => null,
2255  'namemsg' => null,
2256  'license-name' => null,
2257  ];
2258  foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $group ) {
2259  foreach ( $group as $ext ) {
2260  if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
2261  // This shouldn't happen, but does anyway.
2262  continue;
2263  }
2264 
2265  $extpath = $ext['path'];
2266  if ( !is_dir( $extpath ) ) {
2267  $extpath = dirname( $extpath );
2268  }
2269  self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2270  array_intersect_key( $ext, $keep );
2271  }
2272  }
2273  foreach ( ExtensionRegistry::getInstance()->getAllThings() as $ext ) {
2274  $extpath = $ext['path'];
2275  if ( !is_dir( $extpath ) ) {
2276  $extpath = dirname( $extpath );
2277  }
2278  self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2279  array_intersect_key( $ext, $keep );
2280  }
2281  }
2282 
2283  // Now traverse parent directories until we find a match or run out of
2284  // parents.
2285  do {
2286  if ( array_key_exists( $path, self::$extensionInfo ) ) {
2287  // Found it!
2288  $this->mModuleSource = self::$extensionInfo[$path];
2289  return $this->mModuleSource;
2290  }
2291 
2292  $oldpath = $path;
2293  $path = dirname( $path );
2294  } while ( $path !== $oldpath );
2295 
2296  // No idea what extension this might be.
2297  $this->mModuleSource = null;
2298  return null;
2299  }
2300 
2312  public function modifyHelp( array &$help, array $options, array &$tocData ) {
2313  }
2314 
2317  /************************************************************************/
2331  protected function getDescription() {
2332  return false;
2333  }
2334 
2347  protected function getParamDescription() {
2348  return [];
2349  }
2350 
2367  protected function getExamples() {
2368  return false;
2369  }
2370 
2376  public function getModuleProfileName( $db = false ) {
2377  wfDeprecated( __METHOD__, '1.25' );
2378  return '';
2379  }
2380 
2384  public function profileIn() {
2385  // No wfDeprecated() yet because extensions call this and might need to
2386  // keep doing so for BC.
2387  }
2388 
2392  public function profileOut() {
2393  // No wfDeprecated() yet because extensions call this and might need to
2394  // keep doing so for BC.
2395  }
2396 
2400  public function safeProfileOut() {
2401  wfDeprecated( __METHOD__, '1.25' );
2402  }
2403 
2408  public function getProfileTime() {
2409  wfDeprecated( __METHOD__, '1.25' );
2410  return 0;
2411  }
2412 
2416  public function profileDBIn() {
2417  wfDeprecated( __METHOD__, '1.25' );
2418  }
2419 
2423  public function profileDBOut() {
2424  wfDeprecated( __METHOD__, '1.25' );
2425  }
2426 
2431  public function getProfileDBTime() {
2432  wfDeprecated( __METHOD__, '1.25' );
2433  return 0;
2434  }
2435 
2440  protected function useTransactionalTimeLimit() {
2441  if ( $this->getRequest()->wasPosted() ) {
2443  }
2444  }
2445 
2450  public function setWarning( $warning ) {
2451  $msg = new ApiRawMessage( $warning, 'warning' );
2452  $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg );
2453  }
2454 
2468  public function dieUsage( $description, $errorCode, $httpRespCode = 0, $extradata = null ) {
2469  $this->dieWithError(
2470  new RawMessage( '$1', [ $description ] ),
2471  $errorCode,
2472  $extradata,
2473  $httpRespCode
2474  );
2475  }
2476 
2487  public function getErrorFromStatus( $status, &$extraData = null ) {
2488  if ( $status->isGood() ) {
2489  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
2490  }
2491 
2492  $errors = $status->getErrorsByType( 'error' );
2493  if ( !$errors ) {
2494  // No errors? Assume the warnings should be treated as errors
2495  $errors = $status->getErrorsByType( 'warning' );
2496  }
2497  if ( !$errors ) {
2498  // Still no errors? Punt
2499  $errors = [ [ 'message' => 'unknownerror-nocode', 'params' => [] ] ];
2500  }
2501 
2502  if ( $errors[0]['message'] instanceof MessageSpecifier ) {
2503  $msg = $errors[0]['message'];
2504  } else {
2505  $msg = new Message( $errors[0]['message'], $errors[0]['params'] );
2506  }
2507  if ( !$msg instanceof IApiMessage ) {
2508  $key = $msg->getKey();
2509  $params = $msg->getParams();
2510  array_unshift( $params, isset( self::$messageMap[$key] ) ? self::$messageMap[$key] : $key );
2511  $msg = ApiMessage::create( $params );
2512  }
2513 
2514  return [
2515  $msg->getApiCode(),
2516  ApiErrorFormatter::stripMarkup( $msg->inLanguage( 'en' )->useDatabase( false )->text() )
2517  ];
2518  }
2519 
2528  private static $messageMap = [
2529  'unknownerror' => 'apierror-unknownerror',
2530  'unknownerror-nocode' => 'apierror-unknownerror-nocode',
2531  'ns-specialprotected' => 'ns-specialprotected',
2532  'protectedinterface' => 'protectedinterface',
2533  'namespaceprotected' => 'namespaceprotected',
2534  'customcssprotected' => 'customcssprotected',
2535  'customjsprotected' => 'customjsprotected',
2536  'cascadeprotected' => 'cascadeprotected',
2537  'protectedpagetext' => 'protectedpagetext',
2538  'protect-cantedit' => 'protect-cantedit',
2539  'deleteprotected' => 'deleteprotected',
2540  'badaccess-group0' => 'badaccess-group0',
2541  'badaccess-groups' => 'badaccess-groups',
2542  'titleprotected' => 'titleprotected',
2543  'nocreate-loggedin' => 'nocreate-loggedin',
2544  'nocreatetext' => 'nocreatetext',
2545  'movenologintext' => 'movenologintext',
2546  'movenotallowed' => 'movenotallowed',
2547  'confirmedittext' => 'confirmedittext',
2548  'blockedtext' => 'apierror-blocked',
2549  'autoblockedtext' => 'apierror-autoblocked',
2550  'systemblockedtext' => 'apierror-systemblocked',
2551  'actionthrottledtext' => 'apierror-ratelimited',
2552  'alreadyrolled' => 'alreadyrolled',
2553  'cantrollback' => 'cantrollback',
2554  'readonlytext' => 'readonlytext',
2555  'sessionfailure' => 'sessionfailure',
2556  'cannotdelete' => 'cannotdelete',
2557  'notanarticle' => 'apierror-missingtitle',
2558  'selfmove' => 'selfmove',
2559  'immobile_namespace' => 'apierror-immobilenamespace',
2560  'articleexists' => 'articleexists',
2561  'hookaborted' => 'hookaborted',
2562  'cantmove-titleprotected' => 'cantmove-titleprotected',
2563  'imagenocrossnamespace' => 'imagenocrossnamespace',
2564  'imagetypemismatch' => 'imagetypemismatch',
2565  'ip_range_invalid' => 'ip_range_invalid',
2566  'range_block_disabled' => 'range_block_disabled',
2567  'nosuchusershort' => 'nosuchusershort',
2568  'badipaddress' => 'badipaddress',
2569  'ipb_expiry_invalid' => 'ipb_expiry_invalid',
2570  'ipb_already_blocked' => 'ipb_already_blocked',
2571  'ipb_blocked_as_range' => 'ipb_blocked_as_range',
2572  'ipb_cant_unblock' => 'ipb_cant_unblock',
2573  'mailnologin' => 'apierror-cantsend',
2574  'ipbblocked' => 'ipbblocked',
2575  'ipbnounblockself' => 'ipbnounblockself',
2576  'usermaildisabled' => 'usermaildisabled',
2577  'blockedemailuser' => 'apierror-blockedfrommail',
2578  'notarget' => 'apierror-notarget',
2579  'noemail' => 'noemail',
2580  'rcpatroldisabled' => 'rcpatroldisabled',
2581  'markedaspatrollederror-noautopatrol' => 'markedaspatrollederror-noautopatrol',
2582  'delete-toobig' => 'delete-toobig',
2583  'movenotallowedfile' => 'movenotallowedfile',
2584  'userrights-no-interwiki' => 'userrights-no-interwiki',
2585  'userrights-nodatabase' => 'userrights-nodatabase',
2586  'nouserspecified' => 'nouserspecified',
2587  'noname' => 'noname',
2588  'summaryrequired' => 'apierror-summaryrequired',
2589  'import-rootpage-invalid' => 'import-rootpage-invalid',
2590  'import-rootpage-nosubpage' => 'import-rootpage-nosubpage',
2591  'readrequired' => 'apierror-readapidenied',
2592  'writedisabled' => 'apierror-noapiwrite',
2593  'writerequired' => 'apierror-writeapidenied',
2594  'missingparam' => 'apierror-missingparam',
2595  'invalidtitle' => 'apierror-invalidtitle',
2596  'nosuchpageid' => 'apierror-nosuchpageid',
2597  'nosuchrevid' => 'apierror-nosuchrevid',
2598  'nosuchuser' => 'nosuchusershort',
2599  'invaliduser' => 'apierror-invaliduser',
2600  'invalidexpiry' => 'apierror-invalidexpiry',
2601  'pastexpiry' => 'apierror-pastexpiry',
2602  'create-titleexists' => 'apierror-create-titleexists',
2603  'missingtitle-createonly' => 'apierror-missingtitle-createonly',
2604  'cantblock' => 'apierror-cantblock',
2605  'canthide' => 'apierror-canthide',
2606  'cantblock-email' => 'apierror-cantblock-email',
2607  'cantunblock' => 'apierror-permissiondenied-generic',
2608  'cannotundelete' => 'cannotundelete',
2609  'permdenied-undelete' => 'apierror-permissiondenied-generic',
2610  'createonly-exists' => 'apierror-articleexists',
2611  'nocreate-missing' => 'apierror-missingtitle',
2612  'cantchangecontentmodel' => 'apierror-cantchangecontentmodel',
2613  'nosuchrcid' => 'apierror-nosuchrcid',
2614  'nosuchlogid' => 'apierror-nosuchlogid',
2615  'protect-invalidaction' => 'apierror-protect-invalidaction',
2616  'protect-invalidlevel' => 'apierror-protect-invalidlevel',
2617  'toofewexpiries' => 'apierror-toofewexpiries',
2618  'cantimport' => 'apierror-cantimport',
2619  'cantimport-upload' => 'apierror-cantimport-upload',
2620  'importnofile' => 'importnofile',
2621  'importuploaderrorsize' => 'importuploaderrorsize',
2622  'importuploaderrorpartial' => 'importuploaderrorpartial',
2623  'importuploaderrortemp' => 'importuploaderrortemp',
2624  'importcantopen' => 'importcantopen',
2625  'import-noarticle' => 'import-noarticle',
2626  'importbadinterwiki' => 'importbadinterwiki',
2627  'import-unknownerror' => 'apierror-import-unknownerror',
2628  'cantoverwrite-sharedfile' => 'apierror-cantoverwrite-sharedfile',
2629  'sharedfile-exists' => 'apierror-fileexists-sharedrepo-perm',
2630  'mustbeposted' => 'apierror-mustbeposted',
2631  'show' => 'apierror-show',
2632  'specialpage-cantexecute' => 'apierror-specialpage-cantexecute',
2633  'invalidoldimage' => 'apierror-invalidoldimage',
2634  'nodeleteablefile' => 'apierror-nodeleteablefile',
2635  'fileexists-forbidden' => 'fileexists-forbidden',
2636  'fileexists-shared-forbidden' => 'fileexists-shared-forbidden',
2637  'filerevert-badversion' => 'filerevert-badversion',
2638  'noimageredirect-anon' => 'apierror-noimageredirect-anon',
2639  'noimageredirect-logged' => 'apierror-noimageredirect',
2640  'spamdetected' => 'apierror-spamdetected',
2641  'contenttoobig' => 'apierror-contenttoobig',
2642  'noedit-anon' => 'apierror-noedit-anon',
2643  'noedit' => 'apierror-noedit',
2644  'wasdeleted' => 'apierror-pagedeleted',
2645  'blankpage' => 'apierror-emptypage',
2646  'editconflict' => 'editconflict',
2647  'hashcheckfailed' => 'apierror-badmd5',
2648  'missingtext' => 'apierror-notext',
2649  'emptynewsection' => 'apierror-emptynewsection',
2650  'revwrongpage' => 'apierror-revwrongpage',
2651  'undo-failure' => 'undo-failure',
2652  'content-not-allowed-here' => 'content-not-allowed-here',
2653  'edit-hook-aborted' => 'edit-hook-aborted',
2654  'edit-gone-missing' => 'edit-gone-missing',
2655  'edit-conflict' => 'edit-conflict',
2656  'edit-already-exists' => 'edit-already-exists',
2657  'invalid-file-key' => 'apierror-invalid-file-key',
2658  'nouploadmodule' => 'apierror-nouploadmodule',
2659  'uploaddisabled' => 'uploaddisabled',
2660  'copyuploaddisabled' => 'copyuploaddisabled',
2661  'copyuploadbaddomain' => 'apierror-copyuploadbaddomain',
2662  'copyuploadbadurl' => 'apierror-copyuploadbadurl',
2663  'filename-tooshort' => 'filename-tooshort',
2664  'filename-toolong' => 'filename-toolong',
2665  'illegal-filename' => 'illegal-filename',
2666  'filetype-missing' => 'filetype-missing',
2667  'mustbeloggedin' => 'apierror-mustbeloggedin',
2668  ];
2669 
2675  private function parseMsgInternal( $error ) {
2676  $msg = Message::newFromSpecifier( $error );
2677  if ( !$msg instanceof IApiMessage ) {
2678  $key = $msg->getKey();
2679  if ( isset( self::$messageMap[$key] ) ) {
2680  $params = $msg->getParams();
2681  array_unshift( $params, self::$messageMap[$key] );
2682  } else {
2683  $params = [ 'apierror-unknownerror', wfEscapeWikiText( $key ) ];
2684  }
2685  $msg = ApiMessage::create( $params );
2686  }
2687  return $msg;
2688  }
2689 
2696  public function parseMsg( $error ) {
2697  // Check whether someone passed the whole array, instead of one element as
2698  // documented. This breaks if it's actually an array of fallback keys, but
2699  // that's long-standing misbehavior introduced in r87627 to incorrectly
2700  // fix T30797.
2701  if ( is_array( $error ) ) {
2702  $first = reset( $error );
2703  if ( is_array( $first ) ) {
2704  wfDebug( __METHOD__ . ' was passed an array of arrays. ' . wfGetAllCallers( 5 ) );
2705  $error = $first;
2706  }
2707  }
2708 
2709  $msg = $this->parseMsgInternal( $error );
2710  return [
2711  'code' => $msg->getApiCode(),
2713  $msg->inLanguage( 'en' )->useDatabase( false )->text()
2714  ),
2715  'data' => $msg->getApiData()
2716  ];
2717  }
2718 
2725  public function dieUsageMsg( $error ) {
2726  $this->dieWithError( $this->parseMsgInternal( $error ) );
2727  }
2728 
2737  public function dieUsageMsgOrDebug( $error ) {
2738  $this->dieWithErrorOrDebug( $this->parseMsgInternal( $error ) );
2739  }
2740 
2742 }
2743 
ApiBase\dieUsageMsgOrDebug
dieUsageMsgOrDebug( $error)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
Definition: ApiBase.php:2737
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:45
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:34
ContextSource\getConfig
getConfig()
Get the Config object.
Definition: ContextSource.php:68
ApiBase\PARAM_SUBMODULE_MAP
const PARAM_SUBMODULE_MAP
(string[]) When PARAM_TYPE is 'submodule', map parameter values to submodule paths.
Definition: ApiBase.php:168
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:265
ApiUsageException
Exception used to abort API execution with an error.
Definition: ApiUsageException.php:98
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:41
ApiBase\$mMainModule
ApiMain $mMainModule
Definition: ApiBase.php:222
StatusValue
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: StatusValue.php:42
ApiBase\getParent
getParent()
Get the parent of this module.
Definition: ApiBase.php:524
$request
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2612
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1720
Block\getType
getType()
Get the type of target for this particular block.
Definition: Block.php:1391
MWNamespace\getValidNamespaces
static getValidNamespaces()
Returns an array of the namespaces (by integer id) that exist on the wiki.
Definition: MWNamespace.php:264
ApiBase\getFinalParams
getFinalParams( $flags=0)
Get final list of parameters, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2041
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
(boolean) Is the parameter required?
Definition: ApiBase.php:115
ContextSource\msg
msg()
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:187
ApiBase\parseMsg
parseMsg( $error)
Return the error message related to a certain array.
Definition: ApiBase.php:2696
ApiBase\parameterNotEmpty
parameterNotEmpty( $x)
Callback function used in requireOnlyOneParameter to check whether required parameters are set.
Definition: ApiBase.php:880
ApiBase\$mModuleSource
array null bool $mModuleSource
Definition: ApiBase.php:228
captcha-old.count
count
Definition: captcha-old.py:225
ApiBase\getProfileDBTime
getProfileDBTime()
Definition: ApiBase.php:2431
ApiBase\validateToken
validateToken( $token, array $params)
Validate the supplied token.
Definition: ApiBase.php:1497
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1796
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:128
ApiBase\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiBase.php:301
ApiBase\PARAM_ALL
const PARAM_ALL
(boolean|string) When PARAM_TYPE has a defined set of values and PARAM_ISMULTI is true,...
Definition: ApiBase.php:183
ApiBase\validateTimestamp
validateTimestamp( $value, $encParamName)
Validate and normalize of parameters of type 'timestamp'.
Definition: ApiBase.php:1460
ApiBase\dieUsageMsg
dieUsageMsg( $error)
Output the error message related to a certain array.
Definition: ApiBase.php:2725
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1994
ApiBase\profileDBIn
profileDBIn()
Definition: ApiBase.php:2416
ApiBase\$extensionInfo
static array $extensionInfo
Maps extension paths to info arrays.
Definition: ApiBase.php:219
ApiBase\getTitleOrPageId
getTitleOrPageId( $params, $load=false)
Get a WikiPage object from a title or pageid param, if possible.
Definition: ApiBase.php:895
ApiBase\PARAM_TYPE
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below.
Definition: ApiBase.php:91
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:610
ApiBase\getDescriptionMessage
getDescriptionMessage()
Return the description message.
Definition: ApiBase.php:1994
MessageSpecifier
Definition: MessageSpecifier.php:21
$status
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition: hooks.txt:1049
ApiBase\__construct
__construct(ApiMain $mainModule, $moduleName, $modulePrefix='')
Definition: ApiBase.php:235
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
ApiBase\profileDBOut
profileDBOut()
Definition: ApiBase.php:2423
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:371
ApiBase\mustBePosted
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiBase.php:405
$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:246
ApiBase\logFeatureUsage
logFeatureUsage( $feature)
Write logging information for API features to a debug log, for usage analysis.
Definition: ApiBase.php:1972
ApiBase\checkUserRightsAny
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1890
ApiBase\shouldCheckMaxlag
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition: ApiBase.php:374
ApiBase\dieWithErrorOrDebug
dieWithErrorOrDebug( $msg, $code=null, $data=null, $httpCode=null)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
Definition: ApiBase.php:1933
$params
$params
Definition: styleTest.css.php:40
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:556
ApiBase\escapeWikiText
static escapeWikiText( $v)
A subset of wfEscapeWikiText for BC texts.
Definition: ApiBase.php:1618
$s
$s
Definition: mergeMessageFileList.php:188
ApiBase\getDB
getDB()
Gets a default replica DB connection object.
Definition: ApiBase.php:638
ApiBase\makeMessage
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
Definition: ApiBase.php:1642
ApiBase\addMessagesFromStatus
addMessagesFromStatus(StatusValue $status, $types=[ 'warning', 'error'])
Add warnings and/or errors from a Status.
Definition: ApiBase.php:1779
ApiBase\$mSlaveDB
$mSlaveDB
Definition: ApiBase.php:225
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:304
ContextSource\getRequest
getRequest()
Get the WebRequest object.
Definition: ContextSource.php:78
ApiBase\dynamicParameterDocumentation
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition: ApiBase.php:688
ApiBase\modifyHelp
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition: ApiBase.php:2312
$type
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition: hooks.txt:2536
ApiBase\PARAM_ALLOW_DUPLICATES
const PARAM_ALLOW_DUPLICATES
(boolean) Allow the same value to be set more than once when PARAM_ISMULTI is true?
Definition: ApiBase.php:106
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:133
IApiMessage
Interface for messages with machine-readable data for use by the API.
Definition: ApiMessage.php:35
ApiBase\getModuleProfileName
getModuleProfileName( $db=false)
Definition: ApiBase.php:2376
ApiBase\lacksSameOriginSecurity
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:538
ApiBase\PARAM_HELP_MSG_APPEND
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition: ApiBase.php:135
ApiUsageException\newWithMessage
static newWithMessage(ApiBase $module=null, $msg, $code=null, $data=null, $httpCode=0)
Definition: ApiUsageException.php:138
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1092
ApiBase\getWebUITokenSalt
getWebUITokenSalt(array $params)
Fetch the salt used in the Web UI corresponding to this module.
Definition: ApiBase.php:459
ApiBase\isMain
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition: ApiBase.php:515
ApiBase\isReadMode
isReadMode()
Indicates whether this module requires read rights.
Definition: ApiBase.php:382
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:41
ApiRawMessage
Extension of RawMessage implementing IApiMessage.
Definition: ApiMessage.php:268
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:40
ApiBase\getModuleFromPath
getModuleFromPath( $path)
Get a module from its module path.
Definition: ApiBase.php:572
ApiBase\getFinalParamDescription
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2073
ApiMessage
Extension of Message implementing IApiMessage.
Definition: ApiMessage.php:198
ApiBase\PARAM_SENSITIVE
const PARAM_SENSITIVE
(null|boolean|integer|string) Default value of the parameter.
Definition: ApiBase.php:196
ApiBase\dieBlocked
dieBlocked(Block $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition: ApiBase.php:1836
ApiBase\$messageMap
static $messageMap
Definition: ApiBase.php:2528
ApiBase\parseMultiValue
parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues, $allSpecifier=null)
Return an array of values that were given in a 'a|b|c' notation, after it optionally validates them a...
Definition: ApiBase.php:1321
ApiBase\getParamDescription
getParamDescription()
Returns an array of parameter descriptions.
Definition: ApiBase.php:2347
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:80
ApiBase\profileOut
profileOut()
Definition: ApiBase.php:2392
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
(boolean) Is the parameter deprecated (will show a warning)?
Definition: ApiBase.php:109
ApiBase\explodeMultiValue
explodeMultiValue( $value, $limit)
Split a multi-valued parameter string, like explode()
Definition: ApiBase.php:1295
ApiBase\PARAM_MIN
const PARAM_MIN
(integer) Lowest value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
Definition: ApiBase.php:103
MWException
MediaWiki exception.
Definition: MWException.php:26
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:934
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:120
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1128
ApiErrorFormatter\stripMarkup
static stripMarkup( $text)
Turn wikitext into something resembling plaintext.
Definition: ApiErrorFormatter.php:252
ApiBase\warnOrDie
warnOrDie(ApiMessage $msg, $enforceLimits=false)
Adds a warning to the output, else dies.
Definition: ApiBase.php:1820
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:286
ApiBase\getFinalDescription
getFinalDescription()
Get final module description, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2005
wfTransactionalTimeLimit
wfTransactionalTimeLimit()
Set PHP's time limit to the larger of php.ini or $wgTransactionalTimeLimit.
Definition: GlobalFunctions.php:3318
ApiBase\getModulePath
getModulePath()
Get the path to this module.
Definition: ApiBase.php:554
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3060
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:203
ApiBase\getDescription
getDescription()
Returns the description string for this module.
Definition: ApiBase.php:2331
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:30
ApiQueryTokens\getTokenTypeSalts
static getTokenTypeSalts()
Get the salts for known token types.
Definition: ApiQueryTokens.php:65
$IP
$IP
Definition: update.php:3
ApiBase\PARAM_MAX
const PARAM_MAX
(integer) Max value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
Definition: ApiBase.php:94
$limit
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers please use GetContentModels hook to make them known to core if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
Definition: hooks.txt:1049
ApiBase\dieWithException
dieWithException( $exception, array $options=[])
Abort execution with an error derived from an exception.
Definition: ApiBase.php:1808
WatchAction\doWatchOrUnwatch
static doWatchOrUnwatch( $watch, Title $title, User $user)
Watch or unwatch a page.
Definition: WatchAction.php:93
ApiBase\parseMsgInternal
parseMsgInternal( $error)
Definition: ApiBase.php:2675
ApiBase\handleParamNormalization
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition: ApiBase.php:1283
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
ApiBase\isDeprecated
isDeprecated()
Indicates whether this module is deprecated.
Definition: ApiBase.php:414
ApiMessage\create
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
Definition: ApiMessage.php:212
ApiBase\PARAM_EXTRA_NAMESPACES
const PARAM_EXTRA_NAMESPACES
(int[]) When PARAM_TYPE is 'namespace', include these as additional possible values.
Definition: ApiBase.php:189
ApiBase\ALL_DEFAULT_STRING
const ALL_DEFAULT_STRING
Definition: ApiBase.php:200
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:999
string
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:177
ContextSource\setContext
setContext(IContextSource $context)
Set the IContextSource object.
Definition: ContextSource.php:58
ApiBase\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiBase.php:348
ApiBase\validateUser
validateUser( $value, $encParamName)
Validate and normalize of parameters of type 'user'.
Definition: ApiBase.php:1532
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:960
ApiBase\needsToken
needsToken()
Returns the token type this module requires in order to execute.
Definition: ApiBase.php:446
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:498
ApiBase\$mModuleName
string $mModuleName
Definition: ApiBase.php:224
ApiBase\setWatch
setWatch( $watch, $titleObj, $userOption=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
Definition: ApiBase.php:1557
ApiBase\getContinuationManager
getContinuationManager()
Get the continuation manager.
Definition: ApiBase.php:650
$line
$line
Definition: cdb.php:58
ApiBase\addError
addError( $msg, $code=null, $data=null)
Add an error for this module without aborting.
Definition: ApiBase.php:1767
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:538
ApiBase\extractRequestParams
extractRequestParams( $parseLimit=true)
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:718
ApiBase\getWatchlistUser
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition: ApiBase.php:1588
$value
$value
Definition: styleTest.css.php:45
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1950
ApiBase\addDeprecation
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition: ApiBase.php:1734
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:76
ApiBase\LIMIT_SML2
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition: ApiBase.php:209
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:699
ApiBase\dieUsage
dieUsage( $description, $errorCode, $httpRespCode=0, $extradata=null)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition: ApiBase.php:2468
ApiBase\dieReadOnly
dieReadOnly()
Helper function for readonly errors.
Definition: ApiBase.php:1874
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:216
ApiBase\checkTitleUserPermissions
checkTitleUserPermissions(Title $title, $actions, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1908
WikiPage\newFromID
static newFromID( $id, $from='fromdb')
Constructor from a page id.
Definition: WikiPage.php:158
ApiBase\useTransactionalTimeLimit
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: ApiBase.php:2440
ApiBase\getConditionalRequestData
getConditionalRequestData( $condition)
Returns data for HTTP conditional request mechanisms.
Definition: ApiBase.php:475
ApiBase\isWriteMode
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiBase.php:397
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1657
$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:1956
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params, $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:792
ApiBase\requireOnlyOneParameter
requireOnlyOneParameter( $params, $required)
Die if none or more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:754
ApiBase\PARAM_HELP_MSG_INFO
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition: ApiBase.php:145
ApiBase\$mParamCache
$mParamCache
Definition: ApiBase.php:226
Block\TYPE_AUTO
const TYPE_AUTO
Definition: Block.php:86
ApiBase\truncateArray
static truncateArray(&$arr, $limit)
Truncate an array to a certain length.
Definition: ApiBase.php:1572
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:55
ApiBase\profileIn
profileIn()
Definition: ApiBase.php:2384
wfGetAllCallers
wfGetAllCallers( $limit=3)
Return a string consisting of callers in the stack.
Definition: GlobalFunctions.php:1577
ApiBase\PARAM_RANGE_ENFORCE
const PARAM_RANGE_ENFORCE
(boolean) For PARAM_TYPE 'integer', enforce PARAM_MIN and PARAM_MAX?
Definition: ApiBase.php:121
ApiBase\PARAM_VALUE_LINKS
const PARAM_VALUE_LINKS
(string[]) When PARAM_TYPE is an array, this may be an array mapping those values to page titles whic...
Definition: ApiBase.php:152
ChangeTags\canAddTagsAccompanyingChange
static canAddTagsAccompanyingChange(array $tags, User $user=null)
Is it OK to allow the user to apply all the specified tags at the same time as they edit/make the cha...
Definition: ChangeTags.php:395
ApiBase\requireAtLeastOneParameter
requireAtLeastOneParameter( $params, $required)
Die if none of a certain set of parameters is set and not false.
Definition: ApiBase.php:820
ApiBase\setWarning
setWarning( $warning)
Definition: ApiBase.php:2450
Title
Represents a title within MediaWiki.
Definition: Title.php:39
ApiBase\getProfileTime
getProfileTime()
Definition: ApiBase.php:2408
ApiBase\setContinuationManager
setContinuationManager( $manager)
Set the continuation manager.
Definition: ApiBase.php:664
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:205
wfReadOnlyReason
wfReadOnlyReason()
Check if the site is in read-only mode and return the message if so.
Definition: GlobalFunctions.php:1290
ApiQueryTokens\getToken
static getToken(User $user, MediaWiki\Session\Session $session, $salt)
Get a token from a salt.
Definition: ApiQueryTokens.php:96
ApiBase\getModuleManager
getModuleManager()
Get the module manager, or null if this module has no sub-modules.
Definition: ApiBase.php:273
$ext
$ext
Definition: NoLocalSettings.php:25
$code
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
Definition: hooks.txt:783
ApiBase\isInternal
isInternal()
Indicates whether this module is "internal" Internal API modules are not (yet) intended for 3rd party...
Definition: ApiBase.php:424
ApiBase\getModuleSourceInfo
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition: ApiBase.php:2223
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:1407
$path
$path
Definition: NoLocalSettings.php:26
ApiBase\PARAM_DFLT
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
Definition: ApiBase.php:52
ApiBase\getParameter
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition: ApiBase.php:742
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()
Definition: ApiBase.php:2400
Block
Definition: Block.php:27
ApiBase\dieStatus
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1861
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:490
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
Definition: ApiBase.php:55
NS_USER
const NS_USER
Definition: Defines.php:64
ApiBase\PARAM_MAX2
const PARAM_MAX2
(integer) Max value allowed for the parameter for users with the apihighlimits right,...
Definition: ApiBase.php:100
ApiBase\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiBase.php:364
$help
$help
Definition: mcc.php:32
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:506
ApiBase\getParameterFromSettings
getParameterFromSettings( $paramName, $paramSettings, $parseLimit)
Using the settings determine the value for the given parameter.
Definition: ApiBase.php:1002
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation 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\getTitleFromTitleOrPageId
getTitleFromTitleOrPageId( $params)
Get a Title object from a title or pageid param, if possible.
Definition: ApiBase.php:932
User\IGNORE_USER_RIGHTS
const IGNORE_USER_RIGHTS
Definition: User.php:87
ApiBase\getExamples
getExamples()
Returns usage examples for this module.
Definition: ApiBase.php:2367
ApiBase\$mModulePrefix
string $mModulePrefix
Definition: ApiBase.php:224
ApiBase\PARAM_HELP_MSG_PER_VALUE
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:160
ApiBase\PARAM_SUBMODULE_PARAM_PREFIX
const PARAM_SUBMODULE_PARAM_PREFIX
(string) When PARAM_TYPE is 'submodule', used to indicate the 'g' prefix added by ApiQueryGeneratorBa...
Definition: ApiBase.php:175
ApiHelpParamValueMessage
Message subclass that prepends wikitext for API help.
Definition: ApiHelpParamValueMessage.php:36
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:50
Title\newFromID
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:405
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1962
ApiBase\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
ApiBase\errorArrayToStatus
errorArrayToStatus(array $errors, User $user=null)
Turn an array of message keys or key+param arrays into a Status.
Definition: ApiBase.php:1667
ApiBase\getErrorFormatter
getErrorFormatter()
Get the error formatter.
Definition: ApiBase.php:624
$options
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1049
ApiBase\requirePostedParameters
requirePostedParameters( $params, $prefix='prefix')
Die if any of the specified parameters were found in the query part of the URL rather than the post b...
Definition: ApiBase.php:850
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2749
ApiQueryUserInfo\getBlockInfo
static getBlockInfo(Block $block)
Get basic info about a given block.
Definition: ApiQueryUserInfo.php:69
ApiBase\getErrorFromStatus
getErrorFromStatus( $status, &$extraData=null)
Get error (as code, string) from a Status object.
Definition: ApiBase.php:2487
ApiBase\LIMIT_SML1
const LIMIT_SML1
Slow query, standard limit.
Definition: ApiBase.php:207
array
the array() calling protocol came about after MediaWiki 1.4rc1.
ApiBase\getHelpFlags
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition: ApiBase.php:2190