/** * @param Request $request * @param Visitor $visitor * @param Action|null $action * @return int|bool */ public function onExistingVisit(Request $request, Visitor $visitor, $action) { if (empty($action)) { return false; } return $action->getIdActionNameForEntryAndExitIds(); }
private static function getPriority(Action $actionType) { $key = array_search($actionType->getActionType(), self::$factoryPriority); if (false === $key) { return -1; } return $key; }
/** * @param Request $request * @param Visitor $visitor * @param Action|null $action * @return mixed */ public function onNewVisit(Request $request, Visitor $visitor, $action) { $idActionName = false; if (!empty($action)) { $idActionName = $action->getIdActionNameForEntryAndExitIds(); } return (int) $idActionName; }
/** * Detect whether action is an outlink given host aliases * * @param Action $action * @return bool true if the outlink the visitor clicked on points to one of the known hosts for this website */ protected function detectActionIsOutlinkOnAliasHost(Action $action, $idSite) { $decodedActionUrl = $action->getActionUrl(); $actionUrlParsed = @parse_url($decodedActionUrl); if (!isset($actionUrlParsed['host'])) { return false; } return Visit::isHostKnownAliasHost($actionUrlParsed['host'], $idSite); }
/** * @param Request $request * @param Visitor $visitor * @param Action|null $action * @return mixed */ public function onNewVisit(Request $request, Visitor $visitor, $action) { $idActionUrl = false; if (!empty($action)) { $idActionUrl = $action->getIdActionUrlForEntryAndExitIds(); } if ($idActionUrl === false) { return false; } return (int) $idActionUrl; }
/** * @param Request $request * @param Visitor $visitor * @param Action|null $action * @return int */ public function onExistingVisit(Request $request, Visitor $visitor, $action) { if (empty($action)) { return false; } $id = $action->getIdActionUrlForEntryAndExitIds(); if (!empty($id)) { $id = (int) $id; } return $id; }
/** * Detect whether action is an outlink given host aliases * * @param Action $action * @return bool true if the outlink the visitor clicked on points to one of the known hosts for this website */ public static function detectActionIsOutlinkOnAliasHost(Action $action, $idSite) { if ($action->getActionType() != Action::TYPE_OUTLINK) { return false; } $decodedActionUrl = $action->getActionUrl(); $actionUrlParsed = @parse_url($decodedActionUrl); if (!isset($actionUrlParsed['host'])) { return false; } return Visit::isHostKnownAliasHost($actionUrlParsed['host'], $idSite); }
/** * @param Action|null $action * @return bool */ public static function shouldCountInteraction($action) { if (empty($action)) { return false; } $idActionUrl = $action->getIdActionUrlForEntryAndExitIds(); if ($idActionUrl !== false) { return true; } $actionType = $action->getActionType(); $types = array(Action::TYPE_SITE_SEARCH); if (in_array($actionType, $types)) { return true; } return false; }
/** * @param Request $request * @param Visitor $visitor * @param Action|null $action * @return int */ public function onExistingVisit(Request $request, Visitor $visitor, $action) { if (!$action) { return false; } $increment = 'visit_total_actions + 1'; $idActionUrl = $action->getIdActionUrlForEntryAndExitIds(); if ($idActionUrl !== false) { return $increment; } $actionType = $action->getActionType(); if (in_array($actionType, array(Action::TYPE_SITE_SEARCH, Action::TYPE_EVENT))) { return $increment; } return false; }
public function writeDebugInfo() { $write = parent::writeDebugInfo(); if ($write) { Common::printDebug("Event Value = " . $this->getCustomFloatValue()); } return $write; }
public function writeDebugInfo() { $write = parent::writeDebugInfo(); if ($write) { Common::printDebug("Event Category = " . $this->eventCategory . ",\n Event Action = " . $this->eventAction . ",\n Event Name = " . $this->eventName . ",\n Event Value = " . $this->getCustomFloatValue()); } return $write; }
function __construct($url, Request $request) { parent::__construct(Action::TYPE_PAGE_URL, $request); $this->setActionUrl($url); $actionName = $request->getParam('action_name'); $actionName = $this->cleanupActionName($actionName); $this->setActionName($actionName); $this->timeGeneration = $this->request->getPageGenerationTime(); }
public function processRequestParams(VisitProperties $visitProperties, Request $request) { // normal page view, potentially triggering a URL matching goal $action = Action::factory($request); $action->writeDebugInfo(); $request->setMetadata('Actions', 'action', $action); // save the exit actions of the last action in this visit as the referrer actions for the action being tracked. // when the visit is updated, these columns will be changed, so we have to do this before recordLogs $request->setMetadata('Actions', 'idReferrerActionUrl', $visitProperties->getProperty('visit_exit_idaction_url')); $request->setMetadata('Actions', 'idReferrerActionName', $visitProperties->getProperty('visit_exit_idaction_name')); }
private static function insertNewIdsAction($actionsNameAndType, $fieldNamesToInsert) { // Then, we insert all new actions in the lookup table $inserted = array(); foreach ($fieldNamesToInsert as $fieldName) { list($name, $type, $urlPrefix) = $actionsNameAndType[$fieldName]; $actionId = self::getModel()->createNewIdAction($name, $type, $urlPrefix); Common::printDebug("Recorded a new action (" . Action::getTypeAsString($type) . ") in the lookup table: " . $name . " (idaction = " . $actionId . ")"); $inserted[$fieldName] = $actionId; } return $inserted; }
public function getCustomVariables() { $customVariables = parent::getCustomVariables(); // Enrich Site Search actions with Custom Variables, overwriting existing values if (!empty($this->searchCategory)) { if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY])) { Common::printDebug("WARNING: Overwriting existing Custom Variable in slot " . self::CVAR_INDEX_SEARCH_CATEGORY . " for this page view"); } $customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY] = self::CVAR_KEY_SEARCH_CATEGORY; $customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_CATEGORY] = Request::truncateCustomVariable($this->searchCategory); } if ($this->searchCount !== false) { if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT])) { Common::printDebug("WARNING: Overwriting existing Custom Variable in slot " . self::CVAR_INDEX_SEARCH_COUNT . " for this page view"); } $customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT] = self::CVAR_KEY_SEARCH_COUNT; $customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_COUNT] = (int) $this->searchCount; } return $customVariables; }
/** * Main algorithm to handle the visit. * * Once we have the visitor information, we have to determine if the visit is a new or a known visit. * * 1) When the last action was done more than 30min ago, * or if the visitor is new, then this is a new visit. * * 2) If the last action is less than 30min ago, then the same visit is going on. * Because the visit goes on, we can get the time spent during the last action. * * NB: * - In the case of a new visit, then the time spent * during the last action of the previous visit is unknown. * * - In the case of a new visit but with a known visitor, * we can set the 'returning visitor' flag. * * In all the cases we set a cookie to the visitor with the new information. */ public function handle() { // the IP is needed by isExcluded() and GoalManager->recordGoals() $this->visitorInfo['location_ip'] = $this->request->getIp(); $excluded = new VisitExcluded($this->request, $this->visitorInfo['location_ip']); if ($excluded->isExcluded()) { return; } /** * 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. */ Piwik::postEvent('Tracker.setVisitorIp', array(&$this->visitorInfo['location_ip'])); $this->visitorCustomVariables = $this->request->getCustomVariables($scope = 'visit'); if (!empty($this->visitorCustomVariables)) { Common::printDebug("Visit level Custom Variables: "); Common::printDebug($this->visitorCustomVariables); } $this->goalManager = new GoalManager($this->request); $visitIsConverted = false; $action = null; $isManualGoalConversion = $this->goalManager->isManualGoalConversion(); $requestIsEcommerce = $this->goalManager->requestIsEcommerce; if ($requestIsEcommerce) { $someGoalsConverted = true; // Mark the visit as Converted only if it is an order (not for a Cart update) if ($this->goalManager->isGoalAnOrder()) { $visitIsConverted = true; } } elseif ($isManualGoalConversion) { // this request is from the JS call to piwikTracker.trackGoal() $someGoalsConverted = $this->goalManager->detectGoalId($this->request->getIdSite()); $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; } } 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; $action->loadIdsFromLogActionTable(); } /*** * Visitor recognition */ $visitorId = $this->getSettingsObject()->getConfigId(); $visitor = new Visitor($this->request, $visitorId, $this->visitorInfo, $this->visitorCustomVariables); $visitor->recognize(); $this->visitorInfo = $visitor->getVisitorInfo(); $isLastActionInTheSameVisit = $this->isLastActionInTheSameVisit($visitor); 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 // - the visitor doesn't have the Piwik cookie but could be match using heuristics @see recognizeTheVisitor() // ) // AND // - the last page view for this visitor was less than 30 minutes ago @see isLastActionInTheSameVisit() if ($visitor->isVisitorKnown() && $isLastActionInTheSameVisit) { $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: // - two manual goal conversions happen in the same second // - which result in handleExistingVisit throwing the exception // 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 ($isManualGoalConversion || $requestIsEcommerce) { $someGoalsConverted = $visitIsConverted = false; } else { $visitor->setIsVisitorKnown(false); } } } // New visit when: // - the visitor has the Piwik cookie but the last action was performed more than 30 min ago @see isLastActionInTheSameVisit() // - the visitor doesn't have the Piwik cookie, and couldn't be matched in @see recognizeTheVisitor() // - the visitor does have the Piwik cookie but the idcookie and idvisit found in the cookie didn't match to any existing visit in the DB if (!$visitor->isVisitorKnown() || !$isLastActionInTheSameVisit) { $this->handleNewVisit($visitor, $action, $visitIsConverted); if (!is_null($action)) { $action->record($visitor, 0, 0); } } // update the cookie with the new visit information $this->request->setThirdPartyCookie($this->visitorInfo['idvisitor']); // record the goals if applicable if ($someGoalsConverted) { $this->goalManager->recordGoals($visitor, $this->visitorInfo, $this->visitorCustomVariables, $action); } unset($this->goalManager); unset($action); }
public function __construct(Request $request) { parent::__construct(self::TYPE_DOWNLOAD, $request); $this->setActionUrlWithoutExcludingParameters($request->getParam('download')); }
public function __construct(Request $request) { parent::__construct(Action::TYPE_CONTENT, $request); $url = $request->getParam('url'); $this->setActionUrl($url); }
/** * Look at the URL or Page Title and sees if it matches any existing Goal definition * * @param int $idSite * @param Action $action * @throws Exception * @return int Number of goals matched */ function detectGoalsMatchingUrl($idSite, $action) { if (!Common::isGoalPluginEnabled()) { return false; } $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') { continue; } $url = $decodedActionUrl; // Matching on Page Title if ($attribute == 'title') { $url = $action->getActionName(); } $pattern_type = $goal['pattern_type']; $match = $this->isUrlMatchingGoal($goal, $pattern_type, $url); if ($match) { $goal['url'] = $decodedActionUrl; $this->convertedGoals[] = $goal; } } return count($this->convertedGoals) > 0; }
/** * Look at the URL or Page Title and sees if it matches any existing Goal definition * * @param int $idSite * @param Action $action * @throws Exception * @return int Number of goals matched */ function detectGoalsMatchingUrl($idSite, $action) { if (!Common::isGoalPluginEnabled()) { return false; } $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 ($actionType == Action::TYPE_PAGE_URL && $attribute != 'url' && $attribute != 'title' || $actionType == Action::TYPE_DOWNLOAD && $attribute != 'file' || $actionType == Action::TYPE_OUTLINK && $attribute != 'external_website' || $attribute == 'manually') { continue; } $url = $decodedActionUrl; // Matching on Page Title if ($attribute == 'title') { $url = $action->getActionName(); } $pattern_type = $goal['pattern_type']; switch ($pattern_type) { case 'regex': $pattern = $goal['pattern']; if (strpos($pattern, '/') !== false && strpos($pattern, '\\/') === false) { $pattern = str_replace('/', '\\/', $pattern); } $pattern = '/' . $pattern . '/'; if (!$goal['case_sensitive']) { $pattern .= 'i'; } $match = @preg_match($pattern, $url) == 1; break; case 'contains': if ($goal['case_sensitive']) { $matched = strpos($url, $goal['pattern']); } else { $matched = stripos($url, $goal['pattern']); } $match = $matched !== false; break; case 'exact': if ($goal['case_sensitive']) { $matched = strcmp($goal['pattern'], $url); } else { $matched = strcasecmp($goal['pattern'], $url); } $match = $matched == 0; break; default: throw new Exception(Piwik::translate('General_ExceptionInvalidGoalPattern', array($pattern_type))); break; } if ($match) { $goal['url'] = $decodedActionUrl; $this->convertedGoals[] = $goal; } } return count($this->convertedGoals) > 0; }
/** * Look at the URL or Page Title and sees if it matches any existing Goal definition * * @param int $idSite * @param Action $action * @throws Exception * @return int Number of goals matched */ public function detectGoalsMatchingUrl($idSite, $action) { if (!Common::isGoalPluginEnabled()) { return false; } $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) { continue; } switch ($attribute) { case 'title': // Matching on Page Title $url = $action->getActionName(); break; case 'event_action': $url = $action->getEventAction(); break; case 'event_name': $url = $action->getEventName(); break; case 'event_category': $url = $action->getEventCategory(); break; // url, external_website, file, manually... // url, external_website, file, manually... default: $url = $action->getActionUrlRaw(); break; } $pattern_type = $goal['pattern_type']; $match = $this->isUrlMatchingGoal($goal, $pattern_type, $url); if ($match) { $goal['url'] = $action->getActionUrl(); $this->convertedGoals[] = $goal; } } return count($this->convertedGoals) > 0; }
/** * @param Action|null $action * @return bool */ private function isEventAction($action) { return $action && $action->getActionType() == Action::TYPE_EVENT; }
private static function insertNewIdsAction($actionsNameAndType, $fieldNamesToInsert) { $sql = "INSERT INTO " . Common::prefixTable('log_action') . "( 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]; Tracker::getDatabase()->query($sql, array($name, $name, $type, $urlPrefix)); $actionId = Tracker::getDatabase()->lastInsertId(); $inserted[$fieldName] = $actionId; Common::printDebug("Recorded a new action (" . Action::getTypeAsString($type) . ") in the lookup table: " . $name . " (idaction = " . $actionId . ")"); } return $inserted; }
/** * @param Action|null $action * @return bool */ private function isSiteSearchAction($action) { return $action && $action->getActionType() == Action::TYPE_SITE_SEARCH; }
/** * Detects if an Action matches a given goal. If it does, the URL that triggered the goal * is returned. Otherwise null is returned. * * @param array $goal * @param Action $action * @return string|null */ public function detectGoalMatch($goal, Action $action) { $actionType = $action->getActionType(); $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) { return null; } switch ($attribute) { case 'title': // Matching on Page Title $url = $action->getActionName(); break; case 'event_action': $url = $action->getEventAction(); break; case 'event_name': $url = $action->getEventName(); break; case 'event_category': $url = $action->getEventCategory(); break; // url, external_website, file, manually... // url, external_website, file, manually... default: $url = $action->getActionUrlRaw(); break; } $pattern_type = $goal['pattern_type']; $match = $this->isUrlMatchingGoal($goal, $pattern_type, $url); if (!$match) { return null; } return $action->getActionUrl(); }
/** * @dataProvider getExtractUrlData * @group Core */ public function testExtractUrlAndActionNameFromRequest($request, $expected) { PluginManager::getInstance()->loadPlugins(array('Actions', 'SitesManager')); $this->setUpRootAccess(); $idSite = API::getInstance()->addSite("site1", array('http://example.org')); $request['idsite'] = $idSite; $request = new Request($request); $action = Action::factory($request); $processed = array('name' => $action->getActionName(), 'url' => $action->getActionUrl(), 'type' => $action->getActionType()); $this->assertEquals($processed, $expected); }