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; }
/** * 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); } }
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)); }
/** * 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; }
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; } }
/** * 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; }
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; }
/** * 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; }
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')); }
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); }
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(); }