View source
<?php
namespace Drupal\smart_ip_maxmind_geoip2_bin_db\EventSubscriber;
use Drupal\smart_ip_maxmind_geoip2_bin_db\DatabaseFileUtility;
use Drupal\smart_ip_maxmind_geoip2_bin_db\MaxmindGeoip2BinDb;
use Drupal\smart_ip\DatabaseFileUtilityBase;
use Drupal\smart_ip\GetLocationEvent;
use Drupal\smart_ip\AdminSettingsEvent;
use Drupal\smart_ip\DatabaseFileEvent;
use Drupal\smart_ip\SmartIpEventSubscriberBase;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\StreamWrapper\PrivateStream;
use Drupal\Core\Link;
use Drupal\Core\Url;
class SmartIpEventSubscriber extends SmartIpEventSubscriberBase {
public static function sourceId() {
return 'maxmind_geoip2_bin_db';
}
public static function configName() {
return 'smart_ip_maxmind_geoip2_bin_db.settings';
}
public function processQuery(GetLocationEvent $event) {
if ($event
->getDataSource() == self::sourceId()) {
$config = \Drupal::config(self::configName());
$autoUpdate = $config
->get('db_auto_update');
$customPath = $config
->get('bin_file_custom_path');
$version = $config
->get('version');
$edition = $config
->get('edition');
$location = $event
->getLocation();
$ipAddress = $location
->get('ipAddress');
$folder = DatabaseFileUtility::getPath($autoUpdate, $customPath);
$file = DatabaseFileUtility::getFilename($version, $edition);
$dbFile = "{$folder}/{$file}";
if (!file_exists($dbFile)) {
\Drupal::logger('smart_ip')
->error(t('The database file %file does not exist or has been moved.', [
'%file' => $dbFile,
]));
return;
}
if (class_exists('\\MaxMind\\Db\\Reader')) {
$reader = new \MaxMind\Db\Reader($dbFile);
$raw = $reader
->get($ipAddress);
}
else {
$reader = new \GeoIp2\Database\Reader($dbFile);
$edition = $config
->get('edition');
if ($edition == MaxmindGeoip2BinDb::COUNTRY_EDITION) {
$record = $reader
->country($ipAddress);
}
else {
$record = $reader
->city($ipAddress);
}
$raw = $record
->jsonSerialize();
}
$lang = \Drupal::languageManager()
->getCurrentLanguage()
->getId();
if (class_exists('\\MaxMind\\Db\\Reader')) {
$reader
->close();
}
if (!isset($raw['country']['names'][$lang])) {
$lang = 'en';
}
$country = isset($raw['country']['names'][$lang]) ? $raw['country']['names'][$lang] : '';
$countryCode = isset($raw['country']['iso_code']) ? $raw['country']['iso_code'] : '';
$region = isset($raw['subdivisions'][0]['names'][$lang]) ? $raw['subdivisions'][0]['names'][$lang] : '';
$regionCode = isset($raw['subdivisions'][0]['iso_code']) ? $raw['subdivisions'][0]['iso_code'] : '';
$city = isset($raw['city']['names'][$lang]) ? $raw['city']['names'][$lang] : '';
$zip = isset($raw['postal']['code']) ? $raw['postal']['code'] : '';
$latitude = isset($raw['location']['latitude']) ? $raw['location']['latitude'] : '';
$longitude = isset($raw['location']['longitude']) ? $raw['location']['longitude'] : '';
$timeZone = isset($raw['location']['time_zone']) ? $raw['location']['time_zone'] : '';
$isEuCountry = isset($raw['country']['is_in_european_union']) ? $raw['country']['is_in_european_union'] : '';
$isGdprCountry = isset($record['country']['isGdprCountry']) ? $record['country']['isGdprCountry'] : '';
$location
->set('originalData', $raw)
->set('country', $country)
->set('countryCode', Unicode::strtoupper($countryCode))
->set('region', $region)
->set('regionCode', $regionCode)
->set('city', $city)
->set('zip', $zip)
->set('latitude', $latitude)
->set('longitude', $longitude)
->set('timeZone', $timeZone)
->set('isEuCountry', $isEuCountry)
->set('isGdprCountry', $isGdprCountry);
}
}
public function formSettings(AdminSettingsEvent $event) {
$config = \Drupal::config(self::configName());
$autoUpdate = $config
->get('db_auto_update');
$form = $event
->getForm();
$filesystem = \Drupal::service('file_system');
$privateFolder = $filesystem
->realpath(DatabaseFileUtilityBase::DRUPAL_FOLDER);
$errorSourceId = \Drupal::state()
->get('smart_ip.request_db_error_source_id') ?: '';
$autoDbUpdateLabel = t('Automatic MaxMind GeoIP2 binary database update');
if (!$autoUpdate && $errorSourceId == self::sourceId()) {
$form['smart_ip_bin_database_update']['#access'] = FALSE;
}
if (empty($privateFolder)) {
$privateFolder = t('your "smart_ip" labelled folder inside your Drupal private folder (currently it is not yet set)');
}
else {
$privateFolder = t('@path (default)', [
'@path' => $privateFolder,
]);
}
$form['smart_ip_data_source_selection']['smart_ip_data_source']['#options'][self::sourceId()] = t("Use MaxMind GeoIP2 binary database. It is the evolution of MaxMind's \n original GeoIP binary database or now called GeoIP Legacy. This MaxMind's \n binary database uses a custom binary format to maximize lookup speed and \n accessible via two available APIs: @maxmind_db_reader_api which includes \n an optional C extension that you may @install to dramatically increase the \n performance of lookups in GeoIP2 binary database and the default \n @geoip2_api. The binary database file for both lite and licensed version \n can be downloaded @here (you will need to @login to your MaxMind account \n first). The binary database is roughly 130MB, and there's an option below \n to enable the automatic download/extraction of it. If you prefer to \n manually download the file %file_lite_city (if Lite version City edition) \n or %file_licensed_city (if Licensed version City edition) or \n %file_lite_country (if Lite version Country edition) or \n %file_licensed_country (if Licensed version Country edition), it must be \n uploaded to your server at @path or to your defined custom path (Note: It \n is your responsibility to update them manually every month and to define \n such a path, please set '@auto_update_label' to 'No', and fill in the \n field which will then appear).", [
'@maxmind_db_reader_api' => Link::fromTextAndUrl(t('MaxMind DB Reader PHP API'), Url::fromUri('https://github.com/maxmind/MaxMind-DB-Reader-php'))
->toString(),
'@install' => Link::fromTextAndUrl(t('install'), Url::fromUri('https://www.webfoobar.com/node/71#install-maxmind-php-c-extension'))
->toString(),
'@geoip2_api' => Link::fromTextAndUrl(t('GeoIP2 PHP API'), Url::fromUri('http://maxmind.github.io/GeoIP2-php'))
->toString(),
'@login' => Link::fromTextAndUrl(t('login'), Url::fromUri('https://www.maxmind.com/en/account/login'))
->toString(),
'@here' => Link::fromTextAndUrl(t('here'), Url::fromUri('https://www.maxmind.com/en/download_files'))
->toString(),
'%file_lite_city' => MaxmindGeoip2BinDb::FILENAME_LITE_CITY . MaxmindGeoip2BinDb::FILE_EXTENSION,
'%file_licensed_city' => MaxmindGeoip2BinDb::FILENAME_LINCENSED_CITY . MaxmindGeoip2BinDb::FILE_EXTENSION,
'%file_lite_country' => MaxmindGeoip2BinDb::FILENAME_LITE_COUNTRY . MaxmindGeoip2BinDb::FILE_EXTENSION,
'%file_licensed_country' => MaxmindGeoip2BinDb::FILENAME_LINCENSED_COUNTRY . MaxmindGeoip2BinDb::FILE_EXTENSION,
'@path' => $privateFolder,
'@auto_update_label' => $autoDbUpdateLabel,
]);
$form['smart_ip_data_source_selection']['maxmind_geoip2_bin_db_version'] = [
'#type' => 'select',
'#title' => t('MaxMind GeoIP2 binary database version'),
'#description' => t('Select version of MaxMind GeoIP2 binary database.'),
'#options' => [
MaxmindGeoip2BinDb::LINCENSED_VERSION => t('Licensed'),
MaxmindGeoip2BinDb::LITE_VERSION => t('Lite'),
],
'#default_value' => $config
->get('version'),
'#states' => [
'visible' => [
':input[name="smart_ip_data_source"]' => [
'value' => self::sourceId(),
],
],
],
];
$form['smart_ip_data_source_selection']['maxmind_geoip2_bin_db_edition'] = [
'#type' => 'select',
'#title' => t('MaxMind GeoIP2 binary database edition'),
'#description' => t('Select edition of MaxMind GeoIP2 binary database.'),
'#options' => [
MaxmindGeoip2BinDb::CITY_EDITION => t('City'),
MaxmindGeoip2BinDb::COUNTRY_EDITION => t('Country'),
],
'#default_value' => $config
->get('edition'),
'#states' => [
'visible' => [
':input[name="smart_ip_data_source"]' => [
'value' => self::sourceId(),
],
],
],
];
$form['smart_ip_data_source_selection']['maxmind_geoip2_bin_db_user_account'] = [
'#type' => 'textfield',
'#title' => t('MaxMind user account ID'),
'#description' => t('Enter your MaxMind user account ID. This is required for
lite version.'),
'#default_value' => $config
->get('user_account'),
'#size' => 30,
'#states' => [
'visible' => [
':input[name="smart_ip_data_source"]' => [
'value' => self::sourceId(),
],
':input[name="maxmind_geoip2_bin_db_version"]' => [
'value' => MaxmindGeoip2BinDb::LITE_VERSION,
],
':input[name="maxmind_geoip2_bin_db_auto_update"]' => [
'value' => '1',
],
],
],
];
$form['smart_ip_data_source_selection']['maxmind_geoip2_bin_db_license_key'] = [
'#type' => 'textfield',
'#title' => t('MaxMind GeoIP2 license key'),
'#description' => t("Enter your MaxMind GeoIP2 account's license key (view your \n license key @here). This is required for lite and licensed version.", [
'@here' => Link::fromTextAndUrl(t('here'), Url::fromUri('https://www.maxmind.com/en/my_license_key'))
->toString(),
]),
'#default_value' => $config
->get('license_key'),
'#size' => 30,
'#states' => [
'visible' => [
':input[name="smart_ip_data_source"]' => [
'value' => self::sourceId(),
],
':input[name="maxmind_geoip2_bin_db_auto_update"]' => [
'value' => '1',
],
],
],
];
$form['smart_ip_data_source_selection']['maxmind_geoip2_bin_db_auto_update'] = [
'#type' => 'select',
'#title' => $autoDbUpdateLabel,
'#description' => t('MaxMind GeoIP2 binary database will be automatically updated via
cron.php every Wednesday (for licensed and lite/free versions).
MaxMind GeoIP2 updates their database every Tuesday for licensed
and free versions. @cron must be enabled for this to work.', [
'@cron' => Link::fromTextAndUrl(t('Cron'), Url::fromRoute('system.cron_settings'))
->toString(),
]),
'#options' => [
TRUE => t('Yes'),
FALSE => t('No'),
],
'#default_value' => intval($autoUpdate),
'#states' => [
'visible' => [
':input[name="smart_ip_data_source"]' => [
'value' => self::sourceId(),
],
],
],
];
$form['smart_ip_data_source_selection']['maxmind_geoip2_bin_db_custom_path'] = [
'#type' => 'textfield',
'#title' => t('MaxMind GeoIP2 binary database custom path'),
'#description' => t('Define the path where the MaxMind GeoIP2 binary database file is
located in your server (Note: it is your responsibility to add security
on this path. See the online handbook for @security). Include preceding
slash but do not include trailing slash. This is useful for multi Drupal
sites with each of their Smart IP module looks to a common MaxMind
GeoIP2 binary database and it can be also useful for server with
installed GeoIPLookup CLI tool where its MaxMind binary database file
can be used here (usually its path is located at /usr/share/GeoIP). This
path will be ignored if "Automatic MaxMind binary database update" is
enabled which uses the Drupal private file system path. Leave it blank
if you prefer the default Drupal private file system path.', [
'@security' => Link::fromTextAndUrl(t('more information about securing private files'), Url::fromUri('https://www.drupal.org/documentation/modules/file'))
->toString(),
]),
'#default_value' => $config
->get('bin_file_custom_path'),
'#states' => [
'visible' => [
':input[name="smart_ip_data_source"]' => [
'value' => self::sourceId(),
],
':input[name="maxmind_geoip2_bin_db_auto_update"]' => [
'value' => '0',
],
],
],
];
$event
->setForm($form);
}
public function validateFormSettings(AdminSettingsEvent $event) {
$formState = $event
->getFormState();
if ($formState
->getValue('smart_ip_data_source') == self::sourceId()) {
$autoUpdate = $formState
->getValue('maxmind_geoip2_bin_db_auto_update');
if ($autoUpdate && $formState
->getValue('maxmind_geoip2_bin_db_version') == MaxmindGeoip2BinDb::LITE_VERSION && $formState
->isValueEmpty('maxmind_geoip2_bin_db_user_account')) {
$formState
->setErrorByName('maxmind_geoip2_bin_db_user_account', t('Please provide MaxMind GeoIP2 user account ID.'));
}
if ($autoUpdate && $formState
->getValue('maxmind_geoip2_bin_db_version') == MaxmindGeoip2BinDb::LITE_VERSION && $formState
->isValueEmpty('maxmind_geoip2_bin_db_license_key') || $formState
->getValue('maxmind_geoip2_bin_db_version') == MaxmindGeoip2BinDb::LINCENSED_VERSION && $formState
->isValueEmpty('maxmind_geoip2_bin_db_license_key')) {
$formState
->setErrorByName('maxmind_geoip2_bin_db_license_key', t('Please provide MaxMind GeoIP2 license key.'));
}
if ($autoUpdate || !$autoUpdate && $formState
->isValueEmpty('maxmind_geoip2_bin_db_custom_path')) {
if (empty(PrivateStream::basePath())) {
$formState
->setErrorByName('maxmind_geoip2_bin_db_auto_update', t('Your private file system path is not yet configured.
Please check your @filesystem.', [
'@filesystem' => Link::fromTextAndUrl(t('File system'), Url::fromRoute('system.file_system_settings'))
->toString(),
]));
}
else {
$filesystem = \Drupal::service('file_system');
$privateFolder = $filesystem
->realpath(DatabaseFileUtilityBase::DRUPAL_FOLDER);
$file = DatabaseFileUtility::getFilename($formState
->getValue('maxmind_geoip2_bin_db_version'), $formState
->getValue('maxmind_geoip2_bin_db_edition'));
if (!file_exists("{$privateFolder}/{$file}")) {
if ($autoUpdate) {
if (empty($privateFolder)) {
$message = t('There is an @issue in Drupal private file system path.', [
'@issue' => Link::fromTextAndUrl(t('issue'), Url::fromRoute('system.status', [], [
'fragment' => 'error',
]))
->toString(),
]);
}
else {
$message = t('Initially you need to manually download the @file and
upload it to your server at @path. The next succeeding
updates should be automatic.', [
'@file' => $file,
'@path' => $privateFolder,
]);
}
}
else {
$message = t('Please upload the @file at @path.', [
'@file' => $file,
'@path' => $privateFolder,
]);
}
$formState
->setErrorByName('maxmind_geoip2_bin_db_auto_update', $message);
}
}
}
elseif (!$formState
->isValueEmpty('maxmind_geoip2_bin_db_custom_path')) {
$folder = $formState
->getValue('maxmind_geoip2_bin_db_custom_path');
$file = DatabaseFileUtility::getFilename($formState
->getValue('maxmind_geoip2_bin_db_version'), $formState
->getValue('maxmind_geoip2_bin_db_edition'));
if (!file_exists("{$folder}/{$file}")) {
$formState
->setErrorByName('maxmind_geoip2_bin_db_auto_update', t('Please upload the @file at @path.', [
'@file' => $file,
'@path' => $folder,
]));
}
}
}
}
public function submitFormSettings(AdminSettingsEvent $event) {
$formState = $event
->getFormState();
if ($formState
->getValue('smart_ip_data_source') == self::sourceId()) {
$config = \Drupal::configFactory()
->getEditable(self::configName());
$config
->set('version', $formState
->getValue('maxmind_geoip2_bin_db_version'))
->set('edition', $formState
->getValue('maxmind_geoip2_bin_db_edition'))
->set('user_account', $formState
->getValue('maxmind_geoip2_bin_db_user_account'))
->set('license_key', $formState
->getValue('maxmind_geoip2_bin_db_license_key'))
->set('db_auto_update', $formState
->getValue('maxmind_geoip2_bin_db_auto_update'))
->set('bin_file_custom_path', $formState
->getValue('maxmind_geoip2_bin_db_custom_path'))
->save();
}
}
public function manualUpdate(DatabaseFileEvent $event) {
$dataSource = \Drupal::config('smart_ip.settings')
->get('data_source');
if ($dataSource == self::sourceId()) {
DatabaseFileUtility::downloadDatabaseFile();
}
}
public function cronRun(DatabaseFileEvent $event) {
$dataSource = \Drupal::config('smart_ip.settings')
->get('data_source');
if ($dataSource == self::sourceId()) {
$config = \Drupal::config(self::configName());
$autoUpdate = $config
->get('db_auto_update');
$version = $config
->get('version');
$lastUpdateTime = \Drupal::state()
->get('smart_ip_maxmind_geoip2_bin_db.last_update_time') ?: 0;
$frequency = DatabaseFileUtility::DOWNLOAD_WEEKLY;
if (DatabaseFileUtility::needsUpdate($lastUpdateTime, $autoUpdate, $frequency)) {
DatabaseFileUtility::downloadDatabaseFile();
}
}
}
}