PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/fsn-site-central/library/OpenStreetMap/Nominatim.php

https://gitlab.com/team_fsn/fsn-php
PHP | 453 lines | 197 code | 36 blank | 220 comment | 27 complexity | 28b6b517e35fe6ab7fa3bfd6a3207814 MD5 | raw file
  1. <?php
  2. /**
  3. * Nominatim.php
  4. * 20-Mar-2012
  5. *
  6. * PHP Version 5
  7. *
  8. * @category Services
  9. * @package Services_OpenStreetMap
  10. * @subpackage Services_OpenStreetMap_Nominatim
  11. * @author Ken Guest <kguest@php.net>
  12. * @license BSD http://www.opensource.org/licenses/bsd-license.php
  13. * @link Nominatim.php
  14. */
  15. /**
  16. * Services_OpenStreetMap_Nominatim
  17. *
  18. * @category Services
  19. * @package Services_OpenStreetMap
  20. * @subpackage Services_OpenStreetMap_Nominatim
  21. * @author Ken Guest <kguest@php.net>
  22. * @license BSD http://www.opensource.org/licenses/bsd-license.php
  23. * @link Nominatim.php
  24. */
  25. class Services_OpenStreetMap_Nominatim
  26. {
  27. // http://wiki.openstreetmap.org/wiki/Nominatim
  28. /**
  29. * The server to connect to
  30. *
  31. * @var string
  32. */
  33. protected $server = 'http://nominatim.openstreetmap.org/';
  34. /**
  35. * Format to perform queries in (xml|json|html). Defaults to 'xml'
  36. *
  37. * @var string
  38. */
  39. protected $format = 'xml';
  40. /**
  41. * If 1, include a breakdown of the address into elements.
  42. *
  43. * @var int
  44. */
  45. protected $addresssdetails = 0;
  46. /**
  47. * Preferred language order. Standard rfc2616 string or a simple comma
  48. * separated list of language codes.
  49. *
  50. * @var string
  51. */
  52. protected $accept_language = 'en';
  53. /**
  54. * Email address to be sent as a part of the query string, recommended to
  55. * be set if sending large numbers of requests/searches.
  56. *
  57. * @var string
  58. */
  59. protected $email_address = null;
  60. /**
  61. * Output polygon outlines for items found.
  62. *
  63. * @var null|boolean
  64. */
  65. protected $polygon = null;
  66. /**
  67. * The preferred area to find search results
  68. * <left>,<top>,<right>,<bottom>
  69. *
  70. * @var null|string
  71. */
  72. protected $viewbox = null;
  73. /**
  74. * If true, restrict results to those within the bounding box/view box.
  75. *
  76. * @var null|boolean
  77. */
  78. protected $bounded = null;
  79. /**
  80. * Remove duplicates?
  81. *
  82. * @var null|boolean
  83. */
  84. protected $dedupe = null;
  85. /**
  86. * Maximum number of entries to retrieve.
  87. *
  88. * @var int
  89. */
  90. protected $limit = null;
  91. /**
  92. * CSVs of valid country codes to restrict search to.
  93. *
  94. * @var string
  95. */
  96. protected $countryCodes = null;
  97. /**
  98. * The transport to use
  99. *
  100. * @var Services_OpenStreetMap_Transport
  101. */
  102. protected $transport = null;
  103. /**
  104. * Constructor
  105. *
  106. * @param Services_OpenStreetMap_Transport $transport Transport instance.
  107. *
  108. * @return Services_OpenStreetMap_Nominatim
  109. */
  110. public function __construct($transport)
  111. {
  112. $this->setTransport($transport);
  113. }
  114. /**
  115. * Build query portion for request.
  116. *
  117. * @param string $place Name of location/place to search for
  118. *
  119. * @return string
  120. */
  121. private function _buildQuery($place)
  122. {
  123. $format = $this->format;
  124. $limit = $this->limit;
  125. $accept_language = $this->accept_language;
  126. $polygon = $this->polygon;
  127. $viewbox = $this->viewbox;
  128. $bounded = $this->bounded;
  129. $dedupe = $this->dedupe;
  130. $q = $place;
  131. $params = compact(
  132. 'q',
  133. 'format',
  134. 'limit',
  135. 'polygon',
  136. 'viewbox',
  137. 'bounded',
  138. 'dedupe'
  139. );
  140. $params['accept-language'] = $accept_language;
  141. if ($this->email_address !== null) {
  142. $params['email'] = $this->email_address;
  143. }
  144. if ($this->countryCodes !== null) {
  145. $params['countrycodes'] = $this->countryCodes;
  146. }
  147. $query = http_build_query($params);
  148. return $query;
  149. }
  150. /**
  151. * Reverse geocode a lat/lon pair.
  152. *
  153. * Perform a reverse search/geoencoding.
  154. *
  155. * @param string $lat Latitude
  156. * @param string $lon Longitude
  157. * @param bool $addressdetails Include address details, defaults to true.
  158. * @param int $zoom Zoom level, defaults to 18.
  159. *
  160. * @return void
  161. *
  162. * @throws Services_OpenStreetMap_RuntimeException If the set format
  163. * is not supported.
  164. *
  165. * @see setAcceptLanguage
  166. * @see setFormat
  167. */
  168. public function reverseGeocode($lat, $lon, $addressdetails = 1, $zoom = 18)
  169. {
  170. $format = $this->format;
  171. if ($format == 'html') {
  172. throw new Services_OpenStreetMap_RuntimeException(
  173. 'html format not accepted for reverseGeocode'
  174. );
  175. }
  176. $params = compact('format', 'lat', 'lon', 'addressdetails');
  177. $params['accept-language'] = $this->accept_language;
  178. if ($this->email_address !== null) {
  179. $params['email'] = $this->email_address;
  180. }
  181. $query = http_build_query($params);
  182. $url = $this->server . 'reverse?' . $query;
  183. $reversegeocode = null;
  184. $response = $this->getTransport()->getResponse($url);
  185. if ($format == 'xml') {
  186. $xml = simplexml_load_string($response->getBody());
  187. $reversegeocode = $xml->xpath('//reversegeocode');
  188. } elseif ($format == 'json' || $format == 'jsonv2') {
  189. $reversegeocode = json_decode($response->getBody());
  190. }
  191. return $reversegeocode;
  192. }
  193. /**
  194. * Search
  195. *
  196. * @param string $place Name of place to geocode
  197. * @param integer $limit Maximum number of results to retrieve (optional)
  198. *
  199. * @return void
  200. */
  201. public function search($place, $limit = null)
  202. {
  203. if ($limit !== null) {
  204. $this->setLimit($limit);
  205. }
  206. $format = $this->format;
  207. $query = $this->_buildQuery($place);
  208. $url = $this->server . 'search?' . $query;
  209. $response = $this->getTransport()->getResponse($url);
  210. if ($format == 'xml') {
  211. $xml = simplexml_load_string($response->getBody());
  212. $places = $xml->xpath('//place');
  213. return $places;
  214. } elseif ($format == 'json' || $format == 'jsonv2') {
  215. $places = json_decode($response->getBody());
  216. return $places;
  217. } elseif ($format == 'html') {
  218. return $response->getBody();
  219. }
  220. }
  221. /**
  222. * Set format for data to be received in.
  223. *
  224. * Format may be one of: html, json, jsonv2, xml
  225. *
  226. * @param string $format Format for data.
  227. *
  228. * @return Services_OpenStreetMap_Nominatim
  229. * @throws Services_OpenStreetMap_RuntimeException If the specified format
  230. * is not supported.
  231. */
  232. public function setFormat($format)
  233. {
  234. switch($format) {
  235. case 'html':
  236. case 'json':
  237. case 'jsonv2':
  238. case 'xml':
  239. $this->format = $format;
  240. break;
  241. default:
  242. throw new Services_OpenStreetMap_RuntimeException(
  243. sprintf('Unrecognised format (%s)', $format)
  244. );
  245. }
  246. return $this;
  247. }
  248. /**
  249. * Get which format is set for this instance (xml, json, html)
  250. *
  251. * @return string
  252. */
  253. public function getFormat()
  254. {
  255. return $this->format;
  256. }
  257. /**
  258. * Set limit of entries to retrieve.
  259. *
  260. * @param integer $limit Maximum number of entries to retrieve
  261. *
  262. * @return Services_OpenStreetMap_Nominatim
  263. */
  264. public function setLimit($limit)
  265. {
  266. if (is_numeric($limit)) {
  267. $this->limit = $limit;
  268. } else {
  269. throw new Services_OpenStreetMap_RuntimeException(
  270. 'Limit must be a numeric value'
  271. );
  272. }
  273. return $this;
  274. }
  275. /**
  276. * Get Limit
  277. *
  278. * @return integer
  279. */
  280. public function getLimit()
  281. {
  282. return $this->limit;
  283. }
  284. /**
  285. * Set Transport object.
  286. *
  287. * @param Services_OpenStreetMap_Transport $transport transport object
  288. *
  289. * @return Services_OpenStreetMap_Nominatim
  290. */
  291. public function setTransport($transport)
  292. {
  293. $this->transport = $transport;
  294. return $this;
  295. }
  296. /**
  297. * Get current Transport object.
  298. *
  299. * @return Services_OpenStreetMap_Transport
  300. */
  301. public function getTransport()
  302. {
  303. return $this->transport;
  304. }
  305. /**
  306. * Set which server to connect to.
  307. *
  308. * Possible values are 'nominatim', 'mapquest' and any other valid
  309. * endpoint specified as an URL.
  310. *
  311. * @param string $server Server URL or shorthand (nominatim / mapquest)
  312. *
  313. * @return Services_OpenStreetMap_Nominatim
  314. */
  315. public function setServer($server)
  316. {
  317. switch($server) {
  318. case 'nominatim':
  319. $this->server = 'http://nominatim.openstreetmap.org/';
  320. return $this;
  321. break;
  322. case 'mapquest':
  323. $this->server = 'http://open.mapquestapi.com/nominatim/v1/';
  324. return $this;
  325. break;
  326. default:
  327. $parsed = parse_url($server);
  328. if (isset($parsed['scheme'])
  329. && isset($parsed['host'])
  330. && isset($parsed['path'])
  331. ) {
  332. $this->server = $server;
  333. } else {
  334. throw new Services_OpenStreetMap_RuntimeException(
  335. 'Server endpoint invalid'
  336. );
  337. }
  338. return $this;
  339. }
  340. }
  341. /**
  342. * Set referred language order for showing search results.
  343. *
  344. * This overrides the browser value.
  345. * Either uses standard rfc2616 accept-language string or a simple comma
  346. * separated list of language codes.
  347. *
  348. * @param string $language language code
  349. *
  350. * @return Services_OpenStreetMap_Nominatim
  351. */
  352. public function setAcceptLanguage($language)
  353. {
  354. $this->accept_language = $language;
  355. return $this;
  356. }
  357. /**
  358. * Retrieve server endpoint.
  359. *
  360. * @return string
  361. */
  362. public function getServer()
  363. {
  364. return $this->server;
  365. }
  366. /**
  367. * Set email address.
  368. *
  369. * @param string $email Valid email address
  370. *
  371. * @return Services_OpenStreetMap_Nominatim
  372. * @throws Services_OpenStreetMap_RuntimeException If email address invalid
  373. */
  374. public function setEmailAddress($email)
  375. {
  376. if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
  377. throw new Services_OpenStreetMap_RuntimeException(
  378. sprintf("Email address '%s' is not valid", $email)
  379. );
  380. }
  381. $this->email_address = $email;
  382. return $this;
  383. }
  384. /**
  385. * Set country codes to limit search results to.
  386. *
  387. * @param string $codes CSV list of country codes.
  388. *
  389. * @return Services_OpenStreetMap_Nominatim
  390. */
  391. public function setCountryCodes($codes)
  392. {
  393. if ($codes == '') {
  394. $this->countryCodes = null;
  395. } else {
  396. $this->countryCodes = $codes;
  397. }
  398. return $this;
  399. }
  400. /**
  401. * Retrieve set email address.
  402. *
  403. * From OSM documentation:
  404. * If you are making large numbers of request please include a valid
  405. * email address or alternatively include your email address as
  406. * part of the User-Agent string. This information will be kept
  407. * confidential and only used to contact you in the event of a
  408. * problem, see Usage Policy for more details.
  409. *
  410. * @return string|null
  411. */
  412. public function getEmailAddress()
  413. {
  414. return $this->email_address;
  415. }
  416. }
  417. ?>