You are here

device_geolocation.module in Smart IP 7.2

Provides visitor's geographical location using client device location source that implements W3C Geolocation API and Google Geocoding service.

File

modules/device_geolocation/device_geolocation.module
View source
<?php

/**
 * @file
 * Provides visitor's geographical location using client device
 * location source that implements W3C Geolocation API and
 * Google Geocoding service.
 */

/**
 * Implements hook_init().
 */
function device_geolocation_init() {

  // Check to see if the page is one of those allowed for geolocation
  if (!smart_ip_check_allowed_page()) {

    // This page is not on the list to acquire/update user's geolocation
    return;
  }
  $ajax_check = variable_get('device_geolocation_ajax_check', FALSE);
  if ($ajax_check || device_geolocation_check_geolocation_attempt()) {
    device_geolocation_get_coordinates();
    if ($ajax_check) {

      // Add javascript app that checks if device geolocation needs refresh via ajax call
      drupal_add_js(array(
        'device_geolocation' => array(
          'ask_geolocate' => FALSE,
        ),
      ), 'setting');
      drupal_add_js(drupal_get_path('module', 'device_geolocation') . '/js/device_geolocation_check.js', array(
        'scope' => 'footer',
        'weight' => 0,
      ));
    }
    else {
      drupal_add_js(array(
        'device_geolocation' => array(
          'ask_geolocate' => TRUE,
        ),
      ), 'setting');
    }
    $param = '';
    $google_map_api = variable_get('device_geolocation_google_map_api', NULL);
    $google_region = variable_get('device_geolocation_google_map_region', NULL);
    $google_map_language = variable_get('device_geolocation_google_map_language', NULL);
    if ($google_map_api) {
      $param .= "key={$google_map_api}";
    }
    if ($google_region) {
      $param .= "&region={$google_region}";
    }
    if ($google_map_language) {
      $param .= "&language={$google_map_language}";
    }
    drupal_add_js("//maps.googleapis.com/maps/api/js?{$param}", 'external');
    drupal_add_js(drupal_get_path('module', 'device_geolocation') . '/js/device_geolocation.js', array(
      'scope' => 'footer',
      'weight' => 1,
    ));
  }
}

/**
 * Implements hook_user_presave().
 */
function device_geolocation_presave(&$edit, $account, $category) {

  // Reset the timer for frequency of user's geolocation checking
  smart_ip_session_set('device_geolocation_attempt', NULL);
}

/**
 * Implements hook_user_login().
 */
function device_geolocation_user_login(&$edit, $account) {

  // Reset the timer for frequency of user's geolocation checking
  smart_ip_session_set('device_geolocation_attempt', NULL);
}

/**
 * Implements hook_block_info().
 */
function device_geolocation_block_info() {
  $blocks['visitor_geolocation'] = array(
    'info' => t("Visitor's geolocation"),
  );
  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function device_geolocation_block_view($delta = '') {
  $block = array();
  switch ($delta) {
    case 'visitor_geolocation':
      $block['subject'] = t('Your Geolocation Details');
      $block['content'] = device_geolocation_contents();
      break;
  }
  return $block;
}

/**
 * Device geolocation block content function.
 */
function device_geolocation_contents() {
  $location = array();
  $smart_ip_session = smart_ip_session_get('smart_ip');

  // Smart IP user $_SESSION
  if (!is_null($smart_ip_session)) {
    $location = $smart_ip_session['location'];
  }
  else {
    global $user;
    if (isset($user->data['geoip_location'])) {
      $smart_ip_session['location'] = $user->data['geoip_location'];
      smart_ip_session_set('smart_ip', $smart_ip_session);
      $location = $smart_ip_session['location'];
    }
  }
  return theme('device_geolocation_visitor_info', array(
    'location' => $location,
  ));
}

/**
 * Implements hook_theme()
 */
function device_geolocation_theme() {
  return array(
    'device_geolocation_visitor_info' => array(
      'render element' => 'location',
      'template' => 'device-geolocation-visitor-info',
      'path' => drupal_get_path('module', 'device_geolocation') . '/theme',
    ),
  );
}

/**
 * Implements hook_help().
 */
function device_geolocation_help($path, $arg) {
  switch ($path) {
    case 'admin/help#device_geolocation':
      return '<p>' . t("Provides visitor's geographical location using client device location source \n      that implements W3C Geolocation API whereas the coordinates are geocoded using \n      Google Geocoding service. Google Geocoding returns a more detailed location information \n      such as: street number, postal code, route, neighborhood, locality, sublocality, \n      establishment, administrative area level 1, administrative area level 2, etc.") . '</p><p>' . t("Smart IP is the last fallback if W3C Geolocation API failed. Even if the visitors \n      refuses to share their location, the geographical information provided by Smart IP \n      will be used to know your visitors' geolocation details. A themeable Block content \n      is available to show your visitor's geolocation information. Device Geolocation merges \n      its location data (collected at Google Geocoding service) with Smart IP visitor's \n      location data storage which is in session variable (@session) with array key 'smart_ip' \n      and Drupal @user->data object with array key 'geoip_location'.", array(
        '@session' => '$_SESSION',
        '@user' => '$user',
      )) . '</p>';
      break;
  }
}

/**
 * Implements hook_form_alter()
 */
function device_geolocation_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'smart_ip_admin_settings') {

    // Container for Device Geolocation preference forms
    $form['device_geolocation_preferences'] = array(
      '#type' => 'fieldset',
      '#title' => t('Device Geolocation settings'),
      '#collapsible' => FALSE,
      '#collapsed' => FALSE,
      '#weight' => 4,
    );
    $form['device_geolocation_preferences']['device_geolocation_ajax_check'] = array(
      '#type' => 'checkbox',
      '#title' => t("Use AJAX in user's geolocation checking (useful if the site or pages listed above are cached)"),
      '#default_value' => variable_get('device_geolocation_ajax_check', FALSE),
    );
    $device_geolocation_check_frequency = variable_get('device_geolocation_check_frequency', NULL);
    $form['device_geolocation_preferences']['device_geolocation_check_frequency'] = array(
      '#title' => t("Frequency of user's geolocation checking"),
      '#type' => 'textfield',
      '#size' => 10,
      '#description' => t('Specify number of hours will prompt the user for geolocation. Leave it empty to disable.'),
      '#default_value' => $device_geolocation_check_frequency === NULL ? '' : $device_geolocation_check_frequency / 3600,
      '#field_suffix' => t('hours'),
    );
    $form['device_geolocation_preferences']['device_geolocation_google_map_api'] = array(
      '#title' => t('Google map API key'),
      '#type' => 'textfield',
      '#description' => t('The use of Google map service requires API key. Get your API key !here.', array(
        '!here' => l(t('here'), 'https://developers.google.com/maps/documentation/javascript/get-api-key'),
      )),
      '#default_value' => variable_get('device_geolocation_google_map_api', NULL),
    );
    $form['device_geolocation_preferences']['device_geolocation_google_map_region'] = array(
      '#type' => 'textfield',
      '#title' => t('Google map region'),
      '#default_value' => variable_get('device_geolocation_google_map_region', NULL),
      '#description' => t("Specify a region code, which alters the Google map service's behavior based on a given country or territory. See !google_localization_region", array(
        '!google_localization_region' => l(t('Google Maps API - Localizing the Map (Region localization)'), 'https://developers.google.com/maps/documentation/javascript/localization#Region'),
      )),
    );
    $form['device_geolocation_preferences']['device_geolocation_google_map_language'] = array(
      '#type' => 'textfield',
      '#title' => t('Google map language'),
      '#default_value' => variable_get('device_geolocation_google_map_language', NULL),
      '#description' => t('Change the Google map service default language settings. See !google_localization_language', array(
        '!google_localization_language' => l(t('Google Maps API - Localizing the Map (Language localization)'), 'https://developers.google.com/maps/documentation/javascript/localization#Language'),
      )),
    );
    $form['#validate'][] = '_device_geolocation_check_frequency_validate';
  }
}

/**
 * Validation handler to update the "Geolocate on specific pages".
 */
function _device_geolocation_check_frequency_validate($form, &$form_state) {
  $value = $form_state['values']['device_geolocation_check_frequency'];
  if ($value == '') {
    $form_state['values']['device_geolocation_check_frequency'] = NULL;
  }
  elseif (!is_numeric($value) || $value < 0) {
    form_set_error('device_geolocation_check_frequency', t("Frequency of user's geolocation checking must be a positive number."));
  }
  else {

    // Convert from hours to seconds
    $form_state['values']['device_geolocation_check_frequency'] = $value * 3600;
  }
}

/**
 * Implements hook_menu().
 */
function device_geolocation_menu() {
  $items['geolocate-user'] = array(
    'page callback' => 'device_geolocation_detector_ajax',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['check-geolocation-attempt'] = array(
    'page callback' => 'device_geolocation_check_geolocation_attempt_ajax',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Google Geocoding ajax callback function data recipient.
 */
function device_geolocation_detector_ajax() {
  if (isset($_POST['latitude']) && isset($_POST['longitude'])) {
    global $user;
    $smart_ip_session = smart_ip_session_get('smart_ip');
    $ip_address = $smart_ip_session['location']['ip_address'];
    $smart_ip_session['maxmind_location'] = $smart_ip_session['location'];
    smart_ip_session_set('device_geolocation', NULL);
    unset($smart_ip_session['location']);
    $smart_ip_session['location']['ip_address'] = $ip_address;
    $smart_ip_session['location']['country'] = '';
    $smart_ip_session['location']['country_code'] = '';
    $smart_ip_session['location']['region'] = '';
    $smart_ip_session['location']['region_code'] = '';
    $smart_ip_session['location']['city'] = '';
    $smart_ip_session['location']['zip'] = '';
    $smart_ip_session['location']['latitude'] = '';
    $smart_ip_session['location']['longitude'] = '';
    $smart_ip_session['location']['time_zone'] = '';
    $smart_ip_session['location']['is_eu_country'] = '';
    $smart_ip_session['location']['is_gdpr_country'] = '';
    foreach ($_POST as $label => $address) {
      if (!empty($address) && is_string($address) && is_string($label)) {
        $label = check_plain($label);
        if (!is_array($address)) {
          $smart_ip_session['location'][$label] = check_plain($address);
        }
        else {
          $smart_ip_session['location'][$label] = $address;
        }
        smart_ip_session_set('device_geolocation', TRUE);
      }
    }
    $smart_ip_session['location']['timestamp'] = REQUEST_TIME;

    // Allow other modules to modify result via hook_device_geolocation_detector_ajax_alter()
    drupal_alter('device_geolocation_detector_ajax', $smart_ip_session['location']);
    if (isset($smart_ip_session['location']) && $user->uid) {
      $user_obj = user_load($user->uid);
      user_save($user_obj, array(
        'data' => array(
          'geoip_location' => $smart_ip_session['location'],
        ),
      ));
    }
    smart_ip_session_set('smart_ip', $smart_ip_session);
  }
}

/**
 * Get Visitor's coordinates.
 */
function device_geolocation_get_coordinates() {
  global $user;
  $latitude = 0;
  $longitude = 0;
  $smart_ip_session = smart_ip_session_get('smart_ip');
  $is_allowed_page = smart_ip_check_allowed_page();

  // Smart IP user $_SESSION
  if (!is_null($smart_ip_session) && !empty($smart_ip_session['location']['latitude'])) {
    $latitude = $smart_ip_session['location']['latitude'];
    $longitude = $smart_ip_session['location']['longitude'];
  }
  elseif (isset($user->data['geoip_location']) && !empty($user->data['geoip_location']['latitude'])) {
    $smart_ip_session['location'] = $user->data['geoip_location'];
    $latitude = $smart_ip_session['location']['latitude'];
    $longitude = $smart_ip_session['location']['longitude'];
    if ($is_allowed_page) {
      smart_ip_session_set('smart_ip', $smart_ip_session);
    }
  }
  else {
    $smart_ip_session['location'] = smart_ip_get_current_visitor_location_data();
    if ($is_allowed_page) {
      smart_ip_session_set('smart_ip', $smart_ip_session);
    }
    if ($user->uid) {
      $user_obj = user_load($user->uid);
      user_save($user_obj, array(
        'data' => array(
          'geoip_location' => $smart_ip_session['location'],
        ),
      ));
    }
    if (!empty($smart_ip_session['location']['latitude'])) {
      $latitude = $smart_ip_session['location']['latitude'];
      $longitude = $smart_ip_session['location']['longitude'];
    }
    elseif ($is_allowed_page) {
      smart_ip_session_set('smart_ip', NULL);
    }
  }
  $debug_mode = is_user_debug_mode();

  //$debug_mode = FALSE;
  $coordinates = array(
    'latitude' => $latitude,
    'longitude' => $longitude,
    'debug_mode' => $debug_mode,
  );

  // Send also to javascript
  drupal_add_js(array(
    'device_geolocation' => $coordinates,
  ), 'setting');
  return $coordinates;
}

/**
 * Check for Geolocation attempt ajax callback.
 */
function device_geolocation_check_geolocation_attempt_ajax() {
  if (smart_ip_check_allowed_page() && device_geolocation_check_geolocation_attempt()) {
    drupal_json_output(array(
      'ask_geolocate' => TRUE,
    ));
    return;
  }
  drupal_json_output(array(
    'ask_geolocate' => FALSE,
  ));
}

/**
 * Check for Geolocation attempt.
 */
function device_geolocation_check_geolocation_attempt() {
  $device_geolocation_check_frequency = variable_get('device_geolocation_check_frequency', NULL);
  $timestamp = smart_ip_session_get('device_geolocation_attempt');
  if ($device_geolocation_check_frequency === NULL) {

    // User's device geolocation checking is set disabled
    return FALSE;
  }
  elseif (is_null(smart_ip_session_get('device_geolocation')) && empty($timestamp)) {

    // The user has not allowed to share his/her location yet then return that user's location needs
    // update and start the timer.
    smart_ip_session_set('device_geolocation_attempt', REQUEST_TIME);
    return TRUE;
  }
  elseif (!empty($timestamp) && $device_geolocation_check_frequency < REQUEST_TIME - $timestamp) {

    // Return that user's location needs update and reset the timer.
    smart_ip_session_set('device_geolocation_attempt', REQUEST_TIME);
    return TRUE;
  }
  return FALSE;
}

Functions

Namesort descending Description
device_geolocation_block_info Implements hook_block_info().
device_geolocation_block_view Implements hook_block_view().
device_geolocation_check_geolocation_attempt Check for Geolocation attempt.
device_geolocation_check_geolocation_attempt_ajax Check for Geolocation attempt ajax callback.
device_geolocation_contents Device geolocation block content function.
device_geolocation_detector_ajax Google Geocoding ajax callback function data recipient.
device_geolocation_form_alter Implements hook_form_alter()
device_geolocation_get_coordinates Get Visitor's coordinates.
device_geolocation_help Implements hook_help().
device_geolocation_init Implements hook_init().
device_geolocation_menu Implements hook_menu().
device_geolocation_presave Implements hook_user_presave().
device_geolocation_theme Implements hook_theme()
device_geolocation_user_login Implements hook_user_login().
_device_geolocation_check_frequency_validate Validation handler to update the "Geolocate on specific pages".