| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Tracker; |
|
|
| use Piwik\Common; |
| use Piwik\Date; |
| use Piwik\Exception\InvalidRequestParameterException; |
| use Piwik\Exception\UnexpectedWebsiteFoundException; |
| use Piwik\Piwik; |
| use Piwik\Site; |
| use Piwik\Db as PiwikDb; |
| use Piwik\Url; |
|
|
| class Failures |
| { |
| public const CLEANUP_OLD_FAILURES_DAYS = 2; |
| public const FAILURE_ID_INVALID_SITE = 1; |
| public const FAILURE_ID_NOT_AUTHENTICATED = 2; |
|
|
| private $table = 'tracking_failure'; |
| private $tablePrefixed; |
| private $now; |
|
|
| public function __construct() |
| { |
| $this->tablePrefixed = Common::prefixTable($this->table); |
| } |
|
|
| public function setNow(Date $now) |
| { |
| $this->now = $now; |
| } |
|
|
| private function getNow() |
| { |
| if (isset($this->now)) { |
| return $this->now; |
| } |
| return Date::now(); |
| } |
|
|
| public function logFailure($idFailure, Request $request) |
| { |
| $isVisitExcluded = $request->getMetadata('CoreHome', 'isVisitExcluded'); |
|
|
| if ($isVisitExcluded === null) { |
| try { |
| $visitExcluded = new VisitExcluded($request); |
| $isVisitExcluded = $visitExcluded->isExcluded(); |
| } catch (InvalidRequestParameterException $e) { |
| |
| |
| $isVisitExcluded = false; |
| } |
| } |
|
|
| if ($isVisitExcluded) { |
| return; |
| } |
|
|
| $idSite = (int) $request->getIdSiteUnverified(); |
| $idFailure = (int) $idFailure; |
|
|
| if ($idSite > 9999999 || $idSite < 0 || $this->hasLoggedFailure($idSite, $idFailure)) { |
| return; |
| } |
|
|
| $params = $this->getParamsWithTokenAnonymized($request); |
| $sql = sprintf('INSERT INTO `%s` (`idsite`, `idfailure`, `date_first_occurred`, `request_url`) VALUES(?,?,?,?) ON DUPLICATE KEY UPDATE idsite=idsite;', $this->tablePrefixed); |
|
|
| PiwikDb::get()->query($sql, array($idSite, $idFailure, $this->getNow()->getDatetime(), http_build_query($params))); |
| } |
|
|
| private function hasLoggedFailure($idSite, $idFailure) |
| { |
| $sql = sprintf('SELECT idsite FROM `%s` WHERE idsite = ? and idfailure = ?', $this->tablePrefixed); |
| $row = PiwikDb::fetchRow($sql, array($idSite, $idFailure)); |
|
|
| return !empty($row); |
| } |
|
|
| private function getParamsWithTokenAnonymized(Request $request) |
| { |
| |
| |
| |
| $token = $request->getTokenAuth(); |
| $params = $request->getRawParams(); |
| foreach (array('token_auth', 'token', 'tokenauth', 'token__auth') as $key) { |
| if (isset($params[$key])) { |
| $params[$key] = '__TOKEN_AUTH__'; |
| } |
| } |
| foreach ($params as $key => $value) { |
| if (!empty($token) && $value === $token) { |
| $params[$key] = '__TOKEN_AUTH__'; |
| } elseif ( |
| !empty($value) && is_string($value) |
| && mb_strlen($value) >= 29 && mb_strlen($value) <= 36 |
| && ctype_xdigit($value) |
| ) { |
| $params[$key] = '__TOKEN_AUTH__'; |
| } |
| } |
|
|
| return $params; |
| } |
|
|
| public function removeFailuresOlderThanDays($days) |
| { |
| $minutesAgo = $this->getNow()->subDay($days)->getDatetime(); |
|
|
| PiwikDb::query(sprintf('DELETE FROM `%s` WHERE date_first_occurred < ?', $this->tablePrefixed), [$minutesAgo]); |
| } |
|
|
| public function getAllFailures() |
| { |
| $failures = PiwikDb::fetchAll(sprintf('SELECT * FROM `%s`', $this->tablePrefixed)); |
| return $this->enrichFailures($failures); |
| } |
|
|
| public function getFailuresForSites($idSites) |
| { |
| if (empty($idSites)) { |
| return array(); |
| } |
| $idSites = array_map('intval', $idSites); |
| $idSites = implode(',', $idSites); |
| $failures = PiwikDb::fetchAll(sprintf('SELECT * FROM `%s` WHERE idsite IN (%s)', $this->tablePrefixed, $idSites)); |
| return $this->enrichFailures($failures); |
| } |
|
|
| public function deleteTrackingFailure($idSite, $idFailure) |
| { |
| PiwikDb::query(sprintf('DELETE FROM `%s` WHERE idsite = ? and idfailure = ?', $this->tablePrefixed), [$idSite, $idFailure]); |
| } |
|
|
| public function deleteTrackingFailures($idSites) |
| { |
| if (!empty($idSites)) { |
| $idSites = array_map('intval', $idSites); |
| $idSites = implode(',', $idSites); |
| PiwikDb::query(sprintf('DELETE FROM `%s` WHERE idsite IN(%s)', $this->tablePrefixed, $idSites)); |
| } |
| } |
|
|
| public function deleteAllTrackingFailures() |
| { |
| PiwikDb::query(sprintf('DELETE FROM `%s`', $this->tablePrefixed)); |
| } |
|
|
| private function enrichFailures($failures) |
| { |
| foreach ($failures as &$failure) { |
| try { |
| $failure['site_name'] = Site::getNameFor($failure['idsite']); |
| } catch (UnexpectedWebsiteFoundException $e) { |
| $failure['site_name'] = Piwik::translate('General_Unknown'); |
| } |
| $failure['pretty_date_first_occurred'] = Date::factory($failure['date_first_occurred'])->getLocalized(Date::DATETIME_FORMAT_SHORT); |
| parse_str($failure['request_url'], $params); |
| if (empty($params['url'])) { |
| $params['url'] = ' '; |
| } |
| $request = new Request($params); |
| $failure['url'] = trim($request->getParam('url')); |
| $failure['problem'] = ''; |
| $failure['solution'] = ''; |
| $failure['solution_url'] = ''; |
|
|
| switch ($failure['idfailure']) { |
| case self::FAILURE_ID_INVALID_SITE: |
| $failure['problem'] = Piwik::translate('CoreAdminHome_TrackingFailureInvalidSiteProblem'); |
| $failure['solution'] = Piwik::translate('CoreAdminHome_TrackingFailureInvalidSiteSolution'); |
| $failure['solution_url'] = Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/how-to/faq_30838/'); |
| break; |
| case self::FAILURE_ID_NOT_AUTHENTICATED: |
| $failure['problem'] = Piwik::translate('CoreAdminHome_TrackingFailureAuthenticationProblem'); |
| $failure['solution'] = Piwik::translate('CoreAdminHome_TrackingFailureAuthenticationSolution'); |
| $failure['solution_url'] = Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/how-to/faq_30835/'); |
| break; |
| } |
| } |
|
|
| |
| |
| |
| |
| Piwik::postEvent('Tracking.makeFailuresHumanReadable', array(&$failures)); |
|
|
| return $failures; |
| } |
| } |
|
|