Inheritance: extends Piwik\Plugin
 public function testGetMaxCustomVariables_ShouldReadFromCacheIfPossible()
 {
     $cache = Cache::getCacheGeneral();
     $cache['CustomVariables.MaxNumCustomVariables'] = 10;
     Cache::setCacheGeneral($cache);
     $this->assertSame(10, CustomVariables::getMaxCustomVariables());
 }
Beispiel #2
0
 protected function configureSegmentsFor($segmentNameSuffix)
 {
     $numCustomVariables = CustomVariables::getNumUsableCustomVariables();
     $segment = new Segment();
     $segment->setType('dimension');
     $segment->setSegment('customVariable' . $segmentNameSuffix);
     $segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopeVisit') . ')');
     $segment->setUnionOfSegments($this->getSegmentColumns('customVariable' . $segmentNameSuffix, $numCustomVariables));
     $this->addSegment($segment);
     $segment = new Segment();
     $segment->setType('dimension');
     $segment->setSegment('customVariablePage' . $segmentNameSuffix);
     $segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopePage') . ')');
     $segment->setUnionOfSegments($this->getSegmentColumns('customVariablePage' . $segmentNameSuffix, $numCustomVariables));
     $this->addSegment($segment);
     $segmentSuffix = 'v';
     if (strtolower($segmentNameSuffix) === 'name') {
         $segmentSuffix = 'k';
     }
     for ($i = 1; $i <= $numCustomVariables; $i++) {
         $segment = new Segment();
         $segment->setSegment('customVariable' . $segmentNameSuffix . $i);
         $segment->setSqlSegment('log_visit.custom_var_' . $segmentSuffix . $i);
         $segment->setName(Piwik::translate('CustomVariables_ColumnCustomVariable' . $segmentNameSuffix) . ' ' . $i . ' (' . Piwik::translate('CustomVariables_ScopeVisit') . ')');
         $this->addSegment($segment);
         $segment = new Segment();
         $segment->setSegment('customVariablePage' . $segmentNameSuffix . $i);
         $segment->setSqlSegment('log_link_visit_action.custom_var_' . $segmentSuffix . $i);
         $segment->setName(Piwik::translate('CustomVariables_ColumnCustomVariable' . $segmentNameSuffix) . ' ' . $i . ' (' . Piwik::translate('CustomVariables_ScopePage') . ')');
         $this->addSegment($segment);
     }
 }
 public function test_getNumUsableCustomVariables_ShouldReturnMinVariables_IfOneTableHasLessEntriesThanOthers()
 {
     $this->assertEquals(5, CustomVariables::getNumUsableCustomVariables());
     $scopes = Model::getScopes();
     // removing custom vars step by step... as soon as one custom var is removed,
     // it should return the min count of available variables
     for ($i = 4; $i != -1; $i--) {
         foreach ($scopes as $scope) {
             $this->dropCustomVar($scope);
             $this->assertSame($i, CustomVariables::getNumUsableCustomVariables());
         }
     }
     $this->assertEquals(0, CustomVariables::getNumUsableCustomVariables());
     // add custom var, only once all custom vars are written it should write return a higher custom var number
     for ($i = 1; $i != 7; $i++) {
         foreach ($scopes as $index => $scope) {
             $isLastIndex = $index === count($scopes) - 1;
             $this->addCustomVar($scope);
             if ($isLastIndex) {
                 $this->assertSame($i, CustomVariables::getNumUsableCustomVariables());
                 // all scopes have been added, it should consider all custom var counts
             } else {
                 $this->assertSame($i - 1, CustomVariables::getNumUsableCustomVariables());
                 // at least one scope is not added and should therefore return the old custom var count until all
                 // tables have been updated
             }
         }
     }
     $this->assertEquals(6, CustomVariables::getNumUsableCustomVariables());
 }
Beispiel #4
0
 /**
  * @param $idVisit
  * @param $actionsLimit
  * @return array
  * @throws \Exception
  */
 public function queryActionsForVisit($idVisit, $actionsLimit)
 {
     $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
     $sqlCustomVariables = '';
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         $sqlCustomVariables .= ', custom_var_k' . $i . ', custom_var_v' . $i;
     }
     // The second join is a LEFT join to allow returning records that don't have a matching page title
     // eg. Downloads, Outlinks. For these, idaction_name is set to 0
     $sql = "\n\t\t\t\tSELECT\n\t\t\t\t\tCOALESCE(log_action_event_category.type, log_action.type, log_action_title.type) AS type,\n\t\t\t\t\tlog_action.name AS url,\n\t\t\t\t\tlog_action.url_prefix,\n\t\t\t\t\tlog_action_title.name AS pageTitle,\n\t\t\t\t\tlog_action.idaction AS pageIdAction,\n\t\t\t\t\tlog_link_visit_action.idlink_va,\n\t\t\t\t\tlog_link_visit_action.server_time as serverTimePretty,\n\t\t\t\t\tlog_link_visit_action.time_spent_ref_action as timeSpentRef,\n\t\t\t\t\tlog_link_visit_action.idlink_va AS pageId,\n\t\t\t\t\tlog_link_visit_action.custom_float,\n\t\t\t\t\tlog_link_visit_action.interaction_position\n\t\t\t\t\t" . $sqlCustomVariables . ",\n\t\t\t\t\tlog_action_event_category.name AS eventCategory,\n\t\t\t\t\tlog_action_event_action.name as eventAction\n\t\t\t\tFROM " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action\n\t\t\t\t\tON  log_link_visit_action.idaction_url = log_action.idaction\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_title\n\t\t\t\t\tON  log_link_visit_action.idaction_name = log_action_title.idaction\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_event_category\n\t\t\t\t\tON  log_link_visit_action.idaction_event_category = log_action_event_category.idaction\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_event_action\n\t\t\t\t\tON  log_link_visit_action.idaction_event_action = log_action_event_action.idaction\n\t\t\t\tWHERE log_link_visit_action.idvisit = ?\n\t\t\t\tORDER BY server_time ASC\n\t\t\t\tLIMIT 0, {$actionsLimit}\n\t\t\t\t ";
     $actionDetails = Db::fetchAll($sql, array($idVisit));
     return $actionDetails;
 }
Beispiel #5
0
 public function aggregateDayReport()
 {
     $this->dataArray = new DataArray();
     $maxCustomVariables = CustomVariables::getMaxCustomVariables();
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         $this->aggregateCustomVariable($i);
     }
     $this->removeVisitsMetricsFromActionsAggregate();
     $this->dataArray->enrichMetricsWithConversions();
     $table = $this->dataArray->asDataTable();
     $blob = $table->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $columnToSort = Metrics::INDEX_NB_VISITS);
     $this->getProcessor()->insertBlobRecord(self::CUSTOM_VARIABLE_RECORD_NAME, $blob);
 }
Beispiel #6
0
 /**
  * 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
  */
 public function recognize()
 {
     $this->setIsVisitorKnown(false);
     $configId = $this->configId;
     $idSite = $this->request->getIdSite();
     $idVisitor = $this->request->getVisitorId();
     $isVisitorIdToLookup = !empty($idVisitor);
     if ($isVisitorIdToLookup) {
         $this->visitorInfo['idvisitor'] = $idVisitor;
         Common::printDebug("Matching visitors with: visitorId=" . bin2hex($idVisitor) . " OR configId=" . bin2hex($configId));
     } else {
         Common::printDebug("Visitor doesn't have the piwik cookie...");
     }
     $numCustomVarsToRead = 0;
     if (!$this->customVariables) {
         // No custom var were found in the request, so let's copy the previous one in a potential conversion later
         $numCustomVarsToRead = CustomVariables::getMaxCustomVariables();
     }
     $persistedVisitAttributes = $this->getVisitFieldsPersist();
     $shouldMatchOneFieldOnly = $this->shouldLookupOneVisitorFieldOnly($isVisitorIdToLookup);
     list($timeLookBack, $timeLookAhead) = $this->getWindowLookupThisVisit();
     $model = $this->getModel();
     $visitRow = $model->findVisitor($idSite, $configId, $idVisitor, $persistedVisitAttributes, $numCustomVarsToRead, $shouldMatchOneFieldOnly, $isVisitorIdToLookup, $timeLookBack, $timeLookAhead);
     $isNewVisitForced = $this->request->getParam('new_visit');
     $isNewVisitForced = !empty($isNewVisitForced);
     $enforceNewVisit = $isNewVisitForced || Config::getInstance()->Debug['tracker_always_new_visitor'];
     if (!$enforceNewVisit && $visitRow && count($visitRow) > 0) {
         // These values will be used throughout the request
         foreach ($persistedVisitAttributes as $field) {
             $this->visitorInfo[$field] = $visitRow[$field];
         }
         $this->visitorInfo['visit_last_action_time'] = strtotime($visitRow['visit_last_action_time']);
         $this->visitorInfo['visit_first_action_time'] = strtotime($visitRow['visit_first_action_time']);
         // Custom Variables copied from Visit in potential later conversion
         if (!empty($numCustomVarsToRead)) {
             for ($i = 1; $i <= $numCustomVarsToRead; $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];
                 }
             }
         }
         $this->setIsVisitorKnown(true);
         Common::printDebug("The visitor is known (idvisitor = " . bin2hex($this->visitorInfo['idvisitor']) . ",\n                    config_id = " . bin2hex($configId) . ",\n                    idvisit = {$this->visitorInfo['idvisit']},\n                    last action = " . date("r", $this->visitorInfo['visit_last_action_time']) . ",\n                    first action = " . date("r", $this->visitorInfo['visit_first_action_time']) . ",\n                    visit_goal_buyer' = " . $this->visitorInfo['visit_goal_buyer'] . ")");
     } else {
         Common::printDebug("The visitor was not matched with an existing visitor...");
     }
 }
Beispiel #7
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $maxVars = CustomVariables::getMaxCustomVariables();
     if ($this->hasEverywhereSameAmountOfVariables()) {
         $this->writeSuccessMessage($output, array('Your Piwik is configured for ' . $maxVars . ' custom variables.'));
         return;
     }
     $output->writeln('<error>There is a problem with your custom variables configuration:</error>');
     $output->writeln('<error>Some database tables miss custom variables columns.</error>');
     $output->writeln('');
     $output->writeln('Your Piwik seems to be configured for ' . $maxVars . ' custom variables.');
     $output->writeln('Executing "<comment>./console customvariables:set-max-custom-variables ' . $maxVars . '</comment>" might fix this issue.');
     $output->writeln('If not check the following tables whether they have the same columns starting with <comment>custom_var_</comment>: ');
     foreach (Model::getScopes() as $scope) {
         $output->writeln(Common::prefixTable($scope));
     }
 }
Beispiel #8
0
 protected function configureSegmentsFor($segmentNameSuffix)
 {
     $numCustomVariables = CustomVariables::getNumUsableCustomVariables();
     $segment = new Segment();
     $segment->setType('dimension');
     $segment->setSegment('customVariable' . $segmentNameSuffix);
     $segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopeVisit') . ')');
     $segment->setCategory('CustomVariables_CustomVariables');
     $segment->setUnionOfSegments($this->getSegmentColumns('customVariable' . $segmentNameSuffix, $numCustomVariables));
     $this->addSegment($segment);
     $segment = new Segment();
     $segment->setType('dimension');
     $segment->setSegment('customVariablePage' . $segmentNameSuffix);
     $segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopePage') . ')');
     $segment->setCategory('CustomVariables_CustomVariables');
     $segment->setUnionOfSegments($this->getSegmentColumns('customVariablePage' . $segmentNameSuffix, $numCustomVariables));
     $this->addSegment($segment);
 }
Beispiel #9
0
 public function aggregateDayReport()
 {
     $this->dataArray = new DataArray();
     $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         $this->aggregateCustomVariable($i);
     }
     $this->removeVisitsMetricsFromActionsAggregate();
     $this->dataArray->enrichMetricsWithConversions();
     $table = $this->dataArray->asDataTable();
     foreach ($table->getRows() as $row) {
         $label = $row->getColumn('label');
         if (!empty($this->metadata[$label])) {
             foreach ($this->metadata[$label] as $name => $value) {
                 $row->addMetadata($name, $value);
             }
         }
     }
     $blob = $table->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $columnToSort = Metrics::INDEX_NB_VISITS);
     $this->getProcessor()->insertBlobRecord(self::CUSTOM_VARIABLE_RECORD_NAME, $blob);
 }
Beispiel #10
0
 protected function configureSegmentsFor($fieldPrefix, $segmentNameSuffix)
 {
     $numCustomVariables = CustomVariables::getNumUsableCustomVariables();
     $segment = new Segment();
     $segment->setType('dimension');
     $segment->setSegment('customVariable' . $segmentNameSuffix);
     $segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopeVisit') . ')');
     $segment->setCategory('CustomVariables_CustomVariables');
     $segment->setSqlSegment($this->getSegmentColumns('log_visit.' . $fieldPrefix, $numCustomVariables));
     $segment->setSuggestedValuesCallback(function ($idSite, $ignore, DataTable $table) use($segmentNameSuffix) {
         return $table->getColumnsStartingWith('customVariable' . $segmentNameSuffix);
     });
     $this->addSegment($segment);
     $segment = new Segment();
     $segment->setType('dimension');
     $segment->setSegment('customVariablePage' . $segmentNameSuffix);
     $segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopePage') . ')');
     $segment->setCategory('CustomVariables_CustomVariables');
     $segment->setSqlSegment($this->getSegmentColumns('log_link_visit_action.' . $fieldPrefix, $numCustomVariables));
     $segment->setSuggestedValuesCallback(function ($idSite, $ignore, DataTable $table) use($segmentNameSuffix) {
         return $table->getColumnsStartingWith('customVariablePage' . $segmentNameSuffix);
     });
     $this->addSegment($segment);
 }
Beispiel #11
0
 public function test_getCustomVariablesInPageScope_ShouldTruncateValuesIfTheyAreTooLong()
 {
     $maxLen = CustomVariables::getMaxLengthCustomVariables();
     $customVars = $this->buildCustomVars(array('mykey' => 'myval', 'test' => str_pad('test', $maxLen + 5, 't')));
     $expected = $this->buildExpectedCustomVars(array('mykey' => 'myval', 'test' => str_pad('test', $maxLen, 't')));
     $this->assertCustomVariablesInPageScope($expected, $customVars);
 }
Beispiel #12
0
 /**
  * @param $visitorDetailsArray
  * @param $actionsLimit
  * @param $timezone
  * @return array
  */
 public static function enrichVisitorArrayWithActions($visitorDetailsArray, $actionsLimit, $timezone)
 {
     $idVisit = $visitorDetailsArray['idVisit'];
     $maxCustomVariables = CustomVariables::getMaxCustomVariables();
     $sqlCustomVariables = '';
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         $sqlCustomVariables .= ', custom_var_k' . $i . ', custom_var_v' . $i;
     }
     // The second join is a LEFT join to allow returning records that don't have a matching page title
     // eg. Downloads, Outlinks. For these, idaction_name is set to 0
     $sql = "\n\t\t\t\tSELECT\n\t\t\t\t\tCOALESCE(log_action_event_category.type, log_action.type, log_action_title.type) AS type,\n\t\t\t\t\tlog_action.name AS url,\n\t\t\t\t\tlog_action.url_prefix,\n\t\t\t\t\tlog_action_title.name AS pageTitle,\n\t\t\t\t\tlog_action.idaction AS pageIdAction,\n\t\t\t\t\tlog_link_visit_action.server_time as serverTimePretty,\n\t\t\t\t\tlog_link_visit_action.time_spent_ref_action as timeSpentRef,\n\t\t\t\t\tlog_link_visit_action.idlink_va AS pageId,\n\t\t\t\t\tlog_link_visit_action.custom_float\n\t\t\t\t\t" . $sqlCustomVariables . ",\n\t\t\t\t\tlog_action_event_category.name AS eventCategory,\n\t\t\t\t\tlog_action_event_action.name as eventAction\n\t\t\t\tFROM " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action\n\t\t\t\t\tON  log_link_visit_action.idaction_url = log_action.idaction\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_title\n\t\t\t\t\tON  log_link_visit_action.idaction_name = log_action_title.idaction\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_event_category\n\t\t\t\t\tON  log_link_visit_action.idaction_event_category = log_action_event_category.idaction\n\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_event_action\n\t\t\t\t\tON  log_link_visit_action.idaction_event_action = log_action_event_action.idaction\n\t\t\t\tWHERE log_link_visit_action.idvisit = ?\n\t\t\t\tORDER BY server_time ASC\n\t\t\t\tLIMIT 0, {$actionsLimit}\n\t\t\t\t ";
     $actionDetails = Db::fetchAll($sql, array($idVisit));
     foreach ($actionDetails as $actionIdx => &$actionDetail) {
         $actionDetail =& $actionDetails[$actionIdx];
         $customVariablesPage = array();
         for ($i = 1; $i <= $maxCustomVariables; $i++) {
             if (!empty($actionDetail['custom_var_k' . $i])) {
                 $cvarKey = $actionDetail['custom_var_k' . $i];
                 $cvarKey = static::getCustomVariablePrettyKey($cvarKey);
                 $customVariablesPage[$i] = array('customVariablePageName' . $i => $cvarKey, 'customVariablePageValue' . $i => $actionDetail['custom_var_v' . $i]);
             }
             unset($actionDetail['custom_var_k' . $i]);
             unset($actionDetail['custom_var_v' . $i]);
         }
         if (!empty($customVariablesPage)) {
             $actionDetail['customVariables'] = $customVariablesPage;
         }
         if ($actionDetail['type'] == Action::TYPE_CONTENT) {
             unset($actionDetails[$actionIdx]);
             continue;
         } elseif ($actionDetail['type'] == Action::TYPE_EVENT_CATEGORY) {
             // Handle Event
             if (strlen($actionDetail['pageTitle']) > 0) {
                 $actionDetail['eventName'] = $actionDetail['pageTitle'];
             }
             unset($actionDetail['pageTitle']);
         } else {
             if ($actionDetail['type'] == Action::TYPE_SITE_SEARCH) {
                 // Handle Site Search
                 $actionDetail['siteSearchKeyword'] = $actionDetail['pageTitle'];
                 unset($actionDetail['pageTitle']);
             }
         }
         // Event value / Generation time
         if ($actionDetail['type'] == Action::TYPE_EVENT_CATEGORY) {
             if (strlen($actionDetail['custom_float']) > 0) {
                 $actionDetail['eventValue'] = round($actionDetail['custom_float'], self::EVENT_VALUE_PRECISION);
             }
         } elseif ($actionDetail['custom_float'] > 0) {
             $actionDetail['generationTime'] = \Piwik\MetricsFormatter::getPrettyTimeFromSeconds($actionDetail['custom_float'] / 1000);
         }
         unset($actionDetail['custom_float']);
         if ($actionDetail['type'] != Action::TYPE_EVENT_CATEGORY) {
             unset($actionDetail['eventCategory']);
             unset($actionDetail['eventAction']);
         }
         // Reconstruct url from prefix
         $actionDetail['url'] = Tracker\PageUrl::reconstructNormalizedUrl($actionDetail['url'], $actionDetail['url_prefix']);
         unset($actionDetail['url_prefix']);
         // Set the time spent for this action (which is the timeSpentRef of the next action)
         if (isset($actionDetails[$actionIdx + 1])) {
             $actionDetail['timeSpent'] = $actionDetails[$actionIdx + 1]['timeSpentRef'];
             $actionDetail['timeSpentPretty'] = \Piwik\MetricsFormatter::getPrettyTimeFromSeconds($actionDetail['timeSpent']);
         }
         unset($actionDetails[$actionIdx]['timeSpentRef']);
         // not needed after timeSpent is added
     }
     // If the visitor converted a goal, we shall select all Goals
     $sql = "\n\t\t\t\tSELECT\n\t\t\t\t\t\t'goal' as type,\n\t\t\t\t\t\tgoal.name as goalName,\n\t\t\t\t\t\tgoal.idgoal as goalId,\n\t\t\t\t\t\tgoal.revenue as revenue,\n\t\t\t\t\t\tlog_conversion.idlink_va as goalPageId,\n\t\t\t\t\t\tlog_conversion.server_time as serverTimePretty,\n\t\t\t\t\t\tlog_conversion.url as url\n\t\t\t\tFROM " . Common::prefixTable('log_conversion') . " AS log_conversion\n\t\t\t\tLEFT JOIN " . Common::prefixTable('goal') . " AS goal\n\t\t\t\t\tON (goal.idsite = log_conversion.idsite\n\t\t\t\t\t\tAND\n\t\t\t\t\t\tgoal.idgoal = log_conversion.idgoal)\n\t\t\t\t\tAND goal.deleted = 0\n\t\t\t\tWHERE log_conversion.idvisit = ?\n\t\t\t\t\tAND log_conversion.idgoal > 0\n                ORDER BY server_time ASC\n\t\t\t\tLIMIT 0, {$actionsLimit}\n\t\t\t";
     $goalDetails = Db::fetchAll($sql, array($idVisit));
     $sql = "SELECT\n\t\t\t\t\t\tcase idgoal when " . GoalManager::IDGOAL_CART . " then '" . Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART . "' else '" . Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER . "' end as type,\n\t\t\t\t\t\tidorder as orderId,\n\t\t\t\t\t\t" . LogAggregator::getSqlRevenue('revenue') . " as revenue,\n\t\t\t\t\t\t" . LogAggregator::getSqlRevenue('revenue_subtotal') . " as revenueSubTotal,\n\t\t\t\t\t\t" . LogAggregator::getSqlRevenue('revenue_tax') . " as revenueTax,\n\t\t\t\t\t\t" . LogAggregator::getSqlRevenue('revenue_shipping') . " as revenueShipping,\n\t\t\t\t\t\t" . LogAggregator::getSqlRevenue('revenue_discount') . " as revenueDiscount,\n\t\t\t\t\t\titems as items,\n\n\t\t\t\t\t\tlog_conversion.server_time as serverTimePretty\n\t\t\t\t\tFROM " . Common::prefixTable('log_conversion') . " AS log_conversion\n\t\t\t\t\tWHERE idvisit = ?\n\t\t\t\t\t\tAND idgoal <= " . GoalManager::IDGOAL_ORDER . "\n\t\t\t\t\tORDER BY server_time ASC\n\t\t\t\t\tLIMIT 0, {$actionsLimit}";
     $ecommerceDetails = Db::fetchAll($sql, array($idVisit));
     foreach ($ecommerceDetails as &$ecommerceDetail) {
         if ($ecommerceDetail['type'] == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) {
             unset($ecommerceDetail['orderId']);
             unset($ecommerceDetail['revenueSubTotal']);
             unset($ecommerceDetail['revenueTax']);
             unset($ecommerceDetail['revenueShipping']);
             unset($ecommerceDetail['revenueDiscount']);
         }
         // 25.00 => 25
         foreach ($ecommerceDetail as $column => $value) {
             if (strpos($column, 'revenue') !== false) {
                 if ($value == round($value)) {
                     $ecommerceDetail[$column] = round($value);
                 }
             }
         }
     }
     // Enrich ecommerce carts/orders with the list of products
     usort($ecommerceDetails, array('static', 'sortByServerTime'));
     foreach ($ecommerceDetails as &$ecommerceConversion) {
         $sql = "SELECT\n\t\t\t\t\t\t\tlog_action_sku.name as itemSKU,\n\t\t\t\t\t\t\tlog_action_name.name as itemName,\n\t\t\t\t\t\t\tlog_action_category.name as itemCategory,\n\t\t\t\t\t\t\t" . LogAggregator::getSqlRevenue('price') . " as price,\n\t\t\t\t\t\t\tquantity as quantity\n\t\t\t\t\t\tFROM " . Common::prefixTable('log_conversion_item') . "\n\t\t\t\t\t\t\tINNER JOIN " . Common::prefixTable('log_action') . " AS log_action_sku\n\t\t\t\t\t\t\tON  idaction_sku = log_action_sku.idaction\n\t\t\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_name\n\t\t\t\t\t\t\tON  idaction_name = log_action_name.idaction\n\t\t\t\t\t\t\tLEFT JOIN " . Common::prefixTable('log_action') . " AS log_action_category\n\t\t\t\t\t\t\tON idaction_category = log_action_category.idaction\n\t\t\t\t\t\tWHERE idvisit = ?\n\t\t\t\t\t\t\tAND idorder = ?\n\t\t\t\t\t\t\tAND deleted = 0\n\t\t\t\t\t\tLIMIT 0, {$actionsLimit}\n\t\t\t\t";
         $bind = array($idVisit, isset($ecommerceConversion['orderId']) ? $ecommerceConversion['orderId'] : GoalManager::ITEM_IDORDER_ABANDONED_CART);
         $itemsDetails = Db::fetchAll($sql, $bind);
         foreach ($itemsDetails as &$detail) {
             if ($detail['price'] == round($detail['price'])) {
                 $detail['price'] = round($detail['price']);
             }
         }
         $ecommerceConversion['itemDetails'] = $itemsDetails;
     }
     $actions = array_merge($actionDetails, $goalDetails, $ecommerceDetails);
     usort($actions, array('static', 'sortByServerTime'));
     $visitorDetailsArray['actionDetails'] = $actions;
     foreach ($visitorDetailsArray['actionDetails'] as &$details) {
         switch ($details['type']) {
             case 'goal':
                 $details['icon'] = 'plugins/Morpheus/images/goal.png';
                 break;
             case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER:
             case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART:
                 $details['icon'] = 'plugins/Morpheus/images/' . $details['type'] . '.gif';
                 break;
             case Action::TYPE_DOWNLOAD:
                 $details['type'] = 'download';
                 $details['icon'] = 'plugins/Morpheus/images/download.png';
                 break;
             case Action::TYPE_OUTLINK:
                 $details['type'] = 'outlink';
                 $details['icon'] = 'plugins/Morpheus/images/link.gif';
                 break;
             case Action::TYPE_SITE_SEARCH:
                 $details['type'] = 'search';
                 $details['icon'] = 'plugins/Morpheus/images/search_ico.png';
                 break;
             case Action::TYPE_EVENT_CATEGORY:
                 $details['type'] = 'event';
                 $details['icon'] = 'plugins/Morpheus/images/event.png';
                 break;
             default:
                 $details['type'] = 'action';
                 $details['icon'] = null;
                 break;
         }
         // Convert datetimes to the site timezone
         $dateTimeVisit = Date::factory($details['serverTimePretty'], $timezone);
         $details['serverTimePretty'] = $dateTimeVisit->getLocalized(Piwik::translate('CoreHome_ShortDateFormat') . ' %time%');
     }
     $visitorDetailsArray['goalConversions'] = count($goalDetails);
     return $visitorDetailsArray;
 }
Beispiel #13
0
 public function test_truncateCustomVariable_shouldActuallyTruncateTheValue()
 {
     $len = CustomVariables::getMaxLengthCustomVariables();
     $input = str_pad('test', $len + 2, 't');
     $this->assertGreaterThan(100, $len);
     $truncated = Request::truncateCustomVariable($input);
     $this->assertEquals(str_pad('test', $len, 't'), $truncated);
 }
Beispiel #14
0
 public static function truncateCustomVariable($input)
 {
     return substr(trim($input), 0, CustomVariables::getMaxLengthCustomVariables());
 }
Beispiel #15
0
 /**
  * Records one or several goals matched in this request.
  *
  * @param Visitor $visitor
  * @param array $visitorInformation
  * @param array $visitCustomVariables
  * @param Action $action
  */
 public function recordGoals(Visitor $visitor, $visitorInformation, $visitCustomVariables, $action)
 {
     $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
     $goal += $visitCustomVariables;
     $maxCustomVariables = CustomVariables::getMaxCustomVariables();
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         if (isset($visitorInformation['custom_var_k' . $i]) && strlen($visitorInformation['custom_var_k' . $i])) {
             $goal['custom_var_k' . $i] = $visitorInformation['custom_var_k' . $i];
         }
         if (isset($visitorInformation['custom_var_v' . $i]) && strlen($visitorInformation['custom_var_v' . $i])) {
             $goal['custom_var_v' . $i] = $visitorInformation['custom_var_v' . $i];
         }
     }
     // some goals are converted, so must be ecommerce Order or Cart Update
     if ($this->requestIsEcommerce) {
         $this->recordEcommerceGoal($goal, $visitor, $action, $visitorInformation);
     } else {
         $this->recordStandardGoals($goal, $visitor, $action, $visitorInformation);
     }
 }
Beispiel #16
0
 /**
  * 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
  */
 public function recognize()
 {
     $this->setIsVisitorKnown(false);
     $configId = $this->configId;
     $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 = self::getVisitFieldsPersist();
     array_unshift($persistedVisitAttributes, 'visit_first_action_time');
     array_unshift($persistedVisitAttributes, 'visit_last_action_time');
     $persistedVisitAttributes = array_unique($persistedVisitAttributes);
     $selectFields = implode(", ", $persistedVisitAttributes);
     $select = "SELECT\n                        {$selectFields}\n                        {$selectCustomVariables}\n        ";
     $from = "FROM " . Common::prefixTable('log_visit');
     list($timeLookBack, $timeLookAhead) = $this->getWindowLookupThisVisit();
     $shouldMatchOneFieldOnly = $this->shouldLookupOneVisitorFieldOnly($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}\n            {$from}\n            WHERE " . $whereCommon . "\n            ORDER BY visit_last_action_time DESC\n            LIMIT 1";
     } else {
         // will use INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time)
         $where = ' AND config_id = ?';
         $bindSql[] = $configId;
         $sqlConfigId = "{$select} ,\n                0 as priority\n                {$from}\n                WHERE {$whereCommon} {$where}\n                ORDER BY visit_last_action_time DESC\n                LIMIT 1\n            ";
         // 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} ,\n                1 as priority\n                {$from}\n                WHERE {$whereCommon} {$where}\n                ORDER BY visit_last_action_time DESC\n                LIMIT 1\n            ";
         // We join both queries and favor the one matching the visitor_id if it did match
         $sql = " ( {$sqlConfigId} )\n                UNION\n                ( {$sqlVisitorId} )\n                ORDER BY priority DESC\n                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
         foreach ($persistedVisitAttributes as $field) {
             $this->visitorInfo[$field] = $visitRow[$field];
         }
         $this->visitorInfo['visit_last_action_time'] = strtotime($visitRow['visit_last_action_time']);
         $this->visitorInfo['visit_first_action_time'] = strtotime($visitRow['visit_first_action_time']);
         // 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];
                 }
             }
         }
         $this->setIsVisitorKnown(true);
         Common::printDebug("The visitor is known (idvisitor = " . bin2hex($this->visitorInfo['idvisitor']) . ",\n                    config_id = " . bin2hex($configId) . ",\n                    idvisit = {$this->visitorInfo['idvisit']},\n                    last action = " . date("r", $this->visitorInfo['visit_last_action_time']) . ",\n                    first action = " . date("r", $this->visitorInfo['visit_first_action_time']) . ",\n                    visit_goal_buyer' = " . $this->visitorInfo['visit_goal_buyer'] . ")");
         //Common::printDebug($this->visitorInfo);
     } else {
         Common::printDebug("The visitor was not matched with an existing visitor...");
     }
 }
Beispiel #17
0
 /**
  * Records one or several goals matched in this request.
  *
  * @param Visitor $visitor
  * @param array $visitorInformation
  * @param array $visitCustomVariables
  * @param Action $action
  */
 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;
         }
     }
     // Copy Custom Variables from Visit row to the Goal conversion
     // Otherwise, set the Custom Variables found in the cookie sent with this request
     $goal += $visitCustomVariables;
     $maxCustomVariables = CustomVariables::getMaxCustomVariables();
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         if (isset($visitorInformation['custom_var_k' . $i]) && strlen($visitorInformation['custom_var_k' . $i])) {
             $goal['custom_var_k' . $i] = $visitorInformation['custom_var_k' . $i];
         }
         if (isset($visitorInformation['custom_var_v' . $i]) && strlen($visitorInformation['custom_var_v' . $i])) {
             $goal['custom_var_v' . $i] = $visitorInformation['custom_var_v' . $i];
         }
     }
     // some goals are converted, so must be ecommerce Order or Cart Update
     if ($this->requestIsEcommerce) {
         $this->recordEcommerceGoal($goal, $visitor, $action, $visitorInformation);
     } else {
         $this->recordStandardGoals($goal, $visitor, $action, $visitorInformation);
     }
 }
Beispiel #18
0
 /**
  * Records one or several goals matched in this request.
  *
  * @param int $idSite
  * @param array $visitorInformation
  * @param array $visitCustomVariables
  * @param Action $action
  */
 public function recordGoals($idSite, $visitorInformation, $visitCustomVariables, $action)
 {
     $referrerTimestamp = $this->request->getParam('_refts');
     $referrerUrl = $this->request->getParam('_ref');
     $referrerCampaignName = trim(urldecode($this->request->getParam('_rcn')));
     $referrerCampaignKeyword = trim(urldecode($this->request->getParam('_rck')));
     $browserLanguage = $this->request->getBrowserLanguage();
     $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Common::getCountry($browserLanguage, $enableLanguageToCountryGuess = Config::getInstance()->Tracker['enable_language_to_country_guess'], $visitorInformation['location_ip']);
     $goal = array('idvisit' => $visitorInformation['idvisit'], 'idsite' => $idSite, 'idvisitor' => $visitorInformation['idvisitor'], 'server_time' => Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']), 'location_country' => $location_country, 'visitor_returning' => $visitorInformation['visitor_returning'], 'visitor_days_since_first' => $visitorInformation['visitor_days_since_first'], 'visitor_days_since_order' => $visitorInformation['visitor_days_since_order'], 'visitor_count_visits' => $visitorInformation['visitor_count_visits']);
     $extraLocationCols = array('location_region', 'location_city', 'location_latitude', 'location_longitude');
     foreach ($extraLocationCols as $col) {
         if (isset($visitorInformation[$col])) {
             $goal[$col] = $visitorInformation[$col];
         }
     }
     // Copy Custom Variables from Visit row to the Goal conversion
     // Otherwise, set the Custom Variables found in the cookie sent with this request
     $goal += $visitCustomVariables;
     $maxCustomVariables = CustomVariables::getMaxCustomVariables();
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         if (isset($visitorInformation['custom_var_k' . $i]) && strlen($visitorInformation['custom_var_k' . $i])) {
             $goal['custom_var_k' . $i] = $visitorInformation['custom_var_k' . $i];
         }
         if (isset($visitorInformation['custom_var_v' . $i]) && strlen($visitorInformation['custom_var_v' . $i])) {
             $goal['custom_var_v' . $i] = $visitorInformation['custom_var_v' . $i];
         }
     }
     // Attributing the correct Referrer to this conversion.
     // Priority order is as follows:
     // 0) In some cases, the campaign is not passed from the JS so we look it up from the current visit
     // 1) Campaign name/kwd parsed in the JS
     // 2) Referrer URL stored in the _ref cookie
     // 3) If no info from the cookie, attribute to the current visit referrer
     // 3) Default values: current referrer
     $type = $visitorInformation['referer_type'];
     $name = $visitorInformation['referer_name'];
     $keyword = $visitorInformation['referer_keyword'];
     $time = $visitorInformation['visit_first_action_time'];
     // 0) In some (unknown!?) cases the campaign is not found in the attribution cookie, but the URL ref was found.
     //    In this case we look up if the current visit is credited to a campaign and will credit this campaign rather than the URL ref (since campaigns have higher priority)
     if (empty($referrerCampaignName) && $type == Common::REFERRER_TYPE_CAMPAIGN && !empty($name)) {
         // Use default values per above
     } elseif (!empty($referrerCampaignName)) {
         $type = Common::REFERRER_TYPE_CAMPAIGN;
         $name = $referrerCampaignName;
         $keyword = $referrerCampaignKeyword;
         $time = $referrerTimestamp;
     } elseif (!empty($referrerUrl)) {
         $referrer = new Referrer();
         $referrer = $referrer->getReferrerInformation($referrerUrl, $currentUrl = '', $idSite);
         // if the parsed referrer is interesting enough, ie. website or search engine
         if (in_array($referrer['referer_type'], array(Common::REFERRER_TYPE_SEARCH_ENGINE, Common::REFERRER_TYPE_WEBSITE))) {
             $type = $referrer['referer_type'];
             $name = $referrer['referer_name'];
             $keyword = $referrer['referer_keyword'];
             $time = $referrerTimestamp;
         }
     }
     $this->setCampaignValuesToLowercase($type, $name, $keyword);
     $goal += array('referer_type' => $type, 'referer_name' => $name, 'referer_keyword' => $keyword, 'referer_visit_server_date' => date("Y-m-d", $time));
     // some goals are converted, so must be ecommerce Order or Cart Update
     if ($this->requestIsEcommerce) {
         $this->recordEcommerceGoal($goal, $visitorInformation);
     } else {
         $this->recordStandardGoals($goal, $action, $visitorInformation);
     }
 }
 public function testExecute_AddMultiple_RemoveMultiple()
 {
     $this->assertEquals(5, CustomVariables::getMaxCustomVariables());
     $this->executeCommand(9);
     $this->assertEquals(9, CustomVariables::getMaxCustomVariables());
     $this->executeCommand(6);
     $this->assertEquals(6, CustomVariables::getMaxCustomVariables());
 }
Beispiel #20
0
 public function addCustomVariable()
 {
     $dbTable = $this->getDbTableName();
     $index = $this->getHighestCustomVarIndex() + 1;
     $maxLen = CustomVariables::getMaxLengthCustomVariables();
     Db::exec(sprintf('ALTER TABLE %s ', $dbTable) . sprintf('ADD COLUMN custom_var_k%d VARCHAR(%d) DEFAULT NULL,', $index, $maxLen) . sprintf('ADD COLUMN custom_var_v%d VARCHAR(%d) DEFAULT NULL;', $index, $maxLen));
     return $index;
 }
Beispiel #21
0
 /**
  * @return array
  */
 private function getVisitFieldsPersist()
 {
     if (is_null($this->visitFieldsToSelect)) {
         $fields = array('idvisitor', 'idvisit', 'user_id', 'visit_exit_idaction_url', 'visit_exit_idaction_name', 'visitor_returning', 'visitor_days_since_first', 'visitor_days_since_order', 'visitor_count_visits', 'visit_goal_buyer', 'location_country', 'location_region', 'location_city', 'location_latitude', 'location_longitude', 'referer_name', 'referer_keyword', 'referer_type');
         $dimensions = VisitDimension::getAllDimensions();
         foreach ($dimensions as $dimension) {
             if ($dimension->hasImplementedEvent('onExistingVisit') || $dimension->hasImplementedEvent('onAnyGoalConversion')) {
                 $fields[] = $dimension->getColumnName();
             }
             foreach ($dimension->getRequiredVisitFields() as $field) {
                 $fields[] = $field;
             }
         }
         /**
          * This event collects a list of [visit entity](/guides/persistence-and-the-mysql-backend#visits) properties that should be loaded when reading
          * the existing visit. Properties that appear in this list will be available in other tracking
          * events such as 'onExistingVisit'.
          *
          * Plugins can use this event to load additional visit entity properties for later use during tracking.
          *
          * This event is deprecated, use [Dimensions](http://developer.piwik.org/guides/dimensions) instead.
          *
          * @deprecated
          */
         $this->eventDispatcher->postEvent('Tracker.getVisitFieldsToPersist', array(&$fields));
         array_unshift($fields, 'visit_first_action_time');
         array_unshift($fields, 'visit_last_action_time');
         for ($index = 1; $index <= CustomVariables::getNumUsableCustomVariables(); $index++) {
             $fields[] = 'custom_var_k' . $index;
             $fields[] = 'custom_var_v' . $index;
         }
         $this->visitFieldsToSelect = array_unique($fields);
     }
     return $this->visitFieldsToSelect;
 }
Beispiel #22
0
 /**
  * Get a list of all available custom variable slots (scope + index) and which names have been used so far in
  * each slot since the beginning of the website.
  *
  * @param int $idSite
  * @return array
  */
 public function getUsagesOfSlots($idSite)
 {
     Piwik::checkUserHasAdminAccess($idSite);
     $numVars = CustomVariables::getNumUsableCustomVariables();
     $usedCustomVariables = array('visit' => array_fill(1, $numVars, array()), 'page' => array_fill(1, $numVars, array()));
     /** @var DataTable $customVarUsages */
     $today = StaticContainer::get('CustomVariables.today');
     $date = '2008-12-12,' . $today;
     $customVarUsages = Request::processRequest('CustomVariables.getCustomVariables', array('idSite' => $idSite, 'period' => 'range', 'date' => $date, 'format' => 'original'));
     foreach ($customVarUsages->getRows() as $row) {
         $slots = $row->getMetadata('slots');
         if (!empty($slots)) {
             foreach ($slots as $slot) {
                 $usedCustomVariables[$slot['scope']][$slot['index']][] = array('name' => $row->getColumn('label'), 'nb_visits' => $row->getColumn('nb_visits'), 'nb_actions' => $row->getColumn('nb_actions'));
             }
         }
     }
     $grouped = array();
     foreach ($usedCustomVariables as $scope => $scopes) {
         foreach ($scopes as $index => $cvars) {
             $grouped[] = array('scope' => $scope, 'index' => $index, 'usages' => $cvars);
         }
     }
     return $grouped;
 }
 /**
  * @param int $idSite
  * @param string $piwikUrl http://path/to/piwik/site/
  * @param bool $mergeSubdomains
  * @param bool $groupPageTitlesByDomain
  * @param bool $mergeAliasUrls
  * @param array $visitorCustomVariables
  * @param array $pageCustomVariables
  * @param string $customCampaignNameQueryParam
  * @param string $customCampaignKeywordParam
  * @param bool $doNotTrack
  * @param bool $disableCookies
  * @return string Javascript code.
  */
 public function generate($idSite, $piwikUrl, $mergeSubdomains = false, $groupPageTitlesByDomain = false, $mergeAliasUrls = false, $visitorCustomVariables = null, $pageCustomVariables = null, $customCampaignNameQueryParam = null, $customCampaignKeywordParam = null, $doNotTrack = false, $disableCookies = false)
 {
     // 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') {
         $piwikUrl = 'http://' . $piwikUrl;
     }
     preg_match('~^(http|https)://(.*)$~D', $piwikUrl, $matches);
     $piwikUrl = rtrim(@$matches[2], "/");
     // Build optional parameters to be added to text
     $options = '';
     $optionsBeforeTrackerUrl = '';
     if ($groupPageTitlesByDomain) {
         $options .= '  _paq.push(["setDocumentTitle", document.domain + "/" + document.title]);' . "\n";
     }
     if ($mergeSubdomains || $mergeAliasUrls) {
         $options .= $this->getJavascriptTagOptions($idSite, $mergeSubdomains, $mergeAliasUrls);
     }
     $maxCustomVars = CustomVariables::getNumUsableCustomVariables();
     if ($visitorCustomVariables && count($visitorCustomVariables) > 0) {
         $options .= '  // you can set up to ' . $maxCustomVars . ' custom variables for each visitor' . "\n";
         $index = 1;
         foreach ($visitorCustomVariables as $visitorCustomVariable) {
             if (empty($visitorCustomVariable)) {
                 continue;
             }
             $options .= sprintf('  _paq.push(["setCustomVariable", %d, %s, %s, "visit"]);%s', $index++, json_encode($visitorCustomVariable[0]), json_encode($visitorCustomVariable[1]), "\n");
         }
     }
     if ($pageCustomVariables && count($pageCustomVariables) > 0) {
         $options .= '  // you can set up to ' . $maxCustomVars . ' custom variables for each action (page view, download, click, site search)' . "\n";
         $index = 1;
         foreach ($pageCustomVariables as $pageCustomVariable) {
             if (empty($pageCustomVariable)) {
                 continue;
             }
             $options .= sprintf('  _paq.push(["setCustomVariable", %d, %s, %s, "page"]);%s', $index++, json_encode($pageCustomVariable[0]), json_encode($pageCustomVariable[1]), "\n");
         }
     }
     if ($customCampaignNameQueryParam) {
         $options .= '  _paq.push(["setCampaignNameKey", ' . json_encode($customCampaignNameQueryParam) . ']);' . "\n";
     }
     if ($customCampaignKeywordParam) {
         $options .= '  _paq.push(["setCampaignKeywordKey", ' . json_encode($customCampaignKeywordParam) . ']);' . "\n";
     }
     if ($doNotTrack) {
         $options .= '  _paq.push(["setDoNotTrack", true]);' . "\n";
     }
     if ($disableCookies) {
         $options .= '  _paq.push(["disableCookies"]);' . "\n";
     }
     $codeImpl = array('idSite' => $idSite, 'piwikUrl' => Common::sanitizeInputValue($piwikUrl), 'options' => $options, 'optionsBeforeTrackerUrl' => $optionsBeforeTrackerUrl, 'protocol' => '//');
     $parameters = compact('mergeSubdomains', 'groupPageTitlesByDomain', 'mergeAliasUrls', 'visitorCustomVariables', 'pageCustomVariables', 'customCampaignNameQueryParam', 'customCampaignKeywordParam', 'doNotTrack');
     /**
      * Triggered when generating JavaScript tracking code server side. Plugins can use
      * this event to customise the JavaScript tracking code that is displayed to the
      * user.
      *
      * @param array &$codeImpl An array containing snippets of code that the event handler
      *                         can modify. Will contain the following elements:
      *
      *                         - **idSite**: The ID of the site being tracked.
      *                         - **piwikUrl**: The tracker URL to use.
      *                         - **options**: A string of JavaScript code that customises
      *                                        the JavaScript tracker.
      *                         - **optionsBeforeTrackerUrl**: A string of Javascript code that customises
      *                                        the JavaScript tracker inside of anonymous function before
      *                                        adding setTrackerUrl into paq.
      *                         - **protocol**: Piwik url protocol.
      *
      *                         The **httpsPiwikUrl** element can be set if the HTTPS
      *                         domain is different from the normal domain.
      * @param array $parameters The parameters supplied to `TrackerCodeGenerator::generate()`.
      */
     Piwik::postEvent('Piwik.getJavascriptCode', array(&$codeImpl, $parameters));
     $setTrackerUrl = 'var u="' . $codeImpl['protocol'] . '{$piwikUrl}/";';
     if (!empty($codeImpl['httpsPiwikUrl'])) {
         $setTrackerUrl = 'var u=((document.location.protocol === "https:") ? "https://{$httpsPiwikUrl}/" : "http://{$piwikUrl}/");';
         $codeImpl['httpsPiwikUrl'] = rtrim($codeImpl['httpsPiwikUrl'], "/");
     }
     $codeImpl = array('setTrackerUrl' => htmlentities($setTrackerUrl)) + $codeImpl;
     foreach ($codeImpl as $keyToReplace => $replaceWith) {
         $jsCode = str_replace('{$' . $keyToReplace . '}', $replaceWith, $jsCode);
     }
     return $jsCode;
 }
Beispiel #24
0
 /**
  * @param $visitorDetailsArray
  * @param $actionsLimit
  * @param $timezone
  * @return array
  */
 public static function enrichVisitorArrayWithActions($visitorDetailsArray, $actionsLimit, $timezone)
 {
     $idVisit = $visitorDetailsArray['idVisit'];
     $model = new Model();
     $actionDetails = $model->queryActionsForVisit($idVisit, $actionsLimit);
     $formatter = new Formatter();
     $maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
     foreach ($actionDetails as $actionIdx => &$actionDetail) {
         $actionDetail =& $actionDetails[$actionIdx];
         $customVariablesPage = array();
         for ($i = 1; $i <= $maxCustomVariables; $i++) {
             if (!empty($actionDetail['custom_var_k' . $i])) {
                 $cvarKey = $actionDetail['custom_var_k' . $i];
                 $cvarKey = static::getCustomVariablePrettyKey($cvarKey);
                 $customVariablesPage[$i] = array('customVariablePageName' . $i => $cvarKey, 'customVariablePageValue' . $i => $actionDetail['custom_var_v' . $i]);
             }
             unset($actionDetail['custom_var_k' . $i]);
             unset($actionDetail['custom_var_v' . $i]);
         }
         if (!empty($customVariablesPage)) {
             $actionDetail['customVariables'] = $customVariablesPage;
         }
         if ($actionDetail['type'] == Action::TYPE_CONTENT) {
             unset($actionDetails[$actionIdx]);
             continue;
         } elseif ($actionDetail['type'] == Action::TYPE_EVENT) {
             // Handle Event
             if (strlen($actionDetail['pageTitle']) > 0) {
                 $actionDetail['eventName'] = $actionDetail['pageTitle'];
             }
             unset($actionDetail['pageTitle']);
         } else {
             if ($actionDetail['type'] == Action::TYPE_SITE_SEARCH) {
                 // Handle Site Search
                 $actionDetail['siteSearchKeyword'] = $actionDetail['pageTitle'];
                 unset($actionDetail['pageTitle']);
             }
         }
         // Event value / Generation time
         if ($actionDetail['type'] == Action::TYPE_EVENT) {
             if (strlen($actionDetail['custom_float']) > 0) {
                 $actionDetail['eventValue'] = round($actionDetail['custom_float'], self::EVENT_VALUE_PRECISION);
             }
         } elseif ($actionDetail['custom_float'] > 0) {
             $actionDetail['generationTime'] = $formatter->getPrettyTimeFromSeconds($actionDetail['custom_float'] / 1000, true);
         }
         unset($actionDetail['custom_float']);
         if ($actionDetail['type'] != Action::TYPE_EVENT) {
             unset($actionDetail['eventCategory']);
             unset($actionDetail['eventAction']);
         }
         // Reconstruct url from prefix
         $url = Tracker\PageUrl::reconstructNormalizedUrl($actionDetail['url'], $actionDetail['url_prefix']);
         $url = Common::unsanitizeInputValue($url);
         $actionDetail['url'] = $url;
         unset($actionDetail['url_prefix']);
     }
     // If the visitor converted a goal, we shall select all Goals
     $goalDetails = $model->queryGoalConversionsForVisit($idVisit, $actionsLimit);
     $ecommerceDetails = $model->queryEcommerceConversionsForVisit($idVisit, $actionsLimit);
     foreach ($ecommerceDetails as &$ecommerceDetail) {
         if ($ecommerceDetail['type'] == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) {
             unset($ecommerceDetail['orderId']);
             unset($ecommerceDetail['revenueSubTotal']);
             unset($ecommerceDetail['revenueTax']);
             unset($ecommerceDetail['revenueShipping']);
             unset($ecommerceDetail['revenueDiscount']);
         }
         // 25.00 => 25
         foreach ($ecommerceDetail as $column => $value) {
             if (strpos($column, 'revenue') !== false) {
                 if ($value == round($value)) {
                     $ecommerceDetail[$column] = round($value);
                 }
             }
         }
     }
     // Enrich ecommerce carts/orders with the list of products
     usort($ecommerceDetails, array('static', 'sortByServerTime'));
     foreach ($ecommerceDetails as &$ecommerceConversion) {
         $idOrder = isset($ecommerceConversion['orderId']) ? $ecommerceConversion['orderId'] : GoalManager::ITEM_IDORDER_ABANDONED_CART;
         $itemsDetails = $model->queryEcommerceItemsForOrder($idVisit, $idOrder, $actionsLimit);
         foreach ($itemsDetails as &$detail) {
             if ($detail['price'] == round($detail['price'])) {
                 $detail['price'] = round($detail['price']);
             }
         }
         $ecommerceConversion['itemDetails'] = $itemsDetails;
     }
     // Enrich with time spent per action
     foreach ($actionDetails as $actionIdx => &$actionDetail) {
         // Set the time spent for this action (which is the timeSpentRef of the next action)
         $nextActionFound = isset($actionDetails[$actionIdx + 1]);
         if ($nextActionFound) {
             $actionDetail['timeSpent'] = $actionDetails[$actionIdx + 1]['timeSpentRef'];
         } else {
             // Last action of a visit.
             // By default, Piwik does not know how long the user stayed on the page
             // If enableHeartBeatTimer() is used in piwik.js then we can find the accurate time on page for the last pageview
             $timeOfLastActionOrPingInVisitRow = $visitorDetailsArray['lastActionTimestamp'];
             $timeOfLastAction = Date::factory($actionDetail['serverTimePretty'])->getTimestamp();
             $timeSpentOnPage = $timeOfLastActionOrPingInVisitRow - $timeOfLastAction;
             // Safe net, we assume the time is correct when it's more than 10 seconds
             if ($timeSpentOnPage > 10) {
                 $actionDetail['timeSpent'] = $timeSpentOnPage;
             }
         }
         if (isset($actionDetail['timeSpent'])) {
             $actionDetail['timeSpentPretty'] = $formatter->getPrettyTimeFromSeconds($actionDetail['timeSpent'], true);
         }
         unset($actionDetails[$actionIdx]['timeSpentRef']);
         // not needed after timeSpent is added
     }
     $actions = array_merge($actionDetails, $goalDetails, $ecommerceDetails);
     usort($actions, array('static', 'sortByServerTime'));
     foreach ($actions as &$action) {
         unset($action['idlink_va']);
     }
     $visitorDetailsArray['goalConversions'] = count($goalDetails);
     $visitorDetailsArray['actionDetails'] = $actions;
     foreach ($visitorDetailsArray['actionDetails'] as &$details) {
         switch ($details['type']) {
             case 'goal':
                 $details['icon'] = 'plugins/Morpheus/images/goal.png';
                 break;
             case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER:
             case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART:
                 $details['icon'] = 'plugins/Morpheus/images/' . $details['type'] . '.gif';
                 break;
             case Action::TYPE_DOWNLOAD:
                 $details['type'] = 'download';
                 $details['icon'] = 'plugins/Morpheus/images/download.png';
                 break;
             case Action::TYPE_OUTLINK:
                 $details['type'] = 'outlink';
                 $details['icon'] = 'plugins/Morpheus/images/link.gif';
                 break;
             case Action::TYPE_SITE_SEARCH:
                 $details['type'] = 'search';
                 $details['icon'] = 'plugins/Morpheus/images/search_ico.png';
                 break;
             case Action::TYPE_EVENT:
                 $details['type'] = 'event';
                 $details['icon'] = 'plugins/Morpheus/images/event.png';
                 break;
             default:
                 $details['type'] = 'action';
                 $details['icon'] = null;
                 break;
         }
         // Convert datetimes to the site timezone
         $dateTimeVisit = Date::factory($details['serverTimePretty'], $timezone);
         $details['serverTimePretty'] = $dateTimeVisit->getLocalized(Date::DATETIME_FORMAT_SHORT);
         $details['timestamp'] = $dateTimeVisit->getTimestamp();
     }
     return $visitorDetailsArray;
 }
Beispiel #25
0
 /**
  * Records one or several goals matched in this request.
  *
  * @param Visitor $visitor
  * @param array $visitorInformation
  * @param array $visitCustomVariables
  * @param Action $action
  */
 public function recordGoals(VisitProperties $visitProperties, Request $request)
 {
     $visitorInformation = $visitProperties->getProperties();
     $visitCustomVariables = $request->getMetadata('CustomVariables', 'visitCustomVariables');
     /** @var Action $action */
     $action = $request->getMetadata('Actions', 'action');
     $goal = $this->getGoalFromVisitor($visitProperties, $request, $action);
     // Copy Custom Variables from Visit row to the Goal conversion
     // Otherwise, set the Custom Variables found in the cookie sent with this request
     $goal += $visitCustomVariables;
     $maxCustomVariables = CustomVariables::getMaxCustomVariables();
     for ($i = 1; $i <= $maxCustomVariables; $i++) {
         if (isset($visitorInformation['custom_var_k' . $i]) && strlen($visitorInformation['custom_var_k' . $i])) {
             $goal['custom_var_k' . $i] = $visitorInformation['custom_var_k' . $i];
         }
         if (isset($visitorInformation['custom_var_v' . $i]) && strlen($visitorInformation['custom_var_v' . $i])) {
             $goal['custom_var_v' . $i] = $visitorInformation['custom_var_v' . $i];
         }
     }
     // some goals are converted, so must be ecommerce Order or Cart Update
     $isRequestEcommerce = $request->getMetadata('Ecommerce', 'isRequestEcommerce');
     if ($isRequestEcommerce) {
         $this->recordEcommerceGoal($visitProperties, $request, $goal, $action);
     } else {
         $this->recordStandardGoals($visitProperties, $request, $goal, $action);
     }
 }
Beispiel #26
0
 /**
  * Renders and echo's an admin page that lets users generate custom JavaScript
  * tracking code and custom image tracker links.
  */
 public function trackingCodeGenerator()
 {
     $view = new View('@CoreAdminHome/trackingCodeGenerator');
     $this->setBasicVariablesView($view);
     $view->topMenu = MenuTop::getInstance()->getMenu();
     $view->userMenu = MenuUser::getInstance()->getMenu();
     $viewableIdSites = APISitesManager::getInstance()->getSitesIdWithAtLeastViewAccess();
     $defaultIdSite = reset($viewableIdSites);
     $view->idSite = Common::getRequestVar('idSite', $defaultIdSite, 'int');
     $view->defaultReportSiteName = Site::getNameFor($view->idSite);
     $view->defaultSiteRevenue = \Piwik\MetricsFormatter::getCurrencySymbol($view->idSite);
     $view->maxCustomVariables = CustomVariables::getMaxCustomVariables();
     $allUrls = APISitesManager::getInstance()->getSiteUrlsFromId($view->idSite);
     if (isset($allUrls[1])) {
         $aliasUrl = $allUrls[1];
     } else {
         $aliasUrl = 'x.domain.com';
     }
     $view->defaultReportSiteAlias = $aliasUrl;
     $mainUrl = Site::getMainUrlFor($view->idSite);
     $view->defaultReportSiteDomain = @parse_url($mainUrl, PHP_URL_HOST);
     // get currencies for each viewable site
     $view->currencySymbols = APISitesManager::getInstance()->getCurrencySymbols();
     $view->serverSideDoNotTrackEnabled = \Piwik\Plugins\PrivacyManager\DoNotTrackHeaderChecker::isActive();
     return $view->render();
 }
Beispiel #27
0
 /**
  * Renders and echo's an admin page that lets users generate custom JavaScript
  * tracking code and custom image tracker links.
  */
 public function trackingCodeGenerator()
 {
     Piwik::checkUserHasSomeViewAccess();
     $view = new View('@CoreAdminHome/trackingCodeGenerator');
     $this->setBasicVariablesView($view);
     $view->topMenu = MenuTop::getInstance()->getMenu();
     $viewableIdSites = APISitesManager::getInstance()->getSitesIdWithAtLeastViewAccess();
     $defaultIdSite = reset($viewableIdSites);
     $view->idSite = Common::getRequestVar('idSite', $defaultIdSite, 'int');
     $view->defaultReportSiteName = Site::getNameFor($view->idSite);
     $view->defaultSiteRevenue = Site::getCurrencySymbolFor($view->idSite);
     $view->maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
     $view->defaultSite = array('id' => $view->idSite, 'name' => $view->defaultReportSiteName);
     $allUrls = APISitesManager::getInstance()->getSiteUrlsFromId($view->idSite);
     if (isset($allUrls[1])) {
         $aliasUrl = $allUrls[1];
     } else {
         $aliasUrl = 'x.domain.com';
     }
     $view->defaultReportSiteAlias = $aliasUrl;
     $mainUrl = Site::getMainUrlFor($view->idSite);
     $view->defaultReportSiteDomain = @parse_url($mainUrl, PHP_URL_HOST);
     $dntChecker = new DoNotTrackHeaderChecker();
     $view->serverSideDoNotTrackEnabled = $dntChecker->isActive();
     return $view->render();
 }