添加 Piwik 到代码库中。

+YUCHENG HU+

git-svn-id: https://svn.code.sf.net/p/hawebs/svn@428 a2543c7e-f6e9-4f8a-8bff-1ffc34733512
This commit is contained in:
YuCheng Hu
2010-07-10 01:21:06 +00:00
parent bc5b8001cb
commit ba55ebb573
5 changed files with 1119 additions and 0 deletions
@@ -0,0 +1,145 @@
<?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: DataTableGenericFilter.php 2322 2010-06-18 17:11:14Z matt $
*
* @category Piwik
* @package Piwik
*/
/**
* @package Piwik
* @subpackage Piwik_API
*/
class Piwik_API_DataTableGenericFilter
{
function __construct( $datatable, $request )
{
$this->table = $datatable;
$this->request = $request;
}
public function filter()
{
$this->applyGenericFilters($this->table);
}
/**
* Returns an array containing the information of the generic Piwik_DataTable_Filter
* to be applied automatically to the data resulting from the API calls.
*
* Order to apply the filters:
* 1 - Filter that remove filtered rows
* 2 - Filter that sort the remaining rows
* 3 - Filter that keep only a subset of the results
* 4 - Presentation filters
*
* @return array See the code for spec
*/
public static function getGenericFiltersInformation()
{
$genericFilters = array(
'Pattern' => array(
'filter_column' => array('string'),
'filter_pattern' => array('string'),
),
'PatternRecursive' => array(
'filter_column_recursive' => array('string'),
'filter_pattern_recursive' => array('string'),
),
'ExcludeLowPopulation' => array(
'filter_excludelowpop' => array('string'),
'filter_excludelowpop_value'=> array('float', '0'),
),
'AddColumnsWhenShowAllColumns' => array(
'filter_add_columns_when_show_all_columns' => array('integer')
),
'UpdateColumnsWhenShowAllGoals' => array(
'filter_update_columns_when_show_all_goals' => array('integer'),
'filter_only_display_idgoal' => array('integer', Piwik_DataTable_Filter_UpdateColumnsWhenShowAllGoals::GOALS_OVERVIEW),
),
'Sort' => array(
'filter_sort_column' => array('string'),
'filter_sort_order' => array('string'),
),
'Limit' => array(
'filter_offset' => array('integer', '0'),
'filter_limit' => array('integer'),
),
);
return $genericFilters;
}
/**
* Apply generic filters to the DataTable object resulting from the API Call.
* Disable this feature by setting the parameter disable_generic_filters to 1 in the API call request.
*
* @param Piwik_DataTable
*/
protected function applyGenericFilters($datatable)
{
if($datatable instanceof Piwik_DataTable_Array )
{
$tables = $datatable->getArray();
$filterWasApplied = false;
foreach($tables as $table)
{
$filterWasApplied = $this->applyGenericFilters($table);
// if no generic filter was applied to the first table, we can return
// as no filter would be applied to any other dataTable
if(!$filterWasApplied)
{
return;
}
}
return;
}
$genericFilters = self::getGenericFiltersInformation();
$filterApplied = false;
foreach($genericFilters as $filterName => $parameters)
{
$filterParameters = array();
$exceptionRaised = false;
foreach($parameters as $name => $info)
{
// parameter type to cast to
$type = $info[0];
// default value if specified, when the parameter doesn't have a value
$defaultValue = null;
if(isset($info[1]))
{
$defaultValue = $info[1];
}
try {
$value = Piwik_Common::getRequestVar($name, $defaultValue, $type, $this->request);
settype($value, $type);
$filterParameters[] = $value;
}
catch(Exception $e)
{
$exceptionRaised = true;
break;
}
}
if(!$exceptionRaised)
{
if($filterName == 'Limit')
{
$datatable->setRowsCountBeforeLimitFilter();
}
$datatable->filter($filterName, $filterParameters);
$filterApplied = true;
}
}
return $filterApplied;
}
}
@@ -0,0 +1,202 @@
<?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: DocumentationGenerator.php 1968 2010-03-21 17:42:23Z vipsoft $
*
* @category Piwik
* @package Piwik
*/
/**
* @package Piwik
* @subpackage Piwik_API
*/
class Piwik_API_DocumentationGenerator
{
protected $countPluginsLoaded = 0;
/**
* trigger loading all plugins with an API.php file in the Proxy
*/
public function __construct()
{
$plugins = Piwik_PluginsManager::getInstance()->getLoadedPluginsName();
foreach( $plugins as $plugin )
{
$plugin = Piwik::unprefixClass($plugin);
try {
Piwik_API_Proxy::getInstance()->registerClass('Piwik_'.$plugin.'_API');
}
catch(Exception $e){
}
}
}
/**
* 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(Piwik_API_Proxy::getInstance()->getMetadata() as $class => $info)
{
$moduleName = Piwik_API_Proxy::getInstance()->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( preg_match('/(&period)|(&date)/',$exampleUrl))
{
$exampleUrlRss1 = $prefixUrls . $this->getExampleUrl($class, $methodName, array('date' => 'last10') + $parametersToSet) ;
$exampleUrlRss2 = $prefixUrls . $this->getExampleUrl($class, $methodName, array('date' => 'last5','period' => 'week',) + $parametersToSet );
$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 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
*/
protected function getExampleUrl($class, $methodName, $parametersToSet = array())
{
$knowExampleDefaultParametersValues = array(
'access' => 'view',
'userLogin' => 'test',
'passwordMd5ied' => 'passwordExample',
'email' => '[email protected]',
'languageCode' => 'fr',
);
foreach($parametersToSet as $name => $value)
{
$knowExampleDefaultParametersValues[$name] = $value;
}
// no links for these method names
$doNotPrintExampleForTheseMethods = array(
//Sites
'deleteSite',
'addSite',
'updateSite',
'addSiteAliasUrls',
//Users
'deleteUser',
'addUser',
'updateUser',
'setUserAccess',
//Goals
'addGoal',
'updateGoal',
'deleteGoal',
);
if(in_array($methodName,$doNotPrintExampleForTheseMethods))
{
return false;
}
// we try to give an URL example to call the API
$aParameters = Piwik_API_Proxy::getInstance()->getParametersList($class, $methodName);
$moduleName = Piwik_API_Proxy::getInstance()->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 instanceof Piwik_API_Proxy_NoDefaultValue)
{
if(isset($knowExampleDefaultParametersValues[$nameVariable]))
{
$exampleValue = $knowExampleDefaultParametersValues[$nameVariable];
$urlExample .= $nameVariable . '=' . $exampleValue . '&';
}
else
{
return false;
}
}
}
return substr($urlExample,0,-1);
}
/**
* 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')"
*/
protected function getStrListParameters($class, $name)
{
$aParameters = Piwik_API_Proxy::getInstance()->getParametersList($class, $name);
$asParameters = array();
foreach($aParameters as $nameVariable=> $defaultValue)
{
$str = $nameVariable;
if(!($defaultValue instanceof Piwik_API_Proxy_NoDefaultValue))
{
$str .= " = '$defaultValue'";
}
$asParameters[] = $str;
}
$sParameters = implode(", ", $asParameters);
return "($sParameters)";
}
}
File diff suppressed because it is too large Load Diff
+150
View File
@@ -0,0 +1,150 @@
<?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: Request.php 2151 2010-05-07 08:57:27Z matt $
*
* @category Piwik
* @package Piwik
*/
/**
* An API request is the object used to make a call to the API and get the result.
* The request has the format of a normal GET request, ie. parameter_1=X&parameter_2=Y
*
* You can use this object from anywhere in piwik (inside plugins for example).
* You can even call it outside of piwik using the REST API over http
* or in a php script on the same server as piwik, by including piwik/index.php
* (see examples in the documentation http://dev.piwik.org/trac/wiki/API)
*
* Example:
* $request = new Piwik_API_Request('
* method=UserSettings.getWideScreen
* &idSite=1
* &date=yesterday
* &period=week
* &format=xml
* &filter_limit=5
* &filter_offset=0
* ');
* $result = $request->process();
* echo $result;
*
* @see http://dev.piwik.org/trac/wiki/API
* @package Piwik
* @subpackage Piwik_API
*/
class Piwik_API_Request
{
protected $request = null;
/**
* Constructs the request to the API, given the request url
*
* @param string GET request that defines the API call (must at least contain a "method" parameter)
* Example: method=UserSettings.getWideScreen&idSite=1&date=yesterday&period=week&format=xml
* If a request is not provided, then we use the $_GET and $_POST superglobal and fetch
* the values directly from the HTTP GET query.
*/
function __construct($request = null)
{
$defaultRequest = $_GET + $_POST;
$requestArray = $defaultRequest;
if(!is_null($request))
{
$request = trim($request);
$request = str_replace(array("\n","\t"),'', $request);
parse_str($request, $requestArray);
$requestArray = $requestArray + $defaultRequest;
}
foreach($requestArray as &$element)
{
if(!is_array($element))
{
$element = trim($element);
}
}
$this->request = $requestArray;
}
/**
* Handles the request to the API.
* It first checks that the method called (parameter 'method') is available in the module (it means that the method exists and is public)
* It then reads the parameters from the request string and throws an exception if there are missing parameters.
* It then calls the API Proxy which will call the requested method.
*
* @return mixed The data resulting from the API call
*/
public function process()
{
// read the format requested for the output data
$outputFormat = strtolower(Piwik_Common::getRequestVar('format', 'xml', 'string', $this->request));
// create the response
$response = new Piwik_API_ResponseBuilder($outputFormat, $this->request);
try {
// read parameters
$moduleMethod = Piwik_Common::getRequestVar('method', null, null, $this->request);
list($module, $method) = $this->extractModuleAndMethod($moduleMethod);
if(!Piwik_PluginsManager::getInstance()->isPluginActivated($module))
{
throw new Piwik_FrontController_PluginDeactivatedException($module);
}
$module = "Piwik_" . $module . "_API";
self::reloadAuthUsingTokenAuth($this->request);
// call the method
$returnedValue = Piwik_API_Proxy::getInstance()->call($module, $method, $this->request);
$toReturn = $response->getResponse($returnedValue);
} catch(Exception $e ) {
$toReturn = $response->getResponseException( $e );
}
return $toReturn;
}
/**
* If the token_auth is found in the $request parameter,
* the current session will be authenticated using this token_auth.
* It will overwrite the previous Auth object.
*
* @param $request If null, uses the default request ($_GET)
* @return void
*/
static public function reloadAuthUsingTokenAuth($request = null)
{
// if a token_auth is specified in the API request, we load the right permissions
$token_auth = Piwik_Common::getRequestVar('token_auth', '', 'string', $request);
if($token_auth)
{
Piwik_PostEvent('API.Request.authenticate', $token_auth);
Zend_Registry::get('access')->reloadAccess();
}
}
/**
* Returns array( $class, $method) from the given string $class.$method
*
* @return array
* @throws exception if the name is invalid
*/
private function extractModuleAndMethod($parameter)
{
$a = explode('.',$parameter);
if(count($a) != 2)
{
throw new Exception("The method name is invalid. Expected 'module.methodName'");
}
return $a;
}
}
@@ -0,0 +1,293 @@
<?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: ResponseBuilder.php 2294 2010-06-11 15:14:04Z matt $
*
* @category Piwik
* @package Piwik
*/
/**
* @package Piwik
* @subpackage Piwik_API
*/
class Piwik_API_ResponseBuilder
{
private $request = null;
private $outputFormat = null;
public function __construct($outputFormat, $request = array())
{
$this->request = $request;
$this->outputFormat = $outputFormat;
}
/**
* This method processes the data resulting from the API call.
*
* - If the data resulted from the API call is a Piwik_DataTable then
* - we apply the standard filters if the parameters have been found
* in the URL. For example to offset,limit the Table you can add the following parameters to any API
* call that returns a DataTable: filter_limit=10&filter_offset=20
* - we apply the filters that have been previously queued on the DataTable
* @see Piwik_DataTable::queueFilter()
* - we apply the renderer that generate the DataTable in a given format (XML, PHP, HTML, JSON, etc.)
* the format can be changed using the 'format' parameter in the request.
* Example: format=xml
*
* - If there is nothing returned (void) we display a standard success message
*
* - If there is a PHP array returned, we try to convert it to a dataTable
* It is then possible to convert this datatable to any requested format (xml/etc)
*
* - If a bool is returned we convert to a string (true is displayed as 'true' false as 'false')
*
* - If an integer / float is returned, we simply return it
*
* @throws Exception If an object/resource is returned, if any of conversion fails, etc.
*
* @param mixed The initial returned value, before post process. If set to null, success response is returned.
* @return mixed Usually a string, but can still be a PHP data structure if the format requested is 'original'
*/
public function getResponse($value = null)
{
// when null or void is returned from the api call, we handle it as a successful operation
if(!isset($value))
{
return $this->handleSuccess();
}
// If the returned value is an object DataTable we
// apply the set of generic filters if asked in the URL
// and we render the DataTable according to the format specified in the URL
if($value instanceof Piwik_DataTable
|| $value instanceof Piwik_DataTable_Array)
{
return $this->handleDataTable($value);
}
// Case an array is returned from the API call, we convert it to the requested format
// - if calling from inside the application (format = original)
// => the data stays unchanged (ie. a standard php array or whatever data structure)
// - if any other format is requested, we have to convert this data structure (which we assume
// to be an array) to a DataTable in order to apply the requested DataTable_Renderer (for example XML)
if(is_array($value))
{
return $this->handleArray($value);
}
// original data structure requested, we return without process
if( $this->outputFormat == 'original' )
{
return $value;
}
if( is_object($value)
|| is_resource($value))
{
return $this->getResponseException(new Exception('The API cannot handle this data structure.'));
}
// bool // integer // float // serialized object
return $this->handleScalar($value);
}
/**
* Returns an error $message in the requested $format
*
* @param string $message
* @param string $format xml/json/php/csv
* @return string
*/
public function getResponseException(Exception $e)
{
$format = strtolower($this->outputFormat);
if( $format == 'original' )
{
throw $e;
}
try
{
$renderer = Piwik_DataTable_Renderer::factory($format);
} catch (Exception $e) {
return "Error: " . $e->getMessage();
}
$renderer->setException($e);
if($format == 'php')
{
$renderer->setSerialize($this->caseRendererPHPSerialize());
}
return $renderer->renderException();
}
/**
* Returns true if the user requested to serialize the output data (&serialize=1 in the request)
*
* @param $defaultSerializeValue Default value in case the user hasn't specified a value
* @return bool
*/
protected function caseRendererPHPSerialize($defaultSerializeValue = 1)
{
$serialize = Piwik_Common::getRequestVar('serialize', $defaultSerializeValue, 'int', $this->request);
if($serialize)
{
return true;
}
return false;
}
/**
* Apply the specified renderer to the DataTable
*
* @param Piwik_DataTable
* @return string
*/
protected function getRenderedDataTable($dataTable)
{
$format = strtolower($this->outputFormat);
// if asked for original dataStructure
if($format == 'original')
{
// if the original dataStructure is a simpleDataTable
// and has only one column, we return the value
if($dataTable instanceof Piwik_DataTable_Simple)
{
$columns = $dataTable->getFirstRow()->getColumns();
if(count($columns) == 1)
{
$values = array_values($columns);
return $values[0];
}
}
// by default "original" data is not serialized
if($this->caseRendererPHPSerialize( $defaultSerialize = 0))
{
$dataTable = serialize($dataTable);
}
return $dataTable;
}
$renderer = Piwik_DataTable_Renderer::factory($format);
$renderer->setTable($dataTable);
$renderer->setRenderSubTables(Piwik_Common::getRequestVar('expanded', false, 'int', $this->request));
if($format == 'php')
{
$renderer->setSerialize( $this->caseRendererPHPSerialize());
$renderer->setPrettyDisplay(Piwik_Common::getRequestVar('prettyDisplay', false, 'int', $this->request));
}
else if($format == 'html')
{
$renderer->setTableId($this->request['method']);
}
else if($format == 'csv')
{
$renderer->setConvertToUnicode( Piwik_Common::getRequestVar('convertToUnicode', true, 'int') );
}
return $renderer->render();
}
/**
* Returns a success $message in the requested $format
*
* @param string $format xml/json/php/csv
* @param string $message
* @return string
*/
protected function handleSuccess( $message = 'ok' )
{
switch($this->outputFormat)
{
case 'xml':
@header("Content-Type: text/xml;charset=utf-8");
$return =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" .
"<result>\n".
"\t<success message=\"".$message."\" />\n".
"</result>";
break;
case 'json':
@header( "Content-Type: application/json" );
$return = '{"result":"success", "message":"'.$message.'"}';
break;
case 'php':
$return = array('result' => 'success', 'message' => $message);
if($this->caseRendererPHPSerialize())
{
$return = serialize($return);
}
break;
case 'csv':
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=piwik-report-export.csv");
$return = "message\n".$message;
break;
default:
$return = 'Success:'.$message;
break;
}
return $return;
}
protected function handleScalar($scalar)
{
$dataTable = new Piwik_DataTable_Simple();
$dataTable->addRowsFromArray( array($scalar) );
return $this->getRenderedDataTable($dataTable);
}
protected function handleDataTable($datatable)
{
// if the flag disable_generic_filters is defined we skip the generic filters
if('false' == Piwik_Common::getRequestVar('disable_generic_filters', 'false', 'string', $this->request))
{
$genericFilter = new Piwik_API_DataTableGenericFilter($datatable, $this->request);
$genericFilter->filter();
}
// we automatically safe decode all datatable labels (against xss)
$datatable->queueFilter('SafeDecodeLabel');
// if the flag disable_queued_filters is defined we skip the filters that were queued
if(Piwik_Common::getRequestVar('disable_queued_filters', 'false', 'string', $this->request) == 'false')
{
$datatable->applyQueuedFilters();
}
return $this->getRenderedDataTable($datatable);
}
protected function handleArray($array)
{
if($this->outputFormat == 'original')
{
// we handle the serialization. Because some php array have a very special structure that
// couldn't be converted with the automatic DataTable->addRowsFromSimpleArray
// the user may want to request the original PHP data structure serialized by the API
// in case he has to setup serialize=1 in the URL
if($this->caseRendererPHPSerialize( $defaultSerialize = 0))
{
return serialize($array);
}
}
else
{
$dataTable = new Piwik_DataTable();
$dataTable->addRowsFromSimpleArray($array);
return $this->getRenderedDataTable($dataTable);
}
}
}