proxy.php

来自「一款可以和GOOGLE媲美的开源统计系统,运用AJAX.功能强大. 无色提示:」· PHP 代码 · 共 492 行

PHP
492
字号
<?php/** * Piwik - Open source web analytics *  * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later * @version $Id: Proxy.php 581 2008-07-27 23:07:52Z matt $ *  * @package Piwik_API *//** * The API Proxy receives all the API calls requests and forwards them to the given module. *   * It registers all the APIable plugins (@see Piwik_Apiable) * The class checks that a call to the API has the correct number of parameters. * The proxy is a singleton that has the knowledge of every method available, their parameters and default values. *  * It can also log the performances of the API calls (time spent, parameter values, etc.) *  * @package Piwik_API */class Piwik_API_Proxy{	static $classCalled = null;		// array of already registered plugins names	protected $alreadyRegistered = array();		private $api = array();		// when a parameter doesn't have a default value we use this constant	const NO_DEFAULT_VALUE = null;	static private $instance = null;	protected function __construct()	{}		/**	 * Singleton, returns instance	 *	 * @return Piwik_API_Proxy	 */	static public function getInstance()	{		if (self::$instance == null)		{            			$c = __CLASS__;			self::$instance = new $c();		}		return self::$instance;	}		/**	 * Registers the API information of a given module.	 * 	 * The module to be registered must be	 * - extending the Piwik_Apiable class	 * - a singleton (providing a getInstance() method)	 * - the API file must be located in plugins/ModuleName/API.php	 *   for example plugins/Referers/API.php	 * 	 * The method will introspect the methods, their parameters, etc. 	 * 	 * @param string ModuleName eg. "UserSettings"	 */	public function registerClass( $moduleName )	{		if(isset($this->alreadyRegistered[$moduleName]))		{			return;		}		$this->includeApiFile($moduleName);		$class = $this->getClassNameFromModule($moduleName);					$rClass = new ReflectionClass($class);		if(!$rClass->isSubclassOf(new ReflectionClass("Piwik_Apiable")))		{			throw new Exception("To publish its public methods in the API, the class '$class' must be a subclass of 'Piwik_Apiable'.");		}				$this->checkClassIsSingleton($class);				foreach($rClass->getMethods() as $method)		{			$this->loadMethodMetadata($class, $method);		}				$this->alreadyRegistered[$moduleName] = true;	}		/**	 * Checks that the method exists in the class 	 * 	 * @param string The class name	 * @param string The method name	 * @throws exception If the method is not found	 */		public function checkMethodExists($className, $methodName)	{		if(!$this->isMethodAvailable($className, $methodName))		{			throw new Exception("The method '$methodName' does not exist or is not available in the module '".$className."'.");		}	}	/**	 * Magic method used to set a flag telling the module named currently being called	 *	 */	public function __get($name)	{		self::$classCalled = $name;		return $this;	}		/**	 * Method always called when making an API request.	 * It checks several things before actually calling the real method on the given module.	 * 	 * It also logs the API calls, with the parameters values, the returned value, the performance, etc.	 * You can enable logging in config/global.ini.php (log_api_call)	 * 	 * @param string The method name	 * @param array The parameters	 * 	 * @throws Piwik_Access_NoAccessException 	 */	public function __call($methodName, $parameterValues )	{		$returnedValue = null;				try {			$this->registerClass(self::$classCalled);									$className = $this->getClassNameFromModule(self::$classCalled);			// instanciate the object			$object = call_user_func(array($className, "getInstance"));			// check method exists			$this->checkMethodExists($className, $methodName);						// first check number of parameters do match			$this->checkNumberOfParametersMatch($className, $methodName, $parameterValues);						// start the timer			$timer = new Piwik_Timer;						// call the method			$returnedValue = call_user_func_array(array($object, $methodName), $parameterValues);						// log the API Call			$parameterNamesDefaultValues  = $this->getParametersList($className, $methodName);			Zend_Registry::get('logger_api_call')->log(								self::$classCalled,								$methodName,								$parameterNamesDefaultValues,								$parameterValues,								$timer->getTimeMs(),								$returnedValue							);		}		catch( Piwik_Access_NoAccessException $e) {			throw $e;		}		self::$classCalled = null;				return $returnedValue;	}		protected function includeApiFile($fileName)	{		$potentialPaths = array( "plugins/". $fileName ."/API.php", );				$found = false;		foreach($potentialPaths as $path)		{			if(Zend_Loader::isReadable($path))			{				require_once $path;				$found = true;				break;			}		}				if(!$found)		{			throw new Exception("API module $fileName not found.");		}	}		protected function loadMethodMetadata($class, $method)	{		// use this trick to read the static attribute of the class		// $class::$methodsNotToPublish doesn't work		$variablesClass = get_class_vars($class);		$variablesClass['methodsNotToPublish'][] = 'getInstance';		if($method->isPublic() 			&& !$method->isConstructor()			&& !in_array($method->getName(), $variablesClass['methodsNotToPublish'] )		)		{			$name = $method->getName();			$parameters = $method->getParameters();						$aParameters = array();			foreach($parameters as $parameter)			{				$nameVariable = $parameter->getName();								$defaultValue = Piwik_API_Proxy::NO_DEFAULT_VALUE;				if($parameter->isDefaultValueAvailable())				{					$defaultValue = $parameter->getDefaultValue();				}								$aParameters[$nameVariable] = $defaultValue;			}			$this->api[$class][$name]['parameters'] = $aParameters;			$this->api[$class][$name]['numberOfRequiredParameters'] = $method->getNumberOfRequiredParameters();		}	}		/**	 * Returns the  'moduleName' part of 'Piwik_moduleName_API' classname 	 * 	 * @param string moduleName	 * @return string className 	 */ 	protected function getModuleNameFromClassName( $className )	{		$start = strpos($className, '_') + 1;		return substr($className, $start , strrpos($className, '_') - $start);	}		/**	 * Returns a string containing links to examples on how to call a given method on a given API	 * It will export links to XML, CSV, HTML, JSON, PHP, etc.	 * It will not export links for methods such as deleteSite or deleteUser 	 *	 * @param string the class 	 * @param methodName the method	 * @return string|false when not possible	 */	public function getExampleUrl($class, $methodName, $parametersToSet = array())	{		$knowExampleDefaultParametersValues = array(			'access' => 'view',			'userLogin' => 'test',			'password' => 'passwordExample',			'passwordMd5ied' => 'passwordExample',			'email' => 'test@example.org',					'siteName' => 'new example website',			'urls' => 'http://example.org', // used in addSite, updateSite					'languageCode' => 'fr',		);				foreach($parametersToSet as $name => $value)		{			$knowExampleDefaultParametersValues[$name] = $value;		}				// no links for these method names		$doNotPrintExampleForTheseMethods = array(			'deleteSite',			'deleteUser',		);				if(in_array($methodName,$doNotPrintExampleForTheseMethods))		{			return false;		}						// we try to give an URL example to call the API		$aParameters = $this->getParametersList($class, $methodName);		$moduleName = $this->getModuleNameFromClassName($class);		$urlExample = '?module=API&method='.$moduleName.'.'.$methodName.'&';		foreach($aParameters as $nameVariable=> $defaultValue)		{			// if there isn't a default value for a given parameter, 			// we need a 'know default value' or we can't generate the link			if($defaultValue === Piwik_API_Proxy::NO_DEFAULT_VALUE)			{				if(isset($knowExampleDefaultParametersValues[$nameVariable]))				{					$exampleValue = $knowExampleDefaultParametersValues[$nameVariable];					$urlExample .= $nameVariable . '=' . $exampleValue . '&';				}				else				{					return false;				}			}					}				return substr($urlExample,0,-1);	}		/**	 * Returns a HTML page containing help for all the successfully loaded APIs.	 *  For each module it will return a mini help with the method names, parameters to give, 	 * links to get the result in Xml/Csv/etc	 *	 * @return string	 */	public function getAllInterfaceString( $outputExampleUrls = true, $prefixUrls = '' )	{		$str = '';		$token_auth = "&token_auth=" . Piwik::getCurrentUserTokenAuth();		$parametersToSet = array(								'idSite' 	=> Piwik_Common::getRequestVar('idSite', 1, 'int'),								'period' 	=> Piwik_Common::getRequestVar('period', 'day', 'string'),								'date'		=> Piwik_Common::getRequestVar('date', 'today', 'string')							);				foreach($this->api as $class => $info)		{			$moduleName = $this->getModuleNameFromClassName($class);			$str .= "\n<h2 id='$moduleName'>Module ".$moduleName."</h2>";						foreach($info as $methodName => $infoMethod)			{				$params = $this->getStrListParameters($class, $methodName);				$str .= "\n" . "- <b>$moduleName.$methodName " . $params . "</b>";				$str .= '<small>';								if($outputExampleUrls)				{					// we prefix all URLs with $prefixUrls					// used when we include this output in the Piwik official documentation for example					$str .= "<span class=\"example\">";					$exampleUrl = $this->getExampleUrl($class, $methodName, $parametersToSet);					if($exampleUrl !== false)					{						$lastNUrls = '';						if( ereg('(&period)|(&date)',$exampleUrl))						{							$exampleUrlRss1 = $prefixUrls . $this->getExampleUrl($class, $methodName, $parametersToSet + array('date' => 'last10')) ;							$exampleUrlRss2 = $prefixUrls . $this->getExampleUrl($class, $methodName, $parametersToSet + array('date' => 'last5','period' => 'week',));							$lastNUrls = ",	RSS of the last <a target=_blank href='$exampleUrlRss1&format=rss$token_auth'>10 days</a>, <a target=_blank href='$exampleUrlRss2&format=Rss'>5 weeks</a>,									XML of the <a target=_blank href='$exampleUrlRss1&format=xml$token_auth'>last 10 days</a>";						}						$exampleUrl = $prefixUrls . $exampleUrl ;						$str .= " [ Example in  									<a target=_blank href='$exampleUrl&format=xml$token_auth'>XML</a>, 									<a target=_blank href='$exampleUrl&format=PHP&prettyDisplay=true$token_auth'>PHP</a>, 									<a target=_blank href='$exampleUrl&format=JSON$token_auth'>Json</a>, 									<a target=_blank href='$exampleUrl&format=Csv$token_auth'>Csv</a>, 									<a target=_blank href='$exampleUrl&format=Html$token_auth'>Basic html</a> 									$lastNUrls									]";					}					else					{						$str .= " [ No example available ]";					}					$str .= "</span>";				}				$str .= '</small>';				$str .= "\n<br>";			}		}		return $str;	}		/**	 * Returns the methods $class.$name parameters (and default value if provided) as a string.	 * 	 * @param string The class name	 * @param string The method name	 * @return string For example "(idSite, period, date = 'today')"	 */	private function getStrListParameters($class, $name)	{		$aParameters = $this->getParametersList($class, $name);		$asParameters = array();		foreach($aParameters as $nameVariable=> $defaultValue)		{			$str = $nameVariable;			if($defaultValue !== Piwik_API_Proxy::NO_DEFAULT_VALUE)			{				$str .= " = '$defaultValue'";			}			$asParameters[] = $str;		}		$sParameters = implode(", ", $asParameters);		return "($sParameters)";	}		/**	 * Returns the parameters names and default values for the method $name 	 * of the class $class	 * 	 * @param string The class name	 * @param string The method name	 * @return array Format array(	 * 					'testParameter'		=> null, // no default value	 * 					'life'				=> 42, // default value = 42	 * 					'date'				=> 'yesterday',	 * 				);	 */	public function getParametersList($class, $name)	{		return $this->api[$class][$name]['parameters'];	}		/**	 * Returns the number of required parameters (parameters without default values).	 * 	 * @param string The class name	 * @param string The method name	 * @return int The number of required parameters	 */	private function getNumberOfRequiredParameters($class, $name)	{		return $this->api[$class][$name]['numberOfRequiredParameters'];	}		/**	 * Returns true if the method is found in the API of the given class name. 	 * 	 * @param string The class name	 * @param string The method name	 * @return bool 	 */	private function isMethodAvailable( $className, $methodName)	{		return isset($this->api[$className][$methodName]);	}			/**	 * Checks that the count of the given parameters do match with the count of the required ones	 * 	 * @param string The class name	 * @param string The method name	 * @param array 	 * @throws exception If less parameters than required were given	 */	private function checkNumberOfParametersMatch($className, $methodName, $parameters)	{		$nbParamsGiven = count($parameters);		$nbParamsRequired = $this->getNumberOfRequiredParameters($className, $methodName);				if($nbParamsGiven < $nbParamsRequired)		{			throw new Exception("The number of parameters provided ($nbParamsGiven) is less than the number of required parameters ($nbParamsRequired) for this method.							Please check the method API.");		}	}		/**	 * Checks that the class is a Singleton (presence of the getInstance() method)	 * 	 * @param string The class name	 * @throws exception If the class is not a Singleton	 */	private function checkClassIsSingleton($className)	{		if(!method_exists($className, "getInstance"))		{			throw new Exception("Objects that provide an API must be Singleton and have a 'static public function getInstance()' method.");		}	}		/**	 * Returns the API class name given the module name.	 * 	 * For exemple for $module = 'Referers' it returns 'Piwik_Referers_API' 	 * Piwik_Referers_API is the class that extends Piwik_Apiable 	 * and that contains the methods to be published in the API.	 * 	 * @param string module name	 * @return string class name	 */	protected  function getClassNameFromModule($module)	{		$class = Piwik::prefixClass($module ."_API");		return $class;	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?