PluginProbe
Leaflet Map / 3.4.5
Leaflet Map v3.4.5
3.4.7 3.4.6 trunk 2.10.0 2.10.1 2.11.0 2.11.1 2.11.2 2.11.3 2.11.4 2.11.5 2.12.0 2.13.0 2.14.0 2.15.0 2.16.0 2.16.1 2.16.2 2.17.0 2.17.1 2.17.2 2.17.3 2.18.0 2.19.0 2.19.1 All 49 releases
← All changes | class.geocoder.php +246 -157 2.16.23.4.5 View file →
@@ -6,189 +6,278 @@
6 6 *
7 7 */
8 8
9 9 class Leaflet_Geocoder {
10 - /**
11 - * Geocoder should return this on error/not found
12 - * @var array $not_found
13 - */
14 - private $not_found = array('lat' => 0, 'lng' => 0);
15 - /**
16 - * Latitude
17 - * @var float $lat
18 - */
19 - public $lat = 0;
20 - /**
21 - * Longitude
22 - * @var float $lng
23 - */
24 - public $lng = 0;
10 + /**
11 + * Geocoder should return this on error/not found
12 + * @var array $not_found
13 + */
14 + private $not_found = array('lat' => 0, 'lng' => 0);
15 + /**
16 + * Latitude
17 + * @var float $lat
18 + */
19 + public $lat = 0;
20 + /**
21 + * Longitude
22 + * @var float $lng
23 + */
24 + public $lng = 0;
25 25
26 - /**
27 - * new Geocoder from address
28 - *
29 - * handles url encoding and caching
30 - *
31 - * @param string $address the requested address to look up
32 - * @return NOTHING
33 - */
34 - public function __construct ($address) {
35 - $settings = Leaflet_Map_Plugin_Settings::init();
36 - $address = urlencode( $address );
26 + /**
27 + * new Geocoder from address
28 + *
29 + * handles url encoding and caching
30 + *
31 + * @param string $address the requested address to look up
32 + * @return NOTHING
33 + */
34 + public function __construct ($address) {
35 + $settings = Leaflet_Map_Plugin_Settings::init();
36 + // trim all quotes (even smart) from address
37 + $address = trim($address, '\'"”');
38 + $address = urlencode( $address );
39 +
40 + $geocoder = $settings->get('geocoder');
37 41
38 - $geocoder = $settings->get('geocoder');
42 + $cached_address = 'leaflet_' . $geocoder . '_' . $address;
39 43
40 - $cached_address = 'leaflet_' . $geocoder . '_' . $address;
44 + /* retrieve cached geocoded location */
45 + $found_cache = get_option( $cached_address );
41 46
42 - /* retrieve cached geocoded location */
43 - $found_cache = get_option( $cached_address );
47 + if ( $this->is_valid_cached_location( $found_cache ) ) {
48 + $location = $found_cache;
49 + } else {
50 + if ( false !== $found_cache ) {
51 + $this->remove_cache_key( $cached_address );
52 + }
44 53
45 - if ( $found_cache ) {
46 - $location = $found_cache;
47 - } else {
48 - // try geocoding
49 - $geocoding_method = $geocoder . '_geocode';
54 + // try geocoding
55 + $geocoding_method = $geocoder . '_geocode';
50 56
51 - try {
52 - $location = (Object) $this->$geocoding_method( $address );
57 + try {
58 + $location = (Object) $this->$geocoding_method( $address );
53 59
54 - /* add location */
55 - add_option($cached_address, $location);
60 + if ( ! $this->is_valid_cached_location( $location ) ) {
61 + throw new Exception('Invalid geocoder response');
62 + }
56 63
57 - /* add option key to locations for clean up purposes */
58 - $locations = get_option('leaflet_geocoded_locations', array());
59 - array_push($locations, $cached_address);
60 - update_option('leaflet_geocoded_locations', $locations);
61 - } catch (Exception $e) {
62 - // failed
63 - $location = $this->not_found;
64 - }
65 - }
64 + /* add location */
65 + add_option($cached_address, $location);
66 66
67 - // set variables
68 - $this->lat = $location->lat;
69 - $this->lng = $location->lng;
70 - }
67 + /* add option key to locations for clean up purposes */
68 + $locations = get_option('leaflet_geocoded_locations', array());
69 + if ( ! in_array( $cached_address, $locations, true ) ) {
70 + array_push($locations, $cached_address);
71 + update_option('leaflet_geocoded_locations', $locations);
72 + }
73 + } catch (Exception $e) {
74 + // failed
75 + $location = $this->not_found;
76 + }
77 + }
71 78
72 - /**
73 - * Removes location caches
74 - */
75 - public static function remove_caches () {
76 - $addresses = get_option('leaflet_geocoded_locations', array());
77 - foreach ($addresses as $address) {
78 - delete_option($address);
79 - }
80 - delete_option('leaflet_geocoded_locations');
81 - }
79 + if (isset($location->lat) && isset($location->lng)) {
80 + $this->lat = $location->lat;
81 + $this->lng = $location->lng;
82 + }
83 + }
82 84
83 - /**
84 - * Used by geocoders to make requests via curl or file_get_contents
85 - *
86 - * includes a try/catch
87 - *
88 - * @param string $url the urlencoded request url
89 - * @return varies object from API or null (failed)
90 - */
91 - private function get_url( $url ) {
92 - $referer = get_site_url();
85 + /**
86 + * Removes location caches
87 + */
88 + public static function remove_caches () {
89 + $addresses = get_option('leaflet_geocoded_locations', array());
90 + foreach ($addresses as $address) {
91 + delete_option($address);
92 + }
93 + delete_option('leaflet_geocoded_locations');
94 + }
93 95
94 - if (in_array('curl', get_loaded_extensions())) {
95 - /* try curl */
96 - $ch = curl_init();
96 + /**
97 + * Determines whether a cached geocode entry is valid.
98 + *
99 + * @param mixed $location Cached location value from WordPress options.
100 + * @return bool
101 + */
102 + private function is_valid_cached_location( $location ) {
103 + if ( ! is_object( $location ) ) {
104 + return false;
105 + }
97 106
98 - curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
99 - curl_setopt($ch, CURLOPT_HEADER, 0);
100 - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
101 - curl_setopt($ch, CURLOPT_REFERER, $referer);
102 - curl_setopt($ch, CURLOPT_URL, $url);
103 - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
107 + if ( ! isset( $location->lat ) || ! isset( $location->lng ) ) {
108 + return false;
109 + }
104 110
105 - $data = curl_exec($ch);
106 - curl_close($ch);
111 + return filter_var( $location->lat, FILTER_VALIDATE_FLOAT ) !== false
112 + && filter_var( $location->lng, FILTER_VALIDATE_FLOAT ) !== false;
113 + }
107 114
108 - return $data;
109 - } else if (ini_get('allow_url_fopen')) {
110 - /* try file get contents */
115 + /**
116 + * Removes a single geocode cache entry and its registry reference.
117 + *
118 + * @param string $cached_address Option key for the cached geocode.
119 + * @return void
120 + */
121 + private function remove_cache_key( $cached_address ) {
122 + delete_option( $cached_address );
111 123
112 - $opts = array(
113 - 'http' => array(
114 - 'header' => array("Referer: $referer\r\n")
115 - )
116 - );
117 - $context = stream_context_create($opts);
124 + $addresses = get_option( 'leaflet_geocoded_locations', array() );
125 + $addresses = array_values(
126 + array_filter(
127 + $addresses,
128 + function ( $address ) use ( $cached_address ) {
129 + return $address !== $cached_address;
130 + }
131 + )
132 + );
118 133
119 - return file_get_contents($url, false, $context);
120 - }
134 + if ( empty( $addresses ) ) {
135 + delete_option( 'leaflet_geocoded_locations' );
136 + } else {
137 + update_option( 'leaflet_geocoded_locations', $addresses );
138 + }
139 + }
121 140
122 - $error_msg = 'Could not get url: ' . $url;
123 - throw new Exception( $error_msg );
124 - }
141 + /**
142 + * Used by geocoders to make requests via curl or file_get_contents
143 + *
144 + * includes a try/catch
145 + *
146 + * @param string $url the urlencoded request url
147 + * @return varies object from API or null (failed)
148 + */
149 + private function get_url( $url ) {
150 + $referer = get_site_url();
125 151
126 - /**
127 - * Google geocoder (https://developers.google.com/maps/documentation/geocoding/start)
128 - *
129 - * @param string $address the urlencoded address to look up
130 - * @return varies object from API or null (failed)
131 - */
152 + if (in_array('curl', get_loaded_extensions())) {
153 + /* try curl */
154 + $ch = curl_init();
132 155
133 - private function google_geocode ( $address ) {
134 - // Leaflet_Map_Plugin_Settings
156 + curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
157 + curl_setopt($ch, CURLOPT_HEADER, 0);
158 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
159 + curl_setopt($ch, CURLOPT_REFERER, $referer);
160 + curl_setopt($ch, CURLOPT_URL, $url);
161 + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
162 +
163 + $data = curl_exec($ch);
164 + curl_close($ch);
165 +
166 + return $data;
167 + } else if (ini_get('allow_url_fopen')) {
168 + /* try file get contents */
169 +
170 + $opts = array(
171 + 'http' => array(
172 + 'header' => array("Referer: $referer\r\n")
173 + )
174 + );
175 + $context = stream_context_create($opts);
176 +
177 + return file_get_contents($url, false, $context);
178 + }
179 +
180 + $error_msg = 'Could not get url: ' . $url;
181 + throw new Exception( $error_msg );
182 + }
183 +
184 + /**
185 + * Google geocoder (https://developers.google.com/maps/documentation/geocoding/start)
186 + *
187 + * @param string $address the urlencoded address to look up
188 + * @return varies object from API or null (failed)
189 + */
190 +
191 + private function google_geocode ( $address ) {
192 + // Leaflet_Map_Plugin_Settings
135 193 $settings = Leaflet_Map_Plugin_Settings::init();
136 - $key = $settings->get('google_appkey');
137 -
138 - $geocode_url = 'https://maps.googleapis.com/maps/api/geocode/json?address=%s&key=%s';
139 - $geocode_url = sprintf($geocode_url, $address, $key);
140 -
141 - $json = $this->get_url($geocode_url);
142 - $json = json_decode($json);
194 + $key = $settings->get('google_appkey');
195 +
196 + $geocode_url = 'https://maps.googleapis.com/maps/api/geocode/json?address=%s&key=%s';
197 + $geocode_url = sprintf($geocode_url, $address, $key);
198 +
199 + $json = $this->get_url($geocode_url);
200 + $json = json_decode($json);
143 201
144 - /* found location */
145 - if ($json->status == 'OK') {
146 -
147 - $location = $json->results[0]->geometry->location;
202 + /* found location */
203 + if ($json->status == 'OK') {
204 +
205 + $location = $json->results[0]->geometry->location;
148 206
149 - return (Object) $location;
150 - }
151 -
152 - throw new Exception('No Address Found');
153 - }
207 + return (Object) $location;
208 + }
209 +
210 + throw new Exception('No Address Found');
211 + }
154 212
155 - /**
156 - * OpenStreetMap geocoder Nominatim (https://nominatim.openstreetmap.org/)
157 - *
158 - * @param string $address the urlencoded address to look up
159 - * @return varies object from API or null (failed)
160 - */
213 + /**
214 + * OpenStreetMap geocoder Nominatim (https://nominatim.openstreetmap.org/)
215 + *
216 + * @param string $address The URL-encoded address to look up.
217 + * @return object Object containing lat and lng properties.
218 + * @throws Exception When the request fails or no valid coordinates are returned.
219 + */
220 + private function osm_geocode( $address ) {
221 + $request_url = sprintf(
222 + 'https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&q=%s',
223 + $address
224 + );
161 225
162 - private function osm_geocode ( $address ) {
163 - $geocode_url = 'https://nominatim.openstreetmap.org/?format=json&limit=1&q=';
164 - $geocode_url .= $address;
165 - $json = $this->get_url($geocode_url);
166 - $json = json_decode($json);
167 -
168 - return (Object) array(
169 - 'lat' => $json[0]->lat,
170 - 'lng' => $json[0]->lon,
171 - );
172 - }
226 + $accept_language = str_replace( '_', '-', get_locale() );
227 +
228 + $settings = Leaflet_Map_Plugin_Settings::init();
229 + $contact_email = $settings->get( 'nominatim_contact_email' );
173 230
174 - /**
175 - * Danish Addresses Web Application
176 - * (https://dawa.aws.dk)
177 - *
178 - * @param string $address the urlencoded address to look up
179 - * @return varies object from API or null (failed)
180 - */
231 + if ( empty( $contact_email ) ) {
232 + $contact_email = get_bloginfo( 'admin_email' );
233 + }
181 234
182 - private function dawa_geocode ( $address ) {
183 - $geocode_url = 'https://dawa.aws.dk/adresser?format=json&q=';
184 - $geocode_url .= $address;
185 - $json = $this->get_url($geocode_url);
186 - $json = json_decode($json);
235 + $contact_email = apply_filters( 'leaflet_map_nominatim_contact_email', $contact_email );
187 236
188 - /* found location */
189 - return (Object) array(
190 - 'lat' => $json[0]->adgangsadresse->adgangspunkt->koordinater[1],
191 - 'lng' => $json[0]->adgangsadresse->adgangspunkt->koordinater[0]
192 - );
193 - }
194 -}
237 + $agent = 'Nominatim query for ' . get_bloginfo( 'url' ) . '; contact ' . $contact_email;
238 +
239 + $response = wp_remote_get(
240 + $request_url,
241 + array(
242 + 'user-agent' => $agent,
243 + 'headers' => array(
244 + 'Accept-Language' => $accept_language,
245 + ),
246 + )
247 + );
248 +
249 + if ( ! is_wp_error( $response ) && isset( $response['body'] ) ) {
250 + $json = json_decode( $response['body'] );
251 +
252 + if ( isset( $json[0]->lat ) && isset( $json[0]->lon ) ) {
253 + return (object) array(
254 + 'lat' => $json[0]->lat,
255 + 'lng' => $json[0]->lon,
256 + );
257 + }
258 + }
259 +
260 + throw new Exception('No Address Found');
261 + }
262 +
263 + /**
264 + * TODO: does this still work?
265 + * Danish Addresses Web Application
266 + * (https://dawa.aws.dk)
267 + *
268 + * @param string $address the urlencoded address to look up
269 + * @return varies object from API or null (failed)
270 + */
271 + private function dawa_geocode ( $address ) {
272 + $geocode_url = 'https://dawa.aws.dk/adresser?format=json&q=';
273 + $geocode_url .= $address;
274 + $json = $this->get_url($geocode_url);
275 + $json = json_decode($json);
276 +
277 + /* found location */
278 + return (Object) array(
279 + 'lat' => $json[0]->adgangsadresse->adgangspunkt->koordinater[1],
280 + 'lng' => $json[0]->adgangsadresse->adgangspunkt->koordinater[0]
281 + );
282 + }
283 +}