MediaWiki  master
ApiBase.php
Go to the documentation of this file.
1 <?php
40 
55 abstract class ApiBase extends ContextSource {
56 
58 
60  private $hookContainer;
61 
63  private $hookRunner;
64 
70  public const PARAM_DFLT = ParamValidator::PARAM_DEFAULT;
71  public const PARAM_ISMULTI = ParamValidator::PARAM_ISMULTI;
72  public const PARAM_TYPE = ParamValidator::PARAM_TYPE;
73  public const PARAM_MAX = IntegerDef::PARAM_MAX;
74  public const PARAM_MAX2 = IntegerDef::PARAM_MAX2;
75  public const PARAM_MIN = IntegerDef::PARAM_MIN;
76  public const PARAM_ALLOW_DUPLICATES = ParamValidator::PARAM_ALLOW_DUPLICATES;
77  public const PARAM_DEPRECATED = ParamValidator::PARAM_DEPRECATED;
78  public const PARAM_REQUIRED = ParamValidator::PARAM_REQUIRED;
79  public const PARAM_SUBMODULE_MAP = SubmoduleDef::PARAM_SUBMODULE_MAP;
80  public const PARAM_SUBMODULE_PARAM_PREFIX = SubmoduleDef::PARAM_SUBMODULE_PARAM_PREFIX;
81  public const PARAM_ALL = ParamValidator::PARAM_ALL;
82  public const PARAM_EXTRA_NAMESPACES = NamespaceDef::PARAM_EXTRA_NAMESPACES;
83  public const PARAM_SENSITIVE = ParamValidator::PARAM_SENSITIVE;
84  public const PARAM_DEPRECATED_VALUES = EnumDef::PARAM_DEPRECATED_VALUES;
85  public const PARAM_ISMULTI_LIMIT1 = ParamValidator::PARAM_ISMULTI_LIMIT1;
86  public const PARAM_ISMULTI_LIMIT2 = ParamValidator::PARAM_ISMULTI_LIMIT2;
87  public const PARAM_MAX_BYTES = StringDef::PARAM_MAX_BYTES;
88  public const PARAM_MAX_CHARS = StringDef::PARAM_MAX_CHARS;
95  public const PARAM_RANGE_ENFORCE = 'api-param-range-enforce';
96 
97  // region API-specific constants for ::getAllowedParams() arrays
105  public const PARAM_HELP_MSG = 'api-param-help-msg';
106 
112  public const PARAM_HELP_MSG_APPEND = 'api-param-help-msg-append';
113 
122  public const PARAM_HELP_MSG_INFO = 'api-param-help-msg-info';
123 
129  public const PARAM_VALUE_LINKS = 'api-param-value-links';
130 
138  public const PARAM_HELP_MSG_PER_VALUE = 'api-param-help-msg-per-value';
139 
156  public const PARAM_TEMPLATE_VARS = 'param-template-vars';
157 
158  // endregion -- end of API-specific constants for ::getAllowedParams() arrays
159 
160  public const ALL_DEFAULT_STRING = '*';
161 
163  public const LIMIT_BIG1 = 500;
165  public const LIMIT_BIG2 = 5000;
167  public const LIMIT_SML1 = 50;
169  public const LIMIT_SML2 = 500;
170 
176  public const GET_VALUES_FOR_HELP = 1;
177 
179  private static $extensionInfo = null;
180 
182  private static $filterIDsCache = [];
183 
185  private static $blockMsgMap = [
186  'blockedtext' => [ 'apierror-blocked', 'blocked' ],
187  'blockedtext-partial' => [ 'apierror-blocked-partial', 'blocked' ],
188  'autoblockedtext' => [ 'apierror-autoblocked', 'autoblocked' ],
189  'systemblockedtext' => [ 'apierror-systemblocked', 'blocked' ],
190  'blockedtext-composite' => [ 'apierror-blocked', 'blocked' ],
191  ];
192 
194  private $mMainModule;
197  private $mReplicaDB = null;
201  private $mParamCache = [];
203  private $mModuleSource = false;
204 
211  public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
212  $this->mMainModule = $mainModule;
213  $this->mModuleName = $moduleName;
214  $this->mModulePrefix = $modulePrefix;
215 
216  if ( !$this->isMain() ) {
217  $this->setContext( $mainModule->getContext() );
218  }
219  }
220 
221  /***************************************************************************/
222  // region Methods to implement
241  abstract public function execute();
242 
249  public function getModuleManager() {
250  return null;
251  }
252 
263  public function getCustomPrinter() {
264  return null;
265  }
266 
279  protected function getExamplesMessages() {
280  return [];
281  }
282 
289  public function getHelpUrls() {
290  return [];
291  }
292 
306  protected function getAllowedParams( /* $flags = 0 */ ) {
307  // int $flags is not declared because it causes "Strict standards"
308  // warning. Most derived classes do not implement it.
309  return [];
310  }
311 
317  public function shouldCheckMaxlag() {
318  return true;
319  }
320 
326  public function isReadMode() {
327  return true;
328  }
329 
342  public function isWriteMode() {
343  return false;
344  }
345 
351  public function mustBePosted() {
352  return $this->needsToken() !== false;
353  }
354 
361  public function isDeprecated() {
362  return false;
363  }
364 
372  public function isInternal() {
373  return false;
374  }
375 
395  public function needsToken() {
396  return false;
397  }
398 
409  protected function getWebUITokenSalt( array $params ) {
410  return null;
411  }
412 
426  public function getConditionalRequestData( $condition ) {
427  return null;
428  }
429 
430  // endregion -- end of methods to implement
431 
432  /***************************************************************************/
433  // region Data access methods
440  public function getModuleName() {
441  return $this->mModuleName;
442  }
443 
448  public function getModulePrefix() {
449  return $this->mModulePrefix;
450  }
451 
456  public function getMain() {
457  return $this->mMainModule;
458  }
459 
465  public function isMain() {
466  return $this === $this->mMainModule;
467  }
468 
475  public function getParent() {
476  return $this->isMain() ? null : $this->getMain();
477  }
478 
486  private function dieIfMain( string $methodName ) {
487  if ( $this->isMain() ) {
488  self::dieDebug( $methodName, 'base method was called on main module.' );
489  }
490  }
491 
502  public function lacksSameOriginSecurity() {
503  // Main module has this method overridden, avoid infinite loops
504  $this->dieIfMain( __METHOD__ );
505 
506  return $this->getMain()->lacksSameOriginSecurity();
507  }
508 
515  public function getModulePath() {
516  if ( $this->isMain() ) {
517  return 'main';
518  } elseif ( $this->getParent()->isMain() ) {
519  return $this->getModuleName();
520  } else {
521  return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
522  }
523  }
524 
533  public function getModuleFromPath( $path ) {
534  $module = $this->getMain();
535  if ( $path === 'main' ) {
536  return $module;
537  }
538 
539  $parts = explode( '+', $path );
540  if ( count( $parts ) === 1 ) {
541  // In case the '+' was typed into URL, it resolves as a space
542  $parts = explode( ' ', $path );
543  }
544 
545  $count = count( $parts );
546  for ( $i = 0; $i < $count; $i++ ) {
547  $parent = $module;
548  $manager = $parent->getModuleManager();
549  if ( $manager === null ) {
550  $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
551  $this->dieWithError( [ 'apierror-badmodule-nosubmodules', $errorPath ], 'badmodule' );
552  }
553  $module = $manager->getModule( $parts[$i] );
554 
555  if ( $module === null ) {
556  $errorPath = $i ? implode( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
557  $this->dieWithError(
558  [ 'apierror-badmodule-badsubmodule', $errorPath, wfEscapeWikiText( $parts[$i] ) ],
559  'badmodule'
560  );
561  }
562  }
563 
564  return $module;
565  }
566 
571  public function getResult() {
572  // Main module has this method overridden, avoid infinite loops
573  $this->dieIfMain( __METHOD__ );
574 
575  return $this->getMain()->getResult();
576  }
577 
582  public function getErrorFormatter() {
583  // Main module has this method overridden, avoid infinite loops
584  $this->dieIfMain( __METHOD__ );
585 
586  return $this->getMain()->getErrorFormatter();
587  }
588 
594  protected function getDB() {
595  if ( !isset( $this->mReplicaDB ) ) {
596  $this->mReplicaDB = wfGetDB( DB_REPLICA, 'api' );
597  }
598 
599  return $this->mReplicaDB;
600  }
601 
605  public function getContinuationManager() {
606  // Main module has this method overridden, avoid infinite loops
607  $this->dieIfMain( __METHOD__ );
608 
609  return $this->getMain()->getContinuationManager();
610  }
611 
615  public function setContinuationManager( ApiContinuationManager $manager = null ) {
616  // Main module has this method overridden, avoid infinite loops
617  $this->dieIfMain( __METHOD__ );
618 
619  $this->getMain()->setContinuationManager( $manager );
620  }
621 
628  protected function getPermissionManager(): PermissionManager {
629  return MediaWikiServices::getInstance()->getPermissionManager();
630  }
631 
638  protected function getHookContainer() {
639  if ( !$this->hookContainer ) {
640  $this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
641  }
642  return $this->hookContainer;
643  }
644 
653  protected function getHookRunner() {
654  if ( !$this->hookRunner ) {
655  $this->hookRunner = new ApiHookRunner( $this->getHookContainer() );
656  }
657  return $this->hookRunner;
658  }
659 
660  // endregion -- end of data access methods
661 
662  /***************************************************************************/
663  // region Parameter handling
674  public function dynamicParameterDocumentation() {
675  return null;
676  }
677 
685  public function encodeParamName( $paramName ) {
686  if ( is_array( $paramName ) ) {
687  return array_map( function ( $name ) {
688  return $this->mModulePrefix . $name;
689  }, $paramName );
690  } else {
691  return $this->mModulePrefix . $paramName;
692  }
693  }
694 
707  public function extractRequestParams( $options = [] ) {
708  if ( is_bool( $options ) ) {
709  $options = [ 'parseLimit' => $options ];
710  }
711  $options += [
712  'parseLimit' => true,
713  'safeMode' => false,
714  ];
715 
716  $parseLimit = (bool)$options['parseLimit'];
717  $cacheKey = (int)$parseLimit;
718 
719  // Cache parameters, for performance and to avoid T26564.
720  if ( !isset( $this->mParamCache[$cacheKey] ) ) {
721  $params = $this->getFinalParams() ?: [];
722  $results = [];
723  $warned = [];
724 
725  // Process all non-templates and save templates for secondary
726  // processing.
727  $toProcess = [];
728  foreach ( $params as $paramName => $paramSettings ) {
729  if ( isset( $paramSettings[self::PARAM_TEMPLATE_VARS] ) ) {
730  $toProcess[] = [ $paramName, $paramSettings[self::PARAM_TEMPLATE_VARS], $paramSettings ];
731  } else {
732  try {
733  $results[$paramName] = $this->getParameterFromSettings(
734  $paramName, $paramSettings, $parseLimit
735  );
736  } catch ( ApiUsageException $ex ) {
737  $results[$paramName] = $ex;
738  }
739  }
740  }
741 
742  // Now process all the templates by successively replacing the
743  // placeholders with all client-supplied values.
744  // This bit duplicates JavaScript logic in
745  // ApiSandbox.PageLayout.prototype.updateTemplatedParams().
746  // If you update this, see if that needs updating too.
747  while ( $toProcess ) {
748  list( $name, $targets, $settings ) = array_shift( $toProcess );
749 
750  foreach ( $targets as $placeholder => $target ) {
751  if ( !array_key_exists( $target, $results ) ) {
752  // The target wasn't processed yet, try the next one.
753  // If all hit this case, the parameter has no expansions.
754  continue;
755  }
756  if ( !is_array( $results[$target] ) || !$results[$target] ) {
757  // The target was processed but has no (valid) values.
758  // That means it has no expansions.
759  break;
760  }
761 
762  // Expand this target in the name and all other targets,
763  // then requeue if there are more targets left or put in
764  // $results if all are done.
765  unset( $targets[$placeholder] );
766  $placeholder = '{' . $placeholder . '}';
767  // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
768  foreach ( $results[$target] as $value ) {
769  if ( !preg_match( '/^[^{}]*$/', $value ) ) {
770  // Skip values that make invalid parameter names.
771  $encTargetName = $this->encodeParamName( $target );
772  if ( !isset( $warned[$encTargetName][$value] ) ) {
773  $warned[$encTargetName][$value] = true;
774  $this->addWarning( [
775  'apiwarn-ignoring-invalid-templated-value',
776  wfEscapeWikiText( $encTargetName ),
777  wfEscapeWikiText( $value ),
778  ] );
779  }
780  continue;
781  }
782 
783  $newName = str_replace( $placeholder, $value, $name );
784  if ( !$targets ) {
785  try {
786  $results[$newName] = $this->getParameterFromSettings(
787  $newName,
788  $settings,
789  $parseLimit
790  );
791  } catch ( ApiUsageException $ex ) {
792  $results[$newName] = $ex;
793  }
794  } else {
795  $newTargets = [];
796  foreach ( $targets as $k => $v ) {
797  $newTargets[$k] = str_replace( $placeholder, $value, $v );
798  }
799  $toProcess[] = [ $newName, $newTargets, $settings ];
800  }
801  }
802  break;
803  }
804  }
805 
806  $this->mParamCache[$cacheKey] = $results;
807  }
808 
809  $ret = $this->mParamCache[$cacheKey];
810  if ( !$options['safeMode'] ) {
811  foreach ( $ret as $v ) {
812  if ( $v instanceof ApiUsageException ) {
813  throw $v;
814  }
815  }
816  }
817 
818  return $this->mParamCache[$cacheKey];
819  }
820 
827  protected function getParameter( $paramName, $parseLimit = true ) {
828  $ret = $this->extractRequestParams( [
829  'parseLimit' => $parseLimit,
830  'safeMode' => true,
831  ] )[$paramName];
832  if ( $ret instanceof ApiUsageException ) {
833  throw $ret;
834  }
835  return $ret;
836  }
837 
844  public function requireOnlyOneParameter( $params, ...$required ) {
845  $intersection = array_intersect( array_keys( array_filter( $params,
846  [ $this, 'parameterNotEmpty' ] ) ), $required );
847 
848  if ( count( $intersection ) > 1 ) {
849  $this->dieWithError( [
850  'apierror-invalidparammix',
851  Message::listParam( array_map(
852  function ( $p ) {
853  return '<var>' . $this->encodeParamName( $p ) . '</var>';
854  },
855  array_values( $intersection )
856  ) ),
857  count( $intersection ),
858  ] );
859  } elseif ( count( $intersection ) == 0 ) {
860  $this->dieWithError( [
861  'apierror-missingparam-one-of',
862  Message::listParam( array_map(
863  function ( $p ) {
864  return '<var>' . $this->encodeParamName( $p ) . '</var>';
865  },
866  $required
867  ) ),
868  count( $required ),
869  ], 'missingparam' );
870  }
871  }
872 
879  public function requireMaxOneParameter( $params, ...$required ) {
880  $intersection = array_intersect( array_keys( array_filter( $params,
881  [ $this, 'parameterNotEmpty' ] ) ), $required );
882 
883  if ( count( $intersection ) > 1 ) {
884  $this->dieWithError( [
885  'apierror-invalidparammix',
886  Message::listParam( array_map(
887  function ( $p ) {
888  return '<var>' . $this->encodeParamName( $p ) . '</var>';
889  },
890  array_values( $intersection )
891  ) ),
892  count( $intersection ),
893  ] );
894  }
895  }
896 
904  public function requireAtLeastOneParameter( $params, ...$required ) {
905  $intersection = array_intersect(
906  array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
907  $required
908  );
909 
910  if ( count( $intersection ) == 0 ) {
911  $this->dieWithError( [
912  'apierror-missingparam-at-least-one-of',
913  Message::listParam( array_map(
914  function ( $p ) {
915  return '<var>' . $this->encodeParamName( $p ) . '</var>';
916  },
917  $required
918  ) ),
919  count( $required ),
920  ], 'missingparam' );
921  }
922  }
923 
931  public function requirePostedParameters( $params, $prefix = 'prefix' ) {
932  // Skip if $wgDebugAPI is set or we're in internal mode
933  if ( $this->getConfig()->get( 'DebugAPI' ) || $this->getMain()->isInternalMode() ) {
934  return;
935  }
936 
937  $queryValues = $this->getRequest()->getQueryValuesOnly();
938  $badParams = [];
939  foreach ( $params as $param ) {
940  if ( $prefix !== 'noprefix' ) {
941  $param = $this->encodeParamName( $param );
942  }
943  if ( array_key_exists( $param, $queryValues ) ) {
944  $badParams[] = $param;
945  }
946  }
947 
948  if ( $badParams ) {
949  $this->dieWithError(
950  [ 'apierror-mustpostparams', implode( ', ', $badParams ), count( $badParams ) ]
951  );
952  }
953  }
954 
961  private function parameterNotEmpty( $x ) {
962  return $x !== null && $x !== false;
963  }
964 
976  public function getTitleOrPageId( $params, $load = false ) {
977  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
978 
979  $pageObj = null;
980  if ( isset( $params['title'] ) ) {
981  $titleObj = Title::newFromText( $params['title'] );
982  if ( !$titleObj || $titleObj->isExternal() ) {
983  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
984  }
985  if ( !$titleObj->canExist() ) {
986  $this->dieWithError( 'apierror-pagecannotexist' );
987  }
988  $pageObj = WikiPage::factory( $titleObj );
989  if ( $load !== false ) {
990  $pageObj->loadPageData( $load );
991  }
992  } elseif ( isset( $params['pageid'] ) ) {
993  if ( $load === false ) {
994  $load = 'fromdb';
995  }
996  $pageObj = WikiPage::newFromID( $params['pageid'], $load );
997  if ( !$pageObj ) {
998  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
999  }
1000  }
1001 
1002  return $pageObj;
1003  }
1004 
1013  public function getTitleFromTitleOrPageId( $params ) {
1014  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1015 
1016  $titleObj = null;
1017  if ( isset( $params['title'] ) ) {
1018  $titleObj = Title::newFromText( $params['title'] );
1019  if ( !$titleObj || $titleObj->isExternal() ) {
1020  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1021  }
1022  return $titleObj;
1023  } elseif ( isset( $params['pageid'] ) ) {
1024  $titleObj = Title::newFromID( $params['pageid'] );
1025  if ( !$titleObj ) {
1026  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1027  }
1028  }
1029 
1030  return $titleObj;
1031  }
1032 
1042  protected function getParameterFromSettings( $name, $settings, $parseLimit ) {
1043  $validator = $this->getMain()->getParamValidator();
1044  $value = $validator->getValue( $this, $name, $settings, [
1045  'parse-limit' => $parseLimit,
1046  'raw' => ( $settings[ParamValidator::PARAM_TYPE] ?? '' ) === 'raw',
1047  ] );
1048 
1049  // @todo Deprecate and remove this, if possible.
1050  if ( $parseLimit && isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1051  $settings[ParamValidator::PARAM_TYPE] === 'limit' &&
1052  $this->getMain()->getVal( $this->encodeParamName( $name ) ) === 'max'
1053  ) {
1054  $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1055  }
1056 
1057  return $value;
1058  }
1059 
1069  public function handleParamNormalization( $paramName, $value, $rawValue ) {
1070  $this->addWarning( [ 'apiwarn-badutf8', $paramName ] );
1071  }
1072 
1082  final public function validateToken( $token, array $params ) {
1083  $tokenType = $this->needsToken();
1085  if ( !isset( $salts[$tokenType] ) ) {
1086  throw new MWException(
1087  "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1088  'without registering it'
1089  );
1090  }
1091 
1092  $tokenObj = ApiQueryTokens::getToken(
1093  $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1094  );
1095  if ( $tokenObj->match( $token ) ) {
1096  return true;
1097  }
1098 
1099  $webUiSalt = $this->getWebUITokenSalt( $params );
1100  if ( $webUiSalt !== null && $this->getCsrfTokenSet()->matchToken( $token, $webUiSalt ) ) {
1101  return true;
1102  }
1103 
1104  return false;
1105  }
1106 
1107  // endregion -- end of parameter handling
1108 
1109  /***************************************************************************/
1110  // region Utility methods
1119  public function getWatchlistUser( $params ) {
1120  if ( $params['owner'] !== null && $params['token'] !== null ) {
1121  $services = MediaWikiServices::getInstance();
1122  $user = $services->getUserFactory()->newFromName( $params['owner'], UserFactory::RIGOR_NONE );
1123  if ( !$user || !$user->isRegistered() ) {
1124  $this->dieWithError(
1125  [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1126  );
1127  }
1128  $token = $services->getUserOptionsLookup()->getOption( $user, 'watchlisttoken' );
1129  if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1130  $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1131  }
1132  } else {
1133  $user = $this->getUser();
1134  if ( !$user->isRegistered() ) {
1135  $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1136  }
1137  $this->checkUserRightsAny( 'viewmywatchlist' );
1138  }
1139 
1140  return $user;
1141  }
1142 
1155  public static function makeMessage( $msg, IContextSource $context, array $params = null ) {
1156  if ( is_string( $msg ) ) {
1157  $msg = wfMessage( $msg );
1158  } elseif ( is_array( $msg ) ) {
1159  $msg = wfMessage( ...$msg );
1160  }
1161  if ( !$msg instanceof Message ) {
1162  return null;
1163  }
1164 
1165  $msg->setContext( $context );
1166  if ( $params ) {
1167  $msg->params( $params );
1168  }
1169 
1170  return $msg;
1171  }
1172 
1180  public function errorArrayToStatus( array $errors, User $user = null ) {
1181  if ( $user === null ) {
1182  $user = $this->getUser();
1183  }
1184 
1185  $status = Status::newGood();
1186  foreach ( $errors as $error ) {
1187  if ( !is_array( $error ) ) {
1188  $error = [ $error ];
1189  }
1190  if ( is_string( $error[0] ) && isset( self::$blockMsgMap[$error[0]] ) && $user->getBlock() ) {
1191  list( $msg, $code ) = self::$blockMsgMap[$error[0]];
1192  $status->fatal( ApiMessage::create( $msg, $code,
1193  [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
1194  ) );
1195  } else {
1196  $status->fatal( ...$error );
1197  }
1198  }
1199  return $status;
1200  }
1201 
1209  public function addBlockInfoToStatus( StatusValue $status, Authority $user = null ) {
1210  if ( $status instanceof PermissionStatus ) {
1211  $block = $status->getBlock();
1212  } else {
1213  $user = $user ?: $this->getAuthority();
1214  $block = $user->getBlock();
1215  }
1216 
1217  if ( $block ) {
1218  foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
1219  if ( $status->hasMessage( $msg ) ) {
1220  $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
1221  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1222  ) );
1223  }
1224  }
1225  }
1226  }
1227 
1232  protected function useTransactionalTimeLimit() {
1233  if ( $this->getRequest()->wasPosted() ) {
1235  }
1236  }
1237 
1246  protected function filterIDs( $fields, array $ids ) {
1247  $min = INF;
1248  $max = 0;
1249  foreach ( $fields as list( $table, $field ) ) {
1250  if ( isset( self::$filterIDsCache[$table][$field] ) ) {
1251  $row = self::$filterIDsCache[$table][$field];
1252  } else {
1253  $row = $this->getDB()->selectRow(
1254  $table,
1255  [
1256  'min_id' => "MIN($field)",
1257  'max_id' => "MAX($field)",
1258  ],
1259  '',
1260  __METHOD__
1261  );
1262  self::$filterIDsCache[$table][$field] = $row;
1263  }
1264  $min = min( $min, $row->min_id );
1265  $max = max( $max, $row->max_id );
1266  }
1267  return array_filter( $ids, static function ( $id ) use ( $min, $max ) {
1268  return ( is_int( $id ) && $id >= 0 || ctype_digit( $id ) )
1269  && $id >= $min && $id <= $max;
1270  } );
1271  }
1272 
1273  // endregion -- end of utility methods
1274 
1275  /***************************************************************************/
1276  // region Warning and error reporting
1293  public function addWarning( $msg, $code = null, $data = null ) {
1294  $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1295  }
1296 
1307  public function addDeprecation( $msg, $feature, $data = [] ) {
1308  $data = (array)$data;
1309  if ( $feature !== null ) {
1310  $data['feature'] = $feature;
1311  $this->logFeatureUsage( $feature );
1312  }
1313  $this->addWarning( $msg, 'deprecation', $data );
1314 
1315  // No real need to deduplicate here, ApiErrorFormatter does that for
1316  // us (assuming the hook is deterministic).
1317  $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1318  $this->getHookRunner()->onApiDeprecationHelp( $msgs );
1319  if ( count( $msgs ) > 1 ) {
1320  $key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
1321  $msg = ( new RawMessage( $key ) )->params( $msgs );
1322  } else {
1323  $msg = reset( $msgs );
1324  }
1325  $this->getMain()->addWarning( $msg, 'deprecation-help' );
1326  }
1327 
1340  public function addError( $msg, $code = null, $data = null ) {
1341  $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1342  }
1343 
1353  public function addMessagesFromStatus(
1354  StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
1355  ) {
1356  $this->getErrorFormatter()->addMessagesFromStatus(
1357  $this->getModulePath(), $status, $types, $filter
1358  );
1359  }
1360 
1374  public function dieWithError( $msg, $code = null, $data = null, $httpCode = null ) {
1375  throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1376  }
1377 
1386  public function dieWithException( Throwable $exception, array $options = [] ) {
1387  $this->dieWithError(
1388  // @phan-suppress-next-line PhanTypeMismatchArgument
1389  $this->getErrorFormatter()->getMessageFromException( $exception, $options )
1390  );
1391  }
1392 
1401  public function dieBlocked( Block $block ) {
1402  // Die using the appropriate message depending on block type
1403  if ( $block->getType() == Block::TYPE_AUTO ) {
1404  $this->dieWithError(
1405  'apierror-autoblocked',
1406  'autoblocked',
1407  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1408  );
1409  } elseif ( !$block->isSitewide() ) {
1410  $this->dieWithError(
1411  'apierror-blocked-partial',
1412  'blocked',
1413  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1414  );
1415  } else {
1416  $this->dieWithError(
1417  'apierror-blocked',
1418  'blocked',
1419  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1420  );
1421  }
1422  }
1423 
1432  public function dieStatus( StatusValue $status ) {
1433  if ( $status->isGood() ) {
1434  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
1435  }
1436 
1437  // ApiUsageException needs a fatal status, but this method has
1438  // historically accepted any non-good status. Convert it if necessary.
1439  $status->setOK( false );
1440  if ( !$status->getErrorsByType( 'error' ) ) {
1441  $newStatus = Status::newGood();
1442  foreach ( $status->getErrorsByType( 'warning' ) as $err ) {
1443  $newStatus->fatal( $err['message'], ...$err['params'] );
1444  }
1445  if ( !$newStatus->getErrorsByType( 'error' ) ) {
1446  $newStatus->fatal( 'unknownerror-nocode' );
1447  }
1448  $status = $newStatus;
1449  }
1450 
1451  $this->addBlockInfoToStatus( $status );
1452  throw new ApiUsageException( $this, $status );
1453  }
1454 
1460  public function dieReadOnly() {
1461  $this->dieWithError(
1462  'apierror-readonly',
1463  'readonly',
1464  [ 'readonlyreason' => wfReadOnlyReason() ]
1465  );
1466  }
1467 
1476  public function checkUserRightsAny( $rights, $user = null ) {
1477  $authority = $this->getAuthority();
1478  if ( $user !== null ) {
1479  wfDeprecatedMsg( __METHOD__ . ': $user parameter is deprecated', '1.36' );
1480  $authority = $user;
1481  }
1482  $rights = (array)$rights;
1483  if ( !$authority->isAllowedAny( ...$rights ) ) {
1484  $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
1485  }
1486  }
1487 
1502  public function checkTitleUserPermissions(
1503  $pageIdentity,
1504  $actions,
1505  array $options = []
1506  ) {
1507  if ( !$pageIdentity instanceof PageIdentity ) {
1508  wfDeprecatedMsg( __METHOD__ . ': passing LinkTarget as $pageIdentity parameter is deprecated',
1509  '1.36' );
1510  $pageIdentity = Title::castFromLinkTarget( $pageIdentity );
1511  }
1512  $status = new PermissionStatus();
1513  foreach ( (array)$actions as $action ) {
1514  if ( $this->isWriteMode() ) {
1515  $this->getAuthority()->authorizeWrite( $action, $pageIdentity, $status );
1516  } else {
1517  $this->getAuthority()->authorizeRead( $action, $pageIdentity, $status );
1518  }
1519  }
1520  if ( !$status->isGood() ) {
1521  if ( !empty( $options['autoblock'] ) ) {
1522  $this->getUser()->spreadAnyEditBlock();
1523  }
1524  $this->dieStatus( $status );
1525  }
1526  }
1527 
1539  public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
1540  if ( $this->getConfig()->get( 'DebugAPI' ) !== true ) {
1541  $this->dieWithError( $msg, $code, $data, $httpCode );
1542  } else {
1543  $this->addWarning( $msg, $code, $data );
1544  }
1545  }
1546 
1557  protected function dieContinueUsageIf( $condition ) {
1558  if ( $condition ) {
1559  $this->dieWithError( 'apierror-badcontinue' );
1560  }
1561  }
1562 
1569  protected static function dieDebug( $method, $message ) {
1570  throw new MWException( "Internal error in $method: $message" );
1571  }
1572 
1579  public function logFeatureUsage( $feature ) {
1580  static $loggedFeatures = [];
1581 
1582  // Only log each feature once per request. We can get multiple calls from calls to
1583  // extractRequestParams() with different values for 'parseLimit', for example.
1584  if ( isset( $loggedFeatures[$feature] ) ) {
1585  return;
1586  }
1587  $loggedFeatures[$feature] = true;
1588 
1589  $request = $this->getRequest();
1590  $ctx = [
1591  'feature' => $feature,
1592  // Spaces to underscores in 'username' for historical reasons.
1593  'username' => str_replace( ' ', '_', $this->getUser()->getName() ),
1594  'clientip' => $request->getIP(),
1595  'referer' => (string)$request->getHeader( 'Referer' ),
1596  'agent' => $this->getMain()->getUserAgent(),
1597  ];
1598 
1599  // Text string is deprecated. Remove (or replace with just $feature) in MW 1.34.
1600  $s = '"' . addslashes( $ctx['feature'] ) . '"' .
1601  ' "' . wfUrlencode( $ctx['username'] ) . '"' .
1602  ' "' . $ctx['clientip'] . '"' .
1603  ' "' . addslashes( $ctx['referer'] ) . '"' .
1604  ' "' . addslashes( $ctx['agent'] ) . '"';
1605 
1606  wfDebugLog( 'api-feature-usage', $s, 'private', $ctx );
1607  }
1608 
1609  // endregion -- end of warning and error reporting
1610 
1611  /***************************************************************************/
1612  // region Help message generation
1625  protected function getSummaryMessage() {
1626  return "apihelp-{$this->getModulePath()}-summary";
1627  }
1628 
1639  protected function getExtendedDescription() {
1640  return [ [
1641  "apihelp-{$this->getModulePath()}-extended-description",
1642  'api-help-no-extended-description',
1643  ] ];
1644  }
1645 
1653  public function getFinalSummary() {
1654  $msg = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
1655  $this->getModulePrefix(),
1656  $this->getModuleName(),
1657  $this->getModulePath(),
1658  ] );
1659  return $msg;
1660  }
1661 
1669  public function getFinalDescription() {
1670  $summary = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
1671  $this->getModulePrefix(),
1672  $this->getModuleName(),
1673  $this->getModulePath(),
1674  ] );
1675  $extendedDescription = self::makeMessage(
1676  $this->getExtendedDescription(), $this->getContext(), [
1677  $this->getModulePrefix(),
1678  $this->getModuleName(),
1679  $this->getModulePath(),
1680  ]
1681  );
1682 
1683  $msgs = [ $summary, $extendedDescription ];
1684 
1685  $this->getHookRunner()->onAPIGetDescriptionMessages( $this, $msgs );
1686 
1687  return $msgs;
1688  }
1689 
1698  public function getFinalParams( $flags = 0 ) {
1699  // @phan-suppress-next-line PhanParamTooMany
1700  $params = $this->getAllowedParams( $flags );
1701  if ( !$params ) {
1702  $params = [];
1703  }
1704 
1705  if ( $this->needsToken() ) {
1706  $params['token'] = [
1707  self::PARAM_TYPE => 'string',
1708  self::PARAM_REQUIRED => true,
1709  self::PARAM_SENSITIVE => true,
1710  self::PARAM_HELP_MSG => [
1711  'api-help-param-token',
1712  $this->needsToken(),
1713  ],
1714  ] + ( $params['token'] ?? [] );
1715  }
1716 
1717  $this->getHookRunner()->onAPIGetAllowedParams( $this, $params, $flags );
1718 
1719  return $params;
1720  }
1721 
1729  public function getFinalParamDescription() {
1730  $prefix = $this->getModulePrefix();
1731  $name = $this->getModuleName();
1732  $path = $this->getModulePath();
1733 
1734  $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
1735  $msgs = [];
1736  foreach ( $params as $param => $settings ) {
1737  if ( !is_array( $settings ) ) {
1738  $settings = [];
1739  }
1740 
1741  if ( isset( $settings[self::PARAM_HELP_MSG] ) ) {
1742  $msg = $settings[self::PARAM_HELP_MSG];
1743  } else {
1744  $msg = $this->msg( "apihelp-{$path}-param-{$param}" );
1745  }
1746  $msg = self::makeMessage( $msg, $this->getContext(),
1747  [ $prefix, $param, $name, $path ] );
1748  if ( !$msg ) {
1749  self::dieDebug( __METHOD__,
1750  'Value in ApiBase::PARAM_HELP_MSG is not valid' );
1751  }
1752  $msgs[$param] = [ $msg ];
1753 
1754  if ( isset( $settings[self::PARAM_TYPE] ) &&
1755  $settings[self::PARAM_TYPE] === 'submodule'
1756  ) {
1757  if ( isset( $settings[self::PARAM_SUBMODULE_MAP] ) ) {
1758  $map = $settings[self::PARAM_SUBMODULE_MAP];
1759  } else {
1760  $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
1761  $map = [];
1762  foreach ( $this->getModuleManager()->getNames( $param ) as $submoduleName ) {
1763  $map[$submoduleName] = $prefix . $submoduleName;
1764  }
1765  }
1766 
1767  $submodules = [];
1768  $submoduleFlags = []; // for sorting: higher flags are sorted later
1769  $submoduleNames = []; // for sorting: lexicographical, ascending
1770  foreach ( $map as $v => $m ) {
1771  $isDeprecated = false;
1772  $isInternal = false;
1773  $summary = null;
1774  try {
1775  $submod = $this->getModuleFromPath( $m );
1776  if ( $submod ) {
1777  $summary = $submod->getFinalSummary();
1778  $isDeprecated = $submod->isDeprecated();
1779  $isInternal = $submod->isInternal();
1780  }
1781  } catch ( ApiUsageException $ex ) {
1782  // Ignore
1783  }
1784  if ( $summary ) {
1785  $key = $summary->getKey();
1786  $params = $summary->getParams();
1787  } else {
1788  $key = 'api-help-undocumented-module';
1789  $params = [ $m ];
1790  }
1791  $m = new ApiHelpParamValueMessage(
1792  "[[Special:ApiHelp/$m|$v]]",
1793  $key,
1794  $params,
1795  $isDeprecated,
1796  $isInternal
1797  );
1798  $submodules[] = $m->setContext( $this->getContext() );
1799  $submoduleFlags[] = ( $isDeprecated ? 1 : 0 ) | ( $isInternal ? 2 : 0 );
1800  $submoduleNames[] = $v;
1801  }
1802  // sort $submodules by $submoduleFlags and $submoduleNames
1803  array_multisort( $submoduleFlags, $submoduleNames, $submodules );
1804  $msgs[$param] = array_merge( $msgs[$param], $submodules );
1805  } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1806  if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1807  self::dieDebug( __METHOD__,
1808  'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
1809  }
1810  if ( !is_array( $settings[self::PARAM_TYPE] ) ) {
1811  self::dieDebug( __METHOD__,
1812  'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
1813  'ApiBase::PARAM_TYPE is an array' );
1814  }
1815 
1816  $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
1817  $deprecatedValues = $settings[self::PARAM_DEPRECATED_VALUES] ?? [];
1818 
1819  foreach ( $settings[self::PARAM_TYPE] as $value ) {
1820  if ( isset( $valueMsgs[$value] ) ) {
1821  $msg = $valueMsgs[$value];
1822  } else {
1823  $msg = "apihelp-{$path}-paramvalue-{$param}-{$value}";
1824  }
1825  $m = self::makeMessage( $msg, $this->getContext(),
1826  [ $prefix, $param, $name, $path, $value ] );
1827  if ( $m ) {
1828  $m = new ApiHelpParamValueMessage(
1829  $value,
1830  // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal
1831  [ $m->getKey(), 'api-help-param-no-description' ],
1832  $m->getParams(),
1833  isset( $deprecatedValues[$value] )
1834  );
1835  $msgs[$param][] = $m->setContext( $this->getContext() );
1836  } else {
1837  self::dieDebug( __METHOD__,
1838  "Value in ApiBase::PARAM_HELP_MSG_PER_VALUE for $value is not valid" );
1839  }
1840  }
1841  }
1842 
1843  if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
1844  if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
1845  self::dieDebug( __METHOD__,
1846  'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
1847  }
1848  foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
1849  $m = self::makeMessage( $m, $this->getContext(),
1850  [ $prefix, $param, $name, $path ] );
1851  if ( $m ) {
1852  $msgs[$param][] = $m;
1853  } else {
1854  self::dieDebug( __METHOD__,
1855  'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
1856  }
1857  }
1858  }
1859  }
1860 
1861  $this->getHookRunner()->onAPIGetParamDescriptionMessages( $this, $msgs );
1862 
1863  return $msgs;
1864  }
1865 
1875  protected function getHelpFlags() {
1876  $flags = [];
1877 
1878  if ( $this->isDeprecated() ) {
1879  $flags[] = 'deprecated';
1880  }
1881  if ( $this->isInternal() ) {
1882  $flags[] = 'internal';
1883  }
1884  if ( $this->isReadMode() ) {
1885  $flags[] = 'readrights';
1886  }
1887  if ( $this->isWriteMode() ) {
1888  $flags[] = 'writerights';
1889  }
1890  if ( $this->mustBePosted() ) {
1891  $flags[] = 'mustbeposted';
1892  }
1893 
1894  return $flags;
1895  }
1896 
1908  protected function getModuleSourceInfo() {
1909  global $IP;
1910 
1911  if ( $this->mModuleSource !== false ) {
1912  return $this->mModuleSource;
1913  }
1914 
1915  // First, try to find where the module comes from...
1916  $rClass = new ReflectionClass( $this );
1917  $path = $rClass->getFileName();
1918  if ( !$path ) {
1919  // No path known?
1920  $this->mModuleSource = null;
1921  return null;
1922  }
1923  $path = realpath( $path ) ?: $path;
1924 
1925  // Build map of extension directories to extension info
1926  if ( self::$extensionInfo === null ) {
1927  $extDir = $this->getConfig()->get( 'ExtensionDirectory' );
1928  self::$extensionInfo = [
1929  realpath( __DIR__ ) ?: __DIR__ => [
1930  'path' => $IP,
1931  'name' => 'MediaWiki',
1932  'license-name' => 'GPL-2.0-or-later',
1933  ],
1934  realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
1935  realpath( $extDir ) ?: $extDir => null,
1936  ];
1937  $keep = [
1938  'path' => null,
1939  'name' => null,
1940  'namemsg' => null,
1941  'license-name' => null,
1942  ];
1944  foreach ( $credits as $group ) {
1945  foreach ( $group as $ext ) {
1946  if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
1947  // This shouldn't happen, but does anyway.
1948  continue;
1949  }
1950 
1951  $extpath = $ext['path'];
1952  if ( !is_dir( $extpath ) ) {
1953  $extpath = dirname( $extpath );
1954  }
1955  self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
1956  array_intersect_key( $ext, $keep );
1957  }
1958  }
1959  }
1960 
1961  // Now traverse parent directories until we find a match or run out of
1962  // parents.
1963  do {
1964  if ( array_key_exists( $path, self::$extensionInfo ) ) {
1965  // Found it!
1966  $this->mModuleSource = self::$extensionInfo[$path];
1967  return $this->mModuleSource;
1968  }
1969 
1970  $oldpath = $path;
1971  $path = dirname( $path );
1972  } while ( $path !== $oldpath );
1973 
1974  // No idea what extension this might be.
1975  $this->mModuleSource = null;
1976  return null;
1977  }
1978 
1991  public function modifyHelp( array &$help, array $options, array &$tocData ) {
1992  }
1993 
1994  // endregion -- end of help message generation
1995 
1996 }
1997 
1998 /*
1999  * This file uses VisualStudio style region/endregion fold markers which are
2000  * recognised by PHPStorm. If modelines are enabled, the following editor
2001  * configuration will also enable folding in vim, if it is in the last 5 lines
2002  * of the file. We also use "@name" which creates sections in Doxygen.
2003  *
2004  * vim: foldmarker=//\ region,//\ endregion foldmethod=marker
2005  */
ApiBase\checkTitleUserPermissions
checkTitleUserPermissions( $pageIdentity, $actions, array $options=[])
Helper function for permission-denied errors.
Definition: ApiBase.php:1502
Page\PageIdentity
Interface for objects (potentially) representing an editable wiki page.
Definition: PageIdentity.php:64
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:49
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:39
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:72
ApiBase\PARAM_SUBMODULE_MAP
const PARAM_SUBMODULE_MAP
Definition: ApiBase.php:79
ApiBase\$mModuleSource
array null false $mModuleSource
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:203
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:415
ApiUsageException
Exception used to abort API execution with an error.
Definition: ApiUsageException.php:29
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:47
ApiBase\$mMainModule
ApiMain $mMainModule
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:194
StatusValue
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: StatusValue.php:43
ApiBase\getParent
getParent()
Get the parent of this module.
Definition: ApiBase.php:475
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1293
ApiBase\getSummaryMessage
getSummaryMessage()
Return the summary message.
Definition: ApiBase.php:1625
ApiUsageException\newWithMessage
static newWithMessage(?ApiBase $module, $msg, $code=null, $data=null, $httpCode=0, Throwable $previous=null)
Definition: ApiUsageException.php:68
ApiBase\getFinalParams
getFinalParams( $flags=0)
Get final list of parameters, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:1698
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
Definition: ApiBase.php:78
StatusValue\getErrorsByType
getErrorsByType( $type)
Returns a list of status messages of the given type.
Definition: StatusValue.php:290
ApiBase\$hookContainer
HookContainer $hookContainer
Definition: ApiBase.php:60
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:186
ApiBase\parameterNotEmpty
parameterNotEmpty( $x)
Callback function used in requireOnlyOneParameter to check whether required parameters are set.
Definition: ApiBase.php:961
ApiBase\validateToken
validateToken( $token, array $params)
Validate the supplied token.
Definition: ApiBase.php:1082
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:1374
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:105
ApiBase\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiBase.php:279
StatusValue\replaceMessage
replaceMessage( $source, $dest)
If the specified source message exists, replace it with the specified destination message,...
Definition: StatusValue.php:336
ApiBase\PARAM_ALL
const PARAM_ALL
Definition: ApiBase.php:81
ApiBase\$extensionInfo
static array $extensionInfo
Maps extension paths to info arrays.
Definition: ApiBase.php:179
ApiBase\getTitleOrPageId
getTitleOrPageId( $params, $load=false)
Get a WikiPage object from a title or pageid param, if possible.
Definition: ApiBase.php:976
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:72
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:571
ApiBase\__construct
__construct(ApiMain $mainModule, $moduleName, $modulePrefix='')
Definition: ApiBase.php:211
ApiBase\getParameterFromSettings
getParameterFromSettings( $name, $settings, $parseLimit)
Using the settings determine the value for the given parameter.
Definition: ApiBase.php:1042
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:292
ApiBase\mustBePosted
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiBase.php:351
ApiBase\logFeatureUsage
logFeatureUsage( $feature)
Write logging information for API features to a debug log, for usage analysis.
Definition: ApiBase.php:1579
ApiBase\checkUserRightsAny
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1476
ApiBase\shouldCheckMaxlag
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition: ApiBase.php:317
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:1539
ApiBase\setContinuationManager
setContinuationManager(ApiContinuationManager $manager=null)
Definition: ApiBase.php:615
Wikimedia\ParamValidator\TypeDef\EnumDef
Type definition for enumeration types.
Definition: EnumDef.php:32
ApiBase\getExtendedDescription
getExtendedDescription()
Return the extended help text message.
Definition: ApiBase.php:1639
ApiBase\PARAM_ISMULTI_LIMIT1
const PARAM_ISMULTI_LIMIT1
Definition: ApiBase.php:85
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1182
ApiBase\getHookContainer
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
Definition: ApiBase.php:638
ApiBase\getDB
getDB()
Gets a default replica DB connection object.
Definition: ApiBase.php:594
ApiBase\addMessagesFromStatus
addMessagesFromStatus(StatusValue $status, $types=[ 'warning', 'error'], array $filter=[])
Add warnings and/or errors from a Status.
Definition: ApiBase.php:1353
ApiBase\makeMessage
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
Definition: ApiBase.php:1155
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:81
ApiBase\dynamicParameterDocumentation
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition: ApiBase.php:674
ApiBase\modifyHelp
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition: ApiBase.php:1991
ApiBase\PARAM_ALLOW_DUPLICATES
const PARAM_ALLOW_DUPLICATES
Definition: ApiBase.php:76
ContextSource\getUser
getUser()
Definition: ContextSource.php:136
MediaWiki\Api\ApiHookRunner
This class provides an implementation of the hook interfaces used by the core Action API,...
Definition: ApiHookRunner.php:55
StatusValue\setOK
setOK( $ok)
Change operation status.
Definition: StatusValue.php:158
ApiBase\PARAM_DEPRECATED_VALUES
const PARAM_DEPRECATED_VALUES
Definition: ApiBase.php:84
ApiBase\lacksSameOriginSecurity
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:502
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:112
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:958
ApiBase\getWebUITokenSalt
getWebUITokenSalt(array $params)
Fetch the salt used in the Web UI corresponding to this module.
Definition: ApiBase.php:409
Message\listParam
static listParam(array $list, $type='text')
Definition: Message.php:1213
ApiBase\isMain
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition: ApiBase.php:465
ApiBase\isReadMode
isReadMode()
Indicates whether this module requires read rights.
Definition: ApiBase.php:326
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:55
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:533
ApiBase\getFinalParamDescription
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:1729
ApiBase\PARAM_SENSITIVE
const PARAM_SENSITIVE
Definition: ApiBase.php:83
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:1401
ApiBase\PARAM_ISMULTI_LIMIT2
const PARAM_ISMULTI_LIMIT2
Definition: ApiBase.php:86
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:136
ApiBase\getFinalSummary
getFinalSummary()
Get final module summary.
Definition: ApiBase.php:1653
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
Definition: ApiBase.php:77
ApiBase\PARAM_MIN
const PARAM_MIN
Definition: ApiBase.php:75
StatusValue\isGood
isGood()
Returns whether the operation completed and didn't have any error or warnings.
Definition: StatusValue.php:122
wfDeprecatedMsg
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
Definition: GlobalFunctions.php:1028
MWException
MediaWiki exception.
Definition: MWException.php:29
MediaWiki\Block\Block\getType
getType()
Get the type of target for this particular block.
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:263
ApiBase\getFinalDescription
getFinalDescription()
Get final module description, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:1669
wfTransactionalTimeLimit
wfTransactionalTimeLimit()
Raise the request time limit to $wgTransactionalTimeLimit.
Definition: GlobalFunctions.php:2414
ApiBase\getModulePath
getModulePath()
Get the path to this module.
Definition: ApiBase.php:515
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2226
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:163
MediaWiki\Block\Block\isSitewide
isSitewide()
Indicates that the block is a sitewide block.
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:33
ApiBase\addBlockInfoToStatus
addBlockInfoToStatus(StatusValue $status, Authority $user=null)
Add block info to block messages in a Status.
Definition: ApiBase.php:1209
ApiQueryTokens\getTokenTypeSalts
static getTokenTypeSalts()
Get the salts for known token types.
Definition: ApiQueryTokens.php:66
ApiBase\$hookRunner
ApiHookRunner $hookRunner
Definition: ApiBase.php:63
ApiBase\PARAM_MAX
const PARAM_MAX
Definition: ApiBase.php:73
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:707
ApiBase\handleParamNormalization
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition: ApiBase.php:1069
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
ApiBase\isDeprecated
isDeprecated()
Indicates whether this module is deprecated.
Definition: ApiBase.php:361
ApiBase\requireAtLeastOneParameter
requireAtLeastOneParameter( $params,... $required)
Die if none of a certain set of parameters is set and not false.
Definition: ApiBase.php:904
ApiBase\$mReplicaDB
$mReplicaDB
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:197
ApiMessage\create
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
Definition: ApiMessage.php:43
ApiBase\PARAM_EXTRA_NAMESPACES
const PARAM_EXTRA_NAMESPACES
Definition: ApiBase.php:82
ApiBase\ALL_DEFAULT_STRING
const ALL_DEFAULT_STRING
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:160
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:63
Wikimedia\ParamValidator\TypeDef\StringDef
Type definition for string types.
Definition: StringDef.php:24
ApiBase\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiBase.php:289
ApiBlockInfoTrait
trait ApiBlockInfoTrait
Definition: ApiBlockInfoTrait.php:27
ApiBase\needsToken
needsToken()
Returns the token type this module requires in order to execute.
Definition: ApiBase.php:395
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:448
ApiBase\$mModuleName
string $mModuleName
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:196
MediaWiki\Block\Block
Represents a block that may prevent users from performing specific operations.
Definition: Block.php:37
MediaWiki\Permissions\Authority
This interface represents the authority associated the current execution context, such as a web reque...
Definition: Authority.php:37
ApiBase\getContinuationManager
getContinuationManager()
Definition: ApiBase.php:605
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:197
ApiBase\addError
addError( $msg, $code=null, $data=null)
Add an error for this module without aborting.
Definition: ApiBase.php:1340
MediaWiki\Permissions\PermissionManager
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Definition: PermissionManager.php:53
ApiBase\getWatchlistUser
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition: ApiBase.php:1119
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
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:844
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:879
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1557
SpecialVersion\getCredits
static getCredits(ExtensionRegistry $reg, Config $conf)
Definition: SpecialVersion.php:68
ApiBase\addDeprecation
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition: ApiBase.php:1307
ContextSource\getAuthority
getAuthority()
Definition: ContextSource.php:144
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
ApiBase\LIMIT_SML2
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition: ApiBase.php:169
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:685
ContextSource\getCsrfTokenSet
getCsrfTokenSet()
Get a repository to obtain and match CSRF tokens.
Definition: ContextSource.php:219
ApiBase\dieReadOnly
dieReadOnly()
Helper function for readonly errors.
Definition: ApiBase.php:1460
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:176
WikiPage\newFromID
static newFromID( $id, $from='fromdb')
Constructor from a page id.
Definition: WikiPage.php:221
ApiBase\getPermissionManager
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition: ApiBase.php:628
ApiBase\useTransactionalTimeLimit
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: ApiBase.php:1232
ApiBase\getConditionalRequestData
getConditionalRequestData( $condition)
Returns data for HTTP conditional request mechanisms.
Definition: ApiBase.php:426
ApiBase\isWriteMode
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiBase.php:342
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1456
ApiBase\dieIfMain
dieIfMain(string $methodName)
Used to avoid infinite loops - the ApiMain class should override some methods, if it doesn't and uses...
Definition: ApiBase.php:486
ApiBase\PARAM_HELP_MSG_INFO
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition: ApiBase.php:122
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:58
MediaWiki\Permissions\PermissionStatus
A StatusValue for permission errors.
Definition: PermissionStatus.php:35
ApiBase\PARAM_RANGE_ENFORCE
const PARAM_RANGE_ENFORCE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:95
ApiBase\PARAM_VALUE_LINKS
const PARAM_VALUE_LINKS
Deprecated and unused.
Definition: ApiBase.php:129
Wikimedia\ParamValidator\TypeDef\IntegerDef
Type definition for integer types.
Definition: IntegerDef.php:23
ApiBase\PARAM_TEMPLATE_VARS
const PARAM_TEMPLATE_VARS
(array) Indicate that this is a templated parameter, and specify replacements.
Definition: ApiBase.php:156
ApiBase\filterIDs
filterIDs( $fields, array $ids)
Filter out-of-range values from a list of positive integer IDs.
Definition: ApiBase.php:1246
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:165
wfReadOnlyReason
wfReadOnlyReason()
Check if the site is in read-only mode and return the message if so.
Definition: GlobalFunctions.php:1112
ApiQueryTokens\getToken
static getToken(User $user, MediaWiki\Session\Session $session, $salt)
Get a token from a salt.
Definition: ApiQueryTokens.php:99
ApiBase\getModuleManager
getModuleManager()
Get the module manager, or null if this module has no sub-modules.
Definition: ApiBase.php:249
WikiPage\factory
static factory(PageIdentity $pageIdentity)
Create a WikiPage object of the appropriate class for the given PageIdentity.
Definition: WikiPage.php:206
Wikimedia\ParamValidator\ParamValidator::TypeDef\NamespaceDef
Type definition for namespace types.
Definition: NamespaceDef.php:18
ApiBase\isInternal
isInternal()
Indicates whether this module is "internal" Internal API modules are not (yet) intended for 3rd party...
Definition: ApiBase.php:372
ApiBase\getModuleSourceInfo
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition: ApiBase.php:1908
$path
$path
Definition: NoLocalSettings.php:25
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:70
ApiBase\getParameter
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition: ApiBase.php:827
ApiBase\dieWithException
dieWithException(Throwable $exception, array $options=[])
Abort execution with an error derived from a throwable.
Definition: ApiBase.php:1386
ApiBase\dieStatus
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1432
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:440
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:71
Message
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition: Message.php:138
ApiBase\$blockMsgMap
static array $blockMsgMap
Map of web UI block messages to corresponding API messages and codes.
Definition: ApiBase.php:185
ApiBase\PARAM_MAX2
const PARAM_MAX2
Definition: ApiBase.php:74
StatusValue\hasMessage
hasMessage( $message)
Returns true if the specified message is present as a warning or error.
Definition: StatusValue.php:308
ApiBase\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiBase.php:306
$help
$help
Definition: mcc.php:32
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:456
$ext
if(!is_readable( $file)) $ext
Definition: router.php:48
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition: HookContainer.php:45
ApiBase\PARAM_MAX_CHARS
const PARAM_MAX_CHARS
Definition: ApiBase.php:88
ApiBase\getTitleFromTitleOrPageId
getTitleFromTitleOrPageId( $params)
Get a Title object from a title or pageid param, if possible.
Definition: ApiBase.php:1013
Title\castFromLinkTarget
static castFromLinkTarget( $linkTarget)
Same as newFromLinkTarget, but if passed null, returns null.
Definition: Title.php:351
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
ApiBase\$mModulePrefix
string $mModulePrefix
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:196
RawMessage
Variant of the Message class.
Definition: RawMessage.php:35
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:138
ApiBase\PARAM_SUBMODULE_PARAM_PREFIX
const PARAM_SUBMODULE_PARAM_PREFIX
Definition: ApiBase.php:80
ApiBase\$mParamCache
array $mParamCache
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:201
ApiBase\PARAM_MAX_BYTES
const PARAM_MAX_BYTES
Definition: ApiBase.php:87
ApiHelpParamValueMessage
Message subclass that prepends wikitext for API help.
Definition: ApiHelpParamValueMessage.php:34
ApiBase\getHookRunner
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:653
$IP
$IP
Definition: WebStart.php:49
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:68
Title\newFromID
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:561
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1569
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:1180
MediaWiki\User\UserFactory
Creates User objects.
Definition: UserFactory.php:41
ApiBase\getErrorFormatter
getErrorFormatter()
Definition: ApiBase.php:582
MediaWiki\Api\Validator\SubmoduleDef
Type definition for submodule types.
Definition: SubmoduleDef.php:17
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:931
Wikimedia\ParamValidator\ParamValidator
Service for formatting and validating API parameters.
Definition: ParamValidator.php:42
ApiBase\LIMIT_SML1
const LIMIT_SML1
Slow query, standard limit.
Definition: ApiBase.php:167
ApiBase\getHelpFlags
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition: ApiBase.php:1875
ApiBase\$filterIDsCache
static stdClass[][] $filterIDsCache
Cache for self::filterIDs()
Definition: ApiBase.php:182