LocationProviders attempt to determine a visitor's location using visit information. All LocationProviders require a visitor's IP address, some require more, such as the browser language.
 /**
  * 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;
 }
Example #2
0
 /**
  * Attempts to fill in some missing information in a GeoIP location.
  *
  * This method will call LocationProvider::completeLocationResult and then
  * try to set the region name of the location if the country code & region
  * code are set.
  *
  * @param array $location The location information to modify.
  */
 public function completeLocationResult(&$location)
 {
     $this->fixupLocation($location);
     parent::completeLocationResult($location);
     // set region name if region code is set
     if (empty($location[self::REGION_NAME_KEY]) && !empty($location[self::REGION_CODE_KEY]) && !empty($location[self::COUNTRY_CODE_KEY])) {
         $countryCode = $location[self::COUNTRY_CODE_KEY];
         $regionCode = (string) $location[self::REGION_CODE_KEY];
         $location[self::REGION_NAME_KEY] = self::getRegionNameFromCodes($countryCode, $regionCode);
     }
 }
Example #3
0
 public function configureView(ViewDataTable $view)
 {
     $view->config->show_exclude_low_population = false;
     $view->config->addTranslation('label', $this->dimension->getName());
     $view->config->documentation = $this->documentation;
     $view->requestConfig->filter_limit = 5;
     if (LocationProvider::getCurrentProviderId() == LocationProvider\DefaultProvider::ID) {
         // if we're using the default location provider, add a note explaining how it works
         $footerMessage = Piwik::translate("General_Note") . ': ' . Piwik::translate('UserCountry_DefaultLocationProviderExplanation', array('<a rel="noreferrer"  target="_blank" href="http://piwik.org/docs/geo-locate/">', '</a>'));
         $view->config->show_footer_message = $footerMessage;
     }
 }
 /**
  * Test that redundant checks work.
  *
  * @group Plugins
  */
 public function testGeoIpUpdaterRedundantChecks()
 {
     GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
     LocationProvider::$providers = null;
     // create empty ISP & Org files
     $this->createEmptyISPOrgFiles();
     // run redundant checks
     $updater = new Piwik_UserCountry_GeoIPAutoUpdater_publictest();
     $updater->performRedundantDbChecks();
     // check that files are renamed correctly
     $this->checkBrokenGeoIPState();
     // create empty files again & run checks again
     $this->createEmptyISPOrgFiles();
     $updater->performRedundantDbChecks();
     // check that w/ broken files already there, redundant checks still work correctly
     $this->checkBrokenGeoIPState();
 }
 public function setUp()
 {
     self::downloadGeoIpDbs();
     parent::setUp();
     self::updateDatabase();
     // make sure site has an early enough creation date (for period selector tests)
     Db::get()->update(Common::prefixTable("site"), array('ts_created' => '2011-01-01'), "idsite = 1");
     // for proper geolocation
     LocationProvider::setCurrentProvider(LocationProvider\GeoIp\Php::ID);
     IPAnonymizer::deactivate();
     $this->addOverlayVisits();
     $this->addNewSitesForSiteSelector();
     DbHelper::createAnonymousUser();
     UsersManagerAPI::getInstance()->setSuperUserAccess('superUserLogin', true);
     SitesManagerAPI::getInstance()->updateSite(1, null, null, true);
     // create non super user
     UsersManagerAPI::getInstance()->addUser('oliverqueen', 'smartypants', '*****@*****.**');
     UsersManagerAPI::getInstance()->setUserAccess('oliverqueen', 'view', array(1));
 }
 public function execute()
 {
     $isPiwikInstalling = !Config::getInstance()->existsLocalConfig();
     if ($isPiwikInstalling) {
         // Skip the diagnostic if Piwik is being installed
         return array();
     }
     $label = $this->translator->translate('UserCountry_Geolocation');
     $currentProviderId = LocationProvider::getCurrentProviderId();
     $allProviders = LocationProvider::getAllProviderInfo();
     $isRecommendedProvider = in_array($currentProviderId, array(LocationProvider\GeoIp\Php::ID, $currentProviderId == LocationProvider\GeoIp\Pecl::ID));
     $isProviderInstalled = $allProviders[$currentProviderId]['status'] == LocationProvider::INSTALLED;
     if ($isRecommendedProvider && $isProviderInstalled) {
         return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_OK));
     }
     if ($isProviderInstalled) {
         $comment = $this->translator->translate('UserCountry_GeoIpLocationProviderNotRecomnended') . ' ';
         $comment .= $this->translator->translate('UserCountry_GeoIpLocationProviderDesc_ServerBased2', array('<a href="http://piwik.org/docs/geo-locate/" rel="noreferrer" target="_blank">', '', '', '</a>'));
     } else {
         $comment = $this->translator->translate('UserCountry_DefaultLocationProviderDesc1') . ' ';
         $comment .= $this->translator->translate('UserCountry_DefaultLocationProviderDesc2', array('<a href="http://piwik.org/docs/geo-locate/" rel="noreferrer" target="_blank">', '', '', '</a>'));
     }
     return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_WARNING, $comment));
 }
Example #7
0
File: API.php Project: piwik/piwik
 /**
  * Set the location provider
  *
  * @param string $providerId  The ID of the provider to use  eg 'default', 'geoip_php', ...
  * @throws Exception if ID is invalid
  */
 public function setLocationProvider($providerId)
 {
     Piwik::checkUserHasSuperUserAccess();
     if (!UserCountry::isGeoLocationAdminEnabled()) {
         throw new \Exception('Setting geo location has been disabled in config.');
     }
     $provider = LocationProvider::setCurrentProvider($providerId);
     if ($provider === false) {
         throw new Exception("Invalid provider ID: '{$providerId}'.");
     }
 }
 /**
  * Returns true if a GeoIP provider is installed & working, false if otherwise.
  *
  * @return bool
  */
 public function isGeoIPWorking()
 {
     $provider = LocationProvider::getCurrentProvider();
     return $provider instanceof GeoIp && $provider->isAvailable() === true && $provider->isWorking() === true;
 }
 /**
  * Tests a location provider using a test IP address and catches PHP errors
  * (ie, notices) if they occur. PHP error information is held in self::$unzipPhpError.
  *
  * @param LocationProvider $provider The provider to test.
  * @return array|false $location The result of geolocation. False if no location
  *                               can be found.
  */
 private static function getTestLocationCatchPhpErrors($provider)
 {
     // note: in most cases where this will fail, the error will usually be a PHP fatal error/notice.
     // in order to delete the files in such a case (which can be caused by a man-in-the-middle attack)
     // we need to catch them, so we set a new error handler.
     self::$unzipPhpError = null;
     set_error_handler(array('Piwik\\Plugins\\UserCountry\\GeoIPAutoUpdater', 'catchGeoIPError'));
     $location = $provider->getLocation(array('ip' => GeoIp::TEST_IP));
     restore_error_handler();
     return $location;
 }
Example #10
0
 private static function checkGeolocation(&$result)
 {
     $currentProviderId = LocationProvider::getCurrentProviderId();
     $allProviders = LocationProvider::getAllProviderInfo();
     $isRecommendedProvider = in_array($currentProviderId, array(LocationProvider\GeoIp\Php::ID, $currentProviderId == LocationProvider\GeoIp\Pecl::ID));
     $isProviderInstalled = $allProviders[$currentProviderId]['status'] == LocationProvider::INSTALLED;
     $result['geolocation_using_non_recommended'] = $result['geolocation_ok'] = false;
     if ($isRecommendedProvider && $isProviderInstalled) {
         $result['geolocation_ok'] = true;
     } elseif ($isProviderInstalled) {
         $result['geolocation_using_non_recommended'] = true;
     }
 }
Example #11
0
 /**
  * Uses a location provider to find/guess the location of an IP address.
  *
  * See LocationProvider::getLocation to see the details
  * of the result of this function.
  *
  * @param string $ip The IP address.
  * @param bool|string $provider The ID of the provider to use or false to use the
  *                               currently configured one.
  * @throws Exception
  * @return array|false
  */
 public function getLocationFromIP($ip, $provider = false)
 {
     Piwik::checkUserHasSomeViewAccess();
     if ($provider === false) {
         $provider = LocationProvider::getCurrentProviderId();
     }
     $oProvider = LocationProvider::getProviderById($provider);
     if ($oProvider === false) {
         throw new Exception("Cannot find the '{$provider}' provider. It is either an invalid provider " . "ID or the ID of a provider that is not working.");
     }
     $location = $oProvider->getLocation(array('ip' => $ip));
     if (empty($location)) {
         throw new Exception("Could not geolocate '{$ip}'!");
     }
     $location['ip'] = $ip;
     return $location;
 }
Example #12
0
 private function getProvider()
 {
     $id = Common::getCurrentLocationProviderId();
     $provider = LocationProvider::getProviderById($id);
     if ($provider === false) {
         $provider = $this->getDefaultProvider();
         Common::printDebug("GEO: no current location provider sent, falling back to default '{$id}' one.");
     }
     return $provider;
 }
 private function createGeolocator(OutputInterface $output, InputInterface $input)
 {
     $providerId = $input->getOption(self::PROVIDER_ARGUMENT);
     $geolocator = new VisitorGeolocator(LocationProvider::getProviderById($providerId) ?: null);
     $usedProvider = $geolocator->getProvider();
     if (!$usedProvider->isAvailable()) {
         throw new \InvalidArgumentException("The provider '{$providerId}' is not currently available, please make sure it is configured correctly.");
     }
     $isWorkingOrErrorMessage = $usedProvider->isWorking();
     if ($isWorkingOrErrorMessage !== true) {
         $errorMessage = "The provider '{$providerId}' does not appear to be working correctly. Details: {$isWorkingOrErrorMessage}";
         $forceGeolocation = $input->getOption(self::FORCE_OPTION);
         if ($forceGeolocation) {
             $output->writeln("<error>{$errorMessage}</error>");
             $output->writeln("<comment>Ignoring location provider issue, geolocating anyway due to --force option.</comment>");
         } else {
             throw new \InvalidArgumentException($errorMessage);
         }
     }
     return $geolocator;
 }
Example #14
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;
 }
Example #15
0
 public static function unsetLocationProvider()
 {
     try {
         LocationProvider::setCurrentProvider('default');
     } catch (Exception $e) {
         // ignore error
     }
 }
 private function getDefaultProvider()
 {
     return LocationProvider::getProviderById(DefaultProvider::ID);
 }
 private function setMockLocationProvider()
 {
     LocationProvider::setCurrentProvider('mock_provider');
     MockLocationProvider::$locations = array(self::makeLocation('Toronto', 'ON', 'CA', $lat = null, $long = null, $isp = 'comcast.net'), self::makeLocation('Nice', 'B8', 'FR', $lat = null, $long = null, $isp = 'comcast.net'), self::makeLocation('Melbourne', '07', 'AU', $lat = null, $long = null, $isp = 'awesomeisp.com'), self::makeLocation('Yokohama', '19', 'JP'));
 }
Example #18
0
 public function test_trackingWithLangParameter_ForwardsLangParameter_ToDefaultLocationProvider()
 {
     LocationProvider::setCurrentProvider(LocationProvider\DefaultProvider::ID);
     $urlToTest = "?idsite=1&rec=1&action_name=test&lang=fr-be";
     $response = $this->sendTrackingRequestByCurl($urlToTest);
     Fixture::checkResponse($response);
     $logVisitTable = Common::prefixTable('log_visit');
     $visitCount = Db::fetchOne("SELECT COUNT(*) FROM {$logVisitTable}");
     $this->assertEquals(1, $visitCount);
     $visitCountry = Db::fetchOne("SELECT location_country FROM {$logVisitTable}");
     $this->assertEquals('be', $visitCountry);
 }
Example #19
0
 public static function unsetLocationProvider()
 {
     // also fails on other PHP, is it really needed?
     return;
     // this randomly fails on PHP 5.3
     if (strpos(PHP_VERSION, '5.3') === 0) {
         return;
     }
     try {
         LocationProvider::setCurrentProvider('default');
     } catch (Exception $e) {
         // ignore error
     }
 }
 public function tearDown()
 {
     LocationProvider::$providers = null;
     GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
     ManyVisitsWithGeoIP::unsetLocationProvider();
 }