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 
640  return MediaWikiServices::getInstance()->getGroupPermissionsLookup();
641  }
642 
649  protected function getHookContainer() {
650  if ( !$this->hookContainer ) {
651  $this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
652  }
653  return $this->hookContainer;
654  }
655 
664  protected function getHookRunner() {
665  if ( !$this->hookRunner ) {
666  $this->hookRunner = new ApiHookRunner( $this->getHookContainer() );
667  }
668  return $this->hookRunner;
669  }
670 
671  // endregion -- end of data access methods
672 
673  /***************************************************************************/
674  // region Parameter handling
685  public function dynamicParameterDocumentation() {
686  return null;
687  }
688 
696  public function encodeParamName( $paramName ) {
697  if ( is_array( $paramName ) ) {
698  return array_map( function ( $name ) {
699  return $this->mModulePrefix . $name;
700  }, $paramName );
701  } else {
702  return $this->mModulePrefix . $paramName;
703  }
704  }
705 
718  public function extractRequestParams( $options = [] ) {
719  if ( is_bool( $options ) ) {
720  $options = [ 'parseLimit' => $options ];
721  }
722  $options += [
723  'parseLimit' => true,
724  'safeMode' => false,
725  ];
726 
727  $parseLimit = (bool)$options['parseLimit'];
728  $cacheKey = (int)$parseLimit;
729 
730  // Cache parameters, for performance and to avoid T26564.
731  if ( !isset( $this->mParamCache[$cacheKey] ) ) {
732  $params = $this->getFinalParams() ?: [];
733  $results = [];
734  $warned = [];
735 
736  // Process all non-templates and save templates for secondary
737  // processing.
738  $toProcess = [];
739  foreach ( $params as $paramName => $paramSettings ) {
740  if ( isset( $paramSettings[self::PARAM_TEMPLATE_VARS] ) ) {
741  $toProcess[] = [ $paramName, $paramSettings[self::PARAM_TEMPLATE_VARS], $paramSettings ];
742  } else {
743  try {
744  $results[$paramName] = $this->getParameterFromSettings(
745  $paramName, $paramSettings, $parseLimit
746  );
747  } catch ( ApiUsageException $ex ) {
748  $results[$paramName] = $ex;
749  }
750  }
751  }
752 
753  // Now process all the templates by successively replacing the
754  // placeholders with all client-supplied values.
755  // This bit duplicates JavaScript logic in
756  // ApiSandbox.PageLayout.prototype.updateTemplatedParams().
757  // If you update this, see if that needs updating too.
758  while ( $toProcess ) {
759  list( $name, $targets, $settings ) = array_shift( $toProcess );
760 
761  foreach ( $targets as $placeholder => $target ) {
762  if ( !array_key_exists( $target, $results ) ) {
763  // The target wasn't processed yet, try the next one.
764  // If all hit this case, the parameter has no expansions.
765  continue;
766  }
767  if ( !is_array( $results[$target] ) || !$results[$target] ) {
768  // The target was processed but has no (valid) values.
769  // That means it has no expansions.
770  break;
771  }
772 
773  // Expand this target in the name and all other targets,
774  // then requeue if there are more targets left or put in
775  // $results if all are done.
776  unset( $targets[$placeholder] );
777  $placeholder = '{' . $placeholder . '}';
778  // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
779  foreach ( $results[$target] as $value ) {
780  if ( !preg_match( '/^[^{}]*$/', $value ) ) {
781  // Skip values that make invalid parameter names.
782  $encTargetName = $this->encodeParamName( $target );
783  if ( !isset( $warned[$encTargetName][$value] ) ) {
784  $warned[$encTargetName][$value] = true;
785  $this->addWarning( [
786  'apiwarn-ignoring-invalid-templated-value',
787  wfEscapeWikiText( $encTargetName ),
788  wfEscapeWikiText( $value ),
789  ] );
790  }
791  continue;
792  }
793 
794  $newName = str_replace( $placeholder, $value, $name );
795  if ( !$targets ) {
796  try {
797  $results[$newName] = $this->getParameterFromSettings(
798  $newName,
799  $settings,
800  $parseLimit
801  );
802  } catch ( ApiUsageException $ex ) {
803  $results[$newName] = $ex;
804  }
805  } else {
806  $newTargets = [];
807  foreach ( $targets as $k => $v ) {
808  $newTargets[$k] = str_replace( $placeholder, $value, $v );
809  }
810  $toProcess[] = [ $newName, $newTargets, $settings ];
811  }
812  }
813  break;
814  }
815  }
816 
817  $this->mParamCache[$cacheKey] = $results;
818  }
819 
820  $ret = $this->mParamCache[$cacheKey];
821  if ( !$options['safeMode'] ) {
822  foreach ( $ret as $v ) {
823  if ( $v instanceof ApiUsageException ) {
824  throw $v;
825  }
826  }
827  }
828 
829  return $this->mParamCache[$cacheKey];
830  }
831 
838  protected function getParameter( $paramName, $parseLimit = true ) {
839  $ret = $this->extractRequestParams( [
840  'parseLimit' => $parseLimit,
841  'safeMode' => true,
842  ] )[$paramName];
843  if ( $ret instanceof ApiUsageException ) {
844  throw $ret;
845  }
846  return $ret;
847  }
848 
855  public function requireOnlyOneParameter( $params, ...$required ) {
856  $intersection = array_intersect( array_keys( array_filter( $params,
857  [ $this, 'parameterNotEmpty' ] ) ), $required );
858 
859  if ( count( $intersection ) > 1 ) {
860  $this->dieWithError( [
861  'apierror-invalidparammix',
862  Message::listParam( array_map(
863  function ( $p ) {
864  return '<var>' . $this->encodeParamName( $p ) . '</var>';
865  },
866  array_values( $intersection )
867  ) ),
868  count( $intersection ),
869  ] );
870  } elseif ( count( $intersection ) == 0 ) {
871  $this->dieWithError( [
872  'apierror-missingparam-one-of',
873  Message::listParam( array_map(
874  function ( $p ) {
875  return '<var>' . $this->encodeParamName( $p ) . '</var>';
876  },
877  $required
878  ) ),
879  count( $required ),
880  ], 'missingparam' );
881  }
882  }
883 
890  public function requireMaxOneParameter( $params, ...$required ) {
891  $intersection = array_intersect( array_keys( array_filter( $params,
892  [ $this, 'parameterNotEmpty' ] ) ), $required );
893 
894  if ( count( $intersection ) > 1 ) {
895  $this->dieWithError( [
896  'apierror-invalidparammix',
897  Message::listParam( array_map(
898  function ( $p ) {
899  return '<var>' . $this->encodeParamName( $p ) . '</var>';
900  },
901  array_values( $intersection )
902  ) ),
903  count( $intersection ),
904  ] );
905  }
906  }
907 
915  public function requireAtLeastOneParameter( $params, ...$required ) {
916  $intersection = array_intersect(
917  array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
918  $required
919  );
920 
921  if ( count( $intersection ) == 0 ) {
922  $this->dieWithError( [
923  'apierror-missingparam-at-least-one-of',
924  Message::listParam( array_map(
925  function ( $p ) {
926  return '<var>' . $this->encodeParamName( $p ) . '</var>';
927  },
928  $required
929  ) ),
930  count( $required ),
931  ], 'missingparam' );
932  }
933  }
934 
942  public function requirePostedParameters( $params, $prefix = 'prefix' ) {
943  // Skip if $wgDebugAPI is set or we're in internal mode
944  if ( $this->getConfig()->get( 'DebugAPI' ) || $this->getMain()->isInternalMode() ) {
945  return;
946  }
947 
948  $queryValues = $this->getRequest()->getQueryValuesOnly();
949  $badParams = [];
950  foreach ( $params as $param ) {
951  if ( $prefix !== 'noprefix' ) {
952  $param = $this->encodeParamName( $param );
953  }
954  if ( array_key_exists( $param, $queryValues ) ) {
955  $badParams[] = $param;
956  }
957  }
958 
959  if ( $badParams ) {
960  $this->dieWithError(
961  [ 'apierror-mustpostparams', implode( ', ', $badParams ), count( $badParams ) ]
962  );
963  }
964  }
965 
972  private function parameterNotEmpty( $x ) {
973  return $x !== null && $x !== false;
974  }
975 
987  public function getTitleOrPageId( $params, $load = false ) {
988  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
989 
990  $pageObj = null;
991  if ( isset( $params['title'] ) ) {
992  $titleObj = Title::newFromText( $params['title'] );
993  if ( !$titleObj || $titleObj->isExternal() ) {
994  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
995  }
996  if ( !$titleObj->canExist() ) {
997  $this->dieWithError( 'apierror-pagecannotexist' );
998  }
999  $pageObj = WikiPage::factory( $titleObj );
1000  if ( $load !== false ) {
1001  $pageObj->loadPageData( $load );
1002  }
1003  } elseif ( isset( $params['pageid'] ) ) {
1004  if ( $load === false ) {
1005  $load = 'fromdb';
1006  }
1007  $pageObj = WikiPage::newFromID( $params['pageid'], $load );
1008  if ( !$pageObj ) {
1009  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1010  }
1011  }
1012 
1013  return $pageObj;
1014  }
1015 
1024  public function getTitleFromTitleOrPageId( $params ) {
1025  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1026 
1027  $titleObj = null;
1028  if ( isset( $params['title'] ) ) {
1029  $titleObj = Title::newFromText( $params['title'] );
1030  if ( !$titleObj || $titleObj->isExternal() ) {
1031  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1032  }
1033  return $titleObj;
1034  } elseif ( isset( $params['pageid'] ) ) {
1035  $titleObj = Title::newFromID( $params['pageid'] );
1036  if ( !$titleObj ) {
1037  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1038  }
1039  }
1040 
1041  return $titleObj;
1042  }
1043 
1053  protected function getParameterFromSettings( $name, $settings, $parseLimit ) {
1054  $validator = $this->getMain()->getParamValidator();
1055  $value = $validator->getValue( $this, $name, $settings, [
1056  'parse-limit' => $parseLimit,
1057  'raw' => ( $settings[ParamValidator::PARAM_TYPE] ?? '' ) === 'raw',
1058  ] );
1059 
1060  // @todo Deprecate and remove this, if possible.
1061  if ( $parseLimit && isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1062  $settings[ParamValidator::PARAM_TYPE] === 'limit' &&
1063  $this->getMain()->getVal( $this->encodeParamName( $name ) ) === 'max'
1064  ) {
1065  $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1066  }
1067 
1068  return $value;
1069  }
1070 
1080  public function handleParamNormalization( $paramName, $value, $rawValue ) {
1081  $this->addWarning( [ 'apiwarn-badutf8', $paramName ] );
1082  }
1083 
1093  final public function validateToken( $token, array $params ) {
1094  $tokenType = $this->needsToken();
1096  if ( !isset( $salts[$tokenType] ) ) {
1097  throw new MWException(
1098  "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1099  'without registering it'
1100  );
1101  }
1102 
1103  $tokenObj = ApiQueryTokens::getToken(
1104  $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1105  );
1106  if ( $tokenObj->match( $token ) ) {
1107  return true;
1108  }
1109 
1110  $webUiSalt = $this->getWebUITokenSalt( $params );
1111  if ( $webUiSalt !== null && $this->getUser()->matchEditToken(
1112  $token,
1113  $webUiSalt,
1114  $this->getRequest()
1115  ) ) {
1116  return true;
1117  }
1118 
1119  return false;
1120  }
1121 
1122  // endregion -- end of parameter handling
1123 
1124  /***************************************************************************/
1125  // region Utility methods
1134  public function getWatchlistUser( $params ) {
1135  if ( $params['owner'] !== null && $params['token'] !== null ) {
1136  $user = User::newFromName( $params['owner'], false );
1137  if ( !( $user && $user->getId() ) ) {
1138  $this->dieWithError(
1139  [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1140  );
1141  }
1142  $token = $user->getOption( 'watchlisttoken' );
1143  if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1144  $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1145  }
1146  } else {
1147  if ( !$this->getUser()->isRegistered() ) {
1148  $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1149  }
1150  $this->checkUserRightsAny( 'viewmywatchlist' );
1151  $user = $this->getUser();
1152  }
1153 
1154  return $user;
1155  }
1156 
1169  public static function makeMessage( $msg, IContextSource $context, array $params = null ) {
1170  if ( is_string( $msg ) ) {
1171  $msg = wfMessage( $msg );
1172  } elseif ( is_array( $msg ) ) {
1173  $msg = wfMessage( ...$msg );
1174  }
1175  if ( !$msg instanceof Message ) {
1176  return null;
1177  }
1178 
1179  $msg->setContext( $context );
1180  if ( $params ) {
1181  $msg->params( $params );
1182  }
1183 
1184  return $msg;
1185  }
1186 
1194  public function errorArrayToStatus( array $errors, User $user = null ) {
1195  if ( $user === null ) {
1196  $user = $this->getUser();
1197  }
1198 
1199  $status = Status::newGood();
1200  foreach ( $errors as $error ) {
1201  if ( !is_array( $error ) ) {
1202  $error = [ $error ];
1203  }
1204  if ( is_string( $error[0] ) && isset( self::$blockMsgMap[$error[0]] ) && $user->getBlock() ) {
1205  list( $msg, $code ) = self::$blockMsgMap[$error[0]];
1206  $status->fatal( ApiMessage::create( $msg, $code,
1207  [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
1208  ) );
1209  } else {
1210  $status->fatal( ...$error );
1211  }
1212  }
1213  return $status;
1214  }
1215 
1222  public function addBlockInfoToStatus( StatusValue $status, User $user = null ) {
1223  if ( $user === null ) {
1224  $user = $this->getUser();
1225  }
1226 
1227  foreach ( self::$blockMsgMap as $msg => list( $apiMsg, $code ) ) {
1228  if ( $status->hasMessage( $msg ) && $user->getBlock() ) {
1229  $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code,
1230  [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
1231  ) );
1232  }
1233  }
1234  }
1235 
1240  protected function useTransactionalTimeLimit() {
1241  if ( $this->getRequest()->wasPosted() ) {
1243  }
1244  }
1245 
1254  protected function filterIDs( $fields, array $ids ) {
1255  $min = INF;
1256  $max = 0;
1257  foreach ( $fields as list( $table, $field ) ) {
1258  if ( isset( self::$filterIDsCache[$table][$field] ) ) {
1259  $row = self::$filterIDsCache[$table][$field];
1260  } else {
1261  $row = $this->getDB()->selectRow(
1262  $table,
1263  [
1264  'min_id' => "MIN($field)",
1265  'max_id' => "MAX($field)",
1266  ],
1267  '',
1268  __METHOD__
1269  );
1270  self::$filterIDsCache[$table][$field] = $row;
1271  }
1272  $min = min( $min, $row->min_id );
1273  $max = max( $max, $row->max_id );
1274  }
1275  return array_filter( $ids, static function ( $id ) use ( $min, $max ) {
1276  return ( is_int( $id ) && $id >= 0 || ctype_digit( $id ) )
1277  && $id >= $min && $id <= $max;
1278  } );
1279  }
1280 
1281  // endregion -- end of utility methods
1282 
1283  /***************************************************************************/
1284  // region Warning and error reporting
1301  public function addWarning( $msg, $code = null, $data = null ) {
1302  $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1303  }
1304 
1315  public function addDeprecation( $msg, $feature, $data = [] ) {
1316  $data = (array)$data;
1317  if ( $feature !== null ) {
1318  $data['feature'] = $feature;
1319  $this->logFeatureUsage( $feature );
1320  }
1321  $this->addWarning( $msg, 'deprecation', $data );
1322 
1323  // No real need to deduplicate here, ApiErrorFormatter does that for
1324  // us (assuming the hook is deterministic).
1325  $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1326  $this->getHookRunner()->onApiDeprecationHelp( $msgs );
1327  if ( count( $msgs ) > 1 ) {
1328  $key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
1329  $msg = ( new RawMessage( $key ) )->params( $msgs );
1330  } else {
1331  $msg = reset( $msgs );
1332  }
1333  $this->getMain()->addWarning( $msg, 'deprecation-help' );
1334  }
1335 
1348  public function addError( $msg, $code = null, $data = null ) {
1349  $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1350  }
1351 
1361  public function addMessagesFromStatus(
1362  StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
1363  ) {
1364  $this->getErrorFormatter()->addMessagesFromStatus(
1365  $this->getModulePath(), $status, $types, $filter
1366  );
1367  }
1368 
1382  public function dieWithError( $msg, $code = null, $data = null, $httpCode = null ) {
1383  throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1384  }
1385 
1394  public function dieWithException( Throwable $exception, array $options = [] ) {
1395  $this->dieWithError(
1396  // @phan-suppress-next-line PhanTypeMismatchArgument
1397  $this->getErrorFormatter()->getMessageFromException( $exception, $options )
1398  );
1399  }
1400 
1409  public function dieBlocked( AbstractBlock $block ) {
1410  // Die using the appropriate message depending on block type
1411  if ( $block->getType() == DatabaseBlock::TYPE_AUTO ) {
1412  $this->dieWithError(
1413  'apierror-autoblocked',
1414  'autoblocked',
1415  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1416  );
1417  } elseif ( !$block->isSitewide() ) {
1418  $this->dieWithError(
1419  'apierror-blocked-partial',
1420  'blocked',
1421  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1422  );
1423  } else {
1424  $this->dieWithError(
1425  'apierror-blocked',
1426  'blocked',
1427  [ 'blockinfo' => $this->getBlockDetails( $block ) ]
1428  );
1429  }
1430  }
1431 
1440  public function dieStatus( StatusValue $status ) {
1441  if ( $status->isGood() ) {
1442  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
1443  }
1444 
1445  // ApiUsageException needs a fatal status, but this method has
1446  // historically accepted any non-good status. Convert it if necessary.
1447  $status->setOK( false );
1448  if ( !$status->getErrorsByType( 'error' ) ) {
1449  $newStatus = Status::newGood();
1450  foreach ( $status->getErrorsByType( 'warning' ) as $err ) {
1451  $newStatus->fatal( $err['message'], ...$err['params'] );
1452  }
1453  if ( !$newStatus->getErrorsByType( 'error' ) ) {
1454  $newStatus->fatal( 'unknownerror-nocode' );
1455  }
1456  $status = $newStatus;
1457  }
1458 
1459  $this->addBlockInfoToStatus( $status );
1460  throw new ApiUsageException( $this, $status );
1461  }
1462 
1468  public function dieReadOnly() {
1469  $this->dieWithError(
1470  'apierror-readonly',
1471  'readonly',
1472  [ 'readonlyreason' => wfReadOnlyReason() ]
1473  );
1474  }
1475 
1484  public function checkUserRightsAny( $rights, $user = null ) {
1485  $authority = $this->getAuthority();
1486  if ( $user !== null ) {
1487  wfDeprecatedMsg( __METHOD__ . ': $user parameter is deprecated', '1.36' );
1488  $authority = $user;
1489  }
1490  $rights = (array)$rights;
1491  if ( !$authority->isAllowedAny( ...$rights ) ) {
1492  $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
1493  }
1494  }
1495 
1510  public function checkTitleUserPermissions(
1511  $pageIdentity,
1512  $actions,
1513  array $options = []
1514  ) {
1515  if ( !$pageIdentity instanceof PageIdentity ) {
1516  wfDeprecatedMsg( __METHOD__ . ': passing LinkTarget as $pageIdentity parameter is deprecated',
1517  '1.36' );
1518  $pageIdentity = Title::castFromLinkTarget( $pageIdentity );
1519  }
1520  $status = new PermissionStatus();
1521  foreach ( (array)$actions as $action ) {
1522  if ( $this->isWriteMode() ) {
1523  $this->getAuthority()->authorizeWrite( $action, $pageIdentity, $status );
1524  } else {
1525  $this->getAuthority()->authorizeRead( $action, $pageIdentity, $status );
1526  }
1527  }
1528  if ( !$status->isGood() ) {
1529  if ( !empty( $options['autoblock'] ) ) {
1530  $this->getUser()->spreadAnyEditBlock();
1531  }
1532  $this->dieStatus( $status );
1533  }
1534  }
1535 
1547  public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
1548  if ( $this->getConfig()->get( 'DebugAPI' ) !== true ) {
1549  $this->dieWithError( $msg, $code, $data, $httpCode );
1550  } else {
1551  $this->addWarning( $msg, $code, $data );
1552  }
1553  }
1554 
1565  protected function dieContinueUsageIf( $condition ) {
1566  if ( $condition ) {
1567  $this->dieWithError( 'apierror-badcontinue' );
1568  }
1569  }
1570 
1577  protected static function dieDebug( $method, $message ) {
1578  throw new MWException( "Internal error in $method: $message" );
1579  }
1580 
1587  public function logFeatureUsage( $feature ) {
1588  static $loggedFeatures = [];
1589 
1590  // Only log each feature once per request. We can get multiple calls from calls to
1591  // extractRequestParams() with different values for 'parseLimit', for example.
1592  if ( isset( $loggedFeatures[$feature] ) ) {
1593  return;
1594  }
1595  $loggedFeatures[$feature] = true;
1596 
1597  $request = $this->getRequest();
1598  $ctx = [
1599  'feature' => $feature,
1600  // Spaces to underscores in 'username' for historical reasons.
1601  'username' => str_replace( ' ', '_', $this->getUser()->getName() ),
1602  'clientip' => $request->getIP(),
1603  'referer' => (string)$request->getHeader( 'Referer' ),
1604  'agent' => $this->getMain()->getUserAgent(),
1605  ];
1606 
1607  // Text string is deprecated. Remove (or replace with just $feature) in MW 1.34.
1608  $s = '"' . addslashes( $ctx['feature'] ) . '"' .
1609  ' "' . wfUrlencode( $ctx['username'] ) . '"' .
1610  ' "' . $ctx['clientip'] . '"' .
1611  ' "' . addslashes( $ctx['referer'] ) . '"' .
1612  ' "' . addslashes( $ctx['agent'] ) . '"';
1613 
1614  wfDebugLog( 'api-feature-usage', $s, 'private', $ctx );
1615  }
1616 
1617  // endregion -- end of warning and error reporting
1618 
1619  /***************************************************************************/
1620  // region Help message generation
1633  protected function getSummaryMessage() {
1634  return "apihelp-{$this->getModulePath()}-summary";
1635  }
1636 
1647  protected function getExtendedDescription() {
1648  return [ [
1649  "apihelp-{$this->getModulePath()}-extended-description",
1650  'api-help-no-extended-description',
1651  ] ];
1652  }
1653 
1661  public function getFinalSummary() {
1662  $msg = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
1663  $this->getModulePrefix(),
1664  $this->getModuleName(),
1665  $this->getModulePath(),
1666  ] );
1667  return $msg;
1668  }
1669 
1677  public function getFinalDescription() {
1678  $summary = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
1679  $this->getModulePrefix(),
1680  $this->getModuleName(),
1681  $this->getModulePath(),
1682  ] );
1683  $extendedDescription = self::makeMessage(
1684  $this->getExtendedDescription(), $this->getContext(), [
1685  $this->getModulePrefix(),
1686  $this->getModuleName(),
1687  $this->getModulePath(),
1688  ]
1689  );
1690 
1691  $msgs = [ $summary, $extendedDescription ];
1692 
1693  $this->getHookRunner()->onAPIGetDescriptionMessages( $this, $msgs );
1694 
1695  return $msgs;
1696  }
1697 
1706  public function getFinalParams( $flags = 0 ) {
1707  // @phan-suppress-next-line PhanParamTooMany
1708  $params = $this->getAllowedParams( $flags );
1709  if ( !$params ) {
1710  $params = [];
1711  }
1712 
1713  if ( $this->needsToken() ) {
1714  $params['token'] = [
1715  self::PARAM_TYPE => 'string',
1716  self::PARAM_REQUIRED => true,
1717  self::PARAM_SENSITIVE => true,
1718  self::PARAM_HELP_MSG => [
1719  'api-help-param-token',
1720  $this->needsToken(),
1721  ],
1722  ] + ( $params['token'] ?? [] );
1723  }
1724 
1725  $this->getHookRunner()->onAPIGetAllowedParams( $this, $params, $flags );
1726 
1727  return $params;
1728  }
1729 
1737  public function getFinalParamDescription() {
1738  $prefix = $this->getModulePrefix();
1739  $name = $this->getModuleName();
1740  $path = $this->getModulePath();
1741 
1742  $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
1743  $msgs = [];
1744  foreach ( $params as $param => $settings ) {
1745  if ( !is_array( $settings ) ) {
1746  $settings = [];
1747  }
1748 
1749  if ( isset( $settings[self::PARAM_HELP_MSG] ) ) {
1750  $msg = $settings[self::PARAM_HELP_MSG];
1751  } else {
1752  $msg = $this->msg( "apihelp-{$path}-param-{$param}" );
1753  }
1754  $msg = self::makeMessage( $msg, $this->getContext(),
1755  [ $prefix, $param, $name, $path ] );
1756  if ( !$msg ) {
1757  self::dieDebug( __METHOD__,
1758  'Value in ApiBase::PARAM_HELP_MSG is not valid' );
1759  }
1760  $msgs[$param] = [ $msg ];
1761 
1762  if ( isset( $settings[self::PARAM_TYPE] ) &&
1763  $settings[self::PARAM_TYPE] === 'submodule'
1764  ) {
1765  if ( isset( $settings[self::PARAM_SUBMODULE_MAP] ) ) {
1766  $map = $settings[self::PARAM_SUBMODULE_MAP];
1767  } else {
1768  $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
1769  $map = [];
1770  foreach ( $this->getModuleManager()->getNames( $param ) as $submoduleName ) {
1771  $map[$submoduleName] = $prefix . $submoduleName;
1772  }
1773  }
1774 
1775  $submodules = [];
1776  $submoduleFlags = []; // for sorting: higher flags are sorted later
1777  $submoduleNames = []; // for sorting: lexicographical, ascending
1778  foreach ( $map as $v => $m ) {
1779  $isDeprecated = false;
1780  $isInternal = false;
1781  $summary = null;
1782  try {
1783  $submod = $this->getModuleFromPath( $m );
1784  if ( $submod ) {
1785  $summary = $submod->getFinalSummary();
1786  $isDeprecated = $submod->isDeprecated();
1787  $isInternal = $submod->isInternal();
1788  }
1789  } catch ( ApiUsageException $ex ) {
1790  // Ignore
1791  }
1792  if ( $summary ) {
1793  $key = $summary->getKey();
1794  $params = $summary->getParams();
1795  } else {
1796  $key = 'api-help-undocumented-module';
1797  $params = [ $m ];
1798  }
1799  $m = new ApiHelpParamValueMessage(
1800  "[[Special:ApiHelp/$m|$v]]",
1801  $key,
1802  $params,
1803  $isDeprecated,
1804  $isInternal
1805  );
1806  $submodules[] = $m->setContext( $this->getContext() );
1807  $submoduleFlags[] = ( $isDeprecated ? 1 : 0 ) | ( $isInternal ? 2 : 0 );
1808  $submoduleNames[] = $v;
1809  }
1810  // sort $submodules by $submoduleFlags and $submoduleNames
1811  array_multisort( $submoduleFlags, $submoduleNames, $submodules );
1812  $msgs[$param] = array_merge( $msgs[$param], $submodules );
1813  } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1814  if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1815  self::dieDebug( __METHOD__,
1816  'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
1817  }
1818  if ( !is_array( $settings[self::PARAM_TYPE] ) ) {
1819  self::dieDebug( __METHOD__,
1820  'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
1821  'ApiBase::PARAM_TYPE is an array' );
1822  }
1823 
1824  $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
1825  $deprecatedValues = $settings[self::PARAM_DEPRECATED_VALUES] ?? [];
1826 
1827  foreach ( $settings[self::PARAM_TYPE] as $value ) {
1828  if ( isset( $valueMsgs[$value] ) ) {
1829  $msg = $valueMsgs[$value];
1830  } else {
1831  $msg = "apihelp-{$path}-paramvalue-{$param}-{$value}";
1832  }
1833  $m = self::makeMessage( $msg, $this->getContext(),
1834  [ $prefix, $param, $name, $path, $value ] );
1835  if ( $m ) {
1836  $m = new ApiHelpParamValueMessage(
1837  $value,
1838  // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal
1839  [ $m->getKey(), 'api-help-param-no-description' ],
1840  $m->getParams(),
1841  isset( $deprecatedValues[$value] )
1842  );
1843  $msgs[$param][] = $m->setContext( $this->getContext() );
1844  } else {
1845  self::dieDebug( __METHOD__,
1846  "Value in ApiBase::PARAM_HELP_MSG_PER_VALUE for $value is not valid" );
1847  }
1848  }
1849  }
1850 
1851  if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
1852  if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
1853  self::dieDebug( __METHOD__,
1854  'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
1855  }
1856  foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
1857  $m = self::makeMessage( $m, $this->getContext(),
1858  [ $prefix, $param, $name, $path ] );
1859  if ( $m ) {
1860  $msgs[$param][] = $m;
1861  } else {
1862  self::dieDebug( __METHOD__,
1863  'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
1864  }
1865  }
1866  }
1867  }
1868 
1869  $this->getHookRunner()->onAPIGetParamDescriptionMessages( $this, $msgs );
1870 
1871  return $msgs;
1872  }
1873 
1883  protected function getHelpFlags() {
1884  $flags = [];
1885 
1886  if ( $this->isDeprecated() ) {
1887  $flags[] = 'deprecated';
1888  }
1889  if ( $this->isInternal() ) {
1890  $flags[] = 'internal';
1891  }
1892  if ( $this->isReadMode() ) {
1893  $flags[] = 'readrights';
1894  }
1895  if ( $this->isWriteMode() ) {
1896  $flags[] = 'writerights';
1897  }
1898  if ( $this->mustBePosted() ) {
1899  $flags[] = 'mustbeposted';
1900  }
1901 
1902  return $flags;
1903  }
1904 
1916  protected function getModuleSourceInfo() {
1917  global $IP;
1918 
1919  if ( $this->mModuleSource !== false ) {
1920  return $this->mModuleSource;
1921  }
1922 
1923  // First, try to find where the module comes from...
1924  $rClass = new ReflectionClass( $this );
1925  $path = $rClass->getFileName();
1926  if ( !$path ) {
1927  // No path known?
1928  $this->mModuleSource = null;
1929  return null;
1930  }
1931  $path = realpath( $path ) ?: $path;
1932 
1933  // Build map of extension directories to extension info
1934  if ( self::$extensionInfo === null ) {
1935  $extDir = $this->getConfig()->get( 'ExtensionDirectory' );
1936  self::$extensionInfo = [
1937  realpath( __DIR__ ) ?: __DIR__ => [
1938  'path' => $IP,
1939  'name' => 'MediaWiki',
1940  'license-name' => 'GPL-2.0-or-later',
1941  ],
1942  realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
1943  realpath( $extDir ) ?: $extDir => null,
1944  ];
1945  $keep = [
1946  'path' => null,
1947  'name' => null,
1948  'namemsg' => null,
1949  'license-name' => null,
1950  ];
1952  foreach ( $credits as $group ) {
1953  foreach ( $group as $ext ) {
1954  if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
1955  // This shouldn't happen, but does anyway.
1956  continue;
1957  }
1958 
1959  $extpath = $ext['path'];
1960  if ( !is_dir( $extpath ) ) {
1961  $extpath = dirname( $extpath );
1962  }
1963  self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
1964  array_intersect_key( $ext, $keep );
1965  }
1966  }
1967  }
1968 
1969  // Now traverse parent directories until we find a match or run out of
1970  // parents.
1971  do {
1972  if ( array_key_exists( $path, self::$extensionInfo ) ) {
1973  // Found it!
1974  $this->mModuleSource = self::$extensionInfo[$path];
1975  return $this->mModuleSource;
1976  }
1977 
1978  $oldpath = $path;
1979  $path = dirname( $path );
1980  } while ( $path !== $oldpath );
1981 
1982  // No idea what extension this might be.
1983  $this->mModuleSource = null;
1984  return null;
1985  }
1986 
1999  public function modifyHelp( array &$help, array $options, array &$tocData ) {
2000  }
2001 
2002  // endregion -- end of help message generation
2003 
2004 }
2005 
2006 /*
2007  * This file uses VisualStudio style region/endregion fold markers which are
2008  * recognised by PHPStorm. If modelines are enabled, the following editor
2009  * configuration will also enable folding in vim, if it is in the last 5 lines
2010  * of the file. We also use "@name" which creates sections in Doxygen.
2011  *
2012  * vim: foldmarker=//\ region,//\ endregion foldmethod=marker
2013  */
ApiBase\checkTitleUserPermissions
checkTitleUserPermissions( $pageIdentity, $actions, array $options=[])
Helper function for permission-denied errors.
Definition: ApiBase.php:1510
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:48
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:38
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:71
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:385
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:46
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:1301
ApiBase\getSummaryMessage
getSummaryMessage()
Return the summary message.
Definition: ApiBase.php:1633
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:1706
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\Permissions\GroupPermissionsLookup
Definition: GroupPermissionsLookup.php:30
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:179
ApiBase\parameterNotEmpty
parameterNotEmpty( $x)
Callback function used in requireOnlyOneParameter to check whether required parameters are set.
Definition: ApiBase.php:972
ApiBase\validateToken
validateToken( $token, array $params)
Validate the supplied token.
Definition: ApiBase.php:1093
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:1382
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:987
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:1053
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:1587
ApiBase\checkUserRightsAny
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1484
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:1547
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:1647
ApiBase\PARAM_ISMULTI_LIMIT1
const PARAM_ISMULTI_LIMIT1
Definition: ApiBase.php:85
User\newFromName
static newFromName( $name, $validate='valid')
Definition: User.php:590
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1182
ApiBase\addBlockInfoToStatus
addBlockInfoToStatus(StatusValue $status, User $user=null)
Add block info to block messages in a Status.
Definition: ApiBase.php:1222
ApiBase\getHookContainer
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
Definition: ApiBase.php:649
ApiBase\dieBlocked
dieBlocked(AbstractBlock $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition: ApiBase.php:1409
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:1361
ApiBase\makeMessage
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
Definition: ApiBase.php:1169
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:80
ApiBase\dynamicParameterDocumentation
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition: ApiBase.php:685
ApiBase\modifyHelp
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition: ApiBase.php:1999
ApiBase\PARAM_ALLOW_DUPLICATES
const PARAM_ALLOW_DUPLICATES
Definition: ApiBase.php:76
ContextSource\getUser
getUser()
Definition: ContextSource.php:135
MediaWiki\Api\ApiHookRunner
This class provides an implementation of the hook interfaces used by the core Action API,...
Definition: ApiHookRunner.php:54
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:1192
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:1737
ApiBase\PARAM_SENSITIVE
const PARAM_SENSITIVE
Definition: ApiBase.php:83
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:1661
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
Definition: ApiBase.php:77
MediaWiki\Block\DatabaseBlock
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Definition: DatabaseBlock.php:52
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
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:1677
wfTransactionalTimeLimit
wfTransactionalTimeLimit()
Raise the request time limit to $wgTransactionalTimeLimit.
Definition: GlobalFunctions.php:2481
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:2306
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:163
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:32
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\getGroupPermissionsLookup
getGroupPermissionsLookup()
Obtain a GroupPermissionsLookup instance that subclasses may use to access group permissions.
Definition: ApiBase.php:639
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:718
ApiBase\handleParamNormalization
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition: ApiBase.php:1080
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:915
ApiBase\$mReplicaDB
$mReplicaDB
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:197
MediaWiki\Block\AbstractBlock\getType
getType()
Get the type of target for this particular block.
Definition: AbstractBlock.php:325
MediaWiki\Block\AbstractBlock\isSitewide
isSitewide( $x=null)
Indicates that the block is a sitewide block.
Definition: AbstractBlock.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:62
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
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:196
ApiBase\addError
addError( $msg, $code=null, $data=null)
Add an error for this module without aborting.
Definition: ApiBase.php:1348
MediaWiki\Permissions\PermissionManager
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Definition: PermissionManager.php:52
ApiBase\getWatchlistUser
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition: ApiBase.php:1134
$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:855
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:890
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition: ApiBase.php:1565
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:1315
ContextSource\getAuthority
getAuthority()
Definition: ContextSource.php:143
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:696
ApiBase\dieReadOnly
dieReadOnly()
Helper function for readonly errors.
Definition: ApiBase.php:1468
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:223
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:1240
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:57
MediaWiki\Permissions\PermissionStatus
A StatusValue for permission errors.
Definition: PermissionStatus.php:34
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:1254
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:208
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:1916
$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:838
ApiBase\dieWithException
dieWithException(Throwable $exception, array $options=[])
Abort execution with an error derived from a throwable.
Definition: ApiBase.php:1394
ApiBase\dieStatus
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1440
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:136
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
MediaWiki\Block\AbstractBlock
Definition: AbstractBlock.php:37
ApiBase\getTitleFromTitleOrPageId
getTitleFromTitleOrPageId( $params)
Get a Title object from a title or pageid param, if possible.
Definition: ApiBase.php:1024
Title\castFromLinkTarget
static castFromLinkTarget( $linkTarget)
Same as newFromLinkTarget, but if passed null, returns null.
Definition: Title.php:321
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:664
$IP
$IP
Definition: WebStart.php:49
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:67
Title\newFromID
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:531
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1577
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:1194
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:942
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:1883
ApiBase\$filterIDsCache
static stdClass[][] $filterIDsCache
Cache for self::filterIDs()
Definition: ApiBase.php:182