123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- <?php
- if (!defined('STATUSNET')) {
- exit(1);
- }
- class GeonamesPlugin extends Plugin
- {
- const PLUGIN_VERSION = '2.0.0';
- const LOCATION_NS = 1;
- public $host = 'ws.geonames.org';
- public $username = null;
- public $token = null;
- public $expiry = 7776000;
- public $timeout = 2;
- public $timeoutWindow = 60;
- public $cachePrefix = null;
-
- protected $lastTimeout = null;
-
- function onLocationFromName($name, $language, &$location)
- {
- $loc = $this->getCache(array('name' => $name,
- 'language' => $language));
- if ($loc !== false) {
- $location = $loc;
- return false;
- }
- try {
- $geonames = $this->getGeonames('search',
- array('maxRows' => 1,
- 'q' => $name,
- 'lang' => $language,
- 'type' => 'xml'));
- } catch (Exception $e) {
- $this->log(LOG_WARNING, "Error for $name: " . $e->getMessage());
- return true;
- }
- if (count($geonames) == 0) {
-
- $this->setCache(array('name' => $name,
- 'language' => $language),
- null);
- return true;
- }
- $n = $geonames[0];
- $location = new Location();
- $location->lat = $this->canonical($n->lat);
- $location->lon = $this->canonical($n->lng);
- $location->names[$language] = (string)$n->name;
- $location->location_id = (string)$n->geonameId;
- $location->location_ns = self::LOCATION_NS;
- $this->setCache(array('name' => $name,
- 'language' => $language),
- $location);
-
- return false;
- }
-
- function onLocationFromId($id, $ns, $language, &$location)
- {
- if ($ns != self::LOCATION_NS) {
-
- return true;
- }
- $loc = $this->getCache(array('id' => $id));
- if ($loc !== false) {
- $location = $loc;
- return false;
- }
- try {
- $geonames = $this->getGeonames('hierarchy',
- array('geonameId' => $id,
- 'lang' => $language));
- } catch (Exception $e) {
- $this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
- return false;
- }
- $parts = array();
- foreach ($geonames as $level) {
- if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
- $parts[] = (string)$level->name;
- }
- }
- $last = $geonames[count($geonames)-1];
- if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
- $parts[] = (string)$last->name;
- }
- $location = new Location();
- $location->location_id = (string)$last->geonameId;
- $location->location_ns = self::LOCATION_NS;
- $location->lat = $this->canonical($last->lat);
- $location->lon = $this->canonical($last->lng);
- $location->names[$language] = implode(', ', array_reverse($parts));
- $this->setCache(array('id' => (string)$last->geonameId),
- $location);
-
-
- return false;
- }
-
- function onLocationFromLatLon($lat, $lon, $language, &$location)
- {
-
- $lat = $this->canonical($lat);
- $lon = $this->canonical($lon);
- $loc = $this->getCache(array('lat' => $lat,
- 'lon' => $lon));
- if ($loc !== false) {
- $location = $loc;
- return false;
- }
- try {
- $geonames = $this->getGeonames('findNearbyPlaceName',
- array('lat' => $lat,
- 'lng' => $lon,
- 'lang' => $language));
- } catch (Exception $e) {
- $this->log(LOG_WARNING, "Error for coords $lat, $lon: " . $e->getMessage());
- return true;
- }
- if (count($geonames) == 0) {
-
- $this->setCache(array('lat' => $lat,
- 'lon' => $lon),
- null);
- return true;
- }
- $n = $geonames[0];
- $parts = array();
- $location = new Location();
- $parts[] = (string)$n->name;
- if (!empty($n->adminName1)) {
- $parts[] = (string)$n->adminName1;
- }
- if (!empty($n->countryName)) {
- $parts[] = (string)$n->countryName;
- }
- $location->location_id = (string)$n->geonameId;
- $location->location_ns = self::LOCATION_NS;
- $location->lat = $this->canonical($n->lat);
- $location->lon = $this->canonical($n->lng);
- $location->names[$language] = implode(', ', $parts);
- $this->setCache(array('lat' => $lat,
- 'lon' => $lon),
- $location);
-
- return false;
- }
-
- function onLocationNameLanguage($location, $language, &$name)
- {
- if ($location->location_ns != self::LOCATION_NS) {
-
- return true;
- }
- $id = $location->location_id;
- $n = $this->getCache(array('id' => $id,
- 'language' => $language));
- if ($n !== false) {
- $name = $n;
- return false;
- }
- try {
- $geonames = $this->getGeonames('hierarchy',
- array('geonameId' => $id,
- 'lang' => $language));
- } catch (Exception $e) {
- $this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
- return false;
- }
- if (count($geonames) == 0) {
- $this->setCache(array('id' => $id,
- 'language' => $language),
- null);
- return false;
- }
- $parts = array();
- foreach ($geonames as $level) {
- if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
- $parts[] = (string)$level->name;
- }
- }
- $last = $geonames[count($geonames)-1];
- if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
- $parts[] = (string)$last->name;
- }
- if (count($parts)) {
- $name = implode(', ', array_reverse($parts));
- $this->setCache(array('id' => $id,
- 'language' => $language),
- $name);
- }
- return false;
- }
-
- function onLocationUrl($location, &$url)
- {
- if ($location->location_ns != self::LOCATION_NS) {
-
- return true;
- }
- $url = 'http://www.geonames.org/' . $location->location_id;
-
- return false;
- }
-
- function onLocationRdfUrl($location, &$url)
- {
- if ($location->location_ns != self::LOCATION_NS) {
-
- return true;
- }
- $url = 'http://sws.geonames.org/' . $location->location_id . '/';
-
- return false;
- }
- function getCache($attrs)
- {
- $c = Cache::instance();
- if (empty($c)) {
- return null;
- }
- $key = $this->cacheKey($attrs);
- $value = $c->get($key);
- return $value;
- }
- function setCache($attrs, $loc)
- {
- $c = Cache::instance();
- if (empty($c)) {
- return null;
- }
- $key = $this->cacheKey($attrs);
- $result = $c->set($key, $loc, 0, time() + $this->expiry);
- return $result;
- }
- function cacheKey($attrs)
- {
- $key = 'geonames:' .
- implode(',', array_keys($attrs)) . ':'.
- Cache::keyize(implode(',', array_values($attrs)));
- if ($this->cachePrefix) {
- return $this->cachePrefix . ':' . $key;
- } else {
- return Cache::key($key);
- }
- }
- function wsUrl($method, $params)
- {
- if (!empty($this->username)) {
- $params['username'] = $this->username;
- }
- if (!empty($this->token)) {
- $params['token'] = $this->token;
- }
- $str = http_build_query($params, null, '&');
- return 'http://'.$this->host.'/'.$method.'?'.$str;
- }
- function getGeonames($method, $params)
- {
- if ($this->lastTimeout && (time() - $this->lastTimeout < $this->timeoutWindow)) {
-
- throw new Exception(_m('Skipping due to recent web service timeout.'));
- }
- $client = HTTPClient::start();
- $client->setConfig('connect_timeout', $this->timeout);
- $client->setConfig('timeout', $this->timeout);
- try {
- $result = $client->get($this->wsUrl($method, $params));
- } catch (Exception $e) {
- common_log(LOG_ERR, __METHOD__ . ": " . $e->getMessage());
- $this->lastTimeout = time();
- throw $e;
- }
- if (!$result->isOk()) {
-
-
- throw new Exception(sprintf(_m('HTTP error code %s.'),$result->getStatus()));
- }
- $body = $result->getBody();
- if (empty($body)) {
-
- throw new Exception(_m('Empty HTTP body in response.'));
- }
-
- $document = new SimpleXMLElement($body);
-
- $children = $document->children();
- if (count($children) == 0) {
- return array();
- }
- if (isset($document->status)) {
-
-
- throw new Exception(sprintf(_m('Error #%1$s ("%2$s").'),$document->status['value'],$document->status['message']));
- }
-
- return $document->geoname;
- }
- function onPluginVersion(array &$versions)
- {
- $versions[] = array('name' => 'Geonames',
- 'version' => self::PLUGIN_VERSION,
- 'author' => 'Evan Prodromou',
- 'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/Geonames',
- 'rawdescription' =>
-
- _m('Uses <a href="http://geonames.org/">Geonames</a> service to get human-readable '.
- 'names for locations based on user-provided lat/long pairs.'));
- return true;
- }
- function canonical($coord)
- {
- $coord = rtrim($coord, "0");
- $coord = rtrim($coord, ".");
- return $coord;
- }
- }
|