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,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;
}
}