PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,20 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2\Columns;
class Region extends \Piwik\Plugins\UserCountry\Columns\Region
{
protected $columnType = 'char(3) DEFAULT NULL';
protected $segmentName = '';
public function uninstall()
{
// do not remove region column when plugin is deactivated
}
}

View File

@ -0,0 +1,124 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2\Commands;
use Piwik\Common;
use Piwik\Db;
use Piwik\DbHelper;
use Piwik\Option;
use Piwik\Plugin\ConsoleCommand;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ConvertRegionCodesToIso extends ConsoleCommand
{
const OPTION_NAME = 'regioncodes_converted';
const MAPPING_TABLE_NAME = 'fips2iso';
protected function configure()
{
$this->setName('usercountry:convert-region-codes');
$this->setDescription("Convert FIPS region codes saved by GeoIP legacy provider to ISO.");
}
public function isEnabled()
{
return (LocationProvider::getCurrentProvider() instanceof GeoIp2);
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return void|int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// chick if option is set to disable second run
if (Option::get(self::OPTION_NAME)) {
$output->writeln('Converting region codes already done.');
return;
}
$output->setDecorated(true);
$output->write('Creating mapping table in database');
Db::query('DROP table if exists ' . self::MAPPING_TABLE_NAME);
DbHelper::createTable(self::MAPPING_TABLE_NAME,
"`country_code` VARCHAR(2) NOT NULL,
`fips_code` VARCHAR(2) NOT NULL,
`iso_code` VARCHAR(4) NULL DEFAULT NULL,
PRIMARY KEY (`country_code`, `fips_code`)");
$output->writeln(' <fg=green>✓</>');
$mappings = include __DIR__ . '/../data/regionMapping.php';
$output->write('Inserting mapping data ');
$counter = 0;
foreach ($mappings as $country => $regionMapping) {
foreach ($regionMapping as $fips => $iso) {
if ($fips == $iso) {
continue; // nothing needs to be changed, so ignore the mapping
}
Db::query('INSERT INTO `'.Common::prefixTable(self::MAPPING_TABLE_NAME).'` VALUES (?, ?, ?)', [$country, $fips, $iso]);
$counter++;
if ($counter%50 == 0) {
$output->write('.');
}
}
}
$output->writeln(' <fg=green>✓</>');
$output->writeln('Updating Matomo log tables:');
$activationTime = Option::get(GeoIp2::SWITCH_TO_ISO_REGIONS_OPTION_NAME);
$activationDateTime = date('Y-m-d H:i:s', $activationTime);
// fix country and region of tibet so it wil be updated correctly afterwards
$tibetFixQuery = 'UPDATE %s SET location_country = "cn", location_region = "14" WHERE location_country = "ti"';
// replace invalid country codes used by GeoIP Legacy
$fixInvalidCountriesQuery = 'UPDATE %s SET location_country = "" WHERE location_country IN("AP", "EU", "A1", "A2")';
$query = "UPDATE %s INNER JOIN %s ON location_country = country_code AND location_region = fips_code SET location_region = iso_code
WHERE `%s` < ?";
$logTables = ['log_visit' => 'visit_first_action_time', 'log_conversion' => 'server_time'];
foreach ($logTables as $logTable => $dateField) {
$output->write('- Updating ' . $logTable);
Db::query(sprintf($tibetFixQuery, Common::prefixTable($logTable)));
Db::query(sprintf($fixInvalidCountriesQuery, Common::prefixTable($logTable)));
$sql = sprintf($query, Common::prefixTable($logTable), Common::prefixTable(self::MAPPING_TABLE_NAME), $dateField);
Db::query($sql, $activationDateTime);
$output->writeln(' <fg=green>✓</>');
}
$output->write('Removing mapping table from database ');
Db::dropTables(Common::prefixTable(self::MAPPING_TABLE_NAME));
$output->writeln(' <fg=green>✓</>');
// save option to prevent a second run
Option::set(self::OPTION_NAME, true);
$output->writeln('All region codes converted.');
}
}

View File

@ -0,0 +1,673 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2;
require_once PIWIK_INCLUDE_PATH . "/core/ScheduledTask.php"; // for the tracker which doesn't include this file
use Exception;
use Piwik\Common;
use Piwik\Container\StaticContainer;
use Piwik\Date;
use Piwik\Filesystem;
use Piwik\Http;
use Piwik\Log;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2 AS LocationProviderGeoIp2;
use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2\Php;
use Piwik\Plugins\UserCountry\GeoIPAutoUpdater;
use Piwik\Scheduler\Scheduler;
use Piwik\Scheduler\Task;
use Piwik\Scheduler\Timetable;
use Piwik\Scheduler\Schedule\Monthly;
use Piwik\Scheduler\Schedule\Weekly;
use Piwik\SettingsPiwik;
use Piwik\Unzip;
/**
* Used to automatically update installed GeoIP 2 databases, and manages the updater's
* scheduled task.
*/
class GeoIP2AutoUpdater extends Task
{
const SCHEDULE_PERIOD_MONTHLY = 'month';
const SCHEDULE_PERIOD_WEEKLY = 'week';
const SCHEDULE_PERIOD_OPTION_NAME = 'geoip2.updater_period';
const LOC_URL_OPTION_NAME = 'geoip2.loc_db_url';
const ISP_URL_OPTION_NAME = 'geoip2.isp_db_url';
const LAST_RUN_TIME_OPTION_NAME = 'geoip2.updater_last_run_time';
private static $urlOptions = array(
'loc' => self::LOC_URL_OPTION_NAME,
'isp' => self::ISP_URL_OPTION_NAME,
);
/**
* PHP Error caught through a custom error handler while trying to use a downloaded
* GeoIP 2 database. See catchGeoIPError for more info.
*
* @var array
*/
private static $unzipPhpError = null;
/**
* Constructor.
*/
public function __construct()
{
if (!SettingsPiwik::isInternetEnabled()) {
// no automatic updates possible if no internet available
return;
}
$schedulePeriodStr = self::getSchedulePeriod();
// created the scheduledtime instance, also, since GeoIP 2 updates are done on tuesdays,
// get new DBs on Wednesday
switch ($schedulePeriodStr) {
case self::SCHEDULE_PERIOD_WEEKLY:
$schedulePeriod = new Weekly();
$schedulePeriod->setDay(3);
break;
case self::SCHEDULE_PERIOD_MONTHLY:
default:
$schedulePeriod = new Monthly();
$schedulePeriod->setDayOfWeek(3, 0);
break;
}
parent::__construct($this, 'update', null, $schedulePeriod, Task::LOWEST_PRIORITY);
}
/**
* Attempts to download new location & ISP GeoIP databases and
* replace the existing ones w/ them.
*/
public function update()
{
try {
Option::set(self::LAST_RUN_TIME_OPTION_NAME, Date::factory('today')->getTimestamp());
$locUrl = Option::get(self::LOC_URL_OPTION_NAME);
if (!empty($locUrl)) {
$this->downloadFile('loc', $locUrl);
}
$ispUrl = Option::get(self::ISP_URL_OPTION_NAME);
if (!empty($ispUrl)) {
$this->downloadFile('isp', $ispUrl);
}
} catch (Exception $ex) {
// message will already be prefixed w/ 'GeoIP2AutoUpdater: '
Log::error($ex);
$this->performRedundantDbChecks();
throw $ex;
}
$this->performRedundantDbChecks();
}
/**
* Downloads a GeoIP 2 database archive, extracts the .mmdb file and overwrites the existing
* old database.
*
* If something happens that causes the download to fail, no exception is thrown, but
* an error is logged.
*
* @param string $dbType
* @param string $url URL to the database to download. The type of database is determined
* from this URL.
* @throws Exception
*/
protected function downloadFile($dbType, $url)
{
$url = trim($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;
$zippedOutputPath = LocationProviderGeoIp2::getPathForGeoIpDatabase($zippedFilename);
$url = self::removeDateFromUrl($url);
// download zipped file to misc dir
try {
$success = Http::sendHttpRequest($url, $timeout = 3600, $userAgent = null, $zippedOutputPath);
} catch (Exception $ex) {
throw new Exception("GeoIP2AutoUpdater: failed to download '$url' to "
. "'$zippedOutputPath': " . $ex->getMessage());
}
if ($success !== true) {
throw new Exception("GeoIP2AutoUpdater: failed to download '$url' to "
. "'$zippedOutputPath'! (Unknown error)");
}
Log::info("GeoIP2AutoUpdater: successfully downloaded '%s'", $url);
try {
self::unzipDownloadedFile($zippedOutputPath, $dbType, $unlink = true);
} catch (Exception $ex) {
throw new Exception("GeoIP2AutoUpdater: failed to unzip '$zippedOutputPath' after "
. "downloading " . "'$url': " . $ex->getMessage());
}
Log::info("GeoIP2AutoUpdater: successfully updated GeoIP 2 database '%s'", $url);
}
/**
* Unzips a downloaded GeoIP 2 database. Only unzips .gz & .tar.gz files.
*
* @param string $path Path to zipped file.
* @param bool $unlink Whether to unlink archive or not.
* @throws Exception
*/
public static function unzipDownloadedFile($path, $dbType, $unlink = false)
{
// extract file
if (substr($path, -7, 7) == '.tar.gz') {
// find the .dat file in the tar archive
$unzip = Unzip::factory('tar.gz', $path);
$content = $unzip->listContent();
if (empty($content)) {
throw new Exception(Piwik::translate('UserCountry_CannotListContent',
array("'$path'", $unzip->errorInfo())));
}
$fileToExtract = null;
foreach ($content as $info) {
$archivedPath = $info['filename'];
if (in_array(basename($archivedPath), LocationProviderGeoIp2::$dbNames[$dbType])) {
$fileToExtract = $archivedPath;
}
}
if ($fileToExtract === null) {
throw new Exception(Piwik::translate('GeoIp2_CannotFindGeoIPDatabaseInArchive',
array("'$path'")));
}
// extract JUST the .dat file
$unzipped = $unzip->extractInString($fileToExtract);
if (empty($unzipped)) {
throw new Exception(Piwik::translate('GeoIp2_CannotUnzipGeoIPFile',
array("'$path'", $unzip->errorInfo())));
}
$dbFilename = basename($fileToExtract);
$tempFilename = $dbFilename . '.new';
$outputPath = LocationProviderGeoIp2::getPathForGeoIpDatabase($tempFilename);
// write unzipped to file
$fd = fopen($outputPath, 'wb');
fwrite($fd, $unzipped);
fclose($fd);
} else if (substr($path, -3, 3) == '.gz') {
$unzip = Unzip::factory('gz', $path);
$dbFilename = basename($path);
$tempFilename = $dbFilename . '.new';
$outputPath = LocationProviderGeoIp2::getPathForGeoIpDatabase($tempFilename);
$success = $unzip->extract($outputPath);
if ($success !== true) {
throw new Exception(Piwik::translate('UserCountry_CannotUnzipDatFile',
array("'$path'", $unzip->errorInfo())));
}
} else {
$ext = end(explode(basename($path), '.', 2));
throw new Exception(Piwik::translate('UserCountry_UnsupportedArchiveType', "'$ext'"));
}
try {
// test that the new archive is a valid GeoIP 2 database
if (empty($dbFilename) || false === LocationProviderGeoIp2::getGeoIPDatabaseTypeFromFilename($dbFilename)) {
throw new Exception("Unexpected GeoIP 2 archive file name '$path'.");
}
$customDbNames = array(
'loc' => array(),
'isp' => array()
);
$customDbNames[$dbType] = array($tempFilename);
$phpProvider = new Php($customDbNames);
try {
$location = $phpProvider->getLocation(array('ip' => LocationProviderGeoIp2::TEST_IP));
} catch (\Exception $e) {
Log::info("GeoIP2AutoUpdater: Encountered exception when testing newly downloaded" .
" GeoIP 2 database: %s", $e->getMessage());
throw new Exception(Piwik::translate('UserCountry_ThisUrlIsNotAValidGeoIPDB'));
}
if (empty($location)) {
throw new Exception(Piwik::translate('UserCountry_ThisUrlIsNotAValidGeoIPDB'));
}
// delete the existing GeoIP database (if any) and rename the downloaded file
$oldDbFile = LocationProviderGeoIp2::getPathForGeoIpDatabase($dbFilename);
if (file_exists($oldDbFile)) {
unlink($oldDbFile);
}
$tempFile = LocationProviderGeoIp2::getPathForGeoIpDatabase($tempFilename);
if (@rename($tempFile, $oldDbFile) !== true) {
//In case the $tempfile cannot be renamed, we copy the file.
copy($tempFile, $oldDbFile);
unlink($tempFile);
}
// delete original archive
if ($unlink) {
unlink($path);
}
} catch (Exception $ex) {
// remove downloaded files
if (file_exists($outputPath)) {
unlink($outputPath);
}
unlink($path);
throw $ex;
}
}
/**
* Sets the options used by this class based on query parameter values.
*
* See setUpdaterOptions for query params used.
*/
public static function setUpdaterOptionsFromUrl()
{
$options = array(
'loc' => Common::getRequestVar('loc_db', false, 'string'),
'isp' => Common::getRequestVar('isp_db', false, 'string'),
'period' => Common::getRequestVar('period', false, 'string'),
);
foreach (self::$urlOptions as $optionKey => $optionName) {
$options[$optionKey] = Common::unsanitizeInputValue($options[$optionKey]); // URLs should not be sanitized
}
self::setUpdaterOptions($options);
}
/**
* Sets the options used by this class based on the elements in $options.
*
* The following elements of $options are used:
* 'loc' - URL for location database.
* 'isp' - URL for ISP database.
* 'org' - URL for Organization database.
* 'period' - 'weekly' or 'monthly'. When to run the updates.
*
* @param array $options
* @throws Exception
*/
public static function setUpdaterOptions($options)
{
// set url options
foreach (self::$urlOptions as $optionKey => $optionName) {
if (!isset($options[$optionKey])) {
continue;
}
$url = $options[$optionKey];
$url = self::removeDateFromUrl($url);
Option::set($optionName, $url);
}
// set period option
if (!empty($options['period'])) {
$period = $options['period'];
if ($period != self::SCHEDULE_PERIOD_MONTHLY
&& $period != self::SCHEDULE_PERIOD_WEEKLY
) {
throw new Exception(Piwik::translate(
'UserCountry_InvalidGeoIPUpdatePeriod',
array("'$period'", "'" . self::SCHEDULE_PERIOD_MONTHLY . "', '" . self::SCHEDULE_PERIOD_WEEKLY . "'")
));
}
Option::set(self::SCHEDULE_PERIOD_OPTION_NAME, $period);
/** @var Scheduler $scheduler */
$scheduler = StaticContainer::getContainer()->get('Piwik\Scheduler\Scheduler');
$scheduler->rescheduleTaskAndRunTomorrow(new GeoIP2AutoUpdater());
}
// clear option for GeoIP as not needed if GeoIP2 is set up
GeoIPAutoUpdater::clearOptions();
}
/**
* Returns true if the auto-updater is setup to update at least one type of
* database. False if otherwise.
*
* @return bool
*/
public static function isUpdaterSetup()
{
if (Option::get(self::LOC_URL_OPTION_NAME) !== false
|| Option::get(self::ISP_URL_OPTION_NAME) !== false
) {
return true;
}
return false;
}
/**
* Retrieves the URLs used to update various GeoIP 2 database files.
*
* @return array
*/
public static function getConfiguredUrls()
{
$result = array();
foreach (self::$urlOptions as $key => $optionName) {
$result[$key] = Option::get($optionName);
}
return $result;
}
/**
* Returns the confiured URL (if any) for a type of database.
*
* @param string $key 'loc', 'isp' or 'org'
* @throws Exception
* @return string|false
*/
public static function getConfiguredUrl($key)
{
if (empty(self::$urlOptions[$key])) {
throw new Exception("Invalid key $key");
}
$url = Option::get(self::$urlOptions[$key]);
return $url;
}
/**
* Performs a GeoIP 2 database update.
*/
public static function performUpdate()
{
$instance = new GeoIP2AutoUpdater();
$instance->update();
}
/**
* Returns the configured update period, either 'week' or 'month'. Defaults to
* 'month'.
*
* @return string
*/
public static function getSchedulePeriod()
{
$period = Option::get(self::SCHEDULE_PERIOD_OPTION_NAME);
if ($period === false) {
$period = self::SCHEDULE_PERIOD_MONTHLY;
}
return $period;
}
/**
* Returns an array of strings for GeoIP 2 databases that have update URLs configured, but
* are not present in the misc directory. Each string is a key describing the type of
* database (ie, 'loc', 'isp' or 'org').
*
* @return array
*/
public static function getMissingDatabases()
{
$result = array();
foreach (self::getConfiguredUrls() as $key => $url) {
if (!empty($url)) {
// if a database of the type does not exist, but there's a url to update, then
// a database is missing
$path = LocationProviderGeoIp2::getPathToGeoIpDatabase(
LocationProviderGeoIp2::$dbNames[$key]);
if ($path === false) {
$result[] = $key;
}
}
}
return $result;
}
/**
* Returns the extension of a URL used to update a GeoIP 2 database, if it can be found.
*/
public static function getGeoIPUrlExtension($url)
{
// check for &suffix= query param that is special to MaxMind URLs
if (preg_match('/suffix=([^&]+)/', $url, $matches)) {
$ext = $matches[1];
} else {
// use basename of url
$filenameParts = explode('.', basename($url), 2);
if (count($filenameParts) > 1) {
$ext = end($filenameParts);
} else {
$ext = reset($filenameParts);
}
}
self::checkForSupportedArchiveType($ext);
return $ext;
}
/**
* Avoid downloading archive types we don't support. No point in downloading it,
* if we can't unzip it...
*
* @param string $ext The URL file's extension.
* @throws \Exception
*/
private static function checkForSupportedArchiveType($ext)
{
if ($ext != 'tar.gz'
&& $ext != 'gz'
&& $ext != 'mmdb.gz'
) {
throw new \Exception(Piwik::translate('UserCountry_UnsupportedArchiveType', "'$ext'"));
}
}
/**
* Utility function that checks if geolocation works with each installed database,
* and if one or more doesn't, they are renamed to make sure tracking will work.
* This is a safety measure used to make sure tracking isn't affected if strange
* update errors occur.
*
* Databases are renamed to ${original}.broken .
*
* Note: method is protected for testability.
*
* @param $logErrors - only used to hide error logs during tests
*/
protected function performRedundantDbChecks($logErrors = true)
{
$databaseTypes = array_keys(LocationProviderGeoIp2::$dbNames);
foreach ($databaseTypes as $type) {
$customNames = array(
'loc' => array(),
'isp' => array(),
'org' => array()
);
$customNames[$type] = LocationProviderGeoIp2::$dbNames[$type];
// create provider that only uses the DB type we're testing
$provider = new Php($customNames);
// test the provider. on error, we rename the broken DB.
try {
$location = $provider->getLocation(array('ip' => LocationProviderGeoIp2::TEST_IP));
} catch (\Exception $e) {
if($logErrors) {
Log::error("GeoIP2AutoUpdater: Encountered exception when performing redundant tests on GeoIP2 "
. "%s database: %s: %s", $type, $e->getMessage());
}
// get the current filename for the DB and an available new one to rename it to
list($oldPath, $newPath) = $this->getOldAndNewPathsForBrokenDb($customNames[$type]);
// rename the DB so tracking will not fail
if ($oldPath !== false
&& $newPath !== false
) {
if (file_exists($newPath)) {
unlink($newPath);
}
rename($oldPath, $newPath);
}
}
}
}
/**
* Returns the path to a GeoIP 2 database and a path to rename it to if it's broken.
*
* @param array $possibleDbNames The possible names of the database.
* @return array Array with two elements, the path to the existing database, and
* the path to rename it to if it is broken. The second will end
* with something like .broken .
*/
private function getOldAndNewPathsForBrokenDb($possibleDbNames)
{
$pathToDb = LocationProviderGeoIp2::getPathToGeoIpDatabase($possibleDbNames);
$newPath = false;
if ($pathToDb !== false) {
$newPath = $pathToDb . ".broken";
}
return array($pathToDb, $newPath);
}
/**
* Custom PHP error handler used to catch any PHP errors that occur when
* testing a downloaded GeoIP 2 file.
*
* If we download a file that is supposed to be a GeoIP 2 database, we need to make
* sure it is one. This is done simply by attempting to use it. If this fails, it
* will most of the time fail as a PHP error, which we catch w/ this function
* after it is passed to set_error_handler.
*
* The PHP error is stored in self::$unzipPhpError.
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
*/
public static function catchGeoIPError($errno, $errstr, $errfile, $errline)
{
self::$unzipPhpError = array($errno, $errstr, $errfile, $errline);
}
/**
* Returns the time the auto updater was last run.
*
* @return Date|false
*/
public static function getLastRunTime()
{
$timestamp = Option::get(self::LAST_RUN_TIME_OPTION_NAME);
return $timestamp === false ? false : Date::factory((int)$timestamp);
}
/**
* Removes the &date=... query parameter if present in the URL. This query parameter
* is in MaxMind URLs by default and will force the download of an old database.
*
* @param string $url
* @return string
*/
private static function removeDateFromUrl($url)
{
return preg_replace("/&date=[^&#]*/", '', $url);
}
/**
* Returns the next scheduled time for the auto updater.
*
* @return Date|false
*/
public static function getNextRunTime()
{
$task = new GeoIP2AutoUpdater();
$timetable = new Timetable();
return $timetable->getScheduledTaskTime($task->getName());
}
/**
* See {@link Piwik\Scheduler\Schedule\Schedule::getRescheduledTime()}.
*/
public function getRescheduledTime()
{
$nextScheduledTime = parent::getRescheduledTime();
// if a geoip 2 database is out of date, run the updater as soon as possible
if ($this->isAtLeastOneGeoIpDbOutOfDate($nextScheduledTime)) {
return time();
}
return $nextScheduledTime;
}
private function isAtLeastOneGeoIpDbOutOfDate($rescheduledTime)
{
$previousScheduledRuntime = $this->getPreviousScheduledTime($rescheduledTime)->setTime("00:00:00")->getTimestamp();
foreach (LocationProviderGeoIp2::$dbNames as $type => $dbNames) {
$dbUrl = Option::get(self::$urlOptions[$type]);
$dbPath = LocationProviderGeoIp2::getPathToGeoIpDatabase($dbNames);
// if there is a URL for this DB type and the GeoIP 2 DB file's last modified time is before
// the time the updater should have been previously run, then **the file is out of date**
if (!empty($dbUrl)
&& filemtime($dbPath) < $previousScheduledRuntime
) {
return true;
}
}
return false;
}
private function getPreviousScheduledTime($rescheduledTime)
{
$updaterPeriod = self::getSchedulePeriod();
if ($updaterPeriod == self::SCHEDULE_PERIOD_WEEKLY) {
return Date::factory($rescheduledTime)->subWeek(1);
} else if ($updaterPeriod == self::SCHEDULE_PERIOD_MONTHLY) {
return Date::factory($rescheduledTime)->subMonth(1);
}
throw new Exception("Unknown GeoIP 2 updater period found in database: %s", $updaterPeriod);
}
}

View File

@ -0,0 +1,30 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2;
use Piwik\Plugins\UserCountry\LocationProvider;
/**
*
*/
class GeoIp2 extends \Piwik\Plugin
{
public function isTrackerPlugin()
{
return true;
}
public function deactivate()
{
// switch to default provider if GeoIP2 provider was in use
if (LocationProvider::getCurrentProvider() instanceof \Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2) {
LocationProvider::setCurrentProvider(LocationProvider\DefaultProvider::ID);
}
}
}

View File

@ -0,0 +1,265 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2\LocationProvider;
use Exception;
use Piwik\Container\StaticContainer;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Plugins\UserCountry\LocationProvider;
/**
* Base type for all GeoIP 2 LocationProviders.
*
*/
abstract class GeoIp2 extends LocationProvider
{
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';
/**
* Cached region name array. Data is from geoipregionvars.php.
*
* @var array
*/
private static $regionNames = null;
/**
* Stores possible database file names categorized by the type of information
* GeoIP databases hold.
*
* @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'),
);
/**
* Returns true if this provider has been setup correctly, the error message if not.
*
* @return bool|string
*/
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();
list($testIp, $expectedResult) = self::getTestIpAndResult();
// get location using test IP
$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;
}
}
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);
return Piwik::translate('UserCountry_TestIPLocatorFailed', $bind);
}
return true;
} catch (Exception $ex) {
return $ex->getMessage();
}
}
/**
* Returns the path of an existing GeoIP 2 database or false if none can be found.
*
* @param array $possibleFileNames The list of possible file names for the GeoIP database.
* @return string|false
*/
public static function getPathToGeoIpDatabase($possibleFileNames)
{
foreach ($possibleFileNames as $filename) {
$path = self::getPathForGeoIpDatabase($filename);
if (file_exists($path)) {
return $path;
}
}
return false;
}
/**
* Returns full path for a GeoIP 2 database managed by Piwik.
*
* @param string $filename Name of the .dat file.
* @return string
*/
public static function getPathForGeoIpDatabase($filename)
{
return StaticContainer::get('path.geoip2') . $filename;
}
/**
* Returns test IP used by isWorking and expected result.
*
* @return array eg. array('1.2.3.4', array(self::COUNTRY_CODE_KEY => ...))
*/
private static function getTestIpAndResult()
{
static $result = null;
if (is_null($result)) {
$expected = array(self::COUNTRY_CODE_KEY => 'FR',
self::REGION_CODE_KEY => 'BFC',
self::CITY_NAME_KEY => 'Besançon');
$result = array(self::TEST_IP, $expected);
}
return $result;
}
public function activate()
{
$option = Option::get(self::SWITCH_TO_ISO_REGIONS_OPTION_NAME);
if (empty($option)) {
Option::set(self::SWITCH_TO_ISO_REGIONS_OPTION_NAME, time());
}
}
/**
* Returns true if there is a GeoIP 2 database in the 'misc' directory.
*
* @return bool
*/
public static function isDatabaseInstalled()
{
return self::getPathToGeoIpDatabase(self::$dbNames['loc'])
|| self::getPathToGeoIpDatabase(self::$dbNames['isp']);
}
/**
* Returns the type of GeoIP 2 database ('loc' or 'isp') based on the
* filename (eg, 'GeoLite2-City.mmdb', 'GeoIP2-ISP.mmdb', etc).
*
* @param string $filename
* @return string|false 'loc', 'isp' or false if cannot find a database type.
*/
public static function getGeoIPDatabaseTypeFromFilename($filename)
{
foreach (self::$dbNames as $key => $names) {
foreach ($names as $name) {
if ($name === $filename) {
return $key;
}
}
}
return false;
}
/**
* Returns a region name for a country code + region code.
*
* @param string $countryCode
* @param string $regionCode
* @return string The region name or 'Unknown' (translated).
*/
public static function getRegionNameFromCodes($countryCode, $regionCode)
{
$regionNames = self::getRegionNames();
$countryCode = strtoupper($countryCode);
$regionCode = strtoupper($regionCode);
if (isset($regionNames[$countryCode][$regionCode])) {
return $regionNames[$countryCode][$regionCode];
} else {
return Piwik::translate('General_Unknown');
}
}
/**
* Returns an array of region names mapped by country code & region code.
*
* @return array
*/
public static function getRegionNames()
{
if (is_null(self::$regionNames)) {
self::$regionNames = require_once __DIR__ . '/../data/isoRegionNames.php';
}
return self::$regionNames;
}
/**
* Converts an old FIPS region code to ISO
*
* @param string $countryCode
* @param string $fipsRegionCode
* @param bool $returnOriginalIfNotFound return given region code if no mapping was found
* @return array
*/
public static function convertRegionCodeToIso($countryCode, $fipsRegionCode, $returnOriginalIfNotFound = false)
{
static $mapping;
if(empty($mapping)) {
$mapping = include __DIR__ . '/../data/regionMapping.php';
}
$countryCode = strtoupper($countryCode);
if (empty($countryCode) || in_array($countryCode, ['EU', 'AP', 'A1', 'A2'])) {
return ['', ''];
}
if (in_array($countryCode, ['US', 'CA'])) { // US and CA always haven been iso codes
return [$countryCode, $fipsRegionCode];
}
if ($countryCode == 'TI') {
$countryCode = 'CN';
$fipsRegionCode = '14';
}
$isoRegionCode = $returnOriginalIfNotFound ? $fipsRegionCode : '';
if (!empty($fipsRegionCode) && !empty($mapping[$countryCode][$fipsRegionCode])) {
$isoRegionCode = $mapping[$countryCode][$fipsRegionCode];
}
return [$countryCode, $isoRegionCode];
}
/**
* Returns an IP address from an array that was passed into getLocation. This
* will return an IPv4 address or IPv6 address.
*
* @param array $info Must have 'ip' key.
* @return string|null
*/
protected function getIpFromInfo($info)
{
$ip = \Piwik\Network\IP::fromStringIP($info['ip']);
return $ip->toString();
}
}

View File

@ -0,0 +1,335 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use GeoIp2\Database\Reader;
use GeoIp2\Exception\AddressNotFoundException;
use MaxMind\Db\Reader\InvalidDatabaseException;
use Piwik\Log;
use Piwik\Piwik;
use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\Marketplace\Api\Exception;
/**
* A LocationProvider that uses the PHP implementation of GeoIP 2.
*
*/
class Php extends GeoIp2
{
const ID = 'geoip2php';
const TITLE = 'GeoIP 2 (Php)';
/**
* The GeoIP2 reader instances used. This array will contain at most two
* of them: one for location info and one for ISP info
*
* Each instance is mapped w/ one of the following keys: 'loc', 'isp'
*
* @var array of GeoIP instances
*/
private $readerCache = array();
/**
* Possible filenames for each type of GeoIP database. When looking for a database
* file in the 'misc' subdirectory, files with these names will be looked for.
*
* This variable is an array mapping either the 'loc' or 'isp' strings with
* an array of filenames.
*
* By default, this will be set to GeoIp2::$dbNames.
*
* @var array
*/
private $customDbNames;
/**
* Constructor.
*
* @param array|bool $customDbNames The possible filenames for each type of GeoIP database.
* eg array(
* 'loc' => array('GeoLite2-City.mmdb'),
* 'isp' => array('GeoIP2.mmdb', 'GeoIP2-ISP.mmdb')
* )
* If a key is missing (or the parameter not supplied), then the
* default database names are used.
*/
public function __construct($customDbNames = false)
{
$this->customDbNames = parent::$dbNames;
if ($customDbNames !== false) {
foreach ($this->customDbNames as $key => $names) {
if (isset($customDbNames[$key])) {
$this->customDbNames[$key] = $customDbNames[$key];
}
}
}
}
/**
* Uses a GeoIP 2 database to get a visitor's location based on their IP address.
*
* This function will return different results based on the data used. If a city
* database is used, it may return the country code, region code, city name, area
* code, latitude, longitude and postal code of the visitor.
*
* Alternatively, if used with a country database, only the country code will be
* returned.
*
* @param array $info Must have an 'ip' field.
* @return array|false
*/
public function getLocation($info)
{
$ip = $this->getIpFromInfo($info);
if (empty($ip)) {
return false;
}
$result = [];
$reader = $this->getGeoIpInstance('loc');
if ($reader) {
try {
switch ($reader->metadata()->databaseType) {
case 'GeoLite2-Country':
case 'GeoIP2-Country':
$lookupResult = $reader->country($ip);
$this->setCountryResults($lookupResult, $result);
break;
case 'GeoIP2-Enterprise':
case 'GeoLite2-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);
}
$this->setCountryResults($lookupResult, $result);
$this->setCityResults($lookupResult, $result);
break;
default: // unknown database type log warning
Log::warning("Found unrecognized database type: %s", $reader->metadata()->databaseType);
break;
}
} catch (AddressNotFoundException $e) {
// ignore - do nothing
}
}
// NOTE: ISP & ORG require commercial dbs to test.
$ispGeoIp = $this->getGeoIpInstance($key = 'isp');
if ($ispGeoIp) {
try {
switch ($ispGeoIp->metadata()->databaseType) {
case 'GeoIP2-ISP':
$lookupResult = $ispGeoIp->isp($ip);
$result[self::ISP_KEY] = $lookupResult->isp;
$result[self::ORG_KEY] = $lookupResult->organization;
break;
case 'GeoLite2-ASN':
$lookupResult = $ispGeoIp->asn($ip);
$result[self::ISP_KEY] = $lookupResult->autonomousSystemOrganization;
$result[self::ORG_KEY] = $lookupResult->autonomousSystemOrganization;
break;
}
} catch (AddressNotFoundException $e) {
// ignore - do nothing
}
}
if (empty($result)) {
return false;
}
$this->completeLocationResult($result);
return $result;
}
protected function setCountryResults($lookupResult, &$result)
{
$result[self::CONTINENT_NAME_KEY] = $lookupResult->continent->name;
$result[self::CONTINENT_CODE_KEY] = strtoupper($lookupResult->continent->code);
$result[self::COUNTRY_CODE_KEY] = strtoupper($lookupResult->country->isoCode);
$result[self::COUNTRY_NAME_KEY] = $lookupResult->country->name;
}
protected function setCityResults($lookupResult, &$result)
{
$result[self::CITY_NAME_KEY] = $lookupResult->city->name;
$result[self::LATITUDE_KEY] = $lookupResult->location->latitude;
$result[self::LONGITUDE_KEY] = $lookupResult->location->longitude;
$result[self::POSTAL_CODE_KEY] = $lookupResult->postal->code;
if (is_array($lookupResult->subdivisions) && count($lookupResult->subdivisions) > 0) {
$subdivisions = $lookupResult->subdivisions;
$subdivision = $this->determinSubdivision($subdivisions, $result[self::COUNTRY_CODE_KEY]);
$result[self::REGION_CODE_KEY] = strtoupper($subdivision->isoCode);
$result[self::REGION_NAME_KEY] = $subdivision->name;
}
}
protected function determinSubdivision($subdivisions, $countryCode)
{
if (in_array($countryCode, ['GB'])) {
return end($subdivisions);
}
return reset($subdivisions);
}
/**
* Returns true if this location provider is available. Piwik ships w/ the MaxMind
* PHP library, so this provider is available if a location GeoIP database can be found.
*
* @return bool
*/
public function isAvailable()
{
$path = self::getPathToGeoIpDatabase($this->customDbNames['loc']);
return $path !== false;
}
/**
* Returns an array describing the types of location information this provider will
* return.
*
* The location info this provider supports depends on what GeoIP databases it can
* find.
*
* This provider will always support country & continent information.
*
* If a region database is found, then region code & name information will be
* supported.
*
* If a city database is found, then region code, region name, city name,
* area code, latitude, longitude & postal code are all supported.
*
* If an ISP/organization database is found, ISP/organization information is supported.
*
* @return array
*/
public function getSupportedLocationInfo()
{
$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) {
switch ($reader->metadata()->databaseType) {
case 'GeoIP2-Enterprise':
case 'GeoLite2-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':
$result[self::REGION_CODE_KEY] = true;
$result[self::REGION_NAME_KEY] = true;
$result[self::CITY_NAME_KEY] = true;
$result[self::POSTAL_CODE_KEY] = true;
$result[self::LATITUDE_KEY] = true;
$result[self::LONGITUDE_KEY] = true;
break;
}
}
// check if isp info is available
if ($this->getGeoIpInstance($key = 'isp')) {
$result[self::ISP_KEY] = true;
$result[self::ORG_KEY] = true;
}
return $result;
}
/**
* Returns information about this location provider. Contains an id, title & description:
*
* array(
* 'id' => 'geoip2_php',
* 'title' => '...',
* 'description' => '...'
* );
*
* @return array
*/
public function getInfo()
{
$desc = Piwik::translate('GeoIp2_LocationProviderDesc_Php') . '<br/><br/>';
if (extension_loaded('maxminddb')) {
$desc .= Piwik::translate('GeoIp2_LocationProviderDesc_Php_WithExtension',
array('<strong>', '</strong>'));
}
$installDocs = '<a rel="noreferrer" target="_blank" href="https://matomo.org/faq/how-to/#faq_163">'
. Piwik::translate('UserCountry_HowToInstallGeoIPDatabases')
. '</a>';
$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) {
$availableDatabaseTypes[] = Piwik::translate('UserCountry_City');
}
if (self::getPathToGeoIpDatabase(['GeoIP2-Country.mmdb', 'GeoLite2-Country.mmdb']) !== false) {
$availableDatabaseTypes[] = Piwik::translate('UserCountry_Country');
}
if (self::getPathToGeoIpDatabase(self::$dbNames['isp']) !== false) {
$availableDatabaseTypes[] = Piwik::translate('UserCountry_ISPDatabase');
}
if (!empty($availableDatabaseTypes)) {
$extraMessage = '<strong>' . Piwik::translate('General_Note') . '</strong>:&nbsp;'
. Piwik::translate('UserCountry_GeoIPImplHasAccessTo') . ':&nbsp;<strong>'
. implode(', ', $availableDatabaseTypes) . '</strong>.';
} else {
$extraMessage = '<strong>' . Piwik::translate('General_Note') . '</strong>:&nbsp;'
. Piwik::translate('UserCountry_GeoIPNoDatabaseFound');
}
return array('id' => self::ID,
'title' => self::TITLE,
'description' => $desc,
'install_docs' => $installDocs,
'extra_message' => $extraMessage,
'order' => 2);
}
/**
* Returns a GeoIP2 reader instance. Creates it if necessary.
*
* @param string $key 'loc' or 'isp'. Determines the type of GeoIP database
* to load.
* @return Reader|false
*/
private function getGeoIpInstance($key)
{
if (empty($this->readerCache[$key])) {
$pathToDb = self::getPathToGeoIpDatabase($this->customDbNames[$key]);
if ($pathToDb !== false) {
try {
$this->readerCache[$key] = new Reader($pathToDb);
} catch (InvalidDatabaseException $e) {
// ignore invalid database exception
}
}
}
return empty($this->readerCache[$key]) ? false : $this->readerCache[$key];
}
}

View File

@ -0,0 +1,343 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Cache;
use Piwik\Common;
use Piwik\IP;
use Piwik\Piwik;
use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Plugins\GeoIp2\SystemSettings;
use Piwik\Url;
/**
* A LocationProvider that uses an GeoIP 2 module installed in an HTTP Server.
*
* To make this provider available, make sure mod_maxminddb / ngx_http_geoip2_module installed and active
*/
class ServerModule extends GeoIp2
{
const ID = 'geoip2server';
const TITLE = 'GeoIP 2 (%s)';
public static $defaultGeoIpServerVars = array(
parent::CONTINENT_CODE_KEY => 'MM_CONTINENT_CODE',
parent::CONTINENT_NAME_KEY => 'MM_CONTINENT_NAME',
parent::COUNTRY_CODE_KEY => 'MM_COUNTRY_CODE',
parent::COUNTRY_NAME_KEY => 'MM_COUNTRY_NAME',
parent::REGION_CODE_KEY => 'MM_REGION_CODE',
parent::REGION_NAME_KEY => 'MM_REGION_NAME',
parent::LATITUDE_KEY => 'MM_LATITUDE',
parent::LONGITUDE_KEY => 'MM_LONGITUDE',
parent::POSTAL_CODE_KEY => 'MM_POSTAL_CODE',
parent::CITY_NAME_KEY => 'MM_CITY_NAME',
parent::ISP_KEY => 'MM_ISP',
parent::ORG_KEY => 'MM_ORG',
);
/**
* Uses a GeoIP 2 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 2 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 2 (Server Module) does not support this use case... ");
$fallbacks = array(
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.");
return false;
}
$result = array();
foreach (self::getGeoIpServerVars() as $resultKey => $geoipVarName) {
if (!empty($_SERVER[$geoipVarName])) {
$result[$resultKey] = $_SERVER[$geoipVarName];
}
}
$this->completeLocationResult($result);
return $result;
}
/**
* Returns an array describing the types of location information this provider will
* return.
*
* There's no way to tell exactly what database the HTTP server is using, so we just
* assume country and continent information is available. This can make diagnostics
* a bit more difficult, unfortunately.
*
* @return array
*/
public function getSupportedLocationInfo()
{
$result = array();
// assume country info is always available. it's an error if it's not.
$result[self::CONTINENT_CODE_KEY] = true;
$result[self::CONTINENT_NAME_KEY] = true;
$result[self::COUNTRY_CODE_KEY] = true;
$result[self::COUNTRY_NAME_KEY] = true;
$result[self::REGION_CODE_KEY] = array_key_exists(self::getGeoIpServerVars(self::REGION_CODE_KEY), $_SERVER);
$result[self::REGION_NAME_KEY] = array_key_exists(self::getGeoIpServerVars(self::REGION_NAME_KEY), $_SERVER);
$result[self::LATITUDE_KEY] = array_key_exists(self::getGeoIpServerVars(self::LATITUDE_KEY), $_SERVER);
$result[self::LONGITUDE_KEY] = array_key_exists(self::getGeoIpServerVars(self::LONGITUDE_KEY), $_SERVER);
$result[self::POSTAL_CODE_KEY] = array_key_exists(self::getGeoIpServerVars(self::POSTAL_CODE_KEY), $_SERVER);
$result[self::CITY_NAME_KEY] = array_key_exists(self::getGeoIpServerVars(self::CITY_NAME_KEY), $_SERVER);
$result[self::ISP_KEY] = array_key_exists(self::getGeoIpServerVars(self::ISP_KEY), $_SERVER);
$result[self::ORG_KEY] = array_key_exists(self::getGeoIpServerVars(self::ORG_KEY), $_SERVER);
return $result;
}
/**
* Checks if an mod_maxminddb has been installed and MMDB_ADDR server variable is defined.
*
* There's a special check for the Apache module, but we can't check specifically
* for anything else.
*
* @return bool|string
*/
public function isAvailable()
{
if (function_exists('apache_get_modules')) {
foreach (apache_get_modules() as $name) {
if (strpos($name, 'maxminddb') !== false) {
return true;
}
}
}
$settings = self::getGeoIpServerVars();
$available = array_key_exists($settings[self::CONTINENT_CODE_KEY], $_SERVER)
|| array_key_exists($settings[self::COUNTRY_CODE_KEY], $_SERVER)
|| array_key_exists($settings[self::REGION_CODE_KEY], $_SERVER)
|| array_key_exists($settings[self::CITY_NAME_KEY], $_SERVER);
if ($available) {
return true;
}
// if not available return message w/ extra info
if (!function_exists('apache_get_modules')) {
return Piwik::translate('General_Note') . ':&nbsp;' . Piwik::translate('UserCountry_AssumingNonApache');
}
$message = "<strong>" . Piwik::translate('General_Note') . ':&nbsp;'
. Piwik::translate('UserCountry_FoundApacheModules')
. "</strong>:<br/><br/>\n<ul style=\"list-style:disc;margin-left:24px\">\n";
foreach (apache_get_modules() as $name) {
$message .= "<li>$name</li>\n";
}
$message .= "</ul>";
return $message;
}
/**
* Returns true if the MMDB_ADDR server variable is defined.
*
* @return bool
*/
public function isWorking()
{
$settings = self::getGeoIpServerVars();
$available = array_key_exists($settings[self::CONTINENT_CODE_KEY], $_SERVER)
|| array_key_exists($settings[self::COUNTRY_CODE_KEY], $_SERVER)
|| array_key_exists($settings[self::REGION_CODE_KEY], $_SERVER)
|| array_key_exists($settings[self::CITY_NAME_KEY], $_SERVER);
if (!$available) {
return Piwik::translate("UserCountry_CannotFindGeoIPServerVar", $settings[self::COUNTRY_CODE_KEY] . ' $_SERVER');
}
return true;
}
/**
* Returns information about this location provider. Contains an id, title & description:
*
* array(
* 'id' => 'geoip_serverbased',
* 'title' => '...',
* 'description' => '...'
* );
*
* @return array
*/
public function getInfo()
{
if (function_exists('apache_note')) {
$serverDesc = 'Apache';
} else {
$serverDesc = Piwik::translate('UserCountry_HttpServerModule');
}
$title = sprintf(self::TITLE, $serverDesc);
$desc = Piwik::translate('GeoIp2_LocationProviderDesc_ServerModule', array('<strong>', '</strong>'))
. '<br/><br/>'
. Piwik::translate('UserCountry_GeoIpLocationProviderDesc_ServerBasedAnonWarn')
. '<br/><br/>'
. Piwik::translate('GeoIp2_LocationProviderDesc_ServerModule2',
array('<strong>', '</strong>', '<strong>', '</strong>'));
$installDocs =
'<a rel="noreferrer" target="_blank" href="https://maxmind.github.io/mod_maxminddb/">'
. Piwik::translate('UserCountry_HowToInstallApacheModule')
. '</a><br/>'
. '<a rel="noreferrer" target="_blank" href="https://github.com/leev/ngx_http_geoip2_module/blob/master/README.md#installing">'
. Piwik::translate('UserCountry_HowToInstallNginxModule')
. '</a>';
$geoipServerVars = array();
foreach ($_SERVER as $key => $value) {
if (in_array($key, self::getGeoIpServerVars())) {
$geoipServerVars[] = $key;
}
}
if (empty($geoipServerVars)) {
$extraMessage = '<strong>' . Piwik::translate('UserCountry_GeoIPNoServerVars', '$_SERVER') . '</strong>';
} else {
$extraMessage = '<strong>' . Piwik::translate('UserCountry_GeoIPServerVarsFound', '$_SERVER')
. ":</strong><br/><br/>\n<ul style=\"list-style:disc;margin-left:24px\">\n";
foreach ($geoipServerVars as $key) {
$extraMessage .= '<li>' . $key . "</li>\n";
}
$extraMessage .= '</ul>';
}
$configUrl = Url::getCurrentQueryStringWithParametersModified(array(
'module' => 'CoreAdminHome', 'action' => 'generalSettings'
));
$extraMessage .= '<br />'.Piwik::translate('GeoIp2_GeoIPVariablesConfigurationHere', ['<a href="'.$configUrl.'">', '</a>']);
return array('id' => self::ID,
'title' => $title,
'description' => $desc,
'order' => 3,
'install_docs' => $installDocs,
'extra_message' => $extraMessage);
}
/**
* Checks if two IP addresses are the same or if the first is the anonymized
* version of the other.
*
* @param string $ip
* @param string $currentIp This IP should not be anonymized.
* @return bool
*/
public static function isSameOrAnonymizedIp($ip, $currentIp)
{
$ip = array_reverse(explode('.', $ip));
$currentIp = array_reverse(explode('.', $currentIp));
if (count($ip) != count($currentIp)) {
return false;
}
foreach ($ip as $i => $byte) {
if ($byte == 0) {
$currentIp[$i] = 0;
} else {
break;
}
}
foreach ($ip as $i => $byte) {
if ($byte != $currentIp[$i]) {
return false;
}
}
return true;
}
/**
* Returns currently configured server variable name for given type
*
* @param string|null $type
* @return mixed|string
*/
protected static function getGeoIpServerVars($type = null)
{
$storedSettings = self::getSystemSettingsValues();
if ($type === null) {
return $storedSettings;
}
if (array_key_exists($type, $storedSettings)) {
return $storedSettings[$type];
}
return '';
}
protected static function getSystemSettingsValues()
{
$cacheKey = 'geoip2variables';
// use eager cache if this data needs to be available on every tracking request
$cache = Cache::getEagerCache();
if ($cache->contains($cacheKey)) {
return $cache->fetch($cacheKey);
}
$settingValues = self::$defaultGeoIpServerVars; // preset with defaults
try {
$systemSettings = new SystemSettings();
foreach ($systemSettings->geoIp2variables as $name => $setting) {
$settingValues[$name] = $setting->getValue();
}
$cache->save($cacheKey, $settingValues);
} catch (\Exception $e) {
}
return $settingValues;
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2;
use Piwik\Piwik;
use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2\ServerModule;
use Piwik\Plugins\UserCountry\UserCountry;
use Piwik\Settings\Setting;
use Piwik\Settings\FieldConfig;
/**
* Defines Settings for UserCountry.
*/
class SystemSettings extends \Piwik\Settings\Plugin\SystemSettings
{
/** @var Setting[] */
public $geoIp2variables;
/** @var Setting */
public $useCustomVars;
protected function init()
{
$this->title = Piwik::translate('GeoIp2_ServerBasedVariablesConfiguration');
$geoIpAdminEnabled = UserCountry::isGeoLocationAdminEnabled();
$this->useCustomVars = $this->makeSetting('geoip2usecustom', false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
$field->title = Piwik::translate('GeoIp2_ShowCustomServerVariablesConfig');
$field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
});
$this->useCustomVars->setIsWritableByCurrentUser($geoIpAdminEnabled);
foreach (ServerModule::$defaultGeoIpServerVars as $name => $value) {
$this->geoIp2variables[$name] = $this->createGeoIp2ServerVarSetting($name, $value);
$this->geoIp2variables[$name]->setIsWritableByCurrentUser($geoIpAdminEnabled);
}
}
private function createGeoIp2ServerVarSetting($name, $defaultValue)
{
return $this->makeSetting('geoip2var_'.$name, $default = $defaultValue, FieldConfig::TYPE_STRING, function (FieldConfig $field) use ($name) {
$field->title = Piwik::translate('GeoIp2_ServerVariableFor', '<strong>' . str_replace('_', ' ', $name) . '</strong>');
$field->uiControl = FieldConfig::UI_CONTROL_TEXT;
$field->condition = 'geoip2usecustom==1';
});
}
}

View File

@ -0,0 +1,23 @@
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\GeoIp2;
use Piwik\Plugins\UserCountry\UserCountry;
use Piwik\SettingsPiwik;
class Tasks extends \Piwik\Plugin\Tasks
{
public function schedule()
{
// add the auto updater task if GeoIP admin is enabled
if (UserCountry::isGeoLocationAdminEnabled() && SettingsPiwik::isInternetEnabled() === true) {
$this->scheduleTask(new GeoIP2AutoUpdater());
}
}
}

View File

@ -0,0 +1,5 @@
<?php
return [
'path.geoip2' => DI\string('{path.root}/misc/'),
];

View File

@ -0,0 +1,5 @@
<?php
return [
'path.geoip2' => DI\string('{path.root}/tests/lib/geoip-files/'),
];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Im TAR Archiv %1$s konnte keine gültige GeoIP Datenbank gefunden werden!",
"CannotUnzipGeoIPFile": "Konnte GeoIP-Datei in %1$s nicht entpacken: %2$s",
"PluginDescription": "Liefert GeoIP 2 Standorterkennungsdienste.",
"LocationProviderDesc_Php": "Diese Art der Standortbestimmung ist am einfachsten zu installieren, da Sie keine Serverkonfiguration benötigt (Ideal für Shared Hosting!). Sie verwendet eine GeoIP2-Datenbank und die PHP-API von MaxMind um den Standort eines Besuchers genau zu bestimmen.",
"LocationProviderDesc_Php_WithExtension": "Dieser Standorterkennungsdienst wird durch die installierte %1$smaxminddb%2$s Erweiterung beschleunigt.",
"LocationProviderDesc_ServerModule": "Diese Art der Standortbestimmung verwendet das GeoIP2-Modul das auf ihrem HTTP-Server installiert ist. Diese ist am schnellsten und genauesten, aber %1$skann nur bei normalem Browser-Tracking benutzt werden%2$s",
"LocationProviderDesc_ServerModule2": "Falls Sie Protokolldateien oder andere Dinge importieren welche IP-Adressen enthalten sollten Sie die %3$sPHP GeoIP 2 Implementierung%4$s nutzen und die %1$smaxminddb Erweiterung%2$s installieren.",
"ServerBasedVariablesConfiguration": "Einstellungen für die Servervariablen die vom GeoIP 2 HTTP-Server-Modul benutzt werden.",
"GeoIPVariablesConfigurationHere": "Sie können benutze Servervariablen %1$shier%2$s konfigurieren.",
"ServerVariableFor": "Servervariable für %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Δεν βρέθηκε έγκυρη βάση GeoIP στο αρχείο tar %1$s!",
"CannotUnzipGeoIPFile": "Δεν ήταν δυνατή η αποσυμπίεση του αρχείου GeoIP στο %1$s: %2$s",
"PluginDescription": "Δίνει τους παρόχους τοποθεσιών GeoIP2.",
"LocationProviderDesc_Php": "Αυτός ο πάροχος τοποθεσιών είναι ο πιο απλός στην εγκατάσταση, καθώς δεν απαιτεί παραμετροποίηση στον διακομιστή (ιδανικός για μοιραζόμενη φιλοξενία!). Χρησιμοποιεί μια βάση GeoIP 2 και το PHP API της MaxMind για να καθορίσει με ακρίβεια την τοποθεσία των επισκεπτών σας.",
"LocationProviderDesc_Php_WithExtension": "Αυτός ο πάροχος τοποθεσίας αυξάνει την ταχύτητά του με την εγκατεστημένη επέκταση %1$smaxminddb%2$s.",
"LocationProviderDesc_ServerModule": "Αυτός ο πάροχος τοποθεσίας χρησιμοποιεί το άρθρωμα GeoIP 2 που έχει εγκατασταθεί στον διακομιστή ιστού σας. Ο πάροχος είναι γρήγορος και ακριβής, αλλά %1$sμπορεί να χρησιμοποιηθεί μόνο με την κλασική παρακολούθηση μέσω του φυλλομετρητή σας.%2$s",
"LocationProviderDesc_ServerModule2": "Αν επιθυμείτε να εισαγάγετε αρχεία καταγραφής ή να κάνετε κάτι άλλο που απαιτεί τον ορισμό διευθύνσεων IP, χρησιμοποιήστε την %3$sPHP GeoIP 2 υλοποίηση%4$s και εγκαταστήστε την %1$sεπέκταση maxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Παραμετροποίηση των μεταβλητών διακομιστή που χρησιμοποιούνται από τα αρθρώματα GeoIP 2 του διακομιστή",
"GeoIPVariablesConfigurationHere": "Μπορείτε να παραμετροποιήσετε τις μεταβλητές διακομιστή που χρησιμοποιούνται %1$sεδώ%2$s.",
"ServerVariableFor": "Μεταβλητή διακομιστή για %s"
}
}

View File

@ -0,0 +1,15 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "No valid 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 most simple 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.",
"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.",
"ServerBasedVariablesConfiguration": "Configuration for server variables used by GeoIP 2 server modules",
"GeoIPVariablesConfigurationHere": "You can configure used server variables %1$shere%2$s.",
"ShowCustomServerVariablesConfig": "I use the Geoip2 server module (Nginx, Apache...) and want to configure server variables",
"ServerVariableFor": "Server variable for %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "No se pudo encontrar una base de datos GeoIP válida en el archivo tar %1$s!",
"CannotUnzipGeoIPFile": "No se pudo descomprimir archivo GeoIP en %1$s: %2$s",
"PluginDescription": "Suministra proveedores de localización GeoIP2.",
"LocationProviderDesc_Php": "Este proveedor de ubicación es el más sencillo de instalar, ya que no requiere configuración del servidor (¡ideal para alojamiento compartido!). Utiliza una base de datos GeoIP 2 y la API PHP de MaxMind para determinar con precisión la ubicación de sus visitantes.",
"LocationProviderDesc_Php_WithExtension": "Este proveedor de ubicación se acelera con la extensión %1$smaxminddb%2$s instalada.",
"LocationProviderDesc_ServerModule": "Este proveedor de ubicación utiliza el módulo GeoIP 2 que se ha instalado en su servidor HTTP. Este proveedor es rápido y preciso, pero %1$ssolo se puede utilizar con la función de rastreo normal de su navegador.%2$s",
"LocationProviderDesc_ServerModule2": "Si tiene que importar archivos de registro u otras tareas que requieran configurar direcciones IP, use la %3$simplementación de PHP GeoIP 2%4$s e instale la %1$sextensión maxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Configuración para variables de servidor utilizadas por los módulos de servidor GeoIP 2",
"GeoIPVariablesConfigurationHere": "Puede configurar las variables de servidor usadas %1$saquí%2$s",
"ServerVariableFor": "Variable del servidor para %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Aucune base de données GeoIP valide trouvée dans l'archive tar %1$s!",
"CannotUnzipGeoIPFile": "Impossible de décompresser le fichier GeoIP dans %1$s: %2$s",
"PluginDescription": "Fournit des services de localisation GeoIP2.",
"LocationProviderDesc_Php": "Ce service de localisation est le plus simple à installer et ne requiert aucune configuration du serveur (idéal pour les hébergements partagés!). Il utilise une base de données GeoIP 2 et l'API PHP MaxMind afin de déterminer précisément la localisation de vos visiteurs.",
"LocationProviderDesc_Php_WithExtension": "Ce service de localisation est plus performant grâce à l'installation de l'extension %1$smaxminddb%2$s.",
"LocationProviderDesc_ServerModule": "Ce service de localisation utilise le module GeoIP 2 qui peut être installé sur votre serveur HTTP. Ce service est rapide est précis mais %1$speut uniquement être utilisé avec le système de suivit du navigateur classique. %2$s",
"LocationProviderDesc_ServerModule2": "Si vous devez importer des fichiers de journaux ou bien effectuer quoi que ce soit d'autre qui requiert la définition des adresses IP, utilisez %3$sl'implémentation PHP GeoIP 2%4$s et installez %1$sl'extension maxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Configuration des variables serveur utilisées par le module GeoIP 2.",
"GeoIPVariablesConfigurationHere": "Vous pouvez configurer les variables serveur utilisées %1$sici%2$s.",
"ServerVariableFor": "Variable serveur pour %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Nell'archivio tar %1$s non è stato trovato un database GeoIP valido!",
"CannotUnzipGeoIPFile": "impossibile scompattare il file geoIP in %1$s: %2$s",
"PluginDescription": "Fornisce i provider di posizione GeoIP2.",
"LocationProviderDesc_Php": "Il provider di localizzazione è molto semplice da installare poiché non richiede una configurazione del server (ideale per gli hosting condivisi). Esso utilizza un database GeoIP 2 e un'API PHP di MaxMind per determinare con accuratezza la posizione dei tuoi visitatori.",
"LocationProviderDesc_Php_WithExtension": "Questo provider di posizione viene velocizzato dall'estensione installata %1$smaxminddb%2$s.",
"LocationProviderDesc_ServerModule": "Questo provider di posizione utilizza il modulo GeoIP 2 che è stato installato nel tuo server HTTP. Questo provider è veloce e accurato, ma %1$s può solo essere utilizzato con il normale tracciamento del browser.%2$s",
"LocationProviderDesc_ServerModule2": "Se devi importare i file di log o fare qualcos'altro che richiede l'impostazione di indirizzi IP, usa %3$sl'implementazione PHP geoIP 2%4$s e installa %1$sl'estensione maxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Configurazione per le variabili del server utilizzate dai moduli server di GeoIP 2",
"GeoIPVariablesConfigurationHere": "Puoi configurare %1$squi%2$s le variabili del server utilizzate.",
"ServerVariableFor": "Variabili del server per %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "TAR アーカイブ %1$sに有効な GeoIP データベースが見つかりません!",
"CannotUnzipGeoIPFile": "%1$s の GeoIP ファイルを解凍できません: %2$s",
"PluginDescription": "GeoIP2 ロケーションプロバイダを提供します。",
"LocationProviderDesc_Php": "サーバー設定 が必要ないため(共有ホスティングに最適です!) 、この位置情報プロバイダーは非常に簡単にインストールできます。ビジターの位置情報を正確に決定するために、GeoIP2 データベースと MaxMind の PHP API を使用します。",
"LocationProviderDesc_Php_WithExtension": "この位置情報プロバイダーは、インストールされた %1$smaxminddb%2$s 拡張により高速化されています。",
"LocationProviderDesc_ServerModule": "このロケーションプロバイダーは、HTTP サーバーにインストールされている GeoIP2 モジュールを使用します。 このプロバイダは高速で正確ですが、%1$s通常のブラウザトラッキングでのみ使用できます。%2$s",
"LocationProviderDesc_ServerModule2": "ログファイルをインポートする必要がある場合やIPアドレスの設定が必要な場合は、 %3$sPHP GeoIP2 実装%4$s を使用し、%1$smaxminddb 拡張%2$sをインストールしてください。",
"ServerBasedVariablesConfiguration": "GeoIP2 サーバーモジュールで使用されるサーバー変数の設定",
"GeoIPVariablesConfigurationHere": "%1$sこちら%2$s で使用しているサーバー変数の設定ができます。",
"ServerVariableFor": "%s のサーバー変数"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Archiwum tar %1$s nie zawiera poprawnej bazy GeoIP!",
"CannotUnzipGeoIPFile": "Nie udało się rozpakować pliku GeoIP %1$s: %2$s",
"PluginDescription": "Dostarcza dostawców lokalizacji GeoIP2.",
"LocationProviderDesc_Php": "Ten dostawca lokalizacji jest najprostszy w instalacji ponieważ nie wymaga konfiguracji serwera (idealne w hostingu współdzielonym!). Korzysta z bazy GeoIP2 i API PHP firmy MaxMind aby dokładnie określać lokalizację Twoich odwiedzających.",
"LocationProviderDesc_Php_WithExtension": "Ten dostawca lokalizacji przyspiesza dzięki zainstalowanemu rozszerzeniu %1$smaxminddb%2$s.",
"LocationProviderDesc_ServerModule": "Ten dostawca lokalizacji wykorzystuje moduł GeoIP2 zainstalowany w Twoim serwerze WWW. Działa szybko i dokładnie, ale %1$smoże być wykorzystany przy śledzeniu ruchu przeglądarek.%2$s",
"LocationProviderDesc_ServerModule2": "Jeśli musisz zaimportować pliki logów lub zrobić coś innego, co wymaga ustawienia adresu IP, użyj %3$simplementacji PHP dla GeoIP2%4$s i zainstaluj %1$srozszerzenie maxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Konfiguracja zmiennych serwera używanych przez moduł GeoIP2",
"GeoIPVariablesConfigurationHere": "Tu możesz skonfigurować wykorzystywane %1$szmienne serwera%2$s",
"ServerVariableFor": "Zmienna serwera określająca %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Não foi encontrada uma base de dados GeoIP válida no arquivo tar %1$s!",
"CannotUnzipGeoIPFile": "Não foi possível extrair o ficheiro GeoIP em %1$s: %2$s",
"PluginDescription": "Fornece fornecedores de localização GeoIP2.",
"LocationProviderDesc_Php": "Este fornecedor de localização é o mais simples de instalar e não requer configurações no servidor (ideal para alojamentos partilhados). Utiliza uma base de dados GeoIP 2 e a API PHP do MaxMind para determinar com precisão a localização dos seus visitantes.",
"LocationProviderDesc_Php_WithExtension": "Este fornecedor de localização é acelerado pela extensão %1$smaxminddb%2$s instalada.",
"LocationProviderDesc_ServerModule": "Este fornecedor de localização utiliza o módulo GeoIP 2 que foi instalado no seu servidor HTTP. Este fornecedor é rápido e preciso, mas %1$ssó pode ser utilizado para um acompanhamento normal de navegadores.%2$s",
"LocationProviderDesc_ServerModule2": "Se tiver de importar ficheiros de registo ou fazer algo mais que necessite da definição de endereços de IP, utilize a %3$simplementação PHP do GeoIP 2%4$s e instale a %1$sextensão maxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Configuração para variáveis do servidor utilizadas pelos módulos do servidor GeoIP 2",
"GeoIPVariablesConfigurationHere": "Pode configurar as variáveis de servidor utilizadas %1$saqui%2$s.",
"ServerVariableFor": "Variável do servidor para %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "В tar-архиве %1$s не найдено корректной базы данных GeoIP!",
"CannotUnzipGeoIPFile": "Не получилось распаковать файл GeoIP за %1$s:%2$s",
"PluginDescription": "Механизмы определения местонахождения GeoIP 2.",
"LocationProviderDesc_Php": "Этот механизм определения местонахождения является наиболее простым в установке, поскольку не требует настройки сервера (идеально для виртуального хостинга!). Он использует базы данных GeoIP2 и PHP API от MaxMind, чтобы точно определить местоположение ваших посетителей.",
"LocationProviderDesc_Php_WithExtension": "Этот механизм определения местонахождения ускорен установленным расширением %1$smaxminddb%2$s.",
"LocationProviderDesc_ServerModule": "Этот механизм определения местонахождения использует модуль GeoIP 2, установленный на ваш HTTP-сервер. Он быстр и точен, но %1$s может быть использован только при отслеживании обычных браузеров.%2$s",
"LocationProviderDesc_ServerModule2": "Если вам нужно импортировать лог-файлы или сделать что-то еще, требующее использование IP-адресов, используйте %3$sPHP GeoIp 2%4$s и установите расширение %1$smaxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Конфигурация серверных переменных, использованная модулями сервера GeoIP 2.",
"GeoIPVariablesConfigurationHere": "Вы можете сконфигурировать используемые серверные переменные %1$s здесь %2$s.",
"ServerVariableFor": "Серверная переменная для %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Su gjet dot bazë e vlefshme të dhënash GeoIP te arkivi tar %1$s!",
"CannotUnzipGeoIPFile": "Su shzipua dot kartela GeoIP te %1$s: %2$s",
"PluginDescription": "Furnizon shërbime vendndodhjesh GeoIP2.",
"LocationProviderDesc_Php": "Ky furnizues vendndodhjesh është më i thjeshti për tu instaluar, ngaqë slyp formësim shërbyesi (i përsosur për strehim të përbashkët!). Për përcaktimin me saktësi të vendndodhjes së vizitorëve tuaj, ai përdor një bazë të dhënash GeoIP 2 dhe API-n PHP të MaxMind-it.",
"LocationProviderDesc_Php_WithExtension": "Ky furnizues vendndodhjesh përshpejtohet nga zgjerimi %1$smaxminddb%2$s i instaluar.",
"LocationProviderDesc_ServerModule": "Ky furnizues vendndodhjesh përdor modulin GeoIP 2 që është instaluar te shërbyesi juaj HTTP. Ky furnizues është i shpejtë dhe i përpiktë, por %1$smund të përdoret vetëm me ndjekje të zakonshme të shfletimit.%2$s",
"LocationProviderDesc_ServerModule2": "Nëse ju duhet të importoni kartela regjistër ose të bëni diçka tjetër që lyp caktim adresash IP, përdorni %3$ssendërtimin PHP GeoIP 2%4$s dhe instaloni %1$szgjerimin maxminddb%2$s.",
"ServerBasedVariablesConfiguration": "Formësim për ndryshore shërbyesi të përdorura nga module GeoIP 2 shërbyesi",
"GeoIPVariablesConfigurationHere": "Ndryshoret e shërbyesit që përdoren mund ti formësoni nga %1$skëtu%2$s.",
"ServerVariableFor": "Ndryshore shërbyesi për %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Tar-arkivet %1$sinnehåller ingen GeoIP-databas!",
"CannotUnzipGeoIPFile": "Kan inte packa upp GeoIP-filen i %1$s: %2$s",
"PluginDescription": "Tillhandahåller platstjänster för GeoIP2.",
"LocationProviderDesc_Php": "Den här platstjänsten är enklast att installera och kräver ingen serverkonfiguration (perfekt för delade webbhotell!). Den använder en GeoIP 2-databas och MaxMinds PHP-API för att med stor precision fastställa dina besökares platser.",
"LocationProviderDesc_Php_WithExtension": "Den här platstjänsten kan göras snabbare med det installerade %1$smaxminddb%2$s-tillägget.",
"LocationProviderDesc_ServerModule": "Den här platstjänsten använder GeoIP 2-modulen som installerats på din HTTP-server. Den här tjänsten är snabb och träffsäker, men %1$skan endast användas tillsammans med normal webbläsarspårning.%2$s",
"LocationProviderDesc_ServerModule2": "Om du behöver importera loggfiler eller göra något annat som kräver IP-adresser: Använd %1$sPECL GeoIP (rekommenderas)%2$s eller %3$sPHP GeoIP%4$s.",
"ServerBasedVariablesConfiguration": "Konfigurering av servervariabler som används av GeoIP 2-servermoduler",
"GeoIPVariablesConfigurationHere": "Du kan konfigurera de använda servervariablerna %1$shär%2$s.",
"ServerVariableFor": "Servervariabel för %s"
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "%1$s tar arşivi dosyasında geçerli bir GeoIP veritabanı bulunamadı!",
"CannotUnzipGeoIPFile": "%1$s içindeki GeoIP arşivi dosyası ayıklanamadı: %2$s",
"PluginDescription": "GeoIP2 konum hizmeti sağlayıcılarını sunar.",
"LocationProviderDesc_Php": "Bu konum hizmeti sağlayıcısı, sunucu yapılandırması gerektirmediğinden kurulumu en kolay olanıdır (paylaşımlı barındırma için idealdir). GeoIP 2 veritabanı ve MaxMind PHP API uygulamasını kullanarak ziyaretçilerinizin konumunu büyük doğruluk ile belirler.",
"LocationProviderDesc_Php_WithExtension": "Bu konum hizmeti sağlayıcısı %1$smaxminddb%2$s eklentisi kurularak hızlandırılmıştır.",
"LocationProviderDesc_ServerModule": "Bu konum hizmeti sağlayıcısı HTTP sunucunuz üzerine kurulmuş GeoIP 2 modülünü kullanır. Bu hizmet sağlayıcı hızlı ve doğrudur ancak %1$syalnız normal web tarayıcı izlemesi ile kullanılabilir%2$s.",
"LocationProviderDesc_ServerModule2": "Günlük dosyalarını içe aktarmak ya da IP adresinin ayarlanmasını gerektiren başka bir işlem yapmak zorundaysanız, %3$sPHP GeoIp 2 uygulamasını%4$s kullanarak %1$smaxminddb eklentisini%2$s kurun.",
"ServerBasedVariablesConfiguration": "GeoIP 2 sunucu modülleri tarafından kullanılan sunucu değişkeni yapılandırması",
"GeoIPVariablesConfigurationHere": "Kullanılan sunucu değişkenleri %1$sburadan%2$s yapılandırılabilir.",
"ServerVariableFor": "%s için sunucu değişkeni"
}
}

View File

@ -0,0 +1,7 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "Không có cơ sở dữ liệu GeoIP hợp lệ trong kho lưu trữ tar %1$s!",
"CannotUnzipGeoIPFile": "Không thể giải nén tệp GeoIP trong %1$s: %2$s",
"PluginDescription": "Cung cấp vị trí nhà cung cấp GeoIP2."
}
}

View File

@ -0,0 +1,14 @@
{
"GeoIp2": {
"CannotFindGeoIPDatabaseInArchive": "在 tar 壓縮檔 %1$s 中找不到可用的 GeoIP 資料庫。",
"CannotUnzipGeoIPFile": "無法解壓縮 %1$s 中的 GeoIP 檔案:%2$s",
"PluginDescription": "提供 GeoIP2 地理位置供應商。",
"LocationProviderDesc_Php": "這個地理位置供應商是安裝方式最簡單的,因為它不需要更動任何伺服器設定(共享主機適用!)。它使用 GeoIP 2 資料庫和 MaxMind 的 PHP API 來精準的判別訪客的位置。",
"LocationProviderDesc_Php_WithExtension": "這個地理位置供應商已透過安裝的 %1$smaxminddb%2$s 擴充功能加速。",
"LocationProviderDesc_ServerModule": "這個地理位置供應商使用安裝在你 HTTP 伺服器上的 GeoIP 2 模組。這個供應商快又精準,但是%1$s只適用於一般瀏覽器上的追蹤%2$s。",
"LocationProviderDesc_ServerModule2": "如果你需要匯入紀錄檔或是其他需要設定 IP 位址的事情,使用 %3$sPHP GeoIP 2 implementation%4$s 並安裝 %1$smaxminddb 擴充功能%2$s。",
"ServerBasedVariablesConfiguration": "GeoIP 2 伺服器模組所使用的伺服器變數設定檔",
"GeoIPVariablesConfigurationHere": "你可以在%1$s這裡%2$s設置已使用的伺服器變數。",
"ServerVariableFor": "%s 的伺服器變數"
}
}