diff options
author | Thomas Steur <thomas.steur@googlemail.com> | 2014-09-30 09:37:32 +0400 |
---|---|---|
committer | Thomas Steur <thomas.steur@googlemail.com> | 2014-09-30 09:37:32 +0400 |
commit | a00487b0b841c4b15463b591c7f62176c4b84d15 (patch) | |
tree | 6eb893ce356a4740e044c9cdadaf84ffb2095b9d /core | |
parent | 0edef3332289a7cbe54b58084b967907d1086d29 (diff) |
coding style fixes, some PHPStorm inspection fixes, improved readability of code, few refactorings, all as part of our code cleanup strategy
Diffstat (limited to 'core')
155 files changed, 1439 insertions, 935 deletions
diff --git a/core/API/DataTableManipulator.php b/core/API/DataTableManipulator.php index 69dc62063b..30513daaf3 100644 --- a/core/API/DataTableManipulator.php +++ b/core/API/DataTableManipulator.php @@ -141,6 +141,7 @@ abstract class DataTableManipulator /** * Extract the API method for loading subtables from the meta data * + * @throws Exception * @return string */ private function getApiMethodForSubtable() @@ -148,7 +149,7 @@ abstract class DataTableManipulator if (!$this->apiMethodForSubtable) { $meta = API::getInstance()->getMetadata('all', $this->apiModule, $this->apiMethod); - if(empty($meta)) { + if (empty($meta)) { throw new Exception(sprintf( "The DataTable cannot be manipulated: Metadata for report %s.%s could not be found. You can define the metadata in a hook, see example at: http://developer.piwik.org/api-reference/events#apigetreportmetadata", $this->apiModule, $this->apiMethod diff --git a/core/API/DataTableManipulator/Flattener.php b/core/API/DataTableManipulator/Flattener.php index 211af52d2b..cfee16e6ba 100644 --- a/core/API/DataTableManipulator/Flattener.php +++ b/core/API/DataTableManipulator/Flattener.php @@ -127,6 +127,7 @@ class Flattener extends DataTableManipulator * Remove the flat parameter from the subtable request * * @param array $request + * @return array */ protected function manipulateSubtableRequest($request) { diff --git a/core/API/DataTableManipulator/ReportTotalsCalculator.php b/core/API/DataTableManipulator/ReportTotalsCalculator.php index 1dc3bc85d9..1cbfeeb362 100644 --- a/core/API/DataTableManipulator/ReportTotalsCalculator.php +++ b/core/API/DataTableManipulator/ReportTotalsCalculator.php @@ -194,6 +194,7 @@ class ReportTotalsCalculator extends DataTableManipulator * Make sure to get all rows of the first level table. * * @param array $request + * @return array */ protected function manipulateSubtableRequest($request) { diff --git a/core/API/DocumentationGenerator.php b/core/API/DocumentationGenerator.php index 668f97bb60..63ae943433 100644 --- a/core/API/DocumentationGenerator.php +++ b/core/API/DocumentationGenerator.php @@ -47,8 +47,8 @@ class DocumentationGenerator if (!empty($prefixUrls)) { $prefixUrls = 'http://demo.piwik.org/'; } + $str = $toc = ''; - $token_auth = "&token_auth=" . Piwik::getCurrentUserTokenAuth(); $parametersToSet = array( 'idSite' => Common::getRequestVar('idSite', 1, 'int'), 'period' => Common::getRequestVar('period', 'day', 'string'), @@ -57,52 +57,38 @@ class DocumentationGenerator foreach (Proxy::getInstance()->getMetadata() as $class => $info) { $moduleName = Proxy::getInstance()->getModuleNameFromClassName($class); + if (in_array($moduleName, $this->modulesToHide)) { continue; } + $toc .= "<a href='#$moduleName'>$moduleName</a><br/>"; - $str .= "\n<a name='$moduleName' id='$moduleName'></a><h2>Module " . $moduleName . "</h2>"; - $str .= "<div class='apiDescription'> " . $info['__documentation'] . " </div>"; - foreach ($info as $methodName => $infoMethod) { - if ($methodName == '__documentation') { - continue; - } - $params = $this->getParametersString($class, $methodName); - $str .= "\n <div class='apiMethod'>- <b>$moduleName.$methodName </b>" . $params . ""; - $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)) { - $exampleUrlRss = $prefixUrls . $this->getExampleUrl($class, $methodName, array('date' => 'last10', 'period' => 'day') + $parametersToSet); - $lastNUrls = ", RSS of the last <a target=_blank href='$exampleUrlRss&format=rss$token_auth&translateColumnNames=1'>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=JSON$token_auth'>Json</a>, - <a target=_blank href='$exampleUrl&format=Tsv$token_auth&translateColumnNames=1'>Tsv (Excel)</a> - $lastNUrls - ]"; - } else { - $str .= " [ No example available ]"; - } - $str .= "</span>"; - } - $str .= '</small>'; - $str .= "</div>\n"; - } - $str .= '<div style="margin:15px;"><a href="#topApiRef">↑ Back to top</a></div>'; + $str .= $this->getInterfaceString($moduleName, $class, $info, $parametersToSet, $outputExampleUrls, $prefixUrls); } $str = "<h2 id='topApiRef' name='topApiRef'>Quick access to APIs</h2> $toc $str"; + + return $str; + } + + private function getInterfaceString($moduleName, $class, $info, $parametersToSet, $outputExampleUrls, $prefixUrls) + { + $str = ''; + + $str .= "\n<a name='$moduleName' id='$moduleName'></a><h2>Module " . $moduleName . "</h2>"; + $str .= "<div class='apiDescription'> " . $info['__documentation'] . " </div>"; + foreach ($info as $methodName => $infoMethod) { + if ($methodName == '__documentation') { + continue; + } + + $str .= $this->getMethodString($moduleName, $class, $parametersToSet, $outputExampleUrls, $prefixUrls, $methodName, $str); + } + + $str .= '<div style="margin:15px;"><a href="#topApiRef">↑ Back to top</a></div>'; + return $str; } @@ -241,4 +227,43 @@ class DocumentationGenerator $sParameters = implode(", ", $asParameters); return "($sParameters)"; } + + private function getMethodString($moduleName, $class, $parametersToSet, $outputExampleUrls, $prefixUrls, $methodName) + { + $str = ''; + $token_auth = "&token_auth=" . Piwik::getCurrentUserTokenAuth(); + + $params = $this->getParametersString($class, $methodName); + $str .= "\n <div class='apiMethod'>- <b>$moduleName.$methodName </b>" . $params . ""; + $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)) { + $exampleUrlRss = $prefixUrls . $this->getExampleUrl($class, $methodName, array('date' => 'last10', 'period' => 'day') + $parametersToSet); + $lastNUrls = ", RSS of the last <a target=_blank href='$exampleUrlRss&format=rss$token_auth&translateColumnNames=1'>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=JSON$token_auth'>Json</a>, + <a target=_blank href='$exampleUrl&format=Tsv$token_auth&translateColumnNames=1'>Tsv (Excel)</a> + $lastNUrls + ]"; + } else { + $str .= " [ No example available ]"; + } + $str .= "</span>"; + } + + $str .= '</small>'; + $str .= "</div>\n"; + + return $str; + } } diff --git a/core/API/Proxy.php b/core/API/Proxy.php index d3e1fbad3f..daaa5c9f42 100644 --- a/core/API/Proxy.php +++ b/core/API/Proxy.php @@ -24,7 +24,7 @@ use ReflectionMethod; * * It will also log the performance of API calls (time spent, parameter values, etc.) if logger available * - * @method static \Piwik\API\Proxy getInstance() + * @method static Proxy getInstance() */ class Proxy extends Singleton { diff --git a/core/API/Request.php b/core/API/Request.php index 03b555ad18..64e8e054fa 100644 --- a/core/API/Request.php +++ b/core/API/Request.php @@ -70,7 +70,7 @@ use Piwik\Log; */ class Request { - protected $request = null; + private $request = null; /** * Converts the supplied request string into an array of query paramater name/value diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php index 17d5d488f7..401dccf96c 100644 --- a/core/API/ResponseBuilder.php +++ b/core/API/ResponseBuilder.php @@ -18,7 +18,6 @@ use Piwik\DataTable\Filter\PivotByDimension; use Piwik\DataTable\Renderer; use Piwik\DataTable\DataTableInterface; use Piwik\DataTable\Filter\ColumnDelete; -use Piwik\Piwik; /** */ @@ -158,7 +157,7 @@ class ResponseBuilder return Renderer::formatValueXml($message); } - protected function handleDataTable(DataTableInterface $datatable) + private function handleDataTable(DataTableInterface $datatable) { $label = $this->getLabelFromRequest($this->request); @@ -224,7 +223,7 @@ class ResponseBuilder return $this->apiRenderer->renderDataTable($datatable); } - protected function handleArray($array) + private function handleArray($array) { $firstArray = null; $firstKey = null; diff --git a/core/Access.php b/core/Access.php index 00093e6e4f..d18310cb5b 100644 --- a/core/Access.php +++ b/core/Access.php @@ -33,29 +33,6 @@ use Piwik\Db; */ class Access { - private static $instance = null; - - /** - * Gets the singleton instance. Creates it if necessary. - */ - public static function getInstance() - { - if (self::$instance == null) { - self::$instance = new self; - - Piwik::postEvent('Access.createAccessSingleton', array(&self::$instance)); - } - return self::$instance; - } - - /** - * Sets the singleton instance. For testing purposes. - */ - public static function setSingletonInstance($instance) - { - self::$instance = $instance; - } - /** * Array of idsites available to the current user, indexed by permission level * @see getSitesIdWith*() @@ -100,6 +77,29 @@ class Access */ private $auth = null; + private static $instance = null; + + /** + * Gets the singleton instance. Creates it if necessary. + */ + public static function getInstance() + { + if (self::$instance == null) { + self::$instance = new self; + + Piwik::postEvent('Access.createAccessSingleton', array(&self::$instance)); + } + return self::$instance; + } + + /** + * Sets the singleton instance. For testing purposes. + */ + public static function setSingletonInstance($instance) + { + self::$instance = $instance; + } + /** * Returns the list of the existing Access level. * Useful when a given API method requests a given acccess Level. @@ -146,6 +146,7 @@ class Access if ($this->hasSuperUserAccess()) { return $this->reloadAccessSuperUser(); } + return false; } @@ -155,6 +156,7 @@ class Access if (!$result->wasAuthenticationSuccessful()) { return false; } + $this->login = $result->getIdentity(); $this->token_auth = $result->getTokenAuth(); @@ -162,21 +164,26 @@ class Access if ($result->hasSuperUserAccess()) { return $this->reloadAccessSuperUser(); } + // in case multiple calls to API using different tokens, we ensure we reset it as not SU $this->setSuperUserAccess(false); // we join with site in case there are rows in access for an idsite that doesn't exist anymore // (backward compatibility ; before we deleted the site without deleting rows in _access table) $accessRaw = $this->getRawSitesWithSomeViewAccess($this->login); + foreach ($accessRaw as $access) { $this->idsitesByAccess[$access['access']][] = $access['idsite']; } + return true; } public function getRawSitesWithSomeViewAccess($login) { - return Db::fetchAll(self::getSqlAccessSite("access, t2.idsite"), $login); + $sql = self::getSqlAccessSite("access, t2.idsite"); + + return Db::fetchAll($sql, $login); } /** @@ -187,10 +194,11 @@ class Access */ public static function getSqlAccessSite($select) { - return "SELECT " . $select . " - FROM " . Common::prefixTable('access') . " as t1 - JOIN " . Common::prefixTable('site') . " as t2 USING (idsite) " . - " WHERE login = ?"; + $access = Common::prefixTable('access'); + $siteTable = Common::prefixTable('site'); + + return "SELECT " . $select . " FROM " . $access . " as t1 + JOIN " . $siteTable . " as t2 USING (idsite) WHERE login = ?"; } /** @@ -323,7 +331,9 @@ class Access if ($this->hasSuperUserAccess()) { return; } + $idSitesAccessible = $this->getSitesIdWithAdminAccess(); + if (count($idSitesAccessible) == 0) { throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('admin'))); } @@ -339,7 +349,9 @@ class Access if ($this->hasSuperUserAccess()) { return; } + $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess(); + if (count($idSitesAccessible) == 0) { throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('view'))); } @@ -357,8 +369,10 @@ class Access if ($this->hasSuperUserAccess()) { return; } + $idSites = $this->getIdSites($idSites); $idSitesAccessible = $this->getSitesIdWithAdminAccess(); + foreach ($idSites as $idsite) { if (!in_array($idsite, $idSitesAccessible)) { throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'admin'", $idsite))); @@ -378,8 +392,10 @@ class Access if ($this->hasSuperUserAccess()) { return; } + $idSites = $this->getIdSites($idSites); $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess(); + foreach ($idSites as $idsite) { if (!in_array($idsite, $idSitesAccessible)) { throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'view'", $idsite))); @@ -399,9 +415,11 @@ class Access } $idSites = Site::getIdSitesFromIdSitesString($idSites); + if (empty($idSites)) { throw new NoAccessException("The parameter 'idSite=' is missing from the request."); } + return $idSites; } } diff --git a/core/Archive.php b/core/Archive.php index 65b5b91532..7101850c1d 100644 --- a/core/Archive.php +++ b/core/Archive.php @@ -197,18 +197,23 @@ class Archive { $websiteIds = Site::getIdSitesFromIdSitesString($idSites, $_restrictSitesToLogin); - $timezone = count($websiteIds) == 1 ? Site::getTimezoneFor($websiteIds[0]) : false; + $timezone = false; + if (count($websiteIds) == 1) { + $timezone = Site::getTimezoneFor($websiteIds[0]); + } if (Period::isMultiplePeriod($strDate, $period)) { - $oPeriod = PeriodFactory::build($period, $strDate, $timezone); + $oPeriod = PeriodFactory::build($period, $strDate, $timezone); $allPeriods = $oPeriod->getSubperiods(); } else { - $oPeriod = PeriodFactory::makePeriodFromQueryParams($timezone, $period, $strDate); + $oPeriod = PeriodFactory::makePeriodFromQueryParams($timezone, $period, $strDate); $allPeriods = array($oPeriod); } - $segment = new Segment($segment, $websiteIds); - $idSiteIsAll = $idSites == self::REQUEST_ALL_WEBSITES_FLAG; + + $segment = new Segment($segment, $websiteIds); + $idSiteIsAll = $idSites == self::REQUEST_ALL_WEBSITES_FLAG; $isMultipleDate = Period::isMultiplePeriod($strDate, $period); + return Archive::factory($segment, $allPeriods, $websiteIds, $idSiteIsAll, $isMultipleDate, $skipAggregationOfSubTables); } @@ -239,9 +244,11 @@ class Archive { $forceIndexedBySite = false; $forceIndexedByDate = false; + if ($idSiteIsAll || count($idSites) > 1) { $forceIndexedBySite = true; } + if (count($periods) > 1 || $isMultipleDate) { $forceIndexedByDate = true; } @@ -265,7 +272,7 @@ class Archive * * @param string|array $names One or more archive names, eg, `'nb_visits'`, `'Referrers_distinctKeywords'`, * etc. - * @return false|numeric|array `false` if there is no data to return, a single numeric value if we're not querying + * @return false|integer|array `false` if there is no data to return, a single numeric value if we're not querying * for multiple sites/periods, or an array if multiple sites, periods or names are * queried for. */ @@ -406,9 +413,11 @@ class Archive private function getRequestedPlugins($archiveNames) { $result = array(); + foreach ($archiveNames as $name) { $result[] = self::getPluginForReport($name); } + return array_unique($result); } @@ -436,6 +445,7 @@ class Archive * @param int|null $idSubtable See {@link getDataTableExpanded()} * @param bool $skipAggregationOfSubTables Whether or not we should skip the aggregation of all sub-tables and only aggregate parent DataTable. * @param int|null $depth See {@link getDataTableExpanded()} + * @throws \Exception * @return DataTable|DataTable\Map See {@link getDataTable()} and * {@link getDataTableExpanded()} for more * information @@ -445,9 +455,10 @@ class Archive { Piwik::checkUserHasViewAccess($idSite); - if($skipAggregationOfSubTables && ($expanded || $idSubtable)) { + if ($skipAggregationOfSubTables && ($expanded || $idSubtable)) { throw new \Exception("Not expected to skipAggregationOfSubTables when expanded=1 or idSubtable is set."); } + $archive = Archive::build($idSite, $period, $date, $segment, $_restrictSitesToLogin = false, $skipAggregationOfSubTables); if ($idSubtable === false) { $idSubtable = null; @@ -495,6 +506,7 @@ class Archive $archiveNames, $archiveDataType, $this->params->getIdSites(), $this->params->getPeriods(), $defaultRow = null); $archiveIds = $this->getArchiveIds($archiveNames); + if (empty($archiveIds)) { return $result; } @@ -532,7 +544,7 @@ class Archive // figure out which archives haven't been processed (if an archive has been processed, // then we have the archive IDs in $this->idarchives) - $doneFlags = array(); + $doneFlags = array(); $archiveGroups = array(); foreach ($plugins as $plugin) { $doneFlag = $this->getDoneStringForPlugin($plugin); @@ -541,7 +553,7 @@ class Archive if (!isset($this->idarchives[$doneFlag])) { $archiveGroup = $this->getArchiveGroupOfPlugin($plugin); - if($archiveGroup == self::ARCHIVE_ALL_PLUGINS_FLAG) { + if ($archiveGroup == self::ARCHIVE_ALL_PLUGINS_FLAG) { $archiveGroup = reset($plugins); } $archiveGroups[] = $archiveGroup; @@ -559,19 +571,7 @@ class Archive } } - // order idarchives by the table month they belong to - $idArchivesByMonth = array(); - foreach (array_keys($doneFlags) as $doneFlag) { - if (empty($this->idarchives[$doneFlag])) { - continue; - } - - foreach ($this->idarchives[$doneFlag] as $dateRange => $idarchives) { - foreach ($idarchives as $id) { - $idArchivesByMonth[$dateRange][] = $id; - } - } - } + $idArchivesByMonth = $this->getIdArchivesByMonth($doneFlags); return $idArchivesByMonth; } @@ -800,9 +800,29 @@ class Archive $idArchive = $archiveLoader->prepareArchive($plugin); - if($idArchive) { + if ($idArchive) { $this->idarchives[$doneFlag][$periodString][] = $idArchive; } } } + + private function getIdArchivesByMonth($doneFlags) + { + // order idarchives by the table month they belong to + $idArchivesByMonth = array(); + + foreach (array_keys($doneFlags) as $doneFlag) { + if (empty($this->idarchives[$doneFlag])) { + continue; + } + + foreach ($this->idarchives[$doneFlag] as $dateRange => $idarchives) { + foreach ($idarchives as $id) { + $idArchivesByMonth[$dateRange][] = $id; + } + } + } + + return $idArchivesByMonth; + } } diff --git a/core/Archive/DataCollection.php b/core/Archive/DataCollection.php index 89b435f9dc..efd63cd925 100644 --- a/core/Archive/DataCollection.php +++ b/core/Archive/DataCollection.php @@ -188,6 +188,7 @@ class DataCollection $this->putRowInIndex($result, $indexKeys, $row, $idSite, $period); } } + return $result; } @@ -208,6 +209,7 @@ class DataCollection $this->dataNames, $this->dataType, $this->sitesId, $this->periods, $this->defaultRow); $index = $this->getIndexedArray($resultIndices); + return $dataTableFactory->make($index, $resultIndices); } @@ -249,6 +251,7 @@ class DataCollection $dataTableFactory->useSubtable($idSubTable); $index = $this->getIndexedArray($resultIndices); + return $dataTableFactory->make($index, $resultIndices); } diff --git a/core/Archive/DataTableFactory.php b/core/Archive/DataTableFactory.php index 41806c62f9..71eaa7a8c1 100644 --- a/core/Archive/DataTableFactory.php +++ b/core/Archive/DataTableFactory.php @@ -154,6 +154,7 @@ class DataTableFactory } $this->transformMetadata($dataTable); + return $dataTable; } diff --git a/core/ArchiveProcessor.php b/core/ArchiveProcessor.php index 2df309d69c..71e90cde23 100644 --- a/core/ArchiveProcessor.php +++ b/core/ArchiveProcessor.php @@ -79,12 +79,12 @@ class ArchiveProcessor /** * @var \Piwik\DataAccess\ArchiveWriter */ - protected $archiveWriter; + private $archiveWriter; /** * @var \Piwik\DataAccess\LogAggregator */ - protected $logAggregator; + private $logAggregator; /** * @var Archive @@ -94,14 +94,14 @@ class ArchiveProcessor /** * @var Parameters */ - protected $params; + private $params; /** * @var int */ - protected $numberOfVisits = false; + private $numberOfVisits = false; - protected $numberOfVisitsConverted = false; + private $numberOfVisitsConverted = false; /** * If true, unique visitors are not calculated when we are aggregating data for multiple sites. @@ -125,11 +125,12 @@ class ArchiveProcessor protected function getArchive() { - if(empty($this->archive)) { + if (empty($this->archive)) { $subPeriods = $this->params->getSubPeriods(); - $idSites = $this->params->getIdSites(); + $idSites = $this->params->getIdSites(); $this->archive = Archive::factory($this->params->getSegment(), $subPeriods, $idSites); } + return $this->archive; } @@ -208,6 +209,7 @@ class ArchiveProcessor if (!is_array($recordNames)) { $recordNames = array($recordNames); } + $nameToCount = array(); foreach ($recordNames as $recordName) { $latestUsedTableId = Manager::getInstance()->getMostRecentTableId(); @@ -218,7 +220,7 @@ class ArchiveProcessor $nameToCount[$recordName]['level0'] = $rowsCount; $rowsCountRecursive = $rowsCount; - if($this->isAggregateSubTables()) { + if ($this->isAggregateSubTables()) { $rowsCountRecursive = $table->getRowsCountRecursive(); } $nameToCount[$recordName]['recursive'] = $rowsCountRecursive; @@ -271,7 +273,7 @@ class ArchiveProcessor public function getNumberOfVisits() { - if($this->numberOfVisits === false) { + if ($this->numberOfVisits === false) { throw new Exception("visits should have been set here"); } return $this->numberOfVisits; @@ -343,7 +345,7 @@ class ArchiveProcessor */ protected function aggregateDataTableRecord($name, $columnsAggregationOperation = null, $columnsToRenameAfterAggregation = null) { - if($this->isAggregateSubTables()) { + if ($this->isAggregateSubTables()) { // By default we shall aggregate all sub-tables. $dataTable = $this->getArchive()->getDataTableExpanded($name, $idSubTable = null, $depth = null, $addMetadataSubtableId = false); } else { @@ -440,15 +442,18 @@ class ArchiveProcessor protected function getAggregatedDataTableMap($data, $columnsAggregationOperation) { $table = new DataTable(); + if (!empty($columnsAggregationOperation)) { $table->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, $columnsAggregationOperation); } + if ($data instanceof DataTable\Map) { // as $date => $tableToSum $this->aggregatedDataTableMapsAsOne($data, $table); } else { $table->addDataTable($data, $this->isAggregateSubTables()); } + return $table; } @@ -460,7 +465,7 @@ class ArchiveProcessor protected function aggregatedDataTableMapsAsOne(Map $map, DataTable $aggregated) { foreach ($map->getDataTables() as $tableToAggregate) { - if($tableToAggregate instanceof Map) { + if ($tableToAggregate instanceof Map) { $this->aggregatedDataTableMapsAsOne($tableToAggregate, $aggregated); } else { $aggregated->addDataTable($tableToAggregate, $this->isAggregateSubTables()); @@ -477,6 +482,7 @@ class ArchiveProcessor if (is_null($columnsToRenameAfterAggregation)) { $columnsToRenameAfterAggregation = self::$columnsToRenameAfterAggregation; } + foreach ($columnsToRenameAfterAggregation as $oldName => $newName) { $table->renameColumn($oldName, $newName, $this->isAggregateSubTables()); } @@ -487,6 +493,7 @@ class ArchiveProcessor if (!is_array($columns)) { $columns = array($columns); } + $operationForColumn = $this->getOperationForColumns($columns, $operationToApply); $dataTable = $this->getArchive()->getDataTableFromNumeric($columns); @@ -497,7 +504,7 @@ class ArchiveProcessor } $rowMetrics = $results->getFirstRow(); - if($rowMetrics === false) { + if ($rowMetrics === false) { $rowMetrics = new Row; } $this->enrichWithUniqueVisitorsMetric($rowMetrics); @@ -510,6 +517,7 @@ class ArchiveProcessor $metrics[$name] = 0; } } + return $metrics; } diff --git a/core/ArchiveProcessor/Loader.php b/core/ArchiveProcessor/Loader.php index a4ffa4d12e..b684d8fee1 100644 --- a/core/ArchiveProcessor/Loader.php +++ b/core/ArchiveProcessor/Loader.php @@ -10,7 +10,6 @@ namespace Piwik\ArchiveProcessor; use Piwik\Archive; use Piwik\ArchiveProcessor; use Piwik\Config; -use Piwik\DataAccess\ArchivePurger; use Piwik\DataAccess\ArchiveSelector; use Piwik\Date; use Piwik\Period; @@ -82,6 +81,7 @@ class Loader * Prepares the core metrics if needed. * * @param $visits + * @return array */ protected function prepareCoreMetricsArchive($visits, $visitsConverted) { @@ -102,12 +102,14 @@ class Loader $visits = $metrics['nb_visits']; $visitsConverted = $metrics['nb_visits_converted']; } + return array($visits, $visitsConverted); } protected function prepareAllPluginsArchive($visits, $visitsConverted) { $pluginsArchiver = new PluginsArchiver($this->params, $this->isArchiveTemporary()); + if ($this->mustProcessVisitCount($visits) || $this->doesRequestedPluginIncludeVisitsSummary() ) { @@ -115,9 +117,11 @@ class Loader $visits = $metrics['nb_visits']; $visitsConverted = $metrics['nb_visits_converted']; } + if ($this->isThereSomeVisits($visits)) { $pluginsArchiver->callAggregateAllPlugins($visits, $visitsConverted); } + $idArchive = $pluginsArchiver->finalizeArchive(); return array($idArchive, $visits); @@ -136,11 +140,13 @@ class Loader { $period = $this->params->getPeriod()->getLabel(); $debugSetting = 'always_archive_data_period'; // default + if ($period == 'day') { $debugSetting = 'always_archive_data_day'; } elseif ($period == 'range') { $debugSetting = 'always_archive_data_range'; } + return (bool) Config::getInstance()->Debug[$debugSetting]; } @@ -162,9 +168,11 @@ class Loader } $idAndVisits = ArchiveSelector::getArchiveIdAndVisits($this->params, $minDatetimeArchiveProcessedUTC); + if (!$idAndVisits) { return $noArchiveFound; } + return $idAndVisits; } @@ -183,19 +191,27 @@ class Loader // Permanent archive return $endDateTimestamp; } + + $dateStart = $this->params->getDateStart(); + $period = $this->params->getPeriod(); + $segment = $this->params->getSegment(); + $site = $this->params->getSite(); + // Temporary archive - return Rules::getMinTimeProcessedForTemporaryArchive($this->params->getDateStart(), $this->params->getPeriod(), $this->params->getSegment(), $this->params->getSite()); + return Rules::getMinTimeProcessedForTemporaryArchive($dateStart, $period, $segment, $site); } protected static function determineIfArchivePermanent(Date $dateEnd) { $now = time(); $endTimestampUTC = strtotime($dateEnd->getDateEndUTC()); + if ($endTimestampUTC <= $now) { // - if the period we are looking for is finished, we look for a ts_archived that // is greater than the last day of the archive return $endTimestampUTC; } + return false; } @@ -204,6 +220,7 @@ class Loader if (is_null($this->temporaryArchive)) { throw new \Exception("getMinTimeArchiveProcessed() should be called prior to isArchiveTemporary()"); } + return $this->temporaryArchive; } diff --git a/core/ArchiveProcessor/Parameters.php b/core/ArchiveProcessor/Parameters.php index 79cb1c7196..1528d8210c 100644 --- a/core/ArchiveProcessor/Parameters.php +++ b/core/ArchiveProcessor/Parameters.php @@ -91,7 +91,7 @@ class Parameters */ public function getSubPeriods() { - if($this->getPeriod()->getLabel() == 'day') { + if ($this->getPeriod()->getLabel() == 'day') { return array( $this->getPeriod() ); } return $this->getPeriod()->getSubperiods(); diff --git a/core/ArchiveProcessor/PluginsArchiver.php b/core/ArchiveProcessor/PluginsArchiver.php index 10f61287ed..2986d05dd3 100644 --- a/core/ArchiveProcessor/PluginsArchiver.php +++ b/core/ArchiveProcessor/PluginsArchiver.php @@ -56,7 +56,7 @@ class PluginsArchiver */ public function callAggregateCoreMetrics() { - if($this->isSingleSiteDayArchive) { + if ($this->isSingleSiteDayArchive) { $metrics = $this->aggregateDayVisitsMetrics(); } else { $metrics = $this->aggregateMultipleVisitsMetrics(); @@ -92,11 +92,11 @@ class PluginsArchiver /** @var Archiver $archiver */ $archiver = new $archiverClass($this->archiveProcessor); - if(!$archiver->isEnabled()) { + if (!$archiver->isEnabled()) { continue; } - if($this->shouldProcessReportsForPlugin($pluginName)) { - if($this->isSingleSiteDayArchive) { + if ($this->shouldProcessReportsForPlugin($pluginName)) { + if ($this->isSingleSiteDayArchive) { $archiver->aggregateDayReport(); } else { $archiver->aggregateMultipleReports(); diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php index a64a4f81ad..c4a672d3ac 100644 --- a/core/ArchiveProcessor/Rules.php +++ b/core/ArchiveProcessor/Rules.php @@ -222,7 +222,7 @@ class Rules { $uiSettingIsEnabled = Controller::isGeneralSettingsAdminEnabled(); - if($uiSettingIsEnabled) { + if ($uiSettingIsEnabled) { $timeToLive = Option::get(self::OPTION_TODAY_ARCHIVE_TTL); if ($timeToLive !== false) { return $timeToLive; @@ -266,7 +266,7 @@ class Rules { $uiSettingIsEnabled = Controller::isGeneralSettingsAdminEnabled(); - if($uiSettingIsEnabled) { + if ($uiSettingIsEnabled) { $browserArchivingEnabled = Option::get(self::OPTION_BROWSER_TRIGGER_ARCHIVING); if ($browserArchivingEnabled !== false) { return (bool)$browserArchivingEnabled; diff --git a/core/AssetManager.php b/core/AssetManager.php index 1badba4d9e..6759facb2b 100644 --- a/core/AssetManager.php +++ b/core/AssetManager.php @@ -37,7 +37,7 @@ use Piwik\Translate; * the global option 'disable_merged_assets'. See the documentation in the global * config for more information. * - * @method static \Piwik\AssetManager getInstance() + * @method static AssetManager getInstance() */ class AssetManager extends Singleton { @@ -72,7 +72,7 @@ class AssetManager extends Singleton $this->minimalStylesheetFetcher = new StaticUIAssetFetcher(array('plugins/Morpheus/stylesheets/base.less', 'plugins/Morpheus/stylesheets/general/_forms.less'), array(), $this->theme); $theme = Manager::getInstance()->getThemeEnabled(); - if(!empty($theme)) { + if (!empty($theme)) { $this->theme = new Theme(); } } @@ -206,7 +206,7 @@ class AssetManager extends Singleton $pluginName = $plugin->getPluginName(); $pluginIsCore = Manager::getInstance()->isPluginBundledWithCore($pluginName); - if(($pluginIsCore && $core) || (!$pluginIsCore && !$core)) + if (($pluginIsCore && $core) || (!$pluginIsCore && !$core)) $loadedPlugins[] = $pluginName; } @@ -220,12 +220,12 @@ class AssetManager extends Singleton { $assetsToRemove = array($this->getMergedStylesheetAsset()); - if($pluginName) { + if ($pluginName) { - if($this->pluginContainsJScriptAssets($pluginName)) { + if ($this->pluginContainsJScriptAssets($pluginName)) { PiwikConfig::getInstance()->init(); - if(Manager::getInstance()->isPluginBundledWithCore($pluginName)) { + if (Manager::getInstance()->isPluginBundledWithCore($pluginName)) { $assetsToRemove[] = $this->getMergedCoreJSAsset(); @@ -347,13 +347,13 @@ class AssetManager extends Singleton $plugin = Manager::getInstance()->getLoadedPlugin($pluginName); - if($plugin->isTheme()) { + if ($plugin->isTheme()) { $theme = Manager::getInstance()->getTheme($pluginName); $javaScriptFiles = $theme->getJavaScriptFiles(); - if(!empty($javaScriptFiles)) + if (!empty($javaScriptFiles)) $assets = array_merge($assets, $javaScriptFiles); } diff --git a/core/AssetManager/UIAssetCatalog.php b/core/AssetManager/UIAssetCatalog.php index d8a45f8964..826259ecb3 100644 --- a/core/AssetManager/UIAssetCatalog.php +++ b/core/AssetManager/UIAssetCatalog.php @@ -40,7 +40,7 @@ class UIAssetCatalog { $location = $uiAsset->getAbsoluteLocation(); - if(!$this->assetAlreadyInCatalog($location)) { + if (!$this->assetAlreadyInCatalog($location)) { $this->existingAssetLocations[] = $location; $this->uiAssets[] = $uiAsset; } diff --git a/core/AssetManager/UIAssetFetcher.php b/core/AssetManager/UIAssetFetcher.php index 955ced51a7..3bd34c118e 100644 --- a/core/AssetManager/UIAssetFetcher.php +++ b/core/AssetManager/UIAssetFetcher.php @@ -56,7 +56,7 @@ abstract class UIAssetFetcher */ public function getCatalog() { - if($this->catalog == null) + if ($this->catalog == null) $this->createCatalog(); return $this->catalog; diff --git a/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php b/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php index a5ab3d096d..5600068e44 100644 --- a/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php +++ b/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php @@ -18,7 +18,7 @@ class JScriptUIAssetFetcher extends UIAssetFetcher protected function retrieveFileLocations() { - if(!empty($this->plugins)) { + if (!empty($this->plugins)) { /** * Triggered when gathering the list of all JavaScript files needed by Piwik @@ -53,14 +53,14 @@ class JScriptUIAssetFetcher extends UIAssetFetcher protected function addThemeFiles() { $theme = $this->getTheme(); - if(!$theme) { + if (!$theme) { return; } - if(in_array($theme->getThemeName(), $this->plugins)) { + if (in_array($theme->getThemeName(), $this->plugins)) { $jsInThemes = $this->getTheme()->getJavaScriptFiles(); - if(!empty($jsInThemes)) { + if (!empty($jsInThemes)) { foreach($jsInThemes as $jsFile) { diff --git a/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php b/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php index 47a78a47ca..47ac94d04b 100644 --- a/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php +++ b/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php @@ -18,7 +18,6 @@ class StylesheetUIAssetFetcher extends UIAssetFetcher $theme = $this->getTheme(); $themeName = $theme->getThemeName(); - $themeName = $this->getTheme()->getThemeName(); $order = array( 'libs/', 'plugins/CoreHome/stylesheets/color_manager.css', // must be before other Piwik stylesheets @@ -72,7 +71,7 @@ class StylesheetUIAssetFetcher extends UIAssetFetcher protected function addThemeFiles() { $theme = $this->getTheme(); - if(!$theme) { + if (!$theme) { return; } $themeStylesheet = $this->getTheme()->getStylesheet(); diff --git a/core/AssetManager/UIAssetMerger.php b/core/AssetManager/UIAssetMerger.php index 8850de512b..42b5ce0cfe 100644 --- a/core/AssetManager/UIAssetMerger.php +++ b/core/AssetManager/UIAssetMerger.php @@ -48,7 +48,7 @@ abstract class UIAssetMerger public function generateFile() { - if(!$this->shouldGenerate()) + if (!$this->shouldGenerate()) return; $this->mergedContent = $this->getMergedAssets(); @@ -138,8 +138,9 @@ abstract class UIAssetMerger */ private function shouldGenerate() { - if(!$this->mergedAsset->exists()) + if (!$this->mergedAsset->exists()) { return true; + } return !$this->isFileUpToDate(); } @@ -162,19 +163,11 @@ abstract class UIAssetMerger return false; } - /** - * @return boolean - */ - private function isMergedAssetsDisabled() - { - return AssetManager::getInstance()->isMergedAssetsDisabled(); - } - private function adjustPaths() { $theme = $this->assetFetcher->getTheme(); // During installation theme is not yet ready - if($theme) { + if ($theme) { $this->mergedContent = $this->assetFetcher->getTheme()->rewriteAssetsPathToTheme($this->mergedContent); } } @@ -189,7 +182,7 @@ abstract class UIAssetMerger */ protected function getCacheBusterValue() { - if(empty($this->cacheBusterValue)) + if (empty($this->cacheBusterValue)) $this->cacheBusterValue = $this->generateCacheBuster(); return $this->cacheBusterValue; @@ -199,12 +192,4 @@ abstract class UIAssetMerger { $this->mergedContent = $this->getPreamble() . $this->mergedContent; } - - /** - * @return boolean - */ - private function shouldCompareExistingVersion() - { - return $this->isMergedAssetsDisabled(); - } } diff --git a/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php b/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php index bfb2442279..935018c580 100644 --- a/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php +++ b/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php @@ -57,7 +57,7 @@ class JScriptUIAssetMerger extends UIAssetMerger { $plugins = $this->getPlugins(); - if(!empty($plugins)) { + if (!empty($plugins)) { /** * Triggered after all the JavaScript files Piwik uses are minified and merged into a diff --git a/core/AssetManager/UIAssetMinifier.php b/core/AssetManager/UIAssetMinifier.php index 5f738092cc..07dd3c769d 100644 --- a/core/AssetManager/UIAssetMinifier.php +++ b/core/AssetManager/UIAssetMinifier.php @@ -36,6 +36,7 @@ class UIAssetMinifier extends Singleton public function isMinifiedJs($content) { $lineCount = substr_count($content, "\n"); + if ($lineCount == 0) { return true; } diff --git a/core/BaseFactory.php b/core/BaseFactory.php index 6f09f952ef..0bc8716eb2 100644 --- a/core/BaseFactory.php +++ b/core/BaseFactory.php @@ -9,7 +9,6 @@ namespace Piwik; use Exception; -use Piwik\Common; /** * Base class for all factory types. diff --git a/core/CacheFile.php b/core/CacheFile.php index 9eb0587595..48a23004bf 100644 --- a/core/CacheFile.php +++ b/core/CacheFile.php @@ -25,11 +25,7 @@ class CacheFile /** * @var string */ - protected $cachePath; - /** - * @var - */ - protected $cachePrefix; + private $cachePath; /** * Minimum enforced TTL in seconds @@ -67,11 +63,12 @@ class CacheFile if (empty($id)) { return false; } + $id = $this->cleanupId($id); $cache_complete = false; - $content = ''; - $expires_on = false; + $content = ''; + $expires_on = false; // We are assuming that most of the time cache will exists $cacheFilePath = $this->cachePath . $id . '.php'; @@ -88,6 +85,7 @@ class CacheFile ) { return false; } + return $content; } @@ -104,6 +102,7 @@ class CacheFile if (!Filesystem::isValidFilename($id)) { throw new Exception("Invalid cache ID request $id"); } + return $id; } @@ -120,25 +119,23 @@ class CacheFile if (empty($id)) { return false; } + if (!is_dir($this->cachePath)) { Filesystem::mkdir($this->cachePath); } + if (!is_writable($this->cachePath)) { return false; } - $id = $this->cleanupId($id); + $id = $this->cleanupId($id); $id = $this->cachePath . $id . '.php'; if (is_object($content)) { throw new \Exception('You cannot use the CacheFile to cache an object, only arrays, strings and numbers.'); } - $cache_literal = "<" . "?php\n"; - $cache_literal .= "$" . "content = " . var_export($content, true) . ";\n"; - $cache_literal .= "$" . "expires_on = " . $this->getExpiresTime() . ";\n"; - $cache_literal .= "$" . "cache_complete = true;\n"; - $cache_literal .= "?" . ">"; + $cache_literal = $this->buildCacheLiteral($content); // Write cache to a temp file, then rename it, overwriting the old cache // On *nix systems this should guarantee atomicity @@ -162,6 +159,7 @@ class CacheFile return true; } + return false; } @@ -176,14 +174,17 @@ class CacheFile if (empty($id)) { return false; } + $id = $this->cleanupId($id); $filename = $this->cachePath . $id . '.php'; + if (file_exists($filename)) { $this->opCacheInvalidate($filename); @unlink($filename); return true; } + return false; } @@ -218,8 +219,19 @@ class CacheFile @opcache_invalidate($filepath, $force = true); } if (function_exists('apc_delete_file')) { - apc_delete_file($filepath); + @apc_delete_file($filepath); } } } + + private function buildCacheLiteral($content) + { + $cache_literal = "<" . "?php\n"; + $cache_literal .= "$" . "content = " . var_export($content, true) . ";\n"; + $cache_literal .= "$" . "expires_on = " . $this->getExpiresTime() . ";\n"; + $cache_literal .= "$" . "cache_complete = true;\n"; + $cache_literal .= "?" . ">"; + + return $cache_literal; + } } diff --git a/core/CliMulti.php b/core/CliMulti.php index 21e0ee0b0d..6de96af5b0 100644 --- a/core/CliMulti.php +++ b/core/CliMulti.php @@ -58,13 +58,15 @@ class CliMulti { public function request(array $piwikUrls) { $chunks = array($piwikUrls); - if($this->concurrentProcessesLimit) { + if ($this->concurrentProcessesLimit) { $chunks = array_chunk( $piwikUrls, $this->concurrentProcessesLimit); } + $results = array(); foreach($chunks as $urlsChunk) { $results = array_merge($results, $this->requestUrls($urlsChunk)); } + return $results; } @@ -89,17 +91,22 @@ class CliMulti { private function start($piwikUrls) { foreach ($piwikUrls as $index => $url) { - $cmdId = $this->generateCommandId($url) . $index; - $output = new Output($cmdId); + $cmdId = $this->generateCommandId($url) . $index; + $this->executeUrlCommand($cmdId, $url); + } + } - if ($this->supportsAsync) { - $this->executeAsyncCli($url, $output, $cmdId); - } else { - $this->executeNotAsyncHttp($url, $output); - } + private function executeUrlCommand($cmdId, $url) + { + $output = new Output($cmdId); - $this->outputs[] = $output; + if ($this->supportsAsync) { + $this->executeAsyncCli($url, $output, $cmdId); + } else { + $this->executeNotAsyncHttp($url, $output); } + + $this->outputs[] = $output; } private function buildCommand($hostname, $query, $outputFile) @@ -192,7 +199,7 @@ class CliMulti { $timeOneWeekAgo = strtotime('-1 week'); $files = _glob(self::getTmpPath() . '/*'); - if(empty($files)) { + if (empty($files)) { return; } diff --git a/core/CliMulti/CliPhp.php b/core/CliMulti/CliPhp.php index df82e05376..1b164835d4 100644 --- a/core/CliMulti/CliPhp.php +++ b/core/CliMulti/CliPhp.php @@ -18,11 +18,11 @@ class CliPhp { if (defined('PHP_BINARY')) { - if($this->isValidPhpType(PHP_BINARY)) { + if ($this->isValidPhpType(PHP_BINARY)) { return PHP_BINARY . ' -q'; } - if($this->isHhvmBinary(PHP_BINARY)) { + if ($this->isHhvmBinary(PHP_BINARY)) { return PHP_BINARY . ' --php'; } } diff --git a/core/CliMulti/Process.php b/core/CliMulti/Process.php index e8dfb662a4..6c5ac165ca 100644 --- a/core/CliMulti/Process.php +++ b/core/CliMulti/Process.php @@ -154,7 +154,7 @@ class Process return false; } - if(!self::isProcFSMounted()) { + if (!self::isProcFSMounted()) { return false; } @@ -169,11 +169,11 @@ class Process { $uname = @shell_exec('uname -a'); - if(empty($uname)) { + if (empty($uname)) { $uname = php_uname(); } - if(strpos($uname, 'synology') !== false) { + if (strpos($uname, 'synology') !== false) { return true; } return false; @@ -208,7 +208,7 @@ class Process */ private static function isProcFSMounted() { - if(is_resource(@fopen('/proc', 'r'))) { + if (is_resource(@fopen('/proc', 'r'))) { return true; } // Testing if /proc is a resource with @fopen fails on systems with open_basedir set. diff --git a/core/Columns/Updater.php b/core/Columns/Updater.php index 2dd6e4040e..1bc53607ca 100644 --- a/core/Columns/Updater.php +++ b/core/Columns/Updater.php @@ -87,17 +87,17 @@ class Updater extends \Piwik\Updates $changingColumns = array(); - foreach (VisitDimension::getAllDimensions() as $dimension) { + foreach (self::getVisitDimensions() as $dimension) { $updates = self::getUpdatesForDimension($dimension, 'log_visit.', $visitColumns, $conversionColumns); $changingColumns = self::mixinUpdates($changingColumns, $updates); } - foreach (ActionDimension::getAllDimensions() as $dimension) { + foreach (self::getActionDimensions() as $dimension) { $updates = self::getUpdatesForDimension($dimension, 'log_link_visit_action.', $actionColumns); $changingColumns = self::mixinUpdates($changingColumns, $updates); } - foreach (ConversionDimension::getAllDimensions() as $dimension) { + foreach (self::getConversionDimensions() as $dimension) { $updates = self::getUpdatesForDimension($dimension, 'log_conversion.', $conversionColumns); $changingColumns = self::mixinUpdates($changingColumns, $updates); } @@ -167,15 +167,15 @@ class Updater extends \Piwik\Updates $actionColumns = DbHelper::getTableColumns(Common::prefixTable('log_link_visit_action')); $conversionColumns = DbHelper::getTableColumns(Common::prefixTable('log_conversion')); - foreach (VisitDimension::getAllDimensions() as $dimension) { + foreach (self::getVisitDimensions() as $dimension) { $versions = self::mixinVersions($dimension, 'log_visit.', $visitColumns, $versions); } - foreach (ActionDimension::getAllDimensions() as $dimension) { + foreach (self::getActionDimensions() as $dimension) { $versions = self::mixinVersions($dimension, 'log_link_visit_action.', $actionColumns, $versions); } - foreach (ConversionDimension::getAllDimensions() as $dimension) { + foreach (self::getConversionDimensions() as $dimension) { $versions = self::mixinVersions($dimension, 'log_conversion.', $conversionColumns, $versions); } @@ -327,4 +327,25 @@ class Updater extends \Piwik\Updates return array(); } + + private static function getVisitDimensions() + { + return VisitDimension::getAllDimensions(); + } + + /** + * @return mixed|Dimension[] + */ + private static function getActionDimensions() + { + return ActionDimension::getAllDimensions(); + } + + /** + * @return mixed|Dimension[] + */ + private static function getConversionDimensions() + { + return ConversionDimension::getAllDimensions(); + } } diff --git a/core/Common.php b/core/Common.php index d9ddf0be25..bf18343bd3 100644 --- a/core/Common.php +++ b/core/Common.php @@ -362,10 +362,13 @@ class Common */ private static function undoMagicQuotes($value) { - return version_compare(PHP_VERSION, '5.4', '<') - && get_magic_quotes_gpc() - ? stripslashes($value) - : $value; + if (version_compare(PHP_VERSION, '5.4', '<') && + get_magic_quotes_gpc()) { + + return stripslashes($value); + } + + return $value; } /** @@ -375,8 +378,7 @@ class Common */ public static function sanitizeLineBreaks($value) { - $value = str_replace(array("\n", "\r", "\0"), '', $value); - return $value; + return str_replace(array("\n", "\r", "\0"), '', $value); } /** @@ -406,6 +408,7 @@ class Common if (is_null($requestArrayToUse)) { $requestArrayToUse = $_GET + $_POST; } + $varDefault = self::sanitizeInputValues($varDefault); if ($varType === 'int') { // settype accepts only integer @@ -469,6 +472,7 @@ class Common } settype($value, $varType); } + return $value; } @@ -496,14 +500,17 @@ class Common public static function hash($str, $raw_output = false) { static $hashAlgorithm = null; + if (is_null($hashAlgorithm)) { $hashAlgorithm = @Config::getInstance()->General['hash_algorithm']; } if ($hashAlgorithm) { $hash = @hash($hashAlgorithm, $str, $raw_output); - if ($hash !== false) + if ($hash !== false) { + return $hash; + } } return md5($str, $raw_output); @@ -520,7 +527,7 @@ class Common public static function getRandomString($length = 16, $alphabet = "abcdefghijklmnoprstuvwxyz0123456789") { $chars = $alphabet; - $str = ''; + $str = ''; list($usec, $sec) = explode(" ", microtime()); $seed = ((float)$sec + (float)$usec) * 100000; @@ -530,6 +537,7 @@ class Common $rand_key = mt_rand(0, strlen($chars) - 1); $str .= substr($chars, $rand_key, 1); } + return str_shuffle($str); } @@ -571,6 +579,7 @@ class Common ) { throw new Exception("visitorId is expected to be a " . Tracker::LENGTH_HEX_ID_STRING . " hex char string"); } + return self::hex2bin($id); } @@ -584,6 +593,7 @@ class Common { require_once PIWIK_INCLUDE_PATH . '/libs/PiwikTracker/PiwikTracker.php'; $userIdHashed = \PiwikTracker::getUserIdHashed($userId); + return self::convertVisitorIdToBin($userIdHashed); } @@ -730,6 +740,7 @@ class Common if ($includeInternalCodes) { return array_merge($countriesList, $extras); } + return $countriesList; } @@ -1054,7 +1065,7 @@ class Common public static function sendHeader($header, $replace = true) { // don't send header in CLI mode - if(!Common::isPhpCliMode() and !headers_sent()) { + if (!Common::isPhpCliMode() and !headers_sent()) { header($header, $replace); } } diff --git a/core/Config.php b/core/Config.php index 9d6326bb2e..572291b259 100644 --- a/core/Config.php +++ b/core/Config.php @@ -36,7 +36,7 @@ use Exception; * Config::getInstance()->MySection = array('myoption' => 1); * Config::getInstance()->forceSave(); * - * @method static \Piwik\Config getInstance() + * @method static Config getInstance() */ class Config extends Singleton { @@ -416,9 +416,9 @@ class Config extends Singleton $section = $this->getFromGlobalConfig($name); $sectionCommon = $this->getFromCommonConfig($name); - if(empty($section) && !empty($sectionCommon)) { + if (empty($section) && !empty($sectionCommon)) { $section = $sectionCommon; - } elseif(!empty($section) && !empty($sectionCommon)) { + } elseif (!empty($section) && !empty($sectionCommon)) { $section = $this->array_merge_recursive_distinct($section, $sectionCommon); } @@ -559,7 +559,7 @@ class Config extends Singleton } // If there is a common.config.ini.php, this will ensure config.ini.php does not duplicate its values - if(!empty($configCommon)) { + if (!empty($configCommon)) { $configGlobal = $this->array_merge_recursive_distinct($configGlobal, $configCommon); } diff --git a/core/Console.php b/core/Console.php index 03f9df438d..1f418fc79a 100644 --- a/core/Console.php +++ b/core/Console.php @@ -40,6 +40,7 @@ class Console extends Application { $this->initPiwikHost($input); $this->initConfig($output); + try { self::initPlugins(); } catch(\Exception $e) { @@ -51,18 +52,23 @@ class Console extends Application $commands = $this->getAvailableCommands(); foreach ($commands as $command) { - if (!class_exists($command)) { - Log::warning(sprintf('Cannot add command %s, class does not exist', $command)); - } elseif (!is_subclass_of($command, 'Piwik\Plugin\ConsoleCommand')) { - Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\Plugin\ConsoleCommand', $command)); - } else { - $this->add(new $command); - } + $this->addCommandIfExists($command); } return parent::doRun($input, $output); } + private function addCommandIfExists($command) + { + if (!class_exists($command)) { + Log::warning(sprintf('Cannot add command %s, class does not exist', $command)); + } elseif (!is_subclass_of($command, 'Piwik\Plugin\ConsoleCommand')) { + Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\Plugin\ConsoleCommand', $command)); + } else { + $this->add(new $command); + } + } + /** * Returns a list of available command classnames. * @@ -128,9 +134,11 @@ class Console extends Application protected function initConfig(OutputInterface $output) { $config = Config::getInstance(); + try { $config->checkLocalConfigFound(); return $config; + } catch (\Exception $e) { $output->writeln($e->getMessage() . "\n"); } @@ -151,6 +159,8 @@ class Console extends Application $extra = new \Piwik\Plugins\EnterpriseAdmin\EnterpriseAdmin(); $extra->addConsoleCommands($commands); } + return $commands; } + } diff --git a/core/Cookie.php b/core/Cookie.php index d081ec944e..7440c5795c 100644 --- a/core/Cookie.php +++ b/core/Cookie.php @@ -200,12 +200,14 @@ class Cookie private function extractSignedContent($content) { $signature = substr($content, -40); + if (substr($content, -43, 3) == self::VALUE_SEPARATOR . '_=' && $signature == sha1(substr($content, 0, -40) . SettingsPiwik::getSalt()) ) { // strip trailing: VALUE_SEPARATOR '_=' signature" return substr($content, 0, -43); } + return false; } @@ -218,6 +220,7 @@ class Cookie protected function loadContentFromCookie() { $cookieStr = $this->extractSignedContent($_COOKIE[$this->name]); + if ($cookieStr === false) { return; } @@ -255,6 +258,7 @@ class Cookie protected function generateContentString() { $cookieStr = ''; + foreach ($this->value as $name => $value) { if (!is_numeric($value)) { $value = base64_encode(safe_serialize($value)); @@ -335,6 +339,7 @@ class Cookie $this->value[$name] = $value; return; } + $this->value[$this->keyStore][$name] = $value; } @@ -347,14 +352,19 @@ class Cookie public function get($name) { $name = self::escapeValue($name); - if ($this->keyStore === false) { - return isset($this->value[$name]) - ? self::escapeValue($this->value[$name]) - : false; + if (false === $this->keyStore) { + if (isset($this->value[$name])) { + self::escapeValue($this->value[$name]); + } + + return false; + } + + if (isset($this->value[$this->keyStore][$name])) { + return self::escapeValue($this->value[$this->keyStore][$name]); } - return isset($this->value[$this->keyStore][$name]) - ? self::escapeValue($this->value[$this->keyStore][$name]) - : false; + + return false; } /** @@ -364,8 +374,9 @@ class Cookie */ public function __toString() { - $str = 'COOKIE ' . $this->name . ', rows count: ' . count($this->value) . ', cookie size = ' . strlen($this->generateContentString()) . " bytes\n"; + $str = 'COOKIE ' . $this->name . ', rows count: ' . count($this->value) . ', cookie size = ' . strlen($this->generateContentString()) . " bytes\n"; $str .= var_export($this->value, $return = true); + return $str; } diff --git a/core/CronArchive.php b/core/CronArchive.php index 442480051b..045e1f7c62 100644 --- a/core/CronArchive.php +++ b/core/CronArchive.php @@ -181,6 +181,13 @@ class CronArchive */ public $concurrentRequestsPerWebsite = false; + private $websitesWithVisitsSinceLastRun = 0; + private $skippedPeriodsArchivesWebsite = 0; + private $skippedDayArchivesWebsites = 0; + private $skipped = 0; + private $processed = 0; + private $archivedPeriodsArchivesWebsite = 0; + /** * Returns the option name of the option that stores the time core:archive was last executed. * @@ -234,10 +241,10 @@ class CronArchive // record archiving start time Option::set(self::OPTION_ARCHIVING_STARTED_TS, time()); - $this->segments = $this->initSegmentsToArchive(); + $this->segments = $this->initSegmentsToArchive(); $this->allWebsites = APISitesManager::getInstance()->getAllSitesId(); - if(!empty($this->shouldArchiveOnlySpecificPeriods)) { + if (!empty($this->shouldArchiveOnlySpecificPeriods)) { $this->log("- Will process the following periods: " . implode(", ", $this->shouldArchiveOnlySpecificPeriods) . " (--force-periods)"); } @@ -279,13 +286,6 @@ class CronArchive $this->runScheduledTasks(); } - private $websitesWithVisitsSinceLastRun = 0; - private $skippedPeriodsArchivesWebsite = 0; - private $skippedDayArchivesWebsites = 0; - private $skipped = 0; - private $processed = 0; - private $archivedPeriodsArchivesWebsite = 0; - /** * Main function, runs archiving on all websites with new activity */ @@ -310,7 +310,7 @@ class CronArchive } $skipWebsiteForced = in_array($idSite, $this->shouldSkipSpecifiedSites); - if($skipWebsiteForced) { + if ($skipWebsiteForced) { $this->log("Skipped website id $idSite, found in --skip-idsites "); $this->skipped++; continue; @@ -380,6 +380,7 @@ class CronArchive // do not logError since errors are already in stderr $this->log("Error: " . $error); } + $summary = count($this->errors) . " total errors during this script execution, please investigate and try and fix these errors."; $this->logFatalError($summary); } @@ -402,9 +403,11 @@ class CronArchive $this->log("Starting Scheduled tasks... "); $tasksOutput = $this->request("?module=API&method=CoreAdminHome.runScheduledTasks&format=csv&convertToUnicode=0&token_auth=" . $this->token_auth); + if ($tasksOutput == \Piwik\DataTable\Renderer\Csv::NO_DATA_AVAILABLE) { $tasksOutput = " No task to run"; } + $this->log($tasksOutput); $this->log("done"); $this->logSection(""); @@ -415,6 +418,7 @@ class CronArchive $timerWebsite = new Timer; $lastTimestampWebsiteProcessedPeriods = $lastTimestampWebsiteProcessedDay = false; + if ($this->archiveAndRespectTTL) { Option::clearCachedOption($this->lastRunKey($idSite, "periods")); $lastTimestampWebsiteProcessedPeriods = Option::get($this->lastRunKey($idSite, "periods")); @@ -433,6 +437,7 @@ class CronArchive if ($this->processPeriodsMaximumEverySeconds > 10 * 60) { $secondsSinceLastExecution += 5 * 60; } + $shouldArchivePeriods = $secondsSinceLastExecution > $this->processPeriodsMaximumEverySeconds; if (empty($lastTimestampWebsiteProcessedPeriods)) { // 2) OR always if script never executed for this website before @@ -455,7 +460,7 @@ class CronArchive } $websiteIdIsForced = in_array($idSite, $this->shouldArchiveSpecifiedSites); - if($websiteIdIsForced) { + if ($websiteIdIsForced) { $shouldArchivePeriods = true; } @@ -492,7 +497,7 @@ class CronArchive } $shouldProceed = $this->processArchiveDays($idSite, $lastTimestampWebsiteProcessedDay, $shouldArchivePeriods, $timerWebsite); - if(!$shouldProceed) { + if (!$shouldProceed) { return false; } @@ -508,7 +513,7 @@ class CronArchive $success = true; foreach (array('week', 'month', 'year') as $period) { - if(!$this->shouldProcessPeriod($period)) { + if (!$this->shouldProcessPeriod($period)) { // if any period was skipped, we do not mark the Periods archiving as successful $success = false; continue; @@ -521,6 +526,7 @@ class CronArchive if ($success) { Option::set($this->lastRunKey($idSite, "periods"), time()); } + $this->archivedPeriodsArchivesWebsite++; $requestsWebsite = $this->requests - $requestsBefore; @@ -568,9 +574,11 @@ class CronArchive private function initSegmentsToArchive() { $segments = \Piwik\SettingsPiwik::getKnownSegmentsToArchive(); + if (empty($segments)) { return array(); } + $this->log("- Will pre-process " . count($segments) . " Segments for each website and each period: " . implode(", ", $segments)); return $segments; } @@ -603,7 +611,7 @@ class CronArchive // when some data was purged from this website // we make sure we query all previous days/weeks/months $processDaysSince = $lastTimestampWebsiteProcessedDay; - if($this->isOldReportInvalidatedForWebsite($idSite) + if ($this->isOldReportInvalidatedForWebsite($idSite) // when --force-all-websites option, // also forces to archive last52 days to be safe || $this->shouldArchiveAllSites) { @@ -634,7 +642,7 @@ class CronArchive $this->processed++; // If there is no visit today and we don't need to process this website, we can skip remaining archives - if ($visitsToday == 0 + if (0 == $visitsToday && !$shouldArchivePeriods ) { $this->log("Skipped website id $idSite, no visit today, " . $timerWebsite->__toString()); @@ -642,7 +650,7 @@ class CronArchive return false; } - if ($visitsLastDays == 0 + if (0 == $visitsLastDays && !$shouldArchivePeriods && $this->shouldArchiveAllSites ) { @@ -662,7 +670,7 @@ class CronArchive private function getSegmentsForSite($idSite) { $segmentsAllSites = $this->segments; - $segmentsThisSite = \Piwik\SettingsPiwik::getKnownSegmentsToArchiveForSite($idSite); + $segmentsThisSite = SettingsPiwik::getKnownSegmentsToArchiveForSite($idSite); if (!empty($segmentsThisSite)) { $this->log("Will pre-process the following " . count($segmentsThisSite) . " Segments for this website (id = $idSite): " . implode(", ", $segmentsThisSite)); } @@ -731,7 +739,7 @@ class CronArchive } // we have already logged the daily archive above - if($period != "day") { + if ($period != "day") { $this->logArchivedWebsite($idSite, $period, $date, $visitsInLastPeriods, $visitsLastPeriod, $timer); } @@ -744,7 +752,7 @@ class CronArchive private function logSection($title = "") { $this->log("---------------------------"); - if(!empty($title)) { + if (!empty($title)) { $this->log($title); } } @@ -788,7 +796,7 @@ class CronArchive { $url = $this->piwikUrl . $url . self::APPEND_TO_API_REQUEST; - if($this->shouldStartProfiler) { + if ($this->shouldStartProfiler) { $url .= "&xhprof=2"; } @@ -851,6 +859,7 @@ class CronArchive if (Common::isPhpCliMode()) { return; } + $token_auth = Common::getRequestVar('token_auth', '', 'string'); if ($token_auth !== $this->token_auth || strlen($token_auth) != 32 @@ -892,7 +901,7 @@ class CronArchive $this->shouldArchiveOnlySitesWithTrafficSince = $this->isShouldArchiveAllSitesWithTrafficSince(); $this->shouldArchiveOnlySpecificPeriods = $this->getPeriodsToProcess(); - if($this->shouldArchiveOnlySitesWithTrafficSince === false) { + if ($this->shouldArchiveOnlySitesWithTrafficSince === false) { // force-all-periods is not set here if (empty($this->lastSuccessRunTimestamp)) { // First time we run the script @@ -905,7 +914,7 @@ class CronArchive // force-all-periods is set here $this->archiveAndRespectTTL = false; - if($this->shouldArchiveOnlySitesWithTrafficSince === true) { + if ($this->shouldArchiveOnlySitesWithTrafficSince === true) { // force-all-periods without value $this->shouldArchiveOnlySitesWithTrafficSince = self::ARCHIVE_SITES_WITH_TRAFFIC_SINCE; } @@ -935,7 +944,7 @@ class CronArchive */ public function initWebsiteIds() { - if(count($this->shouldArchiveSpecifiedSites) > 0) { + if (count($this->shouldArchiveSpecifiedSites) > 0) { $this->log("- Will process " . count($this->shouldArchiveSpecifiedSites) . " websites (--force-idsites)"); return $this->shouldArchiveSpecifiedSites; @@ -978,12 +987,12 @@ class CronArchive $this->logFatalErrorUrlExpected(); } - if(!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) { + if (!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) { // try adding http:// in case it's missing $piwikUrl = "http://" . $piwikUrl; } - if(!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) { + if (!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) { $this->logFatalErrorUrlExpected(); } @@ -1099,12 +1108,14 @@ class CronArchive $websiteDayHasFinishedSinceLastRun = APISitesManager::getInstance()->getSitesIdFromTimezones($timezones); $websiteDayHasFinishedSinceLastRun = array_diff($websiteDayHasFinishedSinceLastRun, $websiteIds); $this->websiteDayHasFinishedSinceLastRun = $websiteDayHasFinishedSinceLastRun; + if (count($websiteDayHasFinishedSinceLastRun) > 0) { $ids = !empty($websiteDayHasFinishedSinceLastRun) ? ", IDs: " . implode(", ", $websiteDayHasFinishedSinceLastRun) : ""; $this->log("- Will process " . count($websiteDayHasFinishedSinceLastRun) . " other websites because the last time they were archived was on a different day (in the website's timezone) " . $ids); } + return $websiteDayHasFinishedSinceLastRun; } @@ -1170,6 +1181,7 @@ class CronArchive $this->log("WARNING: Automatically increasing --force-timeout-for-periods from {$this->forceTimeoutPeriod} to " . $this->todayArchiveTimeToLive . " to match the cache timeout for Today's report specified in Piwik UI > Settings > General Settings"); + return $this->todayArchiveTimeToLive; } @@ -1178,11 +1190,13 @@ class CronArchive if (empty($this->shouldArchiveAllPeriodsSince)) { return false; } + if (is_numeric($this->shouldArchiveAllPeriodsSince) && $this->shouldArchiveAllPeriodsSince > 1 ) { return (int)$this->shouldArchiveAllPeriodsSince; } + return true; } @@ -1192,6 +1206,7 @@ class CronArchive protected function removeWebsiteFromInvalidatedWebsites($idSite) { $websiteIdsInvalidated = APICoreAdminHome::getWebsiteIdsToInvalidate(); + if (count($websiteIdsInvalidated)) { $found = array_search($idSite, $websiteIdsInvalidated); if ($found !== false) { @@ -1209,25 +1224,29 @@ class CronArchive private function getVisitsLastPeriodFromApiResponse($stats) { - if(empty($stats)) { + if (empty($stats)) { return 0; } + $today = end($stats); + return $today['nb_visits']; } private function getVisitsFromApiResponse($stats) { - if(empty($stats)) { + if (empty($stats)) { return 0; } + $visits = 0; foreach($stats as $metrics) { - if(empty($metrics['nb_visits'])) { + if (empty($metrics['nb_visits'])) { continue; } $visits += $metrics['nb_visits']; } + return $visits; } @@ -1240,9 +1259,11 @@ class CronArchive private function getApiDateParameter($idSite, $period, $lastTimestampWebsiteProcessed = false) { $dateRangeForced = $this->getDateRangeToProcess(); - if(!empty($dateRangeForced)) { + + if (!empty($dateRangeForced)) { return $dateRangeForced; } + return $this->getDateLastN($idSite, $period, $lastTimestampWebsiteProcessed); } @@ -1256,7 +1277,7 @@ class CronArchive */ private function logArchivedWebsite($idSite, $period, $date, $visitsInLastPeriods, $visitsToday, Timer $timer) { - if(substr($date, 0, 4) === 'last') { + if (substr($date, 0, 4) === 'last') { $visitsInLastPeriods = (int)$visitsInLastPeriods . " visits in last " . $date . " " . $period . "s, "; $thisPeriod = $period == "day" ? "today" : "this " . $period; $visitsInLastPeriod = (int)$visitsToday . " visits " . $thisPeriod . ", "; @@ -1276,9 +1297,11 @@ class CronArchive if (empty($this->restrictToDateRange)) { return false; } + if (strpos($this->restrictToDateRange, ',') === false) { throw new Exception("--force-date-range expects a date range ie. YYYY-MM-DD,YYYY-MM-DD"); } + return $this->restrictToDateRange; } @@ -1289,6 +1312,7 @@ class CronArchive { $this->restrictToPeriods = array_intersect($this->restrictToPeriods, $this->getDefaultPeriodsToProcess()); $this->restrictToPeriods = array_intersect($this->restrictToPeriods, PeriodFactory::getPeriodsEnabledForAPI()); + return $this->restrictToPeriods; } @@ -1311,9 +1335,10 @@ class CronArchive private function shouldProcessPeriod($period) { - if(empty($this->shouldArchiveOnlySpecificPeriods)) { + if (empty($this->shouldArchiveOnlySpecificPeriods)) { return true; } + return in_array($period, $this->shouldArchiveOnlySpecificPeriods); } @@ -1344,6 +1369,7 @@ class CronArchive if (!empty($this->dateLastForced)) { $dateLast = $this->dateLastForced; } + return "last" . $dateLast; } @@ -1352,9 +1378,10 @@ class CronArchive */ private function getConcurrentRequestsPerWebsite() { - if ($this->concurrentRequestsPerWebsite !== false) { + if (false !== $this->concurrentRequestsPerWebsite) { return $this->concurrentRequestsPerWebsite; } + return self::MAX_CONCURRENT_API_REQUESTS; } } diff --git a/core/DataAccess/ArchivePurger.php b/core/DataAccess/ArchivePurger.php index 94e1622376..2c1379115d 100644 --- a/core/DataAccess/ArchivePurger.php +++ b/core/DataAccess/ArchivePurger.php @@ -81,8 +81,7 @@ class ArchivePurger protected static function getTemporaryArchiveIdsOlderThan(Date $date, $purgeArchivesOlderThan) { - $query = "SELECT idarchive - FROM " . ArchiveTableCreator::getNumericTable($date) . " + $query = "SELECT idarchive FROM " . ArchiveTableCreator::getNumericTable($date) . " WHERE name LIKE 'done%' AND (( value = " . ArchiveWriter::DONE_OK_TEMPORARY . " AND ts_archived < ?) diff --git a/core/DataAccess/ArchiveSelector.php b/core/DataAccess/ArchiveSelector.php index 5a715e6939..594889d6dd 100644 --- a/core/DataAccess/ArchiveSelector.php +++ b/core/DataAccess/ArchiveSelector.php @@ -14,10 +14,8 @@ use Piwik\ArchiveProcessor; use Piwik\Common; use Piwik\Date; use Piwik\Db; -use Piwik\Log; use Piwik\Period; use Piwik\Period\Range; -use Piwik\Piwik; use Piwik\Segment; /** @@ -150,7 +148,7 @@ class ArchiveSelector */ public static function getArchiveIds($siteIds, $periods, $segment, $plugins, $isSkipAggregationOfSubTables = false) { - if(empty($siteIds)) { + if (empty($siteIds)) { throw new \Exception("Website IDs could not be read from the request, ie. idSite="); } diff --git a/core/DataAccess/LogAggregator.php b/core/DataAccess/LogAggregator.php index 95a7603176..79db3148b7 100644 --- a/core/DataAccess/LogAggregator.php +++ b/core/DataAccess/LogAggregator.php @@ -494,7 +494,7 @@ class LogAggregator * * @param string $dimension One or more **log\_conversion\_item** columns to group aggregated data by. * Eg, `'idaction_sku'` or `'idaction_sku, idaction_category'`. - * @return Zend_Db_Statement A statement object that can be used to iterate through the query's + * @return \Zend_Db_Statement A statement object that can be used to iterate through the query's * result set. See [above](#queryEcommerceItems-result-set) to learn more * about what this query selects. * @api @@ -641,7 +641,7 @@ class LogAggregator if (strpos($joinColumn, ' ') === false) { $joinOn = $tableAlias . '.idaction = ' . $tableName . '.' . $joinColumn; } else { - // more complex join column like IF(...) + // more complex join column like if (...) $joinOn = $tableAlias . '.idaction = ' . $joinColumn; } $from[] = array( @@ -733,7 +733,7 @@ class LogAggregator * @param bool|string $where An optional SQL expression used in the SQL's **WHERE** clause. * @param array $additionalSelects Additional SELECT fields that are not included in the group by * clause. These can be aggregate expressions, eg, `SUM(somecol)`. - * @return Zend_Db_Statement + * @return \Zend_Db_Statement */ public function queryConversionsByDimension($dimensions = array(), $where = false, $additionalSelects = array()) { @@ -743,11 +743,11 @@ class LogAggregator $select = $this->getSelectStatement($dimensions, $tableName, $additionalSelects, $availableMetrics); - $from = array($tableName); - $where = $this->getWhereStatement($tableName, self::CONVERSION_DATETIME_FIELD, $where); + $from = array($tableName); + $where = $this->getWhereStatement($tableName, self::CONVERSION_DATETIME_FIELD, $where); $groupBy = $this->getGroupByStatement($dimensions, $tableName); $orderBy = false; - $query = $this->generateQuery($select, $from, $where, $groupBy, $orderBy); + $query = $this->generateQuery($select, $from, $where, $groupBy, $orderBy); return $this->getDb()->query($query['sql'], $query['bind']); } diff --git a/core/DataArray.php b/core/DataArray.php index 042d5ae961..04c9897125 100644 --- a/core/DataArray.php +++ b/core/DataArray.php @@ -108,7 +108,7 @@ class DataArray // In case the existing Row had no action metrics (eg. Custom Variable XYZ with "visit" scope) // but the new Row has action metrics (eg. same Custom Variable XYZ this time with a "page" scope) - if(!isset($oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS])) { + if (!isset($oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS])) { $toZero = array(Metrics::INDEX_MAX_ACTIONS, Metrics::INDEX_SUM_VISIT_LENGTH, Metrics::INDEX_BOUNCE_COUNT, @@ -247,8 +247,8 @@ class DataArray $oldRowToUpdate[Metrics::INDEX_EVENT_MAX_EVENT_VALUE] = round(max($newRowToAdd[Metrics::INDEX_EVENT_MAX_EVENT_VALUE], $oldRowToUpdate[Metrics::INDEX_EVENT_MAX_EVENT_VALUE]), self::EVENT_VALUE_PRECISION); // Update minimum only if it is set - if($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] !== false) { - if($oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] === false) { + if ($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] !== false) { + if ($oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] === false) { $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] = round($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE], self::EVENT_VALUE_PRECISION); } else { $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] = round(min($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE], $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE]), self::EVENT_VALUE_PRECISION); @@ -360,7 +360,7 @@ class DataArray // if there are no "visit" column, we force one to prevent future complications // eg. This helps the setDefaultColumnsToDisplay() call - if(!isset($values[Metrics::INDEX_NB_VISITS])) { + if (!isset($values[Metrics::INDEX_NB_VISITS])) { $values[Metrics::INDEX_NB_VISITS] = 0; } } diff --git a/core/DataTable.php b/core/DataTable.php index bc5a57cff6..4d308f7d21 100644 --- a/core/DataTable.php +++ b/core/DataTable.php @@ -469,11 +469,13 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess * metadata can be used to specify a different type of operation. * * @param \Piwik\DataTable $tableToSum + * @param bool $doAggregateSubTables + * @throws Exception */ public function addDataTable(DataTable $tableToSum, $doAggregateSubTables = true) { - if($tableToSum instanceof Simple) { - if($tableToSum->getRowsCount() > 1) { + if ($tableToSum instanceof Simple) { + if ($tableToSum->getRowsCount() > 1) { throw new Exception("Did not expect a Simple table with more than one row in addDataTable()"); } $row = $tableToSum->getFirstRow(); @@ -897,7 +899,7 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess foreach ($this->getRows() as $row) { $row->renameColumn($oldName, $newName); - if($doRenameColumnsOfSubTables) { + if ($doRenameColumnsOfSubTables) { if (($idSubDataTable = $row->getIdSubDataTable()) !== null) { Manager::getInstance()->getTable($idSubDataTable)->renameColumn($oldName, $newName); } @@ -1602,7 +1604,7 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess } else { $rowFound->sumRow($row, $copyMeta = true, $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME)); - if($doAggregateSubTables) { + if ($doAggregateSubTables) { // if the row to add has a subtable whereas the current row doesn't // we simply add it (cloning the subtable) // if the row has the subtable already diff --git a/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php b/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php index 742f1aef6d..963ac9acbd 100644 --- a/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php +++ b/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php @@ -8,12 +8,10 @@ */ namespace Piwik\DataTable\Filter; -use Exception; use Piwik\DataTable; use Piwik\DataTable\Row; use Piwik\Metrics; use Piwik\Piwik; -use Piwik\Tracker\GoalManager; /** * Adds goal related metrics to a {@link DataTable} using metrics that already exist. diff --git a/core/DataTable/Filter/BeautifyRangeLabels.php b/core/DataTable/Filter/BeautifyRangeLabels.php index 534f484bff..bf5e8d65d9 100644 --- a/core/DataTable/Filter/BeautifyRangeLabels.php +++ b/core/DataTable/Filter/BeautifyRangeLabels.php @@ -65,7 +65,7 @@ class BeautifyRangeLabels extends ColumnCallbackReplace parent::__construct($table, 'label', array($this, 'beautify'), array()); $this->labelSingular = $labelSingular; - $this->labelPlural = $labelPlural; + $this->labelPlural = $labelPlural; } /** diff --git a/core/DataTable/Filter/CalculateEvolutionFilter.php b/core/DataTable/Filter/CalculateEvolutionFilter.php index 80f789919e..0ef6a30a2f 100755 --- a/core/DataTable/Filter/CalculateEvolutionFilter.php +++ b/core/DataTable/Filter/CalculateEvolutionFilter.php @@ -121,6 +121,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage { $value = self::getPercentageValue($value, $divisor, $this->quotientPrecision); $value = self::appendPercentSign($value); + return $value; } @@ -152,6 +153,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage if ($appendPercentSign) { $number = self::appendPercentSign($number); } + return $number; } @@ -165,6 +167,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage if ($number > 0) { $number = '+' . $number; } + return $number; } diff --git a/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php b/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php index 5cc83d8e3d..81d8eadf04 100644 --- a/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php +++ b/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php @@ -109,6 +109,7 @@ class ColumnCallbackAddColumnQuotient extends BaseFilter if ($divisor > 0 && $value > 0) { $quotient = round($value / $divisor, $this->quotientPrecision); } + return $quotient; } diff --git a/core/DataTable/Filter/ColumnCallbackAddMetadata.php b/core/DataTable/Filter/ColumnCallbackAddMetadata.php index e89000f8fd..c7945839cb 100644 --- a/core/DataTable/Filter/ColumnCallbackAddMetadata.php +++ b/core/DataTable/Filter/ColumnCallbackAddMetadata.php @@ -48,12 +48,12 @@ class ColumnCallbackAddMetadata extends BaseFilter if (!is_array($columnsToRead)) { $columnsToRead = array($columnsToRead); } - $this->columnsToRead = $columnsToRead; - $this->functionToApply = $functionToApply; + $this->columnsToRead = $columnsToRead; + $this->functionToApply = $functionToApply; $this->functionParameters = $functionParameters; - $this->metadataToAdd = $metadataToAdd; - $this->applyToSummaryRow = $applyToSummaryRow; + $this->metadataToAdd = $metadataToAdd; + $this->applyToSummaryRow = $applyToSummaryRow; } /** diff --git a/core/DataTable/Filter/ColumnCallbackDeleteRow.php b/core/DataTable/Filter/ColumnCallbackDeleteRow.php index 189fbd3b81..414bf71e8a 100644 --- a/core/DataTable/Filter/ColumnCallbackDeleteRow.php +++ b/core/DataTable/Filter/ColumnCallbackDeleteRow.php @@ -25,7 +25,6 @@ use Piwik\DataTable\BaseFilter; */ class ColumnCallbackDeleteRow extends BaseFilter { - private $columnToFilter; private $function; private $functionParams; diff --git a/core/DataTable/Filter/ColumnCallbackReplace.php b/core/DataTable/Filter/ColumnCallbackReplace.php index e33dfa9a14..ca53405d7e 100644 --- a/core/DataTable/Filter/ColumnCallbackReplace.php +++ b/core/DataTable/Filter/ColumnCallbackReplace.php @@ -54,14 +54,14 @@ class ColumnCallbackReplace extends BaseFilter $extraColumnParameters = array()) { parent::__construct($table); - $this->functionToApply = $functionToApply; + $this->functionToApply = $functionToApply; $this->functionParameters = $functionParameters; if (!is_array($columnsToFilter)) { $columnsToFilter = array($columnsToFilter); } - $this->columnsToFilter = $columnsToFilter; + $this->columnsToFilter = $columnsToFilter; $this->extraColumnParameters = $extraColumnParameters; } @@ -73,6 +73,7 @@ class ColumnCallbackReplace extends BaseFilter public function filter($table) { foreach ($table->getRows() as $row) { + $extraColumnParameters = array(); foreach ($this->extraColumnParameters as $columnName) { $extraColumnParameters[] = $row->getColumn($columnName); @@ -86,9 +87,11 @@ class ColumnCallbackReplace extends BaseFilter } $parameters = array_merge(array($value), $extraColumnParameters); + if (!is_null($this->functionParameters)) { $parameters = array_merge($parameters, $this->functionParameters); } + $newValue = call_user_func_array($this->functionToApply, $parameters); $this->setElementToReplace($row, $column, $newValue); $this->filterSubTable($row); diff --git a/core/DataTable/Filter/ColumnDelete.php b/core/DataTable/Filter/ColumnDelete.php index 5aac6d44a6..743f5afd86 100644 --- a/core/DataTable/Filter/ColumnDelete.php +++ b/core/DataTable/Filter/ColumnDelete.php @@ -91,6 +91,7 @@ class ColumnDelete extends BaseFilter * See {@link ColumnDelete}. * * @param DataTable $table + * @return DataTable */ public function filter($table) { diff --git a/core/DataTable/Filter/GroupBy.php b/core/DataTable/Filter/GroupBy.php index 8633fb2e9d..b899bb9059 100755 --- a/core/DataTable/Filter/GroupBy.php +++ b/core/DataTable/Filter/GroupBy.php @@ -59,9 +59,9 @@ class GroupBy extends BaseFilter { parent::__construct($table); - $this->groupByColumn = $groupByColumn; + $this->groupByColumn = $groupByColumn; $this->reduceFunction = $reduceFunction; - $this->parameters = $parameters; + $this->parameters = $parameters; } /** @@ -82,7 +82,7 @@ class GroupBy extends BaseFilter // reduce the group by column of this row $groupByColumnValue = $row->getColumn($this->groupByColumn); - $parameters = array_merge(array($groupByColumnValue), $this->parameters); + $parameters = array_merge(array($groupByColumnValue), $this->parameters); $groupByValue = call_user_func_array($this->reduceFunction, $parameters); if (!isset($groupByRows[$groupByValue])) { diff --git a/core/DataTable/Filter/Limit.php b/core/DataTable/Filter/Limit.php index 5cf848a50e..415be29602 100644 --- a/core/DataTable/Filter/Limit.php +++ b/core/DataTable/Filter/Limit.php @@ -34,9 +34,9 @@ class Limit extends BaseFilter public function __construct($table, $offset, $limit = -1, $keepSummaryRow = false) { parent::__construct($table); - $this->offset = $offset; - $this->limit = $limit; + $this->offset = $offset; + $this->limit = $limit; $this->keepSummaryRow = $keepSummaryRow; } diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php index 683e93cffe..9df2250288 100644 --- a/core/DataTable/Filter/Sort.php +++ b/core/DataTable/Filter/Sort.php @@ -38,11 +38,13 @@ class Sort extends BaseFilter public function __construct($table, $columnToSort, $order = 'desc', $naturalSort = true, $recursiveSort = false) { parent::__construct($table); + if ($recursiveSort) { $table->enableRecursiveSort(); } + $this->columnToSort = $columnToSort; - $this->naturalSort = $naturalSort; + $this->naturalSort = $naturalSort; $this->setOrder($order); } @@ -55,10 +57,10 @@ class Sort extends BaseFilter { if ($order == 'asc') { $this->order = 'asc'; - $this->sign = 1; + $this->sign = 1; } else { $this->order = 'desc'; - $this->sign = -1; + $this->sign = -1; } } @@ -225,17 +227,21 @@ class Sort extends BaseFilter if ($table instanceof Simple) { return; } + if (empty($this->columnToSort)) { return; } + $rows = $table->getRows(); if (count($rows) == 0) { return; } + $row = current($rows); if ($row === false) { return; } + $this->columnToSort = $this->selectColumnToSort($row); $value = $row->getColumn($this->columnToSort); @@ -248,6 +254,7 @@ class Sort extends BaseFilter $methodToUse = "sortString"; } } + $table->sort(array($this, $methodToUse), $this->columnToSort); } } diff --git a/core/DataTable/Filter/Truncate.php b/core/DataTable/Filter/Truncate.php index 192d85b82f..120fc37760 100644 --- a/core/DataTable/Filter/Truncate.php +++ b/core/DataTable/Filter/Truncate.php @@ -89,9 +89,10 @@ class Truncate extends BaseFilter return; } - $rows = $table->getRows(); - $count = $table->getRowsCount(); + $rows = $table->getRows(); + $count = $table->getRowsCount(); $newRow = new Row(array(Row::COLUMNS => array('label' => DataTable::LABEL_SUMMARY_ROW))); + for ($i = $this->truncateAfter; $i < $count; $i++) { if (!isset($rows[$i])) { // case when the last row is a summary row, it is not indexed by $cout but by DataTable::ID_SUMMARY_ROW diff --git a/core/DataTable/Manager.php b/core/DataTable/Manager.php index c19060b803..d225b8fb87 100644 --- a/core/DataTable/Manager.php +++ b/core/DataTable/Manager.php @@ -63,6 +63,7 @@ class Manager extends Singleton if (!isset($this->tables[$idTable])) { throw new TableNotFoundException(sprintf("This report has been reprocessed since your last click. To see this error less often, please increase the timeout value in seconds in Settings > General Settings. (error: id %s not found).", $idTable)); } + return $this->tables[$idTable]; } @@ -86,6 +87,7 @@ class Manager extends Singleton $this->deleteTable($id); } } + if ($deleteWhenIdTableGreaterThan == 0) { $this->tables = array(); $this->nextTableId = 1; diff --git a/core/DataTable/Map.php b/core/DataTable/Map.php index dd8bec7ca5..8795eac134 100644 --- a/core/DataTable/Map.php +++ b/core/DataTable/Map.php @@ -246,12 +246,14 @@ class Map implements DataTableInterface public function getColumn($name) { $values = array(); + foreach ($this->getDataTables() as $table) { $moreValues = $table->getColumn($name); foreach ($moreValues as &$value) { $values[] = $value; } } + return $values; } diff --git a/core/DataTable/Renderer.php b/core/DataTable/Renderer.php index 5705b3e205..f825739611 100644 --- a/core/DataTable/Renderer.php +++ b/core/DataTable/Renderer.php @@ -161,13 +161,16 @@ abstract class Renderer extends BaseFactory { $className = ucfirst(strtolower($id)); $className = 'Piwik\DataTable\Renderer\\' . $className; + return $className; } protected static function getInvalidClassIdExceptionMessage($id) { $availableRenderers = implode(', ', self::getRenderers()); - return Piwik::translate('General_ExceptionInvalidRendererFormat', array(self::getClassNameFromClassId($id), $availableRenderers)); + $klassName = self::getClassNameFromClassId($id); + + return Piwik::translate('General_ExceptionInvalidRendererFormat', array($klassName, $availableRenderers)); } /** @@ -187,12 +190,15 @@ abstract class Renderer extends BaseFactory $value = @mb_convert_encoding($value, 'UTF-8', 'UTF-8'); } $value = htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); + $htmlentities = array(" ", "¡", "¢", "£", "¤", "¥", "¦", "§", "¨", "©", "ª", "«", "¬", "­", "®", "¯", "°", "±", "²", "³", "´", "µ", "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß", "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ", "€"); - $xmlentities = array("¢", "£", "¤", "¥", "¦", "§", "¨", "©", "ª", "«", "¬", "­", "®", "¯", "°", "±", "²", "³", "´", "µ", "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß", "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ", "€"); - $value = str_replace($htmlentities, $xmlentities, $value); + $xmlentities = array("¢", "£", "¤", "¥", "¦", "§", "¨", "©", "ª", "«", "¬", "­", "®", "¯", "°", "±", "²", "³", "´", "µ", "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß", "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ", "€"); + $value = str_replace($htmlentities, $xmlentities, $value); + } elseif ($value === false) { $value = 0; } + return $value; } diff --git a/core/DataTable/Renderer/Console.php b/core/DataTable/Renderer/Console.php index 88161165fc..0e1c127fb1 100644 --- a/core/DataTable/Renderer/Console.php +++ b/core/DataTable/Renderer/Console.php @@ -142,7 +142,7 @@ class Console extends Renderer foreach ($metadata as $id => $metadataIn) { $output .= "<br />"; $output .= $prefix . " <b>$id</b><br />"; - if(is_array($metadataIn)) { + if (is_array($metadataIn)) { foreach ($metadataIn as $name => $value) { $output .= $prefix . $prefix . "$name => $value"; } diff --git a/core/DataTable/Renderer/Json.php b/core/DataTable/Renderer/Json.php index 8fea38a658..f53ea60e67 100644 --- a/core/DataTable/Renderer/Json.php +++ b/core/DataTable/Renderer/Json.php @@ -11,7 +11,6 @@ namespace Piwik\DataTable\Renderer; use Piwik\Common; use Piwik\DataTable\Renderer; use Piwik\DataTable; -use Piwik\ProxyHttp; /** * JSON export. diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php index 72e6d67b6c..07946adfd1 100644 --- a/core/DataTable/Row.php +++ b/core/DataTable/Row.php @@ -183,7 +183,7 @@ class Row implements \ArrayAccess, \IteratorAggregate if (isset($this->c[self::COLUMNS][$oldName])) { $this->c[self::COLUMNS][$newName] = $this->c[self::COLUMNS][$oldName]; } - // outside the if() since we want to delete nulled columns + // outside the if () since we want to delete nulled columns unset($this->c[self::COLUMNS][$oldName]); } @@ -500,9 +500,10 @@ class Row implements \ArrayAccess, \IteratorAggregate * * @param \Piwik\DataTable\Row $rowToSum The row to sum to this row. * @param bool $enableCopyMetadata Whether metadata should be copied or not. - * @param array $aggregationOperations for columns that should not be summed, determine which + * @param array|bool $aggregationOperations for columns that should not be summed, determine which * aggregation should be used (min, max). format: * `array('column name' => 'function name')` + * @throws Exception */ public function sumRow(Row $rowToSum, $enableCopyMetadata = true, $aggregationOperations = false) { @@ -528,7 +529,7 @@ class Row implements \ArrayAccess, \IteratorAggregate if ($columnToSumName == Metrics::INDEX_MAX_ACTIONS) { $operation = 'max'; } - if(empty($operation)) { + if (empty($operation)) { throw new Exception("Unknown aggregation operation for column $columnToSumName."); } diff --git a/core/Date.php b/core/Date.php index c5b4cd7af6..5b8e0fab6e 100644 --- a/core/Date.php +++ b/core/Date.php @@ -273,15 +273,16 @@ class Date // Unit tests pass (@see Date.test.php) but I'm pretty sure this is not the right way to do it date_default_timezone_set($this->timezone); $dtzone = timezone_open('UTC'); - $time = date('r', $this->timestamp); - $dtime = date_create($time); + $time = date('r', $this->timestamp); + $dtime = date_create($time); + date_timezone_set($dtime, $dtzone); - $dateWithTimezone = date_format($dtime, 'r'); + $dateWithTimezone = date_format($dtime, 'r'); $dateWithoutTimezone = substr($dateWithTimezone, 0, -6); - $timestamp = strtotime($dateWithoutTimezone); + $timestamp = strtotime($dateWithoutTimezone); date_default_timezone_set('UTC'); - return (int)$timestamp; + return (int) $timestamp; } /** diff --git a/core/Db.php b/core/Db.php index e845a5ab6e..4ad62684f6 100644 --- a/core/Db.php +++ b/core/Db.php @@ -271,7 +271,7 @@ class Db * * @param string $table The name of the table to delete from. Must be prefixed (see {@link Piwik\Common::prefixTable()}). * @param string $where The where clause of the query. Must include the WHERE keyword. - * @param $orderBy The column to order by and the order by direction, eg, `idvisit ASC`. + * @param string $orderBy The column to order by and the order by direction, eg, `idvisit ASC`. * @param int $maxRowsPerQuery The maximum number of rows to delete per `DELETE` query. * @param array $parameters Parameters to bind for each query. * @return int The total number of rows deleted. diff --git a/core/Db/Adapter/Mysqli.php b/core/Db/Adapter/Mysqli.php index c864d057b0..fa74f35c9d 100644 --- a/core/Db/Adapter/Mysqli.php +++ b/core/Db/Adapter/Mysqli.php @@ -56,8 +56,9 @@ class Mysqli extends Zend_Db_Adapter_Mysqli implements AdapterInterface */ public function checkServerVersion() { - $serverVersion = $this->getServerVersion(); + $serverVersion = $this->getServerVersion(); $requiredVersion = Config::getInstance()->General['minimum_mysql_version']; + if (version_compare($serverVersion, $requiredVersion) === -1) { throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MySQL', $serverVersion, $requiredVersion))); } @@ -72,6 +73,7 @@ class Mysqli extends Zend_Db_Adapter_Mysqli implements AdapterInterface { $serverVersion = $this->getServerVersion(); $clientVersion = $this->getClientVersion(); + // incompatible change to DECIMAL implementation in 5.0.3 if (version_compare($serverVersion, '5.0.3') >= 0 && version_compare($clientVersion, '5.0.3') < 0 @@ -168,10 +170,12 @@ class Mysqli extends Zend_Db_Adapter_Mysqli implements AdapterInterface public function getClientVersion() { $this->_connect(); - $version = $this->_connection->server_version; - $major = (int)($version / 10000); - $minor = (int)($version % 10000 / 100); + + $version = $this->_connection->server_version; + $major = (int)($version / 10000); + $minor = (int)($version % 10000 / 100); $revision = (int)($version % 100); + return $major . '.' . $minor . '.' . $revision; } } diff --git a/core/Db/Adapter/Pdo/Mssql.php b/core/Db/Adapter/Pdo/Mssql.php index fd0248958e..ab032e145d 100644 --- a/core/Db/Adapter/Pdo/Mssql.php +++ b/core/Db/Adapter/Pdo/Mssql.php @@ -66,7 +66,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface try { $serverName = $this->_config["host"]; - $database = $this->_config["dbname"]; + $database = $this->_config["dbname"]; if (is_null($database)) { $database = 'master'; } @@ -134,8 +134,9 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface */ public function checkServerVersion() { - $serverVersion = $this->getServerVersion(); + $serverVersion = $this->getServerVersion(); $requiredVersion = Config::getInstance()->General['minimum_mssql_version']; + if (version_compare($serverVersion, $requiredVersion) === -1) { throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MSSQL', $serverVersion, $requiredVersion))); } @@ -149,7 +150,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface public function getServerVersion() { try { - $stmt = $this->query("SELECT CAST(SERVERPROPERTY('productversion') as VARCHAR) as productversion"); + $stmt = $this->query("SELECT CAST(SERVERPROPERTY('productversion') as VARCHAR) as productversion"); $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); if (count($result)) { return $result[0][0]; @@ -169,6 +170,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface { $serverVersion = $this->getServerVersion(); $clientVersion = $this->getClientVersion(); + if (version_compare($serverVersion, '10') >= 0 && version_compare($clientVersion, '10') < 0 ) { @@ -224,6 +226,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface if (preg_match('/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $e->getMessage(), $match)) { return $match[1] == $errno; } + return false; } diff --git a/core/Db/Adapter/Pdo/Mysql.php b/core/Db/Adapter/Pdo/Mysql.php index 59c3880bc9..3ed5ae9c0f 100644 --- a/core/Db/Adapter/Pdo/Mysql.php +++ b/core/Db/Adapter/Pdo/Mysql.php @@ -92,8 +92,9 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface */ public function checkServerVersion() { - $serverVersion = $this->getServerVersion(); + $serverVersion = $this->getServerVersion(); $requiredVersion = Config::getInstance()->General['minimum_mysql_version']; + if (version_compare($serverVersion, $requiredVersion) === -1) { throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MySQL', $serverVersion, $requiredVersion))); } @@ -108,6 +109,7 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface { $serverVersion = $this->getServerVersion(); $clientVersion = $this->getClientVersion(); + // incompatible change to DECIMAL implementation in 5.0.3 if (version_compare($serverVersion, '5.0.3') >= 0 && version_compare($clientVersion, '5.0.3') < 0 @@ -159,6 +161,7 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface if (preg_match('/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $e->getMessage(), $match)) { return $match[1] == $errno; } + return false; } @@ -170,9 +173,11 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface public function isConnectionUTF8() { $charsetInfo = $this->fetchAll('SHOW VARIABLES LIKE ?', array('character_set_connection')); + if (empty($charsetInfo)) { return false; } + $charset = $charsetInfo[0]['Value']; return $charset === 'utf8'; } diff --git a/core/Db/Adapter/Pdo/Pgsql.php b/core/Db/Adapter/Pdo/Pgsql.php index c68280fe28..0a37ab2dc9 100644 --- a/core/Db/Adapter/Pdo/Pgsql.php +++ b/core/Db/Adapter/Pdo/Pgsql.php @@ -47,6 +47,7 @@ class Pgsql extends Zend_Db_Adapter_Pdo_Pgsql implements AdapterInterface { $databaseVersion = $this->getServerVersion(); $requiredVersion = Config::getInstance()->General['minimum_pgsql_version']; + if (version_compare($databaseVersion, $requiredVersion) === -1) { throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('PostgreSQL', $databaseVersion, $requiredVersion))); } @@ -146,6 +147,7 @@ class Pgsql extends Zend_Db_Adapter_Pdo_Pgsql implements AdapterInterface if (preg_match('/([0-9]{2}[0-9P][0-9]{2})/', $e->getMessage(), $match)) { return $match[1] == $map[$errno]; } + return false; } diff --git a/core/Db/BatchInsert.php b/core/Db/BatchInsert.php index 858dad4e38..1e818c2073 100644 --- a/core/Db/BatchInsert.php +++ b/core/Db/BatchInsert.php @@ -123,7 +123,7 @@ class BatchInsert { // Chroot environment: prefix the path with the absolute chroot path $chrootPath = Config::getInstance()->General['absolute_chroot_path']; - if(!empty($chrootPath)) { + if (!empty($chrootPath)) { $filePath = $chrootPath . $filePath; } diff --git a/core/Db/Schema.php b/core/Db/Schema.php index e210de5835..c7823cf70a 100644 --- a/core/Db/Schema.php +++ b/core/Db/Schema.php @@ -38,7 +38,7 @@ class Schema extends Singleton private static function getSchemaClassName($schemaName) { // Upgrade from pre 2.0.4 - if(strtolower($schemaName) == 'myisam' + if (strtolower($schemaName) == 'myisam' || empty($schemaName)) { $schemaName = self::DEFAULT_SCHEMA; } diff --git a/core/DeviceDetectorCache.php b/core/DeviceDetectorCache.php index 2c637aa95e..ba65b82c9f 100644 --- a/core/DeviceDetectorCache.php +++ b/core/DeviceDetectorCache.php @@ -32,6 +32,7 @@ class DeviceDetectorCache extends CacheFile implements \DeviceDetector\Cache\Cac if (empty($id)) { return false; } + $id = $this->cleanupId($id); if (array_key_exists($id, self::$staticCache)) { diff --git a/core/Error.php b/core/Error.php index f7decbbc16..c56e3301a7 100644 --- a/core/Error.php +++ b/core/Error.php @@ -8,11 +8,6 @@ */ namespace Piwik; -use Piwik\Common; -use Piwik\Log; -use Piwik\Piwik; -use Piwik\Version; - require_once PIWIK_INCLUDE_PATH . '/core/Log.php'; /** diff --git a/core/EventDispatcher.php b/core/EventDispatcher.php index d9d26b4377..d343da8beb 100644 --- a/core/EventDispatcher.php +++ b/core/EventDispatcher.php @@ -48,7 +48,7 @@ class EventDispatcher extends Singleton /** * Plugin\Manager instance used to get list of loaded plugins. * - * @var Piwik\Plugin\Manager + * @var \Piwik\Plugin\Manager */ private $pluginManager; diff --git a/core/ExceptionHandler.php b/core/ExceptionHandler.php index 0e526225d5..8566385070 100644 --- a/core/ExceptionHandler.php +++ b/core/ExceptionHandler.php @@ -9,7 +9,6 @@ namespace Piwik; use Piwik\API\ResponseBuilder; -use Piwik\Common; use Piwik\Plugin; /** diff --git a/core/Filechecks.php b/core/Filechecks.php index 33d0ed0696..3dc6d53195 100644 --- a/core/Filechecks.php +++ b/core/Filechecks.php @@ -43,7 +43,7 @@ class Filechecks $directoryToCheck = PIWIK_USER_PATH . $directoryToCheck; } - if(strpos($directoryToCheck, '/tmp/') !== false) { + if (strpos($directoryToCheck, '/tmp/') !== false) { $directoryToCheck = SettingsPiwik::rewriteTmpPathWithInstanceId($directoryToCheck); } @@ -87,9 +87,9 @@ class Filechecks $directoryList = "<code>chown -R ". self::getUserAndGroup() ." " . $realpath . "</code><br />" . $directoryList; } - if(function_exists('shell_exec')) { + if (function_exists('shell_exec')) { $currentUser = self::getUser(); - if(!empty($currentUser)) { + if (!empty($currentUser)) { $optionalUserInfo = " (running as user '" . $currentUser . "')"; } } @@ -211,13 +211,13 @@ class Filechecks private static function getUserAndGroup() { $user = self::getUser(); - if(!function_exists('shell_exec')) { + if (!function_exists('shell_exec')) { return $user . ':' . $user; } $group = trim(shell_exec('groups '. $user .' | cut -f3 -d" "')); - if(empty($group)) { + if (empty($group)) { $group = 'www-data'; } return $user . ':' . $group; @@ -225,7 +225,7 @@ class Filechecks private static function getUser() { - if(!function_exists('shell_exec')) { + if (!function_exists('shell_exec')) { return 'www-data'; } return trim(shell_exec('whoami')); diff --git a/core/FrontController.php b/core/FrontController.php index a50fb152ca..4b5ee6f20b 100644 --- a/core/FrontController.php +++ b/core/FrontController.php @@ -508,22 +508,22 @@ class FrontController extends Singleton protected function handleSSLRedirection() { // Specifically disable for the opt out iframe - if(Piwik::getModule() == 'CoreAdminHome' && Piwik::getAction() == 'optOut') { + if (Piwik::getModule() == 'CoreAdminHome' && Piwik::getAction() == 'optOut') { return; } // Disable Https for VisitorGenerator - if(Piwik::getModule() == 'VisitorGenerator') { + if (Piwik::getModule() == 'VisitorGenerator') { return; } - if(Common::isPhpCliMode()) { + if (Common::isPhpCliMode()) { return; } // Only enable this feature after Piwik is already installed - if(!SettingsPiwik::isPiwikInstalled()) { + if (!SettingsPiwik::isPiwikInstalled()) { return; } // proceed only when force_ssl = 1 - if(!SettingsPiwik::isHttpsForced()) { + if (!SettingsPiwik::isHttpsForced()) { return; } Url::redirectToHttps(); diff --git a/core/Http.php b/core/Http.php index 537330716a..16563ce617 100644 --- a/core/Http.php +++ b/core/Http.php @@ -165,7 +165,7 @@ class Http $aUrl = trim($aUrl); // other result data - $status = null; + $status = null; $headers = array(); if ($method == 'socket') { diff --git a/core/IP.php b/core/IP.php index 52f5f7c23f..691bc7442c 100644 --- a/core/IP.php +++ b/core/IP.php @@ -370,7 +370,7 @@ class IP { $proxyIps = array(); $config = Config::getInstance()->General; - if(isset($config['proxy_ips'])) { + if (isset($config['proxy_ips'])) { $proxyIps = $config['proxy_ips']; } if (!is_array($proxyIps)) { diff --git a/core/Log.php b/core/Log.php index a860dd1989..b3421d13e1 100644 --- a/core/Log.php +++ b/core/Log.php @@ -452,7 +452,7 @@ class Log extends Singleton if ($level == self::ERROR) { $message = $this->getMessageFormattedScreen($level, $tag, $datetime, $message); $this->writeErrorToStandardErrorOutput($message); - if(!isset($this->writers['screen'])) { + if (!isset($this->writers['screen'])) { echo $message; } } @@ -599,7 +599,7 @@ class Log extends Singleton */ private function writeErrorToStandardErrorOutput($message) { - if(defined('PIWIK_TEST_MODE')) { + if (defined('PIWIK_TEST_MODE')) { // do not log on stderr during tests (prevent display of errors in CI output) return; } diff --git a/core/Mail.php b/core/Mail.php index d26b08b154..179b1221ab 100644 --- a/core/Mail.php +++ b/core/Mail.php @@ -34,9 +34,13 @@ class Mail extends Zend_Mail public function setDefaultFromPiwik() { $customLogo = new CustomLogo(); - $fromEmailName = $customLogo->isEnabled() - ? Piwik::translate('CoreHome_WebAnalyticsReports') - : Piwik::translate('ScheduledReports_PiwikReports'); + + if ($customLogo->isEnabled()) { + $fromEmailName = Piwik::translate('CoreHome_WebAnalyticsReports'); + } else { + $fromEmailName = Piwik::translate('ScheduledReports_PiwikReports'); + } + $fromEmailAddress = Config::getInstance()->General['noreply_email_address']; $this->setFrom($fromEmailAddress, $fromEmailName); } @@ -77,20 +81,29 @@ class Mail extends Zend_Mail private function initSmtpTransport() { $mailConfig = Config::getInstance()->mail; + if (empty($mailConfig['host']) || $mailConfig['transport'] != 'smtp' ) { return; } + $smtpConfig = array(); - if (!empty($mailConfig['type'])) + if (!empty($mailConfig['type'])) { $smtpConfig['auth'] = strtolower($mailConfig['type']); - if (!empty($mailConfig['username'])) + } + + if (!empty($mailConfig['username'])) { $smtpConfig['username'] = $mailConfig['username']; - if (!empty($mailConfig['password'])) + } + + if (!empty($mailConfig['password'])) { $smtpConfig['password'] = $mailConfig['password']; - if (!empty($mailConfig['encryption'])) + } + + if (!empty($mailConfig['encryption'])) { $smtpConfig['ssl'] = $mailConfig['encryption']; + } $tr = new \Zend_Mail_Transport_Smtp($mailConfig['host'], $smtpConfig); Mail::setDefaultTransport($tr); @@ -112,12 +125,12 @@ class Mail extends Zend_Mail */ protected function parseDomainPlaceholderAsPiwikHostName($email) { - $hostname = Config::getInstance()->mail['defaultHostnameIfEmpty']; + $hostname = Config::getInstance()->mail['defaultHostnameIfEmpty']; $piwikHost = Url::getCurrentHost($hostname); // If known Piwik URL, use it instead of "localhost" $piwikUrl = SettingsPiwik::getPiwikUrl(); - $url = parse_url($piwikUrl); + $url = parse_url($piwikUrl); if ($this->isHostDefinedAndNotLocal($url)) { $piwikHost = $url['host']; } diff --git a/core/Menu/Group.php b/core/Menu/Group.php index 17e7c9bc5c..90e063e264 100644 --- a/core/Menu/Group.php +++ b/core/Menu/Group.php @@ -18,8 +18,8 @@ class Group public function add($subTitleMenu, $url, $tooltip = false) { $this->items[] = array( - 'name' => $subTitleMenu, - 'url' => $url, + 'name' => $subTitleMenu, + 'url' => $url, 'tooltip' => $tooltip );; } diff --git a/core/Menu/MenuAbstract.php b/core/Menu/MenuAbstract.php index 1fe1152c98..8fcc4786cc 100644 --- a/core/Menu/MenuAbstract.php +++ b/core/Menu/MenuAbstract.php @@ -9,7 +9,6 @@ namespace Piwik\Menu; use Piwik\Common; -use Piwik\Log; use Piwik\Plugins\SitesManager\API; use Piwik\Singleton; use Piwik\Plugin\Manager as PluginManager; @@ -215,8 +214,8 @@ abstract class MenuAbstract extends Singleton { foreach ($this->edits as $edit) { $mainMenuToEdit = $edit[0]; - $subMenuToEdit = $edit[1]; - $newUrl = $edit[2]; + $subMenuToEdit = $edit[1]; + $newUrl = $edit[2]; if ($subMenuToEdit === null) { $menuDataToEdit = @$this->menu[$mainMenuToEdit]; @@ -236,14 +235,14 @@ abstract class MenuAbstract extends Singleton { foreach($this->menuEntriesToRemove as $menuToDelete) { - if(empty($menuToDelete[1])) { + if (empty($menuToDelete[1])) { // Delete Main Menu - if(isset($this->menu[$menuToDelete[0]])) { + if (isset($this->menu[$menuToDelete[0]])) { unset($this->menu[$menuToDelete[0]]); } } else { // Delete Sub Menu - if(isset($this->menu[$menuToDelete[0]][$menuToDelete[1]])) { + if (isset($this->menu[$menuToDelete[0]][$menuToDelete[1]])) { unset($this->menu[$menuToDelete[0]][$menuToDelete[1]]); } } @@ -256,9 +255,10 @@ abstract class MenuAbstract extends Singleton { foreach ($this->renames as $rename) { $mainMenuOriginal = $rename[0]; - $subMenuOriginal = $rename[1]; - $mainMenuRenamed = $rename[2]; - $subMenuRenamed = $rename[3]; + $subMenuOriginal = $rename[1]; + $mainMenuRenamed = $rename[2]; + $subMenuRenamed = $rename[3]; + // Are we changing a submenu? if (!empty($subMenuOriginal)) { if (isset($this->menu[$mainMenuOriginal][$subMenuOriginal])) { diff --git a/core/Menu/MenuAdmin.php b/core/Menu/MenuAdmin.php index 5c814b6706..13e8480596 100644 --- a/core/Menu/MenuAdmin.php +++ b/core/Menu/MenuAdmin.php @@ -45,7 +45,9 @@ class MenuAdmin extends MenuAbstract */ public static function addEntry($adminMenuName, $url, $displayedForCurrentUser = true, $order = 20) { - self::getInstance()->add('General_Settings', $adminMenuName, $url, $displayedForCurrentUser, $order); + if ($displayedForCurrentUser) { + self::getInstance()->addItem('General_Settings', $adminMenuName, $url, $order); + } } /** @@ -59,7 +61,7 @@ class MenuAdmin extends MenuAbstract */ public function addDevelopmentItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('CoreAdminHome_MenuDevelopment', $menuName, $url, true, $order, $tooltip); + $this->addItem('CoreAdminHome_MenuDevelopment', $menuName, $url, $order, $tooltip); } /** @@ -73,7 +75,7 @@ class MenuAdmin extends MenuAbstract */ public function addDiagnosticItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('CoreAdminHome_MenuDiagnostic', $menuName, $url, true, $order, $tooltip); + $this->addItem('CoreAdminHome_MenuDiagnostic', $menuName, $url, $order, $tooltip); } /** @@ -87,7 +89,7 @@ class MenuAdmin extends MenuAbstract */ public function addPlatformItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('CorePluginsAdmin_MenuPlatform', $menuName, $url, true, $order, $tooltip); + $this->addItem('CorePluginsAdmin_MenuPlatform', $menuName, $url, $order, $tooltip); } /** @@ -101,7 +103,7 @@ class MenuAdmin extends MenuAbstract */ public function addSettingsItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('General_Settings', $menuName, $url, true, $order, $tooltip); + $this->addItem('General_Settings', $menuName, $url, $order, $tooltip); } /** @@ -115,7 +117,7 @@ class MenuAdmin extends MenuAbstract */ public function addManageItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('CoreAdminHome_MenuManage', $menuName, $url, true, $order, $tooltip); + $this->addItem('CoreAdminHome_MenuManage', $menuName, $url, $order, $tooltip); } /** diff --git a/core/Menu/MenuMain.php b/core/Menu/MenuMain.php index 5f27f3229e..adb6b538e9 100644 --- a/core/Menu/MenuMain.php +++ b/core/Menu/MenuMain.php @@ -11,7 +11,7 @@ namespace Piwik\Menu; /** * @deprecated since 2.4.0 * @see MenuReporting - * @method static \Piwik\Menu\MenuMain getInstance() + * @method static MenuMain getInstance() * @ignore */ class MenuMain extends MenuReporting diff --git a/core/Menu/MenuReporting.php b/core/Menu/MenuReporting.php index 28fddd8313..ac35151bcb 100644 --- a/core/Menu/MenuReporting.php +++ b/core/Menu/MenuReporting.php @@ -45,7 +45,7 @@ class MenuReporting extends MenuAbstract */ public function addVisitorsItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('General_Visitors', $menuName, $url, true, $order, $tooltip); + $this->addItem('General_Visitors', $menuName, $url, $order, $tooltip); } /** @@ -59,7 +59,7 @@ class MenuReporting extends MenuAbstract */ public function addActionsItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('General_Actions', $menuName, $url, true, $order, $tooltip); + $this->addItem('General_Actions', $menuName, $url, $order, $tooltip); } /** @@ -88,7 +88,7 @@ class MenuReporting extends MenuAbstract */ public function addReferrersItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('Referrers_Referrers', $menuName, $url, true, $order, $tooltip); + $this->addItem('Referrers_Referrers', $menuName, $url, $order, $tooltip); } /** diff --git a/core/Menu/MenuUser.php b/core/Menu/MenuUser.php index ad9b195d46..758ac3d578 100755 --- a/core/Menu/MenuUser.php +++ b/core/Menu/MenuUser.php @@ -26,7 +26,7 @@ namespace Piwik\Menu; * ); * } * - * @method static \Piwik\Menu\MenuUser getInstance() + * @method static MenuUser getInstance() */ class MenuUser extends MenuAbstract { @@ -42,7 +42,7 @@ class MenuUser extends MenuAbstract */ public function addManageItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('CoreAdminHome_MenuManage', $menuName, $url, true, $order, $tooltip); + $this->addItem('CoreAdminHome_MenuManage', $menuName, $url, $order, $tooltip); } /** @@ -56,7 +56,7 @@ class MenuUser extends MenuAbstract */ public function addPlatformItem($menuName, $url, $order = 50, $tooltip = false) { - $this->add('CorePluginsAdmin_MenuPlatform', $menuName, $url, true, $order, $tooltip); + $this->addItem('CorePluginsAdmin_MenuPlatform', $menuName, $url, $order, $tooltip); } /** diff --git a/core/Metrics.php b/core/Metrics.php index 03b9e2e094..0f8baf5a10 100644 --- a/core/Metrics.php +++ b/core/Metrics.php @@ -175,9 +175,11 @@ class Metrics public static function getVisitsMetricNames() { $names = array(); + foreach (self::$metricsAggregatedFromLogs as $metricId) { $names[$metricId] = self::$mappingFromIdToName[$metricId]; } + return $names; } diff --git a/core/Metrics/Processed.php b/core/Metrics/Processed.php index bbc638828a..0e6b7c969b 100644 --- a/core/Metrics/Processed.php +++ b/core/Metrics/Processed.php @@ -11,8 +11,6 @@ namespace Piwik\Metrics; use Piwik\Metrics; use Piwik\DataTable\Row; use Piwik\DataTable; -use Piwik\Piwik; -use Piwik\Tracker\GoalManager; class Processed extends Base { diff --git a/core/MetricsFormatter.php b/core/MetricsFormatter.php index 8c58215e30..8554663525 100644 --- a/core/MetricsFormatter.php +++ b/core/MetricsFormatter.php @@ -61,10 +61,10 @@ class MetricsFormatter // Display 01:45:17 time format if ($displayTimeAsSentence === false) { - $hours = floor($numberOfSeconds / 3600); + $hours = floor($numberOfSeconds / 3600); $minutes = floor(($reminder = ($numberOfSeconds - $hours * 3600)) / 60); $seconds = floor($reminder - $minutes * 60); - $time = sprintf("%02s", $hours) . ':' . sprintf("%02s", $minutes) . ':' . sprintf("%02s", $seconds); + $time = sprintf("%02s", $hours) . ':' . sprintf("%02s", $minutes) . ':' . sprintf("%02s", $seconds); $centiSeconds = ($numberOfSeconds * 100) % 100; if ($centiSeconds) { $time .= '.' . sprintf("%02s", $centiSeconds); @@ -76,19 +76,19 @@ class MetricsFormatter } $secondsInYear = 86400 * 365.25; - $years = floor($numberOfSeconds / $secondsInYear); + $years = floor($numberOfSeconds / $secondsInYear); $minusYears = $numberOfSeconds - $years * $secondsInYear; - $days = floor($minusYears / 86400); + $days = floor($minusYears / 86400); $minusDays = $numberOfSeconds - $days * 86400; - $hours = floor($minusDays / 3600); + $hours = floor($minusDays / 3600); $minusDaysAndHours = $minusDays - $hours * 3600; $minutes = floor($minusDaysAndHours / 60); - $seconds = $minusDaysAndHours - $minutes * 60; + $seconds = $minusDaysAndHours - $minutes * 60; $precision = ($seconds > 0 && $seconds < 0.01 ? 3 : 2); - $seconds = round($seconds, $precision); + $seconds = round($seconds, $precision); if ($years > 0) { $return = sprintf(Piwik::translate('General_YearsDays'), $years, $days); @@ -109,6 +109,7 @@ class MetricsFormatter if ($isHtml) { return str_replace(' ', ' ', $return); } + return $return; } @@ -134,6 +135,7 @@ class MetricsFormatter break; } } + return round($size, $precision) . " " . $currentUnit; } @@ -175,6 +177,7 @@ class MetricsFormatter $value = sprintf("%01." . $precision . "f", $value); } } + $prettyMoney = $currencyBefore . $space . $value . $currencyAfter; return $prettyMoney; } @@ -196,16 +199,19 @@ class MetricsFormatter $timeAsSentence = (substr($columnName, -16) == '_time_generation'); return self::getPrettyTimeFromSeconds($value, $timeAsSentence); } + // Add revenue symbol to revenues if (strpos($columnName, 'revenue') !== false && strpos($columnName, 'evolution') === false) { return self::getPrettyMoney($value, $idSite, $isHtml); } + // Add % symbol to rates if (strpos($columnName, '_rate') !== false) { if (strpos($value, "%") === false) { return $value . "%"; } } + return $value; } @@ -217,12 +223,14 @@ class MetricsFormatter */ public static function getCurrencySymbol($idSite) { - $symbols = MetricsFormatter::getCurrencyList(); - $site = new Site($idSite); + $symbols = MetricsFormatter::getCurrencyList(); + $site = new Site($idSite); $currency = $site->getCurrency(); + if (isset($symbols[$currency])) { return $symbols[$currency][0]; } + return ''; } @@ -235,10 +243,12 @@ class MetricsFormatter public static function getCurrencyList() { static $currenciesList = null; + if (is_null($currenciesList)) { require_once PIWIK_INCLUDE_PATH . '/core/DataFiles/Currencies.php'; $currenciesList = $GLOBALS['Piwik_CurrencyList']; } + return $currenciesList; } } diff --git a/core/Nonce.php b/core/Nonce.php index 3937c4f94b..1b64b87933 100644 --- a/core/Nonce.php +++ b/core/Nonce.php @@ -160,7 +160,7 @@ class Nonce * @param string $nonceName The nonce's unique ID. See {@link getNonce()}. * @param string|null $nonce The nonce from the client. If `null`, the value from the * **nonce** query parameter is used. - * @throws Exception if the nonce is invalid. See {@link verifyNonce()}. + * @throws \Exception if the nonce is invalid. See {@link verifyNonce()}. */ public static function checkNonce($nonceName, $nonce = null) { diff --git a/core/Option.php b/core/Option.php index c2c7816bba..c4410520ea 100644 --- a/core/Option.php +++ b/core/Option.php @@ -68,7 +68,7 @@ class Option */ public static function set($name, $value, $autoload = 0) { - return self::getInstance()->setValue($name, $value, $autoload); + self::getInstance()->setValue($name, $value, $autoload); } /** @@ -79,7 +79,7 @@ class Option */ public static function delete($name, $value = null) { - return self::getInstance()->deleteValue($name, $value); + self::getInstance()->deleteValue($name, $value); } /** @@ -91,7 +91,7 @@ class Option */ public static function deleteLike($namePattern, $value = null) { - return self::getInstance()->deleteNameLike($namePattern, $value); + self::getInstance()->deleteNameLike($namePattern, $value); } public static function clearCachedOption($name) @@ -162,12 +162,13 @@ class Option if (isset($this->all[$name])) { return $this->all[$name]; } - $value = Db::fetchOne('SELECT option_value ' . - 'FROM `' . Common::prefixTable('option') . '` ' . - 'WHERE option_name = ?', $name); + $value = Db::fetchOne('SELECT option_value FROM `' . Common::prefixTable('option') . '` ' . + 'WHERE option_name = ?', $name); + if ($value === false) { return false; } + $this->all[$name] = $value; return $value; } @@ -184,11 +185,11 @@ class Option protected function deleteValue($name, $value) { - $sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name = ?'; + $sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name = ?'; $bind[] = $name; if (isset($value)) { - $sql .= ' AND option_value = ?'; + $sql .= ' AND option_value = ?'; $bind[] = $value; } @@ -199,11 +200,11 @@ class Option protected function deleteNameLike($name, $value = null) { - $sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?'; + $sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?'; $bind[] = $name; if (isset($value)) { - $sql .= ' AND option_value = ?'; + $sql .= ' AND option_value = ?'; $bind[] = $value; } @@ -214,7 +215,7 @@ class Option protected function getNameLike($name) { - $sql = 'SELECT option_name, option_value FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?'; + $sql = 'SELECT option_name, option_value FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?'; $bind = array($name); $result = array(); @@ -235,9 +236,8 @@ class Option return; } - $all = Db::fetchAll('SELECT option_value, option_name - FROM `' . Common::prefixTable('option') . '` - WHERE autoload = 1'); + $all = Db::fetchAll('SELECT option_value, option_name FROM `' . Common::prefixTable('option') . '` + WHERE autoload = 1'); foreach ($all as $option) { $this->all[$option['option_name']] = $option['option_value']; } diff --git a/core/Period.php b/core/Period.php index 6898020ce7..1e3f188b5e 100644 --- a/core/Period.php +++ b/core/Period.php @@ -100,16 +100,20 @@ abstract class Period public function getDateStart() { $this->generate(); + if (count($this->subperiods) == 0) { return $this->getDate(); } + $periods = $this->getSubperiods(); + /** @var $currentPeriod Period */ $currentPeriod = $periods[0]; while ($currentPeriod->getNumberOfSubperiods() > 0) { - $periods = $currentPeriod->getSubperiods(); + $periods = $currentPeriod->getSubperiods(); $currentPeriod = $periods[0]; } + return $currentPeriod->getDate(); } @@ -121,16 +125,20 @@ abstract class Period public function getDateEnd() { $this->generate(); + if (count($this->subperiods) == 0) { return $this->getDate(); } + $periods = $this->getSubperiods(); + /** @var $currentPeriod Period */ $currentPeriod = $periods[count($periods) - 1]; while ($currentPeriod->getNumberOfSubperiods() > 0) { - $periods = $currentPeriod->getSubperiods(); + $periods = $currentPeriod->getSubperiods(); $currentPeriod = $periods[count($periods) - 1]; } + return $currentPeriod->getDate(); } @@ -212,10 +220,12 @@ abstract class Period public function toString($format = "Y-m-d") { $this->generate(); + $dateString = array(); foreach ($this->subperiods as $period) { $dateString[] = $period->toString($format); } + return $dateString; } @@ -259,6 +269,9 @@ abstract class Period */ public function getRangeString() { - return $this->getDateStart()->toString("Y-m-d") . "," . $this->getDateEnd()->toString("Y-m-d"); + $dateStart = $this->getDateStart(); + $dateEnd = $this->getDateEnd(); + + return $dateStart->toString("Y-m-d") . "," . $dateEnd->toString("Y-m-d"); } } diff --git a/core/Period/Day.php b/core/Period/Day.php index 5f64627e45..b8212844cd 100644 --- a/core/Period/Day.php +++ b/core/Period/Day.php @@ -37,8 +37,10 @@ class Day extends Period public function getLocalizedShortString() { //"Mon 15 Aug" - $date = $this->getDateStart(); - $out = $date->getLocalized(Piwik::translate('CoreHome_ShortDateFormat')); + $date = $this->getDateStart(); + $template = Piwik::translate('CoreHome_ShortDateFormat'); + + $out = $date->getLocalized($template); return $out; } @@ -50,8 +52,9 @@ class Day extends Period public function getLocalizedLongString() { //"Mon 15 Aug" - $date = $this->getDateStart(); + $date = $this->getDateStart(); $template = Piwik::translate('CoreHome_DateFormat'); + $out = $date->getLocalized($template); return $out; } diff --git a/core/Period/Factory.php b/core/Period/Factory.php index b490956531..05303f40df 100644 --- a/core/Period/Factory.php +++ b/core/Period/Factory.php @@ -60,7 +60,7 @@ class Factory public static function checkPeriodIsEnabled($period) { - if(!self::isPeriodEnabledForAPI($period)) { + if (!self::isPeriodEnabledForAPI($period)) { self::throwExceptionInvalidPeriod($period); } } diff --git a/core/Period/Month.php b/core/Period/Month.php index 167280f15b..4609180980 100644 --- a/core/Period/Month.php +++ b/core/Period/Month.php @@ -60,6 +60,7 @@ class Month extends Period if ($this->subperiodsProcessed) { return; } + parent::generate(); $date = $this->date; diff --git a/core/Period/Range.php b/core/Period/Range.php index 2ea6ab1792..36692dc0de 100644 --- a/core/Period/Range.php +++ b/core/Period/Range.php @@ -45,12 +45,14 @@ class Range extends Period public function __construct($strPeriod, $strDate, $timezone = 'UTC', $today = false) { $this->strPeriod = $strPeriod; - $this->strDate = $strDate; + $this->strDate = $strDate; + $this->timezone = $timezone; $this->defaultEndDate = null; - $this->timezone = $timezone; + if ($today === false) { $today = Date::factory('now', $this->timezone); } + $this->today = $today; } @@ -63,10 +65,12 @@ class Range extends Period { //"30 Dec 08 - 26 Feb 09" $dateStart = $this->getDateStart(); - $dateEnd = $this->getDateEnd(); - $template = Piwik::translate('CoreHome_ShortDateFormatWithYear'); + $dateEnd = $this->getDateEnd(); + $template = Piwik::translate('CoreHome_ShortDateFormatWithYear'); + $shortDateStart = $dateStart->getLocalized($template); - $shortDateEnd = $dateEnd->getLocalized($template); + $shortDateEnd = $dateEnd->getLocalized($template); + $out = "$shortDateStart - $shortDateEnd"; return $out; } @@ -90,9 +94,11 @@ class Range extends Period public function getDateStart() { $dateStart = parent::getDateStart(); + if (empty($dateStart)) { throw new Exception("Specified date range is invalid."); } + return $dateStart; } @@ -203,10 +209,12 @@ class Range extends Period } else { throw new Exception(Piwik::translate('General_ExceptionInvalidDateRange', array($this->strDate, ' \'lastN\', \'previousN\', \'YYYY-MM-DD,YYYY-MM-DD\''))); } + if ($this->strPeriod != 'range') { $this->fillArraySubPeriods($startDate, $endDate, $this->strPeriod); return; } + $this->processOptimalSubperiods($startDate, $endDate); // When period=range, we want End Date to be the actual specified end date, // rather than the end of the month / week / whatever is used for processing this range @@ -223,9 +231,11 @@ class Range extends Period public static function parseDateRange($dateString) { $matched = preg_match('/^([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}),(([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})|today|now|yesterday)$/D', trim($dateString), $regs); + if (empty($matched)) { return false; } + return $regs; } @@ -241,6 +251,7 @@ class Range extends Period if (!is_null($this->endDate)) { return $this->endDate; } + return parent::getDateEnd(); } @@ -425,7 +436,7 @@ class Range extends Period * @param int $lastN The number of periods of type `$period` that the result range should * span. * @param string $endDate The desired end date of the range. - * @param Site $site The site whose timezone should be used. + * @param \Piwik\Site $site The site whose timezone should be used. * @return string The date range string, eg, `'2012-01-02,2013-01-02'`. * @api */ @@ -434,6 +445,7 @@ class Range extends Period $last30Relative = new Range($period, $lastN, $site->getTimezone()); $last30Relative->setDefaultEndDate(Date::factory($endDate)); $date = $last30Relative->getDateStart()->toString() . "," . $last30Relative->getDateEnd()->toString(); + return $date; } diff --git a/core/Period/Week.php b/core/Period/Week.php index f7b7264943..23f7ab32b6 100644 --- a/core/Period/Week.php +++ b/core/Period/Week.php @@ -26,7 +26,7 @@ class Week extends Period { //"30 Dec - 6 Jan 09" $dateStart = $this->getDateStart(); - $dateEnd = $this->getDateEnd(); + $dateEnd = $this->getDateEnd(); $string = Piwik::translate('CoreHome_ShortWeekFormat'); $string = self::getTranslatedRange($string, $dateStart, $dateEnd); @@ -42,6 +42,7 @@ class Week extends Period { $format = Piwik::translate('CoreHome_LongWeekFormat'); $string = self::getTranslatedRange($format, $this->getDateStart(), $this->getDateEnd()); + return Piwik::translate('CoreHome_PeriodWeek') . " " . $string; } @@ -58,6 +59,7 @@ class Week extends Period $string = $dateStart->getLocalized($string); $string = str_replace('To%', '%', $string); $string = $dateEnd->getLocalized($string); + return $string; } @@ -68,10 +70,11 @@ class Week extends Period */ public function getPrettyString() { - $out = Piwik::translate('General_DateRangeFromTo', - array($this->getDateStart()->toString(), - $this->getDateEnd()->toString()) - ); + $dateStart = $this->getDateStart(); + $dateEnd = $this->getDateEnd(); + + $out = Piwik::translate('General_DateRangeFromTo', array($dateStart->toString(), $dateEnd->toString())); + return $out; } @@ -83,6 +86,7 @@ class Week extends Period if ($this->subperiodsProcessed) { return; } + parent::generate(); $date = $this->date; diff --git a/core/Period/Year.php b/core/Period/Year.php index 3582161e3a..cb2d202ff7 100644 --- a/core/Period/Year.php +++ b/core/Period/Year.php @@ -58,6 +58,7 @@ class Year extends Period if ($this->subperiodsProcessed) { return; } + parent::generate(); $year = $this->date->toString("Y"); @@ -78,10 +79,12 @@ class Year extends Period function toString($format = 'ignored') { $this->generate(); + $stringMonth = array(); foreach ($this->subperiods as $month) { $stringMonth[] = $month->getDateStart()->toString("Y") . "-" . $month->getDateStart()->toString("m") . "-01"; } + return $stringMonth; } } diff --git a/core/Piwik.php b/core/Piwik.php index c00d5e42e9..ea49b72675 100644 --- a/core/Piwik.php +++ b/core/Piwik.php @@ -9,7 +9,6 @@ namespace Piwik; use Exception; -use Piwik\Common; use Piwik\Db\Adapter; use Piwik\Db\Schema; use Piwik\Db; @@ -135,7 +134,7 @@ class Piwik // changes made to this code should be mirrored in plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js var generateJsCode $jsCode = file_get_contents(PIWIK_INCLUDE_PATH . "/plugins/Morpheus/templates/javascriptCode.tpl"); $jsCode = htmlentities($jsCode); - if(substr($piwikUrl, 0, 4) !== 'http') { + if (substr($piwikUrl, 0, 4) !== 'http') { $piwikUrl = 'http://' . $piwikUrl; } preg_match('~^(http|https)://(.*)$~D', $piwikUrl, $matches); @@ -889,4 +888,4 @@ class Piwik return $result; } -}
\ No newline at end of file +} diff --git a/core/Plugin.php b/core/Plugin.php index 8839a96212..55a70ab501 100644 --- a/core/Plugin.php +++ b/core/Plugin.php @@ -354,7 +354,7 @@ class Plugin if ($this->cache->has()) { $components = $this->cache->get(); - if($this->includeComponents($components)) { + if ($this->includeComponents($components)) { return $components; } else { // problem including one cached file, refresh cache diff --git a/core/Plugin/ComponentFactory.php b/core/Plugin/ComponentFactory.php index 68415e9397..9cb9cd1c1b 100644 --- a/core/Plugin/ComponentFactory.php +++ b/core/Plugin/ComponentFactory.php @@ -74,7 +74,7 @@ class ComponentFactory * @param callback $predicate * @return mixed The component that satisfies $predicate or null if not found. */ - public static function getComponentIf($componentTypeClass, $pluginName, $predicate) + public static function getComponentif ($componentTypeClass, $pluginName, $predicate) { $pluginManager = PluginManager::getInstance(); diff --git a/core/Plugin/ConsoleCommand.php b/core/Plugin/ConsoleCommand.php index 884b6f60ee..29e2fc65f6 100644 --- a/core/Plugin/ConsoleCommand.php +++ b/core/Plugin/ConsoleCommand.php @@ -8,7 +8,6 @@ */ namespace Piwik\Plugin; -use Piwik\Common; use Symfony\Component\Console\Command\Command as SymfonyCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/core/Plugin/Controller.php b/core/Plugin/Controller.php index 3ebad0f1ed..53ceab3f75 100644 --- a/core/Plugin/Controller.php +++ b/core/Plugin/Controller.php @@ -897,7 +897,7 @@ abstract class Controller $tokenRequest = Common::getRequestVar('token_auth', false); $tokenUser = Piwik::getCurrentUserTokenAuth(); - if(empty($tokenRequest) && empty($tokenUser)) { + if (empty($tokenRequest) && empty($tokenUser)) { return; // UI tests } diff --git a/core/Plugin/ControllerAdmin.php b/core/Plugin/ControllerAdmin.php index b18fe67de6..e563e759f9 100644 --- a/core/Plugin/ControllerAdmin.php +++ b/core/Plugin/ControllerAdmin.php @@ -43,6 +43,7 @@ abstract class ControllerAdmin extends Controller private static function notifyAnyInvalidPlugin() { $missingPlugins = \Piwik\Plugin\Manager::getInstance()->getMissingPlugins(); + if (empty($missingPlugins)) { return; } @@ -50,9 +51,11 @@ abstract class ControllerAdmin extends Controller if (!Piwik::hasUserSuperUserAccess()) { return; } + $pluginsLink = Url::getCurrentQueryStringWithParametersModified(array( 'module' => 'CorePluginsAdmin', 'action' => 'plugins' )); + $invalidPluginsWarning = Piwik::translate('CoreAdminHome_InvalidPluginsWarning', array( self::getPiwikVersion(), '<strong>' . implode('</strong>, <strong>', $missingPlugins) . '</strong>')) @@ -167,8 +170,10 @@ abstract class ControllerAdmin extends Controller $view->currentAdminMenuName = MenuAdmin::getInstance()->getCurrentAdminMenuName(); $view->isDataPurgeSettingsEnabled = self::isDataPurgeSettingsEnabled(); - $view->enableFrames = PiwikConfig::getInstance()->General['enable_framed_settings']; - if (!$view->enableFrames) { + $enableFrames = PiwikConfig::getInstance()->General['enable_framed_settings']; + $view->enableFrames = $enableFrames; + + if (!$enableFrames) { $view->setXFrameOptions('sameorigin'); } @@ -192,6 +197,7 @@ abstract class ControllerAdmin extends Controller $view->adminMenu = $adminMenu; $notifications = $view->notifications; + if (empty($notifications)) { $view->notifications = NotificationManager::getAllNotificationsToDisplay(); NotificationManager::cancelAllNonPersistent(); diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php index eb234c1b6c..da2ba679df 100644 --- a/core/Plugin/Manager.php +++ b/core/Plugin/Manager.php @@ -10,8 +10,6 @@ namespace Piwik\Plugin; use Piwik\Cache\PersistentCache; -use Piwik\Cache\PluginAwareStaticCache; -use Piwik\Cache\StaticCache; use Piwik\CacheFile; use Piwik\Common; use Piwik\Config as PiwikConfig; @@ -38,7 +36,7 @@ require_once PIWIK_INCLUDE_PATH . '/core/EventDispatcher.php'; /** * The singleton that manages plugin loading/unloading and installation/uninstallation. * - * @method static \Piwik\Plugin\Manager getInstance() + * @method static Manager getInstance() */ class Manager extends Singleton { @@ -166,7 +164,7 @@ class Manager extends Singleton public function isPluginOfficialAndNotBundledWithCore($pluginName) { static $gitModules; - if(empty($gitModules)) { + if (empty($gitModules)) { $gitModules = file_get_contents(PIWIK_INCLUDE_PATH . '/.gitmodules'); } // All submodules are officially maintained plugins @@ -541,7 +539,7 @@ class Manager extends Singleton $listPlugins = array_unique($listPlugins); foreach ($listPlugins as $pluginName) { // Hide plugins that are never going to be used - if($this->isPluginBogus($pluginName)) { + if ($this->isPluginBogus($pluginName)) { continue; } @@ -609,15 +607,15 @@ class Manager extends Singleton protected function isPluginThirdPartyAndBogus($pluginName) { - if($this->isPluginBundledWithCore($pluginName)) { + if ($this->isPluginBundledWithCore($pluginName)) { return false; } - if($this->isPluginBogus($pluginName)) { + if ($this->isPluginBogus($pluginName)) { return true; } $path = $this->getPluginsDirectory() . $pluginName; - if(!$this->isManifestFileFound($path)) { + if (!$this->isManifestFileFound($path)) { return true; } return false; @@ -773,7 +771,7 @@ class Manager extends Singleton $plugins = $this->getLoadedPlugins(); $enabled = $this->getActivatedPlugins(); - if(empty($enabled)) { + if (empty($enabled)) { return array(); } $enabled = array_combine($enabled, $enabled); diff --git a/core/Plugin/MetadataLoader.php b/core/Plugin/MetadataLoader.php index 25f48ce0a0..34bb90dcdc 100644 --- a/core/Plugin/MetadataLoader.php +++ b/core/Plugin/MetadataLoader.php @@ -101,6 +101,7 @@ class MetadataLoader ) { throw new Exception("Invalid JSON file: $path"); } + return $info; } } diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php index 6d950babd2..9037ce664c 100644 --- a/core/Plugin/Report.php +++ b/core/Plugin/Report.php @@ -328,11 +328,12 @@ class Report { if ($this->menuTitle) { $action = $this->getMenuControllerAction(); - $menu->add($this->category, - $this->menuTitle, - array('module' => $this->module, 'action' => $action), - $this->isEnabled(), - $this->order); + if ($this->isEnabled()) { + $menu->addItem($this->category, + $this->menuTitle, + array('module' => $this->module, 'action' => $action), + $this->order); + } } } @@ -731,7 +732,7 @@ class Report */ public static function getForDimension(Dimension $dimension) { - return ComponentFactory::getComponentIf(__CLASS__, $dimension->getModule(), function (Report $report) use ($dimension) { + return ComponentFactory::getComponentif (__CLASS__, $dimension->getModule(), function (Report $report) use ($dimension) { return !$report->isSubtableReport() && $report->getDimension() && $report->getDimension()->getId() == $dimension->getId(); diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php index d7f72028cf..4f3b854127 100644 --- a/core/Plugin/ViewDataTable.php +++ b/core/Plugin/ViewDataTable.php @@ -275,11 +275,11 @@ abstract class ViewDataTable implements ViewInterface protected function assignRelatedReportsTitle() { - if(!empty($this->config->related_reports_title)) { + if (!empty($this->config->related_reports_title)) { // title already assigned by a plugin return; } - if(count($this->config->related_reports) == 1) { + if (count($this->config->related_reports) == 1) { $this->config->related_reports_title = Piwik::translate('General_RelatedReport') . ':'; } else { $this->config->related_reports_title = Piwik::translate('General_RelatedReports') . ':'; diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php index e82a8d7f73..e7e79c62e2 100644 --- a/core/Plugin/Visualization.php +++ b/core/Plugin/Visualization.php @@ -498,6 +498,7 @@ class Visualization extends ViewDataTable 'filter_excludelowpop', 'filter_excludelowpop_value', ); + foreach ($deleteFromJavascriptVariables as $name) { if (isset($javascriptVariablesToSet[$name])) { unset($javascriptVariablesToSet[$name]); diff --git a/core/Profiler.php b/core/Profiler.php index 7468b1f5d6..2b92583d89 100644 --- a/core/Profiler.php +++ b/core/Profiler.php @@ -143,7 +143,7 @@ class Profiler { $totalTime = self::getDbElapsedSecs(); $queryCount = Profiler::getQueryCount(); - if($queryCount > 0) { + if ($queryCount > 0) { Log::debug(sprintf("Total queries = %d (total sql time = %.2fs)", $queryCount, $totalTime)); } } @@ -234,7 +234,7 @@ class Profiler $currentGitBranch = SettingsPiwik::getCurrentGitBranch(); $profilerNamespace = "piwik"; - if($currentGitBranch != 'master') { + if ($currentGitBranch != 'master') { $profilerNamespace .= "." . $currentGitBranch; } @@ -326,7 +326,7 @@ class Profiler { $runIds = file_get_contents( self::getPathToXHProfRunIds() ); $array = json_decode($runIds, $assoc = true); - if(!is_array($array)) { + if (!is_array($array)) { $array = array(); } return $array; diff --git a/core/ProxyHttp.php b/core/ProxyHttp.php index a1e7fda32c..69f7144b44 100644 --- a/core/ProxyHttp.php +++ b/core/ProxyHttp.php @@ -233,6 +233,7 @@ class ProxyHttp // FastCGI $key = 'Status:'; } + Common::sendHeader($key . ' ' . $status); } diff --git a/core/RankingQuery.php b/core/RankingQuery.php index f40ae1273e..f44845f075 100644 --- a/core/RankingQuery.php +++ b/core/RankingQuery.php @@ -215,7 +215,7 @@ class RankingQuery public function execute($innerQuery, $bind = array()) { $query = $this->generateQuery($innerQuery); - $data = Db::fetchAll($query, $bind); + $data = Db::fetchAll($query, $bind); if ($this->columnToMarkExcludedRows !== false) { // split the result into the regular result and the rows with special treatment diff --git a/core/Registry.php b/core/Registry.php index c57420e6f5..5022bf09e2 100644 --- a/core/Registry.php +++ b/core/Registry.php @@ -11,7 +11,7 @@ namespace Piwik; /** * Registry class. * - * @method static \Piwik\Registry getInstance() + * @method static Registry getInstance() * @api */ class Registry extends Singleton diff --git a/core/ReportRenderer/Csv.php b/core/ReportRenderer/Csv.php index 23ace2ac4d..94eca5172a 100644 --- a/core/ReportRenderer/Csv.php +++ b/core/ReportRenderer/Csv.php @@ -105,7 +105,7 @@ class Csv extends ReportRenderer ); $reportData = $csvRenderer->render($processedReport); - if(empty($reportData)) { + if (empty($reportData)) { $reportData = Piwik::translate('CoreHome_ThereIsNoDataForThisReport'); } diff --git a/core/ScheduledTask.php b/core/ScheduledTask.php index 15b702dab8..d570f5bea2 100644 --- a/core/ScheduledTask.php +++ b/core/ScheduledTask.php @@ -77,6 +77,7 @@ class ScheduledTask * should be executed and how long before the next execution. * @param int $priority The priority of the task. Tasks with a higher priority will be executed first. * Tasks with low priority will be executed last. + * @throws Exception */ public function __construct($objectInstance, $methodName, $methodParameter, $scheduledTime, $priority = self::NORMAL_PRIORITY) diff --git a/core/ScheduledTime.php b/core/ScheduledTime.php index f221a82a43..3da4afe98b 100644 --- a/core/ScheduledTime.php +++ b/core/ScheduledTime.php @@ -183,7 +183,7 @@ abstract class ScheduledTime * and a string description of the day within the period to execute the task on. * * @param string $periodType The scheduled period type. Can be `'hourly'`, `'daily'`, `'weekly'`, or `'monthly'`. - * @param string|int|false $periodDay A string describing the day within the scheduled period to execute + * @param bool|false|int|string $periodDay A string describing the day within the scheduled period to execute * the task on. Only valid for week and month periods. * * If `'weekly'` is supplied for `$periodType`, this should be a day @@ -192,6 +192,7 @@ abstract class ScheduledTime * If `'monthly'` is supplied for `$periodType`, this can be a numeric * day in the month or a day in one week of the month. For example, * `12`, `23`, `'first sunday'` or `'fourth tuesday'`. + * @throws Exception * @api */ public static function factory($periodType, $periodDay = false) @@ -203,13 +204,13 @@ abstract class ScheduledTime return new Daily(); case 'weekly': $result = new Weekly(); - if($periodDay !== false) { + if ($periodDay !== false) { $result->setDay($periodDay); } return $result; case 'monthly': $result = new Monthly($periodDay); - if($periodDay !== false) { + if ($periodDay !== false) { if (is_int($periodDay)) { $result->setDay($periodDay); } else { diff --git a/core/ScheduledTime/Monthly.php b/core/ScheduledTime/Monthly.php index d4900530e8..84189f9bad 100644 --- a/core/ScheduledTime/Monthly.php +++ b/core/ScheduledTime/Monthly.php @@ -46,7 +46,6 @@ class Monthly extends ScheduledTime $day = Weekly::getDayIntFromString($dayNumberString) % 7; // get week number - $week = false; $weekNumberString = strtolower($weekNumberString); if (isset(self::$weekNumberStringToInt[$weekNumberString])) { $week = self::$weekNumberStringToInt[$weekNumberString]; diff --git a/core/Segment.php b/core/Segment.php index e12b165028..a0952f3bd7 100644 --- a/core/Segment.php +++ b/core/Segment.php @@ -70,6 +70,7 @@ class Segment * @param string $segmentCondition The segment condition, eg, `'browserCode=ff;countryCode=CA'`. * @param array $idSites The list of sites the segment will be used with. Some segments are * dependent on the site, such as goal segments. + * @throws Exception */ public function __construct($segmentCondition, $idSites) { @@ -155,10 +156,10 @@ class Segment throw new Exception("You do not have enough permission to access the segment " . $name); } - if($matchType != SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY + if ($matchType != SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY && $matchType != SegmentExpression::MATCH_IS_NULL_OR_EMPTY) { - if(isset($segment['sqlFilterValue'])) { + if (isset($segment['sqlFilterValue'])) { $value = call_user_func($segment['sqlFilterValue'], $value); } diff --git a/core/Session/SaveHandler/DbTable.php b/core/Session/SaveHandler/DbTable.php index 249faca6e1..74fc5e388b 100644 --- a/core/Session/SaveHandler/DbTable.php +++ b/core/Session/SaveHandler/DbTable.php @@ -119,8 +119,7 @@ class DbTable implements Zend_Session_SaveHandler_Interface */ public function destroy($id) { - $sql = 'DELETE FROM ' . $this->config['name'] - . ' WHERE ' . $this->config['primary'] . ' = ?'; + $sql = 'DELETE FROM ' . $this->config['name'] . ' WHERE ' . $this->config['primary'] . ' = ?'; Db::get()->query($sql, array($id)); diff --git a/core/SettingsPiwik.php b/core/SettingsPiwik.php index 4e83190e70..26949c560a 100644 --- a/core/SettingsPiwik.php +++ b/core/SettingsPiwik.php @@ -179,7 +179,7 @@ class SettingsPiwik $url = $currentUrl; } - if(ProxyHttp::isHttps()) { + if (ProxyHttp::isHttps()) { $url = str_replace("http://", "https://", $url); } return $url; @@ -195,7 +195,7 @@ class SettingsPiwik $exists = file_exists($config); // Piwik is installed if the config file is found - if(!$exists) { + if (!$exists) { return false; } @@ -205,12 +205,12 @@ class SettingsPiwik if (array_key_exists('installation_in_progress', $general)) { $isInstallationInProgress = (bool) $general['installation_in_progress']; } - if($isInstallationInProgress) { + if ($isInstallationInProgress) { return false; } // Check that the database section is really set, ie. file is not empty - if(empty(Config::getInstance()->database['username'])) { + if (empty(Config::getInstance()->database['username'])) { return false; } return true; @@ -297,6 +297,8 @@ class SettingsPiwik * this will return false.. * * @param $piwikServerUrl + * @param bool $acceptInvalidSSLCertificates + * @throws Exception * @return bool */ public static function checkPiwikServerWorking($piwikServerUrl, $acceptInvalidSSLCertificates = false) @@ -337,7 +339,7 @@ class SettingsPiwik public static function getCurrentGitBranch() { $file = PIWIK_INCLUDE_PATH . '/.git/HEAD'; - if(!file_exists($file)) { + if (!file_exists($file)) { return ''; } $firstLineOfGitHead = file($file); @@ -385,19 +387,19 @@ class SettingsPiwik protected static function getPiwikInstanceId() { // until Piwik is installed, we use hostname as instance_id - if(!self::isPiwikInstalled() + if (!self::isPiwikInstalled() && Common::isPhpCliMode()) { // enterprise:install use case return Config::getHostname(); } // config.ini.php not ready yet, instance_id will not be set - if(!Config::getInstance()->existsLocalConfig()) { + if (!Config::getInstance()->existsLocalConfig()) { return false; } $instanceId = @Config::getInstance()->General['instance_id']; - if(!empty($instanceId)) { + if (!empty($instanceId)) { return $instanceId; } diff --git a/core/Site.php b/core/Site.php index 7efeee77ef..96b7316b76 100644 --- a/core/Site.php +++ b/core/Site.php @@ -94,7 +94,7 @@ class Site */ protected static function setSite($idSite, $infoSite) { - if(empty($idSite) || empty($infoSite)) { + if (empty($idSite) || empty($infoSite)) { throw new Exception("An unexpected website was found, check idSite in the request."); } @@ -361,7 +361,7 @@ class Site return API::getInstance()->getSitesIdWithAtLeastViewAccess($_restrictSitesToLogin); } - if(is_bool($ids)) { + if (is_bool($ids)) { return array(); } if (!is_array($ids)) { @@ -406,7 +406,7 @@ class Site $site = API::getInstance()->getSiteFromId($idsite); self::setSite($idsite, $site); } - if($field) { + if ($field) { return self::$infoSites[$idsite][$field]; } return self::$infoSites[$idsite]; diff --git a/core/Theme.php b/core/Theme.php index b0fe5abecb..f7f85a5291 100644 --- a/core/Theme.php +++ b/core/Theme.php @@ -64,7 +64,7 @@ class Theme return false; } $jsFiles = $info['javascript']; - if(!is_array($jsFiles)) { + if (!is_array($jsFiles)) { $jsFiles = array($jsFiles); } foreach($jsFiles as &$jsFile) { @@ -107,18 +107,18 @@ class Theme // Basic health check, we dont replace if not starting with plugins/ $posPluginsInPath = strpos($pathAsset, 'plugins'); - if( $posPluginsInPath !== 0) { + if ( $posPluginsInPath !== 0) { return $source; } // or if it's already rewritten - if(strpos($pathAsset, $this->themeName) !== false) { + if (strpos($pathAsset, $this->themeName) !== false) { return $source; } $pathPluginName = substr($pathAsset, strlen('plugins/')); $nextSlash = strpos($pathPluginName, '/'); - if($nextSlash === false) { + if ($nextSlash === false) { return $source; } $pathPluginName = substr($pathPluginName, 0, $nextSlash); @@ -133,11 +133,11 @@ class Theme // Strip trailing query string $fileToCheck = $overridingAsset; $queryStringPos = strpos($fileToCheck, '?'); - if( $queryStringPos !== false) { + if ( $queryStringPos !== false) { $fileToCheck = substr($fileToCheck, 0, $queryStringPos); } - if(file_exists($fileToCheck)) { + if (file_exists($fileToCheck)) { return str_replace($pathAsset, $overridingAsset, $source); } return $source; diff --git a/core/Tracker.php b/core/Tracker.php index 733f23d8a3..3aa27237a1 100644 --- a/core/Tracker.php +++ b/core/Tracker.php @@ -221,7 +221,7 @@ class Tracker */ public function main($args = null) { - if(!SettingsPiwik::isPiwikInstalled()) { + if (!SettingsPiwik::isPiwikInstalled()) { return $this->handleEmptyRequest(); } try { @@ -468,7 +468,7 @@ class Tracker Common::sendHeader('Content-Type: text/html; charset=utf-8'); echo $this->getMessageFromException($e); } else { - $this->outputTransparentGif(); + $this->outputTransparentGif (); } exit; } @@ -516,7 +516,7 @@ class Tracker } switch ($this->getState()) { case self::STATE_LOGGING_DISABLE: - $this->outputTransparentGif(); + $this->outputTransparentGif (); Common::printDebug("Logging disabled, display transparent logo"); break; @@ -528,7 +528,7 @@ class Tracker case self::STATE_NOSCRIPT_REQUEST: case self::STATE_NOTHING_TO_NOTICE: default: - $this->outputTransparentGif(); + $this->outputTransparentGif (); Common::printDebug("Nothing to notice => default behaviour"); break; } @@ -663,7 +663,7 @@ class Tracker return $visit; } - protected function outputTransparentGif() + protected function outputTransparentGif () { if (isset($GLOBALS['PIWIK_TRACKER_DEBUG']) && $GLOBALS['PIWIK_TRACKER_DEBUG'] @@ -717,7 +717,7 @@ class Tracker protected function handleEmptyRequest(Request $request = null) { - if(is_null($request)) { + if (is_null($request)) { $request = new Request($_GET + $_POST); } $countParameters = $request->getParamsCount(); diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php index 6175d86e59..aa721a03c5 100644 --- a/core/Tracker/Action.php +++ b/core/Tracker/Action.php @@ -22,33 +22,51 @@ use Piwik\Tracker; */ abstract class Action { - const TYPE_PAGE_URL = 1; - const TYPE_OUTLINK = 2; - const TYPE_DOWNLOAD = 3; + const TYPE_PAGE_URL = 1; + const TYPE_OUTLINK = 2; + const TYPE_DOWNLOAD = 3; const TYPE_PAGE_TITLE = 4; - const TYPE_ECOMMERCE_ITEM_SKU = 5; + const TYPE_ECOMMERCE_ITEM_SKU = 5; const TYPE_ECOMMERCE_ITEM_NAME = 6; const TYPE_ECOMMERCE_ITEM_CATEGORY = 7; const TYPE_SITE_SEARCH = 8; - const TYPE_EVENT = 10; // Alias TYPE_EVENT_CATEGORY + const TYPE_EVENT = 10; // Alias TYPE_EVENT_CATEGORY const TYPE_EVENT_CATEGORY = 10; - const TYPE_EVENT_ACTION = 11; - const TYPE_EVENT_NAME = 12; + const TYPE_EVENT_ACTION = 11; + const TYPE_EVENT_NAME = 12; - const TYPE_CONTENT = 13; // Alias TYPE_CONTENT_NAME - const TYPE_CONTENT_NAME = 13; - const TYPE_CONTENT_PIECE = 14; - const TYPE_CONTENT_TARGET = 15; + const TYPE_CONTENT = 13; // Alias TYPE_CONTENT_NAME + const TYPE_CONTENT_NAME = 13; + const TYPE_CONTENT_PIECE = 14; + const TYPE_CONTENT_TARGET = 15; const TYPE_CONTENT_INTERACTION = 16; const DB_COLUMN_CUSTOM_FLOAT = 'custom_float'; private static $factoryPriority = array( - self::TYPE_PAGE_URL, self::TYPE_CONTENT, self::TYPE_SITE_SEARCH, self::TYPE_EVENT, self::TYPE_OUTLINK, self::TYPE_DOWNLOAD + self::TYPE_PAGE_URL, + self::TYPE_CONTENT, + self::TYPE_SITE_SEARCH, + self::TYPE_EVENT, + self::TYPE_OUTLINK, + self::TYPE_DOWNLOAD ); /** + * Public so that events listener can access it + * + * @var Request + */ + public $request; + + private $idLinkVisitAction; + private $actionIdsCached = array(); + private $actionName; + private $actionType; + private $actionUrl; + + /** * Makes the correct Action object based on the request. * * @param Request $request @@ -102,7 +120,7 @@ abstract class Action $instances = array(); foreach ($actions as $action) { - /** @var \Piwik\Tracker\Action $instance */ + /** @var \Piwik\Tracker\Action $action */ if ($action::shouldHandle($request)) { $instances[] = new $action($request); } @@ -111,19 +129,6 @@ abstract class Action return $instances; } - /** - * Public so that events listener can access it - * - * @var Request - */ - public $request; - - private $idLinkVisitAction; - private $actionIdsCached = array(); - private $actionName; - private $actionType; - private $actionUrl; - public function __construct($type, Request $request) { $this->actionType = $type; @@ -152,8 +157,7 @@ abstract class Action public function getCustomVariables() { - $customVariables = $this->request->getCustomVariables($scope = 'page'); - return $customVariables; + return $this->request->getCustomVariables($scope = 'page'); } // custom_float column @@ -164,8 +168,7 @@ abstract class Action protected function setActionName($name) { - $name = PageUrl::cleanupString((string)$name); - $this->actionName = $name; + $this->actionName = PageUrl::cleanupString((string)$name); } protected function setActionUrl($url) @@ -178,8 +181,7 @@ abstract class Action Common::printDebug(' After is "' . $url . '"'); } - $url = PageUrl::getUrlIfLookValid($url); - $this->actionUrl = $url; + $this->actionUrl = PageUrl::getUrlIfLookValid($url); } abstract protected function getActionsToLookup(); @@ -187,11 +189,13 @@ abstract class Action protected function getUrlAndType() { $url = $this->getActionUrl(); + if (!empty($url)) { // normalize urls by stripping protocol and www $url = PageUrl::normalizeUrl($url); return array($url['url'], self::TYPE_PAGE_URL, $url['prefixId']); } + return false; } @@ -214,9 +218,11 @@ abstract class Action public function getIdActionName() { - if(!isset($this->actionIdsCached['idaction_name'])) { + if (!isset($this->actionIdsCached['idaction_name'])) { + return false; } + return $this->actionIdsCached['idaction_name']; } @@ -230,24 +236,17 @@ abstract class Action return $this->idLinkVisitAction; } - public function writeDebugInfo() - { - $type = self::getTypeAsString($this->getActionType()); - Common::printDebug("Action is a $type, - Action name = " . $this->getActionName() . ", - Action URL = " . $this->getActionUrl()); - return true; - } - public static function getTypeAsString($type) { - $class = new \ReflectionClass("\\Piwik\\Tracker\\Action"); + $class = new \ReflectionClass("\\Piwik\\Tracker\\Action"); $constants = $class->getConstants(); $typeId = array_search($type, $constants); - if($typeId === false) { + + if (false === $typeId) { throw new Exception("Unexpected action type " . $type); } + return str_replace('TYPE_', '', $typeId); } @@ -262,24 +261,27 @@ abstract class Action */ public function loadIdsFromLogActionTable() { - if(!empty($this->actionIdsCached)) { + if (!empty($this->actionIdsCached)) { return; } - $actions = $this->getActionsToLookup(); + /** @var ActionDimension[] $dimensions */ $dimensions = ActionDimension::getAllDimensions(); + $actions = $this->getActionsToLookup(); foreach ($dimensions as $dimension) { $value = $dimension->onLookupAction($this->request, $this); - if ($value !== false) { + if (false !== $value) { $field = $dimension->getColumnName(); if (empty($field)) { - throw new Exception('Dimension ' . get_class($dimension) . ' does not define a field name'); + $dimensionClass = get_class($dimension); + throw new Exception('Dimension ' . $dimensionClass . ' does not define a field name'); } - $actions[$field] = array($value, $dimension->getActionId()); + $actionId = $dimension->getActionId(); + $actions[$field] = array($value, $actionId); Common::printDebug("$field = $value"); } } @@ -316,6 +318,7 @@ abstract class Action 'idaction_name_ref' => $idReferrerActionName ); + /** @var ActionDimension[] $dimensions */ $dimensions = ActionDimension::getAllDimensions(); foreach ($dimensions as $dimension) { @@ -347,12 +350,8 @@ abstract class Action } $visitAction = array_merge($visitAction, $customVariables); - $fields = implode(", ", array_keys($visitAction)); - $bind = array_values($visitAction); - $values = Common::getSqlStringFieldsArray($visitAction); - $sql = "INSERT INTO " . Common::prefixTable('log_link_visit_action') . " ($fields) VALUES ($values)"; - Tracker::getDatabase()->query($sql, $bind); + $this->recordAction($visitAction); $this->idLinkVisitAction = Tracker::getDatabase()->lastInsertId(); $visitAction['idlink_va'] = $this->idLinkVisitAction; @@ -370,13 +369,36 @@ abstract class Action Piwik::postEvent('Tracker.recordAction', array($trackerAction = $this, $visitAction)); } + public function writeDebugInfo() + { + $type = self::getTypeAsString($this->getActionType()); + $name = $this->getActionName(); + $url = $this->getActionUrl(); + + Common::printDebug("Action is a $type, + Action name = " . $name . ", + Action URL = " . $url); + + return true; + } + + private function recordAction($visitAction) + { + $fields = implode(", ", array_keys($visitAction)); + $bind = array_values($visitAction); + $values = Common::getSqlStringFieldsArray($visitAction); + + $sql = "INSERT INTO " . Common::prefixTable('log_link_visit_action') . " ($fields) VALUES ($values)"; + Tracker::getDatabase()->query($sql, $bind); + } + /** * @return bool */ - protected function isActionHasActionName() + private function isActionHasActionName() { - return in_array($this->getActionType(), array(self::TYPE_PAGE_TITLE, - self::TYPE_PAGE_URL, - self::TYPE_SITE_SEARCH)); + $types = array(self::TYPE_PAGE_TITLE, self::TYPE_PAGE_URL, self::TYPE_SITE_SEARCH); + + return in_array($this->getActionType(), $types); } } diff --git a/core/Tracker/ActionPageview.php b/core/Tracker/ActionPageview.php index fa3d0146dc..9088fc543a 100644 --- a/core/Tracker/ActionPageview.php +++ b/core/Tracker/ActionPageview.php @@ -38,7 +38,7 @@ class ActionPageview extends Action { return array( 'idaction_name' => array($this->getActionName(), Action::TYPE_PAGE_TITLE), - 'idaction_url' => $this->getUrlAndType() + 'idaction_url' => $this->getUrlAndType() ); } @@ -55,22 +55,38 @@ class ActionPageview extends Action private function cleanupActionName($actionName) { // get the delimiter, by default '/'; BC, we read the old action_category_delimiter first (see #1067) - $actionCategoryDelimiter = isset(Config::getInstance()->General['action_category_delimiter']) - ? Config::getInstance()->General['action_category_delimiter'] - : Config::getInstance()->General['action_url_category_delimiter']; + $actionCategoryDelimiter = $this->getActionCategoryDelimiter(); // create an array of the categories delimited by the delimiter $split = explode($actionCategoryDelimiter, $actionName); + $split = $this->trimEveryCategory($split); + $split = $this->removeEmptyCategories($split); - // trim every category - $split = array_map('trim', $split); + return $this->rebuildNameOfCleanedCategories($actionCategoryDelimiter, $split); + } + + private function rebuildNameOfCleanedCategories($actionCategoryDelimiter, $split) + { + return implode($actionCategoryDelimiter, $split); + } - // remove empty categories - $split = array_filter($split, 'strlen'); + private function removeEmptyCategories($split) + { + return array_filter($split, 'strlen'); + } + + private function trimEveryCategory($split) + { + return array_map('trim', $split); + } + + private function getActionCategoryDelimiter() + { + if (isset(Config::getInstance()->General['action_category_delimiter'])) { + return Config::getInstance()->General['action_category_delimiter']; + } - // rebuild the name from the array of cleaned categories - $actionName = implode($actionCategoryDelimiter, $split); - return $actionName; + return Config::getInstance()->General['action_url_category_delimiter']; } } diff --git a/core/Tracker/Cache.php b/core/Tracker/Cache.php index 0217b175de..db442378e7 100644 --- a/core/Tracker/Cache.php +++ b/core/Tracker/Cache.php @@ -45,16 +45,19 @@ class Cache */ static function getCacheWebsiteAttributes($idSite) { - if($idSite == 'all') { + if ('all' == $idSite) { return array(); } + $idSite = (int)$idSite; - if($idSite <= 0) { + if ($idSite <= 0) { return array(); } - $cache = self::getInstance(); - if (($cacheContent = $cache->get($idSite)) !== false) { + $cache = self::getInstance(); + $cacheContent = $cache->get($idSite); + + if (false !== $cacheContent) { return $cacheContent; } @@ -95,6 +98,7 @@ class Cache if (!empty($content)) { $cache->set($idSite, $content); } + return $content; } @@ -114,10 +118,12 @@ class Cache */ public static function getCacheGeneral() { - $cache = self::getInstance(); + $cache = self::getInstance(); $cacheId = 'general'; - if (($cacheContent = $cache->get($cacheId)) !== false) { + $cacheContent = $cache->get($cacheId); + + if (false !== $cacheContent) { return $cacheContent; } @@ -161,9 +167,10 @@ class Cache */ public static function setCacheGeneral($value) { - $cache = self::getInstance(); + $cache = self::getInstance(); $cacheId = 'general'; $cache->set($cacheId, $value); + return true; } @@ -177,6 +184,7 @@ class Cache if (!is_array($idSites)) { $idSites = array($idSites); } + foreach ($idSites as $idSite) { self::deleteCacheWebsiteAttributes($idSite); self::getCacheWebsiteAttributes($idSite); diff --git a/core/Tracker/Db.php b/core/Tracker/Db.php index 4ce13a0891..1fe081daac 100644 --- a/core/Tracker/Db.php +++ b/core/Tracker/Db.php @@ -77,10 +77,14 @@ abstract class Db */ protected function recordQueryProfile($query, $timer) { - if (!isset($this->queriesProfiling[$query])) $this->queriesProfiling[$query] = array('sum_time_ms' => 0, 'count' => 0); - $time = $timer->getTimeMs(2); + if (!isset($this->queriesProfiling[$query])) { + $this->queriesProfiling[$query] = array('sum_time_ms' => 0, 'count' => 0); + } + + $time = $timer->getTimeMs(2); $time += $this->queriesProfiling[$query]['sum_time_ms']; $count = $this->queriesProfiling[$query]['count'] + 1; + $this->queriesProfiling[$query] = array('sum_time_ms' => $time, 'count' => $count); } @@ -97,13 +101,12 @@ abstract class Db self::$profiling = false; foreach ($this->queriesProfiling as $query => $info) { - $time = $info['sum_time_ms']; + $time = $info['sum_time_ms']; $count = $info['count']; $queryProfiling = "INSERT INTO " . Common::prefixTable('log_profiling') . " (query,count,sum_time_ms) VALUES (?,$count,$time) - ON DUPLICATE KEY - UPDATE count=count+$count,sum_time_ms=sum_time_ms+$time"; + ON DUPLICATE KEY UPDATE count=count+$count,sum_time_ms=sum_time_ms+$time"; $this->query($queryProfiling, array($query)); } diff --git a/core/Tracker/Db/Mysqli.php b/core/Tracker/Db/Mysqli.php index 78e2d9ee29..e648c41af7 100644 --- a/core/Tracker/Db/Mysqli.php +++ b/core/Tracker/Db/Mysqli.php @@ -73,7 +73,16 @@ class Mysqli extends Db $timer = $this->initProfiler(); } - $this->connection = mysqli_connect($this->host, $this->username, $this->password, $this->dbname, $this->port, $this->socket); + $this->connection = mysqli_init(); + + // Make sure MySQL returns all matched rows on update queries including + // rows that actually didn't have to be updated because the values didn't + // change. This matches common behaviour among other database systems. + // See #6296 why this is important in tracker + $flags = MYSQLI_CLIENT_FOUND_ROWS; + mysqli_real_connect($this->connection, $this->host, $this->username, $this->password, $this->dbname, $this->port, $this->socket, $flags); + + // $this->connection = mysqli_connect($this->host, $this->username, $this->password, $this->dbname, $this->port, $this->socket); if (!$this->connection || mysqli_connect_errno()) { throw new DbException("Connect failed: " . mysqli_connect_error()); } @@ -205,8 +214,8 @@ class Mysqli extends Db return $result; } catch (Exception $e) { throw new DbException("Error query: " . $e->getMessage() . " - In query: $query - Parameters: " . var_export($parameters, true)); + In query: $query + Parameters: " . var_export($parameters, true)); } } @@ -278,57 +287,58 @@ class Mysqli extends Db return mysqli_affected_rows($this->connection); } - /** - * Start Transaction - * @return string TransactionID - */ - - public function beginTransaction() - { - if(!$this->activeTransaction === false ) { - return; - } - - if( $this->connection->autocommit(false) ) { - $this->activeTransaction = uniqid(); - return $this->activeTransaction; - } - } - - /** - * Commit Transaction - * @param string TransactionID from beginTransaction - */ - - public function commit($xid) - { - if($this->activeTransaction != $xid || $this->activeTransaction === false ) { - - return; - } - $this->activeTransaction = false; - - if(!$this->connection->commit() ) { - throw new DbException("Commit failed"); - } - $this->connection->autocommit(true); - } - - /** - * Rollback Transaction - * @param string TransactionID from beginTransaction - */ - - public function rollBack($xid) - { - if($this->activeTransaction != $xid || $this->activeTransaction === false ) { - return; - } - $this->activeTransaction = false; - - if(!$this->connection->rollback() ) { - throw new DbException("Rollback failed"); - } - $this->connection->autocommit(true); - } + /** + * Start Transaction + * @return string TransactionID + */ + public function beginTransaction() + { + if (!$this->activeTransaction === false ) { + return; + } + + if ( $this->connection->autocommit(false) ) { + $this->activeTransaction = uniqid(); + return $this->activeTransaction; + } + } + + /** + * Commit Transaction + * @param $xid + * @throws DbException + * @internal param TransactionID $string from beginTransaction + */ + public function commit($xid) + { + if ($this->activeTransaction != $xid || $this->activeTransaction === false ) { + + return; + } + $this->activeTransaction = false; + + if (!$this->connection->commit() ) { + throw new DbException("Commit failed"); + } + $this->connection->autocommit(true); + } + + /** + * Rollback Transaction + * @param $xid + * @throws DbException + * @internal param TransactionID $string from beginTransaction + */ + public function rollBack($xid) + { + if ($this->activeTransaction != $xid || $this->activeTransaction === false ) { + return; + } + $this->activeTransaction = false; + + if (!$this->connection->rollback() ) { + throw new DbException("Rollback failed"); + } + $this->connection->autocommit(true); + } } diff --git a/core/Tracker/Db/Pdo/Mysql.php b/core/Tracker/Db/Pdo/Mysql.php index a2f5a79b2c..ffc93b417b 100644 --- a/core/Tracker/Db/Pdo/Mysql.php +++ b/core/Tracker/Db/Pdo/Mysql.php @@ -195,8 +195,8 @@ class Mysql extends Db return $sth; } catch (PDOException $e) { throw new DbException("Error query: " . $e->getMessage() . " - In query: $query - Parameters: " . var_export($parameters, true)); + In query: $query + Parameters: " . var_export($parameters, true)); } } @@ -237,54 +237,55 @@ class Mysql extends Db return $queryResult->rowCount(); } - /** - * Start Transaction - * @return string TransactionID - */ - - public function beginTransaction() - { - if(!$this->activeTransaction === false ) { - return; - } - - if( $this->connection->beginTransaction() ) { - $this->activeTransaction = uniqid(); - return $this->activeTransaction; - } - } - - /** - * Commit Transaction - * @param string TransactionID from beginTransaction - */ + /** + * Start Transaction + * @return string TransactionID + */ + public function beginTransaction() + { + if (!$this->activeTransaction === false ) { + return; + } - public function commit($xid) - { - if($this->activeTransaction != $xid || $this->activeTransaction === false ) { - return; - } - $this->activeTransaction = false; + if ( $this->connection->beginTransaction() ) { + $this->activeTransaction = uniqid(); + return $this->activeTransaction; + } + } - if(!$this->connection->commit() ) { - throw new DbException("Commit failed"); - } - } + /** + * Commit Transaction + * @param $xid + * @throws DbException + * @internal param TransactionID $string from beginTransaction + */ + public function commit($xid) + { + if ($this->activeTransaction != $xid || $this->activeTransaction === false ) { + return; + } + $this->activeTransaction = false; - /** - * Rollback Transaction - * @param string TransactionID from beginTransaction - */ + if (!$this->connection->commit() ) { + throw new DbException("Commit failed"); + } + } - public function rollBack($xid) - { - if($this->activeTransaction != $xid || $this->activeTransaction === false ) { - return; - } - $this->activeTransaction = false; + /** + * Rollback Transaction + * @param $xid + * @throws DbException + * @internal param TransactionID $string from beginTransaction + */ + public function rollBack($xid) + { + if ($this->activeTransaction != $xid || $this->activeTransaction === false ) { + return; + } + $this->activeTransaction = false; - if(!$this->connection->rollBack() ) { - throw new DbException("Rollback failed"); - } - } + if (!$this->connection->rollBack() ) { + throw new DbException("Rollback failed"); + } + } } diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php index 1a0944ad9a..7823b88cc2 100644 --- a/core/Tracker/GoalManager.php +++ b/core/Tracker/GoalManager.php @@ -34,6 +34,25 @@ class GoalManager const REVENUE_PRECISION = 2; const MAXIMUM_PRODUCT_CATEGORIES = 5; + + // In the GET items parameter, each item has the following array of information + const INDEX_ITEM_SKU = 0; + const INDEX_ITEM_NAME = 1; + const INDEX_ITEM_CATEGORY = 2; + const INDEX_ITEM_PRICE = 3; + const INDEX_ITEM_QUANTITY = 4; + + // Used in the array of items, internally to this class + const INTERNAL_ITEM_SKU = 0; + const INTERNAL_ITEM_NAME = 1; + const INTERNAL_ITEM_CATEGORY = 2; + const INTERNAL_ITEM_CATEGORY2 = 3; + const INTERNAL_ITEM_CATEGORY3 = 4; + const INTERNAL_ITEM_CATEGORY4 = 5; + const INTERNAL_ITEM_CATEGORY5 = 6; + const INTERNAL_ITEM_PRICE = 7; + const INTERNAL_ITEM_QUANTITY = 8; + public $idGoal; public $requestIsEcommerce; private $isGoalAnOrder; @@ -65,7 +84,7 @@ class GoalManager $this->idGoal = $request->getParam('idgoal'); $this->isGoalAnOrder = !empty($this->orderId); - $this->requestIsEcommerce = ($this->idGoal == 0); + $this->requestIsEcommerce = (0 == $this->idGoal); } public function isGoalAnOrder() @@ -87,30 +106,36 @@ class GoalManager public static function getGoalDefinitions($idSite) { $websiteAttributes = Cache::getCacheWebsiteAttributes($idSite); + if (isset($websiteAttributes['goals'])) { return $websiteAttributes['goals']; } + return array(); } public static function getGoalDefinition($idSite, $idGoal) { $goals = self::getGoalDefinitions($idSite); + foreach ($goals as $goal) { if ($goal['idgoal'] == $idGoal) { return $goal; } } + throw new Exception('Goal not found'); } public static function getGoalIds($idSite) { - $goals = self::getGoalDefinitions($idSite); + $goals = self::getGoalDefinitions($idSite); $goalIds = array(); + foreach ($goals as $goal) { $goalIds[] = $goal['idgoal']; } + return $goalIds; } @@ -131,14 +156,15 @@ class GoalManager $decodedActionUrl = $action->getActionUrl(); $actionType = $action->getActionType(); $goals = $this->getGoalDefinitions($idSite); + foreach ($goals as $goal) { $attribute = $goal['match_attribute']; // if the attribute to match is not the type of the current action - if ( (($attribute == 'url' || $attribute == 'title') && $actionType != Action::TYPE_PAGE_URL) - || ($attribute == 'file' && $actionType != Action::TYPE_DOWNLOAD) - || ($attribute == 'external_website' && $actionType != Action::TYPE_OUTLINK) - || ($attribute == 'manually') - || in_array($attribute, array('event_action', 'event_name', 'event_category')) && $actionType != Action::TYPE_EVENT + if ((($attribute == 'url' || $attribute == 'title') && $actionType != Action::TYPE_PAGE_URL) + || ($attribute == 'file' && $actionType != Action::TYPE_DOWNLOAD) + || ($attribute == 'external_website' && $actionType != Action::TYPE_OUTLINK) + || ($attribute == 'manually') + || in_array($attribute, array('event_action', 'event_name', 'event_category')) && $actionType != Action::TYPE_EVENT ) { continue; } @@ -169,23 +195,33 @@ class GoalManager $this->convertedGoals[] = $goal; } } + return count($this->convertedGoals) > 0; } + public function isManualGoalConversion() + { + return $this->idGoal > 0; + } + public function detectGoalId($idSite) { if (!Common::isGoalPluginEnabled()) { return false; } + $goals = $this->getGoalDefinitions($idSite); + if (!isset($goals[$this->idGoal])) { return false; } + $goal = $goals[$this->idGoal]; - $url = $this->request->getParam('url'); + $url = $this->request->getParam('url'); $goal['url'] = PageUrl::excludeQueryParametersFromUrl($url, $idSite); $this->convertedGoals[] = $goal; + return true; } @@ -199,18 +235,7 @@ class GoalManager */ public function recordGoals(Visitor $visitor, $visitorInformation, $visitCustomVariables, $action) { - $goal = array( - 'idvisit' => $visitorInformation['idvisit'], - 'idvisitor' => $visitorInformation['idvisitor'], - 'server_time' => Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']) - ); - - foreach (VisitDimension::getAllDimensions() as $dimension) { - $value = $dimension->onAnyGoalConversion($this->request, $visitor, $action); - if (false !== $value) { - $goal[$dimension->getColumnName()] = $value; - } - } + $goal = $this->getGoalFromVisitor($visitor, $visitorInformation, $action); // Copy Custom Variables from Visit row to the Goal conversion // Otherwise, set the Custom Variables found in the cookie sent with this request @@ -249,6 +274,7 @@ class GoalManager if (round($revenue) == $revenue) { return $revenue; } + return round($revenue, self::REVENUE_PRECISION); } @@ -291,7 +317,8 @@ class GoalManager // INSERT or Sync items in the Cart / Order for this visit & order $items = $this->getEcommerceItemsFromRequest(); - if ($items === false) { + + if (false === $items) { return; } @@ -338,12 +365,15 @@ class GoalManager private function getEcommerceItemsFromRequest() { $items = Common::unsanitizeInputValue($this->request->getParam('ec_items')); + if (empty($items)) { Common::printDebug("There are no Ecommerce items in the request"); // we still record an Ecommerce order without any item in it return array(); } + $items = Common::json_decode($items, $assoc = true); + if (!is_array($items)) { Common::printDebug("Error while json_decode the Ecommerce items = " . var_export($items, true)); return false; @@ -371,8 +401,7 @@ class GoalManager // Select all items currently in the Cart if any $sql = "SELECT idaction_sku, idaction_name, idaction_category, idaction_category2, idaction_category3, idaction_category4, idaction_category5, price, quantity, deleted, idorder as idorder_original_value FROM " . Common::prefixTable('log_conversion_item') . " - WHERE idvisit = ? - AND (idorder = ? OR idorder = ?)"; + WHERE idvisit = ? AND (idorder = ? OR idorder = ?)"; $bind = array($goal['idvisit'], isset($goal['idorder']) ? $goal['idorder'] : self::ITEM_IDORDER_ABANDONED_CART, @@ -385,6 +414,7 @@ class GoalManager Common::printDebug($itemsInDb); // Look at which items need to be deleted, which need to be added or updated, based on the SKU $skuFoundInDb = $itemsToUpdate = array(); + foreach ($itemsInDb as $itemInDb) { $skuFoundInDb[] = $itemInDb['idaction_sku']; @@ -435,27 +465,10 @@ class GoalManager $itemsToInsert[] = $item; } } + $this->insertEcommerceItems($goal, $itemsToInsert); } - // In the GET items parameter, each item has the following array of information - const INDEX_ITEM_SKU = 0; - const INDEX_ITEM_NAME = 1; - const INDEX_ITEM_CATEGORY = 2; - const INDEX_ITEM_PRICE = 3; - const INDEX_ITEM_QUANTITY = 4; - - // Used in the array of items, internally to this class - const INTERNAL_ITEM_SKU = 0; - const INTERNAL_ITEM_NAME = 1; - const INTERNAL_ITEM_CATEGORY = 2; - const INTERNAL_ITEM_CATEGORY2 = 3; - const INTERNAL_ITEM_CATEGORY3 = 4; - const INTERNAL_ITEM_CATEGORY4 = 5; - const INTERNAL_ITEM_CATEGORY5 = 6; - const INTERNAL_ITEM_PRICE = 7; - const INTERNAL_ITEM_QUANTITY = 8; - /** * Reads items from the request, then looks up the names from the lookup table * and returns a clean array of items ready for the database. @@ -468,9 +481,10 @@ class GoalManager // Clean up the items array $cleanedItems = array(); foreach ($items as $item) { - $name = $category = $category2 = $category3 = $category4 = $category5 = false; - $price = 0; + $name = $category = $category2 = $category3 = $category4 = $category5 = false; + $price = 0; $quantity = 1; + // items are passed in the request as an array: ( $sku, $name, $category, $price, $quantity ) if (empty($item[self::INDEX_ITEM_SKU])) { continue; @@ -562,6 +576,7 @@ class GoalManager $item[5] = $actionsLookedUp[$index * $columnsInEachRow + 5]; $item[6] = $actionsLookedUp[$index * $columnsInEachRow + 6]; } + return $cleanedItems; } @@ -579,6 +594,7 @@ class GoalManager if (empty($itemsToUpdate)) { return; } + Common::printDebug("Goal data used to update ecommerce items:"); Common::printDebug($goal); @@ -588,13 +604,10 @@ class GoalManager $updateParts = $sqlBind = array(); foreach ($newRow as $name => $value) { $updateParts[] = $name . " = ?"; - $sqlBind[] = $value; + $sqlBind[] = $value; } - $sql = 'UPDATE ' . Common::prefixTable('log_conversion_item') . " - SET " . implode($updateParts, ', ') . " - WHERE idvisit = ? - AND idorder = ? - AND idaction_sku = ?"; + $sql = 'UPDATE ' . Common::prefixTable('log_conversion_item') . " SET " . implode($updateParts, ', ') . " + WHERE idvisit = ? AND idorder = ? AND idaction_sku = ?"; $sqlBind[] = $newRow['idvisit']; $sqlBind[] = $item['idorder_original_value']; $sqlBind[] = $newRow['idaction_sku']; @@ -616,6 +629,7 @@ class GoalManager if (empty($itemsToInsert)) { return; } + Common::printDebug("Ecommerce items that are added to the cart/order"); Common::printDebug($itemsToInsert); @@ -625,6 +639,7 @@ class GoalManager VALUES "; $i = 0; $bind = array(); + foreach ($itemsToInsert as $item) { if ($i > 0) { $sql .= ','; @@ -634,6 +649,7 @@ class GoalManager $i++; $bind = array_merge($bind, $newRow); } + Tracker::getDatabase()->query($sql, $bind); Common::printDebug($sql); Common::printDebug($bind); @@ -685,7 +701,7 @@ class GoalManager Common::printDebug("- Goal " . $convertedGoal['idgoal'] . " matched. Recording..."); $conversion = $goal; $conversion['idgoal'] = $convertedGoal['idgoal']; - $conversion['url'] = $convertedGoal['url']; + $conversion['url'] = $convertedGoal['url']; if (!is_null($action)) { $conversion['idaction_url'] = $action->getIdActionUrl(); @@ -741,11 +757,11 @@ class GoalManager $newGoalDebug['idvisitor'] = bin2hex($newGoalDebug['idvisitor']); Common::printDebug($newGoalDebug); - $fields = implode(", ", array_keys($conversion)); + $fields = implode(", ", array_keys($conversion)); $bindFields = Common::getSqlStringFieldsArray($conversion); - $sql = 'INSERT IGNORE INTO ' . Common::prefixTable('log_conversion') . " - ($fields) VALUES ($bindFields) "; - $bind = array_values($conversion); + + $sql = 'INSERT IGNORE INTO ' . Common::prefixTable('log_conversion') . " ($fields) VALUES ($bindFields) "; + $bind = array_values($conversion); $result = Tracker::getDatabase()->query($sql, $bind); // If a record was inserted, we return true @@ -775,24 +791,29 @@ class GoalManager protected function updateExistingConversion($newGoal, $updateWhere) { $updateParts = $sqlBind = $updateWhereParts = array(); + foreach ($newGoal as $name => $value) { $updateParts[] = $name . " = ?"; - $sqlBind[] = $value; + $sqlBind[] = $value; } + foreach ($updateWhere as $name => $value) { $updateWhereParts[] = $name . " = ?"; - $sqlBind[] = $value; + $sqlBind[] = $value; } - $sql = 'UPDATE ' . Common::prefixTable('log_conversion') . " - SET " . implode($updateParts, ', ') . " - WHERE " . implode($updateWhereParts, ' AND '); + + $table = Common::prefixTable('log_conversion'); + $parts = implode($updateParts, ', '); + $sql = 'UPDATE ' . $table . " SET " . $parts . " WHERE " . implode($updateWhereParts, ' AND '); try { Tracker::getDatabase()->query($sql, $sqlBind); } catch(Exception $e){ Common::printDebug("There was an error while updating the Conversion: " . $e->getMessage()); + return false; } + return true; } @@ -842,6 +863,7 @@ class GoalManager throw new Exception(Piwik::translate('General_ExceptionInvalidGoalPattern', array($pattern_type))); break; } + return $match; } @@ -859,7 +881,7 @@ class GoalManager foreach ($dimensions as $dimension) { $value = $dimension->$hook($this->request, $visitor, $action, $this); - if ($value !== false) { + if (false !== $value) { $fieldName = $dimension->getColumnName(); $visitor->setVisitorColumn($fieldName, $value); @@ -869,4 +891,24 @@ class GoalManager return $valuesToUpdate; } + + private function getGoalFromVisitor(Visitor $visitor, $visitorInformation, $action) + { + $goal = array( + 'idvisit' => $visitorInformation['idvisit'], + 'idvisitor' => $visitorInformation['idvisitor'], + 'server_time' => Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']) + ); + + $visitDimensions = VisitDimension::getAllDimensions(); + + foreach ($visitDimensions as $dimension) { + $value = $dimension->onAnyGoalConversion($this->request, $visitor, $action); + if (false !== $value) { + $goal[$dimension->getColumnName()] = $value; + } + } + + return $goal; + } } diff --git a/core/Tracker/PageUrl.php b/core/Tracker/PageUrl.php index 1d8486eda0..ae55b48aac 100644 --- a/core/Tracker/PageUrl.php +++ b/core/Tracker/PageUrl.php @@ -49,17 +49,22 @@ class PageUrl if (empty($parsedUrl['query'])) { if (empty($parsedUrl['fragment'])) { + return UrlHelper::getParseUrlReverse($parsedUrl); } + // Exclude from the hash tag as well $queryParameters = UrlHelper::getArrayFromQueryString($parsedUrl['fragment']); $parsedUrl['fragment'] = UrlHelper::getQueryStringWithExcludedParameters($queryParameters, $parametersToExclude); $url = UrlHelper::getParseUrlReverse($parsedUrl); + return $url; } + $queryParameters = UrlHelper::getArrayFromQueryString($parsedUrl['query']); $parsedUrl['query'] = UrlHelper::getQueryStringWithExcludedParameters($queryParameters, $parametersToExclude); $url = UrlHelper::getParseUrlReverse($parsedUrl); + return $url; } @@ -79,17 +84,15 @@ class PageUrl ); $website = Cache::getCacheWebsiteAttributes($idSite); - $excludedParameters = isset($website['excluded_parameters']) - ? $website['excluded_parameters'] - : array(); + $excludedParameters = self::getExcludedParametersFromWebsite($website); if (!empty($excludedParameters)) { Common::printDebug('Excluding parameters "' . implode(',', $excludedParameters) . '" from URL'); } $parametersToExclude = array_merge($excludedParameters, - self::$queryParametersToExclude, - $campaignTrackingParameters); + self::$queryParametersToExclude, + $campaignTrackingParameters); $parametersToExclude = array_map('strtolower', $parametersToExclude); return $parametersToExclude; @@ -152,6 +155,7 @@ class PageUrl if (empty($parsedUrl)) { return $parsedUrl; } + if (!empty($parsedUrl['host'])) { $parsedUrl['host'] = mb_strtolower($parsedUrl['host'], 'UTF-8'); } @@ -174,19 +178,24 @@ class PageUrl public static function convertMatrixUrl($originalUrl) { $posFirstSemiColon = strpos($originalUrl, ";"); - if ($posFirstSemiColon === false) { + + if (false === $posFirstSemiColon) { return $originalUrl; } + $posQuestionMark = strpos($originalUrl, "?"); - $replace = ($posQuestionMark === false); + $replace = (false === $posQuestionMark); + if ($posQuestionMark > $posFirstSemiColon) { $originalUrl = substr_replace($originalUrl, ";", $posQuestionMark, 1); $replace = true; } + if ($replace) { $originalUrl = substr_replace($originalUrl, "?", strpos($originalUrl, ";"), 1); $originalUrl = str_replace(";", "&", $originalUrl); } + return $originalUrl; } @@ -214,6 +223,7 @@ class PageUrl $value = urlencode(mb_convert_encoding($decoded, 'UTF-8', $encoding)); } } + return $value; } @@ -226,6 +236,7 @@ class PageUrl $value = PageUrl::reencodeParameterValue($value, $encoding); } } + return $queryParameters; } @@ -247,12 +258,13 @@ class PageUrl { // if query params are encoded w/ non-utf8 characters (due to browser bug or whatever), // encode to UTF-8. - if ($encoding !== false - && strtolower($encoding) != 'utf-8' + if (false !== $encoding + && 'utf-8' != strtolower($encoding) && function_exists('mb_check_encoding') ) { $queryParameters = PageUrl::reencodeParametersArray($queryParameters, $encoding); } + return $queryParameters; } @@ -261,6 +273,7 @@ class PageUrl $url = Common::unsanitizeInputValue($url); $url = PageUrl::cleanupString($url); $url = PageUrl::convertMatrixUrl($url); + return $url; } @@ -274,6 +287,7 @@ class PageUrl public static function reconstructNormalizedUrl($url, $prefixId) { $map = array_flip(self::$urlPrefixMap); + if ($prefixId !== null && isset($map[$prefixId])) { $fullUrl = $map[$prefixId] . $url; } else { @@ -283,7 +297,8 @@ class PageUrl // Clean up host & hash tags, for URLs $parsedUrl = @parse_url($fullUrl); $parsedUrl = PageUrl::cleanupHostAndHashTag($parsedUrl); - $url = UrlHelper::getParseUrlReverse($parsedUrl); + $url = UrlHelper::getParseUrlReverse($parsedUrl); + if (!empty($url)) { return $url; } @@ -302,12 +317,14 @@ class PageUrl { foreach (self::$urlPrefixMap as $prefix => $id) { if (strtolower(substr($url, 0, strlen($prefix))) == $prefix) { + return array( 'url' => substr($url, strlen($prefix)), 'prefixId' => $id ); } } + return array('url' => $url, 'prefixId' => null); } @@ -317,10 +334,20 @@ class PageUrl if (!UrlHelper::isLookLikeUrl($url)) { Common::printDebug("WARNING: URL looks invalid and is discarded"); - $url = false; - return $url; + + return false; } + return $url; } + + private static function getExcludedParametersFromWebsite($website) + { + if (isset($website['excluded_parameters'])) { + return $website['excluded_parameters']; + } + + return array(); + } } diff --git a/core/Tracker/Request.php b/core/Tracker/Request.php index b34ee88709..8ded0dc7a2 100644 --- a/core/Tracker/Request.php +++ b/core/Tracker/Request.php @@ -138,10 +138,12 @@ class Request if (!$this->isTimestampValid($cookieFirstVisitTimestamp)) { $cookieFirstVisitTimestamp = $this->getCurrentTimestamp(); } + $daysSinceFirstVisit = round(($this->getCurrentTimestamp() - $cookieFirstVisitTimestamp) / 86400, $precision = 0); if ($daysSinceFirstVisit < 0) { $daysSinceFirstVisit = 0; } + return $daysSinceFirstVisit; } @@ -152,12 +154,14 @@ class Request { $daysSinceLastOrder = false; $lastOrderTimestamp = $this->getParam('_ects'); + if ($this->isTimestampValid($lastOrderTimestamp)) { $daysSinceLastOrder = round(($this->getCurrentTimestamp() - $lastOrderTimestamp) / 86400, $precision = 0); if ($daysSinceLastOrder < 0) { $daysSinceLastOrder = 0; } } + return $daysSinceLastOrder; } @@ -168,12 +172,14 @@ class Request { $daysSinceLastVisit = 0; $lastVisitTimestamp = $this->getParam('_viewts'); + if ($this->isTimestampValid($lastVisitTimestamp)) { $daysSinceLastVisit = round(($this->getCurrentTimestamp() - $lastVisitTimestamp) / 86400, $precision = 0); if ($daysSinceLastVisit < 0) { $daysSinceLastVisit = 0; } } + return $daysSinceLastVisit; } @@ -297,6 +303,7 @@ class Request if (!isset($supportedParams[$name])) { throw new Exception("Requested parameter $name is not a known Tracking API Parameter."); } + $paramDefaultValue = $supportedParams[$name][0]; $paramType = $supportedParams[$name][1]; @@ -318,7 +325,7 @@ class Request protected function isTimestampValid($time) { return $time <= $this->getCurrentTimestamp() - && $time > $this->getCurrentTimestamp() - 10 * 365 * 86400; + && $time > $this->getCurrentTimestamp() - 10 * 365 * 86400; } public function getIdSite() @@ -338,9 +345,11 @@ class Request * request. */ Piwik::postEvent('Tracker.Request.getIdSite', array(&$idSite, $this->params)); + if ($idSite <= 0) { throw new Exception('Invalid idSite: \'' . $idSite . '\''); } + return $idSite; } @@ -359,9 +368,11 @@ class Request } $customVar = Common::unsanitizeInputValues(Common::getRequestVar($parameter, '', 'json', $this->params)); + if (!is_array($customVar)) { return array(); } + $customVariables = array(); $maxCustomVars = CustomVariables::getMaxCustomVariables(); foreach ($customVar as $id => $keyValue) { @@ -374,13 +385,14 @@ class Request Common::printDebug("Invalid custom variables detected (id=$id)"); continue; } + if (strlen($keyValue[1]) == 0) { $keyValue[1] = ""; } // We keep in the URL when Custom Variable have empty names // and values, as it means they can be deleted server side - $key = self::truncateCustomVariable($keyValue[0]); + $key = self::truncateCustomVariable($keyValue[0]); $value = self::truncateCustomVariable($keyValue[1]); $customVariables['custom_var_k' . $id] = $key; $customVariables['custom_var_v' . $id] = $value; @@ -407,6 +419,7 @@ class Request if (!$this->shouldUseThirdPartyCookie()) { return; } + Common::printDebug("We manage the cookie..."); $cookie = $this->makeThirdPartyCookie(); @@ -455,7 +468,7 @@ class Request // If User ID is set it takes precedence $userId = $this->getForcedUserId(); - if($userId) { + if ($userId) { $userIdHashed = $this->getUserIdHashed($userId); $idVisitor = $this->truncateIdAsVisitorId($userIdHashed); Common::printDebug("Request will be recorded for this user_id = " . $userId . " (idvisitor = $idVisitor)"); @@ -502,6 +515,7 @@ class Request return $binVisitorId; } } + return false; } @@ -512,6 +526,7 @@ class Request } else { $ipString = IP::getIpFromHeader(); } + $ip = IP::P2N($ipString); return $ip; } @@ -536,9 +551,11 @@ class Request public function getForcedUserId() { $userId = $this->getParam('uid'); - if(strlen($userId) > 0) { + + if (strlen($userId) > 0) { return $userId; } + return null; } @@ -572,6 +589,7 @@ class Request ) { return (int)$generationTime; } + return false; } diff --git a/core/Tracker/TableLogAction.php b/core/Tracker/TableLogAction.php index c547d742b8..7ae99a535e 100644 --- a/core/Tracker/TableLogAction.php +++ b/core/Tracker/TableLogAction.php @@ -36,17 +36,17 @@ class TableLogAction { // Add url prefix if not set foreach($actionsNameAndType as &$action) { - if(count($action) == 2) { + if (2 == count($action)) { $action[] = null; } } + $actionIds = self::queryIdsAction($actionsNameAndType); list($queriedIds, $fieldNamesToInsert) = self::processIdsToInsert($actionsNameAndType, $actionIds); $insertedIds = self::insertNewIdsAction($actionsNameAndType, $fieldNamesToInsert); - - $queriedIds = $queriedIds + $insertedIds; + $queriedIds = $queriedIds + $insertedIds; return $queriedIds; } @@ -58,9 +58,10 @@ class TableLogAction */ private static function getIdActionMatchingNameAndType($name, $type) { - $sql = TableLogAction::getSqlSelectActionId(); - $bind = array($name, $name, $type); + $sql = TableLogAction::getSqlSelectActionId(); + $bind = array($name, $name, $type); $idAction = \Piwik\Db::fetchOne($sql, $bind); + return $idAction; } @@ -75,6 +76,7 @@ class TableLogAction // now, we handle the cases =@ (contains) and !@ (does not contain) // build the expression based on the match type $sql = 'SELECT idaction FROM ' . Common::prefixTable('log_action') . ' WHERE %s AND type = ' . $actionType . ' )'; + switch ($matchType) { case '=@': // use concat to make sure, no %s occurs because some plugins use %s in their sql @@ -87,7 +89,9 @@ class TableLogAction throw new \Exception("This match type $matchType is not available for action-segments."); break; } + $sql = sprintf($sql, $where); + return $sql; } @@ -97,6 +101,7 @@ class TableLogAction FROM " . Common::prefixTable('log_action') . " WHERE " . " ( hash = CRC32(?) AND name = ? AND type = ? ) "; + return $sql; } @@ -106,6 +111,7 @@ class TableLogAction "( name, hash, type, url_prefix ) VALUES (?,CRC32(?),?,?)"; // Then, we insert all new actions in the lookup table $inserted = array(); + foreach ($fieldNamesToInsert as $fieldName) { list($name, $type, $urlPrefix) = $actionsNameAndType[$fieldName]; @@ -116,13 +122,15 @@ class TableLogAction Common::printDebug("Recorded a new action (" . Action::getTypeAsString($type) . ") in the lookup table: " . $name . " (idaction = " . $actionId . ")"); } + return $inserted; } private static function queryIdsAction($actionsNameAndType) { - $sql = TableLogAction::getSqlSelectActionId(); + $sql = TableLogAction::getSqlSelectActionId(); $bind = array(); + $i = 0; foreach ($actionsNameAndType as &$actionNameType) { list($name, $type, $urlPrefix) = $actionNameType; @@ -141,6 +149,7 @@ class TableLogAction if (empty($bind)) { return false; } + $actionIds = Tracker::getDatabase()->fetchAll($sql, $bind); return $actionIds; } @@ -150,6 +159,7 @@ class TableLogAction // For the Actions found in the lookup table, add the idaction in the array, // If not found in lookup table, queue for INSERT $fieldNamesToInsert = $fieldNameToActionId = array(); + foreach ($actionsNameAndType as $fieldName => &$actionNameType) { @list($name, $type, $urlPrefix) = $actionNameType; if (empty($name)) { @@ -172,6 +182,7 @@ class TableLogAction $fieldNamesToInsert[] = $fieldName; } } + return array($fieldNameToActionId, $fieldNamesToInsert); } @@ -197,6 +208,7 @@ class TableLogAction // for urls trim protocol and www because it is not recorded in the db $valueToMatch = preg_replace('@^http[s]?://(www\.)?@i', '', $valueToMatch); } + $valueToMatch = Common::sanitizeInputValue(Common::unsanitizeInputValue($valueToMatch)); if ($matchType == SegmentExpression::MATCH_EQUAL @@ -214,6 +226,7 @@ class TableLogAction // "name contains $string" match can match several idaction so we cannot return yet an idaction // special case $sql = TableLogAction::getSelectQueryWhereNameContains($matchType, $actionType); + return array( // mark that the returned value is an sql-expression instead of a literal value 'SQL' => $sql, @@ -229,15 +242,16 @@ class TableLogAction private static function guessActionTypeFromSegment($segmentName) { $exactMatch = array( - 'eventAction' => Action::TYPE_EVENT_ACTION, - 'eventCategory' => Action::TYPE_EVENT_CATEGORY, - 'eventName' => Action::TYPE_EVENT_NAME, - 'contentPiece' => Action::TYPE_CONTENT_PIECE, - 'contentTarget' => Action::TYPE_CONTENT_TARGET, - 'contentName' => Action::TYPE_CONTENT_NAME, + 'eventAction' => Action::TYPE_EVENT_ACTION, + 'eventCategory' => Action::TYPE_EVENT_CATEGORY, + 'eventName' => Action::TYPE_EVENT_NAME, + 'contentPiece' => Action::TYPE_CONTENT_PIECE, + 'contentTarget' => Action::TYPE_CONTENT_TARGET, + 'contentName' => Action::TYPE_CONTENT_NAME, 'contentInteraction' => Action::TYPE_CONTENT_INTERACTION, ); - if(!empty($exactMatch[$segmentName])) { + + if (!empty($exactMatch[$segmentName])) { return $exactMatch[$segmentName]; } diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php index 90b58a88b0..75633d95b6 100644 --- a/core/Tracker/Visit.php +++ b/core/Tracker/Visit.php @@ -109,8 +109,9 @@ class Visit implements VisitInterface $visitIsConverted = false; $action = null; - $requestIsManualGoalConversion = ($this->goalManager->idGoal > 0); + $isManualGoalConversion = $this->goalManager->isManualGoalConversion(); $requestIsEcommerce = $this->goalManager->requestIsEcommerce; + if ($requestIsEcommerce) { $someGoalsConverted = true; @@ -118,23 +119,26 @@ class Visit implements VisitInterface if ($this->goalManager->isGoalAnOrder()) { $visitIsConverted = true; } - } // this request is from the JS call to piwikTracker.trackGoal() - elseif ($requestIsManualGoalConversion) { + + } elseif ($isManualGoalConversion) { + // this request is from the JS call to piwikTracker.trackGoal() $someGoalsConverted = $this->goalManager->detectGoalId($this->request->getIdSite()); - $visitIsConverted = $someGoalsConverted; + $visitIsConverted = $someGoalsConverted; + // if we find a idgoal in the URL, but then the goal is not valid, this is most likely a fake request if (!$someGoalsConverted) { Common::printDebug('Invalid goal tracking request for goal id = ' . $this->goalManager->idGoal); return; } - } // normal page view, potentially triggering a URL matching goal - else { + + } else { + // normal page view, potentially triggering a URL matching goal $action = Action::factory($this->request); $action->writeDebugInfo(); $someGoalsConverted = $this->goalManager->detectGoalsMatchingUrl($this->request->getIdSite(), $action); - $visitIsConverted = $someGoalsConverted; + $visitIsConverted = $someGoalsConverted; $action->loadIdsFromLogActionTable(); } @@ -153,6 +157,7 @@ class Visit implements VisitInterface if (!$isLastActionInTheSameVisit) { Common::printDebug("Visitor detected, but last action was more than 30 minutes ago..."); } + // Known visit when: // ( - the visitor has the Piwik cookie with the idcookie ID used by Piwik to match the visitor // OR @@ -165,12 +170,15 @@ class Visit implements VisitInterface ) { $idReferrerActionUrl = $this->visitorInfo['visit_exit_idaction_url']; $idReferrerActionName = $this->visitorInfo['visit_exit_idaction_name']; + try { $this->goalManager->detectIsThereExistingCartInVisit($this->visitorInfo); $this->handleExistingVisit($visitor, $action, $visitIsConverted); + if (!is_null($action)) { $action->record($visitor, $idReferrerActionUrl, $idReferrerActionName); } + } catch (VisitorNotFoundInDb $e) { // There is an edge case when: @@ -179,7 +187,7 @@ class Visit implements VisitInterface // because the UPDATE didn't affect any rows (one row was found, but not updated since no field changed) // - the exception is caught here and will result in a new visit incorrectly // In this case, we cancel the current conversion to be recorded: - if ($requestIsManualGoalConversion + if ($isManualGoalConversion || $requestIsEcommerce ) { $someGoalsConverted = $visitIsConverted = false; @@ -239,8 +247,7 @@ class Visit implements VisitInterface // TODO we should not have to sync this->visitorInfo and $visitor columns. // TODO it should be its own dimension - $this->visitorInfo['time_spent_ref_action'] = $this->getTimeSpentReferrerAction(); - $visitor->setVisitorColumn('time_spent_ref_action', $this->visitorInfo['time_spent_ref_action']); + $this->setVisitorColumn($visitor, 'time_spent_ref_action', $this->getTimeSpentReferrerAction()); // update visitorInfo foreach ($valuesToUpdate as $name => $value) { @@ -262,8 +269,7 @@ class Visit implements VisitInterface $this->updateExistingVisit($valuesToUpdate); - $this->visitorInfo['visit_last_action_time'] = $this->request->getCurrentTimestamp(); - $visitor->setVisitorColumn('visit_last_action_time', $this->visitorInfo['visit_last_action_time']); + $this->setVisitorColumn($visitor, 'visit_last_action_time', $this->request->getCurrentTimestamp()); } /** @@ -275,8 +281,8 @@ class Visit implements VisitInterface if ($timeSpent < 0) { $timeSpent = 0; } - $visitStandardLength = Config::getInstance()->Tracker['visit_standard_length']; - if($timeSpent > $visitStandardLength) { + $visitStandardLength = $this->getVisitStandardLength(); + if ($timeSpent > $visitStandardLength) { $timeSpent = $visitStandardLength; } return $timeSpent; @@ -297,15 +303,7 @@ class Visit implements VisitInterface { Common::printDebug("New Visit (IP = " . IP::N2P($this->getVisitorIp()) . ")"); - $this->visitorInfo = $this->getNewVisitorInformation($visitor); - - // Add Custom variable key,value to the visitor array - $this->visitorInfo = array_merge($this->visitorInfo, $this->visitorCustomVariables); - - $visitor->clearVisitorInfo(); - foreach ($this->visitorInfo as $key => $value) { - $visitor->setVisitorColumn($key, $value); - } + $this->setNewVisitorInformation($visitor); $dimensions = $this->getAllVisitDimensions(); @@ -331,13 +329,9 @@ class Visit implements VisitInterface $idVisit = $this->insertNewVisit( $this->visitorInfo ); - $this->visitorInfo['idvisit'] = $idVisit; - $this->visitorInfo['visit_first_action_time'] = $this->request->getCurrentTimestamp(); - $this->visitorInfo['visit_last_action_time'] = $this->request->getCurrentTimestamp(); - - $visitor->setVisitorColumn('idvisit', $this->visitorInfo['idvisit']); - $visitor->setVisitorColumn('visit_first_action_time', $this->visitorInfo['visit_first_action_time']); - $visitor->setVisitorColumn('visit_last_action_time', $this->visitorInfo['visit_last_action_time']); + $this->setVisitorColumn($visitor, 'idvisit', $idVisit); + $this->setVisitorColumn($visitor, 'visit_first_action_time', $this->request->getCurrentTimestamp()); + $this->setVisitorColumn($visitor, 'visit_last_action_time', $this->request->getCurrentTimestamp()); } /** @@ -353,7 +347,7 @@ class Visit implements VisitInterface // If the visitor had a first party ID cookie, then we use this value if (!empty($this->visitorInfo['idvisitor']) - && strlen($this->visitorInfo['idvisitor']) == Tracker::LENGTH_BINARY_ID + && Tracker::LENGTH_BINARY_ID == strlen($this->visitorInfo['idvisitor']) ) { return $this->visitorInfo['idvisitor']; } @@ -366,8 +360,7 @@ class Visit implements VisitInterface */ public static function generateUniqueVisitorId() { - $uniqueId = substr(Common::generateUniqId(), 0, Tracker::LENGTH_HEX_ID_STRING); - return $uniqueId; + return substr(Common::generateUniqId(), 0, Tracker::LENGTH_HEX_ID_STRING); } /** @@ -387,9 +380,10 @@ class Visit implements VisitInterface */ protected function getSettingsObject() { - if(is_null($this->userSettings)) { + if (is_null($this->userSettings)) { $this->userSettings = new Settings( $this->request, $this->getVisitorIp() ); } + return $this->userSettings; } @@ -410,33 +404,42 @@ class Visit implements VisitInterface public static function isHostKnownAliasHost($urlHost, $idSite) { $websiteData = Cache::getCacheWebsiteAttributes($idSite); + if (isset($websiteData['hosts'])) { $canonicalHosts = array(); foreach ($websiteData['hosts'] as $host) { - $canonicalHosts[] = str_replace('www.', '', mb_strtolower($host, 'UTF-8')); + $canonicalHosts[] = self::toCanonicalHost($host); } - $canonicalHost = str_replace('www.', '', mb_strtolower($urlHost, 'UTF-8')); + + $canonicalHost = self::toCanonicalHost($urlHost); if (in_array($canonicalHost, $canonicalHosts)) { return true; } } + return false; } + private static function toCanonicalHost($host) + { + $hostLower = mb_strtolower($host, 'UTF-8'); + return str_replace('www.', '', $hostLower); + } + /** * @return mixed */ protected function insertNewVisit($visit) { - $fields = implode(", ", array_keys($visit)); + $fields = array_keys($visit); + $fields = implode(", ", $fields); $values = Common::getSqlStringFieldsArray($visit); - $sql = "INSERT INTO " . Common::prefixTable('log_visit') . " ($fields) VALUES ($values)"; + $sql = "INSERT INTO " . Common::prefixTable('log_visit') . " ($fields) VALUES ($values)"; $bind = array_values($visit); Tracker::getDatabase()->query($sql, $bind); - $idVisit = Tracker::getDatabase()->lastInsertId(); - return $idVisit; + return Tracker::getDatabase()->lastInsertId(); } /** @@ -445,25 +448,7 @@ class Visit implements VisitInterface */ protected function updateExistingVisit($valuesToUpdate) { - $sqlQuery = "UPDATE " . Common::prefixTable('log_visit') . " - SET %s - WHERE idsite = ? - AND idvisit = ?"; - // build sql query - $updateParts = $sqlBind = array(); - foreach ($valuesToUpdate as $name => $value) { - // Case where bind parameters don't work - if(strpos($value, $name) !== false) { - //$name = 'visit_total_events' - //$value = 'visit_total_events + 1'; - $updateParts[] = " $name = $value "; - } else { - $updateParts[] = $name . " = ?"; - $sqlBind[] = $value; - } - } - $sqlQuery = sprintf($sqlQuery, implode($updateParts, ', ') ); - array_push($sqlBind, $this->request->getIdSite(), (int)$this->visitorInfo['idvisit']); + list($sqlQuery, $sqlBind) = $this->getUpdateExistingVisitQuery($valuesToUpdate); $result = Tracker::getDatabase()->query($sqlQuery, $sqlBind); @@ -471,6 +456,7 @@ class Visit implements VisitInterface if (isset($valuesToUpdate['idvisitor'])) { $valuesToUpdate['idvisitor'] = bin2hex($valuesToUpdate['idvisitor']); } + Common::printDebug('Updating existing visit: ' . var_export($valuesToUpdate, true)); if (Tracker::getDatabase()->rowCount($result) == 0) { @@ -483,7 +469,13 @@ class Visit implements VisitInterface } } - protected function printVisitorInformation() + private function setVisitorColumn(Visitor $visitor, $key, $value) + { + $this->visitorInfo[$key] = $value; + $visitor->setVisitorColumn($key, $value); + } + + private function printVisitorInformation() { $debugVisitInfo = $this->visitorInfo; $debugVisitInfo['idvisitor'] = bin2hex($debugVisitInfo['idvisitor']); @@ -491,13 +483,22 @@ class Visit implements VisitInterface Common::printDebug($debugVisitInfo); } - protected function getNewVisitorInformation($visitor) + private function setNewVisitorInformation(Visitor $visitor) { - return array( - 'idvisitor' => $this->getVisitorIdcookie($visitor), - 'config_id' => $this->getSettingsObject()->getConfigId(), - 'location_ip' => $this->getVisitorIp(), - ); + $idVisitor = $this->getVisitorIdcookie($visitor); + $visitorIp = $this->getVisitorIp(); + $configId = $this->getSettingsObject()->getConfigId(); + + $this->visitorInfo = array(); + $visitor->clearVisitorInfo(); + + $this->setVisitorColumn($visitor, 'idvisitor', $idVisitor); + $this->setVisitorColumn($visitor, 'config_id', $configId); + $this->setVisitorColumn($visitor, 'location_ip', $visitorIp); + + foreach ($this->visitorCustomVariables as $key => $value) { + $this->setVisitorColumn($visitor, $key, $value); + } } /** @@ -508,7 +509,7 @@ class Visit implements VisitInterface * @param $visitIsConverted * @return array */ - protected function getExistingVisitFieldsToUpdate($visitor, $action, $visitIsConverted) + private function getExistingVisitFieldsToUpdate($visitor, $action, $visitIsConverted) { $valuesToUpdate = array(); @@ -526,8 +527,7 @@ class Visit implements VisitInterface } // Custom Variables overwrite previous values on each page view - $valuesToUpdate = array_merge($valuesToUpdate, $this->visitorCustomVariables); - return $valuesToUpdate; + return array_merge($valuesToUpdate, $this->visitorCustomVariables); } /** @@ -567,7 +567,50 @@ class Visit implements VisitInterface foreach($dimensions as $dimension) { $dimensionNames[] = $dimension->getColumnName(); } + Common::printDebug("Following dimensions have been collected from plugins: " . implode(", ", $dimensionNames)); + return $dimensions; } + + private function fieldsToQuery($valuesToUpdate) + { + $updateParts = array(); + $sqlBind = array(); + + foreach ($valuesToUpdate as $name => $value) { + // Case where bind parameters don't work + if ($value === $name . ' + 1') { + //$name = 'visit_total_events' + //$value = 'visit_total_events + 1'; + $updateParts[] = " $name = $value "; + } else { + $updateParts[] = $name . " = ?"; + $sqlBind[] = $value; + } + } + + return array($updateParts, $sqlBind); + } + + private function getUpdateExistingVisitQuery($valuesToUpdate) + { + $sqlQuery = "UPDATE " . Common::prefixTable('log_visit') . " SET %s WHERE idsite = ? AND idvisit = ?"; + + // build sql query + list($updateParts, $sqlBind) = $this->fieldsToQuery($valuesToUpdate); + + $idSite = $this->request->getIdSite(); + $idVisit = (int) $this->visitorInfo['idvisit']; + + $sqlQuery = sprintf($sqlQuery, implode($updateParts, ', ')); + array_push($sqlBind, $idSite, $idVisit); + + return array($sqlQuery, $sqlBind); + } + + private function getVisitStandardLength() + { + return Config::getInstance()->Tracker['visit_standard_length']; + } } diff --git a/core/Tracker/VisitExcluded.php b/core/Tracker/VisitExcluded.php index 586c874a0c..48eb1e3db7 100644 --- a/core/Tracker/VisitExcluded.php +++ b/core/Tracker/VisitExcluded.php @@ -8,7 +8,6 @@ */ namespace Piwik\Tracker; -use DeviceDetector\Parser\Bot; use Piwik\Common; use Piwik\Config; use Piwik\DeviceDetectorFactory; @@ -27,16 +26,16 @@ class VisitExcluded */ public function __construct(Request $request, $ip = false, $userAgent = false) { - if ($ip === false) { + if (false === $ip) { $ip = $request->getIp(); } - if ($userAgent === false) { + if (false === $userAgent) { $userAgent = $request->getUserAgent(); } - $this->request = $request; - $this->idSite = $request->getIdSite(); + $this->request = $request; + $this->idSite = $request->getIdSite(); $this->userAgent = $userAgent; $this->ip = $ip; } @@ -200,6 +199,7 @@ class VisitExcluded Common::printDebug('Piwik ignore cookie was found, visit not tracked.'); return true; } + return false; } @@ -211,12 +211,14 @@ class VisitExcluded protected function isVisitorIpExcluded() { $websiteAttributes = Cache::getCacheWebsiteAttributes($this->idSite); + if (!empty($websiteAttributes['excluded_ips'])) { if (IP::isIpInRange($this->ip, $websiteAttributes['excluded_ips'])) { Common::printDebug('Visitor IP ' . IP::N2P($this->ip) . ' is excluded from being tracked'); return true; } } + return false; } @@ -232,6 +234,7 @@ class VisitExcluded protected function isUserAgentExcluded() { $websiteAttributes = Cache::getCacheWebsiteAttributes($this->idSite); + if (!empty($websiteAttributes['excluded_user_agents'])) { foreach ($websiteAttributes['excluded_user_agents'] as $excludedUserAgent) { // if the excluded user agent string part is in this visit's user agent, this visit should be excluded @@ -240,6 +243,7 @@ class VisitExcluded } } } + return false; } @@ -254,12 +258,14 @@ class VisitExcluded $spamHosts = explode(",", $spamHosts); $referrerUrl = $this->request->getParam('urlref'); + foreach($spamHosts as $spamHost) { - if( strpos($referrerUrl, $spamHost) !== false) { + if ( strpos($referrerUrl, $spamHost) !== false) { Common::printDebug('Referrer URL is a known spam: ' . $spamHost); return true; } } + return false; } } diff --git a/core/Tracker/Visitor.php b/core/Tracker/Visitor.php index b412078151..a73361e014 100644 --- a/core/Tracker/Visitor.php +++ b/core/Tracker/Visitor.php @@ -209,16 +209,16 @@ class Visitor */ protected function getWindowLookupThisVisit() { - $visitStandardLength = Config::getInstance()->Tracker['visit_standard_length']; + $visitStandardLength = Config::getInstance()->Tracker['visit_standard_length']; $lookBackNSecondsCustom = Config::getInstance()->Tracker['window_look_back_for_visitor']; $lookAheadNSeconds = $visitStandardLength; - $lookBackNSeconds = $visitStandardLength; + $lookBackNSeconds = $visitStandardLength; if ($lookBackNSecondsCustom > $lookBackNSeconds) { $lookBackNSeconds = $lookBackNSecondsCustom; } - $timeLookBack = date('Y-m-d H:i:s', $this->request->getCurrentTimestamp() - $lookBackNSeconds); + $timeLookBack = date('Y-m-d H:i:s', $this->request->getCurrentTimestamp() - $lookBackNSeconds); $timeLookAhead = date('Y-m-d H:i:s', $this->request->getCurrentTimestamp() + $lookAheadNSeconds); return array($timeLookBack, $timeLookAhead); @@ -240,6 +240,7 @@ class Visitor || $isForcedVisitorIdMustMatch || $isForcedUserIdMustMatch || !$isVisitorIdToLookup); + return $shouldMatchOneFieldOnly; } diff --git a/core/Translate.php b/core/Translate.php index 34bd35ba12..65381c0a2d 100644 --- a/core/Translate.php +++ b/core/Translate.php @@ -68,7 +68,7 @@ class Translate private static function loadCoreTranslationFile($language) { - if(empty($language)) { + if (empty($language)) { return; } $path = PIWIK_INCLUDE_PATH . '/lang/' . $language . '.json'; @@ -174,7 +174,7 @@ class Translate } $js = 'var translations = ' . Common::json_encode($clientSideTranslations) . ';'; - $js .= "\n" . 'if(typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }' . + $js .= "\n" . 'if (typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }' . 'for(var i in translations) { piwik_translations[i] = translations[i];} '; return $js; } diff --git a/core/Translate/Validate/NoScripts.php b/core/Translate/Validate/NoScripts.php index 0ee0fc9a57..e7f032ff55 100644 --- a/core/Translate/Validate/NoScripts.php +++ b/core/Translate/Validate/NoScripts.php @@ -28,12 +28,14 @@ class NoScripts extends ValidateAbstract // check if any translation contains restricted script tags $serializedStrings = serialize($translations); $invalids = array("<script", 'document.', 'javascript:', 'src=', 'background=', 'onload='); + foreach ($invalids as $invalid) { if (stripos($serializedStrings, $invalid) !== false) { $this->message = 'script tags restricted for language files'; return false; } } + return true; } } diff --git a/core/Translate/Writer.php b/core/Translate/Writer.php index 617b8b9552..c43beca189 100644 --- a/core/Translate/Writer.php +++ b/core/Translate/Writer.php @@ -71,7 +71,7 @@ class Writer protected $filterMessages = array(); const UNFILTERED = 'unfiltered'; - const FILTERED = 'filtered'; + const FILTERED = 'filtered'; protected $currentState = self::UNFILTERED; @@ -152,12 +152,14 @@ class Writer public function getTranslations($lang) { $path = $this->getTranslationPathBaseDirectory('lang', $lang); + if (!is_readable($path)) { return array(); } $data = file_get_contents($path); $translations = json_decode($data, true); + return $translations; } diff --git a/core/Twig.php b/core/Twig.php index b0707350c4..2e0ef95844 100755 --- a/core/Twig.php +++ b/core/Twig.php @@ -46,7 +46,7 @@ class Twig $loaders = array(); //create loader for custom theme to overwrite twig templates - if($theme && $theme->getPluginName() != \Piwik\Plugin\Manager::DEFAULT_THEME) { + if ($theme && $theme->getPluginName() != \Piwik\Plugin\Manager::DEFAULT_THEME) { $customLoader = $this->getCustomThemeLoader($theme); if ($customLoader) { //make it possible to overwrite plugin templates @@ -187,7 +187,7 @@ class Twig * @return \Twig_Loader_Filesystem */ protected function getCustomThemeLoader(Plugin $theme){ - if(!file_exists(sprintf("%s/plugins/%s/templates/", PIWIK_INCLUDE_PATH, $theme->getPluginName()))){ + if (!file_exists(sprintf("%s/plugins/%s/templates/", PIWIK_INCLUDE_PATH, $theme->getPluginName()))){ return false; } $themeLoader = new Twig_Loader_Filesystem(array( diff --git a/core/Unzip/Gzip.php b/core/Unzip/Gzip.php index 16f08abf0a..7e572e35ea 100755 --- a/core/Unzip/Gzip.php +++ b/core/Unzip/Gzip.php @@ -48,6 +48,7 @@ class Gzip implements UncompressInterface public function extract($pathExtracted) { $file = gzopen($this->filename, 'r'); + if ($file === false) { $this->error = "gzopen failed"; return false; @@ -60,7 +61,7 @@ class Gzip implements UncompressInterface fclose($output); $success = gzclose($file); - if ($success === false) { + if (false === $success) { $this->error = "gzclose failed"; return false; } diff --git a/core/Unzip/PclZip.php b/core/Unzip/PclZip.php index b0ce4b3a75..ff03aac3d9 100644 --- a/core/Unzip/PclZip.php +++ b/core/Unzip/PclZip.php @@ -35,7 +35,7 @@ class PclZip implements UncompressInterface */ public function __construct($filename) { - $this->pclzip = new \PclZip($filename); + $this->pclzip = new \PclZip($filename); $this->filename = $filename; } @@ -55,7 +55,7 @@ class PclZip implements UncompressInterface foreach ($list as $entry) { $filename = str_replace('\\', '/', $entry['stored_filename']); - $parts = explode('/', $filename); + $parts = explode('/', $filename); if (!strncmp($filename, '/', 1) || array_search('..', $parts) !== false || diff --git a/core/Unzip/ZipArchive.php b/core/Unzip/ZipArchive.php index c8d7edd874..e68e168c0c 100644 --- a/core/Unzip/ZipArchive.php +++ b/core/Unzip/ZipArchive.php @@ -53,8 +53,9 @@ class ZipArchive implements UncompressInterface } $fileselector = array(); - $list = array(); + $list = array(); $count = $this->ziparchive->numFiles; + if ($count === 0) { return 0; } @@ -63,7 +64,7 @@ class ZipArchive implements UncompressInterface $entry = $this->ziparchive->statIndex($i); $filename = str_replace('\\', '/', $entry['name']); - $parts = explode('/', $filename); + $parts = explode('/', $filename); if (!strncmp($filename, '/', 1) || array_search('..', $parts) !== false || @@ -71,6 +72,7 @@ class ZipArchive implements UncompressInterface ) { return 0; } + $fileselector[] = $entry['name']; $list[] = array( 'filename' => $pathExtracted . $entry['name'], @@ -84,8 +86,10 @@ class ZipArchive implements UncompressInterface } $res = $this->ziparchive->extractTo($pathExtracted, $fileselector); - if ($res === false) + if ($res === false) { return 0; + } + return $list; } @@ -128,6 +132,7 @@ class ZipArchive implements UncompressInterface } else { $statusString = 'Unknown status'; } + return $statusString . '(' . $this->ziparchive->status . ')'; } } diff --git a/core/UpdateCheck.php b/core/UpdateCheck.php index 228ac23a85..43639da9dc 100644 --- a/core/UpdateCheck.php +++ b/core/UpdateCheck.php @@ -36,7 +36,7 @@ class UpdateCheck */ public static function check($force = false, $interval = null) { - if(!self::isAutoUpdateEnabled()) { + if (!self::isAutoUpdateEnabled()) { return; } diff --git a/core/Updater.php b/core/Updater.php index 1527da723a..0069d1b71b 100644 --- a/core/Updater.php +++ b/core/Updater.php @@ -355,6 +355,7 @@ class Updater * @param string $updateSql Update SQL query. * @param int|false $errorToIgnore A MySQL error code to ignore. * @param string $file The Update file that's calling this method. + * @throws UpdaterErrorException */ public static function handleQueryError($e, $updateSql, $errorToIgnore, $file) { @@ -371,6 +372,7 @@ class Updater * * @param int $error * @param int|int[] $errorCodesToIgnore + * @return boolean */ public static function isDbErrorOneOf($error, $errorCodesToIgnore) { diff --git a/core/Updates/2.0-a17.php b/core/Updates/2.0-a17.php index 2df452c1ab..5d65143596 100644 --- a/core/Updates/2.0-a17.php +++ b/core/Updates/2.0-a17.php @@ -35,7 +35,7 @@ class Updates_2_0_a17 extends Updates } } - if(!empty($errors)) { + if (!empty($errors)) { throw new \Exception("Warnings during the update: <br>" . implode("<br>", $errors)); } } diff --git a/core/Updates/2.0-b13.php b/core/Updates/2.0-b13.php index 78cc791566..a5e9546b90 100644 --- a/core/Updates/2.0-b13.php +++ b/core/Updates/2.0-b13.php @@ -35,7 +35,7 @@ class Updates_2_0_b13 extends Updates } } - if(!empty($errors)) { + if (!empty($errors)) { throw new \Exception("Warnings during the update: <br>" . implode("<br>", $errors)); } } diff --git a/core/Updates/2.0.3-b7.php b/core/Updates/2.0.3-b7.php index f3fa6a34aa..add119e462 100644 --- a/core/Updates/2.0.3-b7.php +++ b/core/Updates/2.0.3-b7.php @@ -56,7 +56,7 @@ class Updates_2_0_3_b7 extends Updates } } - if(!empty($errors)) { + if (!empty($errors)) { throw new \Exception("Warnings during the update: <br>" . implode("<br>", $errors)); } } diff --git a/core/Updates/2.1.1-b11.php b/core/Updates/2.1.1-b11.php index 45b781a1cf..3fa0364e73 100644 --- a/core/Updates/2.1.1-b11.php +++ b/core/Updates/2.1.1-b11.php @@ -41,17 +41,14 @@ class Updates_2_1_1_b11 extends Updates // returning visit segment foreach ($archiveNumericTables as $table) { // get archives w/ *._returning - $sql = "SELECT idarchive, idsite, period, date1, date2 - FROM $table - WHERE name IN ('" . implode("','", $returningMetrics) . "') - GROUP BY idarchive"; + $sql = "SELECT idarchive, idsite, period, date1, date2 FROM $table + WHERE name IN ('" . implode("','", $returningMetrics) . "') + GROUP BY idarchive"; $idArchivesWithReturning = Db::fetchAll($sql); // get archives for visitssummary returning visitor segment - $sql = "SELECT idarchive, idsite, period, date1, date2 - FROM $table - WHERE name = ? - GROUP BY idarchive"; + $sql = "SELECT idarchive, idsite, period, date1, date2 FROM $table + WHERE name = ? GROUP BY idarchive"; $visitSummaryReturningSegmentDone = Rules::getDoneFlagArchiveContainsOnePlugin( new Segment(VisitFrequencyApi::RETURNING_VISITOR_SEGMENT, $idSites = array()), 'VisitsSummary'); $idArchivesWithVisitReturningSegment = Db::fetchAll($sql, array($visitSummaryReturningSegmentDone)); diff --git a/core/Updates/2.4.0-b1.php b/core/Updates/2.4.0-b1.php index a0f6d64f65..cc0d615d54 100644 --- a/core/Updates/2.4.0-b1.php +++ b/core/Updates/2.4.0-b1.php @@ -8,9 +8,6 @@ */ namespace Piwik\Updates; -use Faker\Provider\File; -use Piwik\Filesystem; -use Piwik\Plugins\Installation\ServerFilesGenerator; use Piwik\Updates; class Updates_2_4_0_b1 extends Updates diff --git a/core/Url.php b/core/Url.php index 32ea140f20..75b0731e78 100644 --- a/core/Url.php +++ b/core/Url.php @@ -10,12 +10,7 @@ namespace Piwik; use Exception; -use Piwik\Config; -use Piwik\Common; -use Piwik\IP; -use Piwik\ProxyHttp; use Piwik\Session; -use Piwik\UrlHelper; /** * Provides URL related helper methods. @@ -346,7 +341,7 @@ class Url $hostHeaders = array(); $config = Config::getInstance()->General; - if(isset($config['proxy_host_headers'])) { + if (isset($config['proxy_host_headers'])) { $hostHeaders = $config['proxy_host_headers']; } @@ -473,6 +468,7 @@ class Url * Redirects the user to the specified URL. * * @param string $url + * @throws Exception * @api */ public static function redirectToUrl($url) @@ -490,7 +486,7 @@ class Url echo "Invalid URL to redirect to."; } - if(Common::isPhpCliMode()) { + if (Common::isPhpCliMode()) { throw new Exception("If you were using a browser, Piwik would redirect you to this URL: $url \n\n"); } exit; @@ -501,7 +497,7 @@ class Url */ public static function redirectToHttps() { - if(ProxyHttp::isHttps()) { + if (ProxyHttp::isHttps()) { return; } $url = self::getCurrentUrl(); diff --git a/core/View.php b/core/View.php index bc02e4c792..6200a23113 100644 --- a/core/View.php +++ b/core/View.php @@ -9,12 +9,8 @@ namespace Piwik; use Exception; -use Piwik\Access; use Piwik\AssetManager\UIAssetCacheBuster; -use Piwik\Common; use Piwik\Plugins\UsersManager\API as APIUsersManager; -use Piwik\SettingsPiwik; -use Piwik\Version; use Piwik\View\ViewInterface; use Twig_Environment; diff --git a/core/View/ReportsByDimension.php b/core/View/ReportsByDimension.php index e1cb058459..dbb59be930 100644 --- a/core/View/ReportsByDimension.php +++ b/core/View/ReportsByDimension.php @@ -104,10 +104,10 @@ class ReportsByDimension extends View // display it initially $categories = $this->dimensionCategories; if (!empty($categories)) { - $firstCategory = reset($categories); + $firstCategory = reset($categories); $firstReportInfo = reset($firstCategory); - $oldGet = $_GET; + $oldGet = $_GET; $oldPost = $_POST; foreach ($firstReportInfo['params'] as $key => $value) { @@ -120,7 +120,7 @@ class ReportsByDimension extends View $action = $firstReportInfo['params']['action']; $this->firstReport = FrontController::getInstance()->fetchDispatch($module, $action); - $_GET = $oldGet; + $_GET = $oldGet; $_POST = $oldPost; } diff --git a/core/ViewDataTable/Config.php b/core/ViewDataTable/Config.php index 2bd748d3e4..1706e4b15f 100644 --- a/core/ViewDataTable/Config.php +++ b/core/ViewDataTable/Config.php @@ -598,7 +598,7 @@ class Config // don't add the related report if it references this report if ($this->controllerName == $module && $this->controllerAction == $action) { - if(empty($queryParams)) { + if (empty($queryParams)) { return; } } diff --git a/core/ViewDataTable/Manager.php b/core/ViewDataTable/Manager.php index 19e2335ce1..5d05650657 100644 --- a/core/ViewDataTable/Manager.php +++ b/core/ViewDataTable/Manager.php @@ -156,46 +156,7 @@ class Manager { $result = array(); - // add normal view icons (eg, normal table, all columns, goals) - $normalViewIcons = array( - 'class' => 'tableAllColumnsSwitch', - 'buttons' => array(), - ); - - if ($view->config->show_table) { - $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID); - } - - if ($view->config->show_table_all_columns) { - $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID); - } - - if ($view->config->show_goals) { - $goalButton = static::getFooterIconFor(Goals::ID); - if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') { - $goalButton['icon'] = 'plugins/Morpheus/images/ecommerceOrder.gif'; - } - - $normalViewIcons['buttons'][] = $goalButton; - } - - if ($view->config->show_ecommerce) { - $normalViewIcons['buttons'][] = array( - 'id' => 'ecommerceOrder', - 'title' => Piwik::translate('General_EcommerceOrders'), - 'icon' => 'plugins/Morpheus/images/ecommerceOrder.gif', - 'text' => Piwik::translate('General_EcommerceOrders') - ); - - $normalViewIcons['buttons'][] = array( - 'id' => 'ecommerceAbandonedCart', - 'title' => Piwik::translate('General_AbandonedCarts'), - 'icon' => 'plugins/Morpheus/images/ecommerceAbandonedCart.gif', - 'text' => Piwik::translate('General_AbandonedCarts') - ); - } - - $normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']); + $normalViewIcons = self::getNormalViewIcons($view); if (!empty($normalViewIcons['buttons'])) { $result[] = $normalViewIcons; @@ -207,25 +168,7 @@ class Manager 'buttons' => array(), ); - // add graph views - $graphViewIcons = array( - 'class' => 'tableGraphViews tableGraphCollapsed', - 'buttons' => array(), - ); - - if ($view->config->show_all_views_icons) { - if ($view->config->show_bar_chart) { - $graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID); - } - - if ($view->config->show_pie_chart) { - $graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID); - } - - if ($view->config->show_tag_cloud) { - $graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID); - } - } + $graphViewIcons = self::getGraphViewIcons($view); $nonCoreVisualizations = static::getNonCoreViewDataTables(); @@ -331,4 +274,75 @@ class Manager { return sprintf('viewDataTableParameters_%s_%s', $login, $controllerAction); } + + private static function getNormalViewIcons(ViewDataTable $view) + { + // add normal view icons (eg, normal table, all columns, goals) + $normalViewIcons = array( + 'class' => 'tableAllColumnsSwitch', + 'buttons' => array(), + ); + + if ($view->config->show_table) { + $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID); + } + + if ($view->config->show_table_all_columns) { + $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID); + } + + if ($view->config->show_goals) { + $goalButton = static::getFooterIconFor(Goals::ID); + if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') { + $goalButton['icon'] = 'plugins/Morpheus/images/ecommerceOrder.gif'; + } + + $normalViewIcons['buttons'][] = $goalButton; + } + + if ($view->config->show_ecommerce) { + $normalViewIcons['buttons'][] = array( + 'id' => 'ecommerceOrder', + 'title' => Piwik::translate('General_EcommerceOrders'), + 'icon' => 'plugins/Morpheus/images/ecommerceOrder.gif', + 'text' => Piwik::translate('General_EcommerceOrders') + ); + + $normalViewIcons['buttons'][] = array( + 'id' => 'ecommerceAbandonedCart', + 'title' => Piwik::translate('General_AbandonedCarts'), + 'icon' => 'plugins/Morpheus/images/ecommerceAbandonedCart.gif', + 'text' => Piwik::translate('General_AbandonedCarts') + ); + } + + $normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']); + + return $normalViewIcons; + } + + private static function getGraphViewIcons(ViewDataTable $view) + { + // add graph views + $graphViewIcons = array( + 'class' => 'tableGraphViews tableGraphCollapsed', + 'buttons' => array(), + ); + + if ($view->config->show_all_views_icons) { + if ($view->config->show_bar_chart) { + $graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID); + } + + if ($view->config->show_pie_chart) { + $graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID); + } + + if ($view->config->show_tag_cloud) { + $graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID); + } + } + + return $graphViewIcons; + } } diff --git a/core/ViewDataTable/Request.php b/core/ViewDataTable/Request.php index 9493889944..352ce25899 100644 --- a/core/ViewDataTable/Request.php +++ b/core/ViewDataTable/Request.php @@ -119,8 +119,8 @@ class Request if (isset($_GET[$nameVar])) { return Common::sanitizeInputValue($_GET[$nameVar]); } - $default = $this->getDefault($nameVar); - return $default; + + return $this->getDefault($nameVar); } /** diff --git a/core/Visualization/Sparkline.php b/core/Visualization/Sparkline.php index 8a7b406342..642c1325cb 100644 --- a/core/Visualization/Sparkline.php +++ b/core/Visualization/Sparkline.php @@ -32,6 +32,7 @@ class Sparkline implements ViewInterface public static $enableSparklineImages = true; private static $colorNames = array('backgroundColor', 'lineColor', 'minPointColor', 'lastPointColor', 'maxPointColor'); + private $values = array(); /** * Width of the sparkline @@ -60,7 +61,6 @@ class Sparkline implements ViewInterface */ public function setHeight($height) { - if (!is_numeric($height) || $height <= 0) { return; } @@ -74,7 +74,6 @@ class Sparkline implements ViewInterface */ public function setWidth($width) { - if (!is_numeric($width) || $width <= 0) { return; } @@ -110,7 +109,9 @@ class Sparkline implements ViewInterface $min = $max = $last = null; $i = 0; - $toRemove = array('%', str_replace('%s', '', Piwik::translate('General_Seconds'))); + $seconds = Piwik::translate('General_Seconds'); + $toRemove = array('%', str_replace('%s', '', $seconds)); + foreach ($this->values as $value) { // 50% and 50s should be plotted as 50 $value = str_replace($toRemove, '', $value); @@ -158,6 +159,7 @@ class Sparkline implements ViewInterface private function setSparklineColors($sparkline) { $colors = Common::getRequestVar('colors', false, 'json'); + if (empty($colors)) { // quick fix so row evolution sparklines will have color in widgetize's iframes $colors = array( 'backgroundColor' => '#ffffff', diff --git a/core/dispatch.php b/core/dispatch.php index f18b73f0bd..133f26f355 100644 --- a/core/dispatch.php +++ b/core/dispatch.php @@ -24,7 +24,7 @@ if (!defined('PIWIK_ENABLE_ERROR_HANDLER') || PIWIK_ENABLE_ERROR_HANDLER) { FrontController::setUpSafeMode(); -if(!defined('PIWIK_ENABLE_DISPATCH')) { +if (!defined('PIWIK_ENABLE_DISPATCH')) { define('PIWIK_ENABLE_DISPATCH', true); } @@ -33,7 +33,7 @@ if (PIWIK_ENABLE_DISPATCH) { $controller->init(); $response = $controller->dispatch(); - if(is_array($response)) { + if (is_array($response)) { var_export($response); } elseif (!is_null($response)) { echo $response; diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php index bce404c9e6..3dd3defd3e 100644 --- a/core/testMinimumPhpVersion.php +++ b/core/testMinimumPhpVersion.php @@ -129,7 +129,7 @@ if (!function_exists('Piwik_ExitWithMessage')) { $message = str_replace("\t", "", $message); $message = strip_tags($message); - if($isCli) { + if ($isCli) { echo $message; } else { echo $headerPage . $content . $footerPage; |