As of Piwik 1.3, IP addresses are stored in the DB has VARBINARY(16), and passed around in network address format which has the advantage of being in big-endian byte order. This allows for binary-safe string comparison of addresses (of the same length), even on Intel x86. As a matter of naming convention, we use $ip for the network address format and $ipString for the presentation format (i.e., human-readable form). We're not using the network address format (in_addr) for socket functions, so we don't have to worry about incompatibility with Windows UNICODE and inetPtonW().
Пример #1
0
 /**
  * Uses a GeoIP database to get a visitor's location based on their IP address.
  *
  * This function will return different results based on the data used and based
  * on how the GeoIP module is configured.
  *
  * If a region database is used, it may return the country code, region code,
  * city name, area code, latitude, longitude and postal code of the visitor.
  *
  * Alternatively, only the country code may be returned for another database.
  *
  * If your HTTP server is not configured to include all GeoIP information, some
  * information will not be available to Piwik.
  *
  * @param array $info Must have an 'ip' field.
  * @return array
  */
 public function getLocation($info)
 {
     $ip = $this->getIpFromInfo($info);
     // geoip modules that are built into servers can't use a forced IP. in this case we try
     // to fallback to another version.
     $myIP = IP::getIpFromHeader();
     if (!self::isSameOrAnonymizedIp($ip, $myIP) && (!isset($info['disable_fallbacks']) || !$info['disable_fallbacks'])) {
         Common::printDebug("The request is for IP address: " . $info['ip'] . " but your IP is: {$myIP}. GeoIP Server Module (apache/nginx) does not support this use case... ");
         $fallbacks = array(Pecl::ID, Php::ID);
         foreach ($fallbacks as $fallbackProviderId) {
             $otherProvider = LocationProvider::getProviderById($fallbackProviderId);
             if ($otherProvider) {
                 Common::printDebug("Used {$fallbackProviderId} to detect this visitor IP");
                 return $otherProvider->getLocation($info);
             }
         }
         Common::printDebug("FAILED to lookup the geo location of this IP address, as no fallback location providers is configured. We recommend to configure Geolocation PECL module to fix this error.");
         return false;
     }
     $result = array();
     foreach (self::$geoIpServerVars as $resultKey => $geoipVarName) {
         if (!empty($_SERVER[$geoipVarName])) {
             $result[$resultKey] = $_SERVER[$geoipVarName];
         }
     }
     foreach (self::$geoIpUtfServerVars as $resultKey => $geoipVarName) {
         if (!empty($_SERVER[$geoipVarName])) {
             $result[$resultKey] = utf8_encode($_SERVER[$geoipVarName]);
         }
     }
     $this->completeLocationResult($result);
     return $result;
 }
Пример #2
0
 function getIp()
 {
     if (isset($this->details['location_ip'])) {
         return IP::N2P($this->details['location_ip']);
     }
     return false;
 }
Пример #3
0
 public function enrichVisitWithLocation(&$visitorInfo, \Piwik\Tracker\Request $request)
 {
     require_once PIWIK_INCLUDE_PATH . "/plugins/UserCountry/LocationProvider.php";
     $ipAddress = IP::N2P(Config::getInstance()->Tracker['use_anonymized_ip_for_visit_enrichment'] == 1 ? $visitorInfo['location_ip'] : $request->getIp());
     $userInfo = array('lang' => $visitorInfo['location_browser_lang'], 'ip' => $ipAddress);
     $id = Common::getCurrentLocationProviderId();
     $provider = LocationProvider::getProviderById($id);
     if ($provider === false) {
         $id = DefaultProvider::ID;
         $provider = LocationProvider::getProviderById($id);
         Common::printDebug("GEO: no current location provider sent, falling back to default '{$id}' one.");
     }
     $location = $provider->getLocation($userInfo);
     // if we can't find a location, use default provider
     if ($location === false) {
         $defaultId = DefaultProvider::ID;
         $provider = LocationProvider::getProviderById($defaultId);
         $location = $provider->getLocation($userInfo);
         Common::printDebug("GEO: couldn't find a location with Geo Module '{$id}', using Default '{$defaultId}' provider as fallback...");
         $id = $defaultId;
     }
     Common::printDebug("GEO: Found IP {$ipAddress} location (provider '" . $id . "'): " . var_export($location, true));
     if (empty($location['country_code'])) {
         // sanity check
         $location['country_code'] = \Piwik\Tracker\Visit::UNKNOWN_CODE;
     }
     // add optional location components
     $this->updateVisitInfoWithLocation($visitorInfo, $location);
 }
Пример #4
0
 public function index()
 {
     Piwik::checkUserIsNotAnonymous();
     $view = new View('@MobileMessaging/index');
     $view->isSuperUser = Piwik::hasUserSuperUserAccess();
     $mobileMessagingAPI = API::getInstance();
     $view->delegatedManagement = $mobileMessagingAPI->getDelegatedManagement();
     $view->credentialSupplied = $mobileMessagingAPI->areSMSAPICredentialProvided();
     $view->accountManagedByCurrentUser = $view->isSuperUser || $view->delegatedManagement;
     $view->strHelpAddPhone = Piwik::translate('MobileMessaging_Settings_PhoneNumbers_HelpAdd', array(Piwik::translate('General_Settings'), Piwik::translate('MobileMessaging_SettingsMenu')));
     if ($view->credentialSupplied && $view->accountManagedByCurrentUser) {
         $view->provider = $mobileMessagingAPI->getSMSProvider();
         $view->creditLeft = $mobileMessagingAPI->getCreditLeft();
     }
     $view->smsProviders = SMSProvider::$availableSMSProviders;
     // construct the list of countries from the lang files
     $countries = array();
     foreach (Common::getCountriesList() as $countryCode => $continentCode) {
         if (isset(CountryCallingCodes::$countryCallingCodes[$countryCode])) {
             $countries[$countryCode] = array('countryName' => \Piwik\Plugins\UserCountry\countryTranslate($countryCode), 'countryCallingCode' => CountryCallingCodes::$countryCallingCodes[$countryCode]);
         }
     }
     $view->countries = $countries;
     $view->defaultCountry = Common::getCountry(LanguagesManager::getLanguageCodeForCurrentUser(), true, IP::getIpFromHeader());
     $view->phoneNumbers = $mobileMessagingAPI->getPhoneNumbers();
     $this->setBasicVariablesView($view);
     return $view->render();
 }
Пример #5
0
 /**
  * @dataProvider getipv6Addresses
  * @group Plugins
  */
 public function testApplyIPMask6($ip, $expected)
 {
     // each IP is tested with 0 to 4 octets masked
     for ($maskLength = 0; $maskLength < 4; $maskLength++) {
         $res = IPAnonymizer::applyIPMask(IP::P2N($ip), $maskLength);
         $this->assertEquals($expected[$maskLength], $res, "Got " . bin2hex($res) . ", Expected " . bin2hex($expected[$maskLength]) . ", Mask Level " . $maskLength);
     }
 }
Пример #6
0
 /**
  * Hook on Tracker.Visit.setVisitorIp to anomymize visitor IP addresses
  */
 public function setVisitorIpAddress(&$ip)
 {
     if (!$this->isActiveInTracker()) {
         Common::printDebug("Visitor IP was _not_ anonymized: " . IP::N2P($ip));
         return;
     }
     $originalIp = $ip;
     $ip = self::applyIPMask($ip, Config::getInstance()->Tracker['ip_address_mask_length']);
     Common::printDebug("Visitor IP (was: " . IP::N2P($originalIp) . ") has been anonymized: " . IP::N2P($ip));
 }
Пример #7
0
 /**
  * Hook on Tracker.Visit.setVisitorIp to anomymize visitor IP addresses
  */
 public function setVisitorIpAddress(&$ip)
 {
     if (!$this->isActive()) {
         Common::printDebug("Visitor IP was _not_ anonymized: " . IP::N2P($ip));
         return;
     }
     $originalIp = $ip;
     $privacyConfig = new Config();
     $ip = self::applyIPMask($ip, $privacyConfig->ipAddressMaskLength);
     Common::printDebug("Visitor IP (was: " . IP::N2P($originalIp) . ") has been anonymized: " . IP::N2P($ip));
 }
Пример #8
0
 private function sendMail($subject, $body)
 {
     $feedbackEmailAddress = Config::getInstance()->General['feedback_email_address'];
     $subject = '[ Feedback Feature - Piwik ] ' . $subject;
     $body = Common::unsanitizeInputValue($body) . "\n" . 'Piwik ' . Version::VERSION . "\n" . 'IP: ' . IP::getIpFromHeader() . "\n" . 'URL: ' . Url::getReferrer() . "\n";
     $mail = new Mail();
     $mail->setFrom(Piwik::getCurrentUserEmail());
     $mail->addTo($feedbackEmailAddress, 'Piwik Team');
     $mail->setSubject($subject);
     $mail->setBodyText($body);
     @$mail->send();
 }
Пример #9
0
 /**
  * Main view showing listing of websites and settings
  */
 public function index()
 {
     $view = new View('@SitesManager/index');
     Site::clearCache();
     if (Piwik::isUserIsSuperUser()) {
         $sitesRaw = API::getInstance()->getAllSites();
     } else {
         $sitesRaw = API::getInstance()->getSitesWithAdminAccess();
     }
     // Gets sites after Site.setSite hook was called
     $sites = array_values(Site::getSites());
     if (count($sites) != count($sitesRaw)) {
         throw new Exception("One or more website are missing or invalid.");
     }
     foreach ($sites as &$site) {
         $site['alias_urls'] = API::getInstance()->getSiteUrlsFromId($site['idsite']);
         $site['excluded_ips'] = explode(',', $site['excluded_ips']);
         $site['excluded_parameters'] = explode(',', $site['excluded_parameters']);
         $site['excluded_user_agents'] = explode(',', $site['excluded_user_agents']);
     }
     $view->adminSites = $sites;
     $view->adminSitesCount = count($sites);
     $timezones = API::getInstance()->getTimezonesList();
     $view->timezoneSupported = SettingsServer::isTimezoneSupportEnabled();
     $view->timezones = Common::json_encode($timezones);
     $view->defaultTimezone = API::getInstance()->getDefaultTimezone();
     $view->currencies = Common::json_encode(API::getInstance()->getCurrencyList());
     $view->defaultCurrency = API::getInstance()->getDefaultCurrency();
     $view->utcTime = Date::now()->getDatetime();
     $excludedIpsGlobal = API::getInstance()->getExcludedIpsGlobal();
     $view->globalExcludedIps = str_replace(',', "\n", $excludedIpsGlobal);
     $excludedQueryParametersGlobal = API::getInstance()->getExcludedQueryParametersGlobal();
     $view->globalExcludedQueryParameters = str_replace(',', "\n", $excludedQueryParametersGlobal);
     $globalExcludedUserAgents = API::getInstance()->getExcludedUserAgentsGlobal();
     $view->globalExcludedUserAgents = str_replace(',', "\n", $globalExcludedUserAgents);
     $view->globalSearchKeywordParameters = API::getInstance()->getSearchKeywordParametersGlobal();
     $view->globalSearchCategoryParameters = API::getInstance()->getSearchCategoryParametersGlobal();
     $view->isSearchCategoryTrackingEnabled = \Piwik\Plugin\Manager::getInstance()->isPluginActivated('CustomVariables');
     $view->allowSiteSpecificUserAgentExclude = API::getInstance()->isSiteSpecificUserAgentExcludeEnabled();
     $view->globalKeepURLFragments = API::getInstance()->getKeepURLFragmentsGlobal();
     $view->currentIpAddress = IP::getIpFromHeader();
     $view->showAddSite = (bool) Common::getRequestVar('showaddsite', false);
     $this->setBasicVariablesView($view);
     return $view->render();
 }
Пример #10
0
 private function setManageVariables(View $view)
 {
     $view->isSuperUser = Piwik::hasUserSuperUserAccess();
     $mobileMessagingAPI = API::getInstance();
     $view->delegatedManagement = $mobileMessagingAPI->getDelegatedManagement();
     $view->credentialSupplied = $mobileMessagingAPI->areSMSAPICredentialProvided();
     $view->accountManagedByCurrentUser = $view->isSuperUser || $view->delegatedManagement;
     $view->strHelpAddPhone = $this->translator->translate('MobileMessaging_Settings_PhoneNumbers_HelpAdd', array($this->translator->translate('General_Settings'), $this->translator->translate('MobileMessaging_SettingsMenu')));
     $view->creditLeft = 0;
     $currentProvider = '';
     if ($view->credentialSupplied && $view->accountManagedByCurrentUser) {
         $currentProvider = $mobileMessagingAPI->getSMSProvider();
         $view->creditLeft = $mobileMessagingAPI->getCreditLeft();
     }
     $view->delegateManagementOptions = array(array('key' => '0', 'value' => Piwik::translate('General_No'), 'description' => Piwik::translate('General_Default') . '. ' . Piwik::translate('MobileMessaging_Settings_LetUsersManageAPICredential_No_Help')), array('key' => '1', 'value' => Piwik::translate('General_Yes'), 'description' => Piwik::translate('MobileMessaging_Settings_LetUsersManageAPICredential_Yes_Help')));
     $providers = array();
     $providerOptions = array();
     foreach (SMSProvider::findAvailableSmsProviders() as $provider) {
         if (empty($currentProvider)) {
             $currentProvider = $provider->getId();
         }
         $providers[$provider->getId()] = $provider->getDescription();
         $providerOptions[$provider->getId()] = $provider->getId();
     }
     $view->provider = $currentProvider;
     $view->smsProviders = $providers;
     $view->smsProviderOptions = $providerOptions;
     $defaultCountry = Common::getCountry(LanguagesManager::getLanguageCodeForCurrentUser(), true, IP::getIpFromHeader());
     $view->defaultCallingCode = '';
     // construct the list of countries from the lang files
     $countries = array(array('key' => '', 'value' => ''));
     foreach ($this->regionDataProvider->getCountryList() as $countryCode => $continentCode) {
         if (isset(CountryCallingCodes::$countryCallingCodes[$countryCode])) {
             if ($countryCode == $defaultCountry) {
                 $view->defaultCallingCode = CountryCallingCodes::$countryCallingCodes[$countryCode];
             }
             $countries[] = array('key' => CountryCallingCodes::$countryCallingCodes[$countryCode], 'value' => \Piwik\Plugins\UserCountry\countryTranslate($countryCode));
         }
     }
     $view->countries = $countries;
     $view->phoneNumbers = $mobileMessagingAPI->getPhoneNumbers();
     $this->setBasicVariablesView($view);
 }
Пример #11
0
 private function printVisitorInformation()
 {
     $debugVisitInfo = $this->visitorInfo;
     $debugVisitInfo['idvisitor'] = bin2hex($debugVisitInfo['idvisitor']);
     $debugVisitInfo['config_id'] = bin2hex($debugVisitInfo['config_id']);
     $debugVisitInfo['location_ip'] = IP::N2P($debugVisitInfo['location_ip']);
     Common::printDebug($debugVisitInfo);
 }
Пример #12
0
 /**
  * Returns hostname, without port numbers
  *
  * @param $host
  * @return array
  */
 public static function getHostSanitized($host)
 {
     return IP::sanitizeIp($host);
 }
Пример #13
0
 /**
  * Returns the most accurate IP address availble for the current user, in
  * IPv4 format. This could be the proxy client's IP address.
  *
  * @return string IP address in presentation format.
  */
 public function getIpFromHeader()
 {
     Piwik::checkUserHasSomeViewAccess();
     return IP::getIpFromHeader();
 }
Пример #14
0
 /**
  * In the case of a new visit, we have to do the following actions:
  *
  * 1) Insert the new action
  *
  * 2) Insert the visit information
  *
  * @param Action $action
  * @param bool $visitIsConverted
  */
 protected function handleNewVisit($action, $visitIsConverted)
 {
     Common::printDebug("New Visit (IP = " . IP::N2P($this->getVisitorIp()) . ")");
     $this->visitorInfo = $this->getNewVisitorInformation($action);
     // Add Custom variable key,value to the visitor array
     $this->visitorInfo = array_merge($this->visitorInfo, $this->visitorCustomVariables);
     $this->visitorInfo['visit_goal_converted'] = $visitIsConverted ? 1 : 0;
     $this->visitorInfo['referer_name'] = substr($this->visitorInfo['referer_name'], 0, 70);
     $this->visitorInfo['referer_keyword'] = substr($this->visitorInfo['referer_keyword'], 0, 255);
     $this->visitorInfo['config_resolution'] = substr($this->visitorInfo['config_resolution'], 0, 9);
     /**
      * Triggered before a new [visit entity](/guides/persistence-and-the-mysql-backend#visits) is persisted.
      * 
      * This event can be used to modify the visit entity or add new information to it before it is persisted.
      * The UserCountry plugin, for example, uses this event to add location information for each visit.
      *
      * @param array &$visit The visit entity. Read [this](/guides/persistence-and-the-mysql-backend#visits) to see
      *                      what information it contains.
      * @param \Piwik\Tracker\Request $request An object describing the tracking request being processed.
      */
     Piwik::postEvent('Tracker.newVisitorInformation', array(&$this->visitorInfo, $this->request));
     $this->request->overrideLocation($this->visitorInfo);
     $this->printVisitorInformation();
     $idVisit = $this->insertNewVisit($this->visitorInfo);
     $this->visitorInfo['idvisit'] = $idVisit;
     $this->visitorInfo['visit_first_action_time'] = $this->request->getCurrentTimestamp();
     $this->visitorInfo['visit_last_action_time'] = $this->request->getCurrentTimestamp();
 }
Пример #15
0
 /**
  * In the case of a new visit, we have to do the following actions:
  *
  * 1) Insert the new action
  *
  * 2) Insert the visit information
  *
  * @param Visitor $visitor
  * @param Action $action
  * @param bool $visitIsConverted
  */
 protected function handleNewVisit($visitor, $action, $visitIsConverted)
 {
     Common::printDebug("New Visit (IP = " . IP::N2P($this->getVisitorIp()) . ")");
     $this->visitorInfo = $this->getNewVisitorInformation($visitor);
     // Add Custom variable key,value to the visitor array
     $this->visitorInfo = array_merge($this->visitorInfo, $this->visitorCustomVariables);
     $visitor->clearVisitorInfo();
     foreach ($this->visitorInfo as $key => $value) {
         $visitor->setVisitorColumn($key, $value);
     }
     $dimensions = $this->getAllVisitDimensions();
     $this->triggerHookOnDimensions($dimensions, 'onNewVisit', $visitor, $action);
     if ($visitIsConverted) {
         $this->triggerHookOnDimensions($dimensions, 'onConvertedVisit', $visitor, $action);
     }
     /**
      * Triggered before a new [visit entity](/guides/persistence-and-the-mysql-backend#visits) is persisted.
      *
      * This event can be used to modify the visit entity or add new information to it before it is persisted.
      * The UserCountry plugin, for example, uses this event to add location information for each visit.
      *
      * @param array &$visit The visit entity. Read [this](/guides/persistence-and-the-mysql-backend#visits) to see
      *                      what information it contains.
      * @param \Piwik\Tracker\Request $request An object describing the tracking request being processed.
      */
     Piwik::postEvent('Tracker.newVisitorInformation', array(&$this->visitorInfo, $this->request));
     $this->printVisitorInformation();
     $idVisit = $this->insertNewVisit($this->visitorInfo);
     $this->visitorInfo['idvisit'] = $idVisit;
     $this->visitorInfo['visit_first_action_time'] = $this->request->getCurrentTimestamp();
     $this->visitorInfo['visit_last_action_time'] = $this->request->getCurrentTimestamp();
     $visitor->setVisitorColumn('idvisit', $this->visitorInfo['idvisit']);
     $visitor->setVisitorColumn('visit_first_action_time', $this->visitorInfo['visit_first_action_time']);
     $visitor->setVisitorColumn('visit_last_action_time', $this->visitorInfo['visit_last_action_time']);
 }
Пример #16
0
        }
    }
    $f = fopen($clickheatConf['logPath'] . $final . '/' . date('Y-m-d') . '.log', 'a');
}
if (is_resource($f)) {
    $logMe = true;
    if (isset($_COOKIE['clickheat-admin'])) {
        echo 'OK, but click not logged as you selected it in the admin panel ("Log my clicks/Enregistrer mes clics")';
        $logMe = false;
    } elseif (IS_PIWIK_MODULE === true) {
        $site = (string) (int) $site;
        // prevents path injection
        if (file_exists(PIWIK_INCLUDE_PATH . '/tmp/cache/tracker/' . $site . '.php')) {
            require_once PIWIK_INCLUDE_PATH . '/tmp/cache/tracker/' . $site . '.php';
            if (isset($content['excluded_ips'])) {
                $ip = IPUtils::stringToBinaryIP(\Piwik\Network\IP::fromStringIP(IP::getIpFromHeader()));
                if (isIpInRange($ip, $content['excluded_ips']) === true) {
                    echo 'OK, but click not logged as you prevent this IP to be tracked in Piwik\'s configuration';
                    $logMe = false;
                }
            }
        }
    }
    if ($logMe === true) {
        echo 'OK';
        fputs($f, (int) $_GET['x'] . '|' . (int) $_GET['y'] . '|' . (int) $_GET['w'] . '|' . $browser . '|' . (int) $_GET['c'] . "\n");
    }
    fclose($f);
} else {
    echo 'KO, file not writable';
}
Пример #17
0
 $rows = Db::fetchAll("SELECT idvisit, location_ip, " . implode(',', array_keys($logVisitFieldsToUpdate)) . "\n\t\t\t\t\t\tFROM " . Common::prefixTable('log_visit') . "\n\t\t\t\t\t\tLIMIT {$start}, {$limit}");
 if (!count($rows)) {
     continue;
 }
 foreach ($rows as $row) {
     $fieldsToSet = array();
     foreach ($logVisitFieldsToUpdate as $field => $ignore) {
         if (empty($fieldsToSet[$field])) {
             $fieldsToSet[] = $field;
         }
     }
     // skip if it already has a location
     if (empty($fieldsToSet)) {
         continue;
     }
     $ip = IP::N2P($row['location_ip']);
     $location = $provider->getLocation(array('ip' => $ip));
     if (!empty($location[LocationProvider::COUNTRY_CODE_KEY])) {
         $location[LocationProvider::COUNTRY_CODE_KEY] = strtolower($location[LocationProvider::COUNTRY_CODE_KEY]);
     }
     $row['location_country'] = strtolower($row['location_country']);
     $columnsToSet = array();
     $bind = array();
     foreach ($logVisitFieldsToUpdate as $column => $locationKey) {
         if (!empty($location[$locationKey]) && $location[$locationKey] != $row[$column]) {
             $columnsToSet[] = $column . ' = ?';
             $bind[] = $location[$locationKey];
         }
     }
     if (empty($columnsToSet)) {
         continue;
Пример #18
0
 /**
  * Echo's a pretty formatted location using a specific LocationProvider.
  *
  * Input:
  *   The 'id' query parameter must be set to the ID of the LocationProvider to use.
  *
  * Output:
  *   The pretty formatted location that was obtained. Will be HTML.
  */
 public function getLocationUsingProvider()
 {
     $providerId = Common::getRequestVar('id');
     $provider = LocationProvider::getProviderById($providerId);
     if (empty($provider)) {
         throw new Exception("Invalid provider ID: '{$providerId}'.");
     }
     $location = $provider->getLocation(array('ip' => IP::getIpFromHeader(), 'lang' => Common::getBrowserLanguage(), 'disable_fallbacks' => true));
     $location = LocationProvider::prettyFormatLocation($location, $newline = '<br/>', $includeExtra = true);
     return $location;
 }
Пример #19
0
 /**
  * @return mixed|string
  * @throws Exception
  */
 public function getIpString()
 {
     $cip = $this->getParam('cip');
     if (empty($cip)) {
         return IP::getIpFromHeader();
     }
     if (!$this->isAuthenticated()) {
         Common::printDebug("WARN: Tracker API 'cip' was used with invalid token_auth");
         return IP::getIpFromHeader();
     }
     return $cip;
 }
Пример #20
0
 private function getDefaultIp()
 {
     return IP::getIpFromHeader();
 }
Пример #21
0
 /**
  * Returns an array mapping provider IDs w/ information about the provider,
  * for each location provider.
  *
  * The following information is provided for each provider:
  *   'id' - The provider's unique string ID.
  *   'title' - The provider's title.
  *   'description' - A description of how the location provider works.
  *   'status' - Either self::NOT_INSTALLED, self::INSTALLED or self::BROKEN.
  *   'statusMessage' - If the status is self::BROKEN, then the message describes why.
  *   'location' - A pretty formatted location of the current IP address
  *                (IP::getIpFromHeader()).
  *
  * An example result:
  * array(
  *     'geoip_php' => array('id' => 'geoip_php',
  *                          'title' => '...',
  *                          'desc' => '...',
  *                          'status' => GeoIp::BROKEN,
  *                          'statusMessage' => '...',
  *                          'location' => '...')
  *     'geoip_serverbased' => array(...)
  * )
  *
  * @param string $newline What to separate lines with in the pretty locations.
  * @param bool $includeExtra Whether to include ISP/Org info in formatted location.
  * @return array
  */
 public static function getAllProviderInfo($newline = "\n", $includeExtra = false)
 {
     $allInfo = array();
     foreach (self::getAllProviders() as $provider) {
         $info = $provider->getInfo();
         $status = self::INSTALLED;
         $location = false;
         $statusMessage = false;
         $availableOrMessage = $provider->isAvailable();
         if ($availableOrMessage !== true) {
             $status = self::NOT_INSTALLED;
             if (is_string($availableOrMessage)) {
                 $statusMessage = $availableOrMessage;
             }
         } else {
             $workingOrError = $provider->isWorking();
             if ($workingOrError === true) {
                 $locInfo = array('ip' => IP::getIpFromHeader(), 'lang' => Common::getBrowserLanguage(), 'disable_fallbacks' => true);
                 $location = $provider->getLocation($locInfo);
                 $location = self::prettyFormatLocation($location, $newline, $includeExtra);
             } else {
                 $status = self::BROKEN;
                 $statusMessage = $workingOrError;
             }
         }
         $info['status'] = $status;
         $info['statusMessage'] = $statusMessage;
         $info['location'] = $location;
         $allInfo[$info['order']] = $info;
     }
     ksort($allInfo);
     $result = array();
     foreach ($allInfo as $info) {
         $result[$info['id']] = $info;
     }
     return $result;
 }
Пример #22
0
 /**
  * Returns the current host.
  *
  * @param string $default Default value to return if host unknown
  * @param bool $checkTrustedHost Whether to do trusted host check. Should ALWAYS be true,
  *                               except in Controller.
  * @return string eg, `"example.org"` if the current URL is
  *                `"http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"`
  * @api
  */
 public static function getCurrentHost($default = 'unknown', $checkTrustedHost = true)
 {
     $hostHeaders = array();
     $config = Config::getInstance()->General;
     if (isset($config['proxy_host_headers'])) {
         $hostHeaders = $config['proxy_host_headers'];
     }
     if (!is_array($hostHeaders)) {
         $hostHeaders = array();
     }
     $host = self::getHost($checkTrustedHost);
     $default = Common::sanitizeInputValue($host ? $host : $default);
     return IP::getNonProxyIpFromHeader($default, $hostHeaders);
 }
Пример #23
0
 /**
  * Sends an 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
  * @param bool|string $acceptLanguage Accept-language header
  * @param bool $acceptInvalidSslCertificate Only used with $method == 'curl'. If set to true (NOT recommended!) the SSL certificate will not be checked
  * @param array|bool $byteRange For Range: header. Should be two element array of bytes, eg, array(0, 1024)
  *                                                  Doesn't work w/ fopen method.
  * @param bool $getExtendedInfo True to return status code, headers & response, false if just response.
  * @param string $httpMethod The HTTP method to use. Defaults to `'GET'`.
  *
  * @throws Exception
  * @return bool  true (or string/array) on success; false on HTTP response error code (1xx or 4xx)
  */
 public static function sendHttpRequestBy($method = 'socket', $aUrl, $timeout, $userAgent = null, $destinationPath = null, $file = null, $followDepth = 0, $acceptLanguage = false, $acceptInvalidSslCertificate = false, $byteRange = false, $getExtendedInfo = false, $httpMethod = 'GET')
 {
     if ($followDepth > 5) {
         throw new Exception('Too many redirects (' . $followDepth . ')');
     }
     $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'] . ',' : '') . IP::getIpFromHeader();
     if (empty($userAgent)) {
         $userAgent = self::getUserAgent();
     }
     $via = 'Via: ' . (isset($_SERVER['HTTP_VIA']) && !empty($_SERVER['HTTP_VIA']) ? $_SERVER['HTTP_VIA'] . ', ' : '') . Version::VERSION . ' ' . ($userAgent ? " ({$userAgent})" : '');
     // range header
     $rangeHeader = '';
     if (!empty($byteRange)) {
         $rangeHeader = 'Range: bytes=' . $byteRange[0] . '-' . $byteRange[1] . "\r\n";
     }
     // proxy configuration
     $proxyHost = Config::getInstance()->proxy['host'];
     $proxyPort = Config::getInstance()->proxy['port'];
     $proxyUser = Config::getInstance()->proxy['username'];
     $proxyPassword = Config::getInstance()->proxy['password'];
     $aUrl = trim($aUrl);
     // other result data
     $status = null;
     $headers = array();
     if ($method == 'socket') {
         if (!self::isSocketEnabled()) {
             // can be triggered in tests
             throw new Exception("HTTP socket support is not enabled (php function fsockopen is not available) ");
         }
         // 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;
         if (!empty($proxyHost) && !empty($proxyPort) || !empty($byteRange)) {
             $httpVer = '1.1';
         } else {
             $httpVer = '1.0';
         }
         $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 = "{$httpMethod} {$aUrl} HTTP/{$httpVer}\r\n";
         } else {
             $connectHost = $host;
             $connectPort = $port;
             $requestHeader = "{$httpMethod} {$path} HTTP/{$httpVer}\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" . $rangeHeader . "Connection: close\r\n" . "\r\n";
         fwrite($fsock, $requestHeader);
         $streamMetaData = array('timed_out' => false);
         @stream_set_blocking($fsock, true);
         if (function_exists('stream_set_timeout')) {
             @stream_set_timeout($fsock, $timeout);
         } elseif (function_exists('socket_set_timeout')) {
             @socket_set_timeout($fsock, $timeout);
         }
         // process header
         $status = null;
         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 = (int) $m[2];
                 // Informational 1xx or Client Error 4xx
                 if ($status < 200 || $status >= 400) {
                     if (is_resource($file)) {
                         @fclose($file);
                     }
                     @fclose($fsock);
                     if (!$getExtendedInfo) {
                         return false;
                     } else {
                         return array('status' => $status);
                     }
                 }
                 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, $acceptInvalidSslCertificate = false, $byteRange, $getExtendedInfo, $httpMethod);
             }
             // save expected content length for later verification
             if (preg_match('/^Content-Length:\\s*(\\d+)/', $line, $m)) {
                 $contentLength = (int) $m[1];
             }
             self::parseHeaderLine($headers, $line);
         }
         if (feof($fsock) && $httpMethod != 'HEAD') {
             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" . $rangeHeader, 'max_redirects' => 5, 'timeout' => $timeout));
                 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') {
                 if (!self::isCurlEnabled()) {
                     // can be triggered in tests
                     throw new Exception("CURL is not enabled in php.ini, but is being used.");
                 }
                 $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(CURLOPT_BINARYTRANSFER => is_resource($file), CURLOPT_URL => $aUrl, CURLOPT_USERAGENT => $userAgent, CURLOPT_HTTPHEADER => array($xff, $via, $rangeHeader, $acceptLanguage), CURLOPT_HEADER => is_resource($file) ? false : true, CURLOPT_CONNECTTIMEOUT => $timeout);
                 // Case core:archive command is triggering archiving on https:// and the certificate is not valid
                 if ($acceptInvalidSslCertificate) {
                     $curl_options += array(CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false);
                 }
                 @curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpMethod);
                 if ($httpMethod == 'HEAD') {
                     @curl_setopt($ch, CURLOPT_NOBODY, true);
                 }
                 @curl_setopt_array($ch, $curl_options);
                 self::configCurlCertificate($ch);
                 /*
                  * 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(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 . '. Hostname requested was: ' . UrlHelper::getHostFromUrl($aUrl));
                         }
                         $response = '';
                     } else {
                         $header = '';
                         // redirects are included in the output html, so we look for the last line that starts w/ HTTP/...
                         // to split the response
                         while (substr($response, 0, 5) == "HTTP/") {
                             list($header, $response) = explode("\r\n\r\n", $response, 2);
                         }
                         foreach (explode("\r\n", $header) as $line) {
                             self::parseHeaderLine($headers, $line);
                         }
                     }
                 }
                 $contentLength = @curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
                 $fileLength = is_resource($file) ? @curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD) : strlen($response);
                 $status = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
                 @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 (!$getExtendedInfo) {
         return trim($response);
     } else {
         return array('status' => $status, 'headers' => $headers, 'data' => $response);
     }
 }
Пример #24
0
 /**
  * Returns the hostname given the IP address string
  *
  * @param string $ip IP Address
  * @return string hostname (or human-readable IP address)
  */
 private function getHost($ip)
 {
     return trim(strtolower(@IP::getHostByAddr($ip)));
 }
Пример #25
0
 public function getIp()
 {
     if (!empty($this->enforcedIp)) {
         $ipString = $this->enforcedIp;
     } else {
         $ipString = IP::getIpFromHeader();
     }
     $ip = IP::P2N($ipString);
     return $ip;
 }
Пример #26
0
 /**
  * Sends email confirmation link for a password reset request.
  *
  * @param array $user User info for the requested password reset.
  */
 private function sendEmailConfirmationLink($user)
 {
     $login = $user['login'];
     $email = $user['email'];
     // construct a password reset token from user information
     $resetToken = self::generatePasswordResetToken($user);
     $ip = IP::getIpFromHeader();
     $url = Url::getCurrentUrlWithoutQueryString() . "?module=Login&action=confirmResetPassword&login="******"&resetToken=" . urlencode($resetToken);
     // send email with new password
     $mail = new Mail();
     $mail->addTo($email, $login);
     $mail->setSubject(Piwik::translate('Login_MailTopicPasswordChange'));
     $bodyText = str_replace('\\n', "\n", sprintf(Piwik::translate('Login_MailPasswordChangeBody'), $login, $ip, $url)) . "\n";
     $mail->setBodyText($bodyText);
     $fromEmailName = Config::getInstance()->General['login_password_recovery_email_name'];
     $fromEmailAddress = Config::getInstance()->General['login_password_recovery_email_address'];
     $mail->setFrom($fromEmailAddress, $fromEmailName);
     $replytoEmailName = Config::getInstance()->General['login_password_recovery_replyto_email_name'];
     $replytoEmailAddress = Config::getInstance()->General['login_password_recovery_replyto_email_address'];
     $mail->setReplyTo($replytoEmailAddress, $replytoEmailName);
     @$mail->send();
 }
Пример #27
0
 /**
  * Convert IP address (in network address format) to presentation format.
  * This is a backward compatibility function for code that only expects
  * IPv4 addresses (i.e., doesn't support IPv6).
  *
  * @see IP::N2P()
  *
  * This function does not support the long (or its string representation)
  * returned by the built-in ip2long() function, from Piwik 1.3 and earlier.
  *
  * @deprecated 1.4
  *
  * @param string $ip IP address in network address format
  * @return string
  */
 public static function long2ip($ip)
 {
     return IP::long2ip($ip);
 }
Пример #28
0
 /**
  * Tests if the IP is a valid IP, allowing wildcards, except in the first octet.
  * Wildcards can only be used from right to left, ie. 1.1.*.* is allowed, but 1.1.*.1 is not.
  *
  * @param string $ip IP address
  * @return bool
  */
 private function isValidIp($ip)
 {
     return IP::getIpsForRange($ip) !== false;
 }
 /**
  * Returns an IP address from an array that was passed into getLocation. This
  * will return an IPv4 address or false if the address is IPv6 (IPv6 is not
  * supported yet).
  *
  * @param  array $info Must have 'ip' key.
  * @return string|bool
  */
 protected function getIpFromInfo($info)
 {
     $ip = $info['ip'];
     if (IP::isMappedIPv4($ip)) {
         return IP::getIPv4FromMappedIPv6($ip);
     } else {
         if (IP::isIPv6($ip)) {
             return false;
         } else {
             return $ip;
         }
     }
 }
Пример #30
-1
 /**
  * send email to Piwik team and display nice thanks
  * @throws Exception
  */
 function sendFeedback()
 {
     $email = Common::getRequestVar('email', '', 'string');
     $body = Common::getRequestVar('body', '', 'string');
     $category = Common::getRequestVar('category', '', 'string');
     $nonce = Common::getRequestVar('nonce', '', 'string');
     $view = new View('@Feedback/sendFeedback');
     $view->feedbackEmailAddress = Config::getInstance()->General['feedback_email_address'];
     try {
         $minimumBodyLength = 40;
         if (strlen($body) < $minimumBodyLength || strpos($email, 'probe@') !== false || strpos($body, '&lt;probe') !== false) {
             throw new Exception(Piwik::translate('Feedback_ExceptionBodyLength', array($minimumBodyLength)));
         }
         if (!Piwik::isValidEmailString($email)) {
             throw new Exception(Piwik::translate('UsersManager_ExceptionInvalidEmail'));
         }
         if (preg_match('/https?:/i', $body)) {
             throw new Exception(Piwik::translate('Feedback_ExceptionNoUrls'));
         }
         if (!Nonce::verifyNonce('Feedback.sendFeedback', $nonce)) {
             throw new Exception(Piwik::translate('General_ExceptionNonceMismatch'));
         }
         Nonce::discardNonce('Feedback.sendFeedback');
         $mail = new Mail();
         $mail->setFrom(Common::unsanitizeInputValue($email));
         $mail->addTo($view->feedbackEmailAddress, 'Piwik Team');
         $mail->setSubject('[ Feedback form - Piwik ] ' . $category);
         $mail->setBodyText(Common::unsanitizeInputValue($body) . "\n" . 'Piwik ' . Version::VERSION . "\n" . 'IP: ' . IP::getIpFromHeader() . "\n" . 'URL: ' . Url::getReferrer() . "\n");
         @$mail->send();
     } catch (Exception $e) {
         $view->errorString = $e->getMessage();
         $view->message = $body;
     }
     return $view->render();
 }