X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FGeonamesPlugin.php;h=52cc9c97f94b48a52c7dcdaae09a3e0eb97b371c;hb=f026ecec322e59899b5ce87abaa6d93738f67b9e;hp=e18957c36d9dd561cca16fee49fd8d45a1250cf9;hpb=088081675fb7d5250a9b9dfe5015de0822cb5ac2;p=quix0rs-gnu-social.git diff --git a/plugins/GeonamesPlugin.php b/plugins/GeonamesPlugin.php index e18957c36d..52cc9c97f9 100644 --- a/plugins/GeonamesPlugin.php +++ b/plugins/GeonamesPlugin.php @@ -49,7 +49,12 @@ if (!defined('STATUSNET')) { class GeonamesPlugin extends Plugin { - const NAMESPACE = 1; + const LOCATION_NS = 1; + + public $host = 'ws.geonames.org'; + public $username = null; + public $token = null; + public $expiry = 7776000; // 90-day expiry /** * convert a name into a Location object @@ -63,37 +68,41 @@ class GeonamesPlugin extends Plugin function onLocationFromName($name, $language, &$location) { - $client = HTTPClient::start(); + $loc = $this->getCache(array('name' => $name, + 'language' => $language)); - // XXX: break down a name by commas, narrow by each - - $str = http_build_query(array('maxRows' => 1, - 'q' => $name, - 'lang' => $language, - 'type' => 'json')); + if (!empty($loc)) { + $location = $loc; + return false; + } - $result = $client->get('http://ws.geonames.org/search?'.$str); + 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 ($result->isOk()) { - $rj = json_decode($result->getBody()); - if (count($rj->geonames) > 0) { - $n = $rj->geonames[0]; + $n = $geonames[0]; - $location = new Location(); + $location = new Location(); - $location->lat = $n->lat; - $location->lon = $n->lng; - $location->names[$language] = $n->name; - $location->location_id = $n->geonameId; - $location->location_ns = self::NAMESPACE; + $location->lat = (string)$n->lat; + $location->lon = (string)$n->lng; + $location->names[$language] = (string)$n->name; + $location->location_id = (string)$n->geonameId; + $location->location_ns = self::LOCATION_NS; - // handled, don't continue processing! - return false; - } - } + $this->setCache(array('name' => $name, + 'language' => $language), + $location); - // Continue processing; we don't have the answer - return true; + // handled, don't continue processing! + return false; } /** @@ -109,49 +118,53 @@ class GeonamesPlugin extends Plugin function onLocationFromId($id, $ns, $language, &$location) { - if ($ns != self::NAMESPACE) { + if ($ns != self::LOCATION_NS) { // It's not one of our IDs... keep processing return true; } - $client = HTTPClient::start(); + $loc = $this->getCache(array('id' => $id)); - $str = http_build_query(array('geonameId' => $id, - 'lang' => $language)); - - $result = $client->get('http://ws.geonames.org/hierarchyJSON?'.$str); - - if ($result->isOk()) { + if (!empty($loc)) { + $location = $loc; + return false; + } - $rj = json_decode($result->getBody()); + 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($rj->geonames) > 0) { + $parts = array(); - $parts = array(); + foreach ($geonames as $level) { + if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = (string)$level->name; + } + } - foreach ($rj->geonames as $level) { - if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $level->name; - } - } + $last = $geonames[count($geonames)-1]; - $last = $rj->geonames[count($rj->geonames)-1]; + if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = (string)$last->name; + } - if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $last->name; - } + $location = new Location(); - $location = new Location(); + $location->location_id = (string)$last->geonameId; + $location->location_ns = self::LOCATION_NS; + $location->lat = (string)$last->lat; + $location->lon = (string)$last->lng; + $location->names[$language] = implode(', ', array_reverse($parts)); - $location->location_id = $last->geonameId; - $location->location_ns = self::NAMESPACE; - $location->lat = $last->lat; - $location->lon = $last->lng; - $location->names[$language] = implode(', ', array_reverse($parts)); - } - } + $this->setCache(array('id' => (string)$last->geonameId), + $location); - // We're responsible for this NAMESPACE; nobody else + // We're responsible for this namespace; nobody else // can resolve it return false; @@ -173,53 +186,57 @@ class GeonamesPlugin extends Plugin function onLocationFromLatLon($lat, $lon, $language, &$location) { - $client = HTTPClient::start(); + $lat = rtrim($lat, "0"); + $lon = rtrim($lon, "0"); - $str = http_build_query(array('lat' => $lat, - 'lng' => $lon, - 'lang' => $language)); + $loc = $this->getCache(array('lat' => $lat, + 'lon' => $lon)); - $result = - $client->get('http://ws.geonames.org/findNearbyPlaceNameJSON?'.$str); - - if ($result->isOk()) { - - $rj = json_decode($result->getBody()); - - if (count($rj->geonames) > 0) { + if (!empty($loc)) { + $location = $loc; + return false; + } - $n = $rj->geonames[0]; + 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; + } - $parts = array(); + $n = $geonames[0]; - $location = new Location(); + $parts = array(); - $parts[] = $n->name; + $location = new Location(); - if (!empty($n->adminName1)) { - $parts[] = $n->adminName1; - } + $parts[] = (string)$n->name; - if (!empty($n->countryName)) { - $parts[] = $n->countryName; - } + if (!empty($n->adminName1)) { + $parts[] = (string)$n->adminName1; + } - $location->location_id = $n->geonameId; - $location->location_ns = self::NAMESPACE; - $location->lat = $lat; - $location->lon = $lon; + if (!empty($n->countryName)) { + $parts[] = (string)$n->countryName; + } - $location->names[$language] = implode(', ', $parts); + $location->location_id = (string)$n->geonameId; + $location->location_ns = self::LOCATION_NS; + $location->lat = (string)$lat; + $location->lon = (string)$lon; - // Success! We handled it, so no further processing + $location->names[$language] = implode(', ', $parts); - return false; - } - } + $this->setCache(array('lat' => $lat, + 'lon' => $lon), + $location); - // For some reason we don't know, so pass. + // Success! We handled it, so no further processing - return true; + return false; } /** @@ -237,50 +254,56 @@ class GeonamesPlugin extends Plugin function onLocationNameLanguage($location, $language, &$name) { - if ($location->location_ns != self::NAMESPACE) { + if ($location->location_ns != self::LOCATION_NS) { // It's not one of our IDs... keep processing return true; } - $client = HTTPClient::start(); - - $str = http_build_query(array('geonameId' => $id, - 'lang' => $language)); + $id = $location->location_id; - $result = $client->get('http://ws.geonames.org/hierarchyJSON?'.$str); + $n = $this->getCache(array('id' => $id, + 'language' => $language)); - if ($result->isOk()) { - - $rj = json_decode($result->getBody()); + if (!empty($n)) { + $name = $n; + return false; + } - if (count($rj->geonames) > 0) { + 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(); + $parts = array(); - foreach ($rj->geonames as $level) { - if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $level->name; - } - } + foreach ($geonames as $level) { + if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = (string)$level->name; + } + } - $last = $rj->geonames[count($rj->geonames)-1]; + $last = $geonames[count($geonames)-1]; - if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { - $parts[] = $last->name; - } + if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) { + $parts[] = (string)$last->name; + } - if (count($parts)) { - $name = implode(', ', array_reverse($parts)); - return false; - } - } + if (count($parts)) { + $name = implode(', ', array_reverse($parts)); + $this->setCache(array('id' => $id, + 'language' => $language), + $name); } - return true; + return false; } /** - * Human-readable name for a location + * Human-readable URL for a location * * Given a location, we try to retrieve a geonames.org URL. * @@ -292,7 +315,7 @@ class GeonamesPlugin extends Plugin function onLocationUrl($location, &$url) { - if ($location->location_ns != self::NAMESPACE) { + if ($location->location_ns != self::LOCATION_NS) { // It's not one of our IDs... keep processing return true; } @@ -302,4 +325,117 @@ class GeonamesPlugin extends Plugin // it's been filled, so don't process further. return false; } + + /** + * Machine-readable name for a location + * + * Given a location, we try to retrieve a geonames.org URL. + * + * @param Location $location Location to get the url for + * @param string &$url Place to put the url + * + * @return boolean whether to continue + */ + + function onLocationRdfUrl($location, &$url) + { + if ($location->location_ns != self::LOCATION_NS) { + // It's not one of our IDs... keep processing + return true; + } + + $url = 'http://sw.geonames.org/' . $location->location_id . '/'; + + // it's been filled, so don't process further. + return false; + } + + function getCache($attrs) + { + $c = common_memcache(); + + if (empty($c)) { + return null; + } + + $key = $this->cacheKey($attrs); + + $value = $c->get($key); + + return $value; + } + + function setCache($attrs, $loc) + { + $c = common_memcache(); + + if (empty($c)) { + return null; + } + + $key = $this->cacheKey($attrs); + + $result = $c->set($key, $loc, 0, time() + $this->expiry); + + return $result; + } + + function cacheKey($attrs) + { + return common_cache_key('geonames:'. + implode(',', array_keys($attrs)) . ':'. + common_keyize(implode(',', array_values($attrs)))); + } + + 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) + { + $client = HTTPClient::start(); + + $result = $client->get($this->wsUrl($method, $params)); + + if (!$result->isOk()) { + throw new Exception("HTTP error code " . $result->code); + } + + $document = new SimpleXMLElement($result->getBody()); + + if (empty($document)) { + throw new Exception("No results in response"); + } + + if (isset($document->status)) { + throw new Exception("Error #".$document->status['value']." ('".$document->status['message']."')"); + } + + // Array of elements + + return $document->geoname; + } + + function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'Geonames', + 'version' => STATUSNET_VERSION, + 'author' => 'Evan Prodromou', + 'homepage' => 'http://status.net/wiki/Plugin:Geonames', + 'rawdescription' => + _m('Uses Geonames service to get human-readable '. + 'names for locations based on user-provided lat/long pairs.')); + return true; + } }