2

I have the following script that uses the api on hostip.info. The page parses an xml readout of a user location based on the ip address. In my function everything is working except for the city.

preg_match("@<Hostip>(\s)*<gml:name>(.*?)</gml:name>@si",$xml,$city_match);

I have narrowed it down to my preg_match being wrong but I'm not sure how to fix it. Here is a sample xml output: http://api.hostip.info/?ip=12.215.42.19

<?php
function getCountryCity()
{
    if(isset($_SERVER['REMOTE_ADDR']) && strlen($_SERVER['REMOTE_ADDR']) > 0)  {
        $ipAddr = $_SERVER['REMOTE_ADDR'];
        // verify the IP address
        ip2long($ipAddr)== -1 || ip2long($ipAddr) === false ? trigger_error("Invalid IP", E_USER_ERROR) : "";

        $ipDetail=array();
        // get the XML result from hostip.info
        $xml = file_get_contents("http://api.hostip.info/?ip=".$ipAddr);

        // get the city name inside the node <gml:name> and </gml:name>
        preg_match("@<Hostip>(\s)*<gml:name>(.*?)</gml:name>@si",$xml,$city_match);
        $ipDetail['city'] = $city_match[1]; 

        // get the country name inside the node <countryName> and </countryName>
        preg_match("@<countryName>(.*?)</countryName>@si",$xml,$country_match);
        $ipDetail['country'] = $country_match[1];

        // get the country name inside the node <countryName> and </countryName>
        preg_match("@<countryAbbrev>(.*?)</countryAbbrev>@si",$xml,$cc_match);
        $ipDetail['country_code'] = $cc_match[1];

        // return the array containing city, country and country code
        return $ipDetail;
    } else {
        return false;
    }
}

$ipDetail = getCountryCity();
$user_city = $ipDetail['city'];
$user_country = $ipDetail['country'];
$user_cc = $ipDetail['country_code'];

echo $user_country.' ('.$user_cc.')';
echo $user_city;

?>
8
  • 1
    Is there a reason you cannot use an XML parser for this? Commented Aug 9, 2012 at 14:21
  • this would be literally the only thing i need an xml parser for, not sure if its worth installing if this stupid preg replace is easily fixable Commented Aug 9, 2012 at 14:22
  • What PHP version are you running? Commented Aug 9, 2012 at 14:23
  • im running 5.4.5 locally but 5.2.17 online Commented Aug 9, 2012 at 14:26
  • 1
    You can (and should IMHO) use DOMDocument which is in PHP by default as of 5. because regex is not suitable to parse HTML. Even if it doesn't bite you in the ass right now it will in the future. Commented Aug 9, 2012 at 14:39

3 Answers 3

1

XPATH is a dream for this kind of stuff. Google "SimpleXML PHP Tutorial" if this is new to you. Basically:

$xml = new SimpleXMLElement($yourXML);
$user_city = $xml->xpath('//gml:name/text()');
$user_country= $xml->xpath('//countryName/text()');
$cc= $xml->xpath('//countryAbbrev/text()');

I find XPATH queries to be much easier to write than RegEx.

Sorry this doesn't answer your question as directly as you want. tried to post in a comment but the formatting gets totally screwed up

Sign up to request clarification or add additional context in comments.

1 Comment

thanks man i voted yours up but i made a more rubust solution that i can use
1
preg_match_all("@<gml:name>(.*?)</gml:name>@si",$xml,$city_match);

just remove <Hostip>(\s)* and use preg_match_all it will take all the tags. Then you can select one you need in array.

Comments

0
function getCountryCity() {
    if(isset($_SERVER['REMOTE_ADDR']) && strlen($_SERVER['REMOTE_ADDR']) > 0)  {
        $user_ip = $_SERVER['REMOTE_ADDR'];
        $response = file_get_contents('http://api.hostip.info/?ip='.$user_ip);
        $user_details = array();
        $xml = new DOMDocument();
        $xml->loadXml($response);
        $xpath = new DOMXpath($xml);
        $path = '/HostipLookupResultSet/gml:featureMember/Hostip/';

        // create values for array
        $ip = $xpath->evaluate($path . 'ip')->item(0)->nodeValue;
        $city = $xpath->evaluate($path . 'gml:name')->item(0)->nodeValue;
        $countryName = $xpath->evaluate($path . 'countryName')->item(0)->nodeValue;
        $countryAbbrev = $xpath->evaluate($path . 'countryAbbrev')->item(0)->nodeValue;

        // assign values to array
        $user_details['ip'] = $ip;
        $user_details['city'] = $city;
        $user_details['countryName'] = $countryName;
        $user_details['countryAbbrev'] = $countryAbbrev;

        return $user_details;
    } else {
        return false;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.