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

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Lahaye <86919@supinfo.com>2014-05-27 18:58:37 +0400
committerVincent Lahaye <86919@supinfo.com>2014-05-27 22:33:28 +0400
commit67139d3e3b32ffa38b0d82fed311648a83f01ed1 (patch)
tree28c9a2a0dc412d6b81661868589c1d757afeacc1 /core/Tracker/Visitor.php
parent78c87d836a03389c059150abb17ccd4098016921 (diff)
Refactor visitor recognition in his own class, so that a third party plugin could reuse it.
Diffstat (limited to 'core/Tracker/Visitor.php')
-rw-r--r--core/Tracker/Visitor.php198
1 files changed, 198 insertions, 0 deletions
diff --git a/core/Tracker/Visitor.php b/core/Tracker/Visitor.php
new file mode 100644
index 0000000000..eedaa06d90
--- /dev/null
+++ b/core/Tracker/Visitor.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Tracker;
+
+use Piwik\Common;
+use Piwik\Config;
+use Piwik\Plugins\CustomVariables\CustomVariables;
+use Piwik\Tracker;
+
+class Visitor
+{
+ function __construct(Request $request, $visitorInfo = array(), $customVariables = null)
+ {
+ $this->request = $request;
+ $this->visitorInfo = $visitorInfo;
+ $this->customVariables = $customVariables;
+
+ $settings = new Tracker\Settings($request);
+ $this->userInfo = $settings->getInfo();
+ }
+
+ /**
+ * This methods tries to see if the visitor has visited the website before.
+ *
+ * We have to split the visitor into one of the category
+ * - Known visitor
+ * - New visitor
+ */
+ function recognize()
+ {
+ $configId = $this->userInfo['config_id'];
+
+ $idVisitor = $this->request->getVisitorId();
+ $isVisitorIdToLookup = !empty($idVisitor);
+
+ if ($isVisitorIdToLookup) {
+ $this->visitorInfo['idvisitor'] = $idVisitor;
+ Common::printDebug("Matching visitors with: visitorId=" . bin2hex($this->visitorInfo['idvisitor']) . " OR configId=" . bin2hex($configId));
+ } else {
+ Common::printDebug("Visitor doesn't have the piwik cookie...");
+ }
+
+ $selectCustomVariables = '';
+ // No custom var were found in the request, so let's copy the previous one in a potential conversion later
+ if (!$this->customVariables) {
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+
+ for ($index = 1; $index <= $maxCustomVariables; $index++) {
+ $selectCustomVariables .= ', custom_var_k' . $index . ', custom_var_v' . $index;
+ }
+ }
+
+ $persistedVisitAttributes = Visit::getVisitFieldsPersist();
+
+ $selectFields = implode(", ", $persistedVisitAttributes);
+
+ $select = "SELECT
+ visit_last_action_time,
+ visit_first_action_time,
+ $selectFields
+ $selectCustomVariables
+ ";
+ $from = "FROM " . Common::prefixTable('log_visit');
+
+ list($timeLookBack, $timeLookAhead) = Visit::getWindowLookupThisVisit($this->request);
+
+ $shouldMatchOneFieldOnly = Visit::shouldLookupOneVisitorFieldOnly($this->request, $isVisitorIdToLookup);
+
+ // Two use cases:
+ // 1) there is no visitor ID so we try to match only on config_id (heuristics)
+ // Possible causes of no visitor ID: no browser cookie support, direct Tracking API request without visitor ID passed,
+ // importing server access logs with import_logs.py, etc.
+ // In this case we use config_id heuristics to try find the visitor in tahhhe past. There is a risk to assign
+ // this page view to the wrong visitor, but this is better than creating artificial visits.
+ // 2) there is a visitor ID and we trust it (config setting trust_visitors_cookies, OR it was set using &cid= in tracking API),
+ // and in these cases, we force to look up this visitor id
+ $whereCommon = "visit_last_action_time >= ? AND visit_last_action_time <= ? AND idsite = ?";
+ $bindSql = array(
+ $timeLookBack,
+ $timeLookAhead,
+ $this->request->getIdSite()
+ );
+
+ if ($shouldMatchOneFieldOnly) {
+ if ($isVisitorIdToLookup) {
+ $whereCommon .= ' AND idvisitor = ?';
+ $bindSql[] = $this->visitorInfo['idvisitor'];
+ } else {
+ $whereCommon .= ' AND config_id = ?';
+ $bindSql[] = $configId;
+ }
+
+ $sql = "$select
+ $from
+ WHERE " . $whereCommon . "
+ ORDER BY visit_last_action_time DESC
+ LIMIT 1";
+ } // We have a config_id AND a visitor_id. We match on either of these.
+ // Why do we also match on config_id?
+ // we do not trust the visitor ID only. Indeed, some browsers, or browser addons,
+ // cause the visitor id from the 1st party cookie to be different on each page view!
+ // It is not acceptable to create a new visit every time such browser does a page view,
+ // so we also backup by searching for matching config_id.
+ // We use a UNION here so that each sql query uses its own INDEX
+ else {
+ // will use INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time)
+ $where = ' AND config_id = ?';
+ $bindSql[] = $configId;
+ $sqlConfigId = "$select ,
+ 0 as priority
+ $from
+ WHERE $whereCommon $where
+ ORDER BY visit_last_action_time DESC
+ LIMIT 1
+ ";
+ // will use INDEX index_idsite_idvisitor (idsite, idvisitor)
+ $bindSql[] = $timeLookBack;
+ $bindSql[] = $timeLookAhead;
+ $bindSql[] = $this->request->getIdSite();
+ $where = ' AND idvisitor = ?';
+ $bindSql[] = $this->visitorInfo['idvisitor'];
+ $sqlVisitorId = "$select ,
+ 1 as priority
+ $from
+ WHERE $whereCommon $where
+ ORDER BY visit_last_action_time DESC
+ LIMIT 1
+ ";
+
+ // We join both queries and favor the one matching the visitor_id if it did match
+ $sql = " ( $sqlConfigId )
+ UNION
+ ( $sqlVisitorId )
+ ORDER BY priority DESC
+ LIMIT 1";
+ }
+
+ $visitRow = Tracker::getDatabase()->fetch($sql, $bindSql);
+
+ $isNewVisitForced = $this->request->getParam('new_visit');
+ $isNewVisitForced = !empty($isNewVisitForced);
+ $newVisitEnforcedAPI = $isNewVisitForced
+ && ($this->request->isAuthenticated()
+ || !Config::getInstance()->Tracker['new_visit_api_requires_admin']);
+ $enforceNewVisit = $newVisitEnforcedAPI || Config::getInstance()->Debug['tracker_always_new_visitor'];
+
+ if (!$enforceNewVisit
+ && $visitRow
+ && count($visitRow) > 0
+ ) {
+ // These values will be used throughout the request
+ $this->visitorInfo['visit_last_action_time'] = strtotime($visitRow['visit_last_action_time']);
+ $this->visitorInfo['visit_first_action_time'] = strtotime($visitRow['visit_first_action_time']);
+
+ foreach($persistedVisitAttributes as $field) {
+ $this->visitorInfo[$field] = $visitRow[$field];
+ }
+
+ // Custom Variables copied from Visit in potential later conversion
+ if (!empty($selectCustomVariables)) {
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
+ if (isset($visitRow['custom_var_k' . $i])
+ && strlen($visitRow['custom_var_k' . $i])
+ ) {
+ $this->visitorInfo['custom_var_k' . $i] = $visitRow['custom_var_k' . $i];
+ }
+ if (isset($visitRow['custom_var_v' . $i])
+ && strlen($visitRow['custom_var_v' . $i])
+ ) {
+ $this->visitorInfo['custom_var_v' . $i] = $visitRow['custom_var_v' . $i];
+ }
+ }
+ }
+
+ Common::printDebug("The visitor is known (idvisitor = " . bin2hex($this->visitorInfo['idvisitor']) . ",
+ config_id = " . bin2hex($configId) . ",
+ idvisit = {$this->visitorInfo['idvisit']},
+ last action = " . date("r", $this->visitorInfo['visit_last_action_time']) . ",
+ first action = " . date("r", $this->visitorInfo['visit_first_action_time']) . ",
+ visit_goal_buyer' = " . $this->visitorInfo['visit_goal_buyer'] . ")");
+ //Common::printDebug($this->visitorInfo);
+ } else {
+ Common::printDebug("The visitor was not matched with an existing visitor...");
+ }
+ }
+
+ function getVisitorInfo()
+ {
+ return $this->visitorInfo;
+ }
+} \ No newline at end of file