1 : <?php
2 : /**
3 : * Provide a method of interfacing with Openstreetmap servers.
4 : *
5 : * PHP Version 5
6 : *
7 : * @category Services
8 : * @package Services_Openstreetmap
9 : * @author Ken Guest <kguest@php.net>
10 : * @license BSD http://www.opensource.org/licenses/bsd-license.php
11 : * @version Release: @package_version@
12 : * @link http://pear.php.net/package/Services_Openstreetmap
13 : * @link http://wiki.openstreetmap.org/wiki/Api06
14 : */
15 :
16 : require_once 'HTTP/Request2.php';
17 : require_once 'Services/Openstreetmap/InvalidArgumentException.php';
18 : require_once 'Services/Openstreetmap/RuntimeException.php';
19 : require_once 'Services/Openstreetmap/Config.php';
20 : require_once 'Services/Openstreetmap/Transport.php';
21 : require_once 'Services/Openstreetmap/API/V06.php';
22 : require_once 'Services/Openstreetmap/Object.php';
23 : require_once 'Services/Openstreetmap/Objects.php';
24 : require_once 'Services/Openstreetmap/Node.php';
25 : require_once 'Services/Openstreetmap/Nodes.php';
26 : require_once 'Services/Openstreetmap/Relation.php';
27 : require_once 'Services/Openstreetmap/Relations.php';
28 : require_once 'Services/Openstreetmap/Way.php';
29 : require_once 'Services/Openstreetmap/Ways.php';
30 : #spl_autoload_register(array('Services_Openstreetmap', 'autoload'));
31 :
32 : /**
33 : * Services_Openstreetmap - interface with Openstreetmap
34 : *
35 : * @category Services
36 : * @package Services_Openstreetmap
37 : * @author Ken Guest <kguest@php.net>
38 : * @copyright 2010 Ken Guest
39 : * @license BSD http://www.opensource.org/licenses/bsd-license.php
40 : * @version Release: 0.0.1
41 : * @link http://pear.php.net/package/Services_Openstreetmap
42 : */
43 : class Services_Openstreetmap
44 : {
45 : /**
46 : * Default config settings
47 : *
48 : * @var Services_Openstreetmap_Config
49 : * @see Services_Openstreetmap::getConfig
50 : * @see Services_Openstreetmap::setConfig
51 : */
52 : protected $config = null;
53 :
54 : /**
55 : * [Retrieved] XML
56 : * @var string
57 : * @internal
58 : */
59 : protected $xml = null;
60 :
61 : protected $transport = null;
62 :
63 : /**
64 : * autoloader
65 : *
66 : * @param string $class Name of class
67 : *
68 : * @return boolean
69 : */
70 : public static function autoload($class)
71 : {
72 0 : $dir = dirname(dirname(__FILE__));
73 0 : $file = $dir . '/' . str_replace('_', '/', $class) . '.php';
74 0 : if (file_exists($file)) {
75 0 : echo "utoloading $file\n";
76 0 : return include_once $file;
77 : }
78 0 : return false;
79 : }
80 :
81 : /**
82 : * constructor; which optionally sets config details.
83 : *
84 : * @param array $config Defaults to empty array if none provided
85 : *
86 : * @return Services_Openstreetmap
87 : */
88 : public function __construct($config = array())
89 : {
90 10 : if ($config == array()) {
91 0 : $config = $this->config;
92 0 : }
93 10 : $this->getConfig()->setTransport($this->getTransport());
94 10 : if (!is_null($config)) {
95 10 : $this->getConfig()->setValue($config);
96 10 : }
97 10 : $version = $this->getConfig()->getValue('api_version');
98 10 : $api = "Services_Openstreetmap_API_V" . str_replace('.', '', $version);
99 10 : $this->api = new $api;
100 10 : $this->api->setTransport($this->getTransport());
101 10 : $this->api->setConfig($this->getConfig());
102 10 : }
103 :
104 : /**
105 : * Convert a 'bbox' ordered set of coordinates to ordering required for get
106 : * method.
107 : *
108 : * <code>
109 : * $osm = new Services_Openstreetmap();
110 : * $osm->get($osm->bboxToMinMax($minLat, $minLon, $maxLat, $maxLon));
111 : * file_put_contents("area_covered.osm", $osm->getXML());
112 : * </code>
113 : *
114 : * @param mixed $minLat min Latitude
115 : * @param mixed $minLon min Longitude
116 : * @param mixed $maxLat max Latitude
117 : * @param mixed $maxLon max Longitude
118 : *
119 : * @return array
120 : */
121 : public function bboxToMinMax($minLat, $minLon, $maxLat, $maxLon)
122 : {
123 0 : return array($minLon, $minLat, $maxLon, $maxLat);
124 : }
125 :
126 : /**
127 : * Get XML describing area prescribed by the given co-ordinates.
128 : *
129 : * <code>
130 : * $osm = new Services_Openstreetmap();
131 : * $osm->get(-8.3564758, 52.821022799999994, -7.7330017, 53.0428644);
132 : * file_put_contents("area_covered.osm", $osm->getXML());
133 : * </code>
134 : *
135 : * @param string $minLon min Longitude (leftmost point)
136 : * @param string $minLat min Latitude (bottom point)
137 : * @param string $maxLon max Longitude (rightmost point)
138 : * @param string $maxLat max Latitude (top point)
139 : *
140 : * @return void
141 : */
142 :
143 : public function get($minLon, $minLat, $maxLon, $maxLat)
144 : {
145 0 : $config = $this->getConfig();
146 0 : $url = $config->getValue('server')
147 : . 'api/'
148 0 : . $config->getValue('api_version')
149 0 : . "/map?bbox=$minLat,$minLon,$maxLat,$maxLon";
150 0 : $response = $this->getTransport()->getResponse($url);
151 0 : $this->xml = $response->getBody();
152 0 : }
153 :
154 : /**
155 : * Get co-ordinates of some named place
156 : *
157 : * <code>
158 : * $coords = $osm->getCoordsOfPlace('Limerick, Ireland');
159 : * </code>
160 : *
161 : * @param string $place name
162 : *
163 : * @return array Associated array of lat/lon values.
164 : * @throws Services_Openstreetmap_Exception If the place can not be found.
165 : */
166 : public function getCoordsOfPlace($place)
167 : {
168 : $url = 'http://nominatim.openstreetmap.org/search?q='
169 0 : . urlencode($place) . '&limit=1&format=xml';
170 0 : $response = $this->getTransport()->getResponse($url);
171 0 : $xml = simplexml_load_string($response->getBody());
172 0 : $obj = $xml->xpath('//place');
173 0 : if (empty($obj)) {
174 0 : throw new Services_Openstreetmap_Exception(
175 : 'Could not get coords for ' . $place
176 0 : );
177 : }
178 0 : $attrs = $xml->named[0];
179 0 : $attrs = $obj[0]->attributes();
180 0 : $lat = (string) $attrs['lat'];
181 0 : $lon = (string) $attrs['lon'];
182 0 : return compact('lat', 'lon');
183 : }
184 :
185 : /**
186 : * Given the results of a call to func_get_args return an array of unique
187 : * valid IDs specified in those results (either 1 per argument or each
188 : * argument containing an array of IDs).
189 : *
190 : * @param mixed $args results of call to func_get_args
191 : *
192 : * @return array
193 : *
194 : */
195 : public static function getIDs($args)
196 : {
197 1 : $IDs = array();
198 1 : foreach ($args as $arg) {
199 1 : if (is_array($arg)) {
200 0 : $IDs = array_merge($arg, $IDs);
201 1 : } elseif (is_numeric($arg)) {
202 1 : $IDs[] = $arg;
203 1 : }
204 1 : }
205 1 : return array_unique($IDs);
206 : }
207 :
208 : /**
209 : * Load XML from [cache] file.
210 : *
211 : * @param string $file filename
212 : *
213 : * @return void
214 : */
215 : public function loadXml($file)
216 : {
217 0 : $this->xml = file_get_contents($file);
218 0 : }
219 :
220 : /**
221 : * return XML.
222 : *
223 : * @return string
224 : */
225 : public function getXml()
226 : {
227 0 : return $this->xml;
228 : }
229 :
230 :
231 : /**
232 : * search based on given criteria.
233 : *
234 : * returns an array of objects such as Services_Openstreetmap_Node etc.
235 : *
236 : * <code>
237 : * $osm = new Services_Openstreetmap();
238 : *
239 : * $osm->loadXML("./osm.osm");
240 : * $results = $osm->search(array("amenity" => "pharmacy"));
241 : * echo "List of Pharmacies\n";
242 : * echo "==================\n\n";
243 : *
244 : * foreach ($results as $result) {
245 : * $name = $result->getTag('name');
246 : * $addrStreet = $result->getTag('addr:street');
247 : * $addrCity = $result->getTag('addr:city');
248 : * $addrCountry = $result->getTag('addr:country');
249 : * $addrHouseName = $result->getTag('addr:housename');
250 : * $addrHouseNumber = $result->getTag('addr:housenumber');
251 : * $openingHours = $result->getTag('opening_hours');
252 : * $phone = $result->getTag('phone');
253 : *
254 : * $line1 = ($addrHouseNumber) ? $addrHouseNumber : $addrHouseName;
255 : * if ($line1 != null) {
256 : * $line1 .= ', ';
257 : * }
258 : * echo "$name\n{$line1}{$addrStreet}\n$phone\n$openingHours\n\n";
259 : * }
260 : * </code>
261 : *
262 : * @param array $criteria what to search for
263 : *
264 : * @return array
265 : */
266 : public function search(array $criteria)
267 : {
268 0 : $results = array();
269 :
270 0 : $xml = simplexml_load_string($this->xml);
271 0 : if ($xml === false) {
272 0 : return array();
273 : }
274 0 : foreach ($criteria as $key => $value) {
275 0 : foreach ($xml->xpath('//way') as $node) {
276 0 : $results = array_merge(
277 0 : $results,
278 0 : $this->_searchNode($node, $key, $value, 'way')
279 0 : );
280 0 : }
281 0 : foreach ($xml->xpath('//node') as $node) {
282 0 : $results = array_merge(
283 0 : $results,
284 0 : $this->_searchNode($node, $key, $value, 'node')
285 0 : );
286 0 : }
287 0 : }
288 0 : return $results;
289 : }
290 :
291 : /**
292 : * Search node for a specific key/value pair, allowing for value to be
293 : * included in a semicolon delimited list.
294 : *
295 : * @param SimpleXMLElement $node Node to search
296 : * @param string $key Key to search for (Eg 'amenity')
297 : * @param string $value Value to search for (Eg 'pharmacy')
298 : * @param string $type Type of object to return.
299 : *
300 : * @return array
301 : */
302 : private function _searchNode(SimpleXMLElement $node, $key, $value, $type)
303 : {
304 0 : $class = 'Services_Openstreetmap_' . ucfirst(strtolower($type));
305 0 : $results = array();
306 0 : foreach ($node->tag as $tag) {
307 0 : if ($tag['k'] == $key) {
308 0 : if ($tag['v'] == $value) {
309 0 : $obj = new $class();
310 0 : $obj->setTransport($this->getTransport());
311 0 : $obj->setConfig($this->getConfig());
312 0 : $obj->setXml(simplexml_load_string($node->saveXML()));
313 0 : $results[] = $obj;
314 0 : } elseif (strpos($tag['v'], ';')) {
315 0 : $array = explode(';', $tag['v']);
316 0 : if (in_array($value, $array)) {
317 0 : $obj = new $class();
318 0 : $obj->setTransport($this->getTransport());
319 0 : $obj->setConfig($this->getConfig());
320 0 : $obj->setXml(simplexml_load_string($node->saveXML()));
321 0 : $results[] = $obj;
322 0 : }
323 0 : }
324 0 : }
325 0 : }
326 0 : return $results;
327 : }
328 :
329 : /**
330 : * Return the number of seconds that must elapse before a connection is
331 : * considered to have timed-out.
332 : *
333 : * @return int
334 : */
335 : public function getTimeout()
336 : {
337 0 : return $this->getConfig()->getTimeout();
338 : }
339 :
340 : /**
341 : * minVersion - min API version supported by connected server.
342 : *
343 : * <code>
344 : * $config = array('user' => 'fred@example.net', 'password' => 'wilma4eva');
345 : * $osm = new Services_Openstreetmap($config);
346 : * $min = $osm->getMinVersion();
347 : * </code>
348 : *
349 : * @return float
350 : */
351 : public function getMinVersion()
352 : {
353 0 : return $this->getConfig()->getMinVersion();
354 : }
355 :
356 : /**
357 : * maxVersion - max API version supported by connected server.
358 : *
359 : * <code>
360 : * $config = array('user' => 'fred@example.net', 'password' => 'wilma4eva');
361 : * $osm = new Services_Openstreetmap($config);
362 : * $max = $osm->getMaxVersion();
363 : * </code>
364 : *
365 : * @return float
366 : */
367 : public function getMaxVersion()
368 : {
369 0 : return $this->getConfig()->getMaxVersion();
370 : }
371 :
372 : /**
373 : * Max size of area that can be downloaded in one request.
374 : *
375 : * <code>
376 : * $osm = new Services_Openstreetmap();
377 : * $area_allowed = $osm->getMaxArea();
378 : * </code>
379 : *
380 : * @return float
381 : */
382 : public function getMaxArea()
383 : {
384 0 : return $this->getConfig()->getMaxArea();
385 : }
386 :
387 : /**
388 : * Maximum number of tracepoints per page.
389 : *
390 : * <code>
391 : * $osm = new Services_Openstreetmap();
392 : * $tracepoints = $osm->getTracepointsPerPage();
393 : * </code>
394 : *
395 : * @return float
396 : */
397 : public function getTracepointsPerPage()
398 : {
399 0 : return $this->getConfig()->getTracepointsPerPage();
400 : }
401 :
402 : /**
403 : * Maximum number of nodes per way.
404 : *
405 : * Anymore than that and the way must be split.
406 : *
407 : * <code>
408 : * $osm = new Services_Openstreetmap();
409 : * $max = $osm->getMaxNodes();
410 : * </code>
411 : *
412 : * @return float
413 : */
414 : public function getMaxNodes()
415 : {
416 0 : return $this->getConfig()->getMaxNodes();
417 : }
418 :
419 : /**
420 : * Number of elements allowed per changeset
421 : *
422 : * <code>
423 : * $osm = new Services_Openstreetmap();
424 : * $max = $osm->getMaxElements();
425 : * </code>
426 : *
427 : * @return float
428 : */
429 : public function getMaxElements()
430 : {
431 0 : return $this->getConfig()->getMaxElements();
432 : }
433 :
434 : /**
435 : * Set Config object
436 : *
437 : * @param Services_Openstreetmap_Config $config Config settings.
438 : *
439 : * @return Services_Openstreetmap_API_V06
440 : */
441 : public function setConfig(Services_Openstreetmap_Config $config)
442 : {
443 0 : $this->config = $config;
444 0 : return $this;
445 : }
446 :
447 : /**
448 : * Get current Config object
449 : *
450 : * @return Services_Openstreetmap_Config
451 : */
452 : public function getConfig()
453 : {
454 10 : if (is_null($this->config)) {
455 10 : $config = new Services_Openstreetmap_Config();
456 10 : $this->config = $config;
457 10 : }
458 10 : return $this->config;
459 : }
460 :
461 : /**
462 : * Get current Transport object.
463 : *
464 : * If one is not defined, create it.
465 : *
466 : * @return Services_Openstreetmap_Transport
467 : */
468 : public function getTransport()
469 : {
470 10 : if (is_null($this->transport)) {
471 10 : $transport = new Services_Openstreetmap_Transport();
472 10 : $transport->setConfig($this->getConfig());
473 10 : $this->transport = $transport;
474 :
475 10 : }
476 10 : return $this->transport;
477 : }
478 :
479 : /**
480 : * __call
481 : *
482 : * If possible, call the appropriate method of the API instance.
483 : *
484 : * @param string $name Name of missing method to call.
485 : * @param array $arguments Arguments to be used when calling method.
486 : *
487 : * @return void
488 : * @throws Services_Openstreetmap_Exception If the method is not supported
489 : * by the API instance.
490 : */
491 : public function __call($name, $arguments)
492 : {
493 10 : if (method_exists($this->api, $name)) {
494 10 : return call_user_func_array(array($this->api, $name), $arguments);
495 : } else {
496 0 : throw new Services_Openstreetmap_Exception(
497 0 : sprintf(
498 0 : 'Method %s does not exist.',
499 : $name
500 0 : )
501 0 : );
502 : }
503 : }
504 : }
505 : // vim:set et ts=4 sw=4:
506 : ?>
|