2006-10-01 04:38:31 +00:00
< ? php
/*
* Created on Sep 5 , 2006
*
* API for MediaWiki 1.8 +
*
2007-05-20 23:31:44 +00:00
* Copyright ( C ) 2006 Yuri Astrakhan < Firstname >< Lastname >@ gmail . com
2006-10-01 04:38:31 +00:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
* http :// www . gnu . org / copyleft / gpl . html
*/
2007-04-04 05:22:37 +00:00
/**
2007-05-19 06:42:08 +00:00
* This abstract class implements many basic API functions , and is the base of all API classes .
* The class functions are divided into several areas of functionality :
*
* Module parameters : Derived classes can define getAllowedParams () to specify which parameters to expect ,
* how to parse and validate them .
*
* Profiling : various methods to allow keeping tabs on various tasks and their time costs
*
* Self - documentation : code to allow api to document its own state .
*
2007-04-20 08:55:14 +00:00
* @ addtogroup API
2007-04-04 05:22:37 +00:00
*/
2006-10-01 04:38:31 +00:00
abstract class ApiBase {
// These constants allow modules to specify exactly how to treat incomming parameters.
const PARAM_DFLT = 0 ;
const PARAM_ISMULTI = 1 ;
const PARAM_TYPE = 2 ;
2007-05-19 18:08:36 +00:00
const PARAM_MAX = 3 ;
2006-10-01 04:38:31 +00:00
const PARAM_MAX2 = 4 ;
const PARAM_MIN = 5 ;
2007-05-22 04:39:49 +00:00
const LIMIT_BIG1 = 500 ; // Fast query, std user limit
const LIMIT_BIG2 = 5000 ; // Fast query, bot/sysop limit
const LIMIT_SML1 = 50 ; // Slow query, std user limit
const LIMIT_SML2 = 500 ; // Slow query, bot/sysop limit
2006-10-17 02:01:20 +00:00
2007-07-07 03:05:09 +00:00
private $mMainModule , $mModuleName , $mModulePrefix ;
2006-10-01 04:38:31 +00:00
/**
* Constructor
*/
2007-07-07 03:05:09 +00:00
public function __construct ( $mainModule , $moduleName , $modulePrefix = '' ) {
2006-10-01 04:38:31 +00:00
$this -> mMainModule = $mainModule ;
2006-10-17 02:01:20 +00:00
$this -> mModuleName = $moduleName ;
2007-07-07 03:05:09 +00:00
$this -> mModulePrefix = $modulePrefix ;
2006-10-01 04:38:31 +00:00
}
2008-01-12 07:08:17 +00:00
/*****************************************************************************
* ABSTRACT METHODS *
*****************************************************************************/
/**
* Evaluates the parameters , performs the requested query , and sets up the
* result . Concrete implementations of ApiBase must override this method to
* provide whatever functionality their module offers . Implementations must
* not produce any output on their own and are not expected to handle any
* errors .
*
* The execute method will be invoked directly by ApiMain immediately before
* the result of the module is output . Aside from the constructor , implementations
* should assume that no other methods will be called externally on the module
* before the result is processed .
*
* The result data should be stored in the result object referred to by
* " getResult() " . Refer to ApiResult . php for details on populating a result
* object .
2006-10-01 04:38:31 +00:00
*/
2006-10-01 21:20:55 +00:00
public abstract function execute ();
2006-10-01 04:38:31 +00:00
2008-01-12 07:08:17 +00:00
/**
* Returns a String that identifies the version of the extending class . Typically
* includes the class name , the svn revision , timestamp , and last author . May
* be severely incorrect in many implementations !
*/
public abstract function getVersion ();
2006-10-17 02:01:20 +00:00
/**
* Get the name of the module being executed by this instance
*/
public function getModuleName () {
return $this -> mModuleName ;
}
2007-05-21 06:32:32 +00:00
/**
* Get parameter prefix ( usually two letters or an empty string ) .
*/
2007-07-07 03:05:09 +00:00
public function getModulePrefix () {
return $this -> mModulePrefix ;
2007-05-21 06:32:32 +00:00
}
2006-10-17 02:01:20 +00:00
/**
* Get the name of the module as shown in the profiler log
*/
public function getModuleProfileName ( $db = false ) {
if ( $db )
return 'API:' . $this -> mModuleName . '-DB' ;
else
return 'API:' . $this -> mModuleName ;
}
2006-10-16 23:25:51 +00:00
2006-10-01 04:38:31 +00:00
/**
* Get main module
*/
public function getMain () {
return $this -> mMainModule ;
}
/**
2008-01-12 07:08:17 +00:00
* Returns true if this module is the main module ( $this === $this -> mMainModule ),
* false otherwise .
2006-10-01 04:38:31 +00:00
*/
public function isMain () {
return $this === $this -> mMainModule ;
}
/**
2008-01-12 07:08:17 +00:00
* Get the result object . Please refer to the documentation in ApiResult . php
* for details on populating and accessing data in a result object .
2006-10-01 04:38:31 +00:00
*/
public function getResult () {
// Main module has getResult() method overriden
// Safety - avoid infinite loop:
if ( $this -> isMain ())
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'base method was called on main module. ' );
2006-10-01 04:38:31 +00:00
return $this -> getMain () -> getResult ();
}
/**
* Get the result data array
*/
public function & getResultData () {
return $this -> getResult () -> getData ();
}
2007-07-06 07:16:38 +00:00
/**
2008-01-12 07:08:17 +00:00
* Set warning section for this module . Users should monitor this section to
* notice any changes in API .
2007-07-06 07:16:38 +00:00
*/
public function setWarning ( $warning ) {
$msg = array ();
ApiResult :: setContent ( $msg , $warning );
$this -> getResult () -> addValue ( 'warnings' , $this -> getModuleName (), $msg );
}
2006-10-15 07:43:52 +00:00
/**
* If the module may only be used with a certain format module ,
* it should override this method to return an instance of that formatter .
* A value of null means the default format will be used .
*/
2006-10-16 00:08:03 +00:00
public function getCustomPrinter () {
2006-10-15 07:43:52 +00:00
return null ;
}
2006-10-01 04:38:31 +00:00
/**
* Generates help message for this module , or false if there is no description
*/
public function makeHelpMsg () {
static $lnPrfx = " \n " ;
$msg = $this -> getDescription ();
if ( $msg !== false ) {
if ( ! is_array ( $msg ))
$msg = array (
$msg
);
$msg = $lnPrfx . implode ( $lnPrfx , $msg ) . " \n " ;
// Parameters
$paramsMsg = $this -> makeHelpMsgParameters ();
if ( $paramsMsg !== false ) {
$msg .= " Parameters: \n $paramsMsg " ;
}
// Examples
$examples = $this -> getExamples ();
if ( $examples !== false ) {
if ( ! is_array ( $examples ))
$examples = array (
$examples
);
$msg .= 'Example' . ( count ( $examples ) > 1 ? 's' : '' ) . " : \n " ;
$msg .= implode ( $lnPrfx , $examples ) . " \n " ;
}
2006-10-01 21:20:55 +00:00
if ( $this -> getMain () -> getShowVersions ()) {
$versions = $this -> getVersion ();
2006-11-04 05:24:59 +00:00
$pattern = '(\$.*) ([0-9a-z_]+\.php) (.*\$)' ;
$replacement = '\\0' . " \n " . 'http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/api/\\2' ;
if ( is_array ( $versions )) {
foreach ( $versions as & $v )
$v = eregi_replace ( $pattern , $replacement , $v );
2006-10-01 21:20:55 +00:00
$versions = implode ( " \n " , $versions );
2006-11-04 05:24:59 +00:00
}
else
$versions = eregi_replace ( $pattern , $replacement , $versions );
2006-10-01 21:20:55 +00:00
$msg .= " Version: \n $versions\n " ;
}
2006-10-01 04:38:31 +00:00
}
return $msg ;
}
2008-01-12 07:08:17 +00:00
/**
* Generates the parameter descriptions for this module , to be displayed in the
* module ' s help .
*/
2006-10-01 04:38:31 +00:00
public function makeHelpMsgParameters () {
$params = $this -> getAllowedParams ();
if ( $params !== false ) {
$paramsDescription = $this -> getParamDescription ();
$msg = '' ;
2006-10-16 00:08:03 +00:00
$paramPrefix = " \n " . str_repeat ( ' ' , 19 );
2006-10-18 05:27:43 +00:00
foreach ( $params as $paramName => $paramSettings ) {
2006-10-01 04:38:31 +00:00
$desc = isset ( $paramsDescription [ $paramName ]) ? $paramsDescription [ $paramName ] : '' ;
if ( is_array ( $desc ))
2006-10-16 00:08:03 +00:00
$desc = implode ( $paramPrefix , $desc );
2006-10-30 00:18:05 +00:00
2008-01-12 07:08:17 +00:00
$type = $paramSettings [ self :: PARAM_TYPE ];
2006-11-03 06:53:47 +00:00
if ( isset ( $type )) {
2006-10-30 00:18:05 +00:00
if ( isset ( $paramSettings [ self :: PARAM_ISMULTI ]))
2006-11-03 06:53:47 +00:00
$prompt = 'Values (separate with \'|\'): ' ;
2006-10-30 00:18:05 +00:00
else
2006-11-03 06:53:47 +00:00
$prompt = 'One value: ' ;
if ( is_array ( $type )) {
2007-05-20 23:31:44 +00:00
$choices = array ();
$nothingPrompt = false ;
foreach ( $type as $t )
if ( $t == '' )
$nothingPrompt = 'Can be empty, or ' ;
else
$choices [] = $t ;
$desc .= $paramPrefix . $nothingPrompt . $prompt . implode ( ', ' , $choices );
2007-05-19 18:08:36 +00:00
} else {
switch ( $type ) {
case 'namespace' :
// Special handling because namespaces are type-limited, yet they are not given
$desc .= $paramPrefix . $prompt . implode ( ', ' , ApiBase :: getValidNamespaces ());
break ;
case 'limit' :
$desc .= $paramPrefix . " No more than { $paramSettings [ self :: PARAM_MAX ] } ( { $paramSettings [ self :: PARAM_MAX2 ] } for bots) allowed. " ;
break ;
case 'integer' :
$hasMin = isset ( $paramSettings [ self :: PARAM_MIN ]);
$hasMax = isset ( $paramSettings [ self :: PARAM_MAX ]);
if ( $hasMin || $hasMax ) {
if ( ! $hasMax )
$intRangeStr = " The value must be no less than { $paramSettings [ self :: PARAM_MIN ] } " ;
elseif ( ! $hasMin )
$intRangeStr = " The value must be no more than { $paramSettings [ self :: PARAM_MAX ] } " ;
else
$intRangeStr = " The value must be between { $paramSettings [ self :: PARAM_MIN ] } and { $paramSettings [ self :: PARAM_MAX ] } " ;
$desc .= $paramPrefix . $intRangeStr ;
}
break ;
}
2006-11-03 06:53:47 +00:00
}
2006-10-16 00:08:03 +00:00
}
2006-10-30 00:18:05 +00:00
2006-10-17 02:01:20 +00:00
$default = is_array ( $paramSettings ) ? ( isset ( $paramSettings [ self :: PARAM_DFLT ]) ? $paramSettings [ self :: PARAM_DFLT ] : null ) : $paramSettings ;
2006-10-16 00:08:03 +00:00
if ( ! is_null ( $default ) && $default !== false )
$desc .= $paramPrefix . " Default: $default " ;
2006-10-17 02:01:20 +00:00
2006-10-03 05:41:55 +00:00
$msg .= sprintf ( " %-14s - %s \n " , $this -> encodeParamName ( $paramName ), $desc );
2006-10-01 04:38:31 +00:00
}
return $msg ;
} else
return false ;
}
/**
* Returns the description string for this module
*/
protected function getDescription () {
return false ;
}
/**
* Returns usage examples for this module . Return null if no examples are available .
*/
protected function getExamples () {
return false ;
}
/**
* Returns an array of allowed parameters ( keys ) => default value for that parameter
*/
protected function getAllowedParams () {
return false ;
}
/**
* Returns the description string for the given parameter .
*/
protected function getParamDescription () {
return false ;
}
2006-10-17 02:01:20 +00:00
2006-10-03 05:41:55 +00:00
/**
* This method mangles parameter name based on the prefix supplied to the constructor .
* Override this method to change parameter name during runtime
*/
public function encodeParamName ( $paramName ) {
2007-07-07 03:05:09 +00:00
return $this -> mModulePrefix . $paramName ;
2006-10-03 05:41:55 +00:00
}
2006-10-01 04:38:31 +00:00
/**
* Using getAllowedParams (), makes an array of the values provided by the user ,
* with key being the name of the variable , and value - validated value from user or default .
* This method can be used to generate local variables using extract () .
2008-01-05 10:05:34 +00:00
* limit = max will not be parsed if $parseMaxLimit is set to false ; use this
* when the max limit is not definite , e . g . when getting revisions .
2006-10-01 04:38:31 +00:00
*/
2008-01-05 10:05:34 +00:00
public function extractRequestParams ( $parseMaxLimit = true ) {
2006-10-01 04:38:31 +00:00
$params = $this -> getAllowedParams ();
$results = array ();
foreach ( $params as $paramName => $paramSettings )
2008-01-05 10:05:34 +00:00
$results [ $paramName ] = $this -> getParameterFromSettings ( $paramName , $paramSettings , $parseMaxLimit );
2006-10-01 04:38:31 +00:00
return $results ;
}
2006-10-03 05:41:55 +00:00
/**
* Get a value for the given parameter
*/
protected function getParameter ( $paramName ) {
2006-10-02 23:56:19 +00:00
$params = $this -> getAllowedParams ();
$paramSettings = $params [ $paramName ];
2006-10-03 05:41:55 +00:00
return $this -> getParameterFromSettings ( $paramName , $paramSettings );
2006-10-02 23:56:19 +00:00
}
2006-10-03 05:41:55 +00:00
2008-01-12 07:08:17 +00:00
/**
* Returns an array of the namespaces ( by integer id ) that exist on the
* wiki . Used primarily in help documentation .
*/
2006-11-03 06:53:47 +00:00
public static function getValidNamespaces () {
static $mValidNamespaces = null ;
if ( is_null ( $mValidNamespaces )) {
global $wgContLang ;
$mValidNamespaces = array ();
foreach ( array_keys ( $wgContLang -> getNamespaces ()) as $ns ) {
if ( $ns >= 0 )
$mValidNamespaces [] = $ns ;
}
}
return $mValidNamespaces ;
}
2006-10-03 05:41:55 +00:00
/**
* Using the settings determine the value for the given parameter
2008-01-12 07:08:17 +00:00
*
2006-10-03 05:41:55 +00:00
* @ param $paramName String : parameter name
* @ param $paramSettings Mixed : default value or an array of settings using PARAM_ * constants .
2008-01-05 10:05:34 +00:00
* @ param $parseMaxLimit Boolean : parse limit when max is given ?
2006-10-17 02:01:20 +00:00
*/
2008-01-05 10:05:34 +00:00
protected function getParameterFromSettings ( $paramName , $paramSettings , $parseMaxLimit ) {
2006-10-01 04:38:31 +00:00
2006-10-03 05:41:55 +00:00
// Some classes may decide to change parameter names
2007-06-25 05:44:33 +00:00
$encParamName = $this -> encodeParamName ( $paramName );
2006-10-03 05:41:55 +00:00
2006-10-01 04:38:31 +00:00
if ( ! is_array ( $paramSettings )) {
$default = $paramSettings ;
$multi = false ;
$type = gettype ( $paramSettings );
} else {
2006-10-01 20:17:16 +00:00
$default = isset ( $paramSettings [ self :: PARAM_DFLT ]) ? $paramSettings [ self :: PARAM_DFLT ] : null ;
$multi = isset ( $paramSettings [ self :: PARAM_ISMULTI ]) ? $paramSettings [ self :: PARAM_ISMULTI ] : false ;
$type = isset ( $paramSettings [ self :: PARAM_TYPE ]) ? $paramSettings [ self :: PARAM_TYPE ] : null ;
2006-10-01 04:38:31 +00:00
// When type is not given, and no choices, the type is the same as $default
if ( ! isset ( $type )) {
if ( isset ( $default ))
$type = gettype ( $default );
else
$type = 'NULL' ; // allow everything
}
}
if ( $type == 'boolean' ) {
if ( isset ( $default ) && $default !== false ) {
// Having a default value of anything other than 'false' is pointless
2007-06-25 05:44:33 +00:00
ApiBase :: dieDebug ( __METHOD__ , " Boolean param $encParamName 's default is set to ' $default ' " );
2006-10-01 04:38:31 +00:00
}
2007-06-25 05:44:33 +00:00
$value = $this -> getMain () -> getRequest () -> getCheck ( $encParamName );
2006-10-14 07:18:08 +00:00
} else {
2007-06-25 05:44:33 +00:00
$value = $this -> getMain () -> getRequest () -> getVal ( $encParamName , $default );
2006-11-03 06:53:47 +00:00
if ( isset ( $value ) && $type == 'namespace' )
$type = ApiBase :: getValidNamespaces ();
2006-10-14 07:18:08 +00:00
}
2006-10-17 02:01:20 +00:00
2006-10-01 04:38:31 +00:00
if ( isset ( $value ) && ( $multi || is_array ( $type )))
2007-06-25 05:44:33 +00:00
$value = $this -> parseMultiValue ( $encParamName , $value , $multi , is_array ( $type ) ? $type : null );
2006-10-01 04:38:31 +00:00
// More validation only when choices were not given
// choices were validated in parseMultiValue()
2006-10-21 08:26:32 +00:00
if ( isset ( $value )) {
if ( ! is_array ( $type )) {
switch ( $type ) {
case 'NULL' : // nothing to do
break ;
case 'string' : // nothing to do
break ;
2007-05-19 18:08:36 +00:00
case 'integer' : // Force everything using intval() and optionally validate limits
2006-10-21 08:26:32 +00:00
$value = is_array ( $value ) ? array_map ( 'intval' , $value ) : intval ( $value );
2007-06-25 05:44:33 +00:00
$min = isset ( $paramSettings [ self :: PARAM_MIN ]) ? $paramSettings [ self :: PARAM_MIN ] : null ;
$max = isset ( $paramSettings [ self :: PARAM_MAX ]) ? $paramSettings [ self :: PARAM_MAX ] : null ;
2007-05-20 10:08:40 +00:00
2007-06-25 05:44:33 +00:00
if ( ! is_null ( $min ) || ! is_null ( $max )) {
2007-05-19 18:08:36 +00:00
$values = is_array ( $value ) ? $value : array ( $value );
foreach ( $values as $v ) {
2007-06-25 05:44:33 +00:00
$this -> validateLimit ( $paramName , $v , $min , $max );
2007-05-19 18:08:36 +00:00
}
}
2006-10-21 08:26:32 +00:00
break ;
case 'limit' :
2007-05-19 18:08:36 +00:00
if ( ! isset ( $paramSettings [ self :: PARAM_MAX ]) || ! isset ( $paramSettings [ self :: PARAM_MAX2 ]))
2007-06-25 05:44:33 +00:00
ApiBase :: dieDebug ( __METHOD__ , " MAX1 or MAX2 are not defined for the limit $encParamName " );
2006-10-21 08:26:32 +00:00
if ( $multi )
2007-06-25 05:44:33 +00:00
ApiBase :: dieDebug ( __METHOD__ , " Multi-values not supported for $encParamName " );
2006-10-21 08:26:32 +00:00
$min = isset ( $paramSettings [ self :: PARAM_MIN ]) ? $paramSettings [ self :: PARAM_MIN ] : 0 ;
2007-11-29 15:19:56 +00:00
if ( $value == 'max' ) {
2008-01-05 10:05:34 +00:00
if ( $parseMaxLimit ) {
$value = $this -> getMain () -> canApiHighLimits () ? $paramSettings [ self :: PARAM_MAX2 ] : $paramSettings [ self :: PARAM_MAX ];
$this -> getResult () -> addValue ( 'limits' , 'limit' , $value );
$this -> validateLimit ( $paramName , $value , $min , $paramSettings [ self :: PARAM_MAX ], $paramSettings [ self :: PARAM_MAX2 ]);
}
2007-11-29 15:19:56 +00:00
}
else {
$value = intval ( $value );
2008-01-05 10:05:34 +00:00
$this -> validateLimit ( $paramName , $value , $min , $paramSettings [ self :: PARAM_MAX ], $paramSettings [ self :: PARAM_MAX2 ]);
2007-11-29 15:19:56 +00:00
}
2006-10-21 08:26:32 +00:00
break ;
case 'boolean' :
if ( $multi )
2007-06-25 05:44:33 +00:00
ApiBase :: dieDebug ( __METHOD__ , " Multi-values not supported for $encParamName " );
2006-10-21 08:26:32 +00:00
break ;
case 'timestamp' :
if ( $multi )
2007-06-25 05:44:33 +00:00
ApiBase :: dieDebug ( __METHOD__ , " Multi-values not supported for $encParamName " );
2006-10-21 08:26:32 +00:00
$value = wfTimestamp ( TS_UNIX , $value );
if ( $value === 0 )
2007-06-25 05:44:33 +00:00
$this -> dieUsage ( " Invalid value ' $value ' for timestamp parameter $encParamName " , " badtimestamp_ { $encParamName } " );
2006-10-21 08:26:32 +00:00
$value = wfTimestamp ( TS_MW , $value );
break ;
2007-05-19 04:13:48 +00:00
case 'user' :
$title = Title :: makeTitleSafe ( NS_USER , $value );
if ( is_null ( $title ) )
2007-08-20 08:04:12 +00:00
$this -> dieUsage ( " Invalid value for user parameter $encParamName " , " baduser_ { $encParamName } " );
2007-05-19 04:13:48 +00:00
$value = $title -> getText ();
break ;
2006-10-21 08:26:32 +00:00
default :
2007-06-25 05:44:33 +00:00
ApiBase :: dieDebug ( __METHOD__ , " Param $encParamName 's type is unknown - $type " );
2006-10-21 08:26:32 +00:00
}
2006-10-01 04:38:31 +00:00
}
2006-10-21 08:26:32 +00:00
// There should never be any duplicate values in a list
if ( is_array ( $value ))
$value = array_unique ( $value );
}
2006-10-17 02:01:20 +00:00
2006-10-01 04:38:31 +00:00
return $value ;
}
/**
* Return an array of values that were given in a 'a|b|c' notation ,
* after it optionally validates them against the list allowed values .
*
* @ param valueName - The name of the parameter ( for error reporting )
* @ param value - The value being parsed
* @ param allowMultiple - Can $value contain more than one value separated by '|' ?
* @ param allowedValues - An array of values to check against . If null , all values are accepted .
* @ return ( allowMultiple ? an_array_of_values : a_single_value )
*/
protected function parseMultiValue ( $valueName , $value , $allowMultiple , $allowedValues ) {
$valuesList = explode ( '|' , $value );
if ( ! $allowMultiple && count ( $valuesList ) != 1 ) {
$possibleValues = is_array ( $allowedValues ) ? " of ' " . implode ( " ', ' " , $allowedValues ) . " ' " : '' ;
$this -> dieUsage ( " Only one $possibleValues is allowed for parameter ' $valueName ' " , " multival_ $valueName " );
}
if ( is_array ( $allowedValues )) {
$unknownValues = array_diff ( $valuesList , $allowedValues );
if ( $unknownValues ) {
2006-10-19 08:18:19 +00:00
$this -> dieUsage ( 'Unrecognised value' . ( count ( $unknownValues ) > 1 ? " s " : " " ) . " for parameter ' $valueName ' " , " unknown_ $valueName " );
2006-10-01 04:38:31 +00:00
}
}
return $allowMultiple ? $valuesList : $valuesList [ 0 ];
}
/**
* Validate the value against the minimum and user / bot maximum limits . Prints usage info on failure .
*/
2007-06-25 05:44:33 +00:00
function validateLimit ( $paramName , $value , $min , $max , $botMax = null ) {
if ( ! is_null ( $min ) && $value < $min ) {
$this -> dieUsage ( $this -> encodeParamName ( $paramName ) . " may not be less than $min (set to $value ) " , $paramName );
2006-10-01 04:38:31 +00:00
}
2007-07-15 00:52:35 +00:00
// Minimum is always validated, whereas maximum is checked only if not running in internal call mode
if ( $this -> getMain () -> isInternalMode ())
return ;
2007-06-25 05:44:33 +00:00
// Optimization: do not check user's bot status unless really needed -- skips db query
// assumes $botMax >= $max
if ( ! is_null ( $max ) && $value > $max ) {
2007-11-29 15:19:56 +00:00
if ( ! is_null ( $botMax ) && $this -> getMain () -> canApiHighLimits ()) {
2007-06-25 05:44:33 +00:00
if ( $value > $botMax ) {
$this -> dieUsage ( $this -> encodeParamName ( $paramName ) . " may not be over $botMax (set to $value ) for bots or sysops " , $paramName );
}
} else {
$this -> dieUsage ( $this -> encodeParamName ( $paramName ) . " may not be over $max (set to $value ) for users " , $paramName );
2006-10-01 04:38:31 +00:00
}
2006-10-01 20:17:16 +00:00
}
2006-10-01 04:38:31 +00:00
}
/**
* Call main module ' s error handler
*/
public function dieUsage ( $description , $errorCode , $httpRespCode = 0 ) {
2006-10-14 07:18:08 +00:00
throw new UsageException ( $description , $this -> encodeParamName ( $errorCode ), $httpRespCode );
2006-10-01 04:38:31 +00:00
}
2008-01-15 20:21:16 +00:00
/**
* Array that maps message keys to error messages . $ 1 and friends are replaced .
*/
public static $messageMap = array (
2008-01-18 14:34:14 +00:00
// This one MUST be present, or dieUsageMsg() will recurse infinitely
'unknownerror' => array ( 'code' => 'unknownerror' , 'info' => " Unknown error: `` \$ 1'' " ),
// Messages from Title::getUserPermissionsErrors()
2008-01-15 20:21:16 +00:00
'ns-specialprotected' => array ( 'code' => 'unsupportednamespace' , 'info' => " Pages in the Special namespace can't be edited " ),
'protectedinterface' => array ( 'code' => 'protectednamespace-interface' , 'info' => " You're not allowed to edit interface messages " ),
'namespaceprotected' => array ( 'code' => 'protectednamespace' , 'info' => " You're not allowed to edit pages in the `` \$ 1'' namespace " ),
'customcssjsprotected' => array ( 'code' => 'customcssjsprotected' , 'info' => " You're not allowed to edit custom CSS and JavaScript pages " ),
'cascadeprotected' => array ( 'code' => 'cascadeprotected' , 'info' => " The page you're trying to edit is protected because it's included in a cascade-protected page " ),
'protectedpagetext' => array ( 'code' => 'protectedpage' , 'info' => " The `` \$ 1'' right is required to edit this page " ),
'protect-cantedit' => array ( 'code' => 'cantedit' , 'info' => " You can't protect this page because you can't edit it " ),
'badaccess-group0' => array ( 'code' => 'permissiondenied' , 'info' => " Permission denied " ), // Generic permission denied message
'badaccess-group1' => array ( 'code' => 'permissiondenied' , 'info' => " Permission denied " ), // Can't use the parameter 'cause it's wikilinked
'badaccess-group2' => array ( 'code' => 'permissiondenied' , 'info' => " Permission denied " ),
'badaccess-groups' => array ( 'code' => 'permissiondenied' , 'info' => " Permission denied " ),
'titleprotected' => array ( 'code' => 'protectedtitle' , 'info' => " This title has been protected from creation " ),
'nocreate-loggedin' => array ( 'code' => 'cantcreate' , 'info' => " You don't have permission to create new pages " ),
'nocreatetext' => array ( 'code' => 'cantcreate-anon' , 'info' => " Anonymous users can't create new pages " ),
'movenologintext' => array ( 'code' => 'cantmove-anon' , 'info' => " Anonymous users can't move pages " ),
2008-01-18 14:34:14 +00:00
'movenotallowed' => array ( 'code' => 'cantmove' , 'info' => " You don't have permission to move pages " ),
2008-01-18 15:52:40 +00:00
'confirmedittiext' => array ( 'code' => 'confirmemail' , 'info' => " You must confirm your e-mail address before you can edit " ),
'blockedtext' => array ( 'code' => 'blocked' , 'info' => " You have been blocked from editing " ),
'autoblockedtext' => array ( 'code' => 'autoblocked' , 'info' => " Your IP address has been blocked automatically, because it was used by a blocked user " ),
2008-01-18 14:34:14 +00:00
// Miscellaneous interface messages
'alreadyrolled' => array ( 'code' => 'alreadyrolled' , 'info' => " The page you tried to rollback was already rolled back " ),
'cantrollback' => array ( 'code' => 'onlyauthor' , 'info' => " The page you tried to rollback only has one author " ),
'readonlytext' => array ( 'code' => 'readonly' , 'info' => " The wiki is currently in read-only mode " ),
'sessionfailure' => array ( 'code' => 'badtoken' , 'info' => " Invalid token " ),
'cannotdelete' => array ( 'code' => 'cantdelete' , 'info' => " Couldn't delete `` \$ 1''. Maybe it was deleted already by someone else " ),
'notanarticle' => array ( 'code' => 'missingtitle' , 'info' => " The page you requested doesn't exist " ),
2008-01-18 15:52:40 +00:00
'selfmove' => array ( 'code' => 'selfmove' , 'info' => " Can't move a page to itself " ),
'immobile_namespace' => array ( 'code' => 'immobilenamespace' , 'info' => " You tried to move pages from or to a namespace that is protected from moving " ),
'articleexists' => array ( 'code' => 'articleexists' , 'info' => " The destination article already exists and is not a redirect to the source article " ),
'protectedpage' => array ( 'code' => 'protectedpage' , 'info' => " You don't have permission to perform this move " ),
'hookaborted' => array ( 'code' => 'hookaborted' , 'info' => " The modification you tried to make was aborted by an extension hook " ),
'cantmove-titleprotected' => array ( 'code' => 'protectedtitle' , 'info' => " The destination article has been protected from creation " ),
// 'badarticleerror' => shouldn't happen
// 'badtitletext' => shouldn't happen
2008-01-18 14:34:14 +00:00
// API-specific messages
2008-01-18 16:01:31 +00:00
'missingparam' => array ( 'code' => 'no$1' , 'info' => " The \$ 1 parameter must be set " ),
2008-01-18 14:34:14 +00:00
'invalidtitle' => array ( 'code' => 'invalidtitle' , 'info' => " Bad title `` \$ 1'' " ),
'invaliduser' => array ( 'code' => 'invaliduser' , 'info' => " Invalid username `` \$ 1'' " )
2008-01-15 20:21:16 +00:00
);
/**
* Output the error message related to a certain array
* @ param array $error Element of a getUserPermissionsErrors ()
*/
public function dieUsageMsg ( $error ) {
$key = array_shift ( $error );
if ( isset ( self :: $messageMap [ $key ]))
2008-01-18 16:01:31 +00:00
$this -> dieUsage ( wfMsgReplaceArgs ( self :: $messageMap [ $key ][ 'info' ], $error ), wfMsgReplaceArgs ( self :: $messageMap [ $key ][ 'code' ], $error ));
2008-01-18 14:34:14 +00:00
// If the key isn't present, throw an "unknown error"
$this -> dieUsageMsg ( array ( 'unknownerror' , $key ));
2008-01-15 20:21:16 +00:00
}
2006-10-01 04:38:31 +00:00
/**
* Internal code errors should be reported with this method
*/
2006-10-01 20:17:16 +00:00
protected static function dieDebug ( $method , $message ) {
wfDebugDieBacktrace ( " Internal error in $method : $message " );
2006-10-01 04:38:31 +00:00
}
2007-11-19 15:57:58 +00:00
/**
* Indicates if API needs to check maxlag
*/
public function shouldCheckMaxlag () {
return true ;
}
2007-12-02 15:04:53 +00:00
/**
* Indicates if this module requires edit mode
*/
public function isEditMode () {
return false ;
}
2007-11-19 15:57:58 +00:00
2006-10-01 04:38:31 +00:00
/**
* Profiling : total module execution time
*/
private $mTimeIn = 0 , $mModuleTime = 0 ;
/**
* Start module profiling
*/
public function profileIn () {
if ( $this -> mTimeIn !== 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'called twice without calling profileOut()' );
2006-10-01 04:38:31 +00:00
$this -> mTimeIn = microtime ( true );
2006-10-16 23:25:51 +00:00
wfProfileIn ( $this -> getModuleProfileName ());
2006-10-01 04:38:31 +00:00
}
/**
* End module profiling
*/
public function profileOut () {
if ( $this -> mTimeIn === 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'called without calling profileIn() first' );
2006-10-01 04:38:31 +00:00
if ( $this -> mDBTimeIn !== 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'must be called after database profiling is done with profileDBOut()' );
2006-10-01 04:38:31 +00:00
$this -> mModuleTime += microtime ( true ) - $this -> mTimeIn ;
$this -> mTimeIn = 0 ;
2006-10-17 02:01:20 +00:00
wfProfileOut ( $this -> getModuleProfileName ());
2006-10-01 04:38:31 +00:00
}
2006-10-17 02:01:20 +00:00
/**
* When modules crash , sometimes it is needed to do a profileOut () regardless
* of the profiling state the module was in . This method does such cleanup .
*/
public function safeProfileOut () {
if ( $this -> mTimeIn !== 0 ) {
if ( $this -> mDBTimeIn !== 0 )
$this -> profileDBOut ();
$this -> profileOut ();
}
}
2006-10-30 00:18:05 +00:00
2006-10-01 04:38:31 +00:00
/**
* Total time the module was executed
*/
public function getProfileTime () {
if ( $this -> mTimeIn !== 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'called without calling profileOut() first' );
2006-10-01 04:38:31 +00:00
return $this -> mModuleTime ;
}
/**
* Profiling : database execution time
*/
private $mDBTimeIn = 0 , $mDBTime = 0 ;
/**
* Start module profiling
*/
public function profileDBIn () {
if ( $this -> mTimeIn === 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'must be called while profiling the entire module with profileIn()' );
2006-10-01 04:38:31 +00:00
if ( $this -> mDBTimeIn !== 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'called twice without calling profileDBOut()' );
2006-10-01 04:38:31 +00:00
$this -> mDBTimeIn = microtime ( true );
2006-10-16 23:25:51 +00:00
wfProfileIn ( $this -> getModuleProfileName ( true ));
2006-10-01 04:38:31 +00:00
}
/**
* End database profiling
*/
public function profileDBOut () {
if ( $this -> mTimeIn === 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'must be called while profiling the entire module with profileIn()' );
2006-10-01 04:38:31 +00:00
if ( $this -> mDBTimeIn === 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'called without calling profileDBIn() first' );
2006-10-01 04:38:31 +00:00
$time = microtime ( true ) - $this -> mDBTimeIn ;
$this -> mDBTimeIn = 0 ;
$this -> mDBTime += $time ;
$this -> getMain () -> mDBTime += $time ;
2006-10-16 23:25:51 +00:00
wfProfileOut ( $this -> getModuleProfileName ( true ));
2006-10-01 04:38:31 +00:00
}
/**
* Total time the module used the database
*/
public function getProfileDBTime () {
if ( $this -> mDBTimeIn !== 0 )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'called without calling profileDBOut() first' );
2006-10-01 04:38:31 +00:00
return $this -> mDBTime ;
}
2007-05-14 05:28:06 +00:00
2007-05-19 22:56:42 +00:00
public static function debugPrint ( $value , $name = 'unknown' , $backtrace = false ) {
print " \n \n <pre><b>Debuging value ' $name ':</b> \n \n " ;
2007-05-14 05:28:06 +00:00
var_export ( $value );
2007-05-19 22:56:42 +00:00
if ( $backtrace )
print " \n " . wfBacktrace ();
2007-05-14 05:28:06 +00:00
print " \n </pre> \n " ;
}
2006-10-01 21:20:55 +00:00
2006-10-17 02:01:20 +00:00
2008-01-12 07:08:17 +00:00
/**
* Returns a String that identifies the version of this class .
*/
2006-10-02 18:27:06 +00:00
public static function getBaseVersion () {
2006-10-01 21:20:55 +00:00
return __CLASS__ . ': $Id$' ;
2008-01-15 20:21:16 +00:00
}
2006-10-01 04:38:31 +00:00
}
2007-06-29 01:19:14 +00:00