Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/UserCountry/GeoIPAutoUpdater.php')
-rwxr-xr-xplugins/UserCountry/GeoIPAutoUpdater.php98
1 files changed, 92 insertions, 6 deletions
diff --git a/plugins/UserCountry/GeoIPAutoUpdater.php b/plugins/UserCountry/GeoIPAutoUpdater.php
index 1d87cd6436..aac72ec5bd 100755
--- a/plugins/UserCountry/GeoIPAutoUpdater.php
+++ b/plugins/UserCountry/GeoIPAutoUpdater.php
@@ -29,6 +29,14 @@ class Piwik_UserCountry_GeoIPAutoUpdater
'isp' => self::ISP_URL_OPTION_NAME,
'org' => self::ORG_URL_OPTION_NAME,
);
+
+ /**
+ * PHP Error caught through a custom error handler while trying to use a downloaded
+ * GeoIP database. See catchGeoIPError for more info.
+ *
+ * @var array
+ */
+ private static $unzipPhpError = null;
/**
* Attempts to download new location, ISP & organization GeoIP databases and
@@ -122,7 +130,11 @@ class Piwik_UserCountry_GeoIPAutoUpdater
public static function unzipDownloadedFile( $path, $unlink = false )
{
$parts = explode('.', basename($path));
- $outputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($parts[0].'.dat');
+ $filenameStart = $parts[0];
+
+ $dbFilename = $filenameStart.'.dat';
+ $tempFilename = $filenameStart.'.dat.new';
+ $outputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($tempFilename);
// extract file
if (substr($path, -7, 7) == '.tar.gz')
@@ -141,7 +153,7 @@ class Piwik_UserCountry_GeoIPAutoUpdater
foreach ($content as $info)
{
$archivedPath = $info['filename'];
- if (basename($archivedPath) === basename($outputPath))
+ if (basename($archivedPath) === $dbFilename)
{
$datFile = $archivedPath;
}
@@ -150,7 +162,7 @@ class Piwik_UserCountry_GeoIPAutoUpdater
if ($datFile === null)
{
throw new Exception(Piwik_Translate('UserCountry_CannotFindGeoIPDatabaseInArchive',
- array(basename($outputPath), "'$path'")));
+ array($dbFilename, "'$path'")));
}
// extract JUST the .dat file
@@ -184,6 +196,59 @@ class Piwik_UserCountry_GeoIPAutoUpdater
throw new Exception(Piwik_Translate('UserCountry_UnsupportedArchiveType', "'$ext'"));
}
+ // test that the new archive is a valid GeoIP database
+ $dbType = Piwik_UserCountry_LocationProvider_GeoIp::getGeoIPDatabaseTypeFromFilename($dbFilename);
+ if ($dbType === false) // sanity check
+ {
+ throw new Exception("Unexpected GeoIP archive file name '$path'.");
+ }
+
+ $customDbNames = array(
+ 'loc' => array(),
+ 'isp' => array(),
+ 'org' => array()
+ );
+ $customDbNames[$dbType] = array($tempFilename);
+
+ $phpProvider = new Piwik_UserCountry_LocationProvider_GeoIp_Php($customDbNames);
+
+ // note: in most cases where this will fail, the error will usually be a PHP fatal error/notice.
+ // in order to delete the files in such a case (which can be caused by a man-in-the-middle attack)
+ // we need to catch them, so we set a new error handler.
+ self::$unzipPhpError = null;
+ set_error_handler(array('Piwik_UserCountry_GeoIPAutoUpdater', 'catchGeoIPError'));
+
+ $location = $phpProvider->getLocation(array('ip' => Piwik_UserCountry_LocationProvider_GeoIp::TEST_IP));
+
+ restore_error_handler();
+
+ if (empty($location)
+ || self::$unzipPhpError !== null)
+ {
+ if (self::$unzipPhpError !== null)
+ {
+ list($errno, $errstr, $errfile, $errline) = self::$unzipPhpError;
+ Piwik::log("Piwik_UserCountry_GeoIPAutoUpdater: Encountered PHP error when testing newly downloaded".
+ " GeoIP database: $errno: $errstr on line $errline of $errfile.");
+ }
+
+ // remove downloaded files in this case
+ unlink($outputPath);
+ unlink($path);
+
+ throw new Exception(Piwik_Translate('UserCountry_ThisUrlIsNotAValidGeoIPDB'));
+ }
+
+ // delete the existing GeoIP database (if any) and rename the downloaded file
+ $oldDbFile = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($dbFilename);
+ if (file_exists($oldDbFile))
+ {
+ unlink($oldDbFile);
+ }
+
+ $tempFile = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($tempFilename);
+ rename($existing = $tempFile, $newName = $oldDbFile);
+
// delete original archive
if ($unlink)
{
@@ -251,7 +316,7 @@ class Piwik_UserCountry_GeoIPAutoUpdater
// set url options
foreach (self::$urlOptions as $optionKey => $optionName)
{
- if (empty($options[$optionKey]))
+ if (!isset($options[$optionKey]))
{
continue;
}
@@ -317,7 +382,7 @@ class Piwik_UserCountry_GeoIPAutoUpdater
*/
public static function getConfiguredUrl( $key )
{
- if(!empty(self::$urlOptions[$key])) {
+ if(empty(self::$urlOptions[$key])) {
throw new Exception("Invalid key $key");
}
$url = Piwik_GetOption(self::$urlOptions[$key]);
@@ -361,7 +426,7 @@ class Piwik_UserCountry_GeoIPAutoUpdater
$result = array();
foreach (self::getConfiguredUrls() as $key => $url)
{
- if ($url !== false)
+ if (!empty($url))
{
// if a database of the type does not exist, but there's a url to update, then
// a database is missing
@@ -398,4 +463,25 @@ class Piwik_UserCountry_GeoIPAutoUpdater
return reset($filenameParts);
}
}
+
+ /**
+ * Custom PHP error handler used to catch any PHP errors that occur when
+ * testing a downloaded GeoIP file.
+ *
+ * If we download a file that is supposed to be a GeoIP database, we need to make
+ * sure it is one. This is done simply by attempting to use it. If this fails, it
+ * will most of the time fail as a PHP error, which we catch w/ this function
+ * after it is passed to set_error_handler.
+ *
+ * The PHP error is stored in self::$unzipPhpError.
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ */
+ public static function catchGeoIPError( $errno, $errstr, $errfile, $errline )
+ {
+ self::$unzipPhpError = array($errno, $errstr, $errfile, $errline);
+ }
}