Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ImageGraph/API.php')
-rw-r--r--plugins/ImageGraph/API.php1053
1 files changed, 494 insertions, 559 deletions
diff --git a/plugins/ImageGraph/API.php b/plugins/ImageGraph/API.php
index d1d5bace51..c4a16297b4 100644
--- a/plugins/ImageGraph/API.php
+++ b/plugins/ImageGraph/API.php
@@ -1,7 +1,7 @@
<?php
/**
* Piwik - Open source web analytics
- *
+ *
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
@@ -24,562 +24,497 @@
*/
class Piwik_ImageGraph_API
{
- const FILENAME_KEY = 'filename';
- const TRUNCATE_KEY = 'truncate';
- const WIDTH_KEY = 'width';
- const HEIGHT_KEY = 'height';
- const MAX_WIDTH = 2048;
- const MAX_HEIGHT = 2048;
-
- static private $DEFAULT_PARAMETERS = array(
- Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_LINE => array(
- self::FILENAME_KEY => 'BasicLine',
- self::TRUNCATE_KEY => 6,
- self::WIDTH_KEY => 1044,
- self::HEIGHT_KEY => 290,
- ),
- Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_VERTICAL_BAR => array(
- self::FILENAME_KEY => 'BasicBar',
- self::TRUNCATE_KEY => 6,
- self::WIDTH_KEY => 1044,
- self::HEIGHT_KEY => 290,
- ),
- Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR => array(
- self::FILENAME_KEY => 'HorizontalBar',
- self::TRUNCATE_KEY => null, // horizontal bar graphs are dynamically truncated
- self::WIDTH_KEY => 800,
- self::HEIGHT_KEY => 290,
- ),
- Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_3D_PIE => array(
- self::FILENAME_KEY => '3DPie',
- self::TRUNCATE_KEY => 5,
- self::WIDTH_KEY => 1044,
- self::HEIGHT_KEY => 290,
- ),
- Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_PIE => array(
- self::FILENAME_KEY => 'BasicPie',
- self::TRUNCATE_KEY => 5,
- self::WIDTH_KEY => 1044,
- self::HEIGHT_KEY => 290,
- ),
- );
-
- static private $DEFAULT_GRAPH_TYPE_OVERRIDE = array(
- 'UserSettings_getPlugin' => array(
- false // override if !$isMultiplePeriod
- => Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR,
- ),
- 'Referers_getRefererType' => array(
- false // override if !$isMultiplePeriod
- => Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR,
- ),
- );
-
- const GRAPH_OUTPUT_INLINE = 0;
- const GRAPH_OUTPUT_FILE = 1;
- const GRAPH_OUTPUT_PHP = 2;
-
- const DEFAULT_ORDINATE_METRIC = 'nb_visits';
- const FONT_DIR = '/plugins/ImageGraph/fonts/';
- const DEFAULT_FONT = 'tahoma.ttf';
- const UNICODE_FONT = 'unifont.ttf';
- const DEFAULT_FONT_SIZE = 9;
- const DEFAULT_LEGEND_FONT_SIZE_OFFSET = 2;
-
- // number of row evolutions to plot when no labels are specified, can be overridden using &filter_limit
- const DEFAULT_NB_ROW_EVOLUTIONS = 5;
- const MAX_NB_ROW_LABELS = 10;
-
- static private $instance = null;
-
- /**
- * @return Piwik_ImageGraph_API
- */
- static public function getInstance()
- {
- if (self::$instance == null)
- {
- $c = __CLASS__;
- self::$instance = new $c();
- }
- return self::$instance;
- }
-
- public function get($idSite, $period, $date, $apiModule, $apiAction, $graphType = false,
- $outputType = Piwik_ImageGraph_API::GRAPH_OUTPUT_INLINE, $columns = false, $labels = false, $showLegend = true,
- $width = false, $height = false, $fontSize = Piwik_ImageGraph_API::DEFAULT_FONT_SIZE, $legendFontSize = false,
- $aliasedGraph = true, $idGoal = false, $colors = false, $idSubtable = false, $legendAppendMetric = true)
- {
- Piwik::checkUserHasViewAccess($idSite);
-
- // Health check - should we also test for GD2 only?
- if(!Piwik::isGdExtensionEnabled())
- {
- throw new Exception('Error: To create graphs in Piwik, please enable GD php extension (with Freetype support) in php.ini, and restart your web server.');
- }
-
- $useUnicodeFont = array(
- 'am', 'ar', 'el', 'fa' , 'fi', 'he', 'ja', 'ka', 'ko', 'te', 'th', 'zh-cn', 'zh-tw',
- );
- $languageLoaded = Piwik_Translate::getInstance()->getLanguageLoaded();
- $font = self::getFontPath(self::DEFAULT_FONT);
- if(in_array($languageLoaded, $useUnicodeFont))
- {
- $unicodeFontPath = self::getFontPath(self::UNICODE_FONT);
- $font = file_exists($unicodeFontPath) ? $unicodeFontPath : $font;
- }
-
- // save original GET to reset after processing. Important for API-in-API-call
- $savedGET = $_GET;
-
- try
- {
- $apiParameters = array();
- if(!empty($idGoal)) {
- $apiParameters = array( 'idGoal' => $idGoal);
- }
- // Fetch the metadata for given api-action
- $metadata = Piwik_API_API::getInstance()->getMetadata(
- $idSite, $apiModule, $apiAction, $apiParameters, $languageLoaded, $period, $date,
- $hideMetricsDoc = false, $showSubtableReports = true);
- if(!$metadata)
- {
- throw new Exception('Invalid API Module and/or API Action');
- }
-
- $metadata = $metadata[0];
- $reportHasDimension = !empty($metadata['dimension']);
- $constantRowsCount = !empty($metadata['constantRowsCount']);
-
- $isMultiplePeriod = Piwik_Archive::isMultiplePeriod($date, $period);
- if(!$reportHasDimension && !$isMultiplePeriod)
- {
- throw new Exception('The graph cannot be drawn for this combination of \'date\' and \'period\' parameters.');
- }
-
- if(empty($legendFontSize))
- {
- $legendFontSize = (int)$fontSize + self::DEFAULT_LEGEND_FONT_SIZE_OFFSET;
- }
-
- if(empty($graphType))
- {
- if($isMultiplePeriod)
- {
- $graphType = Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_LINE;
- }
- else
- {
- if($constantRowsCount)
- {
- $graphType = Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_VERTICAL_BAR;
- }
- else
- {
- $graphType = Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR;
- }
- }
-
- $reportUniqueId = $metadata['uniqueId'];
- if(isset(self::$DEFAULT_GRAPH_TYPE_OVERRIDE[$reportUniqueId][$isMultiplePeriod]))
- {
- $graphType = self::$DEFAULT_GRAPH_TYPE_OVERRIDE[$reportUniqueId][$isMultiplePeriod];
- }
- }
- else
- {
- $availableGraphTypes = Piwik_ImageGraph_StaticGraph::getAvailableStaticGraphTypes();
- if (!in_array($graphType, $availableGraphTypes))
- {
- throw new Exception(
- Piwik_TranslateException(
- 'General_ExceptionInvalidStaticGraphType',
- array($graphType, implode(', ', $availableGraphTypes))
- )
- );
- }
- }
-
- $width = (int)$width;
- $height = (int)$height;
- if(empty($width))
- {
- $width = self::$DEFAULT_PARAMETERS[$graphType][self::WIDTH_KEY];
- }
- if(empty($height))
- {
- $height = self::$DEFAULT_PARAMETERS[$graphType][self::HEIGHT_KEY];
- }
-
- // Cap width and height to a safe amount
- $width = min($width, self::MAX_WIDTH);
- $height = min($height, self::MAX_HEIGHT);
-
- $reportColumns = array_merge(
- !empty($metadata['metrics']) ? $metadata['metrics'] : array(),
- !empty($metadata['processedMetrics']) ? $metadata['processedMetrics'] : array(),
- !empty($metadata['metricsGoal']) ? $metadata['metricsGoal'] : array(),
- !empty($metadata['processedMetricsGoal']) ? $metadata['processedMetricsGoal'] : array()
- );
-
- $ordinateColumns = array();
- if(empty($columns))
- {
- $ordinateColumns[] =
- empty($reportColumns[self::DEFAULT_ORDINATE_METRIC]) ? key($metadata['metrics']) : self::DEFAULT_ORDINATE_METRIC;
- }
- else
- {
- $ordinateColumns = explode(',', $columns);
- foreach($ordinateColumns as $column)
- {
- if(empty($reportColumns[$column]))
- {
- throw new Exception(
- Piwik_Translate(
- 'ImageGraph_ColumnOrdinateMissing',
- array($column, implode(',',array_keys($reportColumns)))
- )
- );
- }
- }
- }
-
- $ordinateLabels = array();
- foreach($ordinateColumns as $column)
- {
- $ordinateLabels[$column] = $reportColumns[$column];
- }
-
- // sort and truncate filters
- $defaultFilterTruncate = self::$DEFAULT_PARAMETERS[$graphType][self::TRUNCATE_KEY];
- switch($graphType)
- {
- case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_3D_PIE:
- case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_PIE:
-
- if(count($ordinateColumns) > 1)
- {
- // pChart doesn't support multiple series on pie charts
- throw new Exception("Pie charts do not currently support multiple series");
- }
-
- $_GET['filter_sort_column'] = reset($ordinateColumns);
- $this->setFilterTruncate($defaultFilterTruncate);
- break;
-
- case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_VERTICAL_BAR:
- case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_LINE:
-
- if(!$isMultiplePeriod && !$constantRowsCount)
- {
- $this->setFilterTruncate($defaultFilterTruncate);
- }
- break;
- }
-
- $ordinateLogos = array();
-
- // row evolutions
- if($isMultiplePeriod && $reportHasDimension)
- {
- $plottedMetric = reset($ordinateColumns);
-
- // when no labels are specified, getRowEvolution returns the top N=filter_limit row evolutions
- // rows are sorted using filter_sort_column (see Piwik_API_DataTableGenericFilter for more info)
- if(!$labels)
- {
- $savedFilterSortColumnValue = Piwik_Common::getRequestVar('filter_sort_column', '');
- $_GET['filter_sort_column'] = $plottedMetric;
-
- $savedFilterLimitValue = Piwik_Common::getRequestVar('filter_limit', -1, 'int');
- if($savedFilterLimitValue == -1 || $savedFilterLimitValue > self::MAX_NB_ROW_LABELS)
- {
- $_GET['filter_limit'] = self::DEFAULT_NB_ROW_EVOLUTIONS;
- }
- }
-
- $processedReport = Piwik_API_API::getInstance()->getRowEvolution(
- $idSite,
- $period,
- $date,
- $apiModule,
- $apiAction,
- $labels,
- $segment = false,
- $plottedMetric,
- $languageLoaded,
- $idGoal,
- $legendAppendMetric,
- $labelUseAbsoluteUrl = false
- );
-
- //@review this test will need to be updated after evaluating the @review comment in API/API.php
- if(!$processedReport)
- {
- throw new Exception(Piwik_Translate('General_NoDataForGraph_js'));
- }
-
- // restoring generic filter parameters
- if(!$labels)
- {
- $_GET['filter_sort_column'] = $savedFilterSortColumnValue;
- if($savedFilterLimitValue != -1)
- {
- $_GET['filter_limit'] = $savedFilterLimitValue;
- }
- }
-
- // retrieve metric names & labels
- $metrics = $processedReport['metadata']['metrics'];
- $ordinateLabels = array();
-
- // getRowEvolution returned more than one label
- if(!array_key_exists($plottedMetric, $metrics))
- {
- $ordinateColumns = array();
- $i = 0;
- foreach($metrics as $metric => $info)
- {
- $ordinateColumn = $plottedMetric . '_' . $i++;
- $ordinateColumns[] = $metric;
- $ordinateLabels[$ordinateColumn] = $info['name'];
-
- if(isset($info['logo']))
- {
- $ordinateLogo = $info['logo'];
-
- // @review pChart does not support gifs in graph legends, would it be possible to convert all plugin pictures (cookie.gif, flash.gif, ..) to png files?
- if(!strstr($ordinateLogo, '.gif'))
- {
- $absoluteLogoPath = self::getAbsoluteLogoPath($ordinateLogo);
- if(file_exists($absoluteLogoPath))
- {
- $ordinateLogos[$ordinateColumn] = $absoluteLogoPath;
- }
- }
- }
- }
- }
- else
- {
- $ordinateLabels[$plottedMetric] = $processedReport['label'] . ' (' . $metrics[$plottedMetric]['name'] . ')';
- }
- }
- else
- {
- $processedReport = Piwik_API_API::getInstance()->getProcessedReport(
- $idSite,
- $period,
- $date,
- $apiModule,
- $apiAction,
- $segment = false,
- $apiParameters = false,
- $idGoal,
- $languageLoaded,
- $showTimer = true,
- $hideMetricsDoc = false,
- $idSubtable,
- $showRawMetrics = false
- );
- }
- // prepare abscissa and ordinate series
- $abscissaSeries = array();
- $abscissaLogos = array();
- $ordinateSeries = array();
- $reportData = $processedReport['reportData'];
- $hasData = false;
- $hasNonZeroValue = false;
-
- if(!$isMultiplePeriod)
- {
- $reportMetadata = $processedReport['reportMetadata']->getRows();
-
- $i = 0;
- // $reportData instanceof Piwik_DataTable
- foreach($reportData->getRows() as $row) // Piwik_DataTable_Row[]
- {
- // $row instanceof Piwik_DataTable_Row
- $rowData = $row->getColumns(); // Associative Array
- $abscissaSeries[] = Piwik_Common::unsanitizeInputValue($rowData['label']);
-
- foreach($ordinateColumns as $column)
- {
- $parsedOrdinateValue = $this->parseOrdinateValue($rowData[$column]);
- $hasData = true;
-
- if($parsedOrdinateValue != 0)
- {
- $hasNonZeroValue = true;
- }
- $ordinateSeries[$column][] = $parsedOrdinateValue;
- }
-
- if(isset($reportMetadata[$i]))
- {
- $rowMetadata = $reportMetadata[$i]->getColumns();
- if(isset($rowMetadata['logo']))
- {
- $absoluteLogoPath = self::getAbsoluteLogoPath($rowMetadata['logo']);
- if(file_exists($absoluteLogoPath))
- {
- $abscissaLogos[$i] = $absoluteLogoPath;
- }
- }
- }
- $i++;
- }
- }
- else // if the report has no dimension we have multiple reports each with only one row within the reportData
- {
- // $periodsData instanceof Piwik_DataTable_Simple[]
- $periodsData = array_values($reportData->getArray());
- $periodsCount = count($periodsData);
-
- for ($i = 0 ; $i < $periodsCount ; $i++)
- {
- // $periodsData[$i] instanceof Piwik_DataTable_Simple
- // $rows instanceof Piwik_DataTable_Row[]
- if(empty($periodsData[$i]))
- {
- continue;
- }
- $rows = $periodsData[$i]->getRows();
-
- if(array_key_exists(0, $rows))
- {
- $rowData = $rows[0]->getColumns(); // associative Array
-
- foreach($ordinateColumns as $column)
- {
- $ordinateValue = $rowData[$column];
- $parsedOrdinateValue = $this->parseOrdinateValue($ordinateValue);
-
- $hasData = true;
-
- if(!empty($parsedOrdinateValue))
- {
- $hasNonZeroValue = true;
- }
-
- $ordinateSeries[$column][] = $parsedOrdinateValue;
- }
-
- }
- else
- {
- foreach($ordinateColumns as $column)
- {
- $ordinateSeries[$column][] = 0;
- }
- }
-
- $rowId = $periodsData[$i]->metadata['period']->getLocalizedShortString();
- $abscissaSeries[] = Piwik_Common::unsanitizeInputValue($rowId);
- }
- }
-
- if(!$hasData || !$hasNonZeroValue)
- {
- throw new Exception(Piwik_Translate('General_NoDataForGraph_js'));
- }
-
- //Setup the graph
- $graph = Piwik_ImageGraph_StaticGraph::factory($graphType);
- $graph->setWidth($width);
- $graph->setHeight($height);
- $graph->setFont($font);
- $graph->setFontSize($fontSize);
- $graph->setLegendFontSize($legendFontSize);
- $graph->setOrdinateLabels($ordinateLabels);
- $graph->setShowLegend($showLegend);
- $graph->setAliasedGraph($aliasedGraph);
- $graph->setAbscissaSeries($abscissaSeries);
- $graph->setAbscissaLogos($abscissaLogos);
- $graph->setOrdinateSeries($ordinateSeries);
- $graph->setOrdinateLogos($ordinateLogos);
- $graph->setColors(!empty($colors) ? explode(',', $colors) : array());
- if($period == 'day')
- {
- $graph->setForceSkippedLabels(6);
- }
-
- // render graph
- $graph->renderGraph();
-
- } catch (Exception $e) {
-
- $graph = new Piwik_ImageGraph_StaticGraph_Exception();
- $graph->setWidth($width);
- $graph->setHeight($height);
- $graph->setFont($font);
- $graph->setFontSize($fontSize);
- $graph->setException($e);
- $graph->renderGraph();
- }
-
- // restoring get parameters
- $_GET = $savedGET;
-
- switch($outputType)
- {
- case self::GRAPH_OUTPUT_FILE:
- if($idGoal != '')
- {
- $idGoal = '_' . $idGoal;
- }
- $fileName = self::$DEFAULT_PARAMETERS[$graphType][self::FILENAME_KEY] . '_' . $apiModule . '_' . $apiAction . $idGoal . ' ' . str_replace(',', '-', $date) . ' ' . $idSite . '.png';
- $fileName = str_replace(array(' ','/'), '_', $fileName);
-
- if(!Piwik_Common::isValidFilename($fileName))
- {
- throw new Exception('Error: Image graph filename ' . $fileName . ' is not valid.');
- }
-
- return $graph->sendToDisk($fileName);
-
- case self::GRAPH_OUTPUT_PHP:
- return $graph->getRenderedImage();
-
- case self::GRAPH_OUTPUT_INLINE:
- default:
- $graph->sendToBrowser();
- exit;
- }
- }
-
- private function setFilterTruncate($default)
- {
- $_GET['filter_truncate'] = Piwik_Common::getRequestVar('filter_truncate', $default, 'int');
- }
-
- private static function parseOrdinateValue($ordinateValue)
- {
- $ordinateValue = @str_replace(',', '.', $ordinateValue);
-
- // convert hh:mm:ss formatted time values to number of seconds
- if(preg_match('/([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})/', $ordinateValue, $matches))
- {
- $hour = $matches[1];
- $min = $matches[2];
- $sec = $matches[3];
-
- $ordinateValue = ($hour * 3600) + ($min * 60) + $sec;
- }
-
- // OK, only numbers from here please (strip out currency sign)
- $ordinateValue = preg_replace('/[^0-9.]/', '', $ordinateValue);
- return $ordinateValue;
- }
-
- private static function getFontPath($font)
- {
- return PIWIK_INCLUDE_PATH . self::FONT_DIR . $font;
- }
-
- protected static function getAbsoluteLogoPath($relativeLogoPath)
- {
- return PIWIK_INCLUDE_PATH . '/' . $relativeLogoPath;
- }
+ const FILENAME_KEY = 'filename';
+ const TRUNCATE_KEY = 'truncate';
+ const WIDTH_KEY = 'width';
+ const HEIGHT_KEY = 'height';
+ const MAX_WIDTH = 2048;
+ const MAX_HEIGHT = 2048;
+
+ static private $DEFAULT_PARAMETERS = array(
+ Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_LINE => array(
+ self::FILENAME_KEY => 'BasicLine',
+ self::TRUNCATE_KEY => 6,
+ self::WIDTH_KEY => 1044,
+ self::HEIGHT_KEY => 290,
+ ),
+ Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_VERTICAL_BAR => array(
+ self::FILENAME_KEY => 'BasicBar',
+ self::TRUNCATE_KEY => 6,
+ self::WIDTH_KEY => 1044,
+ self::HEIGHT_KEY => 290,
+ ),
+ Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR => array(
+ self::FILENAME_KEY => 'HorizontalBar',
+ self::TRUNCATE_KEY => null, // horizontal bar graphs are dynamically truncated
+ self::WIDTH_KEY => 800,
+ self::HEIGHT_KEY => 290,
+ ),
+ Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_3D_PIE => array(
+ self::FILENAME_KEY => '3DPie',
+ self::TRUNCATE_KEY => 5,
+ self::WIDTH_KEY => 1044,
+ self::HEIGHT_KEY => 290,
+ ),
+ Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_PIE => array(
+ self::FILENAME_KEY => 'BasicPie',
+ self::TRUNCATE_KEY => 5,
+ self::WIDTH_KEY => 1044,
+ self::HEIGHT_KEY => 290,
+ ),
+ );
+
+ static private $DEFAULT_GRAPH_TYPE_OVERRIDE = array(
+ 'UserSettings_getPlugin' => array(
+ false // override if !$isMultiplePeriod
+ => Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR,
+ ),
+ 'Referers_getRefererType' => array(
+ false // override if !$isMultiplePeriod
+ => Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR,
+ ),
+ );
+
+ const GRAPH_OUTPUT_INLINE = 0;
+ const GRAPH_OUTPUT_FILE = 1;
+ const GRAPH_OUTPUT_PHP = 2;
+
+ const DEFAULT_ORDINATE_METRIC = 'nb_visits';
+ const FONT_DIR = '/plugins/ImageGraph/fonts/';
+ const DEFAULT_FONT = 'tahoma.ttf';
+ const UNICODE_FONT = 'unifont.ttf';
+ const DEFAULT_FONT_SIZE = 9;
+ const DEFAULT_LEGEND_FONT_SIZE_OFFSET = 2;
+
+ // number of row evolutions to plot when no labels are specified, can be overridden using &filter_limit
+ const DEFAULT_NB_ROW_EVOLUTIONS = 5;
+ const MAX_NB_ROW_LABELS = 10;
+
+ static private $instance = null;
+
+ /**
+ * @return Piwik_ImageGraph_API
+ */
+ static public function getInstance()
+ {
+ if (self::$instance == null) {
+ $c = __CLASS__;
+ self::$instance = new $c();
+ }
+ return self::$instance;
+ }
+
+ public function get($idSite, $period, $date, $apiModule, $apiAction, $graphType = false,
+ $outputType = Piwik_ImageGraph_API::GRAPH_OUTPUT_INLINE, $columns = false, $labels = false, $showLegend = true,
+ $width = false, $height = false, $fontSize = Piwik_ImageGraph_API::DEFAULT_FONT_SIZE, $legendFontSize = false,
+ $aliasedGraph = true, $idGoal = false, $colors = false, $idSubtable = false, $legendAppendMetric = true)
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+
+ // Health check - should we also test for GD2 only?
+ if (!Piwik::isGdExtensionEnabled()) {
+ throw new Exception('Error: To create graphs in Piwik, please enable GD php extension (with Freetype support) in php.ini, and restart your web server.');
+ }
+
+ $useUnicodeFont = array(
+ 'am', 'ar', 'el', 'fa', 'fi', 'he', 'ja', 'ka', 'ko', 'te', 'th', 'zh-cn', 'zh-tw',
+ );
+ $languageLoaded = Piwik_Translate::getInstance()->getLanguageLoaded();
+ $font = self::getFontPath(self::DEFAULT_FONT);
+ if (in_array($languageLoaded, $useUnicodeFont)) {
+ $unicodeFontPath = self::getFontPath(self::UNICODE_FONT);
+ $font = file_exists($unicodeFontPath) ? $unicodeFontPath : $font;
+ }
+
+ // save original GET to reset after processing. Important for API-in-API-call
+ $savedGET = $_GET;
+
+ try {
+ $apiParameters = array();
+ if (!empty($idGoal)) {
+ $apiParameters = array('idGoal' => $idGoal);
+ }
+ // Fetch the metadata for given api-action
+ $metadata = Piwik_API_API::getInstance()->getMetadata(
+ $idSite, $apiModule, $apiAction, $apiParameters, $languageLoaded, $period, $date,
+ $hideMetricsDoc = false, $showSubtableReports = true);
+ if (!$metadata) {
+ throw new Exception('Invalid API Module and/or API Action');
+ }
+
+ $metadata = $metadata[0];
+ $reportHasDimension = !empty($metadata['dimension']);
+ $constantRowsCount = !empty($metadata['constantRowsCount']);
+
+ $isMultiplePeriod = Piwik_Archive::isMultiplePeriod($date, $period);
+ if (!$reportHasDimension && !$isMultiplePeriod) {
+ throw new Exception('The graph cannot be drawn for this combination of \'date\' and \'period\' parameters.');
+ }
+
+ if (empty($legendFontSize)) {
+ $legendFontSize = (int)$fontSize + self::DEFAULT_LEGEND_FONT_SIZE_OFFSET;
+ }
+
+ if (empty($graphType)) {
+ if ($isMultiplePeriod) {
+ $graphType = Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_LINE;
+ } else {
+ if ($constantRowsCount) {
+ $graphType = Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_VERTICAL_BAR;
+ } else {
+ $graphType = Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_HORIZONTAL_BAR;
+ }
+ }
+
+ $reportUniqueId = $metadata['uniqueId'];
+ if (isset(self::$DEFAULT_GRAPH_TYPE_OVERRIDE[$reportUniqueId][$isMultiplePeriod])) {
+ $graphType = self::$DEFAULT_GRAPH_TYPE_OVERRIDE[$reportUniqueId][$isMultiplePeriod];
+ }
+ } else {
+ $availableGraphTypes = Piwik_ImageGraph_StaticGraph::getAvailableStaticGraphTypes();
+ if (!in_array($graphType, $availableGraphTypes)) {
+ throw new Exception(
+ Piwik_TranslateException(
+ 'General_ExceptionInvalidStaticGraphType',
+ array($graphType, implode(', ', $availableGraphTypes))
+ )
+ );
+ }
+ }
+
+ $width = (int)$width;
+ $height = (int)$height;
+ if (empty($width)) {
+ $width = self::$DEFAULT_PARAMETERS[$graphType][self::WIDTH_KEY];
+ }
+ if (empty($height)) {
+ $height = self::$DEFAULT_PARAMETERS[$graphType][self::HEIGHT_KEY];
+ }
+
+ // Cap width and height to a safe amount
+ $width = min($width, self::MAX_WIDTH);
+ $height = min($height, self::MAX_HEIGHT);
+
+ $reportColumns = array_merge(
+ !empty($metadata['metrics']) ? $metadata['metrics'] : array(),
+ !empty($metadata['processedMetrics']) ? $metadata['processedMetrics'] : array(),
+ !empty($metadata['metricsGoal']) ? $metadata['metricsGoal'] : array(),
+ !empty($metadata['processedMetricsGoal']) ? $metadata['processedMetricsGoal'] : array()
+ );
+
+ $ordinateColumns = array();
+ if (empty($columns)) {
+ $ordinateColumns[] =
+ empty($reportColumns[self::DEFAULT_ORDINATE_METRIC]) ? key($metadata['metrics']) : self::DEFAULT_ORDINATE_METRIC;
+ } else {
+ $ordinateColumns = explode(',', $columns);
+ foreach ($ordinateColumns as $column) {
+ if (empty($reportColumns[$column])) {
+ throw new Exception(
+ Piwik_Translate(
+ 'ImageGraph_ColumnOrdinateMissing',
+ array($column, implode(',', array_keys($reportColumns)))
+ )
+ );
+ }
+ }
+ }
+
+ $ordinateLabels = array();
+ foreach ($ordinateColumns as $column) {
+ $ordinateLabels[$column] = $reportColumns[$column];
+ }
+
+ // sort and truncate filters
+ $defaultFilterTruncate = self::$DEFAULT_PARAMETERS[$graphType][self::TRUNCATE_KEY];
+ switch ($graphType) {
+ case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_3D_PIE:
+ case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_PIE:
+
+ if (count($ordinateColumns) > 1) {
+ // pChart doesn't support multiple series on pie charts
+ throw new Exception("Pie charts do not currently support multiple series");
+ }
+
+ $_GET['filter_sort_column'] = reset($ordinateColumns);
+ $this->setFilterTruncate($defaultFilterTruncate);
+ break;
+
+ case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_VERTICAL_BAR:
+ case Piwik_ImageGraph_StaticGraph::GRAPH_TYPE_BASIC_LINE:
+
+ if (!$isMultiplePeriod && !$constantRowsCount) {
+ $this->setFilterTruncate($defaultFilterTruncate);
+ }
+ break;
+ }
+
+ $ordinateLogos = array();
+
+ // row evolutions
+ if ($isMultiplePeriod && $reportHasDimension) {
+ $plottedMetric = reset($ordinateColumns);
+
+ // when no labels are specified, getRowEvolution returns the top N=filter_limit row evolutions
+ // rows are sorted using filter_sort_column (see Piwik_API_DataTableGenericFilter for more info)
+ if (!$labels) {
+ $savedFilterSortColumnValue = Piwik_Common::getRequestVar('filter_sort_column', '');
+ $_GET['filter_sort_column'] = $plottedMetric;
+
+ $savedFilterLimitValue = Piwik_Common::getRequestVar('filter_limit', -1, 'int');
+ if ($savedFilterLimitValue == -1 || $savedFilterLimitValue > self::MAX_NB_ROW_LABELS) {
+ $_GET['filter_limit'] = self::DEFAULT_NB_ROW_EVOLUTIONS;
+ }
+ }
+
+ $processedReport = Piwik_API_API::getInstance()->getRowEvolution(
+ $idSite,
+ $period,
+ $date,
+ $apiModule,
+ $apiAction,
+ $labels,
+ $segment = false,
+ $plottedMetric,
+ $languageLoaded,
+ $idGoal,
+ $legendAppendMetric,
+ $labelUseAbsoluteUrl = false
+ );
+
+ //@review this test will need to be updated after evaluating the @review comment in API/API.php
+ if (!$processedReport) {
+ throw new Exception(Piwik_Translate('General_NoDataForGraph_js'));
+ }
+
+ // restoring generic filter parameters
+ if (!$labels) {
+ $_GET['filter_sort_column'] = $savedFilterSortColumnValue;
+ if ($savedFilterLimitValue != -1) {
+ $_GET['filter_limit'] = $savedFilterLimitValue;
+ }
+ }
+
+ // retrieve metric names & labels
+ $metrics = $processedReport['metadata']['metrics'];
+ $ordinateLabels = array();
+
+ // getRowEvolution returned more than one label
+ if (!array_key_exists($plottedMetric, $metrics)) {
+ $ordinateColumns = array();
+ $i = 0;
+ foreach ($metrics as $metric => $info) {
+ $ordinateColumn = $plottedMetric . '_' . $i++;
+ $ordinateColumns[] = $metric;
+ $ordinateLabels[$ordinateColumn] = $info['name'];
+
+ if (isset($info['logo'])) {
+ $ordinateLogo = $info['logo'];
+
+ // @review pChart does not support gifs in graph legends, would it be possible to convert all plugin pictures (cookie.gif, flash.gif, ..) to png files?
+ if (!strstr($ordinateLogo, '.gif')) {
+ $absoluteLogoPath = self::getAbsoluteLogoPath($ordinateLogo);
+ if (file_exists($absoluteLogoPath)) {
+ $ordinateLogos[$ordinateColumn] = $absoluteLogoPath;
+ }
+ }
+ }
+ }
+ } else {
+ $ordinateLabels[$plottedMetric] = $processedReport['label'] . ' (' . $metrics[$plottedMetric]['name'] . ')';
+ }
+ } else {
+ $processedReport = Piwik_API_API::getInstance()->getProcessedReport(
+ $idSite,
+ $period,
+ $date,
+ $apiModule,
+ $apiAction,
+ $segment = false,
+ $apiParameters = false,
+ $idGoal,
+ $languageLoaded,
+ $showTimer = true,
+ $hideMetricsDoc = false,
+ $idSubtable,
+ $showRawMetrics = false
+ );
+ }
+ // prepare abscissa and ordinate series
+ $abscissaSeries = array();
+ $abscissaLogos = array();
+ $ordinateSeries = array();
+ $reportData = $processedReport['reportData'];
+ $hasData = false;
+ $hasNonZeroValue = false;
+
+ if (!$isMultiplePeriod) {
+ $reportMetadata = $processedReport['reportMetadata']->getRows();
+
+ $i = 0;
+ // $reportData instanceof Piwik_DataTable
+ foreach ($reportData->getRows() as $row) // Piwik_DataTable_Row[]
+ {
+ // $row instanceof Piwik_DataTable_Row
+ $rowData = $row->getColumns(); // Associative Array
+ $abscissaSeries[] = Piwik_Common::unsanitizeInputValue($rowData['label']);
+
+ foreach ($ordinateColumns as $column) {
+ $parsedOrdinateValue = $this->parseOrdinateValue($rowData[$column]);
+ $hasData = true;
+
+ if ($parsedOrdinateValue != 0) {
+ $hasNonZeroValue = true;
+ }
+ $ordinateSeries[$column][] = $parsedOrdinateValue;
+ }
+
+ if (isset($reportMetadata[$i])) {
+ $rowMetadata = $reportMetadata[$i]->getColumns();
+ if (isset($rowMetadata['logo'])) {
+ $absoluteLogoPath = self::getAbsoluteLogoPath($rowMetadata['logo']);
+ if (file_exists($absoluteLogoPath)) {
+ $abscissaLogos[$i] = $absoluteLogoPath;
+ }
+ }
+ }
+ $i++;
+ }
+ } else // if the report has no dimension we have multiple reports each with only one row within the reportData
+ {
+ // $periodsData instanceof Piwik_DataTable_Simple[]
+ $periodsData = array_values($reportData->getArray());
+ $periodsCount = count($periodsData);
+
+ for ($i = 0; $i < $periodsCount; $i++) {
+ // $periodsData[$i] instanceof Piwik_DataTable_Simple
+ // $rows instanceof Piwik_DataTable_Row[]
+ if (empty($periodsData[$i])) {
+ continue;
+ }
+ $rows = $periodsData[$i]->getRows();
+
+ if (array_key_exists(0, $rows)) {
+ $rowData = $rows[0]->getColumns(); // associative Array
+
+ foreach ($ordinateColumns as $column) {
+ $ordinateValue = $rowData[$column];
+ $parsedOrdinateValue = $this->parseOrdinateValue($ordinateValue);
+
+ $hasData = true;
+
+ if (!empty($parsedOrdinateValue)) {
+ $hasNonZeroValue = true;
+ }
+
+ $ordinateSeries[$column][] = $parsedOrdinateValue;
+ }
+
+ } else {
+ foreach ($ordinateColumns as $column) {
+ $ordinateSeries[$column][] = 0;
+ }
+ }
+
+ $rowId = $periodsData[$i]->metadata['period']->getLocalizedShortString();
+ $abscissaSeries[] = Piwik_Common::unsanitizeInputValue($rowId);
+ }
+ }
+
+ if (!$hasData || !$hasNonZeroValue) {
+ throw new Exception(Piwik_Translate('General_NoDataForGraph_js'));
+ }
+
+ //Setup the graph
+ $graph = Piwik_ImageGraph_StaticGraph::factory($graphType);
+ $graph->setWidth($width);
+ $graph->setHeight($height);
+ $graph->setFont($font);
+ $graph->setFontSize($fontSize);
+ $graph->setLegendFontSize($legendFontSize);
+ $graph->setOrdinateLabels($ordinateLabels);
+ $graph->setShowLegend($showLegend);
+ $graph->setAliasedGraph($aliasedGraph);
+ $graph->setAbscissaSeries($abscissaSeries);
+ $graph->setAbscissaLogos($abscissaLogos);
+ $graph->setOrdinateSeries($ordinateSeries);
+ $graph->setOrdinateLogos($ordinateLogos);
+ $graph->setColors(!empty($colors) ? explode(',', $colors) : array());
+ if ($period == 'day') {
+ $graph->setForceSkippedLabels(6);
+ }
+
+ // render graph
+ $graph->renderGraph();
+
+ } catch (Exception $e) {
+
+ $graph = new Piwik_ImageGraph_StaticGraph_Exception();
+ $graph->setWidth($width);
+ $graph->setHeight($height);
+ $graph->setFont($font);
+ $graph->setFontSize($fontSize);
+ $graph->setException($e);
+ $graph->renderGraph();
+ }
+
+ // restoring get parameters
+ $_GET = $savedGET;
+
+ switch ($outputType) {
+ case self::GRAPH_OUTPUT_FILE:
+ if ($idGoal != '') {
+ $idGoal = '_' . $idGoal;
+ }
+ $fileName = self::$DEFAULT_PARAMETERS[$graphType][self::FILENAME_KEY] . '_' . $apiModule . '_' . $apiAction . $idGoal . ' ' . str_replace(',', '-', $date) . ' ' . $idSite . '.png';
+ $fileName = str_replace(array(' ', '/'), '_', $fileName);
+
+ if (!Piwik_Common::isValidFilename($fileName)) {
+ throw new Exception('Error: Image graph filename ' . $fileName . ' is not valid.');
+ }
+
+ return $graph->sendToDisk($fileName);
+
+ case self::GRAPH_OUTPUT_PHP:
+ return $graph->getRenderedImage();
+
+ case self::GRAPH_OUTPUT_INLINE:
+ default:
+ $graph->sendToBrowser();
+ exit;
+ }
+ }
+
+ private function setFilterTruncate($default)
+ {
+ $_GET['filter_truncate'] = Piwik_Common::getRequestVar('filter_truncate', $default, 'int');
+ }
+
+ private static function parseOrdinateValue($ordinateValue)
+ {
+ $ordinateValue = @str_replace(',', '.', $ordinateValue);
+
+ // convert hh:mm:ss formatted time values to number of seconds
+ if (preg_match('/([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})/', $ordinateValue, $matches)) {
+ $hour = $matches[1];
+ $min = $matches[2];
+ $sec = $matches[3];
+
+ $ordinateValue = ($hour * 3600) + ($min * 60) + $sec;
+ }
+
+ // OK, only numbers from here please (strip out currency sign)
+ $ordinateValue = preg_replace('/[^0-9.]/', '', $ordinateValue);
+ return $ordinateValue;
+ }
+
+ private static function getFontPath($font)
+ {
+ return PIWIK_INCLUDE_PATH . self::FONT_DIR . $font;
+ }
+
+ protected static function getAbsoluteLogoPath($relativeLogoPath)
+ {
+ return PIWIK_INCLUDE_PATH . '/' . $relativeLogoPath;
+ }
}