In my application, I am using the location module (non-CCK). I require nodes to have country, state / province and city. I harvest country and state via dropdown selects (and thus have the alphanumeric code provided by location module). City is then entered via a location-module text field.

I am very impressed with the geonames service and appreciate the work done here but I find the documentation a little thin - - and BTW, I would be happy to contribute code examples and other How-To's once I get my arms around this.

So - - Given country and state / province, I would like to do the following:

1) obtain a list of named cities for this country and state / province pair.
Having obtained this, I would then make certain the city is correctly entered.

2) once I have a valid a city, if the user enters zip / postal (this field is optional), I would then like to obtain a list of zip / postal codes for that city and make certain that the city - zip pair is valid.

3) alternatively, if the user enters zip / postal first, and then city, I would like to submit country and zip / postal and then check the city.

timely help would be greatly appreciated and I reiterate my offer to help - - and this includes creation of graphics if needed.

I have tried many variations using the geonames_query function with no luck.

thanks so much

S

CommentFileSizeAuthor
#3 Execute PHP Code | localhost.png204.63 KBlyricnz

Comments

lyricnz’s picture

Priority: Critical » Normal

These are really questions for the Geonames service itself: this module only implements the XML web-services described at http://www.geonames.org/export/ws-overview.html.

Your queries may be better resolved by taking a complete dump of their data, and making SQL queries directly. Unfortunately, geonames doesn't seem to have APIs that directly correspond to your situation.

1) Do you really need to get a list of cities? Can't you just check it once they enter it, with a call to "search", restricted to the right (exact) name, Country+State/Province and restricted to type "PPL" (populated place).

eg: http://ws.geonames.org/search?name_equals=Miami&adminCode1=FL&country=US...

Or in PHP code:

    $query = array('name_equals' => 'Miami', 'adminCode1' => 'FL', 'country' => 'US', 'fcode' => 'PPL');
    $results = geonames_query('search', $query);
    if ($results->total_results_count > 1) {
       // look in $results->results for more information about the place(s) that were found
    }

You could even do a similar search to provide an auto-complete function.

2-3) Again, do you really need a list? Check a particular postal code using the "postalCodeSearch" service

eg: http://ws.geonames.org/postalCodeSearch?postalcode=33130&placename=Miami

Or in PHP code:

    $query = array('postalcode' => 33130, 'placename' => 'Miami');
    $results = geonames_query('postalcodesearch', $query);
    if ($results->total_results_count > 1) {
       // look in $results->results for more information about the place(s) that were found
    }

HTH, this response took quite a while to write.

newtonpage’s picture

@ lyricnz

Thanks so much for your detailed reply. I had tried variations of the code you suggested before posting without favorable results.

You make excellent points concerning the approach and I am planning to make individual queries during a node addition from the geonames DB for the moment. I will then work on creating our own tables and refresh from the geoname dumps.

Regarding the geonames drupal module and the suggested code, here is what I have done as test:

First the city:

//try it with drupal module
$d_query = array('name_equals' => 'Miami', 'adminCode1' => 'FL', 'country' => 'US', 'fcode' => 'PPL');
$d_city_results = geonames_query('search', $d_query);

$d_city_valid = FALSE;
if ($d_city_valid->total_results_count >= 1) {
	$d_city_valid = TRUE;
}

print "checking the drupal fetch --> the city is ".$d_city_valid."<br />";

This does not work as shown below.

Examining the returned data (only the relevant section is shown):

dpr($d_city_results);

stdClass Object
(
    [standalone] => no
    [total_results_count] => 0
    [service] => search
    [request] => Array
        (
            [url] => http://ws.geonames.net/search?username=ME&adminCode1=FL&name_equals=Miami&country=US&featureClass=P&maxRows=15
            [bytes] => 255
            [cached] => result
            [seconds] => 0.00788307189941
        )

    [query] => Array
        (
            [admincode1] => FL
            [name_equals] => Miami
            [fcode] => PPL
            [country] => US
            [startrow] => 0
            [featureclass] => p
            [type] => xml
            [maxrows] => 15
        )
. . . and so on

However, doing the same without using the module (with somewhat more ponderous code):

$city = "Chicago";
$country = "US";
$state = "IL";

$city_query = "name_equals=".$city."&adminCode1=".$state."&country=".$country."&maxRows=1";
$url = "http://ws.geonames.org/searchJSON?".$city_query;
$check_city = drupal_http_request($url, $headers = array(), $method = 'GET', $data = NULL, $retry = 3);

//decode the json
$city_results = json_decode($check_city->data);

$city_valid = FALSE;
if ($city_results->totalResultsCount === 1) {
	$city_valid = TRUE;
}
print "checking the http fetch --> the city is ".$city_valid."<br />";

This does work - - noting the camel-case in the returned object for totalResultsCount (versus underscore in the Drupal case).

Obviously, I would like to use the drupal module, but I cannot seem to make this query work.

I have similar results for zip - - this works:

$city = "Chicago";
$country = "US";
$state = "IL";
$zip = 60615;

$zip_query = "&placename=".$city."&adminCode1=".$state."&postalcode=".$zip."&maxRows=200";
$url = "http://ws.geonames.org/postalCodeSearchJSON?".$zip_query;
$check_zip = drupal_http_request($url, $headers = array(), $method = 'GET', $data = NULL, $retry = 3);

$zip_results = json_decode($check_zip->data);

//this returns an object with the results in an array - - so get  the array and count the results
$postal_codes_array = $zip_results->postalCodes;
$postal_codes_array_length = count($postal_codes_array);

//then test if this is greater than 0

Whereas this does not work (in any variation I tried):

$d_zip_valid = FALSE;
$d_zip_query = array('postalcode' => 60615, 'placename' => 'Chicago', 'adminCode1' => 'IL');
$d_zip_results = geonames_query('postalcodesearch', $d_zip_query);

if ($d_zip_results->total_results_count === 1) {
	$d_zip_valid = TRUE;
}


So - - net-net: thank you so much for your help and consideration. I have to say that I do not understand why the drupal-based query (that is, the geonames module-based) query does not work, and I am sure it must be me since this (simple) application of the api must have been tested.

Again, suggestion welcome as I would prefer to do this within Drupal.

If you are interested, I will let you know as I continue to try to get this to work.

Thank again.

N

lyricnz’s picture

StatusFileSize
new204.63 KB

Are you using the latest (dev) version of geonames? I literally just ran the following PHP, and it worked fine (see screenshot).

$query = array('name_equals' => 'Miami', 'adminCode1' => 'FL', 'country' => 'US', 'fcode' => 'PPL');
$results = geonames_query('search', $query);
dsm($results);
lyricnz’s picture

PS: your code actually has a bug:

$d_city_results = geonames_query('search', $d_query);
$d_city_valid = FALSE;
if ($d_city_valid->total_results_count >= 1) {
  $d_city_valid = TRUE;
}

The third line should be checking $d_city_results->total_results_count not $d_city_valid->total_results_count

lyricnz’s picture

PPS: in your second example above, you can see the request URL is http://ws.geonames.net/search?username=ME&adminCode1=FL&name_equals=Miam...

If you open this in your browser, and view source, you can see the following XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<geonames>
<status message="Please provide a valid username for the commercial GeoNames web service or use the free ws.geonames.org server. Thank you for your understanding." value="10"/>
</geonames>

It looks like you've configured a username as "ME" which should only be set if you have a paid-for commercial agreement with geonames.org. See the configuration in the "Geonames Commercial Webservices" section of the Geonames admin settings at /admin/settings/geonames

lyricnz’s picture

PPPS: I just fixed the support for returning error messages from geonames in #667744: Bad status messages from geonames not returned to user.

Also, I suggest you disable caching of geonames (in the geonames settings) while you're testing this kind of thing, or it might mess up your tests.

lyricnz’s picture

Status: Active » Closed (fixed)

No feedback for a month, closing.