diff options
author | mattab <matthieu.aubry@gmail.com> | 2013-03-28 03:42:39 +0400 |
---|---|---|
committer | mattab <matthieu.aubry@gmail.com> | 2013-03-28 03:42:40 +0400 |
commit | ae4b03163792f0b6e933933e5d37df87dc3fd566 (patch) | |
tree | d1d7510a9728f587d3d63ebd03e4ecf3d904838b /plugins/UserCountry/LocationProvider | |
parent | 158c2150f5f2e13ece459b8d131244c11b763997 (diff) |
Mass conversion of all files to the newly agreed coding standard: PSR 1/2
Converting Piwik core source files, PHP, JS, TPL, CSS
More info: http://piwik.org/participate/coding-standards/
Diffstat (limited to 'plugins/UserCountry/LocationProvider')
-rwxr-xr-x | plugins/UserCountry/LocationProvider/Default.php | 182 | ||||
-rwxr-xr-x | plugins/UserCountry/LocationProvider/GeoIp.php | 495 | ||||
-rwxr-xr-x | plugins/UserCountry/LocationProvider/GeoIp/Pecl.php | 641 | ||||
-rwxr-xr-x | plugins/UserCountry/LocationProvider/GeoIp/Php.php | 651 | ||||
-rwxr-xr-x | plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php | 547 |
5 files changed, 1208 insertions, 1308 deletions
diff --git a/plugins/UserCountry/LocationProvider/Default.php b/plugins/UserCountry/LocationProvider/Default.php index a24c3a7cd9..f19fc47641 100755 --- a/plugins/UserCountry/LocationProvider/Default.php +++ b/plugins/UserCountry/LocationProvider/Default.php @@ -1,10 +1,10 @@ <?php /** * Piwik - Open source web analytics - * + * * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * + * * @category Piwik_Plugins * @package Piwik_UserCountry */ @@ -12,99 +12,99 @@ /** * The default LocationProvider, this LocationProvider guesses a visitor's country * using the language they use. This provider is not very accurate. - * + * * @package Piwik_UserCountry */ class Piwik_UserCountry_LocationProvider_Default extends Piwik_UserCountry_LocationProvider { - const ID = 'default'; - const TITLE = 'General_Default'; - - /** - * Guesses a visitor's location using a visitor's browser language. - * - * @param array $info Contains 'ip' & 'lang' keys. - * @return array Contains the guessed country code mapped to LocationProvider::COUNTRY_CODE_KEY. - */ - public function getLocation( $info ) - { - $enableLanguageToCountryGuess = Piwik_Config::getInstance()->Tracker['enable_language_to_country_guess']; + const ID = 'default'; + const TITLE = 'General_Default'; - if(empty($info['lang'])) { - $info['lang'] = Piwik_Common::getBrowserLanguage(); - } - $country = Piwik_Common::getCountry($info['lang'], $enableLanguageToCountryGuess, $info['ip']); - - $location = array(parent::COUNTRY_CODE_KEY => $country); - $this->completeLocationResult($location); - - return $location; - } - - /** - * Returns whether this location provider is available. - * - * This implementation is always available. - * - * @return true - */ - public function isAvailable() - { - return true; - } - - /** - * Returns whether this location provider is working correctly. - * - * This implementation is always working correctly. - * - * @return true - */ - public function isWorking() - { - return true; - } - - /** - * Returns an array describing the types of location information this provider will - * return. - * - * This provider supports the following types of location info: - * - continent code - * - continent name - * - country code - * - country name - * - * @return array - */ - public function getSupportedLocationInfo() - { - return array(self::CONTINENT_CODE_KEY => true, - self::CONTINENT_NAME_KEY => true, - self::COUNTRY_CODE_KEY => true, - self::COUNTRY_NAME_KEY => true); - } - - /** - * Returns information about this location provider. Contains an id, title & description: - * - * array( - * 'id' => 'default', - * 'title' => '...', - * 'description' => '...' - * ); - * - * @return array - */ - public function getInfo() - { - $desc = Piwik_Translate('UserCountry_DefaultLocationProviderDesc1') . ' ' - . Piwik_Translate('UserCountry_DefaultLocationProviderDesc2', - array('<strong>', '<em>', '</em>', '</strong>')) - . '<p><em><a href="http://piwik.org/faq/how-to/#faq_163" target="_blank">' - . Piwik_Translate('UserCountry_HowToInstallGeoIPDatabases') - . '</em></a></p>'; - return array('id' => self::ID, 'title' => self::TITLE, 'description' => $desc, 'order' => 1); - } + /** + * Guesses a visitor's location using a visitor's browser language. + * + * @param array $info Contains 'ip' & 'lang' keys. + * @return array Contains the guessed country code mapped to LocationProvider::COUNTRY_CODE_KEY. + */ + public function getLocation($info) + { + $enableLanguageToCountryGuess = Piwik_Config::getInstance()->Tracker['enable_language_to_country_guess']; + + if (empty($info['lang'])) { + $info['lang'] = Piwik_Common::getBrowserLanguage(); + } + $country = Piwik_Common::getCountry($info['lang'], $enableLanguageToCountryGuess, $info['ip']); + + $location = array(parent::COUNTRY_CODE_KEY => $country); + $this->completeLocationResult($location); + + return $location; + } + + /** + * Returns whether this location provider is available. + * + * This implementation is always available. + * + * @return true + */ + public function isAvailable() + { + return true; + } + + /** + * Returns whether this location provider is working correctly. + * + * This implementation is always working correctly. + * + * @return true + */ + public function isWorking() + { + return true; + } + + /** + * Returns an array describing the types of location information this provider will + * return. + * + * This provider supports the following types of location info: + * - continent code + * - continent name + * - country code + * - country name + * + * @return array + */ + public function getSupportedLocationInfo() + { + return array(self::CONTINENT_CODE_KEY => true, + self::CONTINENT_NAME_KEY => true, + self::COUNTRY_CODE_KEY => true, + self::COUNTRY_NAME_KEY => true); + } + + /** + * Returns information about this location provider. Contains an id, title & description: + * + * array( + * 'id' => 'default', + * 'title' => '...', + * 'description' => '...' + * ); + * + * @return array + */ + public function getInfo() + { + $desc = Piwik_Translate('UserCountry_DefaultLocationProviderDesc1') . ' ' + . Piwik_Translate('UserCountry_DefaultLocationProviderDesc2', + array('<strong>', '<em>', '</em>', '</strong>')) + . '<p><em><a href="http://piwik.org/faq/how-to/#faq_163" target="_blank">' + . Piwik_Translate('UserCountry_HowToInstallGeoIPDatabases') + . '</em></a></p>'; + return array('id' => self::ID, 'title' => self::TITLE, 'description' => $desc, 'order' => 1); + } } diff --git a/plugins/UserCountry/LocationProvider/GeoIp.php b/plugins/UserCountry/LocationProvider/GeoIp.php index 4af024ae96..f7a9029797 100755 --- a/plugins/UserCountry/LocationProvider/GeoIp.php +++ b/plugins/UserCountry/LocationProvider/GeoIp.php @@ -1,274 +1,257 @@ <?php /** * Piwik - Open source web analytics - * + * * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * + * * @category Piwik_Plugins * @package Piwik_UserCountry */ /** * Base type for all GeoIP LocationProviders. - * + * * @package Piwik_UserCountry */ abstract class Piwik_UserCountry_LocationProvider_GeoIp extends Piwik_UserCountry_LocationProvider { - /* For testing, use: 'http://piwik-team.s3.amazonaws.com/GeoLiteCity.dat.gz' */ - const GEO_LITE_URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz'; - const TEST_IP = '194.57.91.215'; - - public static $geoIPDatabaseDir = 'misc'; - - /** - * Stores possible database file names categorized by the type of information - * GeoIP databases hold. - * - * @var array - */ - public static $dbNames = array( - 'loc' => array('GeoIPCity.dat', 'GeoLiteCity.dat', 'GeoIP.dat'), - 'isp' => array('GeoIPISP.dat'), - 'org' => array('GeoIPOrg.dat'), - ); - - /** - * Cached region name array. Data is from geoipregionvars.php. - * - * @var array - */ - private static $regionNames = null; - - /** - * Attempts to fill in some missing information in a GeoIP location. - * - * This method will call LocationProvider::completeLocationResult and then - * try to set the region name of the location if the country code & region - * code are set. - * - * @param array $location The location information to modify. - */ - public function completeLocationResult( &$location ) - { - $this->fixupLocation($location); - parent::completeLocationResult($location); - - // set region name if region code is set - if (empty($location[self::REGION_NAME_KEY]) - && !empty($location[self::REGION_CODE_KEY]) - && !empty($location[self::COUNTRY_CODE_KEY])) - { - $countryCode = $location[self::COUNTRY_CODE_KEY]; - $regionCode = (string)$location[self::REGION_CODE_KEY]; - $location[self::REGION_NAME_KEY] = self::getRegionNameFromCodes($countryCode, $regionCode); - } - } - - /** - * Fix up data to work with our SVG maps which include 'Tib' boundaries - */ - protected function fixupLocation( &$location ) - { - if(!empty($location[self::REGION_CODE_KEY]) - && $location[self::REGION_CODE_KEY] == '14' - && !empty($location[self::COUNTRY_CODE_KEY]) - && strtoupper($location[self::COUNTRY_CODE_KEY]) == 'CN') - { - $location[self::COUNTRY_CODE_KEY] = 'ti'; - $location[self::REGION_CODE_KEY] = '1'; - } - } - - /** - * Returns true if this provider has been setup correctly, the error message if - * otherwise. - * - * @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 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)) - { - require_once PIWIK_INCLUDE_PATH . '/libs/MaxMindGeoIP/geoipregionvars.php'; - self::$regionNames = $GEOIP_REGION_NAME; - } - - return self::$regionNames; - } - - /** - * Returns the path of an existing GeoIP 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 database managed by Piwik. - * - * @param string $filename Name of the .dat file. - * @return string - */ - public static function getPathForGeoIpDatabase( $filename ) - { - return PIWIK_INCLUDE_PATH.'/'.self::$geoIPDatabaseDir.'/'.$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)) - { - // TODO: what happens when IP changes? should we get this information from piwik.org? - $expected = array(self::COUNTRY_CODE_KEY => 'FR', - self::REGION_CODE_KEY => 'A6', - self::CITY_NAME_KEY => 'Besançon'); - $result = array(self::TEST_IP, $expected); - } - return $result; - } - - /** - * Returns true if there is a GeoIP database in the 'misc' directory. - * - * @return bool - */ - public static function isDatabaseInstalled() - { - return self::getPathToGeoIpDatabase(self::$dbNames['loc']) - || self::getPathToGeoIpDatabase(self::$dbNames['isp']) - || self::getPathToGeoIpDatabase(self::$dbNames['org']); - } - - /** - * Returns the type of GeoIP database ('loc', 'isp' or 'org') based on the - * filename (eg, 'GeoLiteCity.dat', 'GeoIPISP.dat', etc). - * - * @param string $filename - * @return string|false 'loc', 'isp', 'org', 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; - } + /* For testing, use: 'http://piwik-team.s3.amazonaws.com/GeoLiteCity.dat.gz' */ + const GEO_LITE_URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz'; + const TEST_IP = '194.57.91.215'; + + public static $geoIPDatabaseDir = 'misc'; + + /** + * Stores possible database file names categorized by the type of information + * GeoIP databases hold. + * + * @var array + */ + public static $dbNames = array( + 'loc' => array('GeoIPCity.dat', 'GeoLiteCity.dat', 'GeoIP.dat'), + 'isp' => array('GeoIPISP.dat'), + 'org' => array('GeoIPOrg.dat'), + ); + + /** + * Cached region name array. Data is from geoipregionvars.php. + * + * @var array + */ + private static $regionNames = null; + + /** + * Attempts to fill in some missing information in a GeoIP location. + * + * This method will call LocationProvider::completeLocationResult and then + * try to set the region name of the location if the country code & region + * code are set. + * + * @param array $location The location information to modify. + */ + public function completeLocationResult(&$location) + { + $this->fixupLocation($location); + parent::completeLocationResult($location); + + // set region name if region code is set + if (empty($location[self::REGION_NAME_KEY]) + && !empty($location[self::REGION_CODE_KEY]) + && !empty($location[self::COUNTRY_CODE_KEY]) + ) { + $countryCode = $location[self::COUNTRY_CODE_KEY]; + $regionCode = (string)$location[self::REGION_CODE_KEY]; + $location[self::REGION_NAME_KEY] = self::getRegionNameFromCodes($countryCode, $regionCode); + } + } + + /** + * Fix up data to work with our SVG maps which include 'Tib' boundaries + */ + protected function fixupLocation(&$location) + { + if (!empty($location[self::REGION_CODE_KEY]) + && $location[self::REGION_CODE_KEY] == '14' + && !empty($location[self::COUNTRY_CODE_KEY]) + && strtoupper($location[self::COUNTRY_CODE_KEY]) == 'CN' + ) { + $location[self::COUNTRY_CODE_KEY] = 'ti'; + $location[self::REGION_CODE_KEY] = '1'; + } + } + + /** + * Returns true if this provider has been setup correctly, the error message if + * otherwise. + * + * @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 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)) { + require_once PIWIK_INCLUDE_PATH . '/libs/MaxMindGeoIP/geoipregionvars.php'; + self::$regionNames = $GEOIP_REGION_NAME; + } + + return self::$regionNames; + } + + /** + * Returns the path of an existing GeoIP 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 database managed by Piwik. + * + * @param string $filename Name of the .dat file. + * @return string + */ + public static function getPathForGeoIpDatabase($filename) + { + return PIWIK_INCLUDE_PATH . '/' . self::$geoIPDatabaseDir . '/' . $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)) { + // TODO: what happens when IP changes? should we get this information from piwik.org? + $expected = array(self::COUNTRY_CODE_KEY => 'FR', + self::REGION_CODE_KEY => 'A6', + self::CITY_NAME_KEY => 'Besançon'); + $result = array(self::TEST_IP, $expected); + } + return $result; + } + + /** + * Returns true if there is a GeoIP database in the 'misc' directory. + * + * @return bool + */ + public static function isDatabaseInstalled() + { + return self::getPathToGeoIpDatabase(self::$dbNames['loc']) + || self::getPathToGeoIpDatabase(self::$dbNames['isp']) + || self::getPathToGeoIpDatabase(self::$dbNames['org']); + } + + /** + * Returns the type of GeoIP database ('loc', 'isp' or 'org') based on the + * filename (eg, 'GeoLiteCity.dat', 'GeoIPISP.dat', etc). + * + * @param string $filename + * @return string|false 'loc', 'isp', 'org', 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; + } } diff --git a/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php b/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php index b484cbf6b5..9ffc4ffa0a 100755 --- a/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php +++ b/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php @@ -1,353 +1,324 @@ <?php /** * Piwik - Open source web analytics - * + * * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * + * * @category Piwik_Plugins * @package Piwik_UserCountry */ /** * A LocationProvider that uses the PECL implementation of GeoIP. - * + * * FIXME: For some reason, if the PECL module is loaded & an organization DB is available, the PHP * module won't return organization info. If the PECL module is not loaded, organization info is returned. - * + * * @package Piwik_UserCountry */ class Piwik_UserCountry_LocationProvider_GeoIp_Pecl extends Piwik_UserCountry_LocationProvider_GeoIp { - const ID = 'geoip_pecl'; - const TITLE = 'GeoIP (PECL)'; - - /** - * Uses the GeoIP PECL module to get a visitor's location based on their IP address. - * - * This function will return different results based on the data available. If a city - * database can be detected by the PECL module, it may return the country code, - * region code, city name, area code, latitude, longitude and postal code of the visitor. - * - * Alternatively, if only the country database can be detected, only the country code - * will be returned. - * - * The GeoIP PECL module will detect the following filenames: - * - GeoIP.dat - * - GeoIPCity.dat - * - GeoIPISP.dat - * - GeoIPOrg.dat - * - * Note how GeoLiteCity.dat, the name for the GeoLite city database, is not detected - * by the PECL module. - * - * @param array $info Must have an 'ip' field. - * @return array - */ - public function getLocation( $info ) - { - $ip = $this->getIpFromInfo($info); - - $result = array(); - - // get location data - if (self::isCityDatabaseAvailable()) - { - // Must hide errors because missing IPV6: - $location = @geoip_record_by_name($ip); - if (!empty($location)) - { - $result[self::COUNTRY_CODE_KEY] = $location['country_code']; - $result[self::REGION_CODE_KEY] = $location['region']; - $result[self::CITY_NAME_KEY] = utf8_encode($location['city']); - $result[self::AREA_CODE_KEY] = $location['area_code']; - $result[self::LATITUDE_KEY] = $location['latitude']; - $result[self::LONGITUDE_KEY] = $location['longitude']; - $result[self::POSTAL_CODE_KEY] = $location['postal_code']; - } - } - else if (self::isRegionDatabaseAvailable()) - { - $location = @geoip_region_by_name($ip); - if (!empty($location)) - { - $result[self::REGION_CODE_KEY] = $location['region']; - $result[self::COUNTRY_CODE_KEY] = $location['country_code']; - } - } - else - { - $result[self::COUNTRY_CODE_KEY] = @geoip_country_code_by_name($ip); - } - - // get organization data if the org database is available - if (self::isOrgDatabaseAvailable()) - { - $org = @geoip_org_by_name($ip); - if ($org !== false) - { - $result[self::ORG_KEY] = utf8_encode($org); - } - } - - // get isp data if the isp database is available - if (self::isISPDatabaseAvailable()) - { - $isp = @geoip_isp_by_name($ip); - if ($ip !== false) - { - $result[self::ISP_KEY] = utf8_encode($isp); - } - } - - if (empty($result)) - { - return false; - } - - $this->completeLocationResult($result); - return $result; - } - - /** - * Returns true if the PECL module is installed and loaded, false if otherwise. - * - * @return bool - */ - public function isAvailable() - { - return function_exists('geoip_db_avail'); - } - - /** - * Returns true if the PECL module that is installed can be successfully used - * to get the location of an IP address. - * - * @return bool - */ - public function isWorking() - { - // if no no location database is available, this implementation is not setup correctly - if (!self::isLocationDatabaseAvailable()) - { - $dbDir = dirname(geoip_db_filename(GEOIP_COUNTRY_EDITION)).'/'; - $quotedDir = "'$dbDir'"; - - // check if the directory the PECL module is looking for exists - if (!is_dir($dbDir)) - { - return Piwik_Translate('UserCountry_PeclGeoIPNoDBDir', array($quotedDir, "'geoip.custom_directory'")); - } - - // check if the user named the city database GeoLiteCity.dat - if (file_exists($dbDir.'GeoLiteCity.dat')) - { - return Piwik_Translate('UserCountry_PeclGeoLiteError', - array($quotedDir, "'GeoLiteCity.dat'", "'GeoIPCity.dat'")); - } - - return Piwik_Translate('UserCountry_CannotFindPeclGeoIPDb', - array($quotedDir, "'GeoIP.dat'", "'GeoIPCity.dat'")); - } - - return parent::isWorking(); - } - - /** - * 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 organization database is found, organization information is - * supported. - * - * If an ISP database is found, ISP 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; - - if (self::isCityDatabaseAvailable()) - { - $result[self::REGION_CODE_KEY] = true; - $result[self::REGION_NAME_KEY] = true; - $result[self::CITY_NAME_KEY] = true; - $result[self::AREA_CODE_KEY] = true; - $result[self::LATITUDE_KEY] = true; - $result[self::LONGITUDE_KEY] = true; - $result[self::POSTAL_CODE_KEY] = true; - } - else if (self::isRegionDatabaseAvailable()) - { - $result[self::REGION_CODE_KEY] = true; - $result[self::REGION_NAME_KEY] = true; - } - - // check if organization info is available - if (self::isOrgDatabaseAvailable()) - { - $result[self::ORG_KEY] = true; - } - - // check if ISP info is available - if (self::isISPDatabaseAvailable()) - { - $result[self::ISP_KEY] = true; - } - - return $result; - } - - /** - * Returns information about this location provider. Contains an id, title & description: - * - * array( - * 'id' => 'geoip_pecl', - * 'title' => '...', - * 'description' => '...' - * ); - * - * @return array - */ - public function getInfo() - { - $desc = Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Pecl1') . '<br/><br/>' - . Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Pecl2'); - $installDocs = '<em>' - . '<a target="_blank" href="http://piwik.org/faq/how-to/#faq_164">' - . Piwik_Translate('UserCountry_HowToInstallGeoIpPecl') - . '</a>' - . '</em>'; - - $extraMessage = false; - if ($this->isAvailable()) - { - $peclDir = ini_get('geoip.custom_directory'); - if ($peclDir === false) - { - $extraMessage = Piwik_Translate('UserCountry_GeoIPPeclCustomDirNotSet', "'geoip.custom_directory'"); - } - else - { - $extraMessage = 'The \'geoip.custom_directory\' PHP ini option is set to \''.$peclDir.'\'.'; - } - - $availableDatabaseTypes = array(); - if (self::isCityDatabaseAvailable()) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_City'); - } - if (self::isRegionDatabaseAvailable()) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Region'); - } - if (self::isCountryDatabaseAvailable()) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Country'); - } - if (self::isISPDatabaseAvailable()) - { - $availableDatabaseTypes[] = 'ISP'; - } - if (self::isOrgDatabaseAvailable()) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Organization'); - } - - $extraMessage .= '<br/><br/>'.Piwik_Translate('UserCountry_GeoIPImplHasAccessTo').': <strong><em>' - . implode(', ', $availableDatabaseTypes).'</em></strong>.'; - - $extraMessage = '<strong><em>'.Piwik_Translate('General_Note').': </em></strong>'.$extraMessage; - } - - return array('id' => self::ID, - 'title' => self::TITLE, - 'description' => $desc, - 'install_docs' => $installDocs, - 'extra_message' => $extraMessage, - 'order' => 3); - } - - /** - * Returns true if the PECL module can detect a location database (either a country, - * region or city will do). - * - * @return bool - */ - public static function isLocationDatabaseAvailable() - { - return self::isCityDatabaseAvailable() - || self::isRegionDatabaseAvailable() - || self::isCountryDatabaseAvailable(); - } - - /** - * Returns true if the PECL module can detect a city database. - * - * @return bool - */ - public static function isCityDatabaseAvailable() - { - return geoip_db_avail(GEOIP_CITY_EDITION_REV0) - || geoip_db_avail(GEOIP_CITY_EDITION_REV1); - } - - /** - * Returns true if the PECL module can detect a region database. - * - * @return bool - */ - public static function isRegionDatabaseAvailable() - { - return geoip_db_avail(GEOIP_REGION_EDITION_REV0) - || geoip_db_avail(GEOIP_REGION_EDITION_REV1); - } - - /** - * Returns true if the PECL module can detect a country database. - * - * @return bool - */ - public static function isCountryDatabaseAvailable() - { - return geoip_db_avail(GEOIP_COUNTRY_EDITION); - } - - /** - * Returns true if the PECL module can detect an organization database. - * - * @return bool - */ - public static function isOrgDatabaseAvailable() - { - return geoip_db_avail(GEOIP_ORG_EDITION); - } - - /** - * Returns true if the PECL module can detect an ISP database. - * - * @return bool - */ - public static function isISPDatabaseAvailable() - { - return geoip_db_avail(GEOIP_ISP_EDITION); - } + const ID = 'geoip_pecl'; + const TITLE = 'GeoIP (PECL)'; + + /** + * Uses the GeoIP PECL module to get a visitor's location based on their IP address. + * + * This function will return different results based on the data available. If a city + * database can be detected by the PECL module, it may return the country code, + * region code, city name, area code, latitude, longitude and postal code of the visitor. + * + * Alternatively, if only the country database can be detected, only the country code + * will be returned. + * + * The GeoIP PECL module will detect the following filenames: + * - GeoIP.dat + * - GeoIPCity.dat + * - GeoIPISP.dat + * - GeoIPOrg.dat + * + * Note how GeoLiteCity.dat, the name for the GeoLite city database, is not detected + * by the PECL module. + * + * @param array $info Must have an 'ip' field. + * @return array + */ + public function getLocation($info) + { + $ip = $this->getIpFromInfo($info); + + $result = array(); + + // get location data + if (self::isCityDatabaseAvailable()) { + // Must hide errors because missing IPV6: + $location = @geoip_record_by_name($ip); + if (!empty($location)) { + $result[self::COUNTRY_CODE_KEY] = $location['country_code']; + $result[self::REGION_CODE_KEY] = $location['region']; + $result[self::CITY_NAME_KEY] = utf8_encode($location['city']); + $result[self::AREA_CODE_KEY] = $location['area_code']; + $result[self::LATITUDE_KEY] = $location['latitude']; + $result[self::LONGITUDE_KEY] = $location['longitude']; + $result[self::POSTAL_CODE_KEY] = $location['postal_code']; + } + } else if (self::isRegionDatabaseAvailable()) { + $location = @geoip_region_by_name($ip); + if (!empty($location)) { + $result[self::REGION_CODE_KEY] = $location['region']; + $result[self::COUNTRY_CODE_KEY] = $location['country_code']; + } + } else { + $result[self::COUNTRY_CODE_KEY] = @geoip_country_code_by_name($ip); + } + + // get organization data if the org database is available + if (self::isOrgDatabaseAvailable()) { + $org = @geoip_org_by_name($ip); + if ($org !== false) { + $result[self::ORG_KEY] = utf8_encode($org); + } + } + + // get isp data if the isp database is available + if (self::isISPDatabaseAvailable()) { + $isp = @geoip_isp_by_name($ip); + if ($ip !== false) { + $result[self::ISP_KEY] = utf8_encode($isp); + } + } + + if (empty($result)) { + return false; + } + + $this->completeLocationResult($result); + return $result; + } + + /** + * Returns true if the PECL module is installed and loaded, false if otherwise. + * + * @return bool + */ + public function isAvailable() + { + return function_exists('geoip_db_avail'); + } + + /** + * Returns true if the PECL module that is installed can be successfully used + * to get the location of an IP address. + * + * @return bool + */ + public function isWorking() + { + // if no no location database is available, this implementation is not setup correctly + if (!self::isLocationDatabaseAvailable()) { + $dbDir = dirname(geoip_db_filename(GEOIP_COUNTRY_EDITION)) . '/'; + $quotedDir = "'$dbDir'"; + + // check if the directory the PECL module is looking for exists + if (!is_dir($dbDir)) { + return Piwik_Translate('UserCountry_PeclGeoIPNoDBDir', array($quotedDir, "'geoip.custom_directory'")); + } + + // check if the user named the city database GeoLiteCity.dat + if (file_exists($dbDir . 'GeoLiteCity.dat')) { + return Piwik_Translate('UserCountry_PeclGeoLiteError', + array($quotedDir, "'GeoLiteCity.dat'", "'GeoIPCity.dat'")); + } + + return Piwik_Translate('UserCountry_CannotFindPeclGeoIPDb', + array($quotedDir, "'GeoIP.dat'", "'GeoIPCity.dat'")); + } + + return parent::isWorking(); + } + + /** + * 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 organization database is found, organization information is + * supported. + * + * If an ISP database is found, ISP 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; + + if (self::isCityDatabaseAvailable()) { + $result[self::REGION_CODE_KEY] = true; + $result[self::REGION_NAME_KEY] = true; + $result[self::CITY_NAME_KEY] = true; + $result[self::AREA_CODE_KEY] = true; + $result[self::LATITUDE_KEY] = true; + $result[self::LONGITUDE_KEY] = true; + $result[self::POSTAL_CODE_KEY] = true; + } else if (self::isRegionDatabaseAvailable()) { + $result[self::REGION_CODE_KEY] = true; + $result[self::REGION_NAME_KEY] = true; + } + + // check if organization info is available + if (self::isOrgDatabaseAvailable()) { + $result[self::ORG_KEY] = true; + } + + // check if ISP info is available + if (self::isISPDatabaseAvailable()) { + $result[self::ISP_KEY] = true; + } + + return $result; + } + + /** + * Returns information about this location provider. Contains an id, title & description: + * + * array( + * 'id' => 'geoip_pecl', + * 'title' => '...', + * 'description' => '...' + * ); + * + * @return array + */ + public function getInfo() + { + $desc = Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Pecl1') . '<br/><br/>' + . Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Pecl2'); + $installDocs = '<em>' + . '<a target="_blank" href="http://piwik.org/faq/how-to/#faq_164">' + . Piwik_Translate('UserCountry_HowToInstallGeoIpPecl') + . '</a>' + . '</em>'; + + $extraMessage = false; + if ($this->isAvailable()) { + $peclDir = ini_get('geoip.custom_directory'); + if ($peclDir === false) { + $extraMessage = Piwik_Translate('UserCountry_GeoIPPeclCustomDirNotSet', "'geoip.custom_directory'"); + } else { + $extraMessage = 'The \'geoip.custom_directory\' PHP ini option is set to \'' . $peclDir . '\'.'; + } + + $availableDatabaseTypes = array(); + if (self::isCityDatabaseAvailable()) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_City'); + } + if (self::isRegionDatabaseAvailable()) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Region'); + } + if (self::isCountryDatabaseAvailable()) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Country'); + } + if (self::isISPDatabaseAvailable()) { + $availableDatabaseTypes[] = 'ISP'; + } + if (self::isOrgDatabaseAvailable()) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Organization'); + } + + $extraMessage .= '<br/><br/>' . Piwik_Translate('UserCountry_GeoIPImplHasAccessTo') . ': <strong><em>' + . implode(', ', $availableDatabaseTypes) . '</em></strong>.'; + + $extraMessage = '<strong><em>' . Piwik_Translate('General_Note') . ': </em></strong>' . $extraMessage; + } + + return array('id' => self::ID, + 'title' => self::TITLE, + 'description' => $desc, + 'install_docs' => $installDocs, + 'extra_message' => $extraMessage, + 'order' => 3); + } + + /** + * Returns true if the PECL module can detect a location database (either a country, + * region or city will do). + * + * @return bool + */ + public static function isLocationDatabaseAvailable() + { + return self::isCityDatabaseAvailable() + || self::isRegionDatabaseAvailable() + || self::isCountryDatabaseAvailable(); + } + + /** + * Returns true if the PECL module can detect a city database. + * + * @return bool + */ + public static function isCityDatabaseAvailable() + { + return geoip_db_avail(GEOIP_CITY_EDITION_REV0) + || geoip_db_avail(GEOIP_CITY_EDITION_REV1); + } + + /** + * Returns true if the PECL module can detect a region database. + * + * @return bool + */ + public static function isRegionDatabaseAvailable() + { + return geoip_db_avail(GEOIP_REGION_EDITION_REV0) + || geoip_db_avail(GEOIP_REGION_EDITION_REV1); + } + + /** + * Returns true if the PECL module can detect a country database. + * + * @return bool + */ + public static function isCountryDatabaseAvailable() + { + return geoip_db_avail(GEOIP_COUNTRY_EDITION); + } + + /** + * Returns true if the PECL module can detect an organization database. + * + * @return bool + */ + public static function isOrgDatabaseAvailable() + { + return geoip_db_avail(GEOIP_ORG_EDITION); + } + + /** + * Returns true if the PECL module can detect an ISP database. + * + * @return bool + */ + public static function isISPDatabaseAvailable() + { + return geoip_db_avail(GEOIP_ISP_EDITION); + } } diff --git a/plugins/UserCountry/LocationProvider/GeoIp/Php.php b/plugins/UserCountry/LocationProvider/GeoIp/Php.php index c2443822fd..7e60ac520a 100755 --- a/plugins/UserCountry/LocationProvider/GeoIp/Php.php +++ b/plugins/UserCountry/LocationProvider/GeoIp/Php.php @@ -1,355 +1,330 @@ <?php /** * Piwik - Open source web analytics - * + * * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * + * * @category Piwik_Plugins * @package Piwik_UserCountry */ /** * A LocationProvider that uses the PHP implementation of GeoIP. - * + * * @package Piwik_UserCountry */ class Piwik_UserCountry_LocationProvider_GeoIp_Php extends Piwik_UserCountry_LocationProvider_GeoIp { - const ID = 'geoip_php'; - const TITLE = 'GeoIP (Php)'; - - /** - * The GeoIP database instances used. This array will contain at most three - * of them: one for location info, one for ISP info and another for organization - * info. - * - * Each instance is mapped w/ one of the following keys: 'loc', 'isp', 'org' - * - * @var array of GeoIP instances - */ - private $geoIpCache = 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', 'isp' or 'org' strings with - * an array of filenames. - * - * By default, this will be set to Piwik_UserCountry_LocationProvider_GeoIp_Php::$dbNames. - * - * @var array - */ - private $customDbNames; - - /** - * Constructor. - * - * @param array|false $customDbNames The possible filenames for each type of GeoIP database. - * eg array( - * 'loc' => array('GeoLiteCity.dat'), - * 'isp' => array('GeoIP.dat', 'GeoIPISP.dat') - * 'org' => array('GeoIPOrg.dat') - * ) - * 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]; - } - } - } - } - - /** - * Closes all open geoip instances. - */ - public function __destruct() - { - foreach ($this->geoIpCache as $instance) - { - geoip_close($instance); - } - } - - /** - * Uses a GeoIP database to get a visitor's location based on their IP address. - * - * This function will return different results based on the data used. 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 - */ - public function getLocation( $info ) - { - $ip = $this->getIpFromInfo($info); - - $result = array(); - - $locationGeoIp = $this->getGeoIpInstance($key = 'loc'); - if ($locationGeoIp) - { - switch ($locationGeoIp->databaseType) - { - case GEOIP_CITY_EDITION_REV0: // city database type - case GEOIP_CITY_EDITION_REV1: - case GEOIP_CITYCOMBINED_EDITION: - $location = geoip_record_by_addr($locationGeoIp, $ip); - if (!empty($location)) - { - $result[self::COUNTRY_CODE_KEY] = $location->country_code; - $result[self::REGION_CODE_KEY] = $location->region; - $result[self::CITY_NAME_KEY] = utf8_encode($location->city); - $result[self::AREA_CODE_KEY] = $location->area_code; - $result[self::LATITUDE_KEY] = $location->latitude; - $result[self::LONGITUDE_KEY] = $location->longitude; - $result[self::POSTAL_CODE_KEY] = $location->postal_code; - } - break; - case GEOIP_REGION_EDITION_REV0: // region database type - case GEOIP_REGION_EDITION_REV1: - $location = geoip_region_by_addr($locationGeoIp, $ip); - if (!empty($location)) - { - $result[self::COUNTRY_CODE_KEY] = $location[0]; - $result[self::REGION_CODE_KEY] = $location[1]; - } - break; - case GEOIP_COUNTRY_EDITION: // country database type - $result[self::COUNTRY_CODE_KEY] = geoip_country_code_by_addr($locationGeoIp, $ip); - break; - default: // unknown database type, log warning and fallback to country edition - Piwik::log(sprintf("Found unrecognized database type: %s", $locationGeoIp->databaseType)); - - $result[self::COUNTRY_CODE_KEY] = geoip_country_code_by_addr($locationGeoIp, $ip); - break; - } - } - - // NOTE: ISP & ORG require commercial dbs to test. this code has been tested manually, - // but not by integration tests. - $ispGeoIp = $this->getGeoIpInstance($key = 'isp'); - if ($ispGeoIp) - { - $isp = geoip_org_by_addr($ispGeoIp, $ip); - if (!empty($isp)) - { - $result[self::ISP_KEY] = utf8_encode($isp); - } - } - - $orgGeoIp = $this->getGeoIpInstance($key = 'org'); - if ($orgGeoIp) - { - $org = geoip_org_by_addr($orgGeoIp, $ip); - if (!empty($org)) - { - $result[self::ORG_KEY] = utf8_encode($org); - } - } - - if (empty($result)) - { - return false; - } - - $this->completeLocationResult($result); - return $result; - } - - /** - * 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 true if this provider has been setup correctly, the error message if - * otherwise. - * - * @return bool|string - */ - public function isWorking() - { - if (!function_exists('mb_internal_encoding')) - { - return Piwik_Translate('UserCountry_GeoIPCannotFindMbstringExtension', - array('mb_internal_encoding', 'mbstring')); - } - - return parent::isWorking(); - } - - /** - * 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 organization database is found, organization information is - * supported. - * - * If an ISP database is found, ISP 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; - - $locationGeoIp = $this->getGeoIpInstance($key = 'loc'); - if ($locationGeoIp) - { - switch ($locationGeoIp->databaseType) - { - case GEOIP_CITY_EDITION_REV0: // city database type - case GEOIP_CITY_EDITION_REV1: - case GEOIP_CITYCOMBINED_EDITION: - $result[self::REGION_CODE_KEY] = true; - $result[self::REGION_NAME_KEY] = true; - $result[self::CITY_NAME_KEY] = true; - $result[self::AREA_CODE_KEY] = true; - $result[self::LATITUDE_KEY] = true; - $result[self::LONGITUDE_KEY] = true; - $result[self::POSTAL_CODE_KEY] = true; - break; - case GEOIP_REGION_EDITION_REV0: // region database type - case GEOIP_REGION_EDITION_REV1: - $result[self::REGION_CODE_KEY] = true; - $result[self::REGION_NAME_KEY] = true; - break; - default: // country or unknown database type - break; - } - } - - // check if isp info is available - if ($this->getGeoIpInstance($key = 'isp')) - { - $result[self::ISP_KEY] = true; - } - - // check of org info is available - if ($this->getGeoIpInstance($key = 'org')) - { - $result[self::ORG_KEY] = true; - } - - return $result; - } - - /** - * Returns information about this location provider. Contains an id, title & description: - * - * array( - * 'id' => 'geoip_php', - * 'title' => '...', - * 'description' => '...' - * ); - * - * @return array - */ - public function getInfo() - { - $desc = Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Php1') . '<br/><br/>' - . Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Php2', - array('<strong><em>', '</em></strong>', '<strong><em>', '</em></strong>')); - $installDocs = '<em><a target="_blank" href="http://piwik.org/faq/how-to/#faq_163">' - . Piwik_Translate('UserCountry_HowToInstallGeoIPDatabases') - . '</em></a>'; - - $availableDatabaseTypes = array(); - if (self::getPathToGeoIpDatabase(array('GeoIPCity.dat', 'GeoLiteCity.dat')) !== false) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_City'); - } - if (self::getPathToGeoIpDatabase(array('GeoIPRegion.dat')) !== false) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Region'); - } - if (self::getPathToGeoIpDatabase(array('GeoIPCountry.dat')) !== false) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Country'); - } - if (self::getPathToGeoIpDatabase(array('GeoIPISP.dat')) !== false) - { - $availableDatabaseTypes[] = 'ISP'; - } - if (self::getPathToGeoIpDatabase(array('GeoIPOrg.dat')) !== false) - { - $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Organization'); - } - - $extraMessage = '<strong><em>'.Piwik_Translate('General_Note').'</em></strong>: ' - . Piwik_Translate('UserCountry_GeoIPImplHasAccessTo').': <strong><em>' - . implode(', ', $availableDatabaseTypes).'</em></strong>.'; - - return array('id' => self::ID, - 'title' => self::TITLE, - 'description' => $desc, - 'install_docs' => $installDocs, - 'extra_message' => $extraMessage, - 'order' => 2); - } - - /** - * Returns a GeoIP instance. Creates it if necessary. - * - * @param string $key 'loc', 'isp' or 'org'. Determines the type of GeoIP database - * to load. - * @return object|false - */ - private function getGeoIpInstance( $key ) - { - if (empty($this->geoIpCache[$key])) - { - // make sure region names are loaded & saved first - parent::getRegionNames(); - require_once PIWIK_INCLUDE_PATH . '/libs/MaxMindGeoIP/geoipcity.inc'; - - $pathToDb = self::getPathToGeoIpDatabase($this->customDbNames[$key]); - if ($pathToDb !== false) - { - $this->geoIpCache[$key] = geoip_open($pathToDb, GEOIP_STANDARD); // TODO support shared memory - } - } - - return empty($this->geoIpCache[$key]) ? false : $this->geoIpCache[$key]; - } + const ID = 'geoip_php'; + const TITLE = 'GeoIP (Php)'; + + /** + * The GeoIP database instances used. This array will contain at most three + * of them: one for location info, one for ISP info and another for organization + * info. + * + * Each instance is mapped w/ one of the following keys: 'loc', 'isp', 'org' + * + * @var array of GeoIP instances + */ + private $geoIpCache = 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', 'isp' or 'org' strings with + * an array of filenames. + * + * By default, this will be set to Piwik_UserCountry_LocationProvider_GeoIp_Php::$dbNames. + * + * @var array + */ + private $customDbNames; + + /** + * Constructor. + * + * @param array|false $customDbNames The possible filenames for each type of GeoIP database. + * eg array( + * 'loc' => array('GeoLiteCity.dat'), + * 'isp' => array('GeoIP.dat', 'GeoIPISP.dat') + * 'org' => array('GeoIPOrg.dat') + * ) + * 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]; + } + } + } + } + + /** + * Closes all open geoip instances. + */ + public function __destruct() + { + foreach ($this->geoIpCache as $instance) { + geoip_close($instance); + } + } + + /** + * Uses a GeoIP database to get a visitor's location based on their IP address. + * + * This function will return different results based on the data used. 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 + */ + public function getLocation($info) + { + $ip = $this->getIpFromInfo($info); + + $result = array(); + + $locationGeoIp = $this->getGeoIpInstance($key = 'loc'); + if ($locationGeoIp) { + switch ($locationGeoIp->databaseType) { + case GEOIP_CITY_EDITION_REV0: // city database type + case GEOIP_CITY_EDITION_REV1: + case GEOIP_CITYCOMBINED_EDITION: + $location = geoip_record_by_addr($locationGeoIp, $ip); + if (!empty($location)) { + $result[self::COUNTRY_CODE_KEY] = $location->country_code; + $result[self::REGION_CODE_KEY] = $location->region; + $result[self::CITY_NAME_KEY] = utf8_encode($location->city); + $result[self::AREA_CODE_KEY] = $location->area_code; + $result[self::LATITUDE_KEY] = $location->latitude; + $result[self::LONGITUDE_KEY] = $location->longitude; + $result[self::POSTAL_CODE_KEY] = $location->postal_code; + } + break; + case GEOIP_REGION_EDITION_REV0: // region database type + case GEOIP_REGION_EDITION_REV1: + $location = geoip_region_by_addr($locationGeoIp, $ip); + if (!empty($location)) { + $result[self::COUNTRY_CODE_KEY] = $location[0]; + $result[self::REGION_CODE_KEY] = $location[1]; + } + break; + case GEOIP_COUNTRY_EDITION: // country database type + $result[self::COUNTRY_CODE_KEY] = geoip_country_code_by_addr($locationGeoIp, $ip); + break; + default: // unknown database type, log warning and fallback to country edition + Piwik::log(sprintf("Found unrecognized database type: %s", $locationGeoIp->databaseType)); + + $result[self::COUNTRY_CODE_KEY] = geoip_country_code_by_addr($locationGeoIp, $ip); + break; + } + } + + // NOTE: ISP & ORG require commercial dbs to test. this code has been tested manually, + // but not by integration tests. + $ispGeoIp = $this->getGeoIpInstance($key = 'isp'); + if ($ispGeoIp) { + $isp = geoip_org_by_addr($ispGeoIp, $ip); + if (!empty($isp)) { + $result[self::ISP_KEY] = utf8_encode($isp); + } + } + + $orgGeoIp = $this->getGeoIpInstance($key = 'org'); + if ($orgGeoIp) { + $org = geoip_org_by_addr($orgGeoIp, $ip); + if (!empty($org)) { + $result[self::ORG_KEY] = utf8_encode($org); + } + } + + if (empty($result)) { + return false; + } + + $this->completeLocationResult($result); + return $result; + } + + /** + * 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 true if this provider has been setup correctly, the error message if + * otherwise. + * + * @return bool|string + */ + public function isWorking() + { + if (!function_exists('mb_internal_encoding')) { + return Piwik_Translate('UserCountry_GeoIPCannotFindMbstringExtension', + array('mb_internal_encoding', 'mbstring')); + } + + return parent::isWorking(); + } + + /** + * 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 organization database is found, organization information is + * supported. + * + * If an ISP database is found, ISP 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; + + $locationGeoIp = $this->getGeoIpInstance($key = 'loc'); + if ($locationGeoIp) { + switch ($locationGeoIp->databaseType) { + case GEOIP_CITY_EDITION_REV0: // city database type + case GEOIP_CITY_EDITION_REV1: + case GEOIP_CITYCOMBINED_EDITION: + $result[self::REGION_CODE_KEY] = true; + $result[self::REGION_NAME_KEY] = true; + $result[self::CITY_NAME_KEY] = true; + $result[self::AREA_CODE_KEY] = true; + $result[self::LATITUDE_KEY] = true; + $result[self::LONGITUDE_KEY] = true; + $result[self::POSTAL_CODE_KEY] = true; + break; + case GEOIP_REGION_EDITION_REV0: // region database type + case GEOIP_REGION_EDITION_REV1: + $result[self::REGION_CODE_KEY] = true; + $result[self::REGION_NAME_KEY] = true; + break; + default: // country or unknown database type + break; + } + } + + // check if isp info is available + if ($this->getGeoIpInstance($key = 'isp')) { + $result[self::ISP_KEY] = true; + } + + // check of org info is available + if ($this->getGeoIpInstance($key = 'org')) { + $result[self::ORG_KEY] = true; + } + + return $result; + } + + /** + * Returns information about this location provider. Contains an id, title & description: + * + * array( + * 'id' => 'geoip_php', + * 'title' => '...', + * 'description' => '...' + * ); + * + * @return array + */ + public function getInfo() + { + $desc = Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Php1') . '<br/><br/>' + . Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_Php2', + array('<strong><em>', '</em></strong>', '<strong><em>', '</em></strong>')); + $installDocs = '<em><a target="_blank" href="http://piwik.org/faq/how-to/#faq_163">' + . Piwik_Translate('UserCountry_HowToInstallGeoIPDatabases') + . '</em></a>'; + + $availableDatabaseTypes = array(); + if (self::getPathToGeoIpDatabase(array('GeoIPCity.dat', 'GeoLiteCity.dat')) !== false) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_City'); + } + if (self::getPathToGeoIpDatabase(array('GeoIPRegion.dat')) !== false) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Region'); + } + if (self::getPathToGeoIpDatabase(array('GeoIPCountry.dat')) !== false) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Country'); + } + if (self::getPathToGeoIpDatabase(array('GeoIPISP.dat')) !== false) { + $availableDatabaseTypes[] = 'ISP'; + } + if (self::getPathToGeoIpDatabase(array('GeoIPOrg.dat')) !== false) { + $availableDatabaseTypes[] = Piwik_Translate('UserCountry_Organization'); + } + + $extraMessage = '<strong><em>' . Piwik_Translate('General_Note') . '</em></strong>: ' + . Piwik_Translate('UserCountry_GeoIPImplHasAccessTo') . ': <strong><em>' + . implode(', ', $availableDatabaseTypes) . '</em></strong>.'; + + return array('id' => self::ID, + 'title' => self::TITLE, + 'description' => $desc, + 'install_docs' => $installDocs, + 'extra_message' => $extraMessage, + 'order' => 2); + } + + /** + * Returns a GeoIP instance. Creates it if necessary. + * + * @param string $key 'loc', 'isp' or 'org'. Determines the type of GeoIP database + * to load. + * @return object|false + */ + private function getGeoIpInstance($key) + { + if (empty($this->geoIpCache[$key])) { + // make sure region names are loaded & saved first + parent::getRegionNames(); + require_once PIWIK_INCLUDE_PATH . '/libs/MaxMindGeoIP/geoipcity.inc'; + + $pathToDb = self::getPathToGeoIpDatabase($this->customDbNames[$key]); + if ($pathToDb !== false) { + $this->geoIpCache[$key] = geoip_open($pathToDb, GEOIP_STANDARD); // TODO support shared memory + } + } + + return empty($this->geoIpCache[$key]) ? false : $this->geoIpCache[$key]; + } } diff --git a/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php b/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php index 7be7324744..cdafeefa6a 100755 --- a/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php +++ b/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php @@ -1,306 +1,277 @@ <?php /** * Piwik - Open source web analytics - * + * * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * + * * @category Piwik_Plugins * @package Piwik_UserCountry */ /** * A LocationProvider that uses an GeoIP module installed in an HTTP Server. - * + * * To make this provider available, make sure the GEOIP_ADDR server * variable is set. - * + * * @package Piwik_UserCountry */ class Piwik_UserCountry_LocationProvider_GeoIp_ServerBased extends Piwik_UserCountry_LocationProvider_GeoIp { - const ID = 'geoip_serverbased'; - const TITLE = 'GeoIP (%s)'; - const TEST_SERVER_VAR = 'GEOIP_ADDR'; - const TEST_SERVER_VAR_ALT = 'GEOIP_COUNTRY_CODE'; - - private static $geoIpServerVars = array( - parent::COUNTRY_CODE_KEY => 'GEOIP_COUNTRY_CODE', - parent::COUNTRY_NAME_KEY => 'GEOIP_COUNTRY_NAME', - parent::REGION_CODE_KEY => 'GEOIP_REGION', - parent::REGION_NAME_KEY => 'GEOIP_REGION_NAME', - parent::AREA_CODE_KEY => 'GEOIP_AREA_CODE', - parent::LATITUDE_KEY => 'GEOIP_LATITUDE', - parent::LONGITUDE_KEY => 'GEOIP_LONGITUDE', - parent::POSTAL_CODE_KEY => 'GEOIP_POSTAL_CODE', - ); - - private static $geoIpUtfServerVars = array( - parent::CITY_NAME_KEY => 'GEOIP_CITY', - parent::ISP_KEY => 'GEOIP_ISP', - parent::ORG_KEY => 'GEOIP_ORGANIZATION', - ); - - /** - * Uses a GeoIP database to get a visitor's location based on their IP address. - * - * This function will return different results based on the data used and based - * on how the GeoIP module is configured. - * - * If a region database is used, it may return the country code, region code, - * city name, area code, latitude, longitude and postal code of the visitor. - * - * Alternatively, only the country code may be returned for another database. - * - * If your HTTP server is not configured to include all GeoIP information, some - * information will not be available to Piwik. - * - * @param array $info Must have an 'ip' field. - * @return array - */ - public function getLocation( $info ) - { - $ip = $this->getIpFromInfo($info); - - // geoip modules that are built into servers can't use a forced IP. in this case we try - // to fallback to another version. - $myIP = Piwik_IP::getIpFromHeader(); - if (!self::isSameOrAnonymizedIp($ip, $myIP) - && (!isset($info['disable_fallbacks']) - || !$info['disable_fallbacks'])) - { - printDebug("The request is for IP address: ".$info['ip'] . " but your IP is: $myIP. GeoIP Server Module (apache/nginx) does not support this use case... "); - $fallbacks = array( - Piwik_UserCountry_LocationProvider_GeoIp_Pecl::ID, - Piwik_UserCountry_LocationProvider_GeoIp_Php::ID - ); - foreach ($fallbacks as $fallbackProviderId) - { - $otherProvider = Piwik_UserCountry_LocationProvider::getProviderById($fallbackProviderId); - if ($otherProvider) - { - printDebug("Used $fallbackProviderId to detect this visitor IP"); - return $otherProvider->getLocation($info); - } - } - printDebug("FAILED to lookup the geo location of this IP address, as no fallback location providers is configured. We recommend to configure Geolocation PECL module to fix this error."); - - return false; - } - - $result = array(); - foreach (self::$geoIpServerVars as $resultKey => $geoipVarName) - { - if (!empty($_SERVER[$geoipVarName])) - { - $result[$resultKey] = $_SERVER[$geoipVarName]; - } - } - foreach (self::$geoIpUtfServerVars as $resultKey => $geoipVarName) - { - if (!empty($_SERVER[$geoipVarName])) - { - $result[$resultKey] = utf8_encode($_SERVER[$geoipVarName]); - } - } - $this->completeLocationResult($result); - return $result; - } - - /** - * 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::COUNTRY_CODE_KEY] = true; - $result[self::COUNTRY_NAME_KEY] = true; - $result[self::CONTINENT_CODE_KEY] = true; - $result[self::CONTINENT_NAME_KEY] = true; - - return $result; - } - - /** - * Checks if an HTTP server module has been installed. It checks by looking for - * the GEOIP_ADDR server variable. - * - * There's a special check for the Apache module, but we can't check specifically - * for anything else. - * - * @return bool|string - */ - public function isAvailable() - { - // check if apache module is installed - if (function_exists('apache_get_modules')) - { - foreach (apache_get_modules() as $name) - { - if (strpos($name, 'geoip') !== false) - { - return true; - } - } - } - - $available = !empty($_SERVER[self::TEST_SERVER_VAR]) - || !empty($_SERVER[self::TEST_SERVER_VAR_ALT]); - - if ($available) - { - return true; - } - else // if not available return message w/ extra info - { - if (!function_exists('apache_get_modules')) - { - return Piwik_Translate('General_Note').': '.Piwik_Translate('UserCountry_AssumingNonApache'); - } - - $message = "<strong><em>".Piwik_Translate('General_Note').': ' - . Piwik_Translate('UserCountry_FoundApacheModules') - . "</em></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 GEOIP_ADDR server variable is defined. - * - * @return bool - */ - public function isWorking() - { - if (empty($_SERVER[self::TEST_SERVER_VAR]) - && empty($_SERVER[self::TEST_SERVER_VAR_ALT])) - { - return Piwik_Translate("UserCountry_CannotFindGeoIPServerVar", self::TEST_SERVER_VAR.' $_SERVER'); - } - - return true; // can't check for another IP - } - - /** - * 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('UserCountry_GeoIpLocationProviderDesc_ServerBased1', array('<strong>', '</strong>')) - . '<br/><br/>' - . '<em>'.Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_ServerBasedAnonWarn').'</em>' - . '<br/><br/>' - . Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_ServerBased2', - array('<strong><em>', '</em></strong>', '<strong><em>', '</em></strong>')); - $installDocs = - '<em><a target="_blank" href="http://piwik.org/faq/how-to/#faq_165">' - . Piwik_Translate('UserCountry_HowToInstallApacheModule') - . '</a></em><br/><em>' - . '<a target="_blank" href="http://piwik.org/faq/how-to/#faq_166">' - . Piwik_Translate('UserCountry_HowToInstallNginxModule') - . '</a></em>'; - - $geoipServerVars = array(); - foreach ($_SERVER as $key => $value) - { - if (strpos($key, 'GEOIP') === 0) - { - $geoipServerVars[] = $key; - } - } - - if (empty($geoipServerVars)) - { - $extraMessage = '<strong><em>'.Piwik_Translate('UserCountry_GeoIPNoServerVars', '$_SERVER').'</em></strong>'; - } - else - { - $extraMessage = '<strong><em>'.Piwik_Translate('UserCountry_GeoIPServerVarsFound', '$_SERVER') - .":</em></strong><br/><br/>\n<ul style=\"list-style:disc;margin-left:24px\">\n"; - foreach ($geoipServerVars as $key) - { - $extraMessage .= '<li>'.$key."</li>\n"; - } - $extraMessage .= '</ul>'; - } - - return array('id' => self::ID, - 'title' => $title, - 'description' => $desc, - 'order' => 4, - '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; - } + const ID = 'geoip_serverbased'; + const TITLE = 'GeoIP (%s)'; + const TEST_SERVER_VAR = 'GEOIP_ADDR'; + const TEST_SERVER_VAR_ALT = 'GEOIP_COUNTRY_CODE'; + + private static $geoIpServerVars = array( + parent::COUNTRY_CODE_KEY => 'GEOIP_COUNTRY_CODE', + parent::COUNTRY_NAME_KEY => 'GEOIP_COUNTRY_NAME', + parent::REGION_CODE_KEY => 'GEOIP_REGION', + parent::REGION_NAME_KEY => 'GEOIP_REGION_NAME', + parent::AREA_CODE_KEY => 'GEOIP_AREA_CODE', + parent::LATITUDE_KEY => 'GEOIP_LATITUDE', + parent::LONGITUDE_KEY => 'GEOIP_LONGITUDE', + parent::POSTAL_CODE_KEY => 'GEOIP_POSTAL_CODE', + ); + + private static $geoIpUtfServerVars = array( + parent::CITY_NAME_KEY => 'GEOIP_CITY', + parent::ISP_KEY => 'GEOIP_ISP', + parent::ORG_KEY => 'GEOIP_ORGANIZATION', + ); + + /** + * Uses a GeoIP database to get a visitor's location based on their IP address. + * + * This function will return different results based on the data used and based + * on how the GeoIP module is configured. + * + * If a region database is used, it may return the country code, region code, + * city name, area code, latitude, longitude and postal code of the visitor. + * + * Alternatively, only the country code may be returned for another database. + * + * If your HTTP server is not configured to include all GeoIP information, some + * information will not be available to Piwik. + * + * @param array $info Must have an 'ip' field. + * @return array + */ + public function getLocation($info) + { + $ip = $this->getIpFromInfo($info); + + // geoip modules that are built into servers can't use a forced IP. in this case we try + // to fallback to another version. + $myIP = Piwik_IP::getIpFromHeader(); + if (!self::isSameOrAnonymizedIp($ip, $myIP) + && (!isset($info['disable_fallbacks']) + || !$info['disable_fallbacks']) + ) { + printDebug("The request is for IP address: " . $info['ip'] . " but your IP is: $myIP. GeoIP Server Module (apache/nginx) does not support this use case... "); + $fallbacks = array( + Piwik_UserCountry_LocationProvider_GeoIp_Pecl::ID, + Piwik_UserCountry_LocationProvider_GeoIp_Php::ID + ); + foreach ($fallbacks as $fallbackProviderId) { + $otherProvider = Piwik_UserCountry_LocationProvider::getProviderById($fallbackProviderId); + if ($otherProvider) { + printDebug("Used $fallbackProviderId to detect this visitor IP"); + return $otherProvider->getLocation($info); + } + } + printDebug("FAILED to lookup the geo location of this IP address, as no fallback location providers is configured. We recommend to configure Geolocation PECL module to fix this error."); + + return false; + } + + $result = array(); + foreach (self::$geoIpServerVars as $resultKey => $geoipVarName) { + if (!empty($_SERVER[$geoipVarName])) { + $result[$resultKey] = $_SERVER[$geoipVarName]; + } + } + foreach (self::$geoIpUtfServerVars as $resultKey => $geoipVarName) { + if (!empty($_SERVER[$geoipVarName])) { + $result[$resultKey] = utf8_encode($_SERVER[$geoipVarName]); + } + } + $this->completeLocationResult($result); + return $result; + } + + /** + * 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::COUNTRY_CODE_KEY] = true; + $result[self::COUNTRY_NAME_KEY] = true; + $result[self::CONTINENT_CODE_KEY] = true; + $result[self::CONTINENT_NAME_KEY] = true; + + return $result; + } + + /** + * Checks if an HTTP server module has been installed. It checks by looking for + * the GEOIP_ADDR server variable. + * + * There's a special check for the Apache module, but we can't check specifically + * for anything else. + * + * @return bool|string + */ + public function isAvailable() + { + // check if apache module is installed + if (function_exists('apache_get_modules')) { + foreach (apache_get_modules() as $name) { + if (strpos($name, 'geoip') !== false) { + return true; + } + } + } + + $available = !empty($_SERVER[self::TEST_SERVER_VAR]) + || !empty($_SERVER[self::TEST_SERVER_VAR_ALT]); + + if ($available) { + return true; + } else // if not available return message w/ extra info + { + if (!function_exists('apache_get_modules')) { + return Piwik_Translate('General_Note') . ': ' . Piwik_Translate('UserCountry_AssumingNonApache'); + } + + $message = "<strong><em>" . Piwik_Translate('General_Note') . ': ' + . Piwik_Translate('UserCountry_FoundApacheModules') + . "</em></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 GEOIP_ADDR server variable is defined. + * + * @return bool + */ + public function isWorking() + { + if (empty($_SERVER[self::TEST_SERVER_VAR]) + && empty($_SERVER[self::TEST_SERVER_VAR_ALT]) + ) { + return Piwik_Translate("UserCountry_CannotFindGeoIPServerVar", self::TEST_SERVER_VAR . ' $_SERVER'); + } + + return true; // can't check for another IP + } + + /** + * 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('UserCountry_GeoIpLocationProviderDesc_ServerBased1', array('<strong>', '</strong>')) + . '<br/><br/>' + . '<em>' . Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_ServerBasedAnonWarn') . '</em>' + . '<br/><br/>' + . Piwik_Translate('UserCountry_GeoIpLocationProviderDesc_ServerBased2', + array('<strong><em>', '</em></strong>', '<strong><em>', '</em></strong>')); + $installDocs = + '<em><a target="_blank" href="http://piwik.org/faq/how-to/#faq_165">' + . Piwik_Translate('UserCountry_HowToInstallApacheModule') + . '</a></em><br/><em>' + . '<a target="_blank" href="http://piwik.org/faq/how-to/#faq_166">' + . Piwik_Translate('UserCountry_HowToInstallNginxModule') + . '</a></em>'; + + $geoipServerVars = array(); + foreach ($_SERVER as $key => $value) { + if (strpos($key, 'GEOIP') === 0) { + $geoipServerVars[] = $key; + } + } + + if (empty($geoipServerVars)) { + $extraMessage = '<strong><em>' . Piwik_Translate('UserCountry_GeoIPNoServerVars', '$_SERVER') . '</em></strong>'; + } else { + $extraMessage = '<strong><em>' . Piwik_Translate('UserCountry_GeoIPServerVarsFound', '$_SERVER') + . ":</em></strong><br/><br/>\n<ul style=\"list-style:disc;margin-left:24px\">\n"; + foreach ($geoipServerVars as $key) { + $extraMessage .= '<li>' . $key . "</li>\n"; + } + $extraMessage .= '</ul>'; + } + + return array('id' => self::ID, + 'title' => $title, + 'description' => $desc, + 'order' => 4, + '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; + } } |