diff --git a/geocoder.admin.inc b/geocoder.admin.inc
index c4ca49b..734e4e7 100644
--- a/geocoder.admin.inc
+++ b/geocoder.admin.inc
@@ -34,6 +34,67 @@ function geocoder_admin_settings($form, &$form_state) {
'#required' => FALSE,
);
+ $form['geocoder_google_auth_method'] = array(
+ '#type' => 'select',
+ '#title' => t('Google API Authorization Method'),
+ '#description' => t("If your website runs on shared hosting, you'll want to authenticate requests to the Google Geocoding API to reduce the likelihood of being rate limited (2500 requests per day / 5 requests per second). Alternatively, Google Maps for Work customers may use their Client ID and Signing Key to authenticate."),
+ '#default_value' => variable_get('geocoder_google_auth_method', GEOCODER_GOOGLE_AUTH_NONE),
+ '#options' => array(
+ GEOCODER_GOOGLE_AUTH_NONE => 'None',
+ GEOCODER_GOOGLE_AUTH_KEY => 'API Key (free)',
+ GEOCODER_GOOGLE_AUTH_WORK => 'Google Maps API for Work',
+ ),
+ );
+
+ $form['geocoder_apikey_google'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Google Maps API Key'),
+ '#description' => t('Obtain a free Google Geocoding API Key at @link', array(
+ '@link' => 'https://developers.google.com/maps/documentation/geocoding/#api_key',
+ )),
+ '#default_value' => empty($geocoder_settings['geocoder_apikey_google']) ? '' : $geocoder_settings['geocoder_apikey_google'],
+ '#required' => FALSE,
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="geocoder_google_auth_method"]' => array('value' => GEOCODER_GOOGLE_AUTH_KEY),
+ ),
+ ),
+ );
+
+ $form['geocoder_google_client_id'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Google Maps API for Work: Client ID'),
+ '#description' => t('For more information, visit @link', array(
+ '@link' => 'https://developers.google.com/maps/documentation/business/webservices/auth#business-specific_parameters',
+ )),
+ '#default_value' => variable_get('geocoder_google_client_id'),
+ '#required' => FALSE,
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="geocoder_google_auth_method"]' => array(
+ 'value' => GEOCODER_GOOGLE_AUTH_WORK,
+ ),
+ ),
+ ),
+ );
+
+ $form['geocoder_google_private_key'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Google Maps API for Work: Private/Signing Key'),
+ '#description' => t('For more information, visit @link', array(
+ '@link' => 'https://developers.google.com/maps/documentation/business/webservices/auth#how_do_i_get_my_signing_key',
+ )),
+ '#default_value' => variable_get('geocoder_google_private_key'),
+ '#required' => FALSE,
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="geocoder_google_auth_method"]' => array(
+ 'value' => GEOCODER_GOOGLE_AUTH_WORK,
+ ),
+ ),
+ ),
+ );
+
$form['geocoder_google_delay'] = array(
'#type' => 'textfield',
'#title' => t('Delay between Google geocoding requests (in milliseconds)'),
@@ -57,5 +118,6 @@ function geocoder_admin_settings_submit($form, &$form_state) {
$geocoder_settings['geocoder_apikey_yahoo'] = trim($form_state['values']['geocoder_apikey_yahoo']);
$geocoder_settings['geocoder_apikey_yandex'] = trim($form_state['values']['geocoder_apikey_yandex']);
$geocoder_settings['geocoder_apikey_bing'] = trim($form_state['values']['geocoder_apikey_bing']);
+ $geocoder_settings['geocoder_apikey_google'] = trim($form_state['values']['geocoder_apikey_google']);
variable_set("geocoder_settings", $geocoder_settings);
}
diff --git a/geocoder.module b/geocoder.module
index 6d6a0c2..0f225bd 100644
--- a/geocoder.module
+++ b/geocoder.module
@@ -8,6 +8,10 @@
include_once('geocoder.widget.inc');
include_once('geocoder.services.inc');
+define('GEOCODER_GOOGLE_AUTH_NONE', 1);
+define('GEOCODER_GOOGLE_AUTH_KEY', 2);
+define('GEOCODER_GOOGLE_AUTH_WORK', 3);
+
/**
* The Geocoder API call.
*
diff --git a/plugins/geocoder_handler/google.inc b/plugins/geocoder_handler/google.inc
index ee7a6e1..5305934 100644
--- a/plugins/geocoder_handler/google.inc
+++ b/plugins/geocoder_handler/google.inc
@@ -52,7 +52,54 @@ function geocoder_google($address, $options = array()) {
$query['components'] = $options['biasing']['components'];
}
- $url = url("http://maps.googleapis.com/maps/api/geocode/json", array('query' => $query));
+ // Add Google API authentication parameters.
+ switch (variable_get('geocoder_google_auth_method')) {
+
+ // Google Geocoding API Key.
+ case GEOCODER_GOOGLE_AUTH_KEY:
+ $geocoder_settings = variable_get("geocoder_settings", array());
+ if (!empty($geocoder_settings['geocoder_apikey_google'])) {
+ $query['key'] = $geocoder_settings['geocoder_apikey_google'];
+ }
+ break;
+
+ // Google Maps for Work signature.
+ case GEOCODER_GOOGLE_AUTH_WORK:
+ $client_id = variable_get('geocoder_google_client_id', FALSE);
+ $private_key = variable_get('geocoder_google_private_key', FALSE);
+ if (!empty($client_id) && !empty($private_key)) {
+ $google_maps_for_work = TRUE;
+ $query['client'] = $client_id;
+ }
+ break;
+ }
+
+ // Build the URL.
+ $url = url("https://maps.googleapis.com/maps/api/geocode/json", array(
+ 'query' => $query,
+ ));
+
+ // If authenticating via Google Maps for Work, add signature.
+ // @see https://developers.google.com/maps/documentation/business/webservices/auth#generating_valid_signatures
+ if (!empty($google_maps_for_work)) {
+
+ // Strip off the protocol and host for signing.
+ $parsed = parse_url($url);
+ $url_to_sign = $parsed['path'] . '?' . $parsed['query'];
+
+ // Decode the key in a URL-safe way (RFC 4648 Section 5).
+ // @see https://www.ietf.org/rfc/rfc4648.txt
+ $decoded_key = base64_decode(strtr($private_key, '-_', '+/'));
+
+ // Use HMAC SHA1 to sign the URL with the decoded key.
+ $signature = hash_hmac('sha1', $url_to_sign, $decoded_key, TRUE);
+
+ // Append the signature to the URL's query parameters. Do this manually to
+ // avoid URL encoding.
+ $url .= '&signature=' . strtr(base64_encode($signature), '+/', '-_');
+ }
+
+ // Send the request.
$result = drupal_http_request($url);
$delay_trigger = TRUE;