MediaWiki  1.33.1
ApiBase.php
Go to the documentation of this file.
1 <?php
24 
37 abstract class ApiBase extends ContextSource {
38 
48  const PARAM_DFLT = 0;
49 
51  const PARAM_ISMULTI = 1;
52 
87  const PARAM_TYPE = 2;
88 
90  const PARAM_MAX = 3;
91 
96  const PARAM_MAX2 = 4;
97 
99  const PARAM_MIN = 5;
100 
103 
105  const PARAM_DEPRECATED = 7;
106 
111  const PARAM_REQUIRED = 8;
112 
118 
124  const PARAM_HELP_MSG = 10;
125 
132 
142 
148  const PARAM_VALUE_LINKS = 13;
149 
158 
166 
173 
180  const PARAM_ALL = 17;
181 
187 
193  const PARAM_SENSITIVE = 19;
194 
203 
209 
216 
221  const PARAM_MAX_BYTES = 23;
222 
227  const PARAM_MAX_CHARS = 24;
228 
246 
249  const ALL_DEFAULT_STRING = '*';
250 
252  const LIMIT_BIG1 = 500;
254  const LIMIT_BIG2 = 5000;
256  const LIMIT_SML1 = 50;
258  const LIMIT_SML2 = 500;
259 
266 
268  private static $extensionInfo = null;
269 
271  private static $filterIDsCache = [];
272 
274  private static $blockMsgMap = [
275  'blockedtext' => [ 'apierror-blocked', 'blocked' ],
276  'blockedtext-partial' => [ 'apierror-blocked', 'blocked' ],
277  'autoblockedtext' => [ 'apierror-autoblocked', 'autoblocked' ],
278  'systemblockedtext' => [ 'apierror-systemblocked', 'blocked' ],
279  ];
280 
282  private $mMainModule;
285  private $mReplicaDB = null;
286  private $mParamCache = [];
288  private $mModuleSource = false;
289 
295  public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
296  $this->mMainModule = $mainModule;
297  $this->mModuleName = $moduleName;
298  $this->mModulePrefix = $modulePrefix;
299 
300  if ( !$this->isMain() ) {
301  $this->setContext( $mainModule->getContext() );
302  }
303  }
304 
305  /************************************************************************/
326  abstract public function execute();
327 
333  public function getModuleManager() {
334  return null;
335  }
336 
346  public function getCustomPrinter() {
347  return null;
348  }
349 
361  protected function getExamplesMessages() {
362  return [];
363  }
364 
370  public function getHelpUrls() {
371  return [];
372  }
373 
386  protected function getAllowedParams( /* $flags = 0 */ ) {
387  // int $flags is not declared because it causes "Strict standards"
388  // warning. Most derived classes do not implement it.
389  return [];
390  }
391 
396  public function shouldCheckMaxlag() {
397  return true;
398  }
399 
404  public function isReadMode() {
405  return true;
406  }
407 
419  public function isWriteMode() {
420  return false;
421  }
422 
427  public function mustBePosted() {
428  return $this->needsToken() !== false;
429  }
430 
436  public function isDeprecated() {
437  return false;
438  }
439 
446  public function isInternal() {
447  return false;
448  }
449 
468  public function needsToken() {
469  return false;
470  }
471 
481  protected function getWebUITokenSalt( array $params ) {
482  return null;
483  }
484 
497  public function getConditionalRequestData( $condition ) {
498  return null;
499  }
500 
503  /************************************************************************/
512  public function getModuleName() {
513  return $this->mModuleName;
514  }
515 
520  public function getModulePrefix() {
521  return $this->mModulePrefix;
522  }
523 
528  public function getMain() {
529  return $this->mMainModule;
530  }
531 
537  public function isMain() {
538  return $this === $this->mMainModule;
539  }
540 
546  public function getParent() {
547  return $this->isMain() ? null : $this->getMain();
548  }
549 
560  public function lacksSameOriginSecurity() {
561  // Main module has this method overridden
562  // Safety - avoid infinite loop:
563  if ( $this->isMain() ) {
564  self::dieDebug( __METHOD__, 'base method was called on main module.' );
565  }
566 
567  return $this->getMain()->lacksSameOriginSecurity();
568  }
569 
576  public function getModulePath() {
577  if ( $this->isMain() ) {
578  return 'main';
579  } elseif ( $this->getParent()->isMain() ) {
580  return $this->getModuleName();
581  } else {
582  return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
583  }
584  }
585 
594  public function getModuleFromPath( $path ) {
595  $module = $this->getMain();
596  if ( $path === 'main' ) {
597  return $module;
598  }
599 
600  $parts = explode( '+', $path );
601  if ( count( $parts ) === 1 ) {
602  // In case the '+' was typed into URL, it resolves as a space
603  $parts = explode( ' ', $path );
604  }
605 
606  $count = count( $parts );
607  for ( $i = 0; $i < $count; $i++ ) {
608  $parent = $module;
609  $manager = $parent->getModuleManager();
610  if ( $manager === null ) {
611  $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
612  $this->dieWithError( [ 'apierror-badmodule-nosubmodules', $errorPath ], 'badmodule' );
613  }
614  $module = $manager->getModule( $parts[$i] );
615 
616  if ( $module === null ) {
617  $errorPath = $i ? implode( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
618  $this->dieWithError(
619  [ 'apierror-badmodule-badsubmodule', $errorPath, wfEscapeWikiText( $parts[$i] ) ],
620  'badmodule'
621  );
622  }
623  }
624 
625  return $module;
626  }
627 
632  public function getResult() {
633  // Main module has getResult() method overridden
634  // Safety - avoid infinite loop:
635  if ( $this->isMain() ) {
636  self::dieDebug( __METHOD__, 'base method was called on main module. ' );
637  }
638 
639  return $this->getMain()->getResult();
640  }
641 
646  public function getErrorFormatter() {
647  // Main module has getErrorFormatter() method overridden
648  // Safety - avoid infinite loop:
649  if ( $this->isMain() ) {
650  self::dieDebug( __METHOD__, 'base method was called on main module. ' );
651  }
652 
653  return $this->getMain()->getErrorFormatter();
654  }
655 
660  protected function getDB() {
661  if ( !isset( $this->mReplicaDB ) ) {
662  $this->mReplicaDB = wfGetDB( DB_REPLICA, 'api' );
663  }
664 
665  return $this->mReplicaDB;
666  }
667 
672  public function getContinuationManager() {
673  // Main module has getContinuationManager() method overridden
674  // Safety - avoid infinite loop:
675  if ( $this->isMain() ) {
676  self::dieDebug( __METHOD__, 'base method was called on main module. ' );
677  }
678 
679  return $this->getMain()->getContinuationManager();
680  }
681 
686  public function setContinuationManager( ApiContinuationManager $manager = null ) {
687  // Main module has setContinuationManager() method overridden
688  // Safety - avoid infinite loop:
689  if ( $this->isMain() ) {
690  self::dieDebug( __METHOD__, 'base method was called on main module. ' );
691  }
692 
693  $this->getMain()->setContinuationManager( $manager );
694  }
695 
698  /************************************************************************/
710  public function dynamicParameterDocumentation() {
711  return null;
712  }
713 
721  public function encodeParamName( $paramName ) {
722  if ( is_array( $paramName ) ) {
723  return array_map( function ( $name ) {
724  return $this->mModulePrefix . $name;
725  }, $paramName );
726  } else {
727  return $this->mModulePrefix . $paramName;
728  }
729  }
730 
743  public function extractRequestParams( $options = [] ) {
744  if ( is_bool( $options ) ) {
745  $options = [ 'parseLimit' => $options ];
746  }
747  $options += [
748  'parseLimit' => true,
749  'safeMode' => false,
750  ];
751 
752  $parseLimit = (bool)$options['parseLimit'];
753 
754  // Cache parameters, for performance and to avoid T26564.
755  if ( !isset( $this->mParamCache[$parseLimit] ) ) {
756  $params = $this->getFinalParams() ?: [];
757  $results = [];
758  $warned = [];
759 
760  // Process all non-templates and save templates for secondary
761  // processing.
762  $toProcess = [];
763  foreach ( $params as $paramName => $paramSettings ) {
764  if ( isset( $paramSettings[self::PARAM_TEMPLATE_VARS] ) ) {
765  $toProcess[] = [ $paramName, $paramSettings[self::PARAM_TEMPLATE_VARS], $paramSettings ];
766  } else {
767  try {
768  $results[$paramName] = $this->getParameterFromSettings(
769  $paramName, $paramSettings, $parseLimit
770  );
771  } catch ( ApiUsageException $ex ) {
772  $results[$paramName] = $ex;
773  }
774  }
775  }
776 
777  // Now process all the templates by successively replacing the
778  // placeholders with all client-supplied values.
779  // This bit duplicates JavaScript logic in
780  // ApiSandbox.PageLayout.prototype.updateTemplatedParams().
781  // If you update this, see if that needs updating too.
782  while ( $toProcess ) {
783  list( $name, $targets, $settings ) = array_shift( $toProcess );
784 
785  foreach ( $targets as $placeholder => $target ) {
786  if ( !array_key_exists( $target, $results ) ) {
787  // The target wasn't processed yet, try the next one.
788  // If all hit this case, the parameter has no expansions.
789  continue;
790  }
791  if ( !is_array( $results[$target] ) || !$results[$target] ) {
792  // The target was processed but has no (valid) values.
793  // That means it has no expansions.
794  break;
795  }
796 
797  // Expand this target in the name and all other targets,
798  // then requeue if there are more targets left or put in
799  // $results if all are done.
800  unset( $targets[$placeholder] );
801  $placeholder = '{' . $placeholder . '}';
802  // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
803  foreach ( $results[$target] as $value ) {
804  if ( !preg_match( '/^[^{}]*$/', $value ) ) {
805  // Skip values that make invalid parameter names.
806  $encTargetName = $this->encodeParamName( $target );
807  if ( !isset( $warned[$encTargetName][$value] ) ) {
808  $warned[$encTargetName][$value] = true;
809  $this->addWarning( [
810  'apiwarn-ignoring-invalid-templated-value',
811  wfEscapeWikiText( $encTargetName ),
813  ] );
814  }
815  continue;
816  }
817 
818  $newName = str_replace( $placeholder, $value, $name );
819  if ( !$targets ) {
820  try {
821  $results[$newName] = $this->getParameterFromSettings( $newName, $settings, $parseLimit );
822  } catch ( ApiUsageException $ex ) {
823  $results[$newName] = $ex;
824  }
825  } else {
826  $newTargets = [];
827  foreach ( $targets as $k => $v ) {
828  $newTargets[$k] = str_replace( $placeholder, $value, $v );
829  }
830  $toProcess[] = [ $newName, $newTargets, $settings ];
831  }
832  }
833  break;
834  }
835  }
836 
837  $this->mParamCache[$parseLimit] = $results;
838  }
839 
840  $ret = $this->mParamCache[$parseLimit];
841  if ( !$options['safeMode'] ) {
842  foreach ( $ret as $v ) {
843  if ( $v instanceof ApiUsageException ) {
844  throw $v;
845  }
846  }
847  }
848 
849  return $this->mParamCache[$parseLimit];
850  }
851 
858  protected function getParameter( $paramName, $parseLimit = true ) {
859  $ret = $this->extractRequestParams( [
860  'parseLimit' => $parseLimit,
861  'safeMode' => true,
862  ] )[$paramName];
863  if ( $ret instanceof ApiUsageException ) {
864  throw $ret;
865  }
866  return $ret;
867  }
868 
875  public function requireOnlyOneParameter( $params, $required /*...*/ ) {
876  $required = func_get_args();
877  array_shift( $required );
878 
879  $intersection = array_intersect( array_keys( array_filter( $params,
880  [ $this, 'parameterNotEmpty' ] ) ), $required );
881 
882  if ( count( $intersection ) > 1 ) {
883  $this->dieWithError( [
884  'apierror-invalidparammix',
885  Message::listParam( array_map(
886  function ( $p ) {
887  return '<var>' . $this->encodeParamName( $p ) . '</var>';
888  },
889  array_values( $intersection )
890  ) ),
891  count( $intersection ),
892  ] );
893  } elseif ( count( $intersection ) == 0 ) {
894  $this->dieWithError( [
895  'apierror-missingparam-one-of',
896  Message::listParam( array_map(
897  function ( $p ) {
898  return '<var>' . $this->encodeParamName( $p ) . '</var>';
899  },
900  array_values( $required )
901  ) ),
902  count( $required ),
903  ], 'missingparam' );
904  }
905  }
906 
913  public function requireMaxOneParameter( $params, $required /*...*/ ) {
914  $required = func_get_args();
915  array_shift( $required );
916 
917  $intersection = array_intersect( array_keys( array_filter( $params,
918  [ $this, 'parameterNotEmpty' ] ) ), $required );
919 
920  if ( count( $intersection ) > 1 ) {
921  $this->dieWithError( [
922  'apierror-invalidparammix',
923  Message::listParam( array_map(
924  function ( $p ) {
925  return '<var>' . $this->encodeParamName( $p ) . '</var>';
926  },
927  array_values( $intersection )
928  ) ),
929  count( $intersection ),
930  ] );
931  }
932  }
933 
941  public function requireAtLeastOneParameter( $params, $required /*...*/ ) {
942  $required = func_get_args();
943  array_shift( $required );
944 
945  $intersection = array_intersect(
946  array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
947  $required
948  );
949 
950  if ( count( $intersection ) == 0 ) {
951  $this->dieWithError( [
952  'apierror-missingparam-at-least-one-of',
953  Message::listParam( array_map(
954  function ( $p ) {
955  return '<var>' . $this->encodeParamName( $p ) . '</var>';
956  },
957  array_values( $required )
958  ) ),
959  count( $required ),
960  ], 'missingparam' );
961  }
962  }
963 
971  public function requirePostedParameters( $params, $prefix = 'prefix' ) {
972  // Skip if $wgDebugAPI is set or we're in internal mode
973  if ( $this->getConfig()->get( 'DebugAPI' ) || $this->getMain()->isInternalMode() ) {
974  return;
975  }
976 
977  $queryValues = $this->getRequest()->getQueryValues();
978  $badParams = [];
979  foreach ( $params as $param ) {
980  if ( $prefix !== 'noprefix' ) {
981  $param = $this->encodeParamName( $param );
982  }
983  if ( array_key_exists( $param, $queryValues ) ) {
984  $badParams[] = $param;
985  }
986  }
987 
988  if ( $badParams ) {
989  $this->dieWithError(
990  [ 'apierror-mustpostparams', implode( ', ', $badParams ), count( $badParams ) ]
991  );
992  }
993  }
994 
1001  private function parameterNotEmpty( $x ) {
1002  return !is_null( $x ) && $x !== false;
1003  }
1004 
1016  public function getTitleOrPageId( $params, $load = false ) {
1017  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1018 
1019  $pageObj = null;
1020  if ( isset( $params['title'] ) ) {
1021  $titleObj = Title::newFromText( $params['title'] );
1022  if ( !$titleObj || $titleObj->isExternal() ) {
1023  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1024  }
1025  if ( !$titleObj->canExist() ) {
1026  $this->dieWithError( 'apierror-pagecannotexist' );
1027  }
1028  $pageObj = WikiPage::factory( $titleObj );
1029  if ( $load !== false ) {
1030  $pageObj->loadPageData( $load );
1031  }
1032  } elseif ( isset( $params['pageid'] ) ) {
1033  if ( $load === false ) {
1034  $load = 'fromdb';
1035  }
1036  $pageObj = WikiPage::newFromID( $params['pageid'], $load );
1037  if ( !$pageObj ) {
1038  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1039  }
1040  }
1041 
1042  return $pageObj;
1043  }
1044 
1053  public function getTitleFromTitleOrPageId( $params ) {
1054  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1055 
1056  $titleObj = null;
1057  if ( isset( $params['title'] ) ) {
1058  $titleObj = Title::newFromText( $params['title'] );
1059  if ( !$titleObj || $titleObj->isExternal() ) {
1060  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1061  }
1062  return $titleObj;
1063  } elseif ( isset( $params['pageid'] ) ) {
1064  $titleObj = Title::newFromID( $params['pageid'] );
1065  if ( !$titleObj ) {
1066  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1067  }
1068  }
1069 
1070  return $titleObj;
1071  }
1072 
1081  protected function getWatchlistValue( $watchlist, $titleObj, $userOption = null ) {
1082  $userWatching = $this->getUser()->isWatched( $titleObj, User::IGNORE_USER_RIGHTS );
1083 
1084  switch ( $watchlist ) {
1085  case 'watch':
1086  return true;
1087 
1088  case 'unwatch':
1089  return false;
1090 
1091  case 'preferences':
1092  # If the user is already watching, don't bother checking
1093  if ( $userWatching ) {
1094  return true;
1095  }
1096  # If no user option was passed, use watchdefault and watchcreations
1097  if ( is_null( $userOption ) ) {
1098  return $this->getUser()->getBoolOption( 'watchdefault' ) ||
1099  $this->getUser()->getBoolOption( 'watchcreations' ) && !$titleObj->exists();
1100  }
1101 
1102  # Watch the article based on the user preference
1103  return $this->getUser()->getBoolOption( $userOption );
1104 
1105  case 'nochange':
1106  return $userWatching;
1107 
1108  default:
1109  return $userWatching;
1110  }
1111  }
1112 
1122  protected function getParameterFromSettings( $paramName, $paramSettings, $parseLimit ) {
1123  // Some classes may decide to change parameter names
1124  $encParamName = $this->encodeParamName( $paramName );
1125 
1126  // Shorthand
1127  if ( !is_array( $paramSettings ) ) {
1128  $paramSettings = [
1129  self::PARAM_DFLT => $paramSettings,
1130  ];
1131  }
1132 
1133  $default = $paramSettings[self::PARAM_DFLT] ?? null;
1134  $multi = $paramSettings[self::PARAM_ISMULTI] ?? false;
1135  $multiLimit1 = $paramSettings[self::PARAM_ISMULTI_LIMIT1] ?? null;
1136  $multiLimit2 = $paramSettings[self::PARAM_ISMULTI_LIMIT2] ?? null;
1137  $type = $paramSettings[self::PARAM_TYPE] ?? null;
1138  $dupes = $paramSettings[self::PARAM_ALLOW_DUPLICATES] ?? false;
1139  $deprecated = $paramSettings[self::PARAM_DEPRECATED] ?? false;
1140  $deprecatedValues = $paramSettings[self::PARAM_DEPRECATED_VALUES] ?? [];
1141  $required = $paramSettings[self::PARAM_REQUIRED] ?? false;
1142  $allowAll = $paramSettings[self::PARAM_ALL] ?? false;
1143 
1144  // When type is not given, and no choices, the type is the same as $default
1145  if ( !isset( $type ) ) {
1146  if ( isset( $default ) ) {
1147  $type = gettype( $default );
1148  } else {
1149  $type = 'NULL'; // allow everything
1150  }
1151  }
1152 
1153  if ( $type == 'password' || !empty( $paramSettings[self::PARAM_SENSITIVE] ) ) {
1154  $this->getMain()->markParamsSensitive( $encParamName );
1155  }
1156 
1157  if ( $type == 'boolean' ) {
1158  if ( isset( $default ) && $default !== false ) {
1159  // Having a default value of anything other than 'false' is not allowed
1161  __METHOD__,
1162  "Boolean param $encParamName's default is set to '$default'. " .
1163  'Boolean parameters must default to false.'
1164  );
1165  }
1166 
1167  $value = $this->getMain()->getCheck( $encParamName );
1168  $provided = $value;
1169  } elseif ( $type == 'upload' ) {
1170  if ( isset( $default ) ) {
1171  // Having a default value is not allowed
1173  __METHOD__,
1174  "File upload param $encParamName's default is set to " .
1175  "'$default'. File upload parameters may not have a default." );
1176  }
1177  if ( $multi ) {
1178  self::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1179  }
1180  $value = $this->getMain()->getUpload( $encParamName );
1181  $provided = $value->exists();
1182  if ( !$value->exists() ) {
1183  // This will get the value without trying to normalize it
1184  // (because trying to normalize a large binary file
1185  // accidentally uploaded as a field fails spectacularly)
1186  $value = $this->getMain()->getRequest()->unsetVal( $encParamName );
1187  if ( $value !== null ) {
1188  $this->dieWithError(
1189  [ 'apierror-badupload', $encParamName ],
1190  "badupload_{$encParamName}"
1191  );
1192  }
1193  }
1194  } else {
1195  $value = $this->getMain()->getVal( $encParamName, $default );
1196  $provided = $this->getMain()->getCheck( $encParamName );
1197 
1198  if ( isset( $value ) && $type == 'namespace' ) {
1200  if ( isset( $paramSettings[self::PARAM_EXTRA_NAMESPACES] ) &&
1201  is_array( $paramSettings[self::PARAM_EXTRA_NAMESPACES] )
1202  ) {
1203  $type = array_merge( $type, $paramSettings[self::PARAM_EXTRA_NAMESPACES] );
1204  }
1205  // Namespace parameters allow ALL_DEFAULT_STRING to be used to
1206  // specify all namespaces irrespective of PARAM_ALL.
1207  $allowAll = true;
1208  }
1209  if ( isset( $value ) && $type == 'submodule' ) {
1210  if ( isset( $paramSettings[self::PARAM_SUBMODULE_MAP] ) ) {
1211  $type = array_keys( $paramSettings[self::PARAM_SUBMODULE_MAP] );
1212  } else {
1213  $type = $this->getModuleManager()->getNames( $paramName );
1214  }
1215  }
1216 
1217  $request = $this->getMain()->getRequest();
1218  $rawValue = $request->getRawVal( $encParamName );
1219  if ( $rawValue === null ) {
1220  $rawValue = $default;
1221  }
1222 
1223  // Preserve U+001F for self::parseMultiValue(), or error out if that won't be called
1224  if ( isset( $value ) && substr( $rawValue, 0, 1 ) === "\x1f" ) {
1225  if ( $multi ) {
1226  // This loses the potential checkTitleEncoding() transformation done by
1227  // WebRequest for $_GET. Let's call that a feature.
1228  $value = implode( "\x1f", $request->normalizeUnicode( explode( "\x1f", $rawValue ) ) );
1229  } else {
1230  $this->dieWithError( 'apierror-badvalue-notmultivalue', 'badvalue_notmultivalue' );
1231  }
1232  }
1233 
1234  // Check for NFC normalization, and warn
1235  if ( $rawValue !== $value ) {
1236  $this->handleParamNormalization( $paramName, $value, $rawValue );
1237  }
1238  }
1239 
1240  $allSpecifier = ( is_string( $allowAll ) ? $allowAll : self::ALL_DEFAULT_STRING );
1241  if ( $allowAll && $multi && is_array( $type ) && in_array( $allSpecifier, $type, true ) ) {
1243  __METHOD__,
1244  "For param $encParamName, PARAM_ALL collides with a possible value" );
1245  }
1246  if ( isset( $value ) && ( $multi || is_array( $type ) ) ) {
1247  $value = $this->parseMultiValue(
1248  $encParamName,
1249  $value,
1250  $multi,
1251  is_array( $type ) ? $type : null,
1252  $allowAll ? $allSpecifier : null,
1253  $multiLimit1,
1254  $multiLimit2
1255  );
1256  }
1257 
1258  if ( isset( $value ) ) {
1259  // More validation only when choices were not given
1260  // choices were validated in parseMultiValue()
1261  if ( !is_array( $type ) ) {
1262  switch ( $type ) {
1263  case 'NULL': // nothing to do
1264  break;
1265  case 'string':
1266  case 'text':
1267  case 'password':
1268  if ( $required && $value === '' ) {
1269  $this->dieWithError( [ 'apierror-missingparam', $encParamName ] );
1270  }
1271  break;
1272  case 'integer': // Force everything using intval() and optionally validate limits
1273  $min = $paramSettings[self::PARAM_MIN] ?? null;
1274  $max = $paramSettings[self::PARAM_MAX] ?? null;
1275  $enforceLimits = $paramSettings[self::PARAM_RANGE_ENFORCE] ?? false;
1276 
1277  if ( is_array( $value ) ) {
1278  $value = array_map( 'intval', $value );
1279  if ( !is_null( $min ) || !is_null( $max ) ) {
1280  foreach ( $value as &$v ) {
1281  $this->validateLimit( $paramName, $v, $min, $max, null, $enforceLimits );
1282  }
1283  }
1284  } else {
1285  $value = (int)$value;
1286  if ( !is_null( $min ) || !is_null( $max ) ) {
1287  $this->validateLimit( $paramName, $value, $min, $max, null, $enforceLimits );
1288  }
1289  }
1290  break;
1291  case 'limit':
1292  if ( !$parseLimit ) {
1293  // Don't do any validation whatsoever
1294  break;
1295  }
1296  if ( !isset( $paramSettings[self::PARAM_MAX] )
1297  || !isset( $paramSettings[self::PARAM_MAX2] )
1298  ) {
1300  __METHOD__,
1301  "MAX1 or MAX2 are not defined for the limit $encParamName"
1302  );
1303  }
1304  if ( $multi ) {
1305  self::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1306  }
1307  $min = $paramSettings[self::PARAM_MIN] ?? 0;
1308  if ( $value == 'max' ) {
1309  $value = $this->getMain()->canApiHighLimits()
1310  ? $paramSettings[self::PARAM_MAX2]
1311  : $paramSettings[self::PARAM_MAX];
1312  $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1313  } else {
1314  $value = (int)$value;
1315  $this->validateLimit(
1316  $paramName,
1317  $value,
1318  $min,
1319  $paramSettings[self::PARAM_MAX],
1320  $paramSettings[self::PARAM_MAX2]
1321  );
1322  }
1323  break;
1324  case 'boolean':
1325  if ( $multi ) {
1326  self::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1327  }
1328  break;
1329  case 'timestamp':
1330  if ( is_array( $value ) ) {
1331  foreach ( $value as $key => $val ) {
1332  $value[$key] = $this->validateTimestamp( $val, $encParamName );
1333  }
1334  } else {
1335  $value = $this->validateTimestamp( $value, $encParamName );
1336  }
1337  break;
1338  case 'user':
1339  if ( is_array( $value ) ) {
1340  foreach ( $value as $key => $val ) {
1341  $value[$key] = $this->validateUser( $val, $encParamName );
1342  }
1343  } else {
1344  $value = $this->validateUser( $value, $encParamName );
1345  }
1346  break;
1347  case 'upload': // nothing to do
1348  break;
1349  case 'tags':
1350  // If change tagging was requested, check that the tags are valid.
1351  if ( !is_array( $value ) && !$multi ) {
1352  $value = [ $value ];
1353  }
1355  if ( !$tagsStatus->isGood() ) {
1356  $this->dieStatus( $tagsStatus );
1357  }
1358  break;
1359  default:
1360  self::dieDebug( __METHOD__, "Param $encParamName's type is unknown - $type" );
1361  }
1362  }
1363 
1364  // Throw out duplicates if requested
1365  if ( !$dupes && is_array( $value ) ) {
1366  $value = array_unique( $value );
1367  }
1368 
1369  if ( in_array( $type, [ 'NULL', 'string', 'text', 'password' ], true ) ) {
1370  foreach ( (array)$value as $val ) {
1371  if ( isset( $paramSettings[self::PARAM_MAX_BYTES] )
1372  && strlen( $val ) > $paramSettings[self::PARAM_MAX_BYTES]
1373  ) {
1374  $this->dieWithError( [ 'apierror-maxbytes', $encParamName,
1375  $paramSettings[self::PARAM_MAX_BYTES] ] );
1376  }
1377  if ( isset( $paramSettings[self::PARAM_MAX_CHARS] )
1378  && mb_strlen( $val, 'UTF-8' ) > $paramSettings[self::PARAM_MAX_CHARS]
1379  ) {
1380  $this->dieWithError( [ 'apierror-maxchars', $encParamName,
1381  $paramSettings[self::PARAM_MAX_CHARS] ] );
1382  }
1383  }
1384  }
1385 
1386  // Set a warning if a deprecated parameter has been passed
1387  if ( $deprecated && $provided ) {
1388  $feature = $encParamName;
1389  $m = $this;
1390  while ( !$m->isMain() ) {
1391  $p = $m->getParent();
1392  $name = $m->getModuleName();
1393  $param = $p->encodeParamName( $p->getModuleManager()->getModuleGroup( $name ) );
1394  $feature = "{$param}={$name}&{$feature}";
1395  $m = $p;
1396  }
1397  $this->addDeprecation( [ 'apiwarn-deprecation-parameter', $encParamName ], $feature );
1398  }
1399 
1400  // Set a warning if a deprecated parameter value has been passed
1401  $usedDeprecatedValues = $deprecatedValues && $provided
1402  ? array_intersect( array_keys( $deprecatedValues ), (array)$value )
1403  : [];
1404  if ( $usedDeprecatedValues ) {
1405  $feature = "$encParamName=";
1406  $m = $this;
1407  while ( !$m->isMain() ) {
1408  $p = $m->getParent();
1409  $name = $m->getModuleName();
1410  $param = $p->encodeParamName( $p->getModuleManager()->getModuleGroup( $name ) );
1411  $feature = "{$param}={$name}&{$feature}";
1412  $m = $p;
1413  }
1414  foreach ( $usedDeprecatedValues as $v ) {
1415  $msg = $deprecatedValues[$v];
1416  if ( $msg === true ) {
1417  $msg = [ 'apiwarn-deprecation-parameter', "$encParamName=$v" ];
1418  }
1419  $this->addDeprecation( $msg, "$feature$v" );
1420  }
1421  }
1422  } elseif ( $required ) {
1423  $this->dieWithError( [ 'apierror-missingparam', $encParamName ] );
1424  }
1425 
1426  return $value;
1427  }
1428 
1436  protected function handleParamNormalization( $paramName, $value, $rawValue ) {
1437  $encParamName = $this->encodeParamName( $paramName );
1438  $this->addWarning( [ 'apiwarn-badutf8', $encParamName ] );
1439  }
1440 
1448  protected function explodeMultiValue( $value, $limit ) {
1449  if ( substr( $value, 0, 1 ) === "\x1f" ) {
1450  $sep = "\x1f";
1451  $value = substr( $value, 1 );
1452  } else {
1453  $sep = '|';
1454  }
1455 
1456  return explode( $sep, $value, $limit );
1457  }
1458 
1476  protected function parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues,
1477  $allSpecifier = null, $limit1 = null, $limit2 = null
1478  ) {
1479  if ( ( $value === '' || $value === "\x1f" ) && $allowMultiple ) {
1480  return [];
1481  }
1482  $limit1 = $limit1 ?: self::LIMIT_SML1;
1483  $limit2 = $limit2 ?: self::LIMIT_SML2;
1484 
1485  // This is a bit awkward, but we want to avoid calling canApiHighLimits()
1486  // because it unstubs $wgUser
1487  $valuesList = $this->explodeMultiValue( $value, $limit2 + 1 );
1488  $sizeLimit = count( $valuesList ) > $limit1 && $this->mMainModule->canApiHighLimits()
1489  ? $limit2
1490  : $limit1;
1491 
1492  if ( $allowMultiple && is_array( $allowedValues ) && $allSpecifier &&
1493  count( $valuesList ) === 1 && $valuesList[0] === $allSpecifier
1494  ) {
1495  return $allowedValues;
1496  }
1497 
1498  if ( count( $valuesList ) > $sizeLimit ) {
1499  $this->dieWithError(
1500  [ 'apierror-toomanyvalues', $valueName, $sizeLimit ],
1501  "too-many-$valueName"
1502  );
1503  }
1504 
1505  if ( !$allowMultiple && count( $valuesList ) != 1 ) {
1506  // T35482 - Allow entries with | in them for non-multiple values
1507  if ( in_array( $value, $allowedValues, true ) ) {
1508  return $value;
1509  }
1510 
1511  $values = array_map( function ( $v ) {
1512  return '<kbd>' . wfEscapeWikiText( $v ) . '</kbd>';
1513  }, $allowedValues );
1514  $this->dieWithError( [
1515  'apierror-multival-only-one-of',
1516  $valueName,
1517  Message::listParam( $values ),
1518  count( $values ),
1519  ], "multival_$valueName" );
1520  }
1521 
1522  if ( is_array( $allowedValues ) ) {
1523  // Check for unknown values
1524  $unknown = array_map( 'wfEscapeWikiText', array_diff( $valuesList, $allowedValues ) );
1525  if ( count( $unknown ) ) {
1526  if ( $allowMultiple ) {
1527  $this->addWarning( [
1528  'apiwarn-unrecognizedvalues',
1529  $valueName,
1530  Message::listParam( $unknown, 'comma' ),
1531  count( $unknown ),
1532  ] );
1533  } else {
1534  $this->dieWithError(
1535  [ 'apierror-unrecognizedvalue', $valueName, wfEscapeWikiText( $valuesList[0] ) ],
1536  "unknown_$valueName"
1537  );
1538  }
1539  }
1540  // Now throw them out
1541  $valuesList = array_intersect( $valuesList, $allowedValues );
1542  }
1543 
1544  return $allowMultiple ? $valuesList : $valuesList[0];
1545  }
1546 
1557  protected function validateLimit( $paramName, &$value, $min, $max, $botMax = null,
1558  $enforceLimits = false
1559  ) {
1560  if ( !is_null( $min ) && $value < $min ) {
1561  $msg = ApiMessage::create(
1562  [ 'apierror-integeroutofrange-belowminimum',
1563  $this->encodeParamName( $paramName ), $min, $value ],
1564  'integeroutofrange',
1565  [ 'min' => $min, 'max' => $max, 'botMax' => $botMax ?: $max ]
1566  );
1567  $this->warnOrDie( $msg, $enforceLimits );
1568  $value = $min;
1569  }
1570 
1571  // Minimum is always validated, whereas maximum is checked only if not
1572  // running in internal call mode
1573  if ( $this->getMain()->isInternalMode() ) {
1574  return;
1575  }
1576 
1577  // Optimization: do not check user's bot status unless really needed -- skips db query
1578  // assumes $botMax >= $max
1579  if ( !is_null( $max ) && $value > $max ) {
1580  if ( !is_null( $botMax ) && $this->getMain()->canApiHighLimits() ) {
1581  if ( $value > $botMax ) {
1582  $msg = ApiMessage::create(
1583  [ 'apierror-integeroutofrange-abovebotmax',
1584  $this->encodeParamName( $paramName ), $botMax, $value ],
1585  'integeroutofrange',
1586  [ 'min' => $min, 'max' => $max, 'botMax' => $botMax ?: $max ]
1587  );
1588  $this->warnOrDie( $msg, $enforceLimits );
1589  $value = $botMax;
1590  }
1591  } else {
1592  $msg = ApiMessage::create(
1593  [ 'apierror-integeroutofrange-abovemax',
1594  $this->encodeParamName( $paramName ), $max, $value ],
1595  'integeroutofrange',
1596  [ 'min' => $min, 'max' => $max, 'botMax' => $botMax ?: $max ]
1597  );
1598  $this->warnOrDie( $msg, $enforceLimits );
1599  $value = $max;
1600  }
1601  }
1602  }
1603 
1610  protected function validateTimestamp( $value, $encParamName ) {
1611  // Confusing synonyms for the current time accepted by wfTimestamp()
1612  // (wfTimestamp() also accepts various non-strings and the string of 14
1613  // ASCII NUL bytes, but those can't get here)
1614  if ( !$value ) {
1615  $this->addDeprecation(
1616  [ 'apiwarn-unclearnowtimestamp', $encParamName, wfEscapeWikiText( $value ) ],
1617  'unclear-"now"-timestamp'
1618  );
1619  return wfTimestamp( TS_MW );
1620  }
1621 
1622  // Explicit synonym for the current time
1623  if ( $value === 'now' ) {
1624  return wfTimestamp( TS_MW );
1625  }
1626 
1627  $timestamp = wfTimestamp( TS_MW, $value );
1628  if ( $timestamp === false ) {
1629  $this->dieWithError(
1630  [ 'apierror-badtimestamp', $encParamName, wfEscapeWikiText( $value ) ],
1631  "badtimestamp_{$encParamName}"
1632  );
1633  }
1634 
1635  return $timestamp;
1636  }
1637 
1647  final public function validateToken( $token, array $params ) {
1648  $tokenType = $this->needsToken();
1650  if ( !isset( $salts[$tokenType] ) ) {
1651  throw new MWException(
1652  "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1653  'without registering it'
1654  );
1655  }
1656 
1657  $tokenObj = ApiQueryTokens::getToken(
1658  $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1659  );
1660  if ( $tokenObj->match( $token ) ) {
1661  return true;
1662  }
1663 
1664  $webUiSalt = $this->getWebUITokenSalt( $params );
1665  if ( $webUiSalt !== null && $this->getUser()->matchEditToken(
1666  $token,
1667  $webUiSalt,
1668  $this->getRequest()
1669  ) ) {
1670  return true;
1671  }
1672 
1673  return false;
1674  }
1675 
1682  private function validateUser( $value, $encParamName ) {
1684  return $value;
1685  }
1686 
1687  $name = User::getCanonicalName( $value, 'valid' );
1688  if ( $name !== false ) {
1689  return $name;
1690  }
1691 
1692  if (
1693  // We allow ranges as well, for blocks.
1694  IP::isIPAddress( $value ) ||
1695  // See comment for User::isIP. We don't just call that function
1696  // here because it also returns true for things like
1697  // 300.300.300.300 that are neither valid usernames nor valid IP
1698  // addresses.
1699  preg_match(
1700  '/^' . RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.xxx$/',
1701  $value
1702  )
1703  ) {
1704  return IP::sanitizeIP( $value );
1705  }
1706 
1707  $this->dieWithError(
1708  [ 'apierror-baduser', $encParamName, wfEscapeWikiText( $value ) ],
1709  "baduser_{$encParamName}"
1710  );
1711  }
1712 
1715  /************************************************************************/
1726  protected function setWatch( $watch, $titleObj, $userOption = null ) {
1727  $value = $this->getWatchlistValue( $watch, $titleObj, $userOption );
1728  if ( $value === null ) {
1729  return;
1730  }
1731 
1732  WatchAction::doWatchOrUnwatch( $value, $titleObj, $this->getUser() );
1733  }
1734 
1741  public function getWatchlistUser( $params ) {
1742  if ( !is_null( $params['owner'] ) && !is_null( $params['token'] ) ) {
1743  $user = User::newFromName( $params['owner'], false );
1744  if ( !( $user && $user->getId() ) ) {
1745  $this->dieWithError(
1746  [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1747  );
1748  }
1749  $token = $user->getOption( 'watchlisttoken' );
1750  if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1751  $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1752  }
1753  } else {
1754  if ( !$this->getUser()->isLoggedIn() ) {
1755  $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1756  }
1757  $this->checkUserRightsAny( 'viewmywatchlist' );
1758  $user = $this->getUser();
1759  }
1760 
1761  return $user;
1762  }
1763 
1776  public static function makeMessage( $msg, IContextSource $context, array $params = null ) {
1777  if ( is_string( $msg ) ) {
1778  $msg = wfMessage( $msg );
1779  } elseif ( is_array( $msg ) ) {
1780  $msg = wfMessage( ...$msg );
1781  }
1782  if ( !$msg instanceof Message ) {
1783  return null;
1784  }
1785 
1786  $msg->setContext( $context );
1787  if ( $params ) {
1788  $msg->params( $params );
1789  }
1790 
1791  return $msg;
1792  }
1793 
1801  public function errorArrayToStatus( array $errors, User $user = null ) {
1802  if ( $user === null ) {
1803  $user = $this->getUser();
1804  }
1805 
1807  foreach ( $errors as $error ) {
1808  if ( !is_array( $error ) ) {
1809  $error = [ $error ];
1810  }
1811  if ( is_string( $error[0] ) && isset( self::$blockMsgMap[$error[0]] ) && $user->getBlock() ) {
1812  list( $msg, $code ) = self::$blockMsgMap[$error[0]];
1813  $status->fatal( ApiMessage::create( $msg, $code,
1814  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
1815  ) );
1816  } else {
1817  $status->fatal( ...$error );
1818  }
1819  }
1820  return $status;
1821  }
1822 
1829  public function addBlockInfoToStatus( StatusValue $status, User $user = null ) {
1830  if ( $user === null ) {
1831  $user = $this->getUser();
1832  }
1833 
1834  foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
1835  if ( $status->hasMessage( $msg ) && $user->getBlock() ) {
1836  $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
1837  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ]
1838  ) );
1839  }
1840  }
1841  }
1842 
1847  protected function useTransactionalTimeLimit() {
1848  if ( $this->getRequest()->wasPosted() ) {
1850  }
1851  }
1852 
1861  protected function filterIDs( $fields, array $ids ) {
1862  $min = INF;
1863  $max = 0;
1864  foreach ( $fields as list( $table, $field ) ) {
1865  if ( isset( self::$filterIDsCache[$table][$field] ) ) {
1866  $row = self::$filterIDsCache[$table][$field];
1867  } else {
1868  $row = $this->getDB()->selectRow(
1869  $table,
1870  [
1871  'min_id' => "MIN($field)",
1872  'max_id' => "MAX($field)",
1873  ],
1874  '',
1875  __METHOD__
1876  );
1877  self::$filterIDsCache[$table][$field] = $row;
1878  }
1879  $min = min( $min, $row->min_id );
1880  $max = max( $max, $row->max_id );
1881  }
1882  return array_filter( $ids, function ( $id ) use ( $min, $max ) {
1883  return ( is_int( $id ) && $id >= 0 || ctype_digit( $id ) )
1884  && $id >= $min && $id <= $max;
1885  } );
1886  }
1887 
1890  /************************************************************************/
1909  public function addWarning( $msg, $code = null, $data = null ) {
1910  $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1911  }
1912 
1923  public function addDeprecation( $msg, $feature, $data = [] ) {
1924  $data = (array)$data;
1925  if ( $feature !== null ) {
1926  $data['feature'] = $feature;
1927  $this->logFeatureUsage( $feature );
1928  }
1929  $this->addWarning( $msg, 'deprecation', $data );
1930 
1931  // No real need to deduplicate here, ApiErrorFormatter does that for
1932  // us (assuming the hook is deterministic).
1933  $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1934  Hooks::run( 'ApiDeprecationHelp', [ &$msgs ] );
1935  if ( count( $msgs ) > 1 ) {
1936  $key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
1937  $msg = ( new RawMessage( $key ) )->params( $msgs );
1938  } else {
1939  $msg = reset( $msgs );
1940  }
1941  $this->getMain()->addWarning( $msg, 'deprecation-help' );
1942  }
1943 
1956  public function addError( $msg, $code = null, $data = null ) {
1957  $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1958  }
1959 
1969  public function addMessagesFromStatus(
1970  StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
1971  ) {
1972  $this->getErrorFormatter()->addMessagesFromStatus(
1973  $this->getModulePath(), $status, $types, $filter
1974  );
1975  }
1976 
1990  public function dieWithError( $msg, $code = null, $data = null, $httpCode = null ) {
1991  throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1992  }
1993 
2002  public function dieWithException( $exception, array $options = [] ) {
2003  $this->dieWithError(
2004  $this->getErrorFormatter()->getMessageFromException( $exception, $options )
2005  );
2006  }
2007 
2014  private function warnOrDie( ApiMessage $msg, $enforceLimits = false ) {
2015  if ( $enforceLimits ) {
2016  $this->dieWithError( $msg );
2017  } else {
2018  $this->addWarning( $msg );
2019  }
2020  }
2021 
2030  public function dieBlocked( Block $block ) {
2031  // Die using the appropriate message depending on block type
2032  if ( $block->getType() == Block::TYPE_AUTO ) {
2033  $this->dieWithError(
2034  'apierror-autoblocked',
2035  'autoblocked',
2036  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
2037  );
2038  } elseif ( !$block->isSitewide() ) {
2039  $this->dieWithError(
2040  'apierror-blocked-partial',
2041  'blocked',
2042  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
2043  );
2044  } else {
2045  $this->dieWithError(
2046  'apierror-blocked',
2047  'blocked',
2048  [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $block ) ]
2049  );
2050  }
2051  }
2052 
2061  public function dieStatus( StatusValue $status ) {
2062  if ( $status->isGood() ) {
2063  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
2064  }
2065 
2066  // ApiUsageException needs a fatal status, but this method has
2067  // historically accepted any non-good status. Convert it if necessary.
2068  $status->setOK( false );
2069  if ( !$status->getErrorsByType( 'error' ) ) {
2070  $newStatus = Status::newGood();
2071  foreach ( $status->getErrorsByType( 'warning' ) as $err ) {
2072  $newStatus->fatal( $err['message'], ...$err['params'] );
2073  }
2074  if ( !$newStatus->getErrorsByType( 'error' ) ) {
2075  $newStatus->fatal( 'unknownerror-nocode' );
2076  }
2077  $status = $newStatus;
2078  }
2079 
2080  $this->addBlockInfoToStatus( $status );
2081  throw new ApiUsageException( $this, $status );
2082  }
2083 
2089  public function dieReadOnly() {
2090  $this->dieWithError(
2091  'apierror-readonly',
2092  'readonly',
2093  [ 'readonlyreason' => wfReadOnlyReason() ]
2094  );
2095  }
2096 
2105  public function checkUserRightsAny( $rights, $user = null ) {
2106  if ( !$user ) {
2107  $user = $this->getUser();
2108  }
2109  $rights = (array)$rights;
2110  if ( !$user->isAllowedAny( ...$rights ) ) {
2111  $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
2112  }
2113  }
2114 
2127  public function checkTitleUserPermissions( Title $title, $actions, $options = [] ) {
2128  if ( !is_array( $options ) ) {
2129  wfDeprecated( '$user as the third parameter to ' . __METHOD__, '1.33' );
2130  $options = [ 'user' => $options ];
2131  }
2132  $user = $options['user'] ?? $this->getUser();
2133 
2134  $errors = [];
2135  foreach ( (array)$actions as $action ) {
2136  $errors = array_merge( $errors, $title->getUserPermissionsErrors( $action, $user ) );
2137  }
2138 
2139  if ( $errors ) {
2140  if ( !empty( $options['autoblock'] ) ) {
2141  $user->spreadAnyEditBlock();
2142  }
2143 
2144  $this->dieStatus( $this->errorArrayToStatus( $errors, $user ) );
2145  }
2146  }
2147 
2159  public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
2160  if ( $this->getConfig()->get( 'DebugAPI' ) !== true ) {
2161  $this->dieWithError( $msg, $code, $data, $httpCode );
2162  } else {
2163  $this->addWarning( $msg, $code, $data );
2164  }
2165  }
2166 
2176  protected function dieContinueUsageIf( $condition ) {
2177  if ( $condition ) {
2178  $this->dieWithError( 'apierror-badcontinue' );
2179  }
2180  }
2181 
2188  protected static function dieDebug( $method, $message ) {
2189  throw new MWException( "Internal error in $method: $message" );
2190  }
2191 
2198  public function logFeatureUsage( $feature ) {
2199  static $loggedFeatures = [];
2200 
2201  // Only log each feature once per request. We can get multiple calls from calls to
2202  // extractRequestParams() with different values for 'parseLimit', for example.
2203  if ( isset( $loggedFeatures[$feature] ) ) {
2204  return;
2205  }
2206  $loggedFeatures[$feature] = true;
2207 
2208  $request = $this->getRequest();
2209  $ctx = [
2210  'feature' => $feature,
2211  // Spaces to underscores in 'username' for historical reasons.
2212  'username' => str_replace( ' ', '_', $this->getUser()->getName() ),
2213  'ip' => $request->getIP(),
2214  'referer' => (string)$request->getHeader( 'Referer' ),
2215  'agent' => $this->getMain()->getUserAgent(),
2216  ];
2217 
2218  // Text string is deprecated. Remove (or replace with just $feature) in MW 1.34.
2219  $s = '"' . addslashes( $ctx['feature'] ) . '"' .
2220  ' "' . wfUrlencode( $ctx['username'] ) . '"' .
2221  ' "' . $ctx['ip'] . '"' .
2222  ' "' . addslashes( $ctx['referer'] ) . '"' .
2223  ' "' . addslashes( $ctx['agent'] ) . '"';
2224 
2225  wfDebugLog( 'api-feature-usage', $s, 'private', $ctx );
2226  }
2227 
2230  /************************************************************************/
2244  protected function getSummaryMessage() {
2245  return "apihelp-{$this->getModulePath()}-summary";
2246  }
2247 
2257  protected function getExtendedDescription() {
2258  return [ [
2259  "apihelp-{$this->getModulePath()}-extended-description",
2260  'api-help-no-extended-description',
2261  ] ];
2262  }
2263 
2270  public function getFinalSummary() {
2271  $msg = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
2272  $this->getModulePrefix(),
2273  $this->getModuleName(),
2274  $this->getModulePath(),
2275  ] );
2276  return $msg;
2277  }
2278 
2286  public function getFinalDescription() {
2287  $summary = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
2288  $this->getModulePrefix(),
2289  $this->getModuleName(),
2290  $this->getModulePath(),
2291  ] );
2292  $extendedDescription = self::makeMessage(
2293  $this->getExtendedDescription(), $this->getContext(), [
2294  $this->getModulePrefix(),
2295  $this->getModuleName(),
2296  $this->getModulePath(),
2297  ]
2298  );
2299 
2300  $msgs = [ $summary, $extendedDescription ];
2301 
2302  Hooks::run( 'APIGetDescriptionMessages', [ $this, &$msgs ] );
2303 
2304  return $msgs;
2305  }
2306 
2315  public function getFinalParams( $flags = 0 ) {
2316  $params = $this->getAllowedParams( $flags );
2317  if ( !$params ) {
2318  $params = [];
2319  }
2320 
2321  if ( $this->needsToken() ) {
2322  $params['token'] = [
2323  self::PARAM_TYPE => 'string',
2324  self::PARAM_REQUIRED => true,
2325  self::PARAM_SENSITIVE => true,
2326  self::PARAM_HELP_MSG => [
2327  'api-help-param-token',
2328  $this->needsToken(),
2329  ],
2330  ] + ( $params['token'] ?? [] );
2331  }
2332 
2333  // Avoid PHP 7.1 warning of passing $this by reference
2334  $apiModule = $this;
2335  Hooks::run( 'APIGetAllowedParams', [ &$apiModule, &$params, $flags ] );
2336 
2337  return $params;
2338  }
2339 
2347  public function getFinalParamDescription() {
2348  $prefix = $this->getModulePrefix();
2349  $name = $this->getModuleName();
2350  $path = $this->getModulePath();
2351 
2352  $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
2353  $msgs = [];
2354  foreach ( $params as $param => $settings ) {
2355  if ( !is_array( $settings ) ) {
2356  $settings = [];
2357  }
2358 
2359  if ( isset( $settings[self::PARAM_HELP_MSG] ) ) {
2360  $msg = $settings[self::PARAM_HELP_MSG];
2361  } else {
2362  $msg = $this->msg( "apihelp-{$path}-param-{$param}" );
2363  }
2364  $msg = self::makeMessage( $msg, $this->getContext(),
2365  [ $prefix, $param, $name, $path ] );
2366  if ( !$msg ) {
2367  self::dieDebug( __METHOD__,
2368  'Value in ApiBase::PARAM_HELP_MSG is not valid' );
2369  }
2370  $msgs[$param] = [ $msg ];
2371 
2372  if ( isset( $settings[self::PARAM_TYPE] ) &&
2373  $settings[self::PARAM_TYPE] === 'submodule'
2374  ) {
2375  if ( isset( $settings[self::PARAM_SUBMODULE_MAP] ) ) {
2376  $map = $settings[self::PARAM_SUBMODULE_MAP];
2377  } else {
2378  $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
2379  $map = [];
2380  foreach ( $this->getModuleManager()->getNames( $param ) as $submoduleName ) {
2381  $map[$submoduleName] = $prefix . $submoduleName;
2382  }
2383  }
2384  ksort( $map );
2385  $submodules = [];
2386  $deprecatedSubmodules = [];
2387  foreach ( $map as $v => $m ) {
2388  $arr = &$submodules;
2389  $isDeprecated = false;
2390  $summary = null;
2391  try {
2392  $submod = $this->getModuleFromPath( $m );
2393  if ( $submod ) {
2394  $summary = $submod->getFinalSummary();
2395  $isDeprecated = $submod->isDeprecated();
2396  if ( $isDeprecated ) {
2397  $arr = &$deprecatedSubmodules;
2398  }
2399  }
2400  } catch ( ApiUsageException $ex ) {
2401  // Ignore
2402  }
2403  if ( $summary ) {
2404  $key = $summary->getKey();
2405  $params = $summary->getParams();
2406  } else {
2407  $key = 'api-help-undocumented-module';
2408  $params = [ $m ];
2409  }
2410  $m = new ApiHelpParamValueMessage( "[[Special:ApiHelp/$m|$v]]", $key, $params, $isDeprecated );
2411  $arr[] = $m->setContext( $this->getContext() );
2412  }
2413  $msgs[$param] = array_merge( $msgs[$param], $submodules, $deprecatedSubmodules );
2414  } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
2415  if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
2416  self::dieDebug( __METHOD__,
2417  'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
2418  }
2419  if ( !is_array( $settings[self::PARAM_TYPE] ) ) {
2420  self::dieDebug( __METHOD__,
2421  'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
2422  'ApiBase::PARAM_TYPE is an array' );
2423  }
2424 
2425  $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
2426  $deprecatedValues = $settings[self::PARAM_DEPRECATED_VALUES] ?? [];
2427 
2428  foreach ( $settings[self::PARAM_TYPE] as $value ) {
2429  if ( isset( $valueMsgs[$value] ) ) {
2430  $msg = $valueMsgs[$value];
2431  } else {
2432  $msg = "apihelp-{$path}-paramvalue-{$param}-{$value}";
2433  }
2434  $m = self::makeMessage( $msg, $this->getContext(),
2435  [ $prefix, $param, $name, $path, $value ] );
2436  if ( $m ) {
2437  $m = new ApiHelpParamValueMessage(
2438  $value,
2439  [ $m->getKey(), 'api-help-param-no-description' ],
2440  $m->getParams(),
2441  isset( $deprecatedValues[$value] )
2442  );
2443  $msgs[$param][] = $m->setContext( $this->getContext() );
2444  } else {
2445  self::dieDebug( __METHOD__,
2446  "Value in ApiBase::PARAM_HELP_MSG_PER_VALUE for $value is not valid" );
2447  }
2448  }
2449  }
2450 
2451  if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2452  if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2453  self::dieDebug( __METHOD__,
2454  'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
2455  }
2456  foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
2457  $m = self::makeMessage( $m, $this->getContext(),
2458  [ $prefix, $param, $name, $path ] );
2459  if ( $m ) {
2460  $msgs[$param][] = $m;
2461  } else {
2462  self::dieDebug( __METHOD__,
2463  'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
2464  }
2465  }
2466  }
2467  }
2468 
2469  Hooks::run( 'APIGetParamDescriptionMessages', [ $this, &$msgs ] );
2470 
2471  return $msgs;
2472  }
2473 
2483  protected function getHelpFlags() {
2484  $flags = [];
2485 
2486  if ( $this->isDeprecated() ) {
2487  $flags[] = 'deprecated';
2488  }
2489  if ( $this->isInternal() ) {
2490  $flags[] = 'internal';
2491  }
2492  if ( $this->isReadMode() ) {
2493  $flags[] = 'readrights';
2494  }
2495  if ( $this->isWriteMode() ) {
2496  $flags[] = 'writerights';
2497  }
2498  if ( $this->mustBePosted() ) {
2499  $flags[] = 'mustbeposted';
2500  }
2501 
2502  return $flags;
2503  }
2504 
2516  protected function getModuleSourceInfo() {
2517  global $IP;
2518 
2519  if ( $this->mModuleSource !== false ) {
2520  return $this->mModuleSource;
2521  }
2522 
2523  // First, try to find where the module comes from...
2524  $rClass = new ReflectionClass( $this );
2525  $path = $rClass->getFileName();
2526  if ( !$path ) {
2527  // No path known?
2528  $this->mModuleSource = null;
2529  return null;
2530  }
2531  $path = realpath( $path ) ?: $path;
2532 
2533  // Build map of extension directories to extension info
2534  if ( self::$extensionInfo === null ) {
2535  $extDir = $this->getConfig()->get( 'ExtensionDirectory' );
2536  self::$extensionInfo = [
2537  realpath( __DIR__ ) ?: __DIR__ => [
2538  'path' => $IP,
2539  'name' => 'MediaWiki',
2540  'license-name' => 'GPL-2.0-or-later',
2541  ],
2542  realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
2543  realpath( $extDir ) ?: $extDir => null,
2544  ];
2545  $keep = [
2546  'path' => null,
2547  'name' => null,
2548  'namemsg' => null,
2549  'license-name' => null,
2550  ];
2551  foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $group ) {
2552  foreach ( $group as $ext ) {
2553  if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
2554  // This shouldn't happen, but does anyway.
2555  continue;
2556  }
2557 
2558  $extpath = $ext['path'];
2559  if ( !is_dir( $extpath ) ) {
2560  $extpath = dirname( $extpath );
2561  }
2562  self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2563  array_intersect_key( $ext, $keep );
2564  }
2565  }
2566  foreach ( ExtensionRegistry::getInstance()->getAllThings() as $ext ) {
2567  $extpath = $ext['path'];
2568  if ( !is_dir( $extpath ) ) {
2569  $extpath = dirname( $extpath );
2570  }
2571  self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2572  array_intersect_key( $ext, $keep );
2573  }
2574  }
2575 
2576  // Now traverse parent directories until we find a match or run out of
2577  // parents.
2578  do {
2579  if ( array_key_exists( $path, self::$extensionInfo ) ) {
2580  // Found it!
2581  $this->mModuleSource = self::$extensionInfo[$path];
2582  return $this->mModuleSource;
2583  }
2584 
2585  $oldpath = $path;
2586  $path = dirname( $path );
2587  } while ( $path !== $oldpath );
2588 
2589  // No idea what extension this might be.
2590  $this->mModuleSource = null;
2591  return null;
2592  }
2593 
2605  public function modifyHelp( array &$help, array $options, array &$tocData ) {
2606  }
2607 
2610  /************************************************************************/
2624  protected function getDescription() {
2625  wfDeprecated( __METHOD__, '1.25' );
2626  return false;
2627  }
2628 
2641  protected function getParamDescription() {
2642  wfDeprecated( __METHOD__, '1.25' );
2643  return [];
2644  }
2645 
2662  protected function getExamples() {
2663  wfDeprecated( __METHOD__, '1.25' );
2664  return false;
2665  }
2666 
2675  protected function getDescriptionMessage() {
2676  wfDeprecated( __METHOD__, '1.30' );
2677  return [ [
2678  "apihelp-{$this->getModulePath()}-description",
2679  "apihelp-{$this->getModulePath()}-summary",
2680  ] ];
2681  }
2682 
2690  public static function truncateArray( &$arr, $limit ) {
2691  wfDeprecated( __METHOD__, '1.32' );
2692  $modified = false;
2693  while ( count( $arr ) > $limit ) {
2694  array_pop( $arr );
2695  $modified = true;
2696  }
2697 
2698  return $modified;
2699  }
2700 
2702 }
2703 
$filter
$filter
Definition: profileinfo.php:341
$status
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action, or null $user:User who performed the tagging when the tagging is subsequent to the action, or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, 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. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'ContentSecurityPolicyDefaultSource':Modify the allowed CSP load sources. This affects all directives except for the script directive. If you want to add a script source, see ContentSecurityPolicyScriptSource hook. & $defaultSrc:Array of Content-Security-Policy allowed sources $policyConfig:Current configuration for the Content-Security-Policy header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyDirectives':Modify the content security policy directives. Use this only if ContentSecurityPolicyDefaultSource and ContentSecurityPolicyScriptSource do not meet your needs. & $directives:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyScriptSource':Modify the allowed CSP script sources. Note that you also have to use ContentSecurityPolicyDefaultSource if you want non-script sources to be loaded from whatever you add. & $scriptSrc:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DatabaseOraclePostInit':Called after initialising an Oracle database $db:the DatabaseOracle object 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DeleteUnknownPreferences':Called by the cleanupPreferences.php maintenance script to build a WHERE clause with which to delete preferences that are not known about. This hook is used by extensions that have dynamically-named preferences that should not be deleted in the usual cleanup process. For example, the Gadgets extension creates preferences prefixed with 'gadget-', and so anything with that prefix is excluded from the deletion. &where:An array that will be passed as the $cond parameter to IDatabase::select() to determine what will be deleted from the user_properties table. $db:The IDatabase object, useful for accessing $db->buildLike() etc. 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1266
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:41
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:33
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:63
ApiBase\PARAM_SUBMODULE_MAP
const PARAM_SUBMODULE_MAP
(string[]) When PARAM_TYPE is 'submodule', map parameter values to submodule paths.
Definition: ApiBase.php:165
$user
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1476
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:306
ApiUsageException
Exception used to abort API execution with an error.
Definition: ApiUsageException.php:28
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:40
ApiBase\$mMainModule
ApiMain $mMainModule
Definition: ApiBase.php:282
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:546
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1909
Block\getType
getType()
Get the type of target for this particular block.
Definition: Block.php:1682
ApiBase\getSummaryMessage
getSummaryMessage()
Return the summary message.
Definition: ApiBase.php:2244
MWNamespace\getValidNamespaces
static getValidNamespaces()
Returns an array of the namespaces (by integer id) that exist on the wiki.
Definition: MWNamespace.php:287
ApiBase\getFinalParams
getFinalParams( $flags=0)
Get final list of parameters, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2315
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
(boolean) Is the parameter required?
Definition: ApiBase.php:111
ApiBase\checkTitleUserPermissions
checkTitleUserPermissions(Title $title, $actions, $options=[])
Helper function for permission-denied errors.
Definition: ApiBase.php:2127
ApiBase\parameterNotEmpty
parameterNotEmpty( $x)
Callback function used in requireOnlyOneParameter to check whether required parameters are set.
Definition: ApiBase.php:1001
ApiBase\$mModuleSource
array null bool $mModuleSource
Definition: ApiBase.php:288
captcha-old.count
count
Definition: captcha-old.py:249
ApiBase\validateToken
validateToken( $token, array $params)
Validate the supplied token.
Definition: ApiBase.php:1647
ApiContinuationManager
This manages continuation state.
Definition: ApiContinuationManager.php:26
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1990
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:124
ContextSource\msg
msg( $key)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:168
ApiBase\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiBase.php:361
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:180
ApiBase\validateTimestamp
validateTimestamp( $value, $encParamName)
Validate and normalize parameters of type 'timestamp'.
Definition: ApiBase.php:1610
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1912
ApiBase\$extensionInfo
static array $extensionInfo
Maps extension paths to info arrays.
Definition: ApiBase.php:268
ApiBase\getTitleOrPageId
getTitleOrPageId( $params, $load=false)
Get a WikiPage object from a title or pageid param, if possible.
Definition: ApiBase.php:1016
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:87
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:632
ApiBase\getDescriptionMessage
getDescriptionMessage()
Return the description message.
Definition: ApiBase.php:2675
ApiBase\__construct
__construct(ApiMain $mainModule, $moduleName, $modulePrefix='')
Definition: ApiBase.php:295
ApiBase\$blockMsgMap
static $blockMsgMap
$var array Map of web UI block messages to corresponding API messages and codes
Definition: ApiBase.php:274
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:333
ApiBase\mustBePosted
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiBase.php:427
ApiBase\logFeatureUsage
logFeatureUsage( $feature)
Write logging information for API features to a debug log, for usage analysis.
Definition: ApiBase.php:2198
ApiBase\checkUserRightsAny
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:2105
ApiBase\shouldCheckMaxlag
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition: ApiBase.php:396
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:2159
ApiBase\setContinuationManager
setContinuationManager(ApiContinuationManager $manager=null)
Set the continuation manager.
Definition: ApiBase.php:686
$params
$params
Definition: styleTest.css.php:44
ApiBase\getExtendedDescription
getExtendedDescription()
Return the extended help text message.
Definition: ApiBase.php:2257
ApiBase\PARAM_ISMULTI_LIMIT1
const PARAM_ISMULTI_LIMIT1
(integer) Maximum number of values, for normal users.
Definition: ApiBase.php:208
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:585
ApiBase\addBlockInfoToStatus
addBlockInfoToStatus(StatusValue $status, User $user=null)
Add block info to block messages in a Status.
Definition: ApiBase.php:1829
$s
$s
Definition: mergeMessageFileList.php:186
ApiBase\getDB
getDB()
Gets a default replica DB connection object.
Definition: ApiBase.php:660
ApiBase\addMessagesFromStatus
addMessagesFromStatus(StatusValue $status, $types=[ 'warning', 'error'], array $filter=[])
Add warnings and/or errors from a Status.
Definition: ApiBase.php:1969
ApiBase\makeMessage
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
Definition: ApiBase.php:1776
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:71
ApiBase\dynamicParameterDocumentation
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition: ApiBase.php:710
ApiBase\modifyHelp
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition: ApiBase.php:2605
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:102
ContextSource\getUser
getUser()
Definition: ContextSource.php:120
ApiBase\PARAM_DEPRECATED_VALUES
const PARAM_DEPRECATED_VALUES
(array) When PARAM_TYPE is an array, this indicates which of the values are deprecated.
Definition: ApiBase.php:202
ApiBase\lacksSameOriginSecurity
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:560
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:131
ApiUsageException\newWithMessage
static newWithMessage(ApiBase $module=null, $msg, $code=null, $data=null, $httpCode=0)
Definition: ApiUsageException.php:63
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:1043
ApiBase\getWebUITokenSalt
getWebUITokenSalt(array $params)
Fetch the salt used in the Web UI corresponding to this module.
Definition: ApiBase.php:481
ApiBase\isMain
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition: ApiBase.php:537
ApiBase\isReadMode
isReadMode()
Indicates whether this module requires read rights.
Definition: ApiBase.php:404
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:37
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
ApiBase\getModuleFromPath
getModuleFromPath( $path)
Get a module from its module path.
Definition: ApiBase.php:594
ApiBase\getFinalParamDescription
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2347
ApiMessage
Extension of Message implementing IApiMessage.
Definition: ApiMessage.php:26
ApiBase\PARAM_SENSITIVE
const PARAM_SENSITIVE
(boolean) Is the parameter sensitive? Note 'password'-type fields are always sensitive regardless of ...
Definition: ApiBase.php:193
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:2030
ApiBase\PARAM_ISMULTI_LIMIT2
const PARAM_ISMULTI_LIMIT2
(integer) Maximum number of values, for users with the apihighimits right.
Definition: ApiBase.php:215
ApiBase\getParamDescription
getParamDescription()
Returns an array of parameter descriptions.
Definition: ApiBase.php:2641
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:98
ApiBase\getFinalSummary
getFinalSummary()
Get final module summary.
Definition: ApiBase.php:2270
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
(boolean) Is the parameter deprecated (will show a warning)?
Definition: ApiBase.php:105
ApiBase\explodeMultiValue
explodeMultiValue( $value, $limit)
Split a multi-valued parameter string, like explode()
Definition: ApiBase.php:1448
ApiBase\PARAM_MIN
const PARAM_MIN
(integer) Lowest value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
Definition: ApiBase.php:99
$data
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
Definition: generatePhpCharToUpperMappings.php:13
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:925
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:138
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1078
ApiBase\warnOrDie
warnOrDie(ApiMessage $msg, $enforceLimits=false)
Adds a warning to the output, else dies.
Definition: ApiBase.php:2014
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:346
ApiBase\getFinalDescription
getFinalDescription()
Get final module description, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2286
wfTransactionalTimeLimit
wfTransactionalTimeLimit()
Set PHP's time limit to the larger of php.ini or $wgTransactionalTimeLimit.
Definition: GlobalFunctions.php:2895
ApiBase\getModulePath
getModulePath()
Get the path to this module.
Definition: ApiBase.php:576
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2636
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:252
ApiBase\getDescription
getDescription()
Returns the description string for this module.
Definition: ApiBase.php:2624
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:29
ApiQueryTokens\getTokenTypeSalts
static getTokenTypeSalts()
Get the salts for known token types.
Definition: ApiQueryTokens.php:63
$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:90
ApiBase\dieWithException
dieWithException( $exception, array $options=[])
Abort execution with an error derived from an exception.
Definition: ApiBase.php:2002
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
$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 When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password 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:780
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:743
WatchAction\doWatchOrUnwatch
static doWatchOrUnwatch( $watch, Title $title, User $user)
Watch or unwatch a page.
Definition: WatchAction.php:89
ApiBase\handleParamNormalization
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition: ApiBase.php:1436
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
ApiBase\isDeprecated
isDeprecated()
Indicates whether this module is deprecated.
Definition: ApiBase.php:436
ApiBase\$mReplicaDB
$mReplicaDB
Definition: ApiBase.php:285
ApiMessage\create
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
Definition: ApiMessage.php:40
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
ApiBase\PARAM_EXTRA_NAMESPACES
const PARAM_EXTRA_NAMESPACES
(int[]) When PARAM_TYPE is 'namespace', include these as additional possible values.
Definition: ApiBase.php:186
ApiBase\ALL_DEFAULT_STRING
const ALL_DEFAULT_STRING
Definition: ApiBase.php:249
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:175
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:55
ApiBase\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiBase.php:370
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
ApiBase\validateUser
validateUser( $value, $encParamName)
Validate and normalize parameters of type 'user'.
Definition: ApiBase.php:1682
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:1081
ApiBase\needsToken
needsToken()
Returns the token type this module requires in order to execute.
Definition: ApiBase.php:468
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:520
null
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
ApiBase\$mModuleName
string $mModuleName
Definition: ApiBase.php:284
$request
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2644
ApiBase\setWatch
setWatch( $watch, $titleObj, $userOption=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
Definition: ApiBase.php:1726
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
ApiBase\getContinuationManager
getContinuationManager()
Get the continuation manager.
Definition: ApiBase.php:672
ApiBase\addError
addError( $msg, $code=null, $data=null)
Add an error for this module without aborting.
Definition: ApiBase.php:1956
ApiBase\getWatchlistUser
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition: ApiBase.php:1741
RE_IP_BYTE
const RE_IP_BYTE
Definition: IP.php:29
$value
$value
Definition: styleTest.css.php:49
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:2176
ApiBase\addDeprecation
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition: ApiBase.php:1923
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:81
ApiBase\LIMIT_SML2
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition: ApiBase.php:258
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:721
ApiBase\dieReadOnly
dieReadOnly()
Helper function for readonly errors.
Definition: ApiBase.php:2089
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:265
WikiPage\newFromID
static newFromID( $id, $from='fromdb')
Constructor from a page id.
Definition: WikiPage.php:176
ApiBase\useTransactionalTimeLimit
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: ApiBase.php:1847
ApiBase\getConditionalRequestData
getConditionalRequestData( $condition)
Returns data for HTTP conditional request mechanisms.
Definition: ApiBase.php:497
ApiBase\isWriteMode
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiBase.php:419
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1577
$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:1993
Block\isSitewide
isSitewide( $x=null)
Indicates that the block is a sitewide block.
Definition: Block.php:1178
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params, $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:913
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:875
ApiBase\PARAM_HELP_MSG_INFO
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition: ApiBase.php:141
ApiBase\$mParamCache
$mParamCache
Definition: ApiBase.php:286
Block\TYPE_AUTO
const TYPE_AUTO
Definition: Block.php:99
ApiBase\truncateArray
static truncateArray(&$arr, $limit)
Truncate an array to a certain length.
Definition: ApiBase.php:2690
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:53
ApiBase\PARAM_RANGE_ENFORCE
const PARAM_RANGE_ENFORCE
(boolean) For PARAM_TYPE 'integer', enforce PARAM_MIN and PARAM_MAX?
Definition: ApiBase.php:117
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:148
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:481
ApiBase\requireAtLeastOneParameter
requireAtLeastOneParameter( $params, $required)
Die if none of a certain set of parameters is set and not false.
Definition: ApiBase.php:941
IP\sanitizeIP
static sanitizeIP( $ip)
Convert an IP into a verbose, uppercase, normalized form.
Definition: IP.php:152
$parent
$parent
Definition: pageupdater.txt:71
Title
Represents a title within MediaWiki.
Definition: Title.php:40
ApiBase\PARAM_TEMPLATE_VARS
const PARAM_TEMPLATE_VARS
(array) Indicate that this is a templated parameter, and specify replacements.
Definition: ApiBase.php:245
ApiBase\filterIDs
filterIDs( $fields, array $ids)
Filter out-of-range values from a list of positive integer IDs.
Definition: ApiBase.php:1861
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:254
wfReadOnlyReason
wfReadOnlyReason()
Check if the site is in read-only mode and return the message if so.
Definition: GlobalFunctions.php:1210
ApiQueryTokens\getToken
static getToken(User $user, MediaWiki\Session\Session $session, $salt)
Get a token from a salt.
Definition: ApiQueryTokens.php:94
$options
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 & $options
Definition: hooks.txt:1993
ApiBase\getModuleManager
getModuleManager()
Get the module manager, or null if this module has no sub-modules.
Definition: ApiBase.php:333
ApiBase\isInternal
isInternal()
Indicates whether this module is "internal" Internal API modules are not (yet) intended for 3rd party...
Definition: ApiBase.php:446
ApiBase\getModuleSourceInfo
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition: ApiBase.php:2516
User\getCanonicalName
static getCanonicalName( $name, $validate='valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid.
Definition: User.php:1244
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:1557
$path
$path
Definition: NoLocalSettings.php:25
ApiBase\PARAM_DFLT
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
Definition: ApiBase.php:48
ApiBase\getParameter
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition: ApiBase.php:858
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
Block
Definition: Block.php:31
ApiBase\dieStatus
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:2061
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:512
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
Definition: ApiBase.php:51
ApiBase\PARAM_MAX2
const PARAM_MAX2
(integer) Max value allowed for the parameter for users with the apihighlimits right,...
Definition: ApiBase.php:96
ApiBase\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiBase.php:386
ApiBase\parseMultiValue
parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues, $allSpecifier=null, $limit1=null, $limit2=null)
Return an array of values that were given in a 'a|b|c' notation, after it optionally validates them a...
Definition: ApiBase.php:1476
$help
$help
Definition: mcc.php:32
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:528
ApiBase\getParameterFromSettings
getParameterFromSettings( $paramName, $paramSettings, $parseLimit)
Using the settings determine the value for the given parameter.
Definition: ApiBase.php:1122
$ext
if(!is_readable( $file)) $ext
Definition: router.php:48
ApiBase\PARAM_MAX_CHARS
const PARAM_MAX_CHARS
(integer) Maximum length of a string in characters (unicode codepoints).
Definition: ApiBase.php:227
ApiBase\getTitleFromTitleOrPageId
getTitleFromTitleOrPageId( $params)
Get a Title object from a title or pageid param, if possible.
Definition: ApiBase.php:1053
User\IGNORE_USER_RIGHTS
const IGNORE_USER_RIGHTS
Definition: User.php:78
ApiBase\getExamples
getExamples()
Returns usage examples for this module.
Definition: ApiBase.php:2662
ApiBase\$mModulePrefix
string $mModulePrefix
Definition: ApiBase.php:284
RawMessage
Variant of the Message class.
Definition: RawMessage.php:34
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 use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
ApiBase\PARAM_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:157
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:172
ApiBase\PARAM_MAX_BYTES
const PARAM_MAX_BYTES
(integer) Maximum length of a string in bytes (in UTF-8 encoding).
Definition: ApiBase.php:221
ApiHelpParamValueMessage
Message subclass that prepends wikitext for API help.
Definition: ApiHelpParamValueMessage.php:32
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:48
Title\newFromID
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:457
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
ApiBase\$filterIDsCache
static int[][][] $filterIDsCache
Cache for self::filterIDs()
Definition: ApiBase.php:271
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:2188
ExternalUserNames\isExternal
static isExternal( $username)
Tells whether the username is external or not.
Definition: ExternalUserNames.php:135
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:1801
ApiBase\getErrorFormatter
getErrorFormatter()
Get the error formatter.
Definition: ApiBase.php:646
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:971
ApiQueryUserInfo\getBlockInfo
static getBlockInfo(Block $block)
Get basic info about a given block.
Definition: ApiQueryUserInfo.php:65
IP\isIPAddress
static isIPAddress( $ip)
Determine if a string is as valid IP address or network (CIDR prefix).
Definition: IP.php:77
ApiBase\LIMIT_SML1
const LIMIT_SML1
Slow query, standard limit.
Definition: ApiBase.php:256
ApiBase\getHelpFlags
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition: ApiBase.php:2483
$type
$type
Definition: testCompression.php:48