You are here

smart_ip.module in Smart IP 8.3

Determines country, geo location (longitude/latitude), region, city and postal code of the user, based on IP address

This module uses the IP address that a user is connected from to extract the location information where the user is located. This method is not foolproof, because a user may connect through an anonymizing proxy, or may be in an unusual case, such as getting service from a neighboring country, or using an IP block leased from a company in another country. Additionaly, users accessing a server on a local network may be using an IP that is not assigned to any country (e.g. 192.168.x.x).

@author Roland Michael dela Peña.

File

smart_ip.module
View source
<?php

/**
 * @file
 * Determines country, geo location (longitude/latitude), region, city and
 * postal code of the user, based on IP address
 *
 * This module uses the IP address that a user is connected from to extract
 * the location information where the user is located.  This method is not
 * foolproof, because a user may connect through an anonymizing proxy, or may
 * be in an unusual case, such as getting service from a neighboring country,
 * or using an IP block leased from a company in another country.
 * Additionaly, users accessing a server on a local network may be using
 * an IP that is not assigned to any country (e.g. 192.168.x.x).
 *
 * @author Roland Michael dela Peña.
 */
use Drupal\smart_ip\SmartIp;
use Drupal\smart_ip\SmartIpEvents;
use Drupal\smart_ip\SmartIpLocationInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Component\Serialization\Json;

/**
 * Implements hook_help().
 */
function smart_ip_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.smart_ip':
      return $output = '<p>' . t("Smart IP identify visitor's geographical location (longitude/latitude), \n        country, region, city and postal code based on the IP address of the user. \n        These information will be stored at session variable (&#36;_SESSION) with \n        array key 'smart_ip' and Drupal user data service using the parameters \n        'smart_ip' as module and 'geoip_location' as name of the user but \n        optionally it can be disabled (by role) at Smart IP admin page. Other\n        modules can use the function \n        \\Drupal\\smart_ip\\SmartIp::query(&#36;ipAddress) that returns an array \n        containing the visitor's ISO 3166 2-character country code, longitude, \n        latitude, region, city and postal code. It provides a feature for you to \n        perform your own IP lookup and admin spoofing of an arbitrary IP for \n        testing purposes.") . '</p>';
      return $output;
    case 'smart_ip.settings':
      $output = '<p>' . t('Configure the Smart IP settings') . '</p>';
      return $output;
  }
  return '';
}

/**
 * Implements hook_entity_insert().
 *
 * Save new user's geolocation upon registration.
 */
function smart_ip_entity_insert(EntityInterface $entity) {
  if ($entity
    ->getEntityTypeId() == 'user') {
    $is_new = $entity
      ->getCreatedTime() == \Drupal::time()
      ->getRequestTime();
    if ($is_new) {
      $save_user_location = \Drupal::config('smart_ip.settings')
        ->get('save_user_location_creation');
      if ($save_user_location) {
        $data['location'] = SmartIp::query();

        // Determine if saving location details of visitor from EU countries are
        // permitted.
        $euVisitorsDontSave = \Drupal::config('smart_ip.settings')
          ->get('eu_visitor_dont_save') && $data['location']['isGdprCountry'];
        if (!$euVisitorsDontSave) {

          /** @var \Drupal\user\UserData $userData */
          $userData = \Drupal::service('user.data');
          $userData
            ->set('smart_ip', $entity
            ->id(), 'geoip_location_original', $data);
        }
      }
    }
  }
}

/**
 * Implements hook_cron().
 */
function smart_ip_cron() {

  /** @var \Drupal\smart_ip\DatabaseFileEvent $event */
  $event = \Drupal::service('smart_ip.database_file_event');

  // Allow Smart IP source module to act on cron run.
  \Drupal::service('event_dispatcher')
    ->dispatch(SmartIpEvents::CRON_RUN, $event);
}

/**
 * Implements hook_page_attachments().
 */
function smart_ip_page_attachments(array &$page) {
  if (!\Drupal\smart_ip\SmartIp::checkAllowedPage()) {

    // This page is not on the list to access user's geolocation.
    return;
  }

  /** @var \Drupal\smart_ip\SmartIpLocation $location */
  $location = \Drupal::service('smart_ip.smart_ip_location');
  $data['location'] = $location
    ->getData(FALSE);
  $value = Json::encode($data);

  // Make user geolocation available to javascript via "drupalSettings.smartIp".
  $page['#attached']['drupalSettings']['smartIp'] = $value;
  $page['#attached']['drupalSettings']['smartIpSrc'] = [
    'smartIp' => SmartIpLocationInterface::SMART_IP,
    'geocodedSmartIp' => SmartIpLocationInterface::GEOCODED_SMART_IP,
    'w3c' => SmartIpLocationInterface::W3C,
  ];
}

/**
 * Implements hook_theme().
 */
function smart_ip_theme() {
  return [
    'smart_ip_latitude_dms' => [
      'variables' => [
        'latitude' => NULL,
      ],
    ],
    'smart_ip_longitude_dms' => [
      'variables' => [
        'longitude' => NULL,
      ],
    ],
  ];
}

/**
 * Display latitude.
 */
function theme_smart_ip_latitude_dms($variable) {
  $output = '';
  list($degrees, $minutes, $seconds, $negative) = coordinates_dd_to_dms($variable['latitude']);
  $output .= "{$degrees}&deg; {$minutes}' {$seconds}\" ";
  if (!$negative) {
    $output .= 'N';
  }
  else {
    $output .= 'S';
  }
  return $output;
}

/**
 * Display longitude.
 */
function theme_smart_ip_longitude_dms($variable) {
  $output = '';
  list($degrees, $minutes, $seconds, $negative) = coordinates_dd_to_dms($variable['longitude']);
  $output .= "{$degrees}&deg; {$minutes}' {$seconds}\" ";
  if (!$negative) {
    $output .= 'E';
  }
  else {
    $output .= 'W';
  }
  return $output;
}

/**
 * Convert decimal degrees to degrees, minutes, seconds.
 */
function coordinates_dd_to_dms($coord) {
  $negative = $coord < 0 ? TRUE : FALSE;
  $coord = abs($coord);
  $degrees = floor($coord);
  $coord -= $degrees;
  $coord *= 60;
  $minutes = floor($coord);
  $coord -= $minutes;
  $coord *= 60;
  $seconds = round($coord, 6);
  return [
    $degrees,
    $minutes,
    $seconds,
    $negative,
  ];
}

/**
 * Helper function for grabbing region name (FIPS).
 */
function smart_ip_get_region_static($country_code, $region_code) {
  $region =& drupal_static(__FUNCTION__);
  if (!isset($region[$country_code][$region_code])) {
    module_load_include('inc', 'smart_ip', 'includes/smart_ip.region_lookup');
    $region[$country_code][$region_code] = smart_ip_get_region($country_code, $region_code);
  }
  return $region;
}

/**
 * Helper function for checking if EU member country and if country follows
 * GDPR.
 *
 * @see https://gist.github.com/henrik/1688572
 * @see https://europa.eu/european-union/about-eu/countries/member-countries_en
 */
function smart_ip_is_eu_gdpr_country($country_code, $eu_member_only = TRUE) {
  $eu_gdpr_country =& drupal_static(__FUNCTION__);
  if (!isset($eu_gdpr_country[$country_code][$eu_member_only])) {
    $eu_member_list = [
      'AT' => 'Austria',
      'BE' => 'Belgium',
      'BG' => 'Bulgaria',
      'HR' => 'Croatia',
      'CY' => 'Cyprus',
      'CZ' => 'Czech Republic',
      'DK' => 'Denmark',
      'EE' => 'Estonia',
      'FI' => 'Finland',
      'FR' => 'France',
      'DE' => 'Germany',
      'GR' => 'Greece',
      'HU' => 'Hungary',
      'IE' => 'Ireland, Republic of (EIRE)',
      'IT' => 'Italy',
      'LV' => 'Latvia',
      'LT' => 'Lithuania',
      'LU' => 'Luxembourg',
      'MT' => 'Malta',
      'NL' => 'Netherlands',
      'PL' => 'Poland',
      'PT' => 'Portugal',
      'RO' => 'Romania',
      'SK' => 'Slovakia',
      'SI' => 'Slovenia',
      'ES' => 'Spain',
      'SE' => 'Sweden',
    ];
    $additional_gdpr_list = [
      'GF' => 'French Guiana',
      'GP' => 'Guadeloupe',
      'MQ' => 'Martinique',
      'ME' => 'Montenegro',
      'YT' => 'Mayotte',
      'RE' => 'Réunion',
      'MF' => 'Saint Martin',
      'GI' => 'Gibraltar',
      'AX' => 'Åland Islands',
      'PM' => 'Saint Pierre and Miquelon',
      'GL' => 'Greenland',
      'BL' => 'Saint Bartelemey',
      'SX' => 'Sint Maarten',
      'AW' => 'Aruba',
      'CW' => 'Curacao',
      'WF' => 'Wallis and Futuna',
      'PF' => 'French Polynesia',
      'NC' => 'New Caledonia',
      'TF' => 'French Southern Territories',
      'AI' => 'Anguilla',
      'BM' => 'Bermuda',
      'IO' => 'British Indian Ocean Territory',
      'VG' => 'Virgin Islands, British',
      'KY' => 'Cayman Islands',
      'FK' => 'Falkland Islands (Malvinas)',
      'MS' => 'Montserrat',
      'PN' => 'Pitcairn',
      'SH' => 'Saint Helena',
      'GS' => 'South Georgia and the South Sandwich Islands',
      'TC' => 'Turks and Caicos Islands',
      'AD' => 'Andorra',
      'LI' => 'Liechtenstein',
      'MC' => 'Monaco',
      'SM' => 'San Marino',
      'VA' => 'Vatican City',
      'JE' => 'Jersey',
      'GG' => 'Guernsey',
      'GI' => 'Gibraltar',
    ];
    $eu_gdpr_country[$country_code][$eu_member_only] = isset($eu_member_list[$country_code]) ? $eu_member_list[$country_code] : NULL;
    if (!$eu_member_only && empty($eu_gdpr_country[$country_code][$eu_member_only])) {

      // The country is not EU member now check if the country follows GDPR.
      $eu_gdpr_country[$country_code][$eu_member_only] = isset($additional_gdpr_list[$country_code]) ? $additional_gdpr_list[$country_code] : NULL;
    }
  }
  return $eu_gdpr_country[$country_code][$eu_member_only];
}

Functions

Namesort descending Description
coordinates_dd_to_dms Convert decimal degrees to degrees, minutes, seconds.
smart_ip_cron Implements hook_cron().
smart_ip_entity_insert Implements hook_entity_insert().
smart_ip_get_region_static Helper function for grabbing region name (FIPS).
smart_ip_help Implements hook_help().
smart_ip_is_eu_gdpr_country Helper function for checking if EU member country and if country follows GDPR.
smart_ip_page_attachments Implements hook_page_attachments().
smart_ip_theme Implements hook_theme().
theme_smart_ip_latitude_dms Display latitude.
theme_smart_ip_longitude_dms Display longitude.