the street portion of the location * 'supplemental' => additional street portion of the location * 'province' => the province, state, or territory * 'country' => lower-cased two-letter ISO code (REQUIRED) * 'postal_code' => the international postal code for this location (REQUIRED) * * @return array * An associative array where * 'lat' => approximate latitude of the center of the postal code's area * 'lon' => approximate longitude of the center of the postal code's area */ function location_latlon_rough_us($location = array()) { if (!isset($location['postal_code'])) { return NULL; } $row = db_query( "SELECT latitude, longitude FROM {zipcodes} where country = :country AND zip = :zip", array( ':country' => $location['country'], ':zip' => substr(str_pad($location['postal_code'], 5, '0', STR_PAD_LEFT), 0, 5), ) )->fetchObject(); if ($row) { return array('lat' => $row->latitude, 'lon' => $row->longitude); } else { return NULL; } } /** * Returns a lat/lon pair of the approximate center of the given postal code in the given country. * * @param array $location * An associative array $location where only postal code and country are necessary, but can have the keys: * 'street' => the street portion of the location * 'supplemental' => additional street portion of the location * 'province' => the province, state, or territory * 'country' => lower-cased two-letter ISO code (REQUIRED) * 'postal_code' => the international postal code for this location (REQUIRED) * * @return array * An associative array where * 'lat' => approximate latitude of the center of the postal code's area * 'lon' => approximate longitude of the center of the postal code's area */ function location_get_postalcode_data_us($location = array()) { $dash_index = strpos($location['postal_code'], '-'); // First we strip slash off if we're dealing with a 9-digit US zipcode. if (!($dash_index === FALSE)) { $location['postal_code'] = substr($location['postal_code'], 0, $dash_index); } // Now we pad the thing and query. $row = db_query( "SELECT * FROM {zipcodes} where country = :country AND zip = :zip", array( ':country' => $location['country'], ':zip' => str_pad($location['postal_code'], 5, "0", STR_PAD_LEFT), ) )->fetchObject(); if ($row) { return array( 'lat' => $row->latitude, 'lon' => $row->longitude, 'city' => $row->city, 'province' => $row->state, 'country' => $row->country, ); } else { return NULL; } } /** * Exact us. * * @param array $location * An associative array $location where * 'street' => the street portion of the location * 'supplemental' => additional street portion of the location * 'province' => the province, state, or territory * 'country' => lower-cased two-letter ISO code (REQUIRED) * 'postal_code' => the international postal code for this location (REQUIRED) * * @return NULL * Deprecated. */ function location_latlon_exact_us($location = array()) { return NULL; // By uncommenting the line of code below, you legally acknowledge that you understand that you can only // do so under the terms of the Non-Commercial Share-alike license described at http://creativecommons.org/licenses/by-nc-sa/2.0/ // return _location_latlon_exact_us_geocoder($location); } /** * Calls up a web-service to retrieve a lat/lon pair for a full, correct U.S. location. * * @param array $location * An associative array that represents an location where * 'street' => is the street location * 'supplemental' => any supplemental portion to the street location * 'city' => city name * 'province' => state, province, or territorial abbreviation * 'postal_code' => postal code * * @return array * An associative array where * 'lat' => Is a float value in latitude * 'lon' => Is a float value in longitude * If the location supplied does not provide enough information, NULL is returned. * "Enough information" means that there is either * (a valid 'street' AND valid 'postal_code') OR (valid 'street' AND valid 'city' AND valid 'province') */ function _location_latlon_exact_us_geocoder($location = array()) { $location_string = ''; if (isset($location['street']) && trim($location['street']) != '') { if (isset($location['postal_code'])) { $location_string = $location['street'] . ' ' . $location['postal_code']; } elseif (isset($location['city']) && isset($location['province']) && trim($location['city']) != '' && trim( $location['province'] ) ) { $location_string = $location['street'] . ', ' . $location['city'] . ', ' . $location['province']; } else { // Else geocoder.us won't do bidness with you. return NULL; } } else { return NULL; } $result = xmlrpc('http://rpc.geocoder.us/service/xmlrpc', array('geocode' => array($location_string))); if (is_array($result) && is_array($result[0]) && isset($result[0]['lat']) && is_numeric( $result[0]['lat'] ) && isset($result[0]['long']) && is_numeric($result[0]['long']) ) { return array('lat' => $result[0]['lat'], 'lon' => $result[0]['long']); } return NULL; } /** * Yahoo link. */ function location_map_link_us_yahoo($location = array()) { $get_query = '?'; if (isset($location['street'])) { $get_query .= 'addr=' . urlencode($location['street']) . '&'; } if ($location['province'] != '' || $location['city'] != '' || $location['postal_code'] != '') { $get_query .= 'csz=' . _location_us_yahoo_csz_get_field($location) . '&'; } $get_query .= 'country=' . urlencode($location['country']); return ('http://maps.yahoo.com/maps_result' . $get_query); } /** * Google link. */ function location_map_link_us_google($location = array()) { $query_params = array(); $q = NULL; foreach (array('street', 'city', 'province', 'postal_code', 'country') as $field) { if (isset($location[$field])) { $query_params[] = $location[$field]; } } if (location_has_coordinates($location)) { $q = urlencode($location['latitude'] . ' ' . $location['longitude'] . ' (' . implode(', ', $query_params) . ')'); } else { if (count($query_params) > 0) { $q = urlencode(implode(", ", $query_params)); } } if ($q != NULL) { return ('http://maps.google.com?q=' . $q); } else { return NULL; } } /** * MapQuest link. */ function location_map_link_us_mapquest($location = array()) { $get_query = ''; if (isset($location['street'])) { $get_query .= 'address=' . urlencode($location['street']) . '&'; } if (isset($location['city'])) { $get_query .= 'city=' . urlencode($location['city']) . '&'; } if (isset($location['province'])) { $get_query .= 'state=' . urlencode($location['province']) . '&'; } if (isset($location['postal_code'])) { $get_query .= 'zipcode=' . urlencode($location['postal_code']); } if (strlen($get_query)) { return 'http://www.mapquest.com/maps/map.adp?searchtype=address&country=US&' . $get_query; } else { return NULL; } } /** * Providers for a links. * * @return array * An array where * -> the key is the word that helps identify the name of function that builds the link. For example, a key of 'yahoo' means the name of the * the function that builds a link to a map on Yahoo! Maps would be 'location_map_link_us_yahoo' * -> the value is itself an array with 3 key/value pairs: * 'name' => points to the name of the mapping service. For 'yahoo', this would be 'Yahoo! Maps' * 'url' => the url of the main page of the mapping service. For 'yahoo', this would be 'http://maps.yahoo.com' * 'tos' => the url of the page that explains the map providers Terms of Service, or Terms of Use. For 'yahoo', this would be * 'http://help.yahoo.com/help/us/maps/maps-24.html' */ function location_map_link_us_providers() { return array( 'google' => array( 'name' => t('Google Maps'), 'url' => 'http://maps.google.com', 'tos' => 'http://www.google.com/help/terms_local.html', ), 'yahoo' => array( 'name' => 'Yahoo! Maps', 'url' => 'http://maps.yahoo.com', 'tos' => 'http://help.yahoo.com/help/us/maps/maps-24.html', ), 'mapquest' => array( 'name' => 'MapQuest', 'url' => 'http://www.mapquest.com', 'tos' => 'http://www.mapquest.com/features/main.adp?page=legal', ), ); } /** * Default providers. * * @return array * An array of values that work as keys to the array returned by location_map_link_us_providers. The idea is that if the * administrator of the site has not yet had a chance to visit the "Map Links" subtab on the location module's settings page, * that we can provide deep-linking to a relatively safe default. By 'relatively safe', we mean that the Terms Of Service of * the provider of the maps are flexible enough for most parties. * * For the case of the U.S., 'google' has relatively flexible Terms Of Service, whereas Yahoo! Maps and MapQuest have more * restrictive Terms Of Service. */ function location_map_link_us_default_providers() { return array('google'); } /** * Geocode providers. */ function location_geocode_us_providers() { return array( 'yahoo' => array( 'name' => 'Yahoo! Maps Web Services', 'url' => 'http://developer.yahoo.com/maps/rest/V1/geocode.html', 'tos' => 'http://developer.yahoo.com/maps/mapsTerms.html', ), ); } /** * Yahoo settings. */ function location_geocode_us_yahoo_settings() { $form = array(); $form['location_geocode_us_yahoo_appid'] = array( '#type' => 'textfield', '#title' => t('Yahoo! Web Services Application ID'), '#size' => 64, '#maxlength' => 128, '#default_value' => variable_get('location_geocode_us_yahoo_appid', 'YahooDemo'), '#description' => t( 'Unless you are using this site to test and develop, you will need to obtain a Yahoo! Web Services Application ID from the %network_link. If you are using for development and testing purposes, you can use \'YahooDemo\' as your AppID. When getting an Application ID from Yahoo!, be sure to review the %usage_policy.', array( '%network_link' => 'Yahoo! Developer Network', '%usage_policy' => 'usage policy', ) ), ); return $form; } /** * Geocode by Yahoo. */ function location_geocode_us_yahoo($location = array()) { $service_url = "http://api.local.yahoo.com/MapsService/V1/geocode?appid=" . variable_get( 'location_geocode_us_yahoo_appid', "YahooDemo" ) . "&location="; $address = location_address2singleline($location); $http_reply = drupal_http_request($service_url . urlencode($address)); // Address may have been improperly formatted or invalid. if ($http_reply->code == 400) { return NULL; } else { // Got a successful reply, but we only want to return if we have address-level precision. $matches = array(); preg_match('/precision="([a-z]*)"/', $http_reply->data, $matches); if ($matches[1] != 'address') { // The precision we got back was not down to the street-address level. return NULL; } else { $lat_match = array(); $lon_match = array(); $latlon = array(); if (preg_match('/(.*)<\/Latitude>/', $http_reply->data, $lat_match)) { $latlon['lat'] = $lat_match[1]; } else { return NULL; } if (preg_match('/(.*)<\/Longitude>/', $http_reply->data, $lon_match)) { $latlon['lon'] = $lon_match[1]; return $latlon; } else { return NULL; } } } } /** * Returns link. * * For now, assume site-admin wants American driving directions linked to Yahoo! Driving Directions. * Maybe later, we can add some kind of country-specific settings page that allows the site-admin to * decide which site to link to for driving directions. * * @param array $location_a * is an associative array that represents a full location where * 'street' => the street portions of the location * 'supplemental' => additional street portion of the location * 'province' => the province, state, or territory * 'country' => lower-cased two-letter ISO code (REQUIRED) * * @param array $location_b * is associative array that represents a full location in the same way that * parameter $location_b does. * * @returns string * Link to driving directions. */ function location_driving_directions_link_us($location_a, $location_b) { return _location_driving_directions_link_us_yahoo($location_a, $location_b); } /** * Direction link by Yahoo. * * @param array $location_a * is an associative array that represents a full location where * 'street' => the street portions of the location * 'supplemental' => additional street portion of the location * 'province' => the province, state, or territory * 'country' => lower-cased two-letter ISO code (REQUIRED) * * @param array $location_b * is associative array that represents a full location in the same way that * parameter $location_b does. * * @return string * a URL with HTTP GET variables * Depending on how full the locationes are, the URL will either point to the driving directions * on Yahoo! or, if only partial locationes are provided, a URL that points to the *form* for * Yahoo! driving directions where the form is filled with whatever fields have been provided * for the partial location(es). */ function _location_driving_directions_link_us_yahoo($location_a, $location_b) { if (trim($location_b['country']) != 'ca' && trim($location_b['country']) != 'us') { return ''; } // These are the fields that need to be in each location if we are to provide a direct // link to yahoo directions. If all of these fields don't have values, then we generate // a link to the *form* for Yahoo! driving directions rather than directly to the driving // directions themselves. foreach ($location_a as $field => $value) { $location_a[$field] = trim($value); } foreach ($location_b as $field => $value) { $location_b[$field] = trim($value); } if (_location_us_enough_fields_for_yahoo($location_a) && _location_us_enough_fields_for_yahoo($location_b)) { $yahoo_maps_path = 'dd_result'; } else { $yahoo_maps_path = 'dd'; } $get_query = '?'; $get_query .= 'addr=' . urlencode($location_a['street']) . '&'; $get_query .= 'csz=' . _location_us_yahoo_csz_get_field($location_a) . '&'; $get_query .= 'country=' . urlencode($location_a['country']) . '&'; $get_query .= 'taddr=' . urlencode($location_b['street']) . '&'; $get_query .= 'tcsz=' . _location_us_yahoo_csz_get_field($location_b) . '&'; $get_query .= 'tcountry=' . urlencode($location_b['country']); $get_query .= '&getrte=' . urlencode('Get Directions'); return ('http://maps.yahoo.com/' . $yahoo_maps_path . $get_query); } /** * Fields fot Yahoo. */ function _location_us_enough_fields_for_yahoo($location) { // These are the fields that need to be in each location if we are to provide a direct // link to yahoo directions. If all of these fields don't have values, then we generate // a link to the *form* for Yahoo! driving directions rather than directly to the driving // directions themselves. if (strlen($location['street']) && strlen($location['city']) && strlen($location['province'])) { return TRUE; } if (strlen($location['street']) && strlen($location['postal_code'])) { return TRUE; } if (strlen($location['street']) && strlen($location['city']) && strlen($location['province'])) { return TRUE; } return FALSE; } /** * Yahoo get fields. * * Don't mess with this function unless you understand its logic. It has to do with * the question of "to comma or not to comma?" */ function _location_us_yahoo_csz_get_field($location) { // For some reasons, to the end of pinpointing a location, Yahoo! Maps and Driving Directions // do better a better job with retrieving info based strictly on a Canadian city/province // than on a Canadian postal code. if ($location['country'] = 'ca') { if (strlen($location['city']) && strlen($location['province'])) { return urlencode($location['city'] . ', ' . $location['province']); } if (strlen($location['postal_code'])) { return urlencode($location['postal_code']); } } else { if (strlen($location['postal_code'])) { return urlencode($location['postal_code']); } if (strlen($location['city']) && strlen($location['province'])) { return urlencode($location['city'] . ', ' . $location['province']); } } if (strlen($location['city']) || strlen($location['province'])) { if (strlen($location['city'])) { return urlencode($location['city']); } else { return urlencode($location['province']); } } return ''; } /** * Geocoder oneline. */ function _location_us_geocoder_oneline($location = array()) { $line = ''; $line .= $location['street'] . ', '; if (strlen($location['city']) && strlen($location['province']) && strlen($location['postal_code'])) { $line .= $location['city'] . ', ' . $location['province'] . ' ' . $location['postal_code']; } elseif (strlen($location['city']) && strlen($location['province'])) { $line .= $location['city'] . ', ' . $location['province']; } elseif (strlen($location['postal_code'])) { if (strlen($location['city']) || strlen($location['province'])) { if (strlen($location['city'])) { $line .= $location['city'] . ', ' . $location['postal_code']; } else { $line .= $location['province'] . ', ' . $location['postal_code']; } } else { $line .= $location['postal_code']; } } return $line; } /** * Location provinces. * * @return array * An associative array of states/territories where * -> the keys are integers starting from 1 * -> the values are the English names for those states/territories * * The states are grouped together at the beginning of the array and sorted * alphabetically. * * The territories are grouped together at the end of the array and sorted * alphabetically. */ function location_province_list_us() { return array( 'AL' => t('Alabama'), 'AK' => t('Alaska'), 'AZ' => t('Arizona'), 'AR' => t('Arkansas'), 'CA' => t('California'), 'CO' => t('Colorado'), 'CT' => t('Connecticut'), 'DE' => t('Delaware'), 'DC' => t('District Of Columbia'), 'FL' => t('Florida'), 'GA' => t('Georgia'), 'HI' => t('Hawaii'), 'ID' => t('Idaho'), 'IL' => t('Illinois'), 'IN' => t('Indiana'), 'IA' => t('Iowa'), 'KS' => t('Kansas'), 'KY' => t('Kentucky'), 'LA' => t('Louisiana'), 'ME' => t('Maine'), 'MD' => t('Maryland'), 'MA' => t('Massachusetts'), 'MI' => t('Michigan'), 'MN' => t('Minnesota'), 'MS' => t('Mississippi'), 'MO' => t('Missouri'), 'MT' => t('Montana'), 'NE' => t('Nebraska'), 'NV' => t('Nevada'), 'NH' => t('New Hampshire'), 'NJ' => t('New Jersey'), 'NM' => t('New Mexico'), 'NY' => t('New York'), 'NC' => t('North Carolina'), 'ND' => t('North Dakota'), 'OH' => t('Ohio'), 'OK' => t('Oklahoma'), 'OR' => t('Oregon'), 'PA' => t('Pennsylvania'), 'RI' => t('Rhode Island'), 'SC' => t('South Carolina'), 'SD' => t('South Dakota'), 'TN' => t('Tennessee'), 'TX' => t('Texas'), 'UT' => t('Utah'), 'VT' => t('Vermont'), 'VA' => t('Virginia'), 'WA' => t('Washington'), 'WV' => t('West Virginia'), 'WI' => t('Wisconsin'), 'WY' => t('Wyoming'), 'AS' => t('American Samoa'), 'FM' => t('Federated States of Micronesia'), 'GU' => t('Guam'), 'MH' => t('Marshall Islands'), 'MP' => t('Northern Mariana Islands'), 'PW' => t('Palau'), 'PR' => t('Puerto Rico'), 'VI' => t('Virgin Islands'), 'AA' => t('Armed Forces Americas'), 'AE' => t('Armed Forces Europe'), 'AP' => t('Armed Forces Pacific'), ); } /** * Location provinces keyed by numeric. * * @return array * An associative array of states/territories where * -> the keys are integers starting from 1 * -> the values are the English names for those states/territories * * The states are grouped together at the beginning of the array and sorted * alphabetically. * * The territories are grouped together at the end of the array and sorted * alphabetically. * * Currently not being used, but may be in order to be compatible with CiviCRM * TODO: These numeric indices need to be changed to match those in the CiviCRM database */ function location_province_list_numeric_us() { return array( '001' => t('Alabama'), '002' => t('Alaska'), '003' => t('Arizona'), '004' => t('Arkansas'), '005' => t('California'), '006' => t('Colorado'), '007' => t('Connecticut'), '008' => t('Delaware'), '009' => t('District Of Columbia'), '010' => t('Florida'), '011' => t('Georgia'), '012' => t('Hawaii'), '013' => t('Idaho'), '014' => t('Illinois'), '015' => t('Indiana'), '016' => t('Iowa'), '017' => t('Kansas'), '018' => t('Kentucky'), '019' => t('Louisiana'), '020' => t('Maine'), '021' => t('Maryland'), '022' => t('Massachusetts'), '023' => t('Michigan'), '024' => t('Minnesota'), '025' => t('Mississippi'), '026' => t('Missouri'), '027' => t('Montana'), '028' => t('Nebraska'), '029' => t('Nevada'), '030' => t('New Hampshire'), '031' => t('New Jersey'), '032' => t('New Mexico'), '033' => t('New York'), '034' => t('North Carolina'), '035' => t('North Dakota'), '036' => t('Ohio'), '037' => t('Oklahoma'), '038' => t('Oregon'), '039' => t('Pennsylvania'), '040' => t('Rhode Island'), '041' => t('South Carolina'), '042' => t('South Dakota'), '043' => t('Tennessee'), '044' => t('Texas'), '045' => t('Utah'), '046' => t('Vermont'), '047' => t('Virginia'), '048' => t('Washington'), '049' => t('West Virginia'), '050' => t('Wisconsin'), '051' => t('Wyoming'), '052' => t('American Samoa'), '053' => t('Federated States of Micronesia'), '054' => t('Guam'), '055' => t('Marshall Islands'), '056' => t('Northern Mariana Islands'), '057' => t('Palau'), '058' => t('Puerto Rico'), '059' => t('Virgin Islands'), ); } /** * Returns minimum and maximum latitude and longitude needed to create a bounding box. */ function location_bounds_us() { return array( 'minlng' => -179.22745, 'minlat' => -56.5109, 'maxlng' => 158.80735, 'maxlat' => 71.399467, ); }