Tuesday, September 15, 2015

Geographical information lookup using GeoNames

Geographical information integration is rapidly becoming an integral part of many websites. People use geographic data for a wide variety of applications. From location based content targeting, censoring information by geographic areas to analyzing website traffic by region. It is surprising how much free geographic information is available on the web. GeoNames is one such service.

The GeoNames database

GeoNames is a geographical database released under the creative commons attribution license, that contains over eight million geographical names and consists of 7 million unique features. The data is accessible free of charge through a number of web services and also as a downloadable database, which is updated on a daily basis.
GeoNames integrates geographical data such as names of places in various languages, elevation, population and other geographical information from various sources around the world.
In this post we will see how we can access the GeoNames API with PHP.

Installing the GeoNames API library

GeoNames API is available as a PEAR package, so we will be using the PEAR installer. Run the following command from your console window.
pear install Services_GeoNames-1.0.0
If the installer doexn’t work you can manually download the package fromServices_GeoNames and install it in your PHP includes folder.

Running your first GeoNames search

Now that we have installed the PEAR library, we will start with a small example that will get a list of places by the name ‘London’ and the country where the place is located. You will be surprised how many places the world over are named ‘London’.
<?php
require_once 'Services/GeoNames.php';
 
$geo = new Services_GeoNames();
 
// Search for all cities named 'London'
$cities = $geo->search(array('name_equals' => "London"));
 
foreach ($cities as $city)
{
    // 'name' and 'countryName' are not the only properties
    // available. Do a 'var_dump' on the $city variable to 
    // get other properties.
    printf(" - %s (%s)\n", $city->name, $city->countryName);
}
 
?>
Below is a partial output listing for the above code:
 - London (United Kingdom)
 - London (Canada)
 - London (United States)
 - London (United States)
 - City of London (United Kingdom)
 - London (South Africa)
 - London (South Africa)
 - London (South Africa)
 - London (Philippines)
 - London (Nigeria)
 - London (Switzerland)
.
.
Lets try another API method. The following returns a list of all the countries and its capitals.
<?php
 
require_once 'Services/GeoNames.php';
 
$geo = new Services_GeoNames();
 
// get a list of all countries and capitals
$countries = $geo->countryInfo();
 
foreach ($countries as $country)
{
    printf(" - %s (%s)\n", $country->countryName, $country->capital);
}
 
?>
One of the interesting method in the API is ‘neighbors’, which gets a list of neighbors for a particular country.
<?php
 
require_once 'Services/GeoNames.php';
 
$geo = new Services_GeoNames();
 
// Get a list of neighboring countries of India
$array  = $geo->countryInfo(array('country' => 'IN'));
$cInfo  = $array[0];
 
$neighbours = $geo->neighbours(array('geonameId' => $cInfo->geonameId));
 
foreach ($neighbours as $neighbor)
{
    printf("%s\n", $neighbour->countryName);
}
 
?>
Which outputs the following; the neighbouring countries of ‘India':
Bangladesh
Bhutan
China
Myanmar
Nepal
Pakistan

API function list

There are many methods available in the class for querying various type of geographic data. Below is the complete list of methods available in the API class.
 
array    children()                children(array $params)
array    cities()                  cities(array $params)
stdclass countryCode()             countryCode(array $params)
array    countryInfo()             countryInfo(array $params)
stdclass countrySubdivision()      countrySubdivision(array $params)
array    earthquakes()             earthquakes(array $params)
array    findNearby()              findNearby(array $params)
array    findNearbyPlaceName()     findNearbyPlaceName(array $params)
array    findNearbyPostalCodes()   findNearbyPostalCodes(array $params)
array    findNearbyStreets()       findNearbyStreets(array $params)
stdclass findNearByWeather()       findNearByWeather(array $params)
array    findNearbyWikipedia()     findNearbyWikipedia(array $params)
stdclass findNearestAddress()      findNearestAddress(array $params)
stdclass findNearestIntersection() findNearestIntersection(array $params)
stdclass get()                     get(array $params)
stdclass gtopo30()                 gtopo30(array $params)
array    hierarchy()               hierarchy(array $params)
stdclass neighbourhood()           neighbourhood(array $params)
array    neighbours()              neighbours(array $params)
array    postalCodeCountryInfo()   postalCodeCountryInfo(array $params)
array    postalCodeLookup()        postalCodeLookup(array $params)
array    postalCodeSearch()        postalCodeSearch(array $params)
array    search()                  search(array $params)
array    siblings()                siblings(array $params)
array    weather()                 weather(array $params)
stdclass weatherIcao()             weatherIcao(array $params)
stdclass srtm3()                   srtm3(array $params)
stdclass timezone()                timezone(array $params)
array    wikipediaBoundingBox()    wikipediaBoundingBox(array $params)
array    wikipediaSearch()         wikipediaSearch(array $params)

Performing a generic search

The API provides a general name search which can be helpful if you need to perform some broad query for a search term. Lets take the following example. We use the ‘search’ method to query for the keyword ‘los angeles’. The method takes an array with the query term and the number of results to return. Note that the parameter ‘q’ searches over all attributes of a place : place name, country name, continent, admin codes etc. There are more parameter options besides ‘q’ and ‘maxRows’ which you can use while performing search.
<?php
 
require_once 'Services/GeoNames.php';
 
$geo = new Services_GeoNames();
 
$results = $geo->search(
                        array('q' => "los angeles",
                              'maxRows' => 10)
                        );
 
print_r($results);
 
?>
Below is the first result for the search term ‘los angeles’.
[countryName] => United States
[adminCode1] => CA
[fclName] => city, village,...
[countryCode] => US
[lng] => -118.2436849
[fcodeName] => populated place
[fcl] => P
[name] => Los Angeles
[fcode] => PPL
[geonameId] => 5368361
[lat] => 34.0522342
[population] => 3694820
[adminName1] => California

Using the GeoService API in your applications

Although the API provides a free service, if your are planning to use it in a critical web application, the company provides a commercial option for the same. The advantage of the commercial option is that the web services have higher up-time and fail-over in case of hardware defects or software bugs.
The API allows a limit of 50000 web access per day-per IP, which should be quite enough for most personal projects. Check the limit information here for further details.

Downloading the database

All the information you can gather from the API is also available for download from GeoNames servers in text format. This can be useful if you would like to create your own database for hosting on your servers for data lookup. But bear in mind that the data is frequently updated, so your custom created database will quickly become outdated, which does not happen with the online API. And also you will have to write your own queries for the created database.

Accessing the GeoNames API with jQuery

As an aside you can use the following example code to access the API web-service from javascript using jQuery.
 
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<div id="data"></div>
 
<script>
 
/* 
  Searches for the keyword 'london', 
  returning a maximum of 5 rows. 
  More information can be found here: 
  http://www.geonames.org/export/geonames-search.html
*/
 
/* 
  Note you need to append 'JSON' to the method 
  name to get the results back in JSON format.
*/  
var apiMethod  = 'searchJSON';
var parameters = 'q=london&maxRows=5';
var result     = '';
 
$.get('http://ws.geonames.org/' + 
      apiMethod + '?' + parameters, function(data) {
 
        $.each(data['geonames'], function(i,item){
           $.each(item, function(j, field){
                result += "(" + j + ") : " + field + "<br/>";
           });
           result += "<br />";
          });
 
$('#data').html(result);          
});
</script>
</body>
</html>
http://www.codediesel.com/libraries/geographical-information-lookup-using-geonames/