Merge pull request #16831 from civicrm/5.24
[civicrm-core.git] / CRM / Utils / Geocode / Google.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * Class that uses google geocoder
20 */
21 class CRM_Utils_Geocode_Google {
22
23 /**
24 * Server to retrieve the lat/long
25 *
26 * @var string
27 */
28 static protected $_server = 'maps.googleapis.com';
29
30 /**
31 * Uri of service.
32 *
33 * @var string
34 */
35 static protected $_uri = '/maps/api/geocode/xml?sensor=false&address=';
36
37 /**
38 * Function that takes an address object and gets the latitude / longitude for this
39 * address. Note that at a later stage, we could make this function also clean up
40 * the address into a more valid format
41 *
42 * @param array $values
43 * @param bool $stateName
44 *
45 * @return bool
46 * true if we modified the address, false otherwise
47 */
48 public static function format(&$values, $stateName = FALSE) {
49 // we need a valid country, else we ignore
50 if (empty($values['country'])) {
51 return FALSE;
52 }
53
54 $config = CRM_Core_Config::singleton();
55
56 $add = '';
57
58 if (!empty($values['street_address'])) {
59 $add = urlencode(str_replace('', '+', $values['street_address']));
60 $add .= ',+';
61 }
62
63 $city = $values['city'] ?? NULL;
64 if ($city) {
65 $add .= '+' . urlencode(str_replace('', '+', $city));
66 $add .= ',+';
67 }
68
69 if (!empty($values['state_province']) || (!empty($values['state_province_id']) && $values['state_province_id'] != 'null')) {
70 if (!empty($values['state_province_id'])) {
71 $stateProvince = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $values['state_province_id']);
72 }
73 else {
74 if (!$stateName) {
75 $stateProvince = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince',
76 $values['state_province'],
77 'name',
78 'abbreviation'
79 );
80 }
81 else {
82 $stateProvince = $values['state_province'];
83 }
84 }
85
86 // dont add state twice if replicated in city (happens in NZ and other countries, CRM-2632)
87 if ($stateProvince != $city) {
88 $add .= '+' . urlencode(str_replace('', '+', $stateProvince));
89 $add .= ',+';
90 }
91 }
92
93 if (!empty($values['postal_code'])) {
94 $add .= '+' . urlencode(str_replace('', '+', $values['postal_code']));
95 $add .= ',+';
96 }
97
98 if (!empty($values['country'])) {
99 $add .= '+' . urlencode(str_replace('', '+', $values['country']));
100 }
101
102 if (!empty($config->geoAPIKey)) {
103 $add .= '&key=' . urlencode($config->geoAPIKey);
104 }
105
106 $query = 'https://' . self::$_server . self::$_uri . $add;
107
108 require_once 'HTTP/Request.php';
109 $request = new HTTP_Request($query);
110 $request->sendRequest();
111 $string = $request->getResponseBody();
112
113 libxml_use_internal_errors(TRUE);
114 $xml = @simplexml_load_string($string);
115 CRM_Utils_Hook::geocoderFormat('Google', $values, $xml);
116 if ($xml === FALSE) {
117 // account blocked maybe?
118 CRM_Core_Error::debug_var('Geocoding failed. Message from Google:', $string);
119 return FALSE;
120 }
121
122 if (isset($xml->status)) {
123 if ($xml->status == 'OK' &&
124 is_a($xml->result->geometry->location,
125 'SimpleXMLElement'
126 )
127 ) {
128 $ret = $xml->result->geometry->location->children();
129 if ($ret->lat && $ret->lng) {
130 $values['geo_code_1'] = (float) $ret->lat;
131 $values['geo_code_2'] = (float) $ret->lng;
132 return TRUE;
133 }
134 }
135 elseif ($xml->status == 'ZERO_RESULTS') {
136 // reset the geo code values if we did not get any good values
137 $values['geo_code_1'] = $values['geo_code_2'] = 'null';
138 return FALSE;
139 }
140 else {
141 CRM_Core_Error::debug_var("Geocoding failed. Message from Google: ({$xml->status})", (string ) $xml->error_message);
142 $values['geo_code_1'] = $values['geo_code_2'] = 'null';
143 $values['geo_code_error'] = $xml->status;
144 return FALSE;
145 }
146 }
147 }
148
149 }