0

I'm using the following code to turn user's IP into latitude/longitude information using the hostip web service:

//get user's location
$ip=$_SERVER['REMOTE_ADDR'];

function get_location($ip) {
    $content = file_get_contents('http://api.hostip.info/?ip='.$ip);
    if ($content != FALSE) {
        $xml = new SimpleXmlElement($content);
        $coordinates = $xml->children('gml', TRUE)->featureMember->children('', TRUE)->Hostip->ipLocation->children('gml', TRUE)->pointProperty->Point->coordinates;
        $longlat = explode(',', $coordinates);
        $location['longitude'] = $longlat[0];
        $location['latitude'] = $longlat[1];        
                $location['citystate'] = '==>'.$xml->children('gml', TRUE)->featureMember->children('', TRUE)->Hostip->children('gml', TRUE)->name;
        $location['country'] =  '==>'.$xml->children('gml', TRUE)->featureMember->children('', TRUE)->Hostip->countryName;
        return $location;
    }
    else return false;
}

$data = get_location($ip);

$center_long=$data['latitude'];
$center_lat=$data['longitude'];

This works fine for me, using $center_long and $center_lat the google map on the page is centered around my city, but I have a friend in Thailand who tested it from there, and he got this error:

Warning: get_location() [function.get-location]: Node no longer exists in /home/bedbugs/registry/index.php on line 21

So I'm completely confused by this, how could he be getting an error if I don't? I tried googling it and it has something to do with parsing XML data, but the parsing process is the same for me and him. Note that line 21 is the one that starts with '$coordinates =' .

robert
  • 811
  • 3
  • 16
  • 28
  • 1
    remove the error suppression please. You cant expect us to do blindfold debugging. – Gordon Feb 25 '12 at 09:56
  • of course, sorry, but I don't get an error with error suppression removed either, as I said, the function works perfectly for me. – robert Feb 25 '12 at 09:58
  • well, do you have [error reporting enabled](http://stackoverflow.com/questions/6575482/php-how-do-i-enable-error-reporting)? can you provide the XML you expect to get back from that service? Which $ip did your friend use? – Gordon Feb 25 '12 at 10:02
  • I just enabled all errors, didn't get anything relevant, just a bunch of stuff to do with date() and strtotime(), completely unrelated to this. You can view the XML output here: http://www.randomsnippets.com/2011/02/03/parsing-xml-data-from-hostip-info-api-service-php/ – robert Feb 25 '12 at 10:07
  • I don't know about his IP, I'll add some echos to the page the next time he's online to check it out, but he's unavailable right now. – robert Feb 25 '12 at 10:09

1 Answers1

2

You need to check the service actually has an <ipLocation> listed, you're doing:

$xml->children('gml', TRUE)->featureMember->children('', TRUE)->Hostip->ipLocation
    ->children('gml', TRUE)->pointProperty->Point->coordinates

but the XML output for my IP is:

<HostipLookupResultSet version="1.0.1" xsi:noNamespaceSchemaLocation="http://www.hostip.info/api/hostip-1.0.1.xsd">
  <gml:description>This is the Hostip Lookup Service</gml:description>
  <gml:name>hostip</gml:name>
  <gml:boundedBy>
    <gml:Null>inapplicable</gml:Null>
  </gml:boundedBy>
  <gml:featureMember>
    <Hostip>
      <ip>...</ip>
      <gml:name>(Unknown City?)</gml:name>
      <countryName>(Unknown Country?)</countryName>
      <countryAbbrev>XX</countryAbbrev>
      <!-- Co-ordinates are unavailable -->
    </Hostip>
  </gml:featureMember>
</HostipLookupResultSet>

The last part ->children('gml', TRUE)->pointProperty->Point->coordinates gives the error because it has no children (for some IPs).


You can add a basic check to see if the <ipLocation> node exists like this (assuming the service always returns at least up to the <hostIp> node):

function get_location($ip) {
    $content = file_get_contents('http://api.hostip.info/?ip='.$ip);
    if ($content === FALSE) return false;

    $location = array('latitude' => 'unknown', 'longitude' => 'unknown');
    $xml = new SimpleXmlElement($content);
    $hostIpNode = $xml->children('gml', TRUE)->featureMember->children('', TRUE)->Hostip;
    if ($hostIpNode->ipLocation) {
        $coordinates = $hostIpNode->ipLocation->children('gml', TRUE)->pointProperty->Point->coordinates;
        $longlat = explode(',', $coordinates);
        $location['longitude'] = $longlat[0];
        $location['latitude'] = $longlat[1];     
    }

    $location['citystate'] = '==>'.$hostIpNode->children('gml', TRUE)->name;
    $location['country'] =  '==>'.$hostIpNode->countryName;
    return $location;
}
pjumble
  • 16,880
  • 6
  • 43
  • 51
  • I see. How do I add that check? Sorry, I haven't worked with XML much, I'm really lost here. – robert Feb 25 '12 at 10:28
  • Also, can you perhaps recommend a better web service for geolocation, since this one seems to not work for a lot of IPs? – robert Feb 25 '12 at 10:31
  • I updated my answer with (basic) checking. I'm not sure which geolocation services are better, but there's some [suggestions here](http://stackoverflow.com/questions/283016/know-a-good-ip-address-geolocation-service) – pjumble Feb 25 '12 at 10:49
  • Thanks, I did that and added a condition that centers the map at a default point in North America in case the function doesn't return the data, now there is no error and the map is displayed one way or another. – robert Feb 25 '12 at 11:01