| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Plugins\GeoIp2; |
|
|
| use Exception; |
| use GeoIp2\Database\Reader; |
| use Piwik\Common; |
| use Piwik\Config; |
| use Piwik\Container\StaticContainer; |
| use Piwik\Date; |
| use Piwik\Filesystem; |
| use Piwik\Http; |
| use Piwik\Log; |
| use Piwik\Option; |
| use Piwik\Piwik; |
| use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2 as LocationProviderGeoIp2; |
| use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2\Php; |
| use Piwik\Plugins\UserCountry\LocationProvider; |
| use Piwik\Scheduler\Schedule\Hourly; |
| use Piwik\Scheduler\Scheduler; |
| use Piwik\Scheduler\Task; |
| use Piwik\Scheduler\Timetable; |
| use Piwik\Scheduler\Schedule\Monthly; |
| use Piwik\Scheduler\Schedule\Weekly; |
| use Piwik\SettingsPiwik; |
| use Piwik\Unzip; |
| use Piwik\Log\LoggerInterface; |
|
|
| |
| |
| |
| |
| class GeoIP2AutoUpdater extends Task |
| { |
| public const SCHEDULE_PERIOD_MONTHLY = 'month'; |
| public const SCHEDULE_PERIOD_WEEKLY = 'week'; |
|
|
| public const SCHEDULE_PERIOD_OPTION_NAME = 'geoip2.updater_period'; |
|
|
| public const LOC_URL_OPTION_NAME = 'geoip2.loc_db_url'; |
| public const ISP_URL_OPTION_NAME = 'geoip2.isp_db_url'; |
|
|
| public const LAST_RUN_TIME_OPTION_NAME = 'geoip2.updater_last_run_time'; |
|
|
| public const AUTO_SETUP_OPTION_NAME = 'geoip2.autosetup'; |
|
|
| private static $urlOptions = array( |
| 'loc' => self::LOC_URL_OPTION_NAME, |
| 'isp' => self::ISP_URL_OPTION_NAME, |
| ); |
|
|
| public function __construct() |
| { |
| $logger = StaticContainer::get(LoggerInterface::class); |
|
|
| if (!SettingsPiwik::isInternetEnabled()) { |
| |
| $logger->info("Internet is disabled in INI config, cannot update GeoIP database."); |
| return; |
| } |
|
|
| $schedulePeriodStr = self::getSchedulePeriod(); |
|
|
| |
| |
| |
| switch ($schedulePeriodStr) { |
| case self::SCHEDULE_PERIOD_WEEKLY: |
| $schedulePeriod = new Weekly(); |
| $schedulePeriod->setDay(3); |
| break; |
| case self::SCHEDULE_PERIOD_MONTHLY: |
| default: |
| $schedulePeriod = new Monthly(); |
| $schedulePeriod->setDay(3); |
| break; |
| } |
|
|
| if (Option::get(self::AUTO_SETUP_OPTION_NAME)) { |
| $schedulePeriod = new Hourly(); |
| } |
|
|
| parent::__construct($this, 'update', null, $schedulePeriod, Task::LOWEST_PRIORITY); |
| } |
|
|
| |
| |
| |
| |
| public function update() |
| { |
| try { |
| Option::set(self::LAST_RUN_TIME_OPTION_NAME, Date::factory('today')->getTimestamp()); |
|
|
| $locUrl = Option::get(self::LOC_URL_OPTION_NAME); |
| if (!empty($locUrl)) { |
| $this->downloadFile('loc', $locUrl); |
| $this->updateDbIpUrlOption(self::LOC_URL_OPTION_NAME); |
| } |
|
|
| $ispUrl = Option::get(self::ISP_URL_OPTION_NAME); |
| if (!empty($ispUrl)) { |
| $this->downloadFile('isp', $ispUrl); |
| $this->updateDbIpUrlOption(self::ISP_URL_OPTION_NAME); |
| } |
| } catch (Exception $ex) { |
| |
| Log::error($ex); |
| $this->performRedundantDbChecks(); |
| throw $ex; |
| } |
|
|
| $this->performRedundantDbChecks(); |
|
|
| if (Option::get(self::AUTO_SETUP_OPTION_NAME)) { |
| Option::delete(self::AUTO_SETUP_OPTION_NAME); |
| LocationProvider::setCurrentProvider(Php::ID); |
| |
| $scheduler = StaticContainer::getContainer()->get('Piwik\Scheduler\Scheduler'); |
| |
| $scheduler->rescheduleTask(new GeoIP2AutoUpdater()); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function downloadFile($dbType, $url) |
| { |
| $logger = StaticContainer::get(LoggerInterface::class); |
|
|
| $url = trim($url); |
|
|
| if (self::isPaidDbIpUrl($url)) { |
| $url = $this->fetchPaidDbIpUrl($url); |
| } elseif (self::isDbIpUrl($url)) { |
| $url = $this->getDbIpUrlWithLatestDate($url); |
| } |
|
|
| $ext = GeoIP2AutoUpdater::getGeoIPUrlExtension($url); |
|
|
| |
| $zippedFilename = $this->getZippedFilenameToDownloadTo($url, $dbType, $ext); |
|
|
| $zippedOutputPath = self::getTemporaryFolder($zippedFilename, true); |
|
|
| $url = self::removeDateFromUrl($url); |
|
|
| |
| try { |
| $logger->info("Downloading {url} to {output}.", [ |
| 'url' => $url, |
| 'output' => $zippedOutputPath, |
| ]); |
|
|
| $success = Http::sendHttpRequest($url, $timeout = 3600, $userAgent = null, $zippedOutputPath); |
| } catch (Exception $ex) { |
| throw new Exception("GeoIP2AutoUpdater: failed to download '$url' to " |
| . "'$zippedOutputPath': " . $ex->getMessage()); |
| } |
|
|
| if ($success !== true) { |
| throw new Exception("GeoIP2AutoUpdater: failed to download '$url' to " |
| . "'$zippedOutputPath'! (Unknown error)"); |
| } |
|
|
| Log::info("GeoIP2AutoUpdater: successfully downloaded '%s'", $url); |
|
|
| try { |
| self::unzipDownloadedFile($zippedOutputPath, $dbType, $url, $unlink = true); |
| } catch (Exception $ex) { |
| throw new Exception("GeoIP2AutoUpdater: failed to unzip '$zippedOutputPath' after " |
| . "downloading " . "'$url': " . $ex->getMessage()); |
| } |
|
|
| Log::info("GeoIP2AutoUpdater: successfully updated GeoIP 2 database '%s'", $url); |
| } |
|
|
| public static function getTemporaryFolder($file, $isDownload = false) |
| { |
| $folder = \Piwik\Container\StaticContainer::get('path.tmp') . '/latest/'; |
| if (!is_dir($folder)) { |
| Filesystem::mkdir($folder); |
| } |
| if (!is_writable($folder)) { |
| throw new \Exception("GeoIP2AutoUpdater: Can't create temporary file for download."); |
| } |
| return $folder . $file . ($isDownload ? '.download' : ''); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public static function unzipDownloadedFile($path, $dbType, $url, $unlink = false) |
| { |
| $isDbIp = self::isDbIpUrl($url); |
|
|
| $filename = $path; |
|
|
| if (substr($filename, -9, 9) === '.download') { |
| $filename = substr($filename, 0, -9); |
| } |
|
|
| $isDbIpUnknownDbType = $isDbIp && substr($filename, -5, 5) == '.mmdb'; |
|
|
| |
| if (substr($filename, -7, 7) == '.tar.gz') { |
| |
| $unzip = Unzip::factory('tar.gz', $path); |
| $content = $unzip->listContent(); |
|
|
| if (empty($content)) { |
| throw new Exception(Piwik::translate( |
| 'GeoIp2_CannotListContent', |
| array("'$path'", $unzip->errorInfo()) |
| )); |
| } |
|
|
| $fileToExtract = null; |
| foreach ($content as $info) { |
| $archivedPath = $info['filename']; |
| foreach (LocationProviderGeoIp2::$dbNames[$dbType] as $dbName) { |
| if ( |
| basename($archivedPath) === $dbName |
| || preg_match('/' . $dbName . '/', basename($archivedPath)) |
| ) { |
| $fileToExtract = $archivedPath; |
| } |
| } |
| } |
|
|
| if ($fileToExtract === null) { |
| throw new Exception(Piwik::translate( |
| 'GeoIp2_CannotFindGeoIPDatabaseInArchive', |
| array("'$path'") |
| )); |
| } |
|
|
| |
| $unzipped = $unzip->extractInString($fileToExtract); |
|
|
| if (empty($unzipped)) { |
| throw new Exception(Piwik::translate( |
| 'GeoIp2_CannotUnzipGeoIPFile', |
| array("'$path'", $unzip->errorInfo()) |
| )); |
| } |
|
|
| $dbFilename = basename($fileToExtract); |
| $tempFilename = $dbFilename . '.new'; |
| $outputPath = self::getTemporaryFolder($tempFilename); |
|
|
| |
| $fd = fopen($outputPath, 'wb'); |
| fwrite($fd, $unzipped); |
| fclose($fd); |
| } elseif ( |
| substr($filename, -3, 3) == '.gz' |
| || $isDbIpUnknownDbType |
| ) { |
| $unzip = Unzip::factory('gz', $path); |
|
|
| if ($isDbIpUnknownDbType) { |
| $tempFilename = 'unzipped-temp-dbip-file.mmdb'; |
| } else { |
| $dbFilename = substr(basename($filename), 0, -3); |
| $tempFilename = $dbFilename . '.new'; |
| } |
|
|
| $outputPath = self::getTemporaryFolder($tempFilename); |
|
|
| $success = $unzip->extract($outputPath); |
| if ($success !== true) { |
| throw new Exception(Piwik::translate( |
| 'General_CannotUnzipFile', |
| array("'$path'", $unzip->errorInfo()) |
| )); |
| } |
|
|
| if ($isDbIpUnknownDbType) { |
| $php = new Php([$dbType => [$outputPath]]); |
| $dbFilename = $php->detectDatabaseType($dbType) . '.mmdb'; |
| unset($php); |
| } |
| } else { |
| $parts = explode(basename($filename), '.', 2); |
| $ext = end($parts); |
| throw new Exception(Piwik::translate('GeoIp2_UnsupportedArchiveType', "'$ext'")); |
| } |
|
|
| try { |
| |
| if (empty($dbFilename) || false === LocationProviderGeoIp2::getGeoIPDatabaseTypeFromFilename($dbFilename)) { |
| throw new Exception("Unexpected GeoIP 2 archive file name '$path'."); |
| } |
|
|
| $customDbNames = array( |
| 'loc' => array(), |
| 'isp' => array(), |
| ); |
| $customDbNames[$dbType] = array($outputPath); |
|
|
| $phpProvider = new Php($customDbNames); |
|
|
| try { |
| $location = $phpProvider->getLocation(array('ip' => LocationProviderGeoIp2::TEST_IP)); |
| unset($phpProvider); |
| } catch (\Exception $e) { |
| Log::info("GeoIP2AutoUpdater: Encountered exception when testing newly downloaded" . |
| " GeoIP 2 database: %s", $e->getMessage()); |
|
|
| throw new Exception(Piwik::translate('GeoIp2_ThisUrlIsNotAValidGeoIPDB')); |
| } |
|
|
| if (empty($location)) { |
| throw new Exception(Piwik::translate('GeoIp2_ThisUrlIsNotAValidGeoIPDB')); |
| } |
|
|
| |
| foreach (LocationProvider::getAllProviders() as $provider) { |
| if ($provider instanceof Php) { |
| $provider->clearCachedInstances(); |
| } |
| } |
|
|
| |
| $oldDbFile = LocationProviderGeoIp2::getPathForGeoIpDatabase($dbFilename); |
| if (file_exists($oldDbFile)) { |
| @unlink($oldDbFile); |
| } |
|
|
| $tempFile = self::getTemporaryFolder($tempFilename); |
| if (@rename($tempFile, $oldDbFile) !== true) { |
| |
| copy($tempFile, $oldDbFile); |
| unlink($tempFile); |
| } |
|
|
| |
| if ($unlink) { |
| unlink($path); |
| } |
|
|
| self::renameAnyExtraGeolocationDatabases($dbFilename, $dbType); |
| } catch (Exception $ex) { |
| |
| if (file_exists($outputPath)) { |
| unlink($outputPath); |
| } |
| unlink($path); |
|
|
| throw $ex; |
| } |
| } |
|
|
| private static function renameAnyExtraGeolocationDatabases($dbFilename, $dbType) |
| { |
| if (!in_array($dbFilename, LocationProviderGeoIp2::$dbNames[$dbType])) { |
| return; |
| } |
|
|
| $logger = StaticContainer::get(LoggerInterface::class); |
| foreach (LocationProviderGeoIp2::$dbNames[$dbType] as $possibleName) { |
| if ($dbFilename == $possibleName) { |
| break; |
| } |
|
|
| $pathToExistingFile = LocationProviderGeoIp2::getPathForGeoIpDatabase($possibleName); |
| if (file_exists($pathToExistingFile)) { |
| $newFilename = $pathToExistingFile . '.' . time() . '.old'; |
| $logger->info("Renaming old geolocation database file {old} to {rename} so new downloaded file {new} will be used.", [ |
| 'old' => $possibleName, |
| 'rename' => $newFilename, |
| 'new' => $dbFilename, |
| ]); |
|
|
| rename($pathToExistingFile, $newFilename); |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| public static function setUpdaterOptionsFromUrl() |
| { |
| $options = array( |
| 'loc' => Common::getRequestVar('loc_db', false, 'string'), |
| 'isp' => Common::getRequestVar('isp_db', false, 'string'), |
| 'period' => Common::getRequestVar('period', false, 'string'), |
| ); |
|
|
| foreach (self::$urlOptions as $optionKey => $optionName) { |
| $options[$optionKey] = Common::unsanitizeInputValue($options[$optionKey]); |
| } |
|
|
| self::setUpdaterOptions($options); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public static function setUpdaterOptions($options) |
| { |
| |
| foreach (self::$urlOptions as $optionKey => $optionName) { |
| if (!isset($options[$optionKey])) { |
| continue; |
| } |
|
|
| $url = $options[$optionKey]; |
| $url = self::removeDateFromUrl($url); |
|
|
| self::checkGeoIPUpdateUrl($url); |
|
|
| Option::set($optionName, $url); |
| } |
|
|
| |
| if (!empty($options['period'])) { |
| $period = $options['period']; |
|
|
| if ( |
| $period != self::SCHEDULE_PERIOD_MONTHLY |
| && $period != self::SCHEDULE_PERIOD_WEEKLY |
| ) { |
| throw new Exception(Piwik::translate( |
| 'GeoIp2_InvalidGeoIPUpdatePeriod', |
| array("'$period'", "'" . self::SCHEDULE_PERIOD_MONTHLY . "', '" . self::SCHEDULE_PERIOD_WEEKLY . "'") |
| )); |
| } |
|
|
| Option::set(self::SCHEDULE_PERIOD_OPTION_NAME, $period); |
|
|
| |
| $scheduler = StaticContainer::getContainer()->get('Piwik\Scheduler\Scheduler'); |
|
|
| $scheduler->rescheduleTaskAndRunTomorrow(new GeoIP2AutoUpdater()); |
| } |
| } |
|
|
| protected static function checkGeoIPUpdateUrl($url) |
| { |
| if (empty($url)) { |
| return; |
| } |
|
|
| $parsedUrl = @parse_url($url); |
| $schema = $parsedUrl['scheme'] ?? ''; |
| $host = $parsedUrl['host'] ?? ''; |
|
|
| if (empty($schema) || empty($host) || !in_array(mb_strtolower($schema), ['http', 'https'])) { |
| throw new Exception(Piwik::translate('GeoIp2_MalFormedUpdateUrl', '<i>' . Common::sanitizeInputValue($url) . '</i>')); |
| } |
|
|
| $validHosts = Config::getInstance()->General['geolocation_download_from_trusted_hosts']; |
| $isValidHost = false; |
|
|
| foreach ($validHosts as $validHost) { |
| if (preg_match('/(^|\.)' . preg_quote($validHost) . '$/i', $host)) { |
| $isValidHost = true; |
| break; |
| } |
| } |
|
|
| if (true !== $isValidHost) { |
| throw new Exception(Piwik::translate('GeoIp2_InvalidGeoIPUpdateHost', [ |
| '<i>' . $url . '</i>', '<i>' . implode(', ', $validHosts) . '</i>', '<i>geolocation_download_from_trusted_hosts</i>', |
| ])); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public static function isUpdaterSetup() |
| { |
| if ( |
| Option::get(self::LOC_URL_OPTION_NAME) !== false |
| || Option::get(self::ISP_URL_OPTION_NAME) !== false |
| ) { |
| return true; |
| } |
|
|
| return false; |
| } |
|
|
| |
| |
| |
| |
| |
| public static function getConfiguredUrls() |
| { |
| $result = array(); |
| foreach (self::$urlOptions as $key => $optionName) { |
| $result[$key] = Option::get($optionName); |
| } |
| return $result; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public static function getConfiguredUrl($key) |
| { |
| if (empty(self::$urlOptions[$key])) { |
| throw new Exception("Invalid key $key"); |
| } |
| $url = Option::get(self::$urlOptions[$key]); |
| return $url; |
| } |
|
|
| |
| |
| |
| public static function performUpdate() |
| { |
| $instance = new GeoIP2AutoUpdater(); |
| $instance->update(); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public static function getSchedulePeriod() |
| { |
| $period = Option::get(self::SCHEDULE_PERIOD_OPTION_NAME); |
| if ($period === false) { |
| $period = self::SCHEDULE_PERIOD_MONTHLY; |
| } |
| return $period; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public static function getMissingDatabases() |
| { |
| $result = array(); |
| foreach (self::getConfiguredUrls() as $key => $url) { |
| if (!empty($url)) { |
| |
| |
| $path = LocationProviderGeoIp2::getPathToGeoIpDatabase( |
| LocationProviderGeoIp2::$dbNames[$key] |
| ); |
| if ($path === false) { |
| $result[] = $key; |
| } |
| } |
| } |
| return $result; |
| } |
|
|
| |
| |
| |
| public static function getGeoIPUrlExtension($url) |
| { |
| |
| if (preg_match('/suffix=([^&]+)/', $url, $matches)) { |
| $ext = $matches[1]; |
| } else { |
| |
| $filenameParts = explode('.', basename($url), 2); |
| if (count($filenameParts) > 1) { |
| $ext = end($filenameParts); |
| } else { |
| $ext = reset($filenameParts); |
| } |
| } |
|
|
| if ('mmdb.gz' === $ext) { |
| $ext = 'gz'; |
| } |
|
|
| self::checkForSupportedArchiveType($url, $ext); |
|
|
| return $ext; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| private static function checkForSupportedArchiveType($url, $ext) |
| { |
| if ($ext === 'mmdb' && self::isDbIpUrl($url)) { |
| return; |
| } |
|
|
| if ( |
| $ext != 'tar.gz' |
| && $ext != 'gz' |
| && $ext != 'mmdb.gz' |
| ) { |
| throw new \Exception(Piwik::translate('GeoIp2_UnsupportedArchiveType', "'$ext'")); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function performRedundantDbChecks($logErrors = true) |
| { |
| $databaseTypes = array_keys(LocationProviderGeoIp2::$dbNames); |
|
|
| foreach ($databaseTypes as $type) { |
| $customNames = array( |
| 'loc' => array(), |
| 'isp' => array(), |
| 'org' => array(), |
| ); |
| $customNames[$type] = LocationProviderGeoIp2::$dbNames[$type]; |
|
|
| |
| $provider = new Php($customNames); |
|
|
| |
| try { |
| |
| $pathToDb = LocationProviderGeoIp2::getPathToGeoIpDatabase($customNames[$type]); |
|
|
| if (empty($pathToDb)) { |
| continue; |
| } |
|
|
| $reader = new Reader($pathToDb); |
|
|
| $location = $provider->getLocation(array('ip' => LocationProviderGeoIp2::TEST_IP)); |
| unset($provider, $reader); |
| } catch (\Exception $e) { |
| if ($logErrors) { |
| Log::error("GeoIP2AutoUpdater: Encountered exception when performing redundant tests on GeoIP2 " |
| . "%s database: %s", $type, $e->getMessage()); |
| } |
|
|
| |
| [$oldPath, $newPath] = $this->getOldAndNewPathsForBrokenDb($customNames[$type]); |
|
|
| |
| if ( |
| $oldPath !== false |
| && $newPath !== false |
| ) { |
| if (file_exists($newPath)) { |
| unlink($newPath); |
| } |
|
|
| rename($oldPath, $newPath); |
| } |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| private function getOldAndNewPathsForBrokenDb($possibleDbNames) |
| { |
| $pathToDb = LocationProviderGeoIp2::getPathToGeoIpDatabase($possibleDbNames); |
| $newPath = false; |
|
|
| if ($pathToDb !== false) { |
| $newPath = $pathToDb . ".broken"; |
| } |
|
|
| return array($pathToDb, $newPath); |
| } |
|
|
| |
| |
| |
| |
| |
| public static function getLastRunTime() |
| { |
| $timestamp = Option::get(self::LAST_RUN_TIME_OPTION_NAME); |
| return $timestamp === false ? false : Date::factory((int)$timestamp); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| private static function removeDateFromUrl($url) |
| { |
| return preg_replace("/&date=[^&#]*/", '', $url); |
| } |
|
|
| |
| |
| |
| |
| |
| public static function getNextRunTime() |
| { |
| $task = new GeoIP2AutoUpdater(); |
|
|
| $timetable = new Timetable(); |
| return $timetable->getScheduledTaskTime($task->getName()); |
| } |
|
|
| |
| |
| |
| public function getRescheduledTime() |
| { |
| $nextScheduledTime = parent::getRescheduledTime(); |
|
|
| |
| if ($this->isAtLeastOneGeoIpDbOutOfDate($nextScheduledTime)) { |
| return time(); |
| } |
|
|
| return $nextScheduledTime; |
| } |
|
|
| private function isAtLeastOneGeoIpDbOutOfDate($rescheduledTime) |
| { |
| $previousScheduledRuntime = $this->getPreviousScheduledTime($rescheduledTime)->setTime("00:00:00")->getTimestamp(); |
|
|
| foreach (LocationProviderGeoIp2::$dbNames as $type => $dbNames) { |
| $dbUrl = Option::get(self::$urlOptions[$type]); |
| $dbPath = LocationProviderGeoIp2::getPathToGeoIpDatabase($dbNames); |
|
|
| |
| |
| if ( |
| !empty($dbUrl) |
| && filemtime($dbPath) < $previousScheduledRuntime |
| ) { |
| return true; |
| } |
| } |
|
|
| return false; |
| } |
|
|
| private function getPreviousScheduledTime($rescheduledTime) |
| { |
| $updaterPeriod = self::getSchedulePeriod(); |
|
|
| if ($updaterPeriod == self::SCHEDULE_PERIOD_WEEKLY) { |
| return Date::factory($rescheduledTime)->subWeek(1); |
| } elseif ($updaterPeriod == self::SCHEDULE_PERIOD_MONTHLY) { |
| return Date::factory($rescheduledTime)->subMonth(1); |
| } |
| throw new Exception("Unknown GeoIP 2 updater period found in database: %s", $updaterPeriod); |
| } |
|
|
| public static function getZippedFilenameToDownloadTo($url, $dbType, $ext) |
| { |
| if (self::isDbIpUrl($url)) { |
| if (preg_match('/(dbip-[a-zA-Z0-9_]+)(?:-lite)?-\d{4}-\d{2}/', $url, $matches)) { |
| $parts = explode('-', $matches[1]); |
| $dbName = $parts[1] === 'asn' ? 'ASN' : ucfirst($parts[1]); |
| return strtoupper($parts[0]) . '-' . $dbName . '.mmdb.' . $ext; |
| } else { |
| return basename($url); |
| } |
| } |
|
|
| return LocationProviderGeoIp2::$dbNames[$dbType][0] . '.' . $ext; |
| } |
|
|
| protected function getDbIpUrlWithLatestDate($url) |
| { |
| $today = Date::today(); |
| return preg_replace('/-\d{4}-\d{2}\./', '-' . $today->toString('Y-m') . '.', $url); |
| } |
|
|
| public static function isDbIpUrl($url) |
| { |
| return !! preg_match('/^http[s]?:\/\/([a-z0-9-]+\.)?db-ip\.com/', $url); |
| } |
|
|
| protected static function isPaidDbIpUrl($url) |
| { |
| return !! preg_match('/^http[s]?:\/\/([a-z0-9-]+\.)?db-ip\.com\/account\/[0-9a-z]+\/db/', $url); |
| } |
|
|
| protected function fetchPaidDbIpUrl($url) |
| { |
| $content = trim($this->fetchUrl($url)); |
|
|
| if (0 === strpos($content, 'http')) { |
| return $content; |
| } |
|
|
| $content = json_decode($content, true); |
|
|
| if (!empty($content['mmdb']['url'])) { |
| return $content['mmdb']['url']; |
| } |
|
|
| if (!empty($content['url'])) { |
| return $content['url']; |
| } |
|
|
| throw new Exception('Unable to determine download url'); |
| } |
|
|
| protected function fetchUrl($url) |
| { |
| return Http::fetchRemoteFile($url); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| protected function updateDbIpUrlOption(string $option): void |
| { |
| if ($option !== self::LOC_URL_OPTION_NAME && $option !== self::ISP_URL_OPTION_NAME) { |
| return; |
| } |
|
|
| $url = trim(Option::get($option)); |
|
|
| if (self::isDbIpUrl($url)) { |
| $latestUrl = $this->getDbIpUrlWithLatestDate($url); |
|
|
| if ($url !== $latestUrl) { |
| Option::set($option, $latestUrl); |
| } |
| } |
| } |
| } |
|
|