public function outputResponse(Tracker $tracker) { if (!$tracker->shouldRecordStatistics()) { $this->outputApiResponse($tracker); Common::printDebug("Logging disabled, display transparent logo"); } elseif (!$tracker->hasLoggedRequests()) { if (!$this->isHttpGetRequest() || !empty($_GET) || !empty($_POST)) { Common::sendResponseCode(400); } Common::printDebug("Empty request => Piwik page"); echo "This resource is part of Piwik. Keep full control of your data with the leading free and open source <a href='https://piwik.org' target='_blank'>digital analytics platform</a> for web and mobile."; } else { $this->outputApiResponse($tracker); Common::printDebug("Nothing to notice => default behaviour"); } Common::printDebug("End of the page."); if ($tracker->isDebugModeEnabled() && $tracker->isDatabaseConnected() && TrackerDb::isProfilingEnabled()) { $db = Tracker::getDatabase(); $db->recordProfiling(); Profiler::displayDbTrackerProfile($db); } if ($tracker->isDebugModeEnabled()) { Common::printDebug($_COOKIE); Common::printDebug((string) $this->timer); } }
public function outputResponse(Tracker $tracker) { if (!$tracker->shouldRecordStatistics()) { $this->outputApiResponse($tracker); Common::printDebug("Logging disabled, display transparent logo"); } elseif (!$tracker->hasLoggedRequests()) { if (!$this->isHttpGetRequest() || !empty($_GET) || !empty($_POST)) { Common::sendResponseCode(400); } Common::printDebug("Empty request => Piwik page"); echo "<a href='/'>Piwik</a> is a free/libre web <a href='http://piwik.org'>analytics</a> that lets you keep control of your data."; } else { $this->outputApiResponse($tracker); Common::printDebug("Nothing to notice => default behaviour"); } Common::printDebug("End of the page."); if ($tracker->isDebugModeEnabled() && $tracker->isDatabaseConnected() && TrackerDb::isProfilingEnabled()) { $db = Tracker::getDatabase(); $db->recordProfiling(); Profiler::displayDbTrackerProfile($db); } if ($tracker->isDebugModeEnabled()) { Common::printDebug($_COOKIE); Common::printDebug((string) $this->timer); } }
public function outputResponse(Tracker $tracker) { if (!$tracker->shouldRecordStatistics()) { $this->outputApiResponse($tracker); Common::printDebug("Logging disabled, display transparent logo"); } elseif (!$tracker->hasLoggedRequests()) { if (!$this->isHttpGetRequest() || !empty($_GET) || !empty($_POST)) { Common::sendResponseCode(400); } Common::printDebug("Empty request => Piwik page"); //echo date('Y-m-d H:i:s'); } else { $this->outputApiResponse($tracker); Common::printDebug("Nothing to notice => default behaviour"); } Common::printDebug("End of the page."); if ($tracker->isDebugModeEnabled() && $tracker->isDatabaseConnected() && TrackerDb::isProfilingEnabled()) { $db = Tracker::getDatabase(); $db->recordProfiling(); Profiler::displayDbTrackerProfile($db); } if ($tracker->isDebugModeEnabled()) { Common::printDebug($_COOKIE); Common::printDebug((string) $this->timer); } }
/** * Returns the database connection and creates it if it hasn't been already. * * @return \Piwik\Tracker\Db|\Piwik\Db\AdapterInterface|\Piwik\Db */ public static function get() { if (SettingsServer::isTrackerApiRequest()) { return Tracker::getDatabase(); } if (!self::hasDatabaseObject()) { self::createDatabaseObject(); } return self::$connection; }
/** * Returns the database connection and creates it if it hasn't been already. * * @return \Piwik\Tracker\Db|\Piwik\Db\AdapterInterface|\Piwik\Db */ public static function get() { if (!empty($GLOBALS['PIWIK_TRACKER_MODE'])) { return Tracker::getDatabase(); } if (self::$connection === null) { self::createDatabaseObject(); } return self::$connection; }
public function test_rowCount_whenUpdating_returnsAllMatchedRowsNotOnlyUpdatedRows() { $db = Tracker::getDatabase(); // insert one record $db->query("INSERT INTO `" . Common::prefixTable('option') . "` VALUES ('rowid', '1', false)"); // We will now UPDATE this table and check rowCount() value $sqlUpdate = "UPDATE `" . Common::prefixTable('option') . "` SET option_value = 2"; // when no record was updated, return 0 $result = $db->query($sqlUpdate . " WHERE option_name = 'NOT FOUND'"); $this->assertSame(0, $db->rowCount($result)); // when one record was found and updated, returns 1 $result = $db->query($sqlUpdate . " WHERE option_name = 'rowid'"); $this->assertSame(1, $db->rowCount($result)); // when one record was found but NOT actually updated (as values have not changed), we make sure to return 1 // testing for MYSQLI_CLIENT_FOUND_ROWS and MYSQL_ATTR_FOUND_ROWS $result = $db->query($sqlUpdate . " WHERE option_name = 'rowid'"); $this->assertSame(1, $db->rowCount($result)); }
/** * Print profiling report for the tracker * * @param \Piwik\Db $db Tracker database object (or null) */ public static function displayDbTrackerProfile($db = null) { if (is_null($db)) { $db = Tracker::getDatabase(); } $LogProfiling = Factory::getDAO('log_profiling', $db); $all = $LogProfiling->getAll(); if ($all === false) { return; } uasort($all, 'self::maxSumMsFirst'); $infoIndexedByQuery = array(); foreach ($all as $infoQuery) { $query = $infoQuery['query']; $count = $infoQuery['count']; $sum_time_ms = $infoQuery['sum_time_ms']; $infoIndexedByQuery[$query] = array('count' => $count, 'sumTimeMs' => $sum_time_ms); } self::getSqlProfilingQueryBreakdownOutput($infoIndexedByQuery); }
private function assertActionEquals($expected, $idaction) { $actionName = Tracker::getDatabase()->fetchOne("SELECT name FROM " . Common::prefixTable('log_action') . " WHERE idaction = ?", array($idaction)); $this->assertEquals($expected, $actionName); }
private function getDb() { return Tracker::getDatabase(); }
protected function getDb() { return Tracker::getDatabase(); }
private static function queryIdsAction($actionsNameAndType) { $sql = TableLogAction::getSqlSelectActionId(); $bind = array(); $i = 0; foreach ($actionsNameAndType as &$actionNameType) { list($name, $type, $urlPrefix) = $actionNameType; if (empty($name)) { continue; } if ($i > 0) { $sql .= " OR ( hash = CRC32(?) AND name = ? AND type = ? ) "; } $bind[] = $name; $bind[] = $name; $bind[] = $type; $i++; } // Case URL & Title are empty if (empty($bind)) { return false; } $actionIds = Tracker::getDatabase()->fetchAll($sql, $bind); return $actionIds; }
/** * Print profiling report for the tracker * * @param \Piwik\Db $db Tracker database object (or null) */ public static function displayDbTrackerProfile($db = null) { if (is_null($db)) { $db = Tracker::getDatabase(); } $tableName = Common::prefixTable('log_profiling'); $all = $db->fetchAll('SELECT * FROM ' . $tableName); if ($all === false) { return; } uasort($all, 'self::maxSumMsFirst'); $infoIndexedByQuery = array(); foreach ($all as $infoQuery) { $query = $infoQuery['query']; $count = $infoQuery['count']; $sum_time_ms = $infoQuery['sum_time_ms']; $infoIndexedByQuery[$query] = array('count' => $count, 'sumTimeMs' => $sum_time_ms); } self::getSqlProfilingQueryBreakdownOutput($infoIndexedByQuery); }
protected function updateExistingConversion($newGoal, $updateWhere) { $updateParts = $sqlBind = $updateWhereParts = array(); foreach ($newGoal as $name => $value) { $updateParts[] = $name . " = ?"; $sqlBind[] = $value; } foreach ($updateWhere as $name => $value) { $updateWhereParts[] = $name . " = ?"; $sqlBind[] = $value; } $sql = 'UPDATE ' . Common::prefixTable('log_conversion') . "\n\t\t\t\t\tSET " . implode($updateParts, ', ') . "\n\t\t\t\t\t\tWHERE " . implode($updateWhereParts, ' AND '); try { Tracker::getDatabase()->query($sql, $sqlBind); } catch (Exception $e) { Common::printDebug("There was an error while updating the Conversion: " . $e->getMessage()); return false; } return true; }
/** * 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..."); } }
private function getIdVisit($idVisit) { $LogVisit = Factory::getDAO('log_visit', Tracker::getDatabase()); return $LogVisit->getByIdvisit($idVisit); }
private function getIdVisit($idVisit) { return Tracker::getDatabase()->fetchRow("SELECT * FROM " . Common::prefixTable('log_visit') . " WHERE idvisit = ?", array($idVisit)); }
/** * @param $valuesToUpdate * @throws VisitorNotFoundInDb */ protected function updateExistingVisit($valuesToUpdate) { $sqlQuery = "UPDATE " . Common::prefixTable('log_visit') . "\n SET %s\n WHERE idsite = ?\n AND idvisit = ?"; // build sql query $updateParts = $sqlBind = array(); foreach ($valuesToUpdate as $name => $value) { // Case where bind parameters don't work if (strpos($value, $name) !== false) { //$name = 'visit_total_events' //$value = 'visit_total_events + 1'; $updateParts[] = " {$name} = {$value} "; } else { $updateParts[] = $name . " = ?"; $sqlBind[] = $value; } } $sqlQuery = sprintf($sqlQuery, implode($updateParts, ', ')); array_push($sqlBind, $this->request->getIdSite(), (int) $this->visitorInfo['idvisit']); $result = Tracker::getDatabase()->query($sqlQuery, $sqlBind); $this->visitorInfo['visit_last_action_time'] = $this->request->getCurrentTimestamp(); // Debug output if (isset($valuesToUpdate['idvisitor'])) { $valuesToUpdate['idvisitor'] = bin2hex($valuesToUpdate['idvisitor']); } Common::printDebug('Updating existing visit: ' . var_export($valuesToUpdate, true)); if (Tracker::getDatabase()->rowCount($result) == 0) { Common::printDebug("Visitor with this idvisit wasn't found in the DB."); Common::printDebug("{$sqlQuery} --- "); Common::printDebug($sqlBind); throw new VisitorNotFoundInDb("The visitor with idvisitor=" . bin2hex($this->visitorInfo['idvisitor']) . " and idvisit=" . $this->visitorInfo['idvisit'] . " wasn't found in the DB, we fallback to a new visitor"); } }
/** * Records in the DB the association between the visit and this action. * * @param int $idVisit is the ID of the current visit in the DB table log_visit * @param $visitorIdCookie * @param int $idReferrerActionUrl is the ID of the last action done by the current visit. * @param $idReferrerActionName * @param int $timeSpentReferrerAction is the number of seconds since the last action was done. * It is directly related to idReferrerActionUrl. */ public function record($idVisit, $visitorIdCookie, $idReferrerActionUrl, $idReferrerActionName, $timeSpentReferrerAction) { $this->loadIdsFromLogActionTable(); $visitAction = array('idvisit' => $idVisit, 'idsite' => $this->request->getIdSite(), 'idvisitor' => $visitorIdCookie, 'server_time' => Tracker::getDatetimeFromTimestamp($this->request->getCurrentTimestamp()), 'idaction_url' => $this->getIdActionUrl(), 'idaction_url_ref' => $idReferrerActionUrl, 'idaction_name_ref' => $idReferrerActionName, 'time_spent_ref_action' => $timeSpentReferrerAction); // idaction_name is NULLable. we only set it when applicable if ($this->isActionHasActionName()) { $visitAction['idaction_name'] = (int) $this->getIdActionName(); } foreach ($this->actionIdsCached as $field => $idAction) { $visitAction[$field] = $idAction === false ? 0 : $idAction; } $customValue = $this->getCustomFloatValue(); if (!empty($customValue)) { $visitAction[self::DB_COLUMN_CUSTOM_FLOAT] = $customValue; } $customVariables = $this->getCustomVariables(); if (!empty($customVariables)) { Common::printDebug("Page level Custom Variables: "); Common::printDebug($customVariables); } $visitAction = array_merge($visitAction, $customVariables); $fields = implode(", ", array_keys($visitAction)); $bind = array_values($visitAction); $values = Common::getSqlStringFieldsArray($visitAction); $sql = "INSERT INTO " . Common::prefixTable('log_link_visit_action') . " ({$fields}) VALUES ({$values})"; Tracker::getDatabase()->query($sql, $bind); $this->idLinkVisitAction = Tracker::getDatabase()->lastInsertId(); $visitAction['idlink_va'] = $this->idLinkVisitAction; Common::printDebug("Inserted new action:"); Common::printDebug($visitAction); /** * Triggered after successfully persisting a [visit action entity](/guides/persistence-and-the-mysql-backend#visit-actions). * * @param Action $tracker Action The Action tracker instance. * @param array $visitAction The visit action entity that was persisted. Read * [this](/guides/persistence-and-the-mysql-backend#visit-actions) to see what it contains. */ Piwik::postEvent('Tracker.recordAction', array($trackerAction = $this, $visitAction)); }