function checkHeader($notification) { $setting = @Piwik_Tracker_Config::getInstance()->Tracker['do_not_track']; if ($setting === '1' && (isset($_SERVER['HTTP_X_DO_NOT_TRACK']) && $_SERVER['HTTP_X_DO_NOT_TRACK'] === '1' || isset($_SERVER['HTTP_DNT']) && $_SERVER['HTTP_DNT'] === '1')) { $exclude =& $notification->getNotificationObject(); $exclude = true; $trackingCookie = Piwik_Tracker_IgnoreCookie::getTrackingCookie(); $trackingCookie->delete(); } }
function test_extractUrlAndActionNameFromRequest() { $userFile = PIWIK_PATH_TEST_TO_ROOT . '/tests/resources/Tracker/Action.config.ini.php'; $config = Piwik_Tracker_Config::getInstance(); $config->init($userFile); $action = new Test_Piwik_TrackerAction_extractUrlAndActionNameFromRequest(); $tests = array(array('request' => array('link' => 'http://example.org'), 'expected' => array('name' => 'http://example.org', 'url' => 'http://example.org', 'type' => Piwik_Tracker_Action::TYPE_OUTLINK)), array('request' => array('link' => ' http://example.org/Category/Test/ '), 'expected' => array('name' => 'http://example.org/Category/Test/', 'url' => 'http://example.org/Category/Test/', 'type' => Piwik_Tracker_Action::TYPE_OUTLINK)), array('request' => array('download' => 'http://example.org/*$test.zip'), 'expected' => array('name' => 'http://example.org/*$test.zip', 'url' => 'http://example.org/*$test.zip', 'type' => Piwik_Tracker_Action::TYPE_DOWNLOAD)), array('request' => array('download' => 'http://example.org/CATEGORY/test///test.pdf'), 'expected' => array('name' => 'http://example.org/CATEGORY/test///test.pdf', 'url' => 'http://example.org/CATEGORY/test///test.pdf', 'type' => Piwik_Tracker_Action::TYPE_DOWNLOAD)), array('request' => array('url' => 'http://example.org/'), 'expected' => array('name' => 'index', 'url' => 'http://example.org/', 'type' => Piwik_Tracker_Action::TYPE_ACTION)), array('request' => array('url' => 'http://example.org/CATEGORY/'), 'expected' => array('name' => 'CATEGORY/index', 'url' => 'http://example.org/CATEGORY/', 'type' => Piwik_Tracker_Action::TYPE_ACTION)), array('request' => array('url' => 'http://example.org/category/', 'action_name' => 'custom name with/one delimiter/two delimiters/'), 'expected' => array('name' => 'custom name with/one delimiter/two delimiters', 'url' => 'http://example.org/category/', 'type' => Piwik_Tracker_Action::TYPE_ACTION)), array('request' => array('url' => 'http://example.org/category/', 'action_name' => 'http://custom action name look like url/'), 'expected' => array('name' => 'http:/custom action name look like url', 'url' => 'http://example.org/category/', 'type' => Piwik_Tracker_Action::TYPE_ACTION)), array('request' => array('url' => "http://example.org/category/test///test wOw \t"), 'expected' => array('name' => 'category/test/test wOw', 'url' => 'http://example.org/category/test///test wOw', 'type' => Piwik_Tracker_Action::TYPE_ACTION)), array('request' => array('url' => "http://example.org/category/1/0/t/test"), 'expected' => array('name' => 'category/1/0/t/test', 'url' => 'http://example.org/category/1/0/t/test', 'type' => Piwik_Tracker_Action::TYPE_ACTION))); foreach ($tests as $test) { $request = $test['request']; $expected = $test['expected']; $action->setRequest($request); $this->assertEqual($action->public_extractUrlAndActionNameFromRequest(), $expected); } }
/** * Returns the table name prefixed by the table prefix. * Works in both Tracker and UI mode. * * @param string The table name to prefix, ie "log_visit" * @return string The table name prefixed, ie "piwik-production_log_visit" */ public static function prefixTable($table) { static $prefixTable = null; if (is_null($prefixTable)) { if (defined('PIWIK_TRACKER_MODE') && PIWIK_TRACKER_MODE) { $prefixTable = Piwik_Tracker_Config::getInstance()->database['tables_prefix']; } else { $config = Zend_Registry::get('config'); if ($config !== false) { $prefixTable = $config->database->tables_prefix; } } } return $prefixTable . $table; }
public function testUserConfigOverwritesSectionGlobalConfigValue() { $userFile = PIWIK_PATH_TEST_TO_ROOT . '/tests/resources/Config/config.ini.php'; $globalFile = PIWIK_PATH_TEST_TO_ROOT . '/tests/resources/Config/global.ini.php'; $config = Piwik_Tracker_Config::getInstance(); $config->init($userFile, $globalFile); $this->assertEqual($config->Category['key1'], "value_overwritten"); $this->assertEqual($config->Category['key2'], "value2"); $this->assertEqual($config->General['login'], 'tes"t'); $this->assertEqual($config->CategoryOnlyInGlobalFile['key3'], "value3"); $this->assertEqual($config->CategoryOnlyInGlobalFile['key4'], "value4"); $expectedArray = array('plugin"1', 'plugin2', 'plugin3'); $array = $config->TestArray; $this->assertEqual($array['installed'], $expectedArray); $expectedArray = array('value1', 'value2'); $array = $config->TestArrayOnlyInGlobalFile; $this->assertEqual($array['my_array'], $expectedArray); }
/** * Get ignore (visit) cookie * * @return Piwik_Cookie */ static public function getIgnoreCookie() { if(!empty($GLOBALS['PIWIK_TRACKER_MODE'])) { $cookie_name = @Piwik_Tracker_Config::getInstance()->Tracker['ignore_visits_cookie_name']; $cookie_path = @Piwik_Tracker_Config::getInstance()->Tracker['cookie_path']; } else { $config = Zend_Registry::get('config'); if($config !== false) { $cookie_name = @$config->Tracker->ignore_visits_cookie_name; $cookie_path = @$config->Tracker->cookie_path; } } return new Piwik_Cookie($cookie_name, null, $cookie_path); }
protected function detectRefererCampaign() { if (isset($this->currentUrlParse['query'])) { $campaignVariableName = Piwik_Tracker_Config::getInstance()->Tracker['campaign_var_name']; $campaignName = Piwik_Common::getParameterFromQueryString($this->currentUrlParse['query'], $campaignVariableName); if (!empty($campaignName)) { $campaignKeywordVariableName = Piwik_Tracker_Config::getInstance()->Tracker['campaign_keyword_var_name']; $campaignKeyword = Piwik_Common::getParameterFromQueryString($this->currentUrlParse['query'], $campaignKeywordVariableName); $this->typeRefererAnalyzed = Piwik_Common::REFERER_TYPE_CAMPAIGN; $this->nameRefererAnalyzed = $campaignName; if (!empty($campaignKeyword)) { $this->keywordRefererAnalyzed = $campaignKeyword; } return true; } } return false; }
protected static function cleanupString($string) { $string = trim($string); $string = str_replace(array("\n", "\r"), "", $string); $limit = Piwik_Tracker_Config::getInstance()->Tracker['page_maximum_length']; return substr($string, 0, $limit); }
/** * Returns the list of Campaign parameter names that will be read to classify * a visit as coming from a Campaign * * @return array array( * 0 => array( ... ) // campaign names parameters * 1 => array( ... ) // campaign keyword parameters * ); */ public static function getCampaignParameters() { if (!empty($GLOBALS['PIWIK_TRACKER_MODE'])) { $return = array(Piwik_Tracker_Config::getInstance()->Tracker['campaign_var_name'], Piwik_Tracker_Config::getInstance()->Tracker['campaign_keyword_var_name']); } else { $return = array(Zend_Registry::get('config')->Tracker->campaign_var_name, Zend_Registry::get('config')->Tracker->campaign_keyword_var_name); } foreach ($return as &$list) { if (strpos($list, ',') !== false) { $list = explode(',', $list); } else { $list = array($list); } } array_walk_recursive($return, 'trim'); return $return; }
/** * Generates a new action for the current visitor. * We random generate some campaigns, action names, download or outlink clicks, etc. * We generate a new Referer, that would be read in the case the visit last page is older than 30 minutes. * * This function tries to generate actions that use the features of Piwik (campaigns, downloads, outlinks, action_name set in the JS tag, etc.) * * @return void * */ protected function generateActionVisit() { // we don't keep the previous action values // reinit them to empty string $this->setCurrentRequest(Piwik_Tracker_Config::getInstance()->Tracker['download_url_var_name'], ''); $this->setCurrentRequest(Piwik_Tracker_Config::getInstance()->Tracker['outlink_url_var_name'], ''); $this->setCurrentRequest('action_name', ''); // generate new url referer ; case the visitor stays more than 30min // (when the visit is known this value will simply be ignored) $this->setCurrentRequest('urlref', $this->getRandom('urlref')); // generates the current URL $url = $this->getRandomUrlFromHost($this->host); // we generate a campaign $urlVars = $this->getRandom('piwik_vars_campaign'); // if we actually generated a campaign if (!empty($urlVars)) { // campaign name $urlValue = $this->getRandomString(5, 3, 'lower'); // add the parameter to the url $url .= '?' . $urlVars . '=' . $urlValue; // for a campaign of the CPC kind, we sometimes generate a keyword if ($urlVars == Piwik_Tracker_Config::getInstance()->Tracker['campaign_var_name'] && mt_rand(0, 1) == 0) { $url .= '&' . Piwik_Tracker_Config::getInstance()->Tracker['campaign_keyword_var_name'] . '=' . $this->getRandomString(6, 3, 'ALL'); } } else { // we generate a download Or Outlink parameter in the GET request so that // the current action is counted as a download action OR a outlink click action $GETParamToAdd = $this->getRandom('piwik_downloadOrOutlink'); if (!empty($GETParamToAdd)) { $possibleDownloadHosts = array('http://piwik.org/', $this->host); $nameDownload = $this->getRandomUrlFromHost($possibleDownloadHosts[mt_rand(0, 1)]); $extensions = array('.zip', '.tar.gz'); $nameDownload .= $extensions[mt_rand(0, 1)]; $urlValue = $nameDownload; // add the parameter to the url $this->setCurrentRequest($GETParamToAdd, $urlValue); } elseif (rand(0, 2) == 1) { $this->setCurrentRequest('action_name', $this->getRandomString(1, 1)); } } $this->setCurrentRequest('url', $url); // setup the title of the page $this->setCurrentRequest('title', $this->getRandomString(15, 5)); }
/** * Generates the name of the action from the URL or the specified name. * Sets the name as $this->actionName * * @return void */ protected function extractUrlAndActionNameFromRequest() { // download? $downloadVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_url_var_name']; $downloadUrl = Piwik_Common::getRequestVar($downloadVariableName, '', 'string', $this->request); if (!empty($downloadUrl)) { $actionType = self::TYPE_DOWNLOAD; $url = $downloadUrl; } // outlink? if (empty($actionType)) { $outlinkVariableName = Piwik_Tracker_Config::getInstance()->Tracker['outlink_url_var_name']; $outlinkUrl = Piwik_Common::getRequestVar($outlinkVariableName, '', 'string', $this->request); if (!empty($outlinkUrl)) { $actionType = self::TYPE_OUTLINK; $url = $outlinkUrl; } } // defaults to page view if (empty($actionType)) { $actionType = self::TYPE_ACTION; $url = Piwik_Common::getRequestVar('url', '', 'string', $this->request); $actionName = Piwik_Common::getRequestVar('action_name', '', 'string', $this->request); if (empty($actionName)) { $cleanedUrl = str_replace(array("\n", "\r", "\t"), "", $url); $actionName = Piwik_Common::getPathAndQueryFromUrl($cleanedUrl); // in case the $actionName is empty or ending with a slash, // we append the defaultActionName: a/b/ becomes a/b/index if (empty($actionName) || substr($actionName, -1) == '/') { $actionName .= $this->getDefaultActionName(); } } // get the delimiter, by default '/' $actionCategoryDelimiter = Piwik_Tracker_Config::getInstance()->General['action_category_delimiter']; // create an array of the categories delimited by the delimiter $split = explode($actionCategoryDelimiter, $actionName); // trim every category $split = array_map('trim', $split); // remove empty categories $split = array_filter($split, 'strlen'); // rebuild the name from the array of cleaned categories $actionName = implode($actionCategoryDelimiter, $split); } $url = trim($url); $url = str_replace(array("\n", "\r"), "", $url); if (empty($actionName)) { $actionName = $url; } return array('name' => $actionName, 'type' => $actionType, 'url' => $url); }
/** * Hook on Tracker.saveVisitorInformation to anonymize visitor IP addresses */ function anonymizeVisitorIpAddress($notification) { $visitorInfo =& $notification->getNotificationObject(); $visitorInfo['location_ip'] = self::applyIPMask($visitorInfo['location_ip'], Piwik_Tracker_Config::getInstance()->Tracker['ip_address_mask_length']); }
/** * Returns a non-proxy IP address from header * * @param string $default Default value to return if no matching proxy header * @param array $proxyHeaders List of proxy headers * @return string */ static public function getNonProxyIpFromHeader($default, $proxyHeaders) { $proxyIps = null; if(!empty($GLOBALS['PIWIK_TRACKER_MODE'])) { $proxyIps = @Piwik_Tracker_Config::getInstance()->General['proxy_ips']; } else { $config = Zend_Registry::get('config'); if($config !== false && isset($config->General->proxy_ips)) { $proxyIps = $config->General->proxy_ips->toArray(); } } if(!is_array($proxyIps)) { $proxyIps = array(); } $proxyIps[] = $default; // examine proxy headers foreach($proxyHeaders as $proxyHeader) { if(!empty($_SERVER[$proxyHeader])) { $proxyIp = self::getLastIpFromList($_SERVER[$proxyHeader], $proxyIps); if(strlen($proxyIp) && stripos($proxyIp, 'unknown') === false) { return $proxyIp; } } } return $default; }
function recordGoals($idSite, $visitorInformation, $visitCustomVariables, $action, $referrerTimestamp, $referrerUrl, $referrerCampaignName, $referrerCampaignKeyword) { $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Piwik_Common::getCountry(Piwik_Common::getBrowserLanguage(), $enableLanguageToCountryGuess = Piwik_Tracker_Config::getInstance()->Tracker['enable_language_to_country_guess'], $visitorInformation['location_ip']); $location_continent = isset($visitorInformation['location_continent']) ? $visitorInformation['location_continent'] : Piwik_Common::getContinent($location_country); $goal = array('idvisit' => $visitorInformation['idvisit'], 'idsite' => $idSite, 'idvisitor' => $visitorInformation['idvisitor'], 'server_time' => Piwik_Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']), 'location_country' => $location_country, 'location_continent' => $location_continent, 'visitor_returning' => $visitorInformation['visitor_returning'], 'visitor_days_since_first' => $visitorInformation['visitor_days_since_first'], 'visitor_count_visits' => $visitorInformation['visitor_count_visits']); // Attributing the correct Referrer to this conversion. // Priority order is as follows: // 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']; // 1) Campaigns from 1st party cookie if (!empty($referrerCampaignName)) { $type = Piwik_Common::REFERER_TYPE_CAMPAIGN; $name = $referrerCampaignName; $keyword = $referrerCampaignKeyword; $time = $referrerTimestamp; } elseif (!empty($referrerUrl)) { $referrer = new Piwik_Tracker_Visit_Referer(); $referrer = $referrer->getRefererInformation($referrerUrl, $currentUrl = '', $idSite); // if the parsed referer is interesting enough, ie. website or search engine if (in_array($referrer['referer_type'], array(Piwik_Common::REFERER_TYPE_SEARCH_ENGINE, Piwik_Common::REFERER_TYPE_WEBSITE))) { $type = $referrer['referer_type']; $name = $referrer['referer_name']; $keyword = $referrer['referer_keyword']; $time = $referrerTimestamp; } } $goal += array('referer_type' => $type, 'referer_name' => $name, 'referer_keyword' => $keyword, 'referer_visit_server_date' => date("Y-m-d", $time)); $goal += $visitCustomVariables; foreach ($this->convertedGoals as $convertedGoal) { printDebug("- Goal " . $convertedGoal['idgoal'] . " matched. Recording..."); $newGoal = $goal; $newGoal['idgoal'] = $convertedGoal['idgoal']; $newGoal['url'] = $convertedGoal['url']; $newGoal['revenue'] = $convertedGoal['revenue']; if (!is_null($action)) { $newGoal['idaction_url'] = $action->getIdActionUrl(); $newGoal['idlink_va'] = $action->getIdLinkVisitAction(); } // If multiple Goal conversions per visit, set a cache buster $newGoal['buster'] = $convertedGoal['allow_multiple'] == 0 ? '0' : $visitorInformation['visit_last_action_time']; $newGoalDebug = $newGoal; $newGoalDebug['idvisitor'] = bin2hex($newGoalDebug['idvisitor']); printDebug($newGoalDebug); $fields = implode(", ", array_keys($newGoal)); $bindFields = substr(str_repeat("?,", count($newGoal)), 0, -1); $sql = "INSERT IGNORE INTO " . Piwik_Common::prefixTable('log_conversion') . "\t\n\t\t\t\t\t({$fields}) VALUES ({$bindFields}) "; $bind = array_values($newGoal); Piwik_Tracker::getDatabase()->query($sql, $bind); } }
/** * Get salt from [superuser] section * * @return string */ public static function getSalt() { static $salt = null; if (is_null($salt)) { if (defined('PIWIK_TRACKER_MODE') && PIWIK_TRACKER_MODE) { $salt = Piwik_Tracker_Config::getInstance()->superuser['salt']; } else { $config = Zend_Registry::get('config'); if ($config !== false) { $salt = $config->superuser->salt; } } } return $salt; }
/** * Sends http request using the specified transport method * * @param string $method * @param string $aUrl * @param int $timeout * @param string $userAgent * @param string $destinationPath * @param resource $file * @param int $followDepth * @return bool true (or string) on success; false on HTTP response error code (1xx or 4xx) * @throws Exception for all other errors */ static public function sendHttpRequestBy($method = 'socket', $aUrl, $timeout, $userAgent = null, $destinationPath = null, $file = null, $followDepth = 0, $acceptLanguage = false) { if ($followDepth > 5) { throw new Exception('Too many redirects ('.$followDepth.')'); } $strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen'; $contentLength = 0; $fileLength = 0; // Piwik services behave like a proxy, so we should act like one. $xff = 'X-Forwarded-For: ' . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] . ',' : '') . Piwik_IP::getIpFromHeader(); $via = 'Via: ' . (isset($_SERVER['HTTP_VIA']) && !empty($_SERVER['HTTP_VIA']) ? $_SERVER['HTTP_VIA'] . ', ' : '') . Piwik_Version::VERSION . ' Piwik' . ($userAgent ? " ($userAgent)" : ''); $acceptLanguage = $acceptLanguage ? 'Accept-Language:'.$acceptLanguage : ''; $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'Piwik/'.Piwik_Version::VERSION; // proxy configuration if(!empty($GLOBALS['PIWIK_TRACKER_MODE'])) { $proxyHost = Piwik_Tracker_Config::getInstance()->proxy['host']; $proxyPort = Piwik_Tracker_Config::getInstance()->proxy['port']; $proxyUser = Piwik_Tracker_Config::getInstance()->proxy['username']; $proxyPassword = Piwik_Tracker_Config::getInstance()->proxy['password']; } else { $config = Zend_Registry::get('config'); if($config !== false) { $proxyHost = $config->proxy->host; $proxyPort = $config->proxy->port; $proxyUser = $config->proxy->username; $proxyPassword = $config->proxy->password; } } if($method == 'socket') { // initialization $url = @parse_url($aUrl); if($url === false || !isset($url['scheme'])) { throw new Exception('Malformed URL: '.$aUrl); } if($url['scheme'] != 'http') { throw new Exception('Invalid protocol/scheme: '.$url['scheme']); } $host = $url['host']; $port = isset($url['port)']) ? $url['port'] : 80; $path = isset($url['path']) ? $url['path'] : '/'; if(isset($url['query'])) { $path .= '?'.$url['query']; } $errno = null; $errstr = null; $proxyAuth = null; if(!empty($proxyHost) && !empty($proxyPort)) { $connectHost = $proxyHost; $connectPort = $proxyPort; if(!empty($proxyUser) && !empty($proxyPassword)) { $proxyAuth = 'Proxy-Authorization: Basic '.base64_encode("$proxyUser:$proxyPassword") ."\r\n"; } $requestHeader = "GET $aUrl HTTP/1.1\r\n"; } else { $connectHost = $host; $connectPort = $port; $requestHeader = "GET $path HTTP/1.0\r\n"; } // connection attempt if (($fsock = @fsockopen($connectHost, $connectPort, $errno, $errstr, $timeout)) === false || !is_resource($fsock)) { if(is_resource($file)) { @fclose($file); } throw new Exception("Error while connecting to: $host. Please try again later. $errstr"); } // send HTTP request header $requestHeader .= "Host: $host".($port != 80 ? ':'.$port : '')."\r\n" .($proxyAuth ? $proxyAuth : '') .'User-Agent: '.$userAgent."\r\n" . ($acceptLanguage ? $acceptLanguage ."\r\n" : '') .$xff."\r\n" .$via."\r\n" ."Connection: close\r\n" ."\r\n"; fwrite($fsock, $requestHeader); $streamMetaData = array('timed_out' => false); @stream_set_blocking($fsock, true); @stream_set_timeout($fsock, $timeout); // process header $status = null; $expectRedirect = false; while(!feof($fsock)) { $line = fgets($fsock, 4096); $streamMetaData = @stream_get_meta_data($fsock); if($streamMetaData['timed_out']) { if(is_resource($file)) { @fclose($file); } @fclose($fsock); throw new Exception('Timed out waiting for server response'); } // a blank line marks the end of the server response header if(rtrim($line, "\r\n") == '') { break; } // parse first line of server response header if(!$status) { // expect first line to be HTTP response status line, e.g., HTTP/1.1 200 OK if(!preg_match('~^HTTP/(\d\.\d)\s+(\d+)(\s*.*)?~', $line, $m)) { if(is_resource($file)) { @fclose($file); } @fclose($fsock); throw new Exception('Expected server response code. Got '.rtrim($line, "\r\n")); } $status = (integer) $m[2]; // Informational 1xx or Client Error 4xx if ($status < 200 || $status >= 400) { if(is_resource($file)) { @fclose($file); } @fclose($fsock); return false; } continue; } // handle redirect if(preg_match('/^Location:\s*(.+)/', rtrim($line, "\r\n"), $m)) { if(is_resource($file)) { @fclose($file); } @fclose($fsock); // Successful 2xx vs Redirect 3xx if($status < 300) { throw new Exception('Unexpected redirect to Location: '.rtrim($line).' for status code '.$status); } return self::sendHttpRequestBy($method, trim($m[1]), $timeout, $userAgent, $destinationPath, $file, $followDepth+1, $acceptLanguage); } // save expected content length for later verification if(preg_match('/^Content-Length:\s*(\d+)/', $line, $m)) { $contentLength = (integer) $m[1]; } } if(feof($fsock)) { throw new Exception('Unexpected end of transmission'); } // process content/body $response = ''; while(!feof($fsock)) { $line = fread($fsock, 8192); $streamMetaData = @stream_get_meta_data($fsock); if($streamMetaData['timed_out']) { if(is_resource($file)) { @fclose($file); } @fclose($fsock); throw new Exception('Timed out waiting for server response'); } $fileLength += $strlen($line); if(is_resource($file)) { // save to file fwrite($file, $line); } else { // concatenate to response string $response .= $line; } } // determine success or failure @fclose(@$fsock); } else if($method == 'fopen') { $response = false; // we make sure the request takes less than a few seconds to fail // we create a stream_context (works in php >= 5.2.1) // we also set the socket_timeout (for php < 5.2.1) $default_socket_timeout = @ini_get('default_socket_timeout'); @ini_set('default_socket_timeout', $timeout); $ctx = null; if(function_exists('stream_context_create')) { $stream_options = array( 'http' => array( 'header' => 'User-Agent: '.$userAgent."\r\n" .($acceptLanguage ? $acceptLanguage."\r\n" : '') .$xff."\r\n" .$via."\r\n", 'max_redirects' => 5, // PHP 5.1.0 'timeout' => $timeout, // PHP 5.2.1 ) ); if(!empty($proxyHost) && !empty($proxyPort)) { $stream_options['http']['proxy'] = 'tcp://'.$proxyHost.':'.$proxyPort; $stream_options['http']['request_fulluri'] = true; // required by squid proxy if(!empty($proxyUser) && !empty($proxyPassword)) { $stream_options['http']['header'] .= 'Proxy-Authorization: Basic '.base64_encode("$proxyUser:$proxyPassword")."\r\n"; } } $ctx = stream_context_create($stream_options); } // save to file if(is_resource($file)) { $handle = fopen($aUrl, 'rb', false, $ctx); while(!feof($handle)) { $response = fread($handle, 8192); $fileLength += $strlen($response); fwrite($file, $response); } fclose($handle); } else { $response = @file_get_contents($aUrl, 0, $ctx); $fileLength = $strlen($response); } // restore the socket_timeout value if(!empty($default_socket_timeout)) { @ini_set('default_socket_timeout', $default_socket_timeout); } } else if($method == 'curl') { $ch = @curl_init(); if(!empty($proxyHost) && !empty($proxyPort)) { @curl_setopt($ch, CURLOPT_PROXY, $proxyHost.':'.$proxyPort); if(!empty($proxyUser) && !empty($proxyPassword)) { // PROXYAUTH defaults to BASIC @curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyUser.':'.$proxyPassword); } } $curl_options = array( // internal to ext/curl CURLOPT_BINARYTRANSFER => is_resource($file), // curl options (sorted oldest to newest) CURLOPT_URL => $aUrl, CURLOPT_USERAGENT => $userAgent, CURLOPT_HTTPHEADER => array( $xff, $via, $acceptLanguage ), CURLOPT_HEADER => false, CURLOPT_CONNECTTIMEOUT => $timeout, ); @curl_setopt_array($ch, $curl_options); /* * use local list of Certificate Authorities, if available */ if(file_exists(PIWIK_INCLUDE_PATH . '/core/DataFiles/cacert.pem')) { @curl_setopt($ch, CURLOPT_CAINFO, PIWIK_INCLUDE_PATH . '/core/DataFiles/cacert.pem'); } /* * as of php 5.2.0, CURLOPT_FOLLOWLOCATION can't be set if * in safe_mode or open_basedir is set */ if((string)ini_get('safe_mode') == '' && ini_get('open_basedir') == '') { $curl_options = array( // curl options (sorted oldest to newest) CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5, ); @curl_setopt_array($ch, $curl_options); } if(is_resource($file)) { // write output directly to file @curl_setopt($ch, CURLOPT_FILE, $file); } else { // internal to ext/curl @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); } ob_start(); $response = @curl_exec($ch); ob_end_clean(); if($response === true) { $response = ''; } else if($response === false) { $errstr = curl_error($ch); if($errstr != '') { throw new Exception('curl_exec: '.$errstr); } $response = ''; } $contentLength = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); $fileLength = is_resource($file) ? curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD) : $strlen($response); @curl_close($ch); unset($ch); } else { throw new Exception('Invalid request method: '.$method); } if(is_resource($file)) { fflush($file); @fclose($file); $fileSize = filesize($destinationPath); if((($contentLength > 0) && ($fileLength != $contentLength)) || ($fileSize != $fileLength)) { throw new Exception('File size error: '.$destinationPath.'; expected '.$contentLength.' bytes; received '.$fileLength.' bytes; saved '.$fileSize.' bytes to file'); } return true; } if(($contentLength > 0) && ($fileLength != $contentLength)) { throw new Exception('Content length error: expected '.$contentLength.' bytes; received '.$fileLength.' bytes'); } return trim($response); }
/** * Records one or several goals matched in this request. */ public function recordGoals($idSite, $visitorInformation, $visitCustomVariables, $action, $referrerTimestamp, $referrerUrl, $referrerCampaignName, $referrerCampaignKeyword) { $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Piwik_Common::getCountry(Piwik_Common::getBrowserLanguage(), $enableLanguageToCountryGuess = Piwik_Tracker_Config::getInstance()->Tracker['enable_language_to_country_guess'], $visitorInformation['location_ip']); $location_continent = isset($visitorInformation['location_continent']) ? $visitorInformation['location_continent'] : Piwik_Common::getContinent($location_country); $goal = array('idvisit' => $visitorInformation['idvisit'], 'idsite' => $idSite, 'idvisitor' => $visitorInformation['idvisitor'], 'server_time' => Piwik_Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']), 'location_country' => $location_country, 'location_continent' => $location_continent, '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']); // Copy Custom Variables from Visit row to the Goal conversion for ($i = 1; $i <= Piwik_Tracker::MAX_CUSTOM_VARIABLES; $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]; } } // Otherwise, set the Custom Variables found in the cookie sent with this request $goal += $visitCustomVariables; // 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($refererCampaignName) && $type == Piwik_Common::REFERER_TYPE_CAMPAIGN && !empty($name)) { // Use default values per above } elseif (!empty($referrerCampaignName)) { $type = Piwik_Common::REFERER_TYPE_CAMPAIGN; $name = $referrerCampaignName; $keyword = $referrerCampaignKeyword; $time = $referrerTimestamp; } elseif (!empty($referrerUrl)) { $referrer = new Piwik_Tracker_Visit_Referer(); $referrer = $referrer->getRefererInformation($referrerUrl, $currentUrl = '', $idSite); // if the parsed referer is interesting enough, ie. website or search engine if (in_array($referrer['referer_type'], array(Piwik_Common::REFERER_TYPE_SEARCH_ENGINE, Piwik_Common::REFERER_TYPE_WEBSITE))) { $type = $referrer['referer_type']; $name = $referrer['referer_name']; $keyword = $referrer['referer_keyword']; $time = $referrerTimestamp; } } $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); } }
/** * Returns the best possible IP of the current user, in the format A.B.C.D * For example, this could be the proxy client's IP address. * * @return string ip */ public static function getIpString() { static $clientHeaders = null; if (is_null($clientHeaders)) { if (!empty($GLOBALS['PIWIK_TRACKER_MODE'])) { $clientHeaders = @Piwik_Tracker_Config::getInstance()->General['proxy_client_headers']; } else { $config = Zend_Registry::get('config'); if ($config !== false && isset($config->General->proxy_client_headers)) { $clientHeaders = $config->General->proxy_client_headers->toArray(); } } if (!is_array($clientHeaders)) { $clientHeaders = array(); } } $default = '0.0.0.0'; if (isset($_SERVER['REMOTE_ADDR'])) { $default = $_SERVER['REMOTE_ADDR']; } return self::getProxyFromHeader($default, $clientHeaders); }
/** * Returns true if the last action was done during the last 30 minutes * @return bool */ protected function isLastActionInTheSameVisit() { return isset($this->visitorInfo['visit_last_action_time']) && $this->visitorInfo['visit_last_action_time'] > $this->getCurrentTimestamp() - Piwik_Tracker_Config::getInstance()->Tracker['visit_standard_length']; }
/** * Hook on Tracker.Visit.setVisitorIp to anonymize visitor IP addresses */ function setVisitorIpAddress($notification) { $ip =& $notification->getNotificationObject(); $ip = self::applyIPMask($ip, Piwik_Tracker_Config::getInstance()->Tracker['ip_address_mask_length']); }
protected function authenticateSuperUserOrAdmin() { $tokenAuth = Piwik_Common::getRequestVar('token_auth', false); if ($tokenAuth) { $superUserLogin = Piwik_Tracker_Config::getInstance()->superuser['login']; $superUserPassword = Piwik_Tracker_Config::getInstance()->superuser['password']; if (md5($superUserLogin . $superUserPassword) == $tokenAuth) { return true; } // Now checking the list of admin token_auth cached in the Tracker config file $idSite = Piwik_Common::getRequestVar('idsite', false, 'int', $this->request); if (!empty($idSite) && $idSite > 0) { $website = Piwik_Common::getCacheWebsiteAttributes($idSite); $adminTokenAuth = $website['admin_token_auth']; if (in_array($tokenAuth, $adminTokenAuth)) { return true; } } printDebug("token_auth = {$tokenAuth} - Warning: Super User / Admin was NOT authenticated"); } return false; }
/** * This method allows to set custom IP + server time when using Tracking API. * These two attributes can be only set by the Super User (passing token_auth). */ protected function handleTrackingApi() { $shouldAuthenticate = Piwik_Tracker_Config::getInstance()->Tracker['tracking_requests_require_authentication']; if ($shouldAuthenticate) { if (!$this->authenticateSuperUserOrAdmin()) { return; } printDebug("token_auth is authenticated!"); } else { printDebug("token_auth authentication not required"); } // Custom IP to use for this visitor $customIp = Piwik_Common::getRequestVar('cip', false, 'string', $this->request); if (!empty($customIp)) { $this->setForceIp($customIp); } // Custom server date time to use $customDatetime = Piwik_Common::getRequestVar('cdt', false, 'string', $this->request); if (!empty($customDatetime)) { $this->setForceDateTime($customDatetime); } // Forced Visitor ID to record the visit / action $customVisitorId = Piwik_Common::getRequestVar('cid', false, 'string', $this->request); if (!empty($customVisitorId)) { $this->setForceVisitorId($customVisitorId); } }
protected function handleDisabledTracker() { $saveStats = Piwik_Tracker_Config::getInstance()->Tracker['record_statistics']; if ($saveStats == 0) { $this->setState(self::STATE_LOGGING_DISABLE); } }
/** * Generates the name of the action from the URL or the specified name. * Sets the name as $this->actionName * * @return array */ protected function extractUrlAndActionNameFromRequest() { $actionName = null; // download? $downloadUrl = Piwik_Common::getRequestVar('download', '', 'string', $this->request); if (!empty($downloadUrl)) { $actionType = self::TYPE_DOWNLOAD; $url = $downloadUrl; } // outlink? if (empty($actionType)) { $outlinkUrl = Piwik_Common::getRequestVar('link', '', 'string', $this->request); if (!empty($outlinkUrl)) { $actionType = self::TYPE_OUTLINK; $url = $outlinkUrl; } } $actionName = Piwik_Common::getRequestVar('action_name', '', 'string', $this->request); // defaults to page view if (empty($actionType)) { $actionType = self::TYPE_ACTION_URL; $url = Piwik_Common::getRequestVar('url', '', 'string', $this->request); // get the delimiter, by default '/'; BC, we read the old action_category_delimiter first (see #1067) $actionCategoryDelimiter = isset(Piwik_Tracker_Config::getInstance()->General['action_category_delimiter']) ? Piwik_Tracker_Config::getInstance()->General['action_category_delimiter'] : Piwik_Tracker_Config::getInstance()->General['action_url_category_delimiter']; // create an array of the categories delimited by the delimiter $split = explode($actionCategoryDelimiter, $actionName); // trim every category $split = array_map('trim', $split); // remove empty categories $split = array_filter($split, 'strlen'); // rebuild the name from the array of cleaned categories $actionName = implode($actionCategoryDelimiter, $split); } $url = trim($url); $url = str_replace(array("\n", "\r"), "", $url); $actionName = trim($actionName); $actionName = str_replace(array("\n", "\r"), "", $actionName); return array('name' => empty($actionName) ? '' : $actionName, 'type' => $actionType, 'url' => $url); }
function recordGoals($visitorInformation, $action) { $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Piwik_Common::getCountry(Piwik_Common::getBrowserLanguage(), $enableLanguageToCountryGuess = Piwik_Tracker_Config::getInstance()->Tracker['enable_language_to_country_guess']); $location_continent = isset($visitorInformation['location_continent']) ? $visitorInformation['location_continent'] : Piwik_Common::getContinent($location_country); $goal = array('idvisit' => $visitorInformation['idvisit'], 'idsite' => $visitorInformation['idsite'], 'visitor_idcookie' => $visitorInformation['visitor_idcookie'], 'server_time' => Piwik_Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']), 'visit_server_date' => $visitorInformation['visit_server_date'], 'location_country' => $location_country, 'location_continent' => $location_continent, 'visitor_returning' => $this->cookie->get(Piwik_Tracker::COOKIE_INDEX_VISITOR_RETURNING)); $referer_idvisit = $this->cookie->get(Piwik_Tracker::COOKIE_INDEX_REFERER_ID_VISIT); if ($referer_idvisit !== false) { $goal += array('referer_idvisit' => $referer_idvisit, 'referer_visit_server_date' => date("Y-m-d", $this->cookie->get(Piwik_Tracker::COOKIE_INDEX_REFERER_TIMESTAMP)), 'referer_type' => htmlspecialchars_decode($this->cookie->get(Piwik_Tracker::COOKIE_INDEX_REFERER_TYPE)), 'referer_name' => htmlspecialchars_decode($this->cookie->get(Piwik_Tracker::COOKIE_INDEX_REFERER_NAME)), 'referer_keyword' => htmlspecialchars_decode($this->cookie->get(Piwik_Tracker::COOKIE_INDEX_REFERER_KEYWORD))); } foreach ($this->convertedGoals as $convertedGoal) { printDebug("- Goal " . $convertedGoal['idgoal'] . " matched. Recording..."); $newGoal = $goal; $newGoal['idgoal'] = $convertedGoal['idgoal']; $newGoal['url'] = $convertedGoal['url']; $newGoal['revenue'] = $convertedGoal['revenue']; if (!is_null($action)) { $newGoal['idaction'] = $action->getIdAction(); $newGoal['idlink_va'] = $action->getIdLinkVisitAction(); } printDebug($newGoal); $fields = implode(", ", array_keys($newGoal)); $bindFields = substr(str_repeat("?,", count($newGoal)), 0, -1); try { Piwik_Tracker::getDatabase()->query("INSERT INTO " . Piwik_Common::prefixTable('log_conversion') . "\t({$fields}) \n\t\t\t\t\tVALUES ({$bindFields}) ", array_values($newGoal)); } catch (Exception $e) { if (strpos($e->getMessage(), '1062') !== false) { // integrity violation when same visit converts to the same goal twice printDebug("--> Goal already recorded for this (idvisit, idgoal)"); } else { throw $e; } } //$idlog_goal = Piwik_Tracker::getDatabase()->lastInsertId(); } }
/** * Records one or several goals matched in this request. */ public function recordGoals($idSite, $visitorInformation, $visitCustomVariables, $action, $referrerTimestamp, $referrerUrl, $referrerCampaignName, $referrerCampaignKeyword) { $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Piwik_Common::getCountry( Piwik_Common::getBrowserLanguage(), $enableLanguageToCountryGuess = Piwik_Tracker_Config::getInstance()->Tracker['enable_language_to_country_guess'], $visitorInformation['location_ip'] ); $location_continent = isset($visitorInformation['location_continent']) ? $visitorInformation['location_continent'] : Piwik_Common::getContinent($location_country); $goal = array( 'idvisit' => $visitorInformation['idvisit'], 'idsite' => $idSite, 'idvisitor' => $visitorInformation['idvisitor'], 'server_time' => Piwik_Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']), 'location_country' => $location_country, 'location_continent'=> $location_continent, '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'], ); // Attributing the correct Referrer to this conversion. // Priority order is as follows: // 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']; // 1) Campaigns from 1st party cookie if(!empty($referrerCampaignName)) { $type = Piwik_Common::REFERER_TYPE_CAMPAIGN; $name = $referrerCampaignName; $keyword = $referrerCampaignKeyword; $time = $referrerTimestamp; } // 2) Referrer URL parsing elseif(!empty($referrerUrl)) { $referrer = new Piwik_Tracker_Visit_Referer(); $referrer = $referrer->getRefererInformation($referrerUrl, $currentUrl = '', $idSite); // if the parsed referer is interesting enough, ie. website or search engine if(in_array($referrer['referer_type'], array(Piwik_Common::REFERER_TYPE_SEARCH_ENGINE, Piwik_Common::REFERER_TYPE_WEBSITE))) { $type = $referrer['referer_type']; $name = $referrer['referer_name']; $keyword = $referrer['referer_keyword']; $time = $referrerTimestamp; } } $goal += array( 'referer_type' => $type, 'referer_name' => $name, 'referer_keyword' => $keyword, // this field is currently unused 'referer_visit_server_date' => date("Y-m-d", $time), ); $goal += $visitCustomVariables; // 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); } }