MediaWiki  1.23.15
ApiBase.php
Go to the documentation of this file.
1 <?php
42 abstract class ApiBase extends ContextSource {
43  // These constants allow modules to specify exactly how to treat incoming parameters.
44 
45  // Default value of the parameter
46  const PARAM_DFLT = 0;
47  // Boolean, do we accept more than one item for this parameter (e.g.: titles)?
48  const PARAM_ISMULTI = 1;
49  // Can be either a string type (e.g.: 'integer') or an array of allowed values
50  const PARAM_TYPE = 2;
51  // Max value allowed for a parameter. Only applies if TYPE='integer'
52  const PARAM_MAX = 3;
53  // Max value allowed for a parameter for bots and sysops. Only applies if TYPE='integer'
54  const PARAM_MAX2 = 4;
55  // Lowest value allowed for a parameter. Only applies if TYPE='integer'
56  const PARAM_MIN = 5;
57  // Boolean, do we allow the same value to be set more than once when ISMULTI=true
59  // Boolean, is the parameter deprecated (will show a warning)
60  const PARAM_DEPRECATED = 7;
62  const PARAM_REQUIRED = 8; // Boolean, is the parameter required?
64  // Boolean, if MIN/MAX are set, enforce (die) these?
65  // Only applies if TYPE='integer' Use with extreme caution
67 
68  // Name of property group that is on the root element of the result,
69  // i.e. not part of a list
70  const PROP_ROOT = 'ROOT';
71  // Boolean, is the result multiple items? Defaults to true for query modules,
72  // to false for other modules
73  const PROP_LIST = 'LIST';
74  const PROP_TYPE = 0; // Type of the property, uses same format as PARAM_TYPE
75  // Boolean, can the property be not included in the result? Defaults to false
76  const PROP_NULLABLE = 1;
77 
78  const LIMIT_BIG1 = 500; // Fast query, std user limit
79  const LIMIT_BIG2 = 5000; // Fast query, bot/sysop limit
80  const LIMIT_SML1 = 50; // Slow query, std user limit
81  const LIMIT_SML2 = 500; // Slow query, bot/sysop limit
82 
89 
91  private $mSlaveDB = null;
92  private $mParamCache = array();
93 
100  public function __construct( $mainModule, $moduleName, $modulePrefix = '' ) {
101  $this->mMainModule = $mainModule;
102  $this->mModuleName = $moduleName;
103  $this->mModulePrefix = $modulePrefix;
104 
105  if ( !$this->isMain() ) {
106  $this->setContext( $mainModule->getContext() );
107  }
108  }
109 
110  /*****************************************************************************
111  * ABSTRACT METHODS *
112  *****************************************************************************/
113 
130  abstract public function execute();
131 
139  public function getVersion() {
140  wfDeprecated( __METHOD__, '1.21' );
141 
142  return '';
143  }
144 
149  public function getModuleName() {
150  return $this->mModuleName;
151  }
152 
158  public function getModuleManager() {
159  return null;
160  }
161 
166  public function getModulePrefix() {
167  return $this->mModulePrefix;
168  }
169 
177  public function getModuleProfileName( $db = false ) {
178  if ( $db ) {
179  return 'API:' . $this->mModuleName . '-DB';
180  }
181 
182  return 'API:' . $this->mModuleName;
183  }
184 
189  public function getMain() {
190  return $this->mMainModule;
191  }
192 
198  public function isMain() {
199  return $this === $this->mMainModule;
200  }
201 
206  public function getResult() {
207  // Main module has getResult() method overridden
208  // Safety - avoid infinite loop:
209  if ( $this->isMain() ) {
210  ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
211  }
212 
213  return $this->getMain()->getResult();
214  }
215 
220  public function getResultData() {
221  return $this->getResult()->getData();
222  }
223 
233  public function createContext() {
234  wfDeprecated( __METHOD__, '1.19' );
235 
236  return new DerivativeContext( $this->getContext() );
237  }
238 
246  public function setWarning( $warning ) {
247  $result = $this->getResult();
248  $data = $result->getData();
249  $moduleName = $this->getModuleName();
250  if ( isset( $data['warnings'][$moduleName] ) ) {
251  // Don't add duplicate warnings
252  $oldWarning = $data['warnings'][$moduleName]['*'];
253  $warnPos = strpos( $oldWarning, $warning );
254  // If $warning was found in $oldWarning, check if it starts at 0 or after "\n"
255  if ( $warnPos !== false && ( $warnPos === 0 || $oldWarning[$warnPos - 1] === "\n" ) ) {
256  // Check if $warning is followed by "\n" or the end of the $oldWarning
257  $warnPos += strlen( $warning );
258  if ( strlen( $oldWarning ) <= $warnPos || $oldWarning[$warnPos] === "\n" ) {
259  return;
260  }
261  }
262  // If there is a warning already, append it to the existing one
263  $warning = "$oldWarning\n$warning";
264  }
265  $msg = array();
266  ApiResult::setContent( $msg, $warning );
267  $result->disableSizeCheck();
268  $result->addValue( 'warnings', $moduleName,
270  $result->enableSizeCheck();
271  }
272 
279  public function getCustomPrinter() {
280  return null;
281  }
282 
287  public function makeHelpMsg() {
288  static $lnPrfx = "\n ";
289 
290  $msg = $this->getFinalDescription();
291 
292  if ( $msg !== false ) {
293 
294  if ( !is_array( $msg ) ) {
295  $msg = array(
296  $msg
297  );
298  }
299  $msg = $lnPrfx . implode( $lnPrfx, $msg ) . "\n";
300 
301  $msg .= $this->makeHelpArrayToString( $lnPrfx, false, $this->getHelpUrls() );
302 
303  if ( $this->isReadMode() ) {
304  $msg .= "\nThis module requires read rights";
305  }
306  if ( $this->isWriteMode() ) {
307  $msg .= "\nThis module requires write rights";
308  }
309  if ( $this->mustBePosted() ) {
310  $msg .= "\nThis module only accepts POST requests";
311  }
312  if ( $this->isReadMode() || $this->isWriteMode() ||
313  $this->mustBePosted()
314  ) {
315  $msg .= "\n";
316  }
317 
318  // Parameters
319  $paramsMsg = $this->makeHelpMsgParameters();
320  if ( $paramsMsg !== false ) {
321  $msg .= "Parameters:\n$paramsMsg";
322  }
323 
324  $examples = $this->getExamples();
325  if ( $examples ) {
326  if ( !is_array( $examples ) ) {
327  $examples = array(
328  $examples
329  );
330  }
331  $msg .= "Example" . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
332  foreach ( $examples as $k => $v ) {
333  if ( is_numeric( $k ) ) {
334  $msg .= " $v\n";
335  } else {
336  if ( is_array( $v ) ) {
337  $msgExample = implode( "\n", array_map( array( $this, 'indentExampleText' ), $v ) );
338  } else {
339  $msgExample = " $v";
340  }
341  $msgExample .= ":";
342  $msg .= wordwrap( $msgExample, 100, "\n" ) . "\n $k\n";
343  }
344  }
345  }
346  }
347 
348  return $msg;
349  }
350 
361  public function lacksSameOriginSecurity() {
362  // Main module has this method overridden
363  // Safety - avoid infinite loop:
364  if ( $this->isMain() ) {
365  ApiBase::dieDebug( __METHOD__, 'base method was called on main module.' );
366  }
367 
368  return $this->getMain()->lacksSameOriginSecurity();
369  }
370 
375  private function indentExampleText( $item ) {
376  return " " . $item;
377  }
378 
385  protected function makeHelpArrayToString( $prefix, $title, $input ) {
386  if ( $input === false ) {
387  return '';
388  }
389  if ( !is_array( $input ) ) {
390  $input = array( $input );
391  }
392 
393  if ( count( $input ) > 0 ) {
394  if ( $title ) {
395  $msg = $title . ( count( $input ) > 1 ? 's' : '' ) . ":\n ";
396  } else {
397  $msg = ' ';
398  }
399  $msg .= implode( $prefix, $input ) . "\n";
400 
401  return $msg;
402  }
403 
404  return '';
405  }
406 
412  public function makeHelpMsgParameters() {
414  if ( $params ) {
415 
416  $paramsDescription = $this->getFinalParamDescription();
417  $msg = '';
418  $paramPrefix = "\n" . str_repeat( ' ', 24 );
419  $descWordwrap = "\n" . str_repeat( ' ', 28 );
420  foreach ( $params as $paramName => $paramSettings ) {
421  $desc = isset( $paramsDescription[$paramName] ) ? $paramsDescription[$paramName] : '';
422  if ( is_array( $desc ) ) {
423  $desc = implode( $paramPrefix, $desc );
424  }
425 
426  //handle shorthand
427  if ( !is_array( $paramSettings ) ) {
428  $paramSettings = array(
429  self::PARAM_DFLT => $paramSettings,
430  );
431  }
432 
433  //handle missing type
434  if ( !isset( $paramSettings[ApiBase::PARAM_TYPE] ) ) {
435  $dflt = isset( $paramSettings[ApiBase::PARAM_DFLT] )
436  ? $paramSettings[ApiBase::PARAM_DFLT]
437  : null;
438  if ( is_bool( $dflt ) ) {
439  $paramSettings[ApiBase::PARAM_TYPE] = 'boolean';
440  } elseif ( is_string( $dflt ) || is_null( $dflt ) ) {
441  $paramSettings[ApiBase::PARAM_TYPE] = 'string';
442  } elseif ( is_int( $dflt ) ) {
443  $paramSettings[ApiBase::PARAM_TYPE] = 'integer';
444  }
445  }
446 
447  if ( isset( $paramSettings[self::PARAM_DEPRECATED] )
448  && $paramSettings[self::PARAM_DEPRECATED]
449  ) {
450  $desc = "DEPRECATED! $desc";
451  }
452 
453  if ( isset( $paramSettings[self::PARAM_REQUIRED] )
454  && $paramSettings[self::PARAM_REQUIRED]
455  ) {
456  $desc .= $paramPrefix . "This parameter is required";
457  }
458 
459  $type = isset( $paramSettings[self::PARAM_TYPE] )
460  ? $paramSettings[self::PARAM_TYPE]
461  : null;
462  if ( isset( $type ) ) {
463  $hintPipeSeparated = true;
464  $multi = isset( $paramSettings[self::PARAM_ISMULTI] )
465  ? $paramSettings[self::PARAM_ISMULTI]
466  : false;
467  if ( $multi ) {
468  $prompt = 'Values (separate with \'|\'): ';
469  } else {
470  $prompt = 'One value: ';
471  }
472 
473  if ( is_array( $type ) ) {
474  $choices = array();
475  $nothingPrompt = '';
476  foreach ( $type as $t ) {
477  if ( $t === '' ) {
478  $nothingPrompt = 'Can be empty, or ';
479  } else {
480  $choices[] = $t;
481  }
482  }
483  $desc .= $paramPrefix . $nothingPrompt . $prompt;
484  $choicesstring = implode( ', ', $choices );
485  $desc .= wordwrap( $choicesstring, 100, $descWordwrap );
486  $hintPipeSeparated = false;
487  } else {
488  switch ( $type ) {
489  case 'namespace':
490  // Special handling because namespaces are
491  // type-limited, yet they are not given
492  $desc .= $paramPrefix . $prompt;
493  $desc .= wordwrap( implode( ', ', MWNamespace::getValidNamespaces() ),
494  100, $descWordwrap );
495  $hintPipeSeparated = false;
496  break;
497  case 'limit':
498  $desc .= $paramPrefix . "No more than {$paramSettings[self::PARAM_MAX]}";
499  if ( isset( $paramSettings[self::PARAM_MAX2] ) ) {
500  $desc .= " ({$paramSettings[self::PARAM_MAX2]} for bots)";
501  }
502  $desc .= ' allowed';
503  break;
504  case 'integer':
505  $s = $multi ? 's' : '';
506  $hasMin = isset( $paramSettings[self::PARAM_MIN] );
507  $hasMax = isset( $paramSettings[self::PARAM_MAX] );
508  if ( $hasMin || $hasMax ) {
509  if ( !$hasMax ) {
510  $intRangeStr = "The value$s must be no less than " .
511  "{$paramSettings[self::PARAM_MIN]}";
512  } elseif ( !$hasMin ) {
513  $intRangeStr = "The value$s must be no more than " .
514  "{$paramSettings[self::PARAM_MAX]}";
515  } else {
516  $intRangeStr = "The value$s must be between " .
517  "{$paramSettings[self::PARAM_MIN]} and {$paramSettings[self::PARAM_MAX]}";
518  }
519 
520  $desc .= $paramPrefix . $intRangeStr;
521  }
522  break;
523  case 'upload':
524  $desc .= $paramPrefix . "Must be posted as a file upload using multipart/form-data";
525  break;
526  }
527  }
528 
529  if ( $multi ) {
530  if ( $hintPipeSeparated ) {
531  $desc .= $paramPrefix . "Separate values with '|'";
532  }
533 
534  $isArray = is_array( $type );
535  if ( !$isArray
536  || $isArray && count( $type ) > self::LIMIT_SML1
537  ) {
538  $desc .= $paramPrefix . "Maximum number of values " .
539  self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)";
540  }
541  }
542  }
543 
544  $default = isset( $paramSettings[self::PARAM_DFLT] ) ? $paramSettings[self::PARAM_DFLT] : null;
545  if ( !is_null( $default ) && $default !== false ) {
546  $desc .= $paramPrefix . "Default: $default";
547  }
548 
549  $msg .= sprintf( " %-19s - %s\n", $this->encodeParamName( $paramName ), $desc );
550  }
551 
552  return $msg;
553  }
554 
555  return false;
556  }
557 
562  protected function getDescription() {
563  return false;
564  }
565 
570  protected function getExamples() {
571  return false;
572  }
573 
586  protected function getAllowedParams( /* $flags = 0 */ ) {
587  // int $flags is not declared because it causes "Strict standards"
588  // warning. Most derived classes do not implement it.
589  return false;
590  }
591 
598  protected function getParamDescription() {
599  return false;
600  }
601 
610  public function getFinalParams( $flags = 0 ) {
611  $params = $this->getAllowedParams( $flags );
612  wfRunHooks( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
613 
614  return $params;
615  }
616 
623  public function getFinalParamDescription() {
624  $desc = $this->getParamDescription();
625  wfRunHooks( 'APIGetParamDescription', array( &$this, &$desc ) );
626 
627  return $desc;
628  }
629 
646  protected function getResultProperties() {
647  return false;
648  }
649 
656  public function getFinalResultProperties() {
657  $properties = $this->getResultProperties();
658  wfRunHooks( 'APIGetResultProperties', array( $this, &$properties ) );
659 
660  return $properties;
661  }
662 
667  protected static function addTokenProperties( &$props, $tokenFunctions ) {
668  foreach ( array_keys( $tokenFunctions ) as $token ) {
669  $props[''][$token . 'token'] = array(
670  ApiBase::PROP_TYPE => 'string',
671  ApiBase::PROP_NULLABLE => true
672  );
673  }
674  }
675 
682  public function getFinalDescription() {
683  $desc = $this->getDescription();
684  wfRunHooks( 'APIGetDescription', array( &$this, &$desc ) );
685 
686  return $desc;
687  }
688 
695  public function encodeParamName( $paramName ) {
696  return $this->mModulePrefix . $paramName;
697  }
698 
708  public function extractRequestParams( $parseLimit = true ) {
709  // Cache parameters, for performance and to avoid bug 24564.
710  if ( !isset( $this->mParamCache[$parseLimit] ) ) {
711  $params = $this->getFinalParams();
712  $results = array();
713 
714  if ( $params ) { // getFinalParams() can return false
715  foreach ( $params as $paramName => $paramSettings ) {
716  $results[$paramName] = $this->getParameterFromSettings(
717  $paramName, $paramSettings, $parseLimit );
718  }
719  }
720  $this->mParamCache[$parseLimit] = $results;
721  }
722 
723  return $this->mParamCache[$parseLimit];
724  }
725 
732  protected function getParameter( $paramName, $parseLimit = true ) {
733  $params = $this->getFinalParams();
734  $paramSettings = $params[$paramName];
735 
736  return $this->getParameterFromSettings( $paramName, $paramSettings, $parseLimit );
737  }
738 
743  public function requireOnlyOneParameter( $params ) {
744  $required = func_get_args();
745  array_shift( $required );
746  $p = $this->getModulePrefix();
747 
748  $intersection = array_intersect( array_keys( array_filter( $params,
749  array( $this, "parameterNotEmpty" ) ) ), $required );
750 
751  if ( count( $intersection ) > 1 ) {
752  $this->dieUsage(
753  "The parameters {$p}" . implode( ", {$p}", $intersection ) . ' can not be used together',
754  'invalidparammix' );
755  } elseif ( count( $intersection ) == 0 ) {
756  $this->dieUsage(
757  "One of the parameters {$p}" . implode( ", {$p}", $required ) . ' is required',
758  'missingparam'
759  );
760  }
761  }
762 
770  $p = $this->getModulePrefix();
771  $params = implode( ", {$p}", $params );
772 
773  return array(
774  array(
775  'code' => "{$p}missingparam",
776  'info' => "One of the parameters {$p}{$params} is required"
777  ),
778  array(
779  'code' => "{$p}invalidparammix",
780  'info' => "The parameters {$p}{$params} can not be used together"
781  )
782  );
783  }
784 
790  public function requireMaxOneParameter( $params ) {
791  $required = func_get_args();
792  array_shift( $required );
793  $p = $this->getModulePrefix();
794 
795  $intersection = array_intersect( array_keys( array_filter( $params,
796  array( $this, "parameterNotEmpty" ) ) ), $required );
797 
798  if ( count( $intersection ) > 1 ) {
799  $this->dieUsage(
800  "The parameters {$p}" . implode( ", {$p}", $intersection ) . ' can not be used together',
801  'invalidparammix'
802  );
803  }
804  }
805 
813  $p = $this->getModulePrefix();
814  $params = implode( ", {$p}", $params );
815 
816  return array(
817  array(
818  'code' => "{$p}invalidparammix",
819  'info' => "The parameters {$p}{$params} can not be used together"
820  )
821  );
822  }
823 
831  public function requireAtLeastOneParameter( $params ) {
832  $required = func_get_args();
833  array_shift( $required );
834  $p = $this->getModulePrefix();
835 
836  $intersection = array_intersect(
837  array_keys( array_filter( $params, array( $this, "parameterNotEmpty" ) ) ),
838  $required
839  );
840 
841  if ( count( $intersection ) == 0 ) {
842  $this->dieUsage( "At least one of the parameters {$p}" .
843  implode( ", {$p}", $required ) . ' is required', "{$p}missingparam" );
844  }
845  }
846 
855  $p = $this->getModulePrefix();
856  $params = implode( ", {$p}", $params );
857 
858  return array(
859  array(
860  'code' => "{$p}missingparam",
861  'info' => "At least one of the parameters {$p}{$params} is required",
862  ),
863  );
864  }
865 
874  public function getTitleOrPageId( $params, $load = false ) {
875  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
876 
877  $pageObj = null;
878  if ( isset( $params['title'] ) ) {
879  $titleObj = Title::newFromText( $params['title'] );
880  if ( !$titleObj || $titleObj->isExternal() ) {
881  $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
882  }
883  if ( !$titleObj->canExist() ) {
884  $this->dieUsage( "Namespace doesn't allow actual pages", 'pagecannotexist' );
885  }
886  $pageObj = WikiPage::factory( $titleObj );
887  if ( $load !== false ) {
888  $pageObj->loadPageData( $load );
889  }
890  } elseif ( isset( $params['pageid'] ) ) {
891  if ( $load === false ) {
892  $load = 'fromdb';
893  }
894  $pageObj = WikiPage::newFromID( $params['pageid'], $load );
895  if ( !$pageObj ) {
896  $this->dieUsageMsg( array( 'nosuchpageid', $params['pageid'] ) );
897  }
898  }
899 
900  return $pageObj;
901  }
902 
906  public function getTitleOrPageIdErrorMessage() {
907  return array_merge(
908  $this->getRequireOnlyOneParameterErrorMessages( array( 'title', 'pageid' ) ),
909  array(
910  array( 'invalidtitle', 'title' ),
911  array( 'nosuchpageid', 'pageid' ),
912  )
913  );
914  }
915 
922  private function parameterNotEmpty( $x ) {
923  return !is_null( $x ) && $x !== false;
924  }
925 
934  protected function getWatchlistValue( $watchlist, $titleObj, $userOption = null ) {
935 
936  $userWatching = $this->getUser()->isWatched( $titleObj, WatchedItem::IGNORE_USER_RIGHTS );
937 
938  switch ( $watchlist ) {
939  case 'watch':
940  return true;
941 
942  case 'unwatch':
943  return false;
944 
945  case 'preferences':
946  # If the user is already watching, don't bother checking
947  if ( $userWatching ) {
948  return true;
949  }
950  # If no user option was passed, use watchdefault and watchcreations
951  if ( is_null( $userOption ) ) {
952  return $this->getUser()->getBoolOption( 'watchdefault' ) ||
953  $this->getUser()->getBoolOption( 'watchcreations' ) && !$titleObj->exists();
954  }
955 
956  # Watch the article based on the user preference
957  return $this->getUser()->getBoolOption( $userOption );
958 
959  case 'nochange':
960  return $userWatching;
961 
962  default:
963  return $userWatching;
964  }
965  }
966 
973  protected function setWatch( $watch, $titleObj, $userOption = null ) {
974  $value = $this->getWatchlistValue( $watch, $titleObj, $userOption );
975  if ( $value === null ) {
976  return;
977  }
978 
979  WatchAction::doWatchOrUnwatch( $value, $titleObj, $this->getUser() );
980  }
981 
991  protected function getParameterFromSettings( $paramName, $paramSettings, $parseLimit ) {
992  // Some classes may decide to change parameter names
993  $encParamName = $this->encodeParamName( $paramName );
994 
995  if ( !is_array( $paramSettings ) ) {
996  $default = $paramSettings;
997  $multi = false;
998  $type = gettype( $paramSettings );
999  $dupes = false;
1000  $deprecated = false;
1001  $required = false;
1002  } else {
1003  $default = isset( $paramSettings[self::PARAM_DFLT] )
1004  ? $paramSettings[self::PARAM_DFLT]
1005  : null;
1006  $multi = isset( $paramSettings[self::PARAM_ISMULTI] )
1007  ? $paramSettings[self::PARAM_ISMULTI]
1008  : false;
1009  $type = isset( $paramSettings[self::PARAM_TYPE] )
1010  ? $paramSettings[self::PARAM_TYPE]
1011  : null;
1012  $dupes = isset( $paramSettings[self::PARAM_ALLOW_DUPLICATES] )
1013  ? $paramSettings[self::PARAM_ALLOW_DUPLICATES]
1014  : false;
1015  $deprecated = isset( $paramSettings[self::PARAM_DEPRECATED] )
1016  ? $paramSettings[self::PARAM_DEPRECATED]
1017  : false;
1018  $required = isset( $paramSettings[self::PARAM_REQUIRED] )
1019  ? $paramSettings[self::PARAM_REQUIRED]
1020  : false;
1021 
1022  // When type is not given, and no choices, the type is the same as $default
1023  if ( !isset( $type ) ) {
1024  if ( isset( $default ) ) {
1025  $type = gettype( $default );
1026  } else {
1027  $type = 'NULL'; // allow everything
1028  }
1029  }
1030  }
1031 
1032  if ( $type == 'boolean' ) {
1033  if ( isset( $default ) && $default !== false ) {
1034  // Having a default value of anything other than 'false' is not allowed
1036  __METHOD__,
1037  "Boolean param $encParamName's default is set to '$default'. " .
1038  "Boolean parameters must default to false."
1039  );
1040  }
1041 
1042  $value = $this->getMain()->getCheck( $encParamName );
1043  } elseif ( $type == 'upload' ) {
1044  if ( isset( $default ) ) {
1045  // Having a default value is not allowed
1047  __METHOD__,
1048  "File upload param $encParamName's default is set to " .
1049  "'$default'. File upload parameters may not have a default." );
1050  }
1051  if ( $multi ) {
1052  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1053  }
1054  $value = $this->getMain()->getUpload( $encParamName );
1055  if ( !$value->exists() ) {
1056  // This will get the value without trying to normalize it
1057  // (because trying to normalize a large binary file
1058  // accidentally uploaded as a field fails spectacularly)
1059  $value = $this->getMain()->getRequest()->unsetVal( $encParamName );
1060  if ( $value !== null ) {
1061  $this->dieUsage(
1062  "File upload param $encParamName is not a file upload; " .
1063  "be sure to use multipart/form-data for your POST and include " .
1064  "a filename in the Content-Disposition header.",
1065  "badupload_{$encParamName}"
1066  );
1067  }
1068  }
1069  } else {
1070  $value = $this->getMain()->getVal( $encParamName, $default );
1071 
1072  if ( isset( $value ) && $type == 'namespace' ) {
1074  }
1075  }
1076 
1077  if ( isset( $value ) && ( $multi || is_array( $type ) ) ) {
1078  $value = $this->parseMultiValue(
1079  $encParamName,
1080  $value,
1081  $multi,
1082  is_array( $type ) ? $type : null
1083  );
1084  }
1085 
1086  // More validation only when choices were not given
1087  // choices were validated in parseMultiValue()
1088  if ( isset( $value ) ) {
1089  if ( !is_array( $type ) ) {
1090  switch ( $type ) {
1091  case 'NULL': // nothing to do
1092  break;
1093  case 'string':
1094  if ( $required && $value === '' ) {
1095  $this->dieUsageMsg( array( 'missingparam', $paramName ) );
1096  }
1097  break;
1098  case 'integer': // Force everything using intval() and optionally validate limits
1099  $min = isset( $paramSettings[self::PARAM_MIN] ) ? $paramSettings[self::PARAM_MIN] : null;
1100  $max = isset( $paramSettings[self::PARAM_MAX] ) ? $paramSettings[self::PARAM_MAX] : null;
1101  $enforceLimits = isset( $paramSettings[self::PARAM_RANGE_ENFORCE] )
1102  ? $paramSettings[self::PARAM_RANGE_ENFORCE] : false;
1103 
1104  if ( is_array( $value ) ) {
1105  $value = array_map( 'intval', $value );
1106  if ( !is_null( $min ) || !is_null( $max ) ) {
1107  foreach ( $value as &$v ) {
1108  $this->validateLimit( $paramName, $v, $min, $max, null, $enforceLimits );
1109  }
1110  }
1111  } else {
1112  $value = intval( $value );
1113  if ( !is_null( $min ) || !is_null( $max ) ) {
1114  $this->validateLimit( $paramName, $value, $min, $max, null, $enforceLimits );
1115  }
1116  }
1117  break;
1118  case 'limit':
1119  if ( !$parseLimit ) {
1120  // Don't do any validation whatsoever
1121  break;
1122  }
1123  if ( !isset( $paramSettings[self::PARAM_MAX] )
1124  || !isset( $paramSettings[self::PARAM_MAX2] )
1125  ) {
1127  __METHOD__,
1128  "MAX1 or MAX2 are not defined for the limit $encParamName"
1129  );
1130  }
1131  if ( $multi ) {
1132  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1133  }
1134  $min = isset( $paramSettings[self::PARAM_MIN] ) ? $paramSettings[self::PARAM_MIN] : 0;
1135  if ( $value == 'max' ) {
1136  $value = $this->getMain()->canApiHighLimits()
1137  ? $paramSettings[self::PARAM_MAX2]
1138  : $paramSettings[self::PARAM_MAX];
1139  $this->getResult()->setParsedLimit( $this->getModuleName(), $value );
1140  } else {
1141  $value = intval( $value );
1142  $this->validateLimit(
1143  $paramName,
1144  $value,
1145  $min,
1146  $paramSettings[self::PARAM_MAX],
1147  $paramSettings[self::PARAM_MAX2]
1148  );
1149  }
1150  break;
1151  case 'boolean':
1152  if ( $multi ) {
1153  ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
1154  }
1155  break;
1156  case 'timestamp':
1157  if ( is_array( $value ) ) {
1158  foreach ( $value as $key => $val ) {
1159  $value[$key] = $this->validateTimestamp( $val, $encParamName );
1160  }
1161  } else {
1162  $value = $this->validateTimestamp( $value, $encParamName );
1163  }
1164  break;
1165  case 'user':
1166  if ( is_array( $value ) ) {
1167  foreach ( $value as $key => $val ) {
1168  $value[$key] = $this->validateUser( $val, $encParamName );
1169  }
1170  } else {
1171  $value = $this->validateUser( $value, $encParamName );
1172  }
1173  break;
1174  case 'upload': // nothing to do
1175  break;
1176  default:
1177  ApiBase::dieDebug( __METHOD__, "Param $encParamName's type is unknown - $type" );
1178  }
1179  }
1180 
1181  // Throw out duplicates if requested
1182  if ( !$dupes && is_array( $value ) ) {
1183  $value = array_unique( $value );
1184  }
1185 
1186  // Set a warning if a deprecated parameter has been passed
1187  if ( $deprecated && $value !== false ) {
1188  $this->setWarning( "The $encParamName parameter has been deprecated." );
1189  }
1190  } elseif ( $required ) {
1191  $this->dieUsageMsg( array( 'missingparam', $paramName ) );
1192  }
1193 
1194  return $value;
1195  }
1196 
1210  protected function parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues ) {
1211  if ( trim( $value ) === '' && $allowMultiple ) {
1212  return array();
1213  }
1214 
1215  // This is a bit awkward, but we want to avoid calling canApiHighLimits()
1216  // because it unstubs $wgUser
1217  $valuesList = explode( '|', $value, self::LIMIT_SML2 + 1 );
1218  $sizeLimit = count( $valuesList ) > self::LIMIT_SML1 && $this->mMainModule->canApiHighLimits()
1220  : self::LIMIT_SML1;
1221 
1222  if ( self::truncateArray( $valuesList, $sizeLimit ) ) {
1223  $this->setWarning( "Too many values supplied for parameter '$valueName': " .
1224  "the limit is $sizeLimit" );
1225  }
1226 
1227  if ( !$allowMultiple && count( $valuesList ) != 1 ) {
1228  // Bug 33482 - Allow entries with | in them for non-multiple values
1229  if ( in_array( $value, $allowedValues, true ) ) {
1230  return $value;
1231  }
1232 
1233  $possibleValues = is_array( $allowedValues )
1234  ? "of '" . implode( "', '", $allowedValues ) . "'"
1235  : '';
1236  $this->dieUsage(
1237  "Only one $possibleValues is allowed for parameter '$valueName'",
1238  "multival_$valueName"
1239  );
1240  }
1241 
1242  if ( is_array( $allowedValues ) ) {
1243  // Check for unknown values
1244  $unknown = array_diff( $valuesList, $allowedValues );
1245  if ( count( $unknown ) ) {
1246  if ( $allowMultiple ) {
1247  $s = count( $unknown ) > 1 ? 's' : '';
1248  $vals = implode( ", ", $unknown );
1249  $this->setWarning( "Unrecognized value$s for parameter '$valueName': $vals" );
1250  } else {
1251  $this->dieUsage(
1252  "Unrecognized value for parameter '$valueName': {$valuesList[0]}",
1253  "unknown_$valueName"
1254  );
1255  }
1256  }
1257  // Now throw them out
1258  $valuesList = array_intersect( $valuesList, $allowedValues );
1259  }
1260 
1261  return $allowMultiple ? $valuesList : $valuesList[0];
1262  }
1263 
1274  function validateLimit( $paramName, &$value, $min, $max, $botMax = null, $enforceLimits = false ) {
1275  if ( !is_null( $min ) && $value < $min ) {
1276 
1277  $msg = $this->encodeParamName( $paramName ) . " may not be less than $min (set to $value)";
1278  $this->warnOrDie( $msg, $enforceLimits );
1279  $value = $min;
1280  }
1281 
1282  // Minimum is always validated, whereas maximum is checked only if not
1283  // running in internal call mode
1284  if ( $this->getMain()->isInternalMode() ) {
1285  return;
1286  }
1287 
1288  // Optimization: do not check user's bot status unless really needed -- skips db query
1289  // assumes $botMax >= $max
1290  if ( !is_null( $max ) && $value > $max ) {
1291  if ( !is_null( $botMax ) && $this->getMain()->canApiHighLimits() ) {
1292  if ( $value > $botMax ) {
1293  $msg = $this->encodeParamName( $paramName ) .
1294  " may not be over $botMax (set to $value) for bots or sysops";
1295  $this->warnOrDie( $msg, $enforceLimits );
1296  $value = $botMax;
1297  }
1298  } else {
1299  $msg = $this->encodeParamName( $paramName ) . " may not be over $max (set to $value) for users";
1300  $this->warnOrDie( $msg, $enforceLimits );
1301  $value = $max;
1302  }
1303  }
1304  }
1305 
1312  function validateTimestamp( $value, $encParamName ) {
1313  $unixTimestamp = wfTimestamp( TS_UNIX, $value );
1314  if ( $unixTimestamp === false ) {
1315  $this->dieUsage(
1316  "Invalid value '$value' for timestamp parameter $encParamName",
1317  "badtimestamp_{$encParamName}"
1318  );
1319  }
1320 
1321  return wfTimestamp( TS_MW, $unixTimestamp );
1322  }
1323 
1330  private function validateUser( $value, $encParamName ) {
1332  if ( $title === null ) {
1333  $this->dieUsage(
1334  "Invalid value '$value' for user parameter $encParamName",
1335  "baduser_{$encParamName}"
1336  );
1337  }
1338 
1339  return $title->getText();
1340  }
1341 
1348  private function warnOrDie( $msg, $enforceLimits = false ) {
1349  if ( $enforceLimits ) {
1350  $this->dieUsage( $msg, 'integeroutofrange' );
1351  }
1352 
1353  $this->setWarning( $msg );
1354  }
1355 
1362  public static function truncateArray( &$arr, $limit ) {
1363  $modified = false;
1364  while ( count( $arr ) > $limit ) {
1365  array_pop( $arr );
1366  $modified = true;
1367  }
1368 
1369  return $modified;
1370  }
1371 
1384  public function dieUsage( $description, $errorCode, $httpRespCode = 0, $extradata = null ) {
1385  Profiler::instance()->close();
1386  throw new UsageException(
1387  $description,
1388  $this->encodeParamName( $errorCode ),
1389  $httpRespCode,
1390  $extradata
1391  );
1392  }
1393 
1401  public function getErrorFromStatus( $status ) {
1402  if ( $status->isGood() ) {
1403  throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
1404  }
1405 
1406  $errors = $status->getErrorsArray();
1407  if ( !$errors ) {
1408  // No errors? Assume the warnings should be treated as errors
1409  $errors = $status->getWarningsArray();
1410  }
1411  if ( !$errors ) {
1412  // Still no errors? Punt
1413  $errors = array( array( 'unknownerror-nocode' ) );
1414  }
1415 
1416  // Cannot use dieUsageMsg() because extensions might return custom
1417  // error messages.
1418  if ( $errors[0] instanceof Message ) {
1419  $msg = $errors[0];
1420  $code = $msg->getKey();
1421  } else {
1422  $code = array_shift( $errors[0] );
1423  $msg = wfMessage( $code, $errors[0] );
1424  }
1425  if ( isset( ApiBase::$messageMap[$code] ) ) {
1426  // Translate message to code, for backwards compatability
1427  $code = ApiBase::$messageMap[$code]['code'];
1428  }
1429 
1430  return array( $code, $msg->inLanguage( 'en' )->useDatabase( false )->plain() );
1431  }
1432 
1440  public function dieStatus( $status ) {
1441 
1442  list( $code, $msg ) = $this->getErrorFromStatus( $status );
1443  $this->dieUsage( $msg, $code );
1444  }
1445 
1446  // @codingStandardsIgnoreStart Allow long lines. Cannot split these.
1450  public static $messageMap = array(
1451  // This one MUST be present, or dieUsageMsg() will recurse infinitely
1452  'unknownerror' => array( 'code' => 'unknownerror', 'info' => "Unknown error: \"\$1\"" ),
1453  'unknownerror-nocode' => array( 'code' => 'unknownerror', 'info' => 'Unknown error' ),
1454 
1455  // Messages from Title::getUserPermissionsErrors()
1456  'ns-specialprotected' => array(
1457  'code' => 'unsupportednamespace',
1458  'info' => "Pages in the Special namespace can't be edited"
1459  ),
1460  'protectedinterface' => array(
1461  'code' => 'protectednamespace-interface',
1462  'info' => "You're not allowed to edit interface messages"
1463  ),
1464  'namespaceprotected' => array(
1465  'code' => 'protectednamespace',
1466  'info' => "You're not allowed to edit pages in the \"\$1\" namespace"
1467  ),
1468  'customcssprotected' => array(
1469  'code' => 'customcssprotected',
1470  'info' => "You're not allowed to edit custom CSS pages"
1471  ),
1472  'customjsprotected' => array(
1473  'code' => 'customjsprotected',
1474  'info' => "You're not allowed to edit custom JavaScript pages"
1475  ),
1476  'cascadeprotected' => array(
1477  'code' => 'cascadeprotected',
1478  'info' => "The page you're trying to edit is protected because it's included in a cascade-protected page"
1479  ),
1480  'protectedpagetext' => array(
1481  'code' => 'protectedpage',
1482  'info' => "The \"\$1\" right is required to edit this page"
1483  ),
1484  'protect-cantedit' => array(
1485  'code' => 'cantedit',
1486  'info' => "You can't protect this page because you can't edit it"
1487  ),
1488  'badaccess-group0' => array(
1489  'code' => 'permissiondenied',
1490  'info' => "Permission denied"
1491  ), // Generic permission denied message
1492  'badaccess-groups' => array(
1493  'code' => 'permissiondenied',
1494  'info' => "Permission denied"
1495  ),
1496  'titleprotected' => array(
1497  'code' => 'protectedtitle',
1498  'info' => "This title has been protected from creation"
1499  ),
1500  'nocreate-loggedin' => array(
1501  'code' => 'cantcreate',
1502  'info' => "You don't have permission to create new pages"
1503  ),
1504  'nocreatetext' => array(
1505  'code' => 'cantcreate-anon',
1506  'info' => "Anonymous users can't create new pages"
1507  ),
1508  'movenologintext' => array(
1509  'code' => 'cantmove-anon',
1510  'info' => "Anonymous users can't move pages"
1511  ),
1512  'movenotallowed' => array(
1513  'code' => 'cantmove',
1514  'info' => "You don't have permission to move pages"
1515  ),
1516  'confirmedittext' => array(
1517  'code' => 'confirmemail',
1518  'info' => "You must confirm your email address before you can edit"
1519  ),
1520  'blockedtext' => array(
1521  'code' => 'blocked',
1522  'info' => "You have been blocked from editing"
1523  ),
1524  'autoblockedtext' => array(
1525  'code' => 'autoblocked',
1526  'info' => "Your IP address has been blocked automatically, because it was used by a blocked user"
1527  ),
1528 
1529  // Miscellaneous interface messages
1530  'actionthrottledtext' => array(
1531  'code' => 'ratelimited',
1532  'info' => "You've exceeded your rate limit. Please wait some time and try again"
1533  ),
1534  'alreadyrolled' => array(
1535  'code' => 'alreadyrolled',
1536  'info' => "The page you tried to rollback was already rolled back"
1537  ),
1538  'cantrollback' => array(
1539  'code' => 'onlyauthor',
1540  'info' => "The page you tried to rollback only has one author"
1541  ),
1542  'readonlytext' => array(
1543  'code' => 'readonly',
1544  'info' => "The wiki is currently in read-only mode"
1545  ),
1546  'sessionfailure' => array(
1547  'code' => 'badtoken',
1548  'info' => "Invalid token" ),
1549  'cannotdelete' => array(
1550  'code' => 'cantdelete',
1551  'info' => "Couldn't delete \"\$1\". Maybe it was deleted already by someone else"
1552  ),
1553  'notanarticle' => array(
1554  'code' => 'missingtitle',
1555  'info' => "The page you requested doesn't exist"
1556  ),
1557  'selfmove' => array( 'code' => 'selfmove', 'info' => "Can't move a page to itself"
1558  ),
1559  'immobile_namespace' => array(
1560  'code' => 'immobilenamespace',
1561  'info' => "You tried to move pages from or to a namespace that is protected from moving"
1562  ),
1563  'articleexists' => array(
1564  'code' => 'articleexists',
1565  'info' => "The destination article already exists and is not a redirect to the source article"
1566  ),
1567  'protectedpage' => array(
1568  'code' => 'protectedpage',
1569  'info' => "You don't have permission to perform this move"
1570  ),
1571  'hookaborted' => array(
1572  'code' => 'hookaborted',
1573  'info' => "The modification you tried to make was aborted by an extension hook"
1574  ),
1575  'cantmove-titleprotected' => array(
1576  'code' => 'protectedtitle',
1577  'info' => "The destination article has been protected from creation"
1578  ),
1579  'imagenocrossnamespace' => array(
1580  'code' => 'nonfilenamespace',
1581  'info' => "Can't move a file to a non-file namespace"
1582  ),
1583  'imagetypemismatch' => array(
1584  'code' => 'filetypemismatch',
1585  'info' => "The new file extension doesn't match its type"
1586  ),
1587  // 'badarticleerror' => shouldn't happen
1588  // 'badtitletext' => shouldn't happen
1589  'ip_range_invalid' => array( 'code' => 'invalidrange', 'info' => "Invalid IP range" ),
1590  'range_block_disabled' => array(
1591  'code' => 'rangedisabled',
1592  'info' => "Blocking IP ranges has been disabled"
1593  ),
1594  'nosuchusershort' => array(
1595  'code' => 'nosuchuser',
1596  'info' => "The user you specified doesn't exist"
1597  ),
1598  'badipaddress' => array( 'code' => 'invalidip', 'info' => "Invalid IP address specified" ),
1599  'ipb_expiry_invalid' => array( 'code' => 'invalidexpiry', 'info' => "Invalid expiry time" ),
1600  'ipb_already_blocked' => array(
1601  'code' => 'alreadyblocked',
1602  'info' => "The user you tried to block was already blocked"
1603  ),
1604  'ipb_blocked_as_range' => array(
1605  'code' => 'blockedasrange',
1606  'info' => "IP address \"\$1\" was blocked as part of range \"\$2\". You can't unblock the IP individually, but you can unblock the range as a whole."
1607  ),
1608  'ipb_cant_unblock' => array(
1609  'code' => 'cantunblock',
1610  'info' => "The block you specified was not found. It may have been unblocked already"
1611  ),
1612  'mailnologin' => array(
1613  'code' => 'cantsend',
1614  'info' => "You are not logged in, you do not have a confirmed email address, or you are not allowed to send email to other users, so you cannot send email"
1615  ),
1616  'ipbblocked' => array(
1617  'code' => 'ipbblocked',
1618  'info' => 'You cannot block or unblock users while you are yourself blocked'
1619  ),
1620  'ipbnounblockself' => array(
1621  'code' => 'ipbnounblockself',
1622  'info' => 'You are not allowed to unblock yourself'
1623  ),
1624  'usermaildisabled' => array(
1625  'code' => 'usermaildisabled',
1626  'info' => "User email has been disabled"
1627  ),
1628  'blockedemailuser' => array(
1629  'code' => 'blockedfrommail',
1630  'info' => "You have been blocked from sending email"
1631  ),
1632  'notarget' => array(
1633  'code' => 'notarget',
1634  'info' => "You have not specified a valid target for this action"
1635  ),
1636  'noemail' => array(
1637  'code' => 'noemail',
1638  'info' => "The user has not specified a valid email address, or has chosen not to receive email from other users"
1639  ),
1640  'rcpatroldisabled' => array(
1641  'code' => 'patroldisabled',
1642  'info' => "Patrolling is disabled on this wiki"
1643  ),
1644  'markedaspatrollederror-noautopatrol' => array(
1645  'code' => 'noautopatrol',
1646  'info' => "You don't have permission to patrol your own changes"
1647  ),
1648  'delete-toobig' => array(
1649  'code' => 'bigdelete',
1650  'info' => "You can't delete this page because it has more than \$1 revisions"
1651  ),
1652  'movenotallowedfile' => array(
1653  'code' => 'cantmovefile',
1654  'info' => "You don't have permission to move files"
1655  ),
1656  'userrights-no-interwiki' => array(
1657  'code' => 'nointerwikiuserrights',
1658  'info' => "You don't have permission to change user rights on other wikis"
1659  ),
1660  'userrights-nodatabase' => array(
1661  'code' => 'nosuchdatabase',
1662  'info' => "Database \"\$1\" does not exist or is not local"
1663  ),
1664  'nouserspecified' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ),
1665  'noname' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ),
1666  'summaryrequired' => array( 'code' => 'summaryrequired', 'info' => 'Summary required' ),
1667  'import-rootpage-invalid' => array(
1668  'code' => 'import-rootpage-invalid',
1669  'info' => 'Root page is an invalid title'
1670  ),
1671  'import-rootpage-nosubpage' => array(
1672  'code' => 'import-rootpage-nosubpage',
1673  'info' => 'Namespace "$1" of the root page does not allow subpages'
1674  ),
1675 
1676  // API-specific messages
1677  'readrequired' => array(
1678  'code' => 'readapidenied',
1679  'info' => "You need read permission to use this module"
1680  ),
1681  'writedisabled' => array(
1682  'code' => 'noapiwrite',
1683  'info' => "Editing of this wiki through the API is disabled. Make sure the \$wgEnableWriteAPI=true; statement is included in the wiki's LocalSettings.php file"
1684  ),
1685  'writerequired' => array(
1686  'code' => 'writeapidenied',
1687  'info' => "You're not allowed to edit this wiki through the API"
1688  ),
1689  'missingparam' => array( 'code' => 'no$1', 'info' => "The \$1 parameter must be set" ),
1690  'invalidtitle' => array( 'code' => 'invalidtitle', 'info' => "Bad title \"\$1\"" ),
1691  'nosuchpageid' => array( 'code' => 'nosuchpageid', 'info' => "There is no page with ID \$1" ),
1692  'nosuchrevid' => array( 'code' => 'nosuchrevid', 'info' => "There is no revision with ID \$1" ),
1693  'nosuchuser' => array( 'code' => 'nosuchuser', 'info' => "User \"\$1\" doesn't exist" ),
1694  'invaliduser' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ),
1695  'invalidexpiry' => array( 'code' => 'invalidexpiry', 'info' => "Invalid expiry time \"\$1\"" ),
1696  'pastexpiry' => array( 'code' => 'pastexpiry', 'info' => "Expiry time \"\$1\" is in the past" ),
1697  'create-titleexists' => array(
1698  'code' => 'create-titleexists',
1699  'info' => "Existing titles can't be protected with 'create'"
1700  ),
1701  'missingtitle-createonly' => array(
1702  'code' => 'missingtitle-createonly',
1703  'info' => "Missing titles can only be protected with 'create'"
1704  ),
1705  'cantblock' => array( 'code' => 'cantblock',
1706  'info' => "You don't have permission to block users"
1707  ),
1708  'canthide' => array(
1709  'code' => 'canthide',
1710  'info' => "You don't have permission to hide user names from the block log"
1711  ),
1712  'cantblock-email' => array(
1713  'code' => 'cantblock-email',
1714  'info' => "You don't have permission to block users from sending email through the wiki"
1715  ),
1716  'unblock-notarget' => array(
1717  'code' => 'notarget',
1718  'info' => "Either the id or the user parameter must be set"
1719  ),
1720  'unblock-idanduser' => array(
1721  'code' => 'idanduser',
1722  'info' => "The id and user parameters can't be used together"
1723  ),
1724  'cantunblock' => array(
1725  'code' => 'permissiondenied',
1726  'info' => "You don't have permission to unblock users"
1727  ),
1728  'cannotundelete' => array(
1729  'code' => 'cantundelete',
1730  'info' => "Couldn't undelete: the requested revisions may not exist, or may have been undeleted already"
1731  ),
1732  'permdenied-undelete' => array(
1733  'code' => 'permissiondenied',
1734  'info' => "You don't have permission to restore deleted revisions"
1735  ),
1736  'createonly-exists' => array(
1737  'code' => 'articleexists',
1738  'info' => "The article you tried to create has been created already"
1739  ),
1740  'nocreate-missing' => array(
1741  'code' => 'missingtitle',
1742  'info' => "The article you tried to edit doesn't exist"
1743  ),
1744  'cantchangecontentmodel' => array(
1745  'code' => 'cantchangecontentmodel',
1746  'info' => "You don't have permission to change the content model of a page"
1747  ),
1748  'nosuchrcid' => array(
1749  'code' => 'nosuchrcid',
1750  'info' => "There is no change with rcid \"\$1\""
1751  ),
1752  'protect-invalidaction' => array(
1753  'code' => 'protect-invalidaction',
1754  'info' => "Invalid protection type \"\$1\""
1755  ),
1756  'protect-invalidlevel' => array(
1757  'code' => 'protect-invalidlevel',
1758  'info' => "Invalid protection level \"\$1\""
1759  ),
1760  'toofewexpiries' => array(
1761  'code' => 'toofewexpiries',
1762  'info' => "\$1 expiry timestamps were provided where \$2 were needed"
1763  ),
1764  'cantimport' => array(
1765  'code' => 'cantimport',
1766  'info' => "You don't have permission to import pages"
1767  ),
1768  'cantimport-upload' => array(
1769  'code' => 'cantimport-upload',
1770  'info' => "You don't have permission to import uploaded pages"
1771  ),
1772  'importnofile' => array( 'code' => 'nofile', 'info' => "You didn't upload a file" ),
1773  'importuploaderrorsize' => array(
1774  'code' => 'filetoobig',
1775  'info' => 'The file you uploaded is bigger than the maximum upload size'
1776  ),
1777  'importuploaderrorpartial' => array(
1778  'code' => 'partialupload',
1779  'info' => 'The file was only partially uploaded'
1780  ),
1781  'importuploaderrortemp' => array(
1782  'code' => 'notempdir',
1783  'info' => 'The temporary upload directory is missing'
1784  ),
1785  'importcantopen' => array(
1786  'code' => 'cantopenfile',
1787  'info' => "Couldn't open the uploaded file"
1788  ),
1789  'import-noarticle' => array(
1790  'code' => 'badinterwiki',
1791  'info' => 'Invalid interwiki title specified'
1792  ),
1793  'importbadinterwiki' => array(
1794  'code' => 'badinterwiki',
1795  'info' => 'Invalid interwiki title specified'
1796  ),
1797  'import-unknownerror' => array(
1798  'code' => 'import-unknownerror',
1799  'info' => "Unknown error on import: \"\$1\""
1800  ),
1801  'cantoverwrite-sharedfile' => array(
1802  'code' => 'cantoverwrite-sharedfile',
1803  'info' => 'The target file exists on a shared repository and you do not have permission to override it'
1804  ),
1805  'sharedfile-exists' => array(
1806  'code' => 'fileexists-sharedrepo-perm',
1807  'info' => 'The target file exists on a shared repository. Use the ignorewarnings parameter to override it.'
1808  ),
1809  'mustbeposted' => array(
1810  'code' => 'mustbeposted',
1811  'info' => "The \$1 module requires a POST request"
1812  ),
1813  'show' => array(
1814  'code' => 'show',
1815  'info' => 'Incorrect parameter - mutually exclusive values may not be supplied'
1816  ),
1817  'specialpage-cantexecute' => array(
1818  'code' => 'specialpage-cantexecute',
1819  'info' => "You don't have permission to view the results of this special page"
1820  ),
1821  'invalidoldimage' => array(
1822  'code' => 'invalidoldimage',
1823  'info' => 'The oldimage parameter has invalid format'
1824  ),
1825  'nodeleteablefile' => array(
1826  'code' => 'nodeleteablefile',
1827  'info' => 'No such old version of the file'
1828  ),
1829  'fileexists-forbidden' => array(
1830  'code' => 'fileexists-forbidden',
1831  'info' => 'A file with name "$1" already exists, and cannot be overwritten.'
1832  ),
1833  'fileexists-shared-forbidden' => array(
1834  'code' => 'fileexists-shared-forbidden',
1835  'info' => 'A file with name "$1" already exists in the shared file repository, and cannot be overwritten.'
1836  ),
1837  'filerevert-badversion' => array(
1838  'code' => 'filerevert-badversion',
1839  'info' => 'There is no previous local version of this file with the provided timestamp.'
1840  ),
1841 
1842  // ApiEditPage messages
1843  'noimageredirect-anon' => array(
1844  'code' => 'noimageredirect-anon',
1845  'info' => "Anonymous users can't create image redirects"
1846  ),
1847  'noimageredirect-logged' => array(
1848  'code' => 'noimageredirect',
1849  'info' => "You don't have permission to create image redirects"
1850  ),
1851  'spamdetected' => array(
1852  'code' => 'spamdetected',
1853  'info' => "Your edit was refused because it contained a spam fragment: \"\$1\""
1854  ),
1855  'contenttoobig' => array(
1856  'code' => 'contenttoobig',
1857  'info' => "The content you supplied exceeds the article size limit of \$1 kilobytes"
1858  ),
1859  'noedit-anon' => array( 'code' => 'noedit-anon', 'info' => "Anonymous users can't edit pages" ),
1860  'noedit' => array( 'code' => 'noedit', 'info' => "You don't have permission to edit pages" ),
1861  'wasdeleted' => array(
1862  'code' => 'pagedeleted',
1863  'info' => "The page has been deleted since you fetched its timestamp"
1864  ),
1865  'blankpage' => array(
1866  'code' => 'emptypage',
1867  'info' => "Creating new, empty pages is not allowed"
1868  ),
1869  'editconflict' => array( 'code' => 'editconflict', 'info' => "Edit conflict detected" ),
1870  'hashcheckfailed' => array( 'code' => 'badmd5', 'info' => "The supplied MD5 hash was incorrect" ),
1871  'missingtext' => array(
1872  'code' => 'notext',
1873  'info' => "One of the text, appendtext, prependtext and undo parameters must be set"
1874  ),
1875  'emptynewsection' => array(
1876  'code' => 'emptynewsection',
1877  'info' => 'Creating empty new sections is not possible.'
1878  ),
1879  'revwrongpage' => array(
1880  'code' => 'revwrongpage',
1881  'info' => "r\$1 is not a revision of \"\$2\""
1882  ),
1883  'undo-failure' => array(
1884  'code' => 'undofailure',
1885  'info' => 'Undo failed due to conflicting intermediate edits'
1886  ),
1887 
1888  // Messages from WikiPage::doEit()
1889  'edit-hook-aborted' => array(
1890  'code' => 'edit-hook-aborted',
1891  'info' => "Your edit was aborted by an ArticleSave hook"
1892  ),
1893  'edit-gone-missing' => array(
1894  'code' => 'edit-gone-missing',
1895  'info' => "The page you tried to edit doesn't seem to exist anymore"
1896  ),
1897  'edit-conflict' => array( 'code' => 'editconflict', 'info' => "Edit conflict detected" ),
1898  'edit-already-exists' => array(
1899  'code' => 'edit-already-exists',
1900  'info' => 'It seems the page you tried to create already exist'
1901  ),
1902 
1903  // uploadMsgs
1904  'invalid-file-key' => array( 'code' => 'invalid-file-key', 'info' => 'Not a valid file key' ),
1905  'nouploadmodule' => array( 'code' => 'nouploadmodule', 'info' => 'No upload module set' ),
1906  'uploaddisabled' => array(
1907  'code' => 'uploaddisabled',
1908  'info' => 'Uploads are not enabled. Make sure $wgEnableUploads is set to true in LocalSettings.php and the PHP ini setting file_uploads is true'
1909  ),
1910  'copyuploaddisabled' => array(
1911  'code' => 'copyuploaddisabled',
1912  'info' => 'Uploads by URL is not enabled. Make sure $wgAllowCopyUploads is set to true in LocalSettings.php.'
1913  ),
1914  'copyuploadbaddomain' => array(
1915  'code' => 'copyuploadbaddomain',
1916  'info' => 'Uploads by URL are not allowed from this domain.'
1917  ),
1918  'copyuploadbadurl' => array(
1919  'code' => 'copyuploadbadurl',
1920  'info' => 'Upload not allowed from this URL.'
1921  ),
1922 
1923  'filename-tooshort' => array(
1924  'code' => 'filename-tooshort',
1925  'info' => 'The filename is too short'
1926  ),
1927  'filename-toolong' => array( 'code' => 'filename-toolong', 'info' => 'The filename is too long' ),
1928  'illegal-filename' => array(
1929  'code' => 'illegal-filename',
1930  'info' => 'The filename is not allowed'
1931  ),
1932  'filetype-missing' => array(
1933  'code' => 'filetype-missing',
1934  'info' => 'The file is missing an extension'
1935  ),
1936 
1937  'mustbeloggedin' => array( 'code' => 'mustbeloggedin', 'info' => 'You must be logged in to $1.' )
1938  );
1939  // @codingStandardsIgnoreEnd
1940 
1944  public function dieReadOnly() {
1945  $parsed = $this->parseMsg( array( 'readonlytext' ) );
1946  $this->dieUsage( $parsed['info'], $parsed['code'], /* http error */ 0,
1947  array( 'readonlyreason' => wfReadOnlyReason() ) );
1948  }
1949 
1954  public function dieUsageMsg( $error ) {
1955  # most of the time we send a 1 element, so we might as well send it as
1956  # a string and make this an array here.
1957  if ( is_string( $error ) ) {
1958  $error = array( $error );
1959  }
1960  $parsed = $this->parseMsg( $error );
1961  $this->dieUsage( $parsed['info'], $parsed['code'] );
1962  }
1963 
1970  public function dieUsageMsgOrDebug( $error ) {
1971  global $wgDebugAPI;
1972  if ( $wgDebugAPI !== true ) {
1973  $this->dieUsageMsg( $error );
1974  }
1975 
1976  if ( is_string( $error ) ) {
1977  $error = array( $error );
1978  }
1979 
1980  $parsed = $this->parseMsg( $error );
1981  $this->setWarning( '$wgDebugAPI: ' . $parsed['code'] . ' - ' . $parsed['info'] );
1982  }
1983 
1990  protected function dieContinueUsageIf( $condition ) {
1991  if ( $condition ) {
1992  $this->dieUsage(
1993  'Invalid continue param. You should pass the original value returned by the previous query',
1994  'badcontinue' );
1995  }
1996  }
1997 
2003  public function parseMsg( $error ) {
2004  $error = (array)$error; // It seems strings sometimes make their way in here
2005  $key = array_shift( $error );
2006 
2007  // Check whether the error array was nested
2008  // array( array( <code>, <params> ), array( <another_code>, <params> ) )
2009  if ( is_array( $key ) ) {
2010  $error = $key;
2011  $key = array_shift( $error );
2012  }
2013 
2014  if ( isset( self::$messageMap[$key] ) ) {
2015  return array(
2016  'code' => wfMsgReplaceArgs( self::$messageMap[$key]['code'], $error ),
2017  'info' => wfMsgReplaceArgs( self::$messageMap[$key]['info'], $error )
2018  );
2019  }
2020 
2021  // If the key isn't present, throw an "unknown error"
2022  return $this->parseMsg( array( 'unknownerror', $key ) );
2023  }
2024 
2031  protected static function dieDebug( $method, $message ) {
2032  throw new MWException( "Internal error in $method: $message" );
2033  }
2034 
2039  public function shouldCheckMaxlag() {
2040  return true;
2041  }
2042 
2047  public function isReadMode() {
2048  return true;
2049  }
2050 
2055  public function isWriteMode() {
2056  return false;
2057  }
2058 
2063  public function mustBePosted() {
2064  return false;
2065  }
2066 
2073  public function needsToken() {
2074  return false;
2075  }
2076 
2085  public function getTokenSalt() {
2086  return false;
2087  }
2088 
2095  public function getWatchlistUser( $params ) {
2096  if ( !is_null( $params['owner'] ) && !is_null( $params['token'] ) ) {
2097  $user = User::newFromName( $params['owner'], false );
2098  if ( !( $user && $user->getId() ) ) {
2099  $this->dieUsage( 'Specified user does not exist', 'bad_wlowner' );
2100  }
2101  $token = $user->getOption( 'watchlisttoken' );
2102  if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
2103  $this->dieUsage(
2104  'Incorrect watchlist token provided -- please set a correct token in Special:Preferences',
2105  'bad_wltoken'
2106  );
2107  }
2108  } else {
2109  if ( !$this->getUser()->isLoggedIn() ) {
2110  $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
2111  }
2112  if ( !$this->getUser()->isAllowed( 'viewmywatchlist' ) ) {
2113  $this->dieUsage( 'You don\'t have permission to view your watchlist', 'permissiondenied' );
2114  }
2115  $user = $this->getUser();
2116  }
2117 
2118  return $user;
2119  }
2120 
2125  public function getHelpUrls() {
2126  return false;
2127  }
2128 
2138  public function getPossibleErrors() {
2139  $ret = array();
2140 
2141  $params = $this->getFinalParams();
2142  if ( $params ) {
2143  foreach ( $params as $paramName => $paramSettings ) {
2144  if ( isset( $paramSettings[ApiBase::PARAM_REQUIRED] )
2145  && $paramSettings[ApiBase::PARAM_REQUIRED]
2146  ) {
2147  $ret[] = array( 'missingparam', $paramName );
2148  }
2149  }
2150  if ( array_key_exists( 'continue', $params ) ) {
2151  $ret[] = array(
2152  'code' => 'badcontinue',
2153  'info' => 'Invalid continue param. You should pass the ' .
2154  'original value returned by the previous query'
2155  );
2156  }
2157  }
2158 
2159  if ( $this->mustBePosted() ) {
2160  $ret[] = array( 'mustbeposted', $this->getModuleName() );
2161  }
2162 
2163  if ( $this->isReadMode() ) {
2164  $ret[] = array( 'readrequired' );
2165  }
2166 
2167  if ( $this->isWriteMode() ) {
2168  $ret[] = array( 'writerequired' );
2169  $ret[] = array( 'writedisabled' );
2170  }
2171 
2172  if ( $this->needsToken() ) {
2173  if ( !isset( $params['token'][ApiBase::PARAM_REQUIRED] )
2174  || !$params['token'][ApiBase::PARAM_REQUIRED]
2175  ) {
2176  // Add token as possible missing parameter, if not already done
2177  $ret[] = array( 'missingparam', 'token' );
2178  }
2179  $ret[] = array( 'sessionfailure' );
2180  }
2181 
2182  return $ret;
2183  }
2184 
2192  public function getFinalPossibleErrors() {
2193  $possibleErrors = $this->getPossibleErrors();
2194  wfRunHooks( 'APIGetPossibleErrors', array( $this, &$possibleErrors ) );
2195 
2196  return $possibleErrors;
2197  }
2198 
2205  public function parseErrors( $errors ) {
2206  $ret = array();
2207 
2208  foreach ( $errors as $row ) {
2209  if ( isset( $row['code'] ) && isset( $row['info'] ) ) {
2210  $ret[] = $row;
2211  } else {
2212  $ret[] = $this->parseMsg( $row );
2213  }
2214  }
2215 
2216  return $ret;
2217  }
2218 
2222  private $mTimeIn = 0, $mModuleTime = 0;
2223 
2227  public function profileIn() {
2228  if ( $this->mTimeIn !== 0 ) {
2229  ApiBase::dieDebug( __METHOD__, 'Called twice without calling profileOut()' );
2230  }
2231  $this->mTimeIn = microtime( true );
2232  wfProfileIn( $this->getModuleProfileName() );
2233  }
2234 
2238  public function profileOut() {
2239  if ( $this->mTimeIn === 0 ) {
2240  ApiBase::dieDebug( __METHOD__, 'Called without calling profileIn() first' );
2241  }
2242  if ( $this->mDBTimeIn !== 0 ) {
2244  __METHOD__,
2245  'Must be called after database profiling is done with profileDBOut()'
2246  );
2247  }
2248 
2249  $this->mModuleTime += microtime( true ) - $this->mTimeIn;
2250  $this->mTimeIn = 0;
2251  wfProfileOut( $this->getModuleProfileName() );
2252  }
2253 
2258  public function safeProfileOut() {
2259  if ( $this->mTimeIn !== 0 ) {
2260  if ( $this->mDBTimeIn !== 0 ) {
2261  $this->profileDBOut();
2262  }
2263  $this->profileOut();
2264  }
2265  }
2266 
2271  public function getProfileTime() {
2272  if ( $this->mTimeIn !== 0 ) {
2273  ApiBase::dieDebug( __METHOD__, 'Called without calling profileOut() first' );
2274  }
2275 
2276  return $this->mModuleTime;
2277  }
2278 
2282  private $mDBTimeIn = 0, $mDBTime = 0;
2283 
2287  public function profileDBIn() {
2288  if ( $this->mTimeIn === 0 ) {
2290  __METHOD__,
2291  'Must be called while profiling the entire module with profileIn()'
2292  );
2293  }
2294  if ( $this->mDBTimeIn !== 0 ) {
2295  ApiBase::dieDebug( __METHOD__, 'Called twice without calling profileDBOut()' );
2296  }
2297  $this->mDBTimeIn = microtime( true );
2298  wfProfileIn( $this->getModuleProfileName( true ) );
2299  }
2300 
2304  public function profileDBOut() {
2305  if ( $this->mTimeIn === 0 ) {
2306  ApiBase::dieDebug( __METHOD__, 'Must be called while profiling ' .
2307  'the entire module with profileIn()' );
2308  }
2309  if ( $this->mDBTimeIn === 0 ) {
2310  ApiBase::dieDebug( __METHOD__, 'Called without calling profileDBIn() first' );
2311  }
2312 
2313  $time = microtime( true ) - $this->mDBTimeIn;
2314  $this->mDBTimeIn = 0;
2315 
2316  $this->mDBTime += $time;
2317  $this->getMain()->mDBTime += $time;
2318  wfProfileOut( $this->getModuleProfileName( true ) );
2319  }
2320 
2325  public function getProfileDBTime() {
2326  if ( $this->mDBTimeIn !== 0 ) {
2327  ApiBase::dieDebug( __METHOD__, 'Called without calling profileDBOut() first' );
2328  }
2329 
2330  return $this->mDBTime;
2331  }
2332 
2337  protected function getDB() {
2338  if ( !isset( $this->mSlaveDB ) ) {
2339  $this->profileDBIn();
2340  $this->mSlaveDB = wfGetDB( DB_SLAVE, 'api' );
2341  $this->profileDBOut();
2342  }
2343 
2344  return $this->mSlaveDB;
2345  }
2346 
2353  public static function debugPrint( $value, $name = 'unknown', $backtrace = false ) {
2354  print "\n\n<pre><b>Debugging value '$name':</b>\n\n";
2355  var_export( $value );
2356  if ( $backtrace ) {
2357  print "\n" . wfBacktrace();
2358  }
2359  print "\n</pre>\n";
2360  }
2361 }
ApiBase\createContext
createContext()
Create a new RequestContext object to use e.g.
Definition: ApiBase.php:232
ApiBase\dieUsageMsgOrDebug
dieUsageMsgOrDebug( $error)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
Definition: ApiBase.php:1969
ApiBase\makeHelpMsgParameters
makeHelpMsgParameters()
Generates the parameter descriptions for this module, to be displayed in the module's help.
Definition: ApiBase.php:411
ApiBase\dieStatus
dieStatus( $status)
Throw a UsageException based on the errors in the Status object.
Definition: ApiBase.php:1439
ApiBase\$mDBTimeIn
$mDBTimeIn
Profiling: database execution time.
Definition: ApiBase.php:2281
ApiBase\__construct
__construct( $mainModule, $moduleName, $modulePrefix='')
Constructor.
Definition: ApiBase.php:100
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
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:189
ContextSource\getContext
getContext()
Get the RequestContext object.
Definition: ContextSource.php:40
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
MWNamespace\getValidNamespaces
static getValidNamespaces()
Returns an array of the namespaces (by integer id) that exist on the wiki.
Definition: Namespace.php:273
ApiBase\getFinalParams
getFinalParams( $flags=0)
Get final list of parameters, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:609
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
Definition: ApiBase.php:62
Profiler\instance
static instance()
Singleton.
Definition: Profiler.php:127
ApiBase\getTokenSalt
getTokenSalt()
Returns the token salt if there is one, '' if the module doesn't require a salt, else false if the mo...
Definition: ApiBase.php:2084
ApiBase\$mModuleTime
$mModuleTime
Definition: ApiBase.php:2221
ApiBase\parseMsg
parseMsg( $error)
Return the error message related to a certain array.
Definition: ApiBase.php:2002
ApiBase\parameterNotEmpty
parameterNotEmpty( $x)
Callback function used in requireOnlyOneParameter to check whether required parameters are set.
Definition: ApiBase.php:921
ApiResult\setContent
static setContent(&$arr, $value, $subElemName=null)
Adds a content element to an array.
Definition: ApiResult.php:201
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3714
ApiBase\getProfileDBTime
getProfileDBTime()
Total time the module used the database.
Definition: ApiBase.php:2324
ApiBase\validateTimestamp
validateTimestamp( $value, $encParamName)
Validate and normalize of parameters of type 'timestamp'.
Definition: ApiBase.php:1311
ApiBase\dieUsageMsg
dieUsageMsg( $error)
Output the error message related to a certain array.
Definition: ApiBase.php:1953
ApiBase\indentExampleText
indentExampleText( $item)
Definition: ApiBase.php:374
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:2530
ApiBase\$mModulePrefix
$mModulePrefix
Definition: ApiBase.php:90
ApiBase\profileDBIn
profileDBIn()
Start module profiling.
Definition: ApiBase.php:2286
ApiBase\getTitleOrPageId
getTitleOrPageId( $params, $load=false)
Definition: ApiBase.php:873
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:50
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:205
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1530
ApiBase\profileDBOut
profileDBOut()
End database profiling.
Definition: ApiBase.php:2303
ApiBase\mustBePosted
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiBase.php:2062
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1358
ApiBase\shouldCheckMaxlag
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition: ApiBase.php:2038
$params
$params
Definition: styleTest.css.php:40
$limit
if( $sleep) $limit
Definition: importImages.php:99
wfMsgReplaceArgs
wfMsgReplaceArgs( $message, $args)
Replace message parameter keys on the given formatted output.
Definition: GlobalFunctions.php:1637
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:389
$s
$s
Definition: mergeMessageFileList.php:156
ApiBase\getDB
getDB()
Gets a default slave database connection object.
Definition: ApiBase.php:2336
ApiBase\$mSlaveDB
$mSlaveDB
Definition: ApiBase.php:91
ApiBase\makeHelpArrayToString
makeHelpArrayToString( $prefix, $title, $input)
Definition: ApiBase.php:384
ApiBase\PARAM_ALLOW_DUPLICATES
const PARAM_ALLOW_DUPLICATES
Definition: ApiBase.php:58
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2124
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:132
ApiBase\getModuleProfileName
getModuleProfileName( $db=false)
Get the name of the module as shown in the profiler log.
Definition: ApiBase.php:176
ApiBase\lacksSameOriginSecurity
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:360
ApiBase\$mModuleName
$mModuleName
Definition: ApiBase.php:90
ApiBase\isMain
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition: ApiBase.php:197
ApiBase\isReadMode
isReadMode()
Indicates whether this module requires read rights.
Definition: ApiBase.php:2046
ApiBase\$mDBTime
$mDBTime
Definition: ApiBase.php:2281
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:42
ApiBase\getFinalParamDescription
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:622
ApiBase\$mTimeIn
$mTimeIn
Profiling: total module execution time.
Definition: ApiBase.php:2221
ApiBase\$messageMap
static $messageMap
Array that maps message keys to error messages.
Definition: ApiBase.php:1449
ApiBase\getParamDescription
getParamDescription()
Returns an array of parameter descriptions.
Definition: ApiBase.php:597
wfBacktrace
wfBacktrace()
Get a debug backtrace as a string.
Definition: GlobalFunctions.php:1933
ApiBase\profileOut
profileOut()
End module profiling.
Definition: ApiBase.php:2237
ApiBase\PARAM_DEPRECATED
const PARAM_DEPRECATED
Definition: ApiBase.php:60
ApiBase\PROP_LIST
const PROP_LIST
Definition: ApiBase.php:73
ApiBase\PARAM_MIN
const PARAM_MIN
Definition: ApiBase.php:56
DerivativeContext
An IContextSource implementation which will inherit context from another source but allow individual ...
Definition: DerivativeContext.php:32
MWException
MediaWiki exception.
Definition: MWException.php:26
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:103
ApiBase\getFinalResultProperties
getFinalResultProperties()
Get final possible result properties, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:655
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1174
ApiBase\getFinalPossibleErrors
getFinalPossibleErrors()
Get final list of possible errors, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:2191
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:278
ApiBase\$mMainModule
$mMainModule
Definition: ApiBase.php:90
ApiBase\getFinalDescription
getFinalDescription()
Get final module description, after hooks have had a chance to tweak it as needed.
Definition: ApiBase.php:681
UsageException
This exception will be thrown when dieUsage is called to stop module execution.
Definition: ApiMain.php:1439
ApiBase\LIMIT_BIG1
const LIMIT_BIG1
Definition: ApiBase.php:78
ApiBase\getDescription
getDescription()
Returns the description string for this module.
Definition: ApiBase.php:561
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:30
WatchedItem\IGNORE_USER_RIGHTS
const IGNORE_USER_RIGHTS
Constant to specify that user rights 'editmywatchlist' and 'viewmywatchlist' should not be checked.
Definition: WatchedItem.php:35
ApiBase\getVersion
getVersion()
Returns a string that identifies the version of the extending class.
Definition: ApiBase.php:138
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
wfMessage
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
ApiBase\PARAM_MAX
const PARAM_MAX
Definition: ApiBase.php:52
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4066
WatchAction\doWatchOrUnwatch
static doWatchOrUnwatch( $watch, Title $title, User $user)
Watch or unwatch a page.
Definition: WatchAction.php:106
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
ApiBase\parseMultiValue
parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues)
Return an array of values that were given in a 'a|b|c' notation, after it optionally validates them a...
Definition: ApiBase.php:1209
ApiBase\getRequireOnlyOneParameterErrorMessages
getRequireOnlyOneParameterErrorMessages( $params)
Generates the possible errors requireOnlyOneParameter() can die with.
Definition: ApiBase.php:768
ContextSource\setContext
setContext(IContextSource $context)
Set the IContextSource object.
Definition: ContextSource.php:57
ApiBase\requireAtLeastOneParameter
requireAtLeastOneParameter( $params)
Die if none of a certain set of parameters is set and not false.
Definition: ApiBase.php:830
ApiBase\PROP_TYPE
const PROP_TYPE
Definition: ApiBase.php:74
ApiBase\getHelpUrls
getHelpUrls()
Definition: ApiBase.php:2124
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
ApiBase\validateUser
validateUser( $value, $encParamName)
Validate and normalize of parameters of type 'user'.
Definition: ApiBase.php:1329
ApiBase\getWatchlistValue
getWatchlistValue( $watchlist, $titleObj, $userOption=null)
Return true if we're to watch the page, false if not, null if no change.
Definition: ApiBase.php:933
ApiBase\needsToken
needsToken()
Returns whether this module requires a token to execute It is used to show possible errors in action=...
Definition: ApiBase.php:2072
ApiBase\getModulePrefix
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition: ApiBase.php:165
ApiBase\setWatch
setWatch( $watch, $titleObj, $userOption=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
Definition: ApiBase.php:972
TS_MW
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition: GlobalFunctions.php:2478
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:422
ApiBase\extractRequestParams
extractRequestParams( $parseLimit=true)
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:707
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
ApiBase\getWatchlistUser
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition: ApiBase.php:2094
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
$value
$value
Definition: styleTest.css.php:45
ApiBase\dieContinueUsageIf
dieContinueUsageIf( $condition)
Die with the $prefix.
Definition: ApiBase.php:1989
ApiBase\LIMIT_SML2
const LIMIT_SML2
Definition: ApiBase.php:81
ApiBase\encodeParamName
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:694
ApiBase\dieUsage
dieUsage( $description, $errorCode, $httpRespCode=0, $extradata=null)
Throw a UsageException, which will (if uncaught) call the main module's error handler and die with an...
Definition: ApiBase.php:1383
ApiBase\dieReadOnly
dieReadOnly()
Helper function for readonly errors.
Definition: ApiBase.php:1943
ApiBase\requireOnlyOneParameter
requireOnlyOneParameter( $params)
Die if none or more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:742
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:88
ApiBase\getResultData
getResultData()
Get the result data array (read-only)
Definition: ApiBase.php:219
ApiBase\addTokenProperties
static addTokenProperties(&$props, $tokenFunctions)
Add token properties to the array used by getResultProperties, based on a token functions mapping.
Definition: ApiBase.php:666
WikiPage\newFromID
static newFromID( $id, $from='fromdb')
Constructor from a page id.
Definition: WikiPage.php:136
ApiBase\getPossibleErrors
getPossibleErrors()
Returns a list of all possible errors returned by the module.
Definition: ApiBase.php:2137
ApiBase\isWriteMode
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiBase.php:2054
ApiBase\PROP_NULLABLE
const PROP_NULLABLE
Definition: ApiBase.php:76
ApiBase\getResultProperties
getResultProperties()
Returns possible properties in the result, grouped by the value of the prop parameter that shows them...
Definition: ApiBase.php:645
ApiBase\$mParamCache
$mParamCache
Definition: ApiBase.php:92
ApiBase\truncateArray
static truncateArray(&$arr, $limit)
Truncate an array to a certain length.
Definition: ApiBase.php:1361
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
ApiBase\profileIn
profileIn()
Start module profiling.
Definition: ApiBase.php:2226
ApiBase\PARAM_RANGE_ENFORCE
const PARAM_RANGE_ENFORCE
Definition: ApiBase.php:66
ApiBase\setWarning
setWarning( $warning)
Set warning section for this module.
Definition: ApiBase.php:245
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
ApiBase\getProfileTime
getProfileTime()
Total time the module was executed.
Definition: ApiBase.php:2270
ApiResult\ADD_ON_TOP
const ADD_ON_TOP
For addValue() and setElement(), if the value does not exist, add it as the first element.
Definition: ApiResult.php:57
ApiBase\getErrorFromStatus
getErrorFromStatus( $status)
Get error (as code, string) from a Status object.
Definition: ApiBase.php:1400
ApiBase\LIMIT_BIG2
const LIMIT_BIG2
Definition: ApiBase.php:79
wfReadOnlyReason
wfReadOnlyReason()
Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
Definition: GlobalFunctions.php:1369
ApiBase\getModuleManager
getModuleManager()
Get the module manager, or null if this module has no sub-modules.
Definition: ApiBase.php:157
TS_UNIX
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
Definition: GlobalFunctions.php:2473
ApiBase\validateLimit
validateLimit( $paramName, &$value, $min, $max, $botMax=null, $enforceLimits=false)
Validate the value against the minimum and user/bot maximum limits.
Definition: ApiBase.php:1273
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:46
ApiBase\getParameter
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition: ApiBase.php:731
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
ApiBase\safeProfileOut
safeProfileOut()
When modules crash, sometimes it is needed to do a profileOut() regardless of the profiling state the...
Definition: ApiBase.php:2257
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:148
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:48
ApiBase\warnOrDie
warnOrDie( $msg, $enforceLimits=false)
Adds a warning to the output, else dies.
Definition: ApiBase.php:1347
NS_USER
const NS_USER
Definition: Defines.php:81
ApiResult\OVERRIDE
const OVERRIDE
override existing value in addValue() and setElement()
Definition: ApiResult.php:50
ApiBase\PARAM_MAX2
const PARAM_MAX2
Definition: ApiBase.php:54
ApiBase\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiBase.php:585
ApiBase\debugPrint
static debugPrint( $value, $name='unknown', $backtrace=false)
Debugging function that prints a value and an optional backtrace.
Definition: ApiBase.php:2352
ApiBase\makeHelpMsg
makeHelpMsg()
Generates help message for this module, or false if there is no description.
Definition: ApiBase.php:286
ApiBase\getMain
getMain()
Get the main module.
Definition: ApiBase.php:188
ApiBase\getParameterFromSettings
getParameterFromSettings( $paramName, $paramSettings, $parseLimit)
Using the settings determine the value for the given parameter.
Definition: ApiBase.php:990
$t
$t
Definition: testCompression.php:65
ApiBase\getExamples
getExamples()
Returns usage examples for this module.
Definition: ApiBase.php:569
$error
usually copyright or history_copyright This message must be in HTML not wikitext $subpages will be ignored and the rest of subPageSubtitle() will run. 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink' whether MediaWiki currently thinks this is a CSS JS page Hooks may change this value to override the return value of Title::isCssOrJsPage(). 'TitleIsAlwaysKnown' whether MediaWiki currently thinks this page is known isMovable() always returns false. $title whether MediaWiki currently thinks this page is movable Hooks may change this value to override the return value of Title::isMovable(). 'TitleIsWikitextPage' whether MediaWiki currently thinks this is a wikitext page Hooks may change this value to override the return value of Title::isWikitextPage() 'TitleMove' use UploadVerification and UploadVerifyFile instead where the first element is the message key and the remaining elements are used as parameters to the message based on mime etc Preferred in most cases over UploadVerification object with all info about the upload string as detected by MediaWiki Handlers will typically only apply for specific mime types object & $error
Definition: hooks.txt:2584
ApiBase\getRequireMaxOneParameterErrorMessages
getRequireMaxOneParameterErrorMessages( $params)
Generates the possible error requireMaxOneParameter() can die with.
Definition: ApiBase.php:811
ApiBase\requireMaxOneParameter
requireMaxOneParameter( $params)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:789
ApiBase\parseErrors
parseErrors( $errors)
Parses a list of errors into a standardised format.
Definition: ApiBase.php:2204
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:2030
ApiBase\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
ApiBase\PROP_ROOT
const PROP_ROOT
Definition: ApiBase.php:70
ApiBase\LIMIT_SML1
const LIMIT_SML1
Definition: ApiBase.php:80
ApiBase\getRequireAtLeastOneParameterErrorMessages
getRequireAtLeastOneParameterErrorMessages( $params)
Generates the possible errors requireAtLeastOneParameter() can die with.
Definition: ApiBase.php:853
$type
$type
Definition: testCompression.php:46
ApiBase\getTitleOrPageIdErrorMessage
getTitleOrPageIdErrorMessage()
Definition: ApiBase.php:905