diff options
author | diosmosis <diosmosis@users.noreply.github.com> | 2020-01-08 05:28:48 +0300 |
---|---|---|
committer | Thomas Steur <tsteur@users.noreply.github.com> | 2020-01-08 05:28:48 +0300 |
commit | 4ad9f4ac89e6cbdb7b7c50bed4155193eb762dcc (patch) | |
tree | 693f09b52652174d1cadafc0d4c605e50818f878 /plugins/GeoIp2 | |
parent | 0d2f4e2aaac43817b37f52789bc3c98e07540cfb (diff) |
Allow using and auto-updating dbip databases and default to db-ip.com lite in the UI (#15319)
Diffstat (limited to 'plugins/GeoIp2')
-rw-r--r-- | plugins/GeoIp2/GeoIP2AutoUpdater.php | 119 | ||||
-rw-r--r-- | plugins/GeoIp2/LocationProvider/GeoIp2.php | 63 | ||||
-rw-r--r-- | plugins/GeoIp2/LocationProvider/GeoIp2/Php.php | 108 | ||||
-rw-r--r-- | plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php | 2 | ||||
-rw-r--r-- | plugins/GeoIp2/lang/en.json | 6 |
5 files changed, 226 insertions, 72 deletions
diff --git a/plugins/GeoIp2/GeoIP2AutoUpdater.php b/plugins/GeoIp2/GeoIP2AutoUpdater.php index 9e2fe00f81..4af0e8c4b2 100644 --- a/plugins/GeoIp2/GeoIP2AutoUpdater.php +++ b/plugins/GeoIp2/GeoIP2AutoUpdater.php @@ -29,6 +29,7 @@ use Piwik\Scheduler\Schedule\Monthly; use Piwik\Scheduler\Schedule\Weekly; use Piwik\SettingsPiwik; use Piwik\Unzip; +use Psr\Log\LoggerInterface; /** * Used to automatically update installed GeoIP 2 databases, and manages the updater's @@ -56,15 +57,19 @@ class GeoIP2AutoUpdater extends Task */ public function __construct() { + $logger = StaticContainer::get(LoggerInterface::class); + if (!SettingsPiwik::isInternetEnabled()) { // no automatic updates possible if no internet available + $logger->info("Internet is disabled in INI config, cannot update GeoIP database."); return; } $schedulePeriodStr = self::getSchedulePeriod(); // created the scheduledtime instance, also, since GeoIP 2 updates are done on tuesdays, - // get new DBs on Wednesday + // get new DBs on Wednesday. For db-ip, the databases are updated daily, so it doesn't matter exactly + // when we download a new one. switch ($schedulePeriodStr) { case self::SCHEDULE_PERIOD_WEEKLY: $schedulePeriod = new Weekly(); @@ -122,12 +127,17 @@ class GeoIP2AutoUpdater extends Task */ protected function downloadFile($dbType, $url) { + $logger = StaticContainer::get(LoggerInterface::class); + $url = trim($url); + if ($this->isDbIpUrl($url)) { + $url = $this->getDbIpUrlWithLatestDate($url); + } $ext = GeoIP2AutoUpdater::getGeoIPUrlExtension($url); // NOTE: using the first item in $dbNames[$dbType] makes sure GeoLiteCity will be renamed to GeoIPCity - $zippedFilename = LocationProviderGeoIp2::$dbNames[$dbType][0] . '.' . $ext; + $zippedFilename = $this->getZippedFilenameToDownloadTo($url, $dbType, $ext); $zippedOutputPath = self::getTemporaryFolder($zippedFilename); @@ -135,6 +145,11 @@ class GeoIP2AutoUpdater extends Task // download zipped file to misc dir try { + $logger->info("Downloading {url} to {output}.", [ + 'url' => $url, + 'output' => $zippedOutputPath, + ]); + $success = Http::sendHttpRequest($url, $timeout = 3600, $userAgent = null, $zippedOutputPath); } catch (Exception $ex) { throw new Exception("GeoIP2AutoUpdater: failed to download '$url' to " @@ -149,7 +164,7 @@ class GeoIP2AutoUpdater extends Task Log::info("GeoIP2AutoUpdater: successfully downloaded '%s'", $url); try { - self::unzipDownloadedFile($zippedOutputPath, $dbType, $unlink = true); + self::unzipDownloadedFile($zippedOutputPath, $dbType, $url, $unlink = true); } catch (Exception $ex) { throw new Exception("GeoIP2AutoUpdater: failed to unzip '$zippedOutputPath' after " . "downloading " . "'$url': " . $ex->getMessage()); @@ -170,8 +185,11 @@ class GeoIP2AutoUpdater extends Task * @param bool $unlink Whether to unlink archive or not. * @throws Exception */ - public static function unzipDownloadedFile($path, $dbType, $unlink = false) + public static function unzipDownloadedFile($path, $dbType, $url, $unlink = false) { + $isDbIp = self::isDbIpUrl($url); + $isDbIpUnknownDbType = $isDbIp && substr($path, -5, 5) == '.mmdb'; + // extract file if (substr($path, -7, 7) == '.tar.gz') { // find the .dat file in the tar archive @@ -186,8 +204,12 @@ class GeoIP2AutoUpdater extends Task $fileToExtract = null; foreach ($content as $info) { $archivedPath = $info['filename']; - if (in_array(basename($archivedPath), LocationProviderGeoIp2::$dbNames[$dbType])) { - $fileToExtract = $archivedPath; + foreach (LocationProviderGeoIp2::$dbNames[$dbType] as $dbName) { + if (basename($archivedPath) === $dbName + || preg_match('/' . $dbName . '/', basename($archivedPath)) + ) { + $fileToExtract = $archivedPath; + } } } @@ -212,19 +234,30 @@ class GeoIP2AutoUpdater extends Task $fd = fopen($outputPath, 'wb'); fwrite($fd, $unzipped); fclose($fd); - } else if (substr($path, -3, 3) == '.gz') { + } else if (substr($path, -3, 3) == '.gz' + || $isDbIpUnknownDbType + ) { $unzip = Unzip::factory('gz', $path); - $dbFilename = basename($path); - $tempFilename = $dbFilename . '.new'; + if ($isDbIpUnknownDbType) { + $tempFilename = 'unzipped-temp-dbip-file.mmdb'; + } else { + $dbFilename = substr(basename($path), 0, -3); + $tempFilename = $dbFilename . '.new'; + } + $outputPath = self::getTemporaryFolder($tempFilename); $success = $unzip->extract($outputPath); - if ($success !== true) { throw new Exception(Piwik::translate('UserCountry_CannotUnzipDatFile', array("'$path'", $unzip->errorInfo()))); } + + if ($isDbIpUnknownDbType) { + $php = new Php([$dbType => [$outputPath]]); + $dbFilename = $php->detectDatabaseType($dbType) . '.mmdb'; + } } else { $ext = end(explode(basename($path), '.', 2)); throw new Exception(Piwik::translate('UserCountry_UnsupportedArchiveType', "'$ext'")); @@ -274,6 +307,8 @@ class GeoIP2AutoUpdater extends Task if ($unlink) { unlink($path); } + + self::renameAnyExtraGeolocationDatabases($dbFilename, $dbType); } catch (Exception $ex) { // remove downloaded files if (file_exists($outputPath)) { @@ -285,6 +320,32 @@ class GeoIP2AutoUpdater extends Task } } + private static function renameAnyExtraGeolocationDatabases($dbFilename, $dbType) + { + if (!in_array($dbFilename, LocationProviderGeoIp2::$dbNames[$dbType])) { + return; + } + + $logger = StaticContainer::get(LoggerInterface::class); + foreach (LocationProviderGeoIp2::$dbNames[$dbType] as $possibleName) { + if ($dbFilename == $possibleName) { + break; + } + + $pathToExistingFile = LocationProviderGeoIp2::getPathForGeoIpDatabase($possibleName); + if (file_exists($pathToExistingFile)) { + $newFilename = $pathToExistingFile . '.' . time() . '.old'; + $logger->info("Renaming old geolocation database file {old} to {rename} so new downloaded file {new} will be used.", [ + 'old' => $possibleName, + 'rename' => $newFilename, + 'new' => $dbFilename, + ]); + + rename($pathToExistingFile, $newFilename); // adding timestamp to avoid any potential race conditions + } + } + } + /** * Sets the options used by this class based on query parameter values. * @@ -469,7 +530,11 @@ class GeoIP2AutoUpdater extends Task } } - self::checkForSupportedArchiveType($ext); + if ('mmdb.gz' === $ext) { + $ext = 'gz'; + } + + self::checkForSupportedArchiveType($url, $ext); return $ext; } @@ -481,8 +546,12 @@ class GeoIP2AutoUpdater extends Task * @param string $ext The URL file's extension. * @throws \Exception */ - private static function checkForSupportedArchiveType($ext) + private static function checkForSupportedArchiveType($url, $ext) { + if ($ext === 'mmdb' && self::isDbIpUrl($url)) { + return; + } + if ($ext != 'tar.gz' && $ext != 'gz' && $ext != 'mmdb.gz' @@ -646,4 +715,30 @@ class GeoIP2AutoUpdater extends Task } throw new Exception("Unknown GeoIP 2 updater period found in database: %s", $updaterPeriod); } + + public static function getZippedFilenameToDownloadTo($url, $dbType, $ext) + { + if (self::isDbIpUrl($url)) { + if (preg_match('/(dbip-[a-zA-Z0-9_]+)(?:-lite)?-\d{4}-\d{2}/', $url, $matches)) { + $parts = explode('-', $matches[1]); + $filename = strtoupper($parts[0]) . '-' . ucfirst($parts[1]) . '.mmdb.' . $ext; + return $filename; + } else { + return basename($url); + } + } + + return LocationProviderGeoIp2::$dbNames[$dbType][0] . '.' . $ext; + } + + private function getDbIpUrlWithLatestDate($url) + { + $today = Date::today(); + return preg_replace('/-\d{4}-\d{2}\./', '-' . $today->toString('Y-m') . '.', $url); + } + + public static function isDbIpUrl($url) + { + return !! preg_match('/db-ip\.com/', $url); + } } diff --git a/plugins/GeoIp2/LocationProvider/GeoIp2.php b/plugins/GeoIp2/LocationProvider/GeoIp2.php index 6258a8cb9d..e4e9a7efa3 100644 --- a/plugins/GeoIp2/LocationProvider/GeoIp2.php +++ b/plugins/GeoIp2/LocationProvider/GeoIp2.php @@ -10,6 +10,7 @@ namespace Piwik\Plugins\GeoIp2\LocationProvider; use Exception; use Piwik\Container\StaticContainer; +use Piwik\Date; use Piwik\Option; use Piwik\Piwik; use Piwik\Plugins\UserCountry\LocationProvider; @@ -20,7 +21,9 @@ use Piwik\Plugins\UserCountry\LocationProvider; */ abstract class GeoIp2 extends LocationProvider { + /** @deprecated */ const GEO_LITE_URL = 'https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz'; + const TEST_IP = '194.57.91.215'; const SWITCH_TO_ISO_REGIONS_OPTION_NAME = 'usercountry.switchtoisoregions'; @@ -38,10 +41,19 @@ abstract class GeoIp2 extends LocationProvider * @var array */ public static $dbNames = array( - 'loc' => array('GeoIP2-City.mmdb', 'GeoIP2-City-Africa.mmdb', 'GeoIP2-City-Asia-Pacific.mmdb', 'GeoIP2-City-Europe.mmdb', 'GeoIP2-City-North-America.mmdb', 'GeoIP2-City-South-America.mmdb', 'GeoIP2-Enterprise.mmdb', 'GeoIP2-Country.mmdb', 'GeoLite2-City.mmdb', 'GeoLite2-Country.mmdb'), - 'isp' => array('GeoIP2-ISP.mmdb', 'GeoLite2-ASN.mmdb'), + 'loc' => array('GeoIP2-City.mmdb', 'DBIP-City.mmdb', 'DBIP-City-Lite.mmdb', 'DBIP-Country-Lite.mmdb', 'DBIP-Country.mmdb', + 'dbip-city-lite-\d{4}-\d{2}.mmdb', 'GeoIP2-City-Africa.mmdb', 'GeoIP2-City-Asia-Pacific.mmdb', 'GeoIP2-City-Europe.mmdb', + 'GeoIP2-City-North-America.mmdb', 'GeoIP2-City-South-America.mmdb', 'GeoIP2-Enterprise.mmdb', 'GeoIP2-Country.mmdb', + 'dbip-country-lite-\d{4}-\d{2}.mmdb', 'GeoLite2-City.mmdb', 'GeoLite2-Country.mmdb', 'DBIP-Enterprise.mmdb'), + 'isp' => array('GeoIP2-ISP.mmdb', 'GeoLite2-ASN.mmdb', 'DBIP-ISP.mmdb', 'GeoIP2-Enterprise.mmdb', 'DBIP-Enterprise.mmdb'), ); + public static function getDbIpLiteUrl($type = 'city') + { + $today = Date::today(); + return "https://download.db-ip.com/free/dbip-{$type}-lite-{$today->toString('Y-m')}.mmdb.gz"; + } + /** * Returns true if this provider has been setup correctly, the error message if not. * @@ -50,46 +62,16 @@ abstract class GeoIp2 extends LocationProvider public function isWorking() { // test with an example IP to make sure the provider is working - // NOTE: At the moment only country, region & city info is tested. try { - $supportedInfo = $this->getSupportedLocationInfo(); + $testIp = self::TEST_IP; - list($testIp, $expectedResult) = self::getTestIpAndResult(); - - // get location using test IP + // get location using test IP and check that some information was returned $location = $this->getLocation(array('ip' => $testIp)); - - // check that result is the same as expected - $isResultCorrect = true; - foreach ($expectedResult as $key => $value) { - // if this provider is not configured to support this information type, skip it - if (empty($supportedInfo[$key])) { - continue; - } - - if (empty($location[$key]) - || $location[$key] != $value - ) { - $isResultCorrect = false; - } - } + $location = array_filter($location); + $isResultCorrect = !empty($location); if (!$isResultCorrect) { - $unknown = Piwik::translate('General_Unknown'); - - $location = "'" - . (empty($location[self::CITY_NAME_KEY]) ? $unknown : $location[self::CITY_NAME_KEY]) - . ", " - . (empty($location[self::REGION_CODE_KEY]) ? $unknown : $location[self::REGION_CODE_KEY]) - . ", " - . (empty($location[self::COUNTRY_CODE_KEY]) ? $unknown : $location[self::COUNTRY_CODE_KEY]) - . "'"; - - $expectedLocation = "'" . $expectedResult[self::CITY_NAME_KEY] . ", " - . $expectedResult[self::REGION_CODE_KEY] . ", " - . $expectedResult[self::COUNTRY_CODE_KEY] . "'"; - - $bind = array($testIp, $location, $expectedLocation); + $bind = array($testIp); return Piwik::translate('UserCountry_TestIPLocatorFailed', $bind); } @@ -135,13 +117,14 @@ abstract class GeoIp2 extends LocationProvider * Returns test IP used by isWorking and expected result. * * @return array eg. array('1.2.3.4', array(self::COUNTRY_CODE_KEY => ...)) + * @deprecated */ - private static function getTestIpAndResult() + protected function getTestIpAndResult() { static $result = null; if (is_null($result)) { $expected = array(self::COUNTRY_CODE_KEY => 'FR', - self::REGION_CODE_KEY => 'BFC', + self::REGION_CODE_KEY => 'BFC', self::CITY_NAME_KEY => 'Besançon'); $result = array(self::TEST_IP, $expected); } @@ -178,7 +161,7 @@ abstract class GeoIp2 extends LocationProvider { foreach (self::$dbNames as $key => $names) { foreach ($names as $name) { - if ($name === $filename) { + if ($name === $filename || preg_match('/'.$name.'/', $filename)) { return $key; } } diff --git a/plugins/GeoIp2/LocationProvider/GeoIp2/Php.php b/plugins/GeoIp2/LocationProvider/GeoIp2/Php.php index 90823971ef..f2c145e35e 100644 --- a/plugins/GeoIp2/LocationProvider/GeoIp2/Php.php +++ b/plugins/GeoIp2/LocationProvider/GeoIp2/Php.php @@ -23,7 +23,7 @@ use Piwik\Plugins\Marketplace\Api\Exception; class Php extends GeoIp2 { const ID = 'geoip2php'; - const TITLE = 'GeoIP 2 (Php)'; + const TITLE = 'DBIP / GeoIP 2 (Php)'; /** * The GeoIP2 reader instances used. This array will contain at most two @@ -99,22 +99,30 @@ class Php extends GeoIp2 switch ($reader->metadata()->databaseType) { case 'GeoLite2-Country': case 'GeoIP2-Country': + case 'DBIP-Country-Lite': + case 'DBIP-Country': + case 'DBIP-Location (compat=Country)': $lookupResult = $reader->country($ip); $this->setCountryResults($lookupResult, $result); break; - case 'GeoIP2-Enterprise': case 'GeoLite2-City': + case 'DBIP-City-Lite': + case 'DBIP-City': case 'GeoIP2-City': case 'GeoIP2-City-Africa': case 'GeoIP2-City-Asia-Pacific': case 'GeoIP2-City-Europe': case 'GeoIP2-City-North-America': case 'GeoIP2-City-South-America': - if ($reader->metadata()->databaseType === 'GeoIP2-Enterprise') { - $lookupResult = $reader->enterprise($ip); - } else { - $lookupResult = $reader->city($ip); - } + case 'DBIP-Location (compat=City)': + $lookupResult = $reader->city($ip); + $this->setCountryResults($lookupResult, $result); + $this->setCityResults($lookupResult, $result); + break; + case 'GeoIP2-Enterprise': + case 'DBIP-Location-ISP (compat=Enterprise)': + case 'DBIP-Enterprise': + $lookupResult = $reader->enterprise($ip); $this->setCountryResults($lookupResult, $result); $this->setCityResults($lookupResult, $result); break; @@ -142,6 +150,15 @@ class Php extends GeoIp2 $result[self::ISP_KEY] = $lookupResult->autonomousSystemOrganization; $result[self::ORG_KEY] = $lookupResult->autonomousSystemOrganization; break; + case 'GeoIP2-Enterprise': + case 'DBIP-ISP (compat=Enterprise)': + case 'DBIP-Location-ISP (compat=Enterprise)': + case 'DBIP-ISP': + case 'DBIP-Enterprise': + $lookupResult = $ispGeoIp->enterprise($ip); + $result[self::ISP_KEY] = $lookupResult->traits->isp; + $result[self::ORG_KEY] = $lookupResult->traits->organization; + break; } } catch (AddressNotFoundException $e) { // ignore - do nothing @@ -156,6 +173,54 @@ class Php extends GeoIp2 return $result; } + /** + * Returns a generalized name for the type of GeoIP database that is configured to load. The result is suitable + * for use as a filename, is not the exact value of the databaseType metadata. + * + * @param string $dbType 'loc', 'isp', etc. + */ + public function detectDatabaseType($dbType) + { + $reader = $this->getGeoIpInstance($dbType); + if (empty($reader)) { + throw new \Exception("Unable to determine what type of database this is."); + } + + $specificDatabaseTypeMetadata = $reader->metadata()->databaseType; + switch ($specificDatabaseTypeMetadata) { + case 'DBIP-Country-Lite': + case 'DBIP-Location (compat=Country)': + return 'DBIP-Country'; + case 'DBIP-City-Lite': + case 'DBIP-Location (compat=City)': + return 'DBIP-City'; + case 'GeoLite2-Country': + return 'GeoIP2-Country'; + case 'DBIP-ISP (compat=Enterprise)': + return 'DBIP-ISP'; + case 'DBIP-Location-ISP (compat=Enterprise)': + return 'DBIP-Enterprise'; + case 'GeoLite2-City': + case 'GeoIP2-City-Africa': + case 'GeoIP2-City-Asia-Pacific': + case 'GeoIP2-City-Europe': + case 'GeoIP2-City-North-America': + case 'GeoIP2-City-South-America': + return 'GeoIP2-City'; + case 'GeoIP2-ISP': + case 'GeoLite2-ASN': + case 'DBIP-Country': + case 'DBIP-City': + case 'GeoIP2-City': + case 'GeoIP2-Enterprise': + case 'GeoIP2-Country': + case 'DBIP-ISP': + return $specificDatabaseTypeMetadata; + default: + throw new \Exception("Unknown database type: $specificDatabaseTypeMetadata"); + } + } + protected function setCountryResults($lookupResult, &$result) { $result[self::CONTINENT_NAME_KEY] = $lookupResult->continent->name; @@ -222,23 +287,29 @@ class Php extends GeoIp2 { $result = array(); - // country & continent info always available - $result[self::CONTINENT_CODE_KEY] = true; - $result[self::CONTINENT_NAME_KEY] = true; - $result[self::COUNTRY_CODE_KEY] = true; - $result[self::COUNTRY_NAME_KEY] = true; - $reader = $this->getGeoIpInstance($key = 'loc'); if ($reader) { + // country & continent info always available + $result[self::CONTINENT_CODE_KEY] = true; + $result[self::CONTINENT_NAME_KEY] = true; + $result[self::COUNTRY_CODE_KEY] = true; + $result[self::COUNTRY_NAME_KEY] = true; + switch ($reader->metadata()->databaseType) { case 'GeoIP2-Enterprise': case 'GeoLite2-City': + case 'DBIP-City-Lite': + case 'DBIP-City': case 'GeoIP2-City': case 'GeoIP2-City-Africa': case 'GeoIP2-City-Asia-Pacific': case 'GeoIP2-City-Europe': case 'GeoIP2-City-North-America': case 'GeoIP2-City-South-America': + case 'DBIP-Enterprise': + case 'DBIP-Location-ISP (compat=Enterprise)': + case 'DBIP-ISP (compat=Enterprise)': + case 'DBIP-Location (compat=City)': $result[self::REGION_CODE_KEY] = true; $result[self::REGION_NAME_KEY] = true; $result[self::CITY_NAME_KEY] = true; @@ -282,14 +353,19 @@ class Php extends GeoIp2 . Piwik::translate('UserCountry_HowToInstallGeoIPDatabases') . '</a>'; + $availableInfo = $this->getSupportedLocationInfo(); + $availableDatabaseTypes = array(); - if (self::getPathToGeoIpDatabase(['GeoIP2-City.mmdb', 'GeoIP2-City-Africa.mmdb', 'GeoIP2-City-Asia-Pacific.mmdb', 'GeoIP2-City-Europe.mmdb', 'GeoIP2-City-North-America.mmdb', 'GeoIP2-City-South-America.mmdb', 'GeoIP2-Enterprise.mmdb', 'GeoLite2-City.mmdb']) !== false) { + + if (isset($availableInfo[self::CITY_NAME_KEY]) && $availableInfo[self::CITY_NAME_KEY]) { $availableDatabaseTypes[] = Piwik::translate('UserCountry_City'); } - if (self::getPathToGeoIpDatabase(['GeoIP2-Country.mmdb', 'GeoLite2-Country.mmdb']) !== false) { + + if (isset($availableInfo[self::COUNTRY_NAME_KEY]) && $availableInfo[self::COUNTRY_NAME_KEY]) { $availableDatabaseTypes[] = Piwik::translate('UserCountry_Country'); } - if (self::getPathToGeoIpDatabase(self::$dbNames['isp']) !== false) { + + if (isset($availableInfo[self::ISP_KEY]) && $availableInfo[self::ISP_KEY]) { $availableDatabaseTypes[] = Piwik::translate('UserCountry_ISPDatabase'); } diff --git a/plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php b/plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php index b5c5666ef8..5e2facc549 100644 --- a/plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php +++ b/plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php @@ -26,7 +26,7 @@ use Piwik\Url; class ServerModule extends GeoIp2 { const ID = 'geoip2server'; - const TITLE = 'GeoIP 2 (%s)'; + const TITLE = 'DBIP / GeoIP 2 (%s)'; public static $defaultGeoIpServerVars = array( parent::CONTINENT_CODE_KEY => 'MM_CONTINENT_CODE', diff --git a/plugins/GeoIp2/lang/en.json b/plugins/GeoIp2/lang/en.json index 0ad99cd838..d0559328eb 100644 --- a/plugins/GeoIp2/lang/en.json +++ b/plugins/GeoIp2/lang/en.json @@ -1,9 +1,9 @@ { "GeoIp2": { - "CannotFindGeoIPDatabaseInArchive": "No valid GeoIP database could be found in tar archive %1$s!", + "CannotFindGeoIPDatabaseInArchive": "No valid DBIP / GeoIP database could be found in tar archive %1$s!", "CannotUnzipGeoIPFile": "Could not unzip GeoIP file in %1$s: %2$s", - "PluginDescription": "Provides GeoIP2 location providers.", - "LocationProviderDesc_Php": "This location provider is the simplest to install as it does not require server configuration (ideal for shared hosting!). It uses a GeoIP 2 database and MaxMind's PHP API to accurately determine the location of your visitors.", + "PluginDescription": "Provides DBIP / GeoIP2 location providers.", + "LocationProviderDesc_Php": "This location provider is the simplest to install as it does not require server configuration (ideal for shared hosting!). It uses a DBIP or GeoIP 2 database and MaxMind's PHP API to accurately determine the location of your visitors.", "LocationProviderDesc_Php_WithExtension": "This location provider is speeded up by the installed %1$smaxminddb%2$s extension.", "LocationProviderDesc_ServerModule": "This location provider uses the GeoIP 2 module that has been installed in your HTTP server. This provider is fast and accurate, but %1$scan only be used with normal browser tracking.%2$s", "LocationProviderDesc_ServerModule2": "If you have to import log files or do something else that requires setting IP addresses, use the %3$sPHP GeoIP 2 implementation%4$s and install %1$smaxminddb extension%2$s.", |