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 
73  public const PARAM_DFLT = ParamValidator::PARAM_DEFAULT;
77  public const PARAM_ISMULTI = ParamValidator::PARAM_ISMULTI;
81  public const PARAM_TYPE = ParamValidator::PARAM_TYPE;
85  public const PARAM_MAX = IntegerDef::PARAM_MAX;
89  public const PARAM_MAX2 = IntegerDef::PARAM_MAX2;
93  public const PARAM_MIN = IntegerDef::PARAM_MIN;
97  public const PARAM_ALLOW_DUPLICATES = ParamValidator::PARAM_ALLOW_DUPLICATES;
101  public const PARAM_DEPRECATED = ParamValidator::PARAM_DEPRECATED;
105  public const PARAM_REQUIRED = ParamValidator::PARAM_REQUIRED;
109  public const PARAM_SUBMODULE_MAP = SubmoduleDef::PARAM_SUBMODULE_MAP;
113  public const PARAM_SUBMODULE_PARAM_PREFIX = SubmoduleDef::PARAM_SUBMODULE_PARAM_PREFIX;
117  public const PARAM_ALL = ParamValidator::PARAM_ALL;
121  public const PARAM_EXTRA_NAMESPACES = NamespaceDef::PARAM_EXTRA_NAMESPACES;
125  public const PARAM_SENSITIVE = ParamValidator::PARAM_SENSITIVE;
129  public const PARAM_DEPRECATED_VALUES = EnumDef::PARAM_DEPRECATED_VALUES;
133  public const PARAM_ISMULTI_LIMIT1 = ParamValidator::PARAM_ISMULTI_LIMIT1;
137  public const PARAM_ISMULTI_LIMIT2 = ParamValidator::PARAM_ISMULTI_LIMIT2;
141  public const PARAM_MAX_BYTES = StringDef::PARAM_MAX_BYTES;
145  public const PARAM_MAX_CHARS = StringDef::PARAM_MAX_CHARS;
152  public const PARAM_RANGE_ENFORCE = 'api-param-range-enforce';
153 
154  // region API-specific constants for ::getAllowedParams() arrays
162  public const PARAM_HELP_MSG = 'api-param-help-msg';
163 
169  public const PARAM_HELP_MSG_APPEND = 'api-param-help-msg-append';
170 
179  public const PARAM_HELP_MSG_INFO = 'api-param-help-msg-info';
180 
186  public const PARAM_VALUE_LINKS = 'api-param-value-links';
187 
195  public const PARAM_HELP_MSG_PER_VALUE = 'api-param-help-msg-per-value';
196 
213  public const PARAM_TEMPLATE_VARS = 'param-template-vars';
214 
215  // endregion -- end of API-specific constants for ::getAllowedParams() arrays
216 
217  public const ALL_DEFAULT_STRING = '*';
218 
220  public const LIMIT_BIG1 = 500;
222  public const LIMIT_BIG2 = 5000;
224  public const LIMIT_SML1 = 50;
226  public const LIMIT_SML2 = 500;
227 
233  public const GET_VALUES_FOR_HELP = 1;
234 
236  private static $extensionInfo = null;
237 
239  private static $filterIDsCache = [];
240 
242  private static $blockMsgMap = [
243  'blockedtext' => [ 'apierror-blocked', 'blocked' ],
244  'blockedtext-partial' => [ 'apierror-blocked-partial', 'blocked' ],
245  'autoblockedtext' => [ 'apierror-autoblocked', 'autoblocked' ],
246  'systemblockedtext' => [ 'apierror-systemblocked', 'blocked' ],
247  'blockedtext-composite' => [ 'apierror-blocked', 'blocked' ],
248  ];
249 
251  private $mMainModule;
254  private $mReplicaDB = null;
258  private $mParamCache = [];
260  private $mModuleSource = false;
261 
268  public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
269  $this->mMainModule = $mainModule;
270  $this->mModuleName = $moduleName;
271  $this->mModulePrefix = $modulePrefix;
272 
273  if ( !$this->isMain() ) {
274  $this->setContext( $mainModule->getContext() );
275  }
276  }
277 
278  /***************************************************************************/
279  // region Methods to implement
298  abstract public function execute();
299 
306  public function getModuleManager() {
307  return null;
308  }
309 
320  public function getCustomPrinter() {
321  return null;
322  }
323 
336  protected function getExamplesMessages() {
337  return [];
338  }
339 
346  public function getHelpUrls() {
347  return [];
348  }
349 
363  protected function getAllowedParams( /* $flags = 0 */ ) {
364  // int $flags is not declared because it causes "Strict standards"
365  // warning. Most derived classes do not implement it.
366  return [];
367  }
368 
374  public function shouldCheckMaxlag() {
375  return true;
376  }
377 
383  public function isReadMode() {
384  return true;
385  }
386 
399  public function isWriteMode() {
400  return false;
401  }
402 
408  public function mustBePosted() {
409  return $this->needsToken() !== false;
410  }
411 
418  public function isDeprecated() {
419  return false;
420  }
421 
429  public function isInternal() {
430  return false;
431  }
432 
452  public function needsToken() {
453  return false;
454  }
455 
466  protected function getWebUITokenSalt( array $params ) {
467  return null;
468  }
469 
483  public function getConditionalRequestData( $condition ) {
484  return null;
485  }
486 
487  // endregion -- end of methods to implement
488 
489  /***************************************************************************/
490  // region Data access methods
497  public function getModuleName() {
498  return $this->mModuleName;
499  }
500 
505  public function getModulePrefix() {
506  return $this->mModulePrefix;
507  }
508 
513  public function getMain() {
514  return $this->mMainModule;
515  }
516 
522  public function isMain() {
523  return $this === $this->mMainModule;
524  }
525 
532  public function getParent() {
533  return $this->isMain() ? null : $this->getMain();
534  }
535 
543  private function dieIfMain( string $methodName ) {
544  if ( $this->isMain() ) {
545  self::dieDebug( $methodName, 'base method was called on main module.' );
546  }
547  }
548 
559  public function lacksSameOriginSecurity() {
560  // Main module has this method overridden, avoid infinite loops
561  $this->dieIfMain( __METHOD__ );
562 
563  return $this->getMain()->lacksSameOriginSecurity();
564  }
565 
572  public function getModulePath() {
573  if ( $this->isMain() ) {
574  return 'main';
575  } elseif ( $this->getParent()->isMain() ) {
576  return $this->getModuleName();
577  } else {
578  return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
579  }
580  }
581 
590  public function getModuleFromPath( $path ) {
591  $module = $this->getMain();
592  if ( $path === 'main' ) {
593  return $module;
594  }
595 
596  $parts = explode( '+', $path );
597  if ( count( $parts ) === 1 ) {
598  // In case the '+' was typed into URL, it resolves as a space
599  $parts = explode( ' ', $path );
600  }
601 
602  $count = count( $parts );
603  for ( $i = 0; $i < $count; $i++ ) {
604  $parent = $module;
605  $manager = $parent->getModuleManager();
606  if ( $manager === null ) {
607  $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
608  $this->dieWithError( [ 'apierror-badmodule-nosubmodules', $errorPath ], 'badmodule' );
609  }
610  $module = $manager->getModule( $parts[$i] );
611 
612  if ( $module === null ) {
613  $errorPath = $i ? implode( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
614  $this->dieWithError(
615  [ 'apierror-badmodule-badsubmodule', $errorPath, wfEscapeWikiText( $parts[$i] ) ],
616  'badmodule'
617  );
618  }
619  }
620 
621  return $module;
622  }
623 
628  public function getResult() {
629  // Main module has this method overridden, avoid infinite loops
630  $this->dieIfMain( __METHOD__ );
631 
632  return $this->getMain()->getResult();
633  }
634 
639  public function getErrorFormatter() {
640  // Main module has this method overridden, avoid infinite loops
641  $this->dieIfMain( __METHOD__ );
642 
643  return $this->getMain()->getErrorFormatter();
644  }
645 
651  protected function getDB() {
652  if ( !isset( $this->mReplicaDB ) ) {
653  $this->mReplicaDB = wfGetDB( DB_REPLICA, 'api' );
654  }
655 
656  return $this->mReplicaDB;
657  }
658 
662  public function getContinuationManager() {
663  // Main module has this method overridden, avoid infinite loops
664  $this->dieIfMain( __METHOD__ );
665 
666  return $this->getMain()->getContinuationManager();
667  }
668 
672  public function setContinuationManager( ApiContinuationManager $manager = null ) {
673  // Main module has this method overridden, avoid infinite loops
674  $this->dieIfMain( __METHOD__ );
675 
676  $this->getMain()->setContinuationManager( $manager );
677  }
678 
685  protected function getPermissionManager(): PermissionManager {
686  return MediaWikiServices::getInstance()->getPermissionManager();
687  }
688 
695  protected function getHookContainer() {
696  if ( !$this->hookContainer ) {
697  $this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
698  }
699  return $this->hookContainer;
700  }
701 
710  protected function getHookRunner() {
711  if ( !$this->hookRunner ) {
712  $this->hookRunner = new ApiHookRunner( $this->getHookContainer() );
713  }
714  return $this->hookRunner;
715  }
716 
717  // endregion -- end of data access methods
718 
719  /***************************************************************************/
720  // region Parameter handling
731  public function dynamicParameterDocumentation() {
732  return null;
733  }
734 
742  public function encodeParamName( $paramName ) {
743  if ( is_array( $paramName ) ) {
744  return array_map( function ( $name ) {
745  return $this->mModulePrefix . $name;
746  }, $paramName );
747  } else {
748  return $this->mModulePrefix . $paramName;
749  }
750  }
751 
764  public function extractRequestParams( $options = [] ) {
765  if ( is_bool( $options ) ) {
766  $options = [ 'parseLimit' => $options ];
767  }
768  $options += [
769  'parseLimit' => true,
770  'safeMode' => false,
771  ];
772 
773  $parseLimit = (bool)$options['parseLimit'];
774  $cacheKey = (int)$parseLimit;
775 
776  // Cache parameters, for performance and to avoid T26564.
777  if ( !isset( $this->mParamCache[$cacheKey] ) ) {
778  $params = $this->getFinalParams() ?: [];
779  $results = [];
780  $warned = [];
781 
782  // Process all non-templates and save templates for secondary
783  // processing.
784  $toProcess = [];
785  foreach ( $params as $paramName => $paramSettings ) {
786  if ( isset( $paramSettings[self::PARAM_TEMPLATE_VARS] ) ) {
787  $toProcess[] = [ $paramName, $paramSettings[self::PARAM_TEMPLATE_VARS], $paramSettings ];
788  } else {
789  try {
790  $results[$paramName] = $this->getParameterFromSettings(
791  $paramName, $paramSettings, $parseLimit
792  );
793  } catch ( ApiUsageException $ex ) {
794  $results[$paramName] = $ex;
795  }
796  }
797  }
798 
799  // Now process all the templates by successively replacing the
800  // placeholders with all client-supplied values.
801  // This bit duplicates JavaScript logic in
802  // ApiSandbox.PageLayout.prototype.updateTemplatedParams().
803  // If you update this, see if that needs updating too.
804  while ( $toProcess ) {
805  list( $name, $targets, $settings ) = array_shift( $toProcess );
806 
807  foreach ( $targets as $placeholder => $target ) {
808  if ( !array_key_exists( $target, $results ) ) {
809  // The target wasn't processed yet, try the next one.
810  // If all hit this case, the parameter has no expansions.
811  continue;
812  }
813  if ( !is_array( $results[$target] ) || !$results[$target] ) {
814  // The target was processed but has no (valid) values.
815  // That means it has no expansions.
816  break;
817  }
818 
819  // Expand this target in the name and all other targets,
820  // then requeue if there are more targets left or put in
821  // $results if all are done.
822  unset( $targets[$placeholder] );
823  $placeholder = '{' . $placeholder . '}';
824  // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
825  foreach ( $results[$target] as $value ) {
826  if ( !preg_match( '/^[^{}]*$/', $value ) ) {
827  // Skip values that make invalid parameter names.
828  $encTargetName = $this->encodeParamName( $target );
829  if ( !isset( $warned[$encTargetName][$value] ) ) {
830  $warned[$encTargetName][$value] = true;
831  $this->addWarning( [
832  'apiwarn-ignoring-invalid-templated-value',
833  wfEscapeWikiText( $encTargetName ),
834  wfEscapeWikiText( $value ),
835  ] );
836  }
837  continue;
838  }
839 
840  $newName = str_replace( $placeholder, $value, $name );
841  if ( !$targets ) {
842  try {
843  $results[$newName] = $this->getParameterFromSettings(
844  $newName,
845  $settings,
846  $parseLimit
847  );
848  } catch ( ApiUsageException $ex ) {
849  $results[$newName] = $ex;
850  }
851  } else {
852  $newTargets = [];
853  foreach ( $targets as $k => $v ) {
854  $newTargets[$k] = str_replace( $placeholder, $value, $v );
855  }
856  $toProcess[] = [ $newName, $newTargets, $settings ];
857  }
858  }
859  break;
860  }
861  }
862 
863  $this->mParamCache[$cacheKey] = $results;
864  }
865 
866  $ret = $this->mParamCache[$cacheKey];
867  if ( !$options['safeMode'] ) {
868  foreach ( $ret as $v ) {
869  if ( $v instanceof ApiUsageException ) {
870  throw $v;
871  }
872  }
873  }
874 
875  return $this->mParamCache[$cacheKey];
876  }
877 
884  protected function getParameter( $paramName, $parseLimit = true ) {
885  $ret = $this->extractRequestParams( [
886  'parseLimit' => $parseLimit,
887  'safeMode' => true,
888  ] )[$paramName];
889  if ( $ret instanceof ApiUsageException ) {
890  throw $ret;
891  }
892  return $ret;
893  }
894 
901  public function requireOnlyOneParameter( $params, ...$required ) {
902  $intersection = array_intersect( array_keys( array_filter( $params,
903  [ $this, 'parameterNotEmpty' ] ) ), $required );
904 
905  if ( count( $intersection ) > 1 ) {
906  $this->dieWithError( [
907  'apierror-invalidparammix',
908  Message::listParam( array_map(
909  function ( $p ) {
910  return '<var>' . $this->encodeParamName( $p ) . '</var>';
911  },
912  array_values( $intersection )
913  ) ),
914  count( $intersection ),
915  ] );
916  } elseif ( count( $intersection ) == 0 ) {
917  $this->dieWithError( [
918  'apierror-missingparam-one-of',
919  Message::listParam( array_map(
920  function ( $p ) {
921  return '<var>' . $this->encodeParamName( $p ) . '</var>';
922  },
923  $required
924  ) ),
925  count( $required ),
926  ], 'missingparam' );
927  }
928  }
929 
936  public function requireMaxOneParameter( $params, ...$required ) {
937  $intersection = array_intersect( array_keys( array_filter( $params,
938  [ $this, 'parameterNotEmpty' ] ) ), $required );
939 
940  if ( count( $intersection ) > 1 ) {
941  $this->dieWithError( [
942  'apierror-invalidparammix',
943  Message::listParam( array_map(
944  function ( $p ) {
945  return '<var>' . $this->encodeParamName( $p ) . '</var>';
946  },
947  array_values( $intersection )
948  ) ),
949  count( $intersection ),
950  ] );
951  }
952  }
953 
961  public function requireAtLeastOneParameter( $params, ...$required ) {
962  $intersection = array_intersect(
963  array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
964  $required
965  );
966 
967  if ( count( $intersection ) == 0 ) {
968  $this->dieWithError( [
969  'apierror-missingparam-at-least-one-of',
970  Message::listParam( array_map(
971  function ( $p ) {
972  return '<var>' . $this->encodeParamName( $p ) . '</var>';
973  },
974  $required
975  ) ),
976  count( $required ),
977  ], 'missingparam' );
978  }
979  }
980 
988  public function requirePostedParameters( $params, $prefix = 'prefix' ) {
989  // Skip if $wgDebugAPI is set or we're in internal mode
990  if ( $this->getConfig()->get( 'DebugAPI' ) || $this->getMain()->isInternalMode() ) {
991  return;
992  }
993 
994  $queryValues = $this->getRequest()->getQueryValuesOnly();
995  $badParams = [];
996  foreach ( $params as $param ) {
997  if ( $prefix !== 'noprefix' ) {
998  $param = $this->encodeParamName( $param );
999  }
1000  if ( array_key_exists( $param, $queryValues ) ) {
1001  $badParams[] = $param;
1002  }
1003  }
1004 
1005  if ( $badParams ) {
1006  $this->dieWithError(
1007  [ 'apierror-mustpostparams', implode( ', ', $badParams ), count( $badParams ) ]
1008  );
1009  }
1010  }
1011 
1018  private function parameterNotEmpty( $x ) {
1019  return $x !== null && $x !== false;
1020  }
1021 
1033  public function getTitleOrPageId( $params, $load = false ) {
1034  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1035 
1036  $pageObj = null;
1037  if ( isset( $params['title'] ) ) {
1038  $titleObj = Title::newFromText( $params['title'] );
1039  if ( !$titleObj || $titleObj->isExternal() ) {
1040  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1041  }
1042  if ( !$titleObj->canExist() ) {
1043  $this->dieWithError( 'apierror-pagecannotexist' );
1044  }
1045  $pageObj = WikiPage::factory( $titleObj );
1046  if ( $load !== false ) {
1047  $pageObj->loadPageData( $load );
1048  }
1049  } elseif ( isset( $params['pageid'] ) ) {
1050  if ( $load === false ) {
1051  $load = 'fromdb';
1052  }
1053  $pageObj = WikiPage::newFromID( $params['pageid'], $load );
1054  if ( !$pageObj ) {
1055  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1056  }
1057  }
1058 
1059  return $pageObj;
1060  }
1061 
1070  public function getTitleFromTitleOrPageId( $params ) {
1071  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1072 
1073  $titleObj = null;
1074  if ( isset( $params['title'] ) ) {
1075  $titleObj = Title::newFromText( $params['title'] );
1076  if ( !$titleObj || $titleObj->isExternal() ) {
1077  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1078  }
1079  return $titleObj;
1080  } elseif ( isset( $params['pageid'] ) ) {
1081  $titleObj = Title::newFromID( $params['pageid'] );
1082  if ( !$titleObj ) {
1083  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1084  }
1085  }
1086 
1087  return $titleObj;
1088  }
1089 
1099  protected function getParameterFromSettings( $name, $settings, $parseLimit ) {
1100  $validator = $this->getMain()->getParamValidator();
1101  $value = $validator->getValue( $this, $name, $settings, [
1102  'parse-limit' => $parseLimit,
1103  'raw' => ( $settings[ParamValidator::PARAM_TYPE] ?? '' ) === 'raw',
1104  ] );
1105 
1106  // @todo Deprecate and remove this, if possible.
1107  if ( $parseLimit && isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1108  $settings[ParamValidator::PARAM_TYPE] === 'limit' &&
1109  $this->getMain()->getVal( $this->encodeParamName( $name ) ) === 'max'
1110  ) {
1111  $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1112  }
1113 
1114  return $value;
1115  }
1116 
1126  public function handleParamNormalization( $paramName, $value, $rawValue ) {
1127  $this->addWarning( [ 'apiwarn-badutf8', $paramName ] );
1128  }
1129 
1139  final public function validateToken( $token, array $params ) {
1140  $tokenType = $this->needsToken();
1142  if ( !isset( $salts[$tokenType] ) ) {
1143  throw new MWException(
1144  "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1145  'without registering it'
1146  );
1147  }
1148 
1149  $tokenObj = ApiQueryTokens::getToken(
1150  $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1151  );
1152  if ( $tokenObj->match( $token ) ) {
1153  return true;
1154  }
1155 
1156  $webUiSalt = $this->getWebUITokenSalt( $params );
1157  if ( $webUiSalt !== null && $this->getUser()->matchEditToken(
1158  $token,
1159  $webUiSalt,
1160  $this->getRequest()
1161  ) ) {
1162  return true;
1163  }
1164 
1165  return false;
1166  }
1167 
1168  // endregion -- end of parameter handling
1169 
1170  /***************************************************************************/
1171  // region Utility methods
1180  public function getWatchlistUser( $params ) {
1181  if ( $params['owner'] !== null && $params['token'] !== null ) {
1182  $services = MediaWikiServices::getInstance();
1183  $user = $services->getUserFactory()->newFromName( $params['owner'], UserFactory::RIGOR_NONE );
1184  if ( !$user || !$user->isRegistered() ) {
1185  $this->dieWithError(
1186  [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1187  );
1188  }
1189  $token = $services->getUserOptionsLookup()->getOption( $user, 'watchlisttoken' );
1190  if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1191  $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1192  }
1193  } else {
1194  $user = $this->getUser();
1195  if ( !$user->isRegistered() ) {
1196  $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1197  }
1198  $this->checkUserRightsAny( 'viewmywatchlist' );
1199  }
1200 
1201  return $user;
1202  }
1203 
1216  public static function makeMessage( $msg, IContextSource $context, array $params = null ) {
1217  if ( is_string( $msg ) ) {
1218  $msg = wfMessage( $msg );
1219  } elseif ( is_array( $msg ) ) {
1220  $msg = wfMessage( ...$msg );
1221  }
1222  if ( !$msg instanceof Message ) {
1223  return null;
1224  }
1225 
1226  $msg->setContext( $context );
1227  if ( $params ) {
1228  $msg->params( $params );
1229  }
1230 
1231  return $msg;
1232  }
1233 
1241  public function errorArrayToStatus( array $errors, User $user = null ) {
1242  if ( $user === null ) {
1243  $user = $this->getUser();
1244  }
1245 
1246  $status = Status::newGood();
1247  foreach ( $errors as $error ) {
1248  if ( !is_array( $error ) ) {
1249  $error = [ $error ];
1250  }
1251  if ( is_string( $error[0] ) && isset( self::$blockMsgMap[$error[0]] ) && $user->getBlock() ) {
1252  list( $msg, $code ) = self::$blockMsgMap[$error[0]];
1253  $status->fatal( ApiMessage::create( $msg, $code,
1254  [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
1255  ) );
1256  } else {
1257  $status->fatal( ...$error );
1258  }
1259  }
1260  return $status;
1261  }
1262 
1270  public function addBlockInfoToStatus( StatusValue $status, Authority $user = null ) {
1271  if ( $status instanceof PermissionStatus ) {
1272  $block = $status->getBlock();
1273  } else {
1274  $user = $user ?: $this->getAuthority();
1275  $block = $user->getBlock();
1276  }
1277 
1278  if ( $block ) {
1279  foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
1280  if ( $status->hasMessage( $msg ) ) {
1281  $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
1282  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1283  ) );
1284  }
1285  }
1286  }
1287  }
1288 
1293  protected function useTransactionalTimeLimit() {
1294  if ( $this->getRequest()->wasPosted() ) {
1296  }
1297  }
1298 
1307  protected function filterIDs( $fields, array $ids ) {
1308  $min = INF;
1309  $max = 0;
1310  foreach ( $fields as list( $table, $field ) ) {
1311  if ( isset( self::$filterIDsCache[$table][$field] ) ) {
1312  $row = self::$filterIDsCache[$table][$field];
1313  } else {
1314  $row = $this->getDB()->selectRow(
1315  $table,
1316  [
1317  'min_id' => "MIN($field)",
1318  'max_id' => "MAX($field)",
1319  ],
1320  '',
1321  __METHOD__
1322  );
1323  self::$filterIDsCache[$table][$field] = $row;
1324  }
1325  $min = min( $min, $row->min_id );
1326  $max = max( $max, $row->max_id );
1327  }
1328  return array_filter( $ids, static function ( $id ) use ( $min, $max ) {
1329  return ( is_int( $id ) && $id >= 0 || ctype_digit( $id ) )
1330  && $id >= $min && $id <= $max;
1331  } );
1332  }
1333 
1334  // endregion -- end of utility methods
1335 
1336  /***************************************************************************/
1337  // region Warning and error reporting
1354  public function addWarning( $msg, $code = null, $data = null ) {
1355  $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1356  }
1357 
1368  public function addDeprecation( $msg, $feature, $data = [] ) {
1369  $data = (array)$data;
1370  if ( $feature !== null ) {
1371  $data['feature'] = $feature;
1372  $this->logFeatureUsage( $feature );
1373  }
1374  $this->addWarning( $msg, 'deprecation', $data );
1375 
1376  // No real need to deduplicate here, ApiErrorFormatter does that for
1377  // us (assuming the hook is deterministic).
1378  $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1379  $this->getHookRunner()->onApiDeprecationHelp( $msgs );
1380  if ( count( $msgs ) > 1 ) {
1381  $key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
1382  $msg = ( new RawMessage( $key ) )->params( $msgs );
1383  } else {
1384  $msg = reset( $msgs );
1385  }
1386  $this->getMain()->addWarning( $msg, 'deprecation-help' );
1387  }
1388 
1401  public function addError( $msg, $code = null, $data = null ) {
1402  $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1403  }
1404 
1414  public function addMessagesFromStatus(
1415  StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
1416  ) {
1417  $this->getErrorFormatter()->addMessagesFromStatus(
1418  $this->getModulePath(), $status, $types, $filter
1419  );
1420  }
1421 
1436  public function dieWithError( $msg, $code = null, $data = null, $httpCode = null ) {
1437  throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1438  }
1439 
1449  public function dieWithException( Throwable $exception, array $options = [] ) {
1450  // @phan-suppress-previous-line PhanTypeMissingReturn
1451  $this->dieWithError(
1452  // @phan-suppress-next-line PhanTypeMismatchArgument
1453  $this->getErrorFormatter()->getMessageFromException( $exception, $options )
1454  );
1455  }
1456 
1466  public function dieBlocked( Block $block ) {
1467  // @phan-suppress-previous-line PhanTypeMissingReturn
1468  // Die using the appropriate message depending on block type
1469  if ( $block->getType() == Block::TYPE_AUTO ) {
1470  $this->dieWithError(
1471  'apierror-autoblocked',
1472  'autoblocked',
1473  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1474  );
1475  } elseif ( !$block->isSitewide() ) {
1476  $this->dieWithError(
1477  'apierror-blocked-partial',
1478  'blocked',
1479  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1480  );
1481  } else {
1482  $this->dieWithError(
1483  'apierror-blocked',
1484  'blocked',
1485  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1486  );
1487  }
1488  }
1489 
1499  public function dieStatus( StatusValue $status ) {
1500  if ( $status->isGood() ) {
1501  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
1502  }
1503 
1504  // ApiUsageException needs a fatal status, but this method has
1505  // historically accepted any non-good status. Convert it if necessary.
1506  $status->setOK( false );
1507  if ( !$status->getErrorsByType( 'error' ) ) {
1508  $newStatus = Status::newGood();
1509  foreach ( $status->getErrorsByType( 'warning' ) as $err ) {
1510  $newStatus->fatal( $err['message'], ...$err['params'] );
1511  }
1512  if ( !$newStatus->getErrorsByType( 'error' ) ) {
1513  $newStatus->fatal( 'unknownerror-nocode' );
1514  }
1515  $status = $newStatus;
1516  }
1517 
1518  $this->addBlockInfoToStatus( $status );
1519  throw new ApiUsageException( $this, $status );
1520  }
1521 
1528  public function dieReadOnly() {
1529  // @phan-suppress-previous-line PhanTypeMissingReturn
1530  $this->dieWithError(
1531  'apierror-readonly',
1532  'readonly',
1533  [ 'readonlyreason' => wfReadOnlyReason() ]
1534  );
1535  }
1536 
1545  public function checkUserRightsAny( $rights, $user = null ) {
1546  $authority = $this->getAuthority();
1547  if ( $user !== null ) {
1548  wfDeprecatedMsg( __METHOD__ . ': $user parameter is deprecated', '1.36' );
1549  $authority = $user;
1550  }
1551  $rights = (array)$rights;
1552  if ( !$authority->isAllowedAny( ...$rights ) ) {
1553  $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
1554  }
1555  }
1556 
1571  public function checkTitleUserPermissions(
1572  $pageIdentity,
1573  $actions,
1574  array $options = []
1575  ) {
1576  if ( !$pageIdentity instanceof PageIdentity ) {
1577  wfDeprecatedMsg( __METHOD__ . ': passing LinkTarget as $pageIdentity parameter is deprecated',
1578  '1.36' );
1579  $pageIdentity = Title::castFromLinkTarget( $pageIdentity );
1580  }
1581  $status = new PermissionStatus();
1582  foreach ( (array)$actions as $action ) {
1583  if ( $this->isWriteMode() ) {
1584  $this->getAuthority()->authorizeWrite( $action, $pageIdentity, $status );
1585  } else {
1586  $this->getAuthority()->authorizeRead( $action, $pageIdentity, $status );
1587  }
1588  }
1589  if ( !$status->isGood() ) {
1590  if ( !empty( $options['autoblock'] ) ) {
1591  $this->getUser()->spreadAnyEditBlock();
1592  }
1593  $this->dieStatus( $status );
1594  }
1595  }
1596 
1608  public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
1609  if ( $this->getConfig()->get( 'DebugAPI' ) !== true ) {
1610  $this->dieWithError( $msg, $code, $data, $httpCode );
1611  } else {
1612  $this->addWarning( $msg, $code, $data );
1613  }
1614  }
1615 
1626  protected function dieContinueUsageIf( $condition ) {
1627  if ( $condition ) {
1628  $this->dieWithError( 'apierror-badcontinue' );
1629  }
1630  }
1631 
1639  protected static function dieDebug( $method, $message ) {
1640  throw new MWException( "Internal error in $method: $message" );
1641  }
1642 
1649  public function logFeatureUsage( $feature ) {
1650  static $loggedFeatures = [];
1651 
1652  // Only log each feature once per request. We can get multiple calls from calls to
1653  // extractRequestParams() with different values for 'parseLimit', for example.
1654  if ( isset( $loggedFeatures[$feature] ) ) {
1655  return;
1656  }
1657  $loggedFeatures[$feature] = true;
1658 
1659  $request = $this->getRequest();
1660  $ctx = [
1661  'feature' => $feature,
1662  // Spaces to underscores in 'username' for historical reasons.
1663  'username' => str_replace( ' ', '_', $this->getUser()->getName() ),
1664  'clientip' => $request->getIP(),
1665  'referer' => (string)$request->getHeader( 'Referer' ),
1666  'agent' => $this->getMain()->getUserAgent(),
1667  ];
1668 
1669  // Text string is deprecated. Remove (or replace with just $feature) in MW 1.34.
1670  $s = '"' . addslashes( $ctx['feature'] ) . '"' .
1671  ' "' . wfUrlencode( $ctx['username'] ) . '"' .
1672  ' "' . $ctx['clientip'] . '"' .
1673  ' "' . addslashes( $ctx['referer'] ) . '"' .
1674  ' "' . addslashes( $ctx['agent'] ) . '"';
1675 
1676  wfDebugLog( 'api-feature-usage', $s, 'private', $ctx );
1677  }
1678 
1679  // endregion -- end of warning and error reporting
1680 
1681  /***************************************************************************/
1682  // region Help message generation
1695  protected function getSummaryMessage() {
1696  return "apihelp-{$this->getModulePath()}-summary";
1697  }
1698 
1709  protected function getExtendedDescription() {
1710  return [ [
1711  "apihelp-{$this->getModulePath()}-extended-description",
1712  'api-help-no-extended-description',
1713  ] ];
1714  }
1715 
1723  public function getFinalSummary() {
1724  $msg = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
1725  $this->getModulePrefix(),
1726  $this->getModuleName(),
1727  $this->getModulePath(),
1728  ] );
1729  return $msg;
1730  }
1731 
1739  public function getFinalDescription() {
1740  $summary = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
1741  $this->getModulePrefix(),
1742  $this->getModuleName(),
1743  $this->getModulePath(),
1744  ] );
1745  $extendedDescription = self::makeMessage(
1746  $this->getExtendedDescription(), $this->getContext(), [
1747  $this->getModulePrefix(),
1748  $this->getModuleName(),
1749  $this->getModulePath(),
1750  ]
1751  );
1752 
1753  $msgs = [ $summary, $extendedDescription ];
1754 
1755  $this->getHookRunner()->onAPIGetDescriptionMessages( $this, $msgs );
1756 
1757  return $msgs;
1758  }
1759 
1768  public function getFinalParams( $flags = 0 ) {
1769  // @phan-suppress-next-line PhanParamTooMany
1770  $params = $this->getAllowedParams( $flags );
1771  if ( !$params ) {
1772  $params = [];
1773  }
1774 
1775  if ( $this->needsToken() ) {
1776  $params['token'] = [
1777  self::PARAM_TYPE => 'string',
1778  self::PARAM_REQUIRED => true,
1779  self::PARAM_SENSITIVE => true,
1780  self::PARAM_HELP_MSG => [
1781  'api-help-param-token',
1782  $this->needsToken(),
1783  ],
1784  ] + ( $params['token'] ?? [] );
1785  }
1786 
1787  $this->getHookRunner()->onAPIGetAllowedParams( $this, $params, $flags );
1788 
1789  return $params;
1790  }
1791 
1799  public function getFinalParamDescription() {
1800  $prefix = $this->getModulePrefix();
1801  $name = $this->getModuleName();
1802  $path = $this->getModulePath();
1803 
1804  $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
1805  $msgs = [];
1806  foreach ( $params as $param => $settings ) {
1807  if ( !is_array( $settings ) ) {
1808  $settings = [];
1809  }
1810 
1811  if ( isset( $settings[self::PARAM_HELP_MSG] ) ) {
1812  $msg = $settings[self::PARAM_HELP_MSG];
1813  } else {
1814  $msg = $this->msg( "apihelp-{$path}-param-{$param}" );
1815  }
1816  $msg = self::makeMessage( $msg, $this->getContext(),
1817  [ $prefix, $param, $name, $path ] );
1818  if ( !$msg ) {
1819  self::dieDebug( __METHOD__,
1820  'Value in ApiBase::PARAM_HELP_MSG is not valid' );
1821  }
1822  $msgs[$param] = [ $msg ];
1823 
1824  if ( isset( $settings[self::PARAM_TYPE] ) &&
1825  $settings[self::PARAM_TYPE] === 'submodule'
1826  ) {
1827  if ( isset( $settings[self::PARAM_SUBMODULE_MAP] ) ) {
1828  $map = $settings[self::PARAM_SUBMODULE_MAP];
1829  } else {
1830  $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
1831  $map = [];
1832  foreach ( $this->getModuleManager()->getNames( $param ) as $submoduleName ) {
1833  $map[$submoduleName] = $prefix . $submoduleName;
1834  }
1835  }
1836 
1837  $submodules = [];
1838  $submoduleFlags = []; // for sorting: higher flags are sorted later
1839  $submoduleNames = []; // for sorting: lexicographical, ascending
1840  foreach ( $map as $v => $m ) {
1841  $isDeprecated = false;
1842  $isInternal = false;
1843  $summary = null;
1844  try {
1845  $submod = $this->getModuleFromPath( $m );
1846  if ( $submod ) {
1847  $summary = $submod->getFinalSummary();
1848  $isDeprecated = $submod->isDeprecated();
1849  $isInternal = $submod->isInternal();
1850  }
1851  } catch ( ApiUsageException $ex ) {
1852  // Ignore
1853  }
1854  if ( $summary ) {
1855  $key = $summary->getKey();
1856  $params = $summary->getParams();
1857  } else {
1858  $key = 'api-help-undocumented-module';
1859  $params = [ $m ];
1860  }
1861  $m = new ApiHelpParamValueMessage(
1862  "[[Special:ApiHelp/$m|$v]]",
1863  $key,
1864  $params,
1865  $isDeprecated,
1866  $isInternal
1867  );
1868  $submodules[] = $m->setContext( $this->getContext() );
1869  $submoduleFlags[] = ( $isDeprecated ? 1 : 0 ) | ( $isInternal ? 2 : 0 );
1870  $submoduleNames[] = $v;
1871  }
1872  // sort $submodules by $submoduleFlags and $submoduleNames
1873  array_multisort( $submoduleFlags, $submoduleNames, $submodules );
1874  $msgs[$param] = array_merge( $msgs[$param], $submodules );
1875  } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1876  if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1877  self::dieDebug( __METHOD__,
1878  'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
1879  }
1880  if ( !is_array( $settings[self::PARAM_TYPE] ) ) {
1881  self::dieDebug( __METHOD__,
1882  'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
1883  'ApiBase::PARAM_TYPE is an array' );
1884  }
1885 
1886  $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
1887  $deprecatedValues = $settings[self::PARAM_DEPRECATED_VALUES] ?? [];
1888 
1889  foreach ( $settings[self::PARAM_TYPE] as $value ) {
1890  if ( isset( $valueMsgs[$value] ) ) {
1891  $msg = $valueMsgs[$value];
1892  } else {
1893  $msg = "apihelp-{$path}-paramvalue-{$param}-{$value}";
1894  }
1895  $m = self::makeMessage( $msg, $this->getContext(),
1896  [ $prefix, $param, $name, $path, $value ] );
1897  if ( $m ) {
1898  $m = new ApiHelpParamValueMessage(
1899  $value,
1900  // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal
1901  [ $m->getKey(), 'api-help-param-no-description' ],
1902  $m->getParams(),
1903  isset( $deprecatedValues[$value] )
1904  );
1905  $msgs[$param][] = $m->setContext( $this->getContext() );
1906  } else {
1907  self::dieDebug( __METHOD__,
1908  "Value in ApiBase::PARAM_HELP_MSG_PER_VALUE for $value is not valid" );
1909  }
1910  }
1911  }
1912 
1913  if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
1914  if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
1915  self::dieDebug( __METHOD__,
1916  'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
1917  }
1918  foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
1919  $m = self::makeMessage( $m, $this->getContext(),
1920  [ $prefix, $param, $name, $path ] );
1921  if ( $m ) {
1922  $msgs[$param][] = $m;
1923  } else {
1924  self::dieDebug( __METHOD__,
1925  'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
1926  }
1927  }
1928  }
1929  }
1930 
1931  $this->getHookRunner()->onAPIGetParamDescriptionMessages( $this, $msgs );
1932 
1933  return $msgs;
1934  }
1935 
1945  protected function getHelpFlags() {
1946  $flags = [];
1947 
1948  if ( $this->isDeprecated() ) {
1949  $flags[] = 'deprecated';
1950  }
1951  if ( $this->isInternal() ) {
1952  $flags[] = 'internal';
1953  }
1954  if ( $this->isReadMode() ) {
1955  $flags[] = 'readrights';
1956  }
1957  if ( $this->isWriteMode() ) {
1958  $flags[] = 'writerights';
1959  }
1960  if ( $this->mustBePosted() ) {
1961  $flags[] = 'mustbeposted';
1962  }
1963 
1964  return $flags;
1965  }
1966 
1978  protected function getModuleSourceInfo() {
1979  global $IP;
1980 
1981  if ( $this->mModuleSource !== false ) {
1982  return $this->mModuleSource;
1983  }
1984 
1985  // First, try to find where the module comes from...
1986  $rClass = new ReflectionClass( $this );
1987  $path = $rClass->getFileName();
1988  if ( !$path ) {
1989  // No path known?
1990  $this->mModuleSource = null;
1991  return null;
1992  }
1993  $path = realpath( $path ) ?: $path;
1994 
1995  // Build map of extension directories to extension info
1996  if ( self::$extensionInfo === null ) {
1997  $extDir = $this->getConfig()->get( 'ExtensionDirectory' );
1998  self::$extensionInfo = [
1999  realpath( __DIR__ ) ?: __DIR__ => [
2000  'path' => $IP,
2001  'name' => 'MediaWiki',
2002  'license-name' => 'GPL-2.0-or-later',
2003  ],
2004  realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
2005  realpath( $extDir ) ?: $extDir => null,
2006  ];
2007  $keep = [
2008  'path' => null,
2009  'name' => null,
2010  'namemsg' => null,
2011  'license-name' => null,
2012  ];
2014  foreach ( $credits as $group ) {
2015  foreach ( $group as $ext ) {
2016  if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
2017  // This shouldn't happen, but does anyway.
2018  continue;
2019  }
2020 
2021  $extpath = $ext['path'];
2022  if ( !is_dir( $extpath ) ) {
2023  $extpath = dirname( $extpath );
2024  }
2025  self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2026  array_intersect_key( $ext, $keep );
2027  }
2028  }
2029  }
2030 
2031  // Now traverse parent directories until we find a match or run out of
2032  // parents.
2033  do {
2034  if ( array_key_exists( $path, self::$extensionInfo ) ) {
2035  // Found it!
2036  $this->mModuleSource = self::$extensionInfo[$path];
2037  return $this->mModuleSource;
2038  }
2039 
2040  $oldpath = $path;
2041  $path = dirname( $path );
2042  } while ( $path !== $oldpath );
2043 
2044  // No idea what extension this might be.
2045  $this->mModuleSource = null;
2046  return null;
2047  }
2048 
2061  public function modifyHelp( array &$help, array $options, array &$tocData ) {
2062  }
2063 
2064  // endregion -- end of help message generation
2065 
2066 }
2067 
2068 /*
2069  * This file uses VisualStudio style region/endregion fold markers which are
2070  * recognised by PHPStorm. If modelines are enabled, the following editor
2071  * configuration will also enable folding in vim, if it is in the last 5 lines
2072  * of the file. We also use "@name" which creates sections in Doxygen.
2073  *
2074  * vim: foldmarker=//\ region,//\ endregion foldmethod=marker
2075  */
ApiBase\checkTitleUserPermissions
checkTitleUserPermissions( $pageIdentity, $actions, array $options=[])
Helper function for permission-denied errors.
Definition: ApiBase.php:1571
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:109
ApiBase\$mModuleSource
array null false $mModuleSource
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:260
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:382
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:251
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:532
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1354
ApiBase\getSummaryMessage
getSummaryMessage()
Return the summary message.
Definition: ApiBase.php:1695
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:1768
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
Definition: ApiBase.php:105
StatusValue\getErrorsByType
getErrorsByType( $type)
Returns a list of status messages of the given type.
Definition: StatusValue.php:301
ApiBase\$hookContainer
HookContainer $hookContainer
Definition: ApiBase.php:60
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:199
ApiBase\parameterNotEmpty
parameterNotEmpty( $x)
Callback function used in requireOnlyOneParameter to check whether required parameters are set.
Definition: ApiBase.php:1018
ApiBase\validateToken
validateToken( $token, array $params)
Validate the supplied token.
Definition: ApiBase.php:1139
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:1436
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:162
ApiBase\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiBase.php:336
StatusValue\replaceMessage
replaceMessage( $source, $dest)
If the specified source message exists, replace it with the specified destination message,...
Definition: StatusValue.php:347
ApiBase\PARAM_ALL
const PARAM_ALL
Definition: ApiBase.php:117
ApiBase\$extensionInfo
static array $extensionInfo
Maps extension paths to info arrays.
Definition: ApiBase.php:236
ApiBase\getTitleOrPageId
getTitleOrPageId( $params, $load=false)
Get a WikiPage object from a title or pageid param, if possible.
Definition: ApiBase.php:1033
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:81
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:628
ApiBase\__construct
__construct(ApiMain $mainModule, $moduleName, $modulePrefix='')
Definition: ApiBase.php:268
ApiBase\getParameterFromSettings
getParameterFromSettings( $name, $settings, $parseLimit)
Using the settings determine the value for the given parameter.
Definition: ApiBase.php:1099
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:408
ApiBase\logFeatureUsage
logFeatureUsage( $feature)
Write logging information for API features to a debug log, for usage analysis.
Definition: ApiBase.php:1649
ApiBase\checkUserRightsAny
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1545
ApiBase\shouldCheckMaxlag
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition: ApiBase.php:374
ApiBase\dieWithErrorOrDebug
dieWithErrorOrDebug( $msg, $code=null, $data=null, $httpCode=null)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
Definition: ApiBase.php:1608
ApiBase\setContinuationManager
setContinuationManager(ApiContinuationManager $manager=null)
Definition: ApiBase.php:672
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:1709
ApiBase\PARAM_ISMULTI_LIMIT1
const PARAM_ISMULTI_LIMIT1
Definition: ApiBase.php:133
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1183
ApiBase\getHookContainer
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
Definition: ApiBase.php:695
ApiBase\getDB
getDB()
Gets a default replica DB connection object.
Definition: ApiBase.php:651
ApiBase\addMessagesFromStatus
addMessagesFromStatus(StatusValue $status, $types=[ 'warning', 'error'], array $filter=[])
Add warnings and/or errors from a Status.
Definition: ApiBase.php:1414
ApiBase\makeMessage
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
Definition: ApiBase.php:1216
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:731
ApiBase\modifyHelp
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition: ApiBase.php:2061
ApiBase\PARAM_ALLOW_DUPLICATES
const PARAM_ALLOW_DUPLICATES
Definition: ApiBase.php:97
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:159
ApiBase\PARAM_DEPRECATED_VALUES
const PARAM_DEPRECATED_VALUES
Definition: ApiBase.php:129
ApiBase\lacksSameOriginSecurity
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:559
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:169
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:466
Message\listParam
static listParam(array $list, $type='text')
Definition: Message.php:1227
ApiBase\isMain
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition: ApiBase.php:522
ApiBase\isReadMode
isReadMode()
Indicates whether this module requires read rights.
Definition: ApiBase.php:383
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:590
ApiBase\getFinalParamDescription
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:1799
ApiBase\PARAM_SENSITIVE
const PARAM_SENSITIVE
Definition: ApiBase.php:125
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:1466
ApiBase\PARAM_ISMULTI_LIMIT2
const PARAM_ISMULTI_LIMIT2
Definition: ApiBase.php:137
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:134
ApiBase\getFinalSummary
getFinalSummary()
Get final module summary.
Definition: ApiBase.php:1723
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
Definition: ApiBase.php:101
ApiBase\PARAM_MIN
const PARAM_MIN
Definition: ApiBase.php:93
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:320
ApiBase\getFinalDescription
getFinalDescription()
Get final module description, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:1739
wfTransactionalTimeLimit
wfTransactionalTimeLimit()
Raise the request time limit to $wgTransactionalTimeLimit.
Definition: GlobalFunctions.php:2390
ApiBase\getModulePath
getModulePath()
Get the path to this module.
Definition: ApiBase.php:572
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2200
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:220
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:1270
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:85
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:764
ApiBase\handleParamNormalization
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition: ApiBase.php:1126
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
ApiBase\isDeprecated
isDeprecated()
Indicates whether this module is deprecated.
Definition: ApiBase.php:418
ApiBase\requireAtLeastOneParameter
requireAtLeastOneParameter( $params,... $required)
Die if none of a certain set of parameters is set and not false.
Definition: ApiBase.php:961
ApiBase\$mReplicaDB
$mReplicaDB
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:254
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:121
ApiBase\ALL_DEFAULT_STRING
const ALL_DEFAULT_STRING
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:217
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:346
ApiBlockInfoTrait
trait ApiBlockInfoTrait
Definition: ApiBlockInfoTrait.php:27
ApiBase\needsToken
needsToken()
Returns the token type this module requires in order to execute.
Definition: ApiBase.php:452
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:505
ApiBase\$mModuleName
string $mModuleName
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:253
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:662
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:1401
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:1180
$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:901
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:936
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1626
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:1368
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:226
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:742
ApiBase\dieReadOnly
dieReadOnly()
Helper function for readonly errors.
Definition: ApiBase.php:1528
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:233
WikiPage\newFromID
static newFromID( $id, $from='fromdb')
Constructor from a page id.
Definition: WikiPage.php:215
ApiBase\getPermissionManager
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition: ApiBase.php:685
ApiBase\useTransactionalTimeLimit
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: ApiBase.php:1293
ApiBase\getConditionalRequestData
getConditionalRequestData( $condition)
Returns data for HTTP conditional request mechanisms.
Definition: ApiBase.php:483
ApiBase\isWriteMode
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiBase.php:399
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:543
ApiBase\PARAM_HELP_MSG_INFO
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition: ApiBase.php:179
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:152
ApiBase\PARAM_VALUE_LINKS
const PARAM_VALUE_LINKS
Deprecated and unused.
Definition: ApiBase.php:186
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:213
ApiBase\filterIDs
filterIDs( $fields, array $ids)
Filter out-of-range values from a list of positive integer IDs.
Definition: ApiBase.php:1307
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:222
wfReadOnlyReason
wfReadOnlyReason()
Check if the site is in read-only mode and return the message if so.
Definition: GlobalFunctions.php:1113
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:306
WikiPage\factory
static factory(PageIdentity $pageIdentity)
Create a WikiPage object of the appropriate class for the given PageIdentity.
Definition: WikiPage.php:200
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:429
ApiBase\getModuleSourceInfo
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition: ApiBase.php:1978
$path
$path
Definition: NoLocalSettings.php:25
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:73
ApiBase\getParameter
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition: ApiBase.php:884
ApiBase\dieWithException
dieWithException(Throwable $exception, array $options=[])
Abort execution with an error derived from a throwable.
Definition: ApiBase.php:1449
ApiBase\dieStatus
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1499
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:497
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:77
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:242
ApiBase\PARAM_MAX2
const PARAM_MAX2
Definition: ApiBase.php:89
StatusValue\hasMessage
hasMessage( $message)
Returns true if the specified message is present as a warning or error.
Definition: StatusValue.php:319
ApiBase\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiBase.php:363
$help
$help
Definition: mcc.php:32
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:513
$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:145
ApiBase\getTitleFromTitleOrPageId
getTitleFromTitleOrPageId( $params)
Get a Title object from a title or pageid param, if possible.
Definition: ApiBase.php:1070
Title\castFromLinkTarget
static castFromLinkTarget( $linkTarget)
Same as newFromLinkTarget, but if passed null, returns null.
Definition: Title.php:318
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:253
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:195
ApiBase\PARAM_SUBMODULE_PARAM_PREFIX
const PARAM_SUBMODULE_PARAM_PREFIX
Definition: ApiBase.php:113
ApiBase\$mParamCache
array $mParamCache
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:258
ApiBase\PARAM_MAX_BYTES
const PARAM_MAX_BYTES
Definition: ApiBase.php:141
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:710
$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:528
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1639
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:1241
MediaWiki\User\UserFactory
Creates User objects.
Definition: UserFactory.php:41
ApiBase\getErrorFormatter
getErrorFormatter()
Definition: ApiBase.php:639
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:988
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:224
ApiBase\getHelpFlags
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition: ApiBase.php:1945
ApiBase\$filterIDsCache
static stdClass[][] $filterIDsCache
Cache for self::filterIDs()
Definition: ApiBase.php:239