Newer
Older
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\CoreHome\Tracker;
diosmosis
a validé
use Piwik\Common;
use Piwik\Date;
pboehlke
a validé
use Piwik\Config;
use Piwik\EventDispatcher;
diosmosis
a validé
use Piwik\Exception\UnexpectedWebsiteFoundException;
use Piwik\Tracker\Cache;
use Piwik\Tracker\Request;
use Piwik\Tracker\RequestProcessor;
diosmosis
a validé
use Piwik\Tracker\Settings;
use Piwik\Tracker\Visit\VisitProperties;
use Piwik\Tracker\VisitExcluded;
diosmosis
a validé
use Piwik\Tracker\VisitorRecognizer;
use Piwik\Plugins\PrivacyManager\Config as PrivacyManagerConfig;
/**
* Encapsulates core tracking logic related to visits.
* ## Request Metadata
*
* This RequestProcessor exposes the following metadata for the **CoreHome** plugin:
*
* * **visitorId**: A hash that identifies the current visitor being tracked. This value is
* calculated using the Piwik\Tracker\Settings;:getConfigId() method.
*
* Set in `processRequestParams()`.
*
* * **isVisitorKnown**: True if the current visitor has visited the site before. False if
* otherwise.
*
* Set in `processRequestParams()`.
*
* * **isNewVisit**: True if the current action is the start of a new visit, false if it
* is part of an ongoing visit.
*
* Set in `processRequestParams()`. Other RequestProcessors can override
* this value to force a new visit or stop a new visit.
*
* * **visitorNotFoundInDb**: True if the current visit could not be updated.
*
* Set by the Visit object.
*/
class VisitRequestProcessor extends RequestProcessor
{
// TODO: much of the logic in this class should be moved to new service class
/**
* @var EventDispatcher
*/
private $eventDispatcher;
diosmosis
a validé
/**
* @var VisitorRecognizer
*/
private $visitorRecognizer;
/**
* @var Settings
*/
private $userSettings;
/**
* @var int
*/
private $visitStandardLength;
public function __construct(EventDispatcher $eventDispatcher, VisitorRecognizer $visitorRecognizer, Settings $userSettings,
$visitStandardLength)
{
$this->eventDispatcher = $eventDispatcher;
diosmosis
a validé
$this->visitorRecognizer = $visitorRecognizer;
$this->userSettings = $userSettings;
$this->visitStandardLength = $visitStandardLength;
}
public function processRequestParams(VisitProperties $visitProperties, Request $request)
{
// the IP is needed by isExcluded() and GoalManager->recordGoals()
diosmosis
a validé
$visitProperties->setProperty('location_ip', $request->getIp());
Matthieu Aubry
a validé
$excluded = new VisitExcluded($request);
if ($excluded->isExcluded()) {
return true;
}
$privacyConfig = new PrivacyManagerConfig();
$ip = $request->getIpString();
if ($privacyConfig->useAnonymizedIpForVisitEnrichment) {
$ip = $visitProperties->getProperty('location_ip');
}
diosmosis
a validé
// visitor recognition
$visitorId = $this->userSettings->getConfigId($request, $ip);
$request->setMetadata('CoreHome', 'visitorId', $visitorId);
diosmosis
a validé
$isKnown = $this->visitorRecognizer->findKnownVisitor($visitorId, $visitProperties, $request);
$request->setMetadata('CoreHome', 'isVisitorKnown', $isKnown);
diosmosis
a validé
$isNewVisit = $this->isVisitNew($visitProperties, $request);
$request->setMetadata('CoreHome', 'isNewVisit', $isNewVisit);
diosmosis
a validé
return false;
}
public function afterRequestProcessed(VisitProperties $visitProperties, Request $request)
{
diosmosis
a validé
$ip = $visitProperties->getProperty('location_ip');
/**
* Triggered after visits are tested for exclusion so plugins can modify the IP address
* persisted with a visit.
*
* This event is primarily used by the **PrivacyManager** plugin to anonymize IP addresses.
*
* @param string &$ip The visitor's IP address.
*/
diosmosis
a validé
$this->eventDispatcher->postEvent('Tracker.setVisitorIp', array(&$ip));
$visitProperties->setProperty('location_ip', $ip);
}
diosmosis
a validé
/**
* Determines if the tracker if the current action should be treated as the start of a new visit or
* an action in an existing visit.
*
* Note: public only for tests.
*
diosmosis
a validé
* @param VisitProperties $visitProperties The current visit/visitor information.
* @param Request $request
* @return bool
*/
public function isVisitNew(VisitProperties $visitProperties, Request $request)
diosmosis
a validé
{
$isKnown = $request->getMetadata('CoreHome', 'isVisitorKnown');
diosmosis
a validé
if (!$isKnown) {
return true;
}
$isLastActionInTheSameVisit = $this->isLastActionInTheSameVisit($visitProperties, $request);
if (!$isLastActionInTheSameVisit) {
Common::printDebug("Visitor detected, but last action was more than 30 minutes ago...");
return true;
}
$wasLastActionYesterday = $this->wasLastActionNotToday($visitProperties, $request);
pboehlke
a validé
$forceNewVisitAtMidnight = (bool) Config::getInstance()->Tracker['create_new_visit_after_midnight'];
if ($wasLastActionYesterday && $forceNewVisitAtMidnight) {
diosmosis
a validé
Common::printDebug("Visitor detected, but last action was yesterday...");
return true;
}
return false;
}
/**
* Returns true if the last action was done during the last 30 minutes
* @return bool
*/
protected function isLastActionInTheSameVisit(VisitProperties $visitProperties, Request $request)
{
diosmosis
a validé
$lastActionTime = $visitProperties->getProperty('visit_last_action_time');
diosmosis
a validé
return isset($lastActionTime)
&& false !== $lastActionTime
diosmosis
a validé
&& ($lastActionTime > ($request->getCurrentTimestamp() - $this->visitStandardLength));
diosmosis
a validé
}
/**
* Returns true if the last action was not today.
* @param VisitProperties $visitor
* @return bool
*/
private function wasLastActionNotToday(VisitProperties $visitProperties, Request $request)
{
diosmosis
a validé
$lastActionTime = $visitProperties->getProperty('visit_last_action_time');
diosmosis
a validé
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
if (empty($lastActionTime)) {
return false;
}
$idSite = $request->getIdSite();
$timezone = $this->getTimezoneForSite($idSite);
if (empty($timezone)) {
throw new UnexpectedWebsiteFoundException('An unexpected website was found, check idSite in the request');
}
$date = Date::factory((int)$lastActionTime, $timezone);
$now = $request->getCurrentTimestamp();
$now = Date::factory((int)$now, $timezone);
return $date->toString() !== $now->toString();
}
private function getTimezoneForSite($idSite) // TODO: duplicate function in Visit
{
try {
$site = Cache::getCacheWebsiteAttributes($idSite);
} catch (UnexpectedWebsiteFoundException $e) {
return null;
}
if (!empty($site['timezone'])) {
return $site['timezone'];
}
return null;
}