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.php397
1 files changed, 397 insertions, 0 deletions
diff --git a/plugins/UserCountry/GeoIPAutoUpdater.php b/plugins/UserCountry/GeoIPAutoUpdater.php
new file mode 100755
index 0000000000..391a226937
--- /dev/null
+++ b/plugins/UserCountry/GeoIPAutoUpdater.php
@@ -0,0 +1,397 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ * @version $Id$
+ *
+ * @category Piwik_Plugins
+ * @package Piwik_UserCountry
+ */
+
+/**
+ * Used to automatically update installed GeoIP databases, and manages the updater's
+ * scheduled task.
+ */
+class Piwik_UserCountry_GeoIPAutoUpdater
+{
+ const SCHEDULE_PERIOD_MONTHLY = 'month';
+ const SCHEDULE_PERIOD_WEEKLY = 'week';
+
+ const SCHEDULE_PERIOD_OPTION_NAME = 'geoip.updater_period';
+ const LOC_URL_OPTION_NAME = 'geoip.loc_db_url';
+ const ISP_URL_OPTION_NAME = 'geoip.isp_db_url';
+ const ORG_URL_OPTION_NAME = 'geoip.org_db_url';
+
+ private static $urlOptions = array(
+ 'loc' => self::LOC_URL_OPTION_NAME,
+ 'isp' => self::ISP_URL_OPTION_NAME,
+ 'org' => self::ORG_URL_OPTION_NAME,
+ );
+
+ /**
+ * Attempts to download new location, ISP & organization GeoIP databases and
+ * replace the existing ones w/ them.
+ */
+ public function update()
+ {
+ try
+ {
+ $locUrl = Piwik_GetOption(self::LOC_URL_OPTION_NAME);
+ if ($locUrl !== false)
+ {
+ $this->downloadFile('loc', $locUrl);
+ }
+
+ $ispUrl = Piwik_GetOption(self::ISP_URL_OPTION_NAME);
+ if ($ispUrl !== false)
+ {
+ $this->downloadFile('isp', $ispUrl);
+ }
+
+ $orgUrl = Piwik_GetOption(self::ORG_URL_OPTION_NAME);
+ if ($orgUrl !== false)
+ {
+ $this->downloadFile('org', $orgUrl);
+ }
+ }
+ catch (Exception $ex)
+ {
+ // message will already be prefixed w/ 'Piwik_UserCountry_GeoIPAutoUpdater: '
+ Piwik::log($ex->getMessage());
+ throw $ex;
+ }
+ }
+
+ /**
+ * Downloads a GeoIP database archive, extracts the .dat file and overwrites the existing
+ * old database.
+ *
+ * If something happens that causes the download to fail, no exception is thrown, but
+ * an error is logged.
+ *
+ * @param string $url URL to the database to download. The type of database is determined
+ * from this URL.
+ */
+ private function downloadFile( $dbType, $url )
+ {
+ $ext = Piwik_UserCountry_GeoIPAutoUpdater::getGeoIPUrlExtension($url);
+ $zippedFilename = Piwik_UserCountry_LocationProvider_GeoIp::$dbNames[$dbType][0].'.'.$ext;
+
+ $zippedOutputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($zippedFilename);
+
+ // download zipped file to misc dir
+ try
+ {
+ $success = Piwik_Http::sendHttpRequest($url, $timeout = 3600, $userAgent = null, $zippedOutputPath);
+ }
+ catch (Exception $ex)
+ {
+ throw new Exception("Piwik_UserCountry_GeoIPAutoUpdater: failed to download '$url' to "
+ . "'$zippedOutputPath': " . $ex->getMessage());
+ }
+
+ if ($success !== true)
+ {
+ throw new Exception("Piwik_UserCountry_GeoIPAutoUpdater: failed to download '$url' to "
+ . "'$zippedOutputPath'! (Unknown error)");
+ }
+
+ Piwik::log("Piwik_UserCountry_GeoIPAutoUpdater: successfully downloaded '$url'");
+
+ try
+ {
+ self::unzipDownloadedFile($zippedOutputPath, $unlink = true);
+ }
+ catch (Exception $ex)
+ {
+ throw new Exception("Piwik_UserCountry_GeoIPAutoUpdater: failed to unzip '$zippedOutputPath' after "
+ . "downloading " . "'$url': ".$ex->getMessage());
+ }
+
+ Piwik::log("Piwik_UserCountry_GeoIPAutoUpdater: successfully updated GeoIP database '$url'");
+ }
+
+ /**
+ * Unzips a downloaded GeoIP database. Only unzips .gz & .tar.gz files.
+ *
+ * @param string $path Path to zipped file.
+ * @param bool $unlink Whether to unlink archive or not.
+ */
+ public static function unzipDownloadedFile( $path, $unlink = false )
+ {
+ $parts = explode('.', basename($path));
+ $outputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($parts[0].'.dat');
+
+ // extract file
+ if (substr($path, -7, 7) == '.tar.gz')
+ {
+ // find the .dat file in the tar archive
+ $unzip = Piwik_Unzip::factory('tar.gz', $path);
+ $content = $unzip->listContent();
+
+ if (empty($content))
+ {
+ throw new Exception(Piwik_Translate('UserCountry_CannotListContent',
+ array("'$path'", $unzip->errorInfo())));
+ }
+
+ $datFile = null;
+ foreach ($content as $info)
+ {
+ $archivedPath = $info['filename'];
+ if (basename($archivedPath) === basename($outputPath))
+ {
+ $datFile = $archivedPath;
+ }
+ }
+
+ if ($datFile === null)
+ {
+ throw new Exception(Piwik_Translate('UserCountry_CannotFindGeoIPDatabaseInArchive',
+ array(basename($outputPath), "'$path'")));
+ }
+
+ // extract JUST the .dat file
+ $unzipped = $unzip->extractInString($datFile);
+
+ if (empty($unzipped))
+ {
+ throw new Exception(Piwik_Translate('UserCountry_CannotUnzipDatFile',
+ array("'$path'", $unzip->errorInfo())));
+ }
+
+ // write unzipped to file
+ $fd = fopen($outputPath, 'wb');
+ fwrite($fd, $unzipped);
+ fclose($fd);
+ }
+ else if (substr($path, -3, 3) == '.gz')
+ {
+ $unzip = Piwik_Unzip::factory('gz', $path);
+ $success = $unzip->extract($outputPath);
+
+ if ($success !== true)
+ {
+ throw new Exception(Piwik_Translate('UserCountry_CannotUnzipDatFile',
+ array("'$path'", $unzip->errorInfo())));
+ }
+ }
+ else
+ {
+ $ext = end(explode(basename($path), '.', 2));
+ throw new Exception(Piwik_Translate('UserCountry_UnsupportedArchiveType', "'$ext'"));
+ }
+
+ // delete original archive
+ if ($unlink)
+ {
+ unlink($path);
+ }
+ }
+
+ /**
+ * Creates a ScheduledTask instance based on set option values.
+ *
+ * @return Piwik_ScheduledTask
+ */
+ public static function makeScheduledTask()
+ {
+ $instance = new Piwik_UserCountry_GeoIPAutoUpdater();
+
+ $schedulePeriodStr = self::getSchedulePeriod();
+
+ // created the scheduledtime instance, also, since GeoIP updates are done on tuesdays,
+ // get new DBs on Wednesday
+ switch ($schedulePeriodStr)
+ {
+ case self::SCHEDULE_PERIOD_WEEKLY:
+ $schedulePeriod = new Piwik_ScheduledTime_Weekly();
+ $schedulePeriod->setDay(3);
+ break;
+ case self::SCHEDULE_PERIOD_MONTHLY:
+ default:
+ $schedulePeriod = new Piwik_ScheduledTime_Monthly();
+ $schedulePeriod->setDayOfWeek(3, 0);
+ break;
+ }
+
+ return new Piwik_ScheduledTask($instance, 'update', $schedulePeriod, Piwik_ScheduledTask::LOWEST_PRIORITY);
+ }
+
+ /**
+ * Sets the options used by this class based on query parameter values.
+ *
+ * See setUpdaterOptions for query params used.
+ */
+ public static function setUpdaterOptionsFromUrl()
+ {
+ self::setUpdaterOptions(array(
+ 'loc' => Piwik_Common::getRequestVar('loc_db', false, 'string'),
+ 'isp' => Piwik_Common::getRequestVar('isp_db', false, 'string'),
+ 'org' => Piwik_Common::getRequestVar('org_db', false, 'string'),
+ 'period' => Piwik_Common::getRequestVar('period', false, 'string'),
+ ));
+ }
+
+ /**
+ * Sets the options used by this class based on the elements in $options.
+ *
+ * The following elements of $options are used:
+ * 'loc' - URL for location database.
+ * 'isp' - URL for ISP database.
+ * 'org' - URL for Organization database.
+ * 'period' - 'weekly' or 'monthly'. When to run the updates.
+ *
+ * @param array $options
+ */
+ public static function setUpdaterOptions( $options )
+ {
+ // set url options
+ foreach (self::$urlOptions as $optionKey => $optionName)
+ {
+ if (empty($options[$optionKey]))
+ {
+ continue;
+ }
+
+ Piwik_SetOption($optionName, $url = $options[$optionKey]);
+ }
+
+ // set period option
+ if (!empty($options['period']))
+ {
+ $period = $options['period'];
+ if ($period != self::SCHEDULE_PERIOD_MONTHLY
+ && $period != self::SCHEDULE_PERIOD_WEEKLY)
+ {
+ throw new Exception(Piwik_Translate(
+ 'UserCountry_InvalidGeoIPUpdatePeriod',
+ array("'$period'", "'".self::SCHEDULE_PERIOD_MONTHLY."', '".self::SCHEDULE_PERIOD_WEEKLY."'")
+ ));
+ }
+
+ Piwik_SetOption(self::SCHEDULE_PERIOD_OPTION_NAME, $period);
+ }
+ }
+
+ /**
+ * Returns true if the auto-updater is setup to update at least one type of
+ * database. False if otherwise.
+ *
+ * @return bool
+ */
+ public static function isUpdaterSetup()
+ {
+ if (Piwik_GetOption(self::LOC_URL_OPTION_NAME) !== false
+ || Piwik_GetOption(self::ISP_URL_OPTION_NAME) !== false
+ || Piwik_GetOption(self::ORG_URL_OPTION_NAME) !== false)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieves the URLs used to update various GeoIP database files.
+ *
+ * @return array
+ */
+ public static function getConfiguredUrls()
+ {
+ $result = array();
+ foreach (self::$urlOptions as $key => $optionName)
+ {
+ $result[$key] = Piwik_GetOption($optionName);
+ }
+ return $result;
+ }
+
+ /**
+ * Returns the confiured URL (if any) for a type of database.
+ *
+ * @param string $key 'loc', 'isp' or 'org'
+ * @return string|false
+ */
+ public static function getConfiguredUrl( $key )
+ {
+ return Piwik_GetOption(self::$urlOptions[$key]);
+ }
+
+ /**
+ * Performs a GeoIP database update.
+ */
+ public static function performUpdate()
+ {
+ $instance = new Piwik_UserCountry_GeoIPAutoUpdater();
+ $instance->update();
+ }
+
+ /**
+ * Returns the configured update period, either 'week' or 'month'. Defaults to
+ * 'month'.
+ *
+ * @return string
+ */
+ public static function getSchedulePeriod()
+ {
+ $period = Piwik_GetOption(self::SCHEDULE_PERIOD_OPTION_NAME);
+ if ($period === false)
+ {
+ $period = self::SCHEDULE_PERIOD_MONTHLY;
+ }
+ return $period;
+ }
+
+ /**
+ * Returns an array of strings for GeoIP databases that have update URLs configured, but
+ * are not present in the misc directory. Each string is a key describing the type of
+ * database (ie, 'loc', 'isp' or 'org').
+ *
+ * @return array
+ */
+ public static function getMissingDatabases()
+ {
+ $result = array();
+ foreach (self::getConfiguredUrls() as $key => $url)
+ {
+ if ($url !== false)
+ {
+ // if a database of the type does not exist, but there's a url to update, then
+ // a database is missing
+ $path = Piwik_UserCountry_LocationProvider_GeoIp::getPathToGeoIpDatabase(
+ Piwik_UserCountry_LocationProvider_GeoIp::$dbNames[$key]);
+ if ($path === false)
+ {
+ $result[] = $key;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Returns the extension of a URL used to update a GeoIP database, if it can be found.
+ */
+ public static function getGeoIPUrlExtension( $url )
+ {
+ // check for &suffix= query param that is special to MaxMind URLs
+ if (preg_match('/suffix=([^&]+)/', $url, $matches))
+ {
+ return $matches[1];
+ }
+
+ // use basename of url
+ $filenameParts = explode('.', basename($url), 2);
+ if (count($filenameParts) > 1)
+ {
+ return end($filenameParts);
+ }
+ else
+ {
+ return reset($filenameParts);
+ }
+ }
+}