Getting the location from an IP address

PhpGeolocationIpGeoip

Php Problem Overview


I want to retrieve information like the city, state, and country of a visitor from their IP address, so that I can customize my web page according to their location. Is there a good and reliable way to do this in PHP? I am using JavaScript for client-side scripting, PHP for server-side scripting, and MySQL for the database.

Php Solutions


Solution 1 - Php

You could download a free GeoIP database and lookup the IP address locally, or you could use a third party service and perform a remote lookup. This is the simpler option, as it requires no setup, but it does introduce additional latency.

One third party service you could use is mine, http://ipinfo.io. They provide hostname, geolocation, network owner and additional information, eg:

$ curl ipinfo.io/8.8.8.8
{
  "ip": "8.8.8.8",
  "hostname": "google-public-dns-a.google.com",
  "loc": "37.385999999999996,-122.0838",
  "org": "AS15169 Google Inc.",
  "city": "Mountain View",
  "region": "CA",
  "country": "US",
  "phone": 650
}

Here's a PHP example:

$ip = $_SERVER['REMOTE_ADDR'];
$details = json_decode(file_get_contents("http://ipinfo.io/{$ip}/json"));
echo $details->city; // -> "Mountain View"

You can also use it client-side. Here's a simple jQuery example:

$.get("https://ipinfo.io/json", function (response) {
    $("#ip").html("IP: " + response.ip);
    $("#address").html("Location: " + response.city + ", " + response.region);
    $("#details").html(JSON.stringify(response, null, 4));
}, "jsonp");

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h3>Client side IP geolocation using <a href="http://ipinfo.io">ipinfo.io</a></h3>

<hr/>
<div id="ip"></div>
<div id="address"></div>
<hr/>Full response: <pre id="details"></pre>

Solution 2 - Php

Thought I'd post as nobody seems to have given info on this particular API, but its returning exactly what I'm after and you can get it to return in multiple formats, json, xml and csv.

 $location = file_get_contents('http://freegeoip.net/json/'.$_SERVER['REMOTE_ADDR']);
 print_r($location);

This will give you all of the things you could possibly want:

{
      "ip": "77.99.179.98",
      "country_code": "GB",
      "country_name": "United Kingdom",
      "region_code": "H9",
      "region_name": "London, City of",
      "city": "London",
      "zipcode": "",
      "latitude": 51.5142,
      "longitude": -0.0931,
      "metro_code": "",
      "areacode": ""

}

Solution 3 - Php

A pure Javascript example, using the services of https://geolocation-db.com They provide a JSON and JSONP-callback solution.

No jQuery required!

<!DOCTYPE html>
<html>
<head>
<title>Geo City Locator by geolocation-db.com</title>
</head>
<body>
    <div>Country: <span id="country"></span></div>
    <div>State: <span id="state"></span></div>
    <div>City: <span id="city"></span></div>
    <div>Postal: <span id="postal"></span></div>
    <div>Latitude: <span id="latitude"></span></div>
    <div>Longitude: <span id="longitude"></span></div>
    <div>IP address: <span id="ipv4"></span></div>                             
</body>
<script>

    var country = document.getElementById('country');
    var state = document.getElementById('state');
    var city = document.getElementById('city');
    var postal = document.getElementById('postal');
    var latitude = document.getElementById('latitude');
    var longitude = document.getElementById('longitude');
    var ip = document.getElementById('ipv4');

    function callback(data)
    {
        country.innerHTML = data.country_name;
        state.innerHTML = data.state;
        city.innerHTML = data.city;
        postal.innerHTML = data.postal;
        latitude.innerHTML = data.latitude;
        longitude.innerHTML = data.longitude;
        ip.innerHTML = data.IPv4;
    }

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'https://geolocation-db.com/json/geoip.php?jsonp=callback';
    var h = document.getElementsByTagName('script')[0];
    h.parentNode.insertBefore(script, h);

</script> 
</html>

Solution 4 - Php

Using Google APIS:

<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script>
contry_code = google.loader.ClientLocation.address.country_code
city = google.loader.ClientLocation.address.city
region = google.loader.ClientLocation.address.region
</script>

Solution 5 - Php

You need to use an external service... such as http://www.hostip.info/ if you google search for "geo-ip" you can get more results.

The Host-IP API is HTTP based so you can use it either in PHP or JavaScript depending on your needs.

Solution 6 - Php

I wrote a bot using an API from ipapi.co, here's how you can get location for an IP address (e.g. 1.2.3.4) in php :

Set header :

$opts = array('http'=>array('method'=>"GET", 'header'=>"User-Agent: mybot.v0.7.1"));
$context = stream_context_create($opts);

Get JSON response

echo file_get_contents('https://ipapi.co/1.2.3.4/json/', false, $context);

of get a specific field (country, timezone etc.)

echo file_get_contents('https://ipapi.co/1.2.3.4/country/', false, $context);

Solution 7 - Php

This question is protected, which I understand. However, I do not see an answer here, what I see is a lot of people showing what they came up with from having the same question.

There are currently five Regional Internet Registries with varying degrees of functionality that serve as the first point of contact with regard to IP ownership. The process is in flux, which is why the various services here work sometimes and don't at other times.

Who Is is (obviously) an ancient TCP protocol, however -- the way it worked originally was by connection to port 43, which makes it problematic getting it routed through leased connections, through firewalls...etc.

At this moment -- most Who Is is done via RESTful HTTP and ARIN, RIPE and APNIC have RESTful services that work. LACNIC's returns a 503 and AfriNIC apparently has no such API. (All have online services, however.)

That will get you -- the address of the IP's registered owner, but -- not your client's location -- you must get that from them and also -- you have to ask for it. Also, proxies are the least of your worries when validating the IP that you think is the originator.

People do not appreciate the notion that they are being tracked, so -- my thoughts are -- get it from your client directly and with their permission and expect a lot to balk at the notion.

Solution 8 - Php

Look at the API from hostip.info - it provides lots of information.
Example in PHP:

$data = file_get_contents("http://api.hostip.info/country.php?ip=12.215.42.19");
//$data contains: "US"

$data = file_get_contents("http://api.hostip.info/?ip=12.215.42.19");
//$data contains: XML with country, lat, long, city, etc...

If you trust hostip.info, it seems to be a very useful API.

Solution 9 - Php

I like the free GeoLite City from Maxmind which works for most applications and from which you can upgrade to a paying version if it's not precise enough. There is a PHP API included, as well as for other languages. And if you are running Lighttpd as a webserver, you can even use a module to get the information in the SERVER variable for every visitor if that's what you need.

I should add there is also a free Geolite Country (which would be faster if you don't need to pinpoint the city the IP is from) and Geolite ASN (if you want to know who owns the IP) and that finally all these are downloadable on your own server, are updated every month and are pretty quick to lookup with the provided APIs as they state "thousands of lookups per second".

Solution 10 - Php

The service in Ben Dowling's response has changed, so it's now simpler. To find the location, simply do:

// no need to pass ip any longer; ipinfo grabs the ip of the person requesting
$details = json_decode(file_get_contents("http://ipinfo.io/"));
echo $details->city; // city

The coordinates return in a single string like '31,-80', so from there you just:

$coordinates = explode(",", $details->loc); // -> '31,-89' becomes'31','-80'
echo $coordinates[0]; // latitude
echo $coordinates[1]; // longitude

Solution 11 - Php

I run the service at IPLocate.io, which you can hook into for free with one easy call:

<?php
$res = file_get_contents('https://www.iplocate.io/api/lookup/8.8.8.8');
$res = json_decode($res);

echo $res->country; // United States
echo $res->continent; // North America
echo $res->latitude; // 37.751
echo $res->longitude; // -97.822

var_dump($res);

The $res object will contain your geolocation fields like country, city, etc.

Check out the docs for more information.

Solution 12 - Php

Assuming you want to do it yourself and not rely upon other providers, IP2Nation provides a MySQL database of the mappings which are updated as the regional registries change things around.

Solution 13 - Php

PHP has an extension for that.

From PHP.net:

> The GeoIP extension allows you to find the location of an IP address. > City, State, Country, Longitude, Latitude, and other information as > all, such as ISP and connection type can be obtained with the help of > GeoIP.

For example:

$record = geoip_record_by_name($ip);
echo $record['city'];

Solution 14 - Php

In case anyone stumbles upon this thread, here's another solution. At timezoneapi.io you can request an IP address and get several objects in return (I've created the service). It was created because I needed to know which timezone my users were in, where in the world and what time it currently is.

In PHP - returns location, timezone and date/time:

// Get IP address
$ip_address = getenv('HTTP_CLIENT_IP') ?: getenv('HTTP_X_FORWARDED_FOR') ?: getenv('HTTP_X_FORWARDED') ?: getenv('HTTP_FORWARDED_FOR') ?: getenv('HTTP_FORWARDED') ?: getenv('REMOTE_ADDR');

// Get JSON object
$jsondata = file_get_contents("http://timezoneapi.io/api/ip/?" . $ip_address);

// Decode
$data = json_decode($jsondata, true);

// Request OK?
if($data['meta']['code'] == '200'){

    // Example: Get the city parameter
    echo "City: " . $data['data']['city'] . "<br>";

    // Example: Get the users time
    echo "Time: " . $data['data']['datetime']['date_time_txt'] . "<br>";

}

Using jQuery:

// Get JSON object
$.getJSON('https://timezoneapi.io/api/ip', function(data){

    // Request OK?
    if(data.meta.code == '200'){

        // Log
        console.log(data);

        // Example: Get the city parameter
        var city = data.data.city;
        alert(city);

        // Example: Get the users time
        var time = data.data.datetime.date_time_txt;
        alert(time);

    }

});

Solution 15 - Php

Ipdata.co is a fast, highly available IP Geolocation API with reliable performance.

It's extremely scalable with 10 endpoints around the world each able to handle >10,000 requests per second!

> This answer uses a 'test' API Key that is very limited and only meant for testing a few calls. Signup for your own Free API Key and get up to 1500 requests daily for development.

In php

php > $ip = '8.8.8.8';
php > $details = json_decode(file_get_contents("https://api.ipdata.co/{$ip}?api-key=test"));
php > echo $details->region;
California
php > echo $details->city;
Mountain View
php > echo $details->country_name;
United States
php > echo $details->latitude;
37.751

Here's a client-side example showing how you'd get the country, region and city;

$.get("https://api.ipdata.co?api-key=test", function (response) {
	$("#response").html(JSON.stringify(response, null, 4));
  $("#country").html('Country: ' + response.country_name);
  $("#region").html('Region ' + response.region);
  $("#city").html('City' + response.city);  
}, "jsonp");

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="country"></div>
<div id="region"></div>
<div id="city"></div>
<pre id="response"></pre>

Disclaimer;

I built the service.

For examples in multiple languages see the Docs

Also see this detailed analysis of the best IP Geolocation APIs.

Solution 16 - Php

If you need to get location from an IP address you can use reliable geo ip service, you can get more detail here. It supports IPv6.

As a bonus it allows to check whether ip address is a tor node, public proxy or spammer.

You can use javascript or php as below.

Javascript Code:

$(document).ready(function () {
        $('#btnGetIpDetail').click(function () {
            if ($('#txtIP').val() == '') {
                alert('IP address is reqired');
                return false;
            }
            $.getJSON("http://ip-api.io/json/" + $('#txtIP').val(),
                 function (result) {
                     alert('City Name: ' + result.city)
                     console.log(result);
                 });
        });
    });

Php Code:

$result = json_decode(file_get_contents('http://ip-api.io/json/64.30.228.118'));
var_dump($result);

Output:

{
"ip": "64.30.228.118",
"country_code": "US",
"country_name": "United States",
"region_code": "FL",
"region_name": "Florida",
"city": "Fort Lauderdale",
"zip_code": "33309",
"time_zone": "America/New_York",
"latitude": 26.1882,
"longitude": -80.1711,
"metro_code": 528,
"suspicious_factors": {
"is_proxy": false,
"is_tor_node": false,
"is_spam": false,
"is_suspicious": false
}

Solution 17 - Php

The following is a modified version of a snippet I found that uses http://ipinfodb.com/ip_locator.php to get its information. Keep in mind, you can also apply for an API key with them and use the API directly to get the information supplied as you see fit.

Snippet

function detect_location($ip=NULL, $asArray=FALSE) {
	if (empty($ip)) {
		if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; }
		elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; }
		else { $ip = $_SERVER['REMOTE_ADDR']; }
	}
	elseif (!is_string($ip) || strlen($ip) < 1 || $ip == '127.0.0.1' || $ip == 'localhost') {
		$ip = '8.8.8.8';
	}
	
	$url = 'http://ipinfodb.com/ip_locator.php?ip=' . urlencode($ip);
	$i = 0; $content; $curl_info;
	
	while (empty($content) && $i < 5) {
		$ch = curl_init();
		$curl_opt = array(
			CURLOPT_FOLLOWLOCATION => 1,
			CURLOPT_HEADER => 0,
			CURLOPT_RETURNTRANSFER  => 1,
			CURLOPT_URL => $url,
			CURLOPT_TIMEOUT => 1,
			CURLOPT_REFERER => 'http://' . $_SERVER['HTTP_HOST'],
		);
		if (isset($_SERVER['HTTP_USER_AGENT'])) $curl_opt[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
		curl_setopt_array($ch, $curl_opt);
		$content = curl_exec($ch);
		if (!is_null($curl_info)) $curl_info = curl_getinfo($ch);
		curl_close($ch);
	}
	
	$araResp = array();
	if (preg_match('{<li>City : ([^<]*)</li>}i', $content, $regs)) $araResp['city'] = trim($regs[1]);
	if (preg_match('{<li>State/Province : ([^<]*)</li>}i', $content, $regs)) $araResp['state'] = trim($regs[1]);
	if (preg_match('{<li>Country : ([^<]*)}i', $content, $regs)) $araResp['country'] = trim($regs[1]);
	if (preg_match('{<li>Zip or postal code : ([^<]*)</li>}i', $content, $regs)) $araResp['zip'] = trim($regs[1]);
	if (preg_match('{<li>Latitude : ([^<]*)</li>}i', $content, $regs)) $araResp['latitude'] = trim($regs[1]);
	if (preg_match('{<li>Longitude : ([^<]*)</li>}i', $content, $regs)) $araResp['longitude'] = trim($regs[1]);
	if (preg_match('{<li>Timezone : ([^<]*)</li>}i', $content, $regs)) $araResp['timezone'] = trim($regs[1]);
	if (preg_match('{<li>Hostname : ([^<]*)</li>}i', $content, $regs)) $araResp['hostname'] = trim($regs[1]);
	
	$strResp = ($araResp['city'] != '' && $araResp['state'] != '') ? ($araResp['city'] . ', ' . $araResp['state']) : 'UNKNOWN';
	
	return $asArray ? $araResp : $strResp;
}

To Use

detect_location();
//	returns "CITY, STATE" based on user IP

detect_location('xxx.xxx.xxx.xxx');
//	returns "CITY, STATE" based on IP you provide

detect_location(NULL, TRUE);	//	 based on user IP
//	returns array(8) { ["city"] => "CITY", ["state"] => "STATE", ["country"] => "US", ["zip"] => "xxxxx", ["latitude"] => "xx.xxxxxx", ["longitude"] => "-xx.xxxxxx", ["timezone"] => "-07:00", ["hostname"] => "xx-xx-xx-xx.host.name.net" }

detect_location('xxx.xxx.xxx.xxx', TRUE);	//	 based on IP you provide
//	returns array(8) { ["city"] => "CITY", ["state"] => "STATE", ["country"] => "US", ["zip"] => "xxxxx", ["latitude"] => "xx.xxxxxx", ["longitude"] => "-xx.xxxxxx", ["timezone"] => "-07:00", ["hostname"] => "xx-xx-xx-xx.host.name.net" }

Solution 18 - Php

You can also use "smart-ip" service:

$.getJSON("http://smart-ip.net/geoip-json?callback=?",
	function (data) {
		alert(data.countryName);
		alert(data.city);
	}
);

Solution 19 - Php

I've done a bunch of testing with IP address services and here are a few ways I do it myself. First off a bunch off links to useful websites that I use:

https://db-ip.com/db Has a free ip-lookup service and has a few free csv files you can download. This uses a free api key that is attached to your email. It limits at 2000 queries per day.

http://ipinfo.io/ Free ip-lookup service without a api-key PHP functions:

//uses http://ipinfo.io/.
function ip_visitor_country($ip){
    $ip_data_in = get_web_page("http://ipinfo.io/".$ip."/json"); //add the ip to the url and retrieve the json data
    $ip_data = json_decode($ip_data_in['content'],true); //json_decode it for php use

    //this ip-lookup service returns 404 if the ip is invalid/not found so return false if this is the case.
    if(empty($ip_data) || $ip_data_in['httpcode'] == 404){
        return false;
    }else{
        return $ip_data; 
    }
}

function get_web_page($url){
    $user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0';
    
    $options = array(
        CURLOPT_CUSTOMREQUEST  =>"GET",        //set request type post or get
        CURLOPT_POST           =>false,        //set to GET
        CURLOPT_USERAGENT      => $user_agent, //set user agent
        CURLOPT_RETURNTRANSFER => true,     // return web page
        CURLOPT_HEADER         => false,    // don't return headers
        CURLOPT_FOLLOWLOCATION => true,     // follow redirects
        CURLOPT_ENCODING       => "",       // handle all encodings
        CURLOPT_AUTOREFERER    => true,     // set referer on redirect
        CURLOPT_CONNECTTIMEOUT => 120,      // timeout on connect
        CURLOPT_TIMEOUT        => 120,      // timeout on response
        CURLOPT_MAXREDIRS      => 10,       // stop after 10 redirects
    );
    $ch = curl_init( $url );
    curl_setopt_array( $ch, $options );
    $content = curl_exec( $ch );
    $err     = curl_errno( $ch );
    $errmsg  = curl_error( $ch );
    $header  = curl_getinfo( $ch );
    $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
    curl_close( $ch );  
    $header['errno']   = $err; //curl error code
    $header['errmsg']  = $errmsg; //curl error message
    $header['content'] = $content; //the webpage result (In this case the ip data in json array form)
    $header['httpcode'] = $httpCode; //the webpage response code
    return $header; //return the collected data and response codes
}

In the end you get something like this:

Array
(
    [ip] => 1.1.1.1
    [hostname] => No Hostname
    [city] => 
    [country] => AU
    [loc] => -27.0000,133.0000
    [org] => AS15169 Google Inc.
)

http://www.geoplugin.com/ Slightly older but this service gives you a bunch of extra usefull information such as the currency off the country, continent code, longitude and more.


http://lite.ip2location.com/database-ip-country-region-city-latitude-longitude Offers a bunch of downloadable files with instructions to import them into your database. Once you have one off these files in your database you can select the data fairly easily.

SELECT * FROM `ip2location_db5` WHERE IP > ip_from AND IP < ip_to

Use the php function ip2long(); to turn the ip-address into a numeric value. For example 1.1.1.1 becomes 16843009. This lets you scan for the ip ranges given to you by the database file.

So in order to find out where 1.1.1.1 belongs to all we do is run this query:

SELECT * FROM `ip2location_db5` WHERE 16843009 > ip_from AND 16843009 < ip_to;

This returns this data as a example.

FROM: 16843008
TO: 16843263
Country code: AU
Country: Australia
Region: Queensland
City: Brisbane
Latitude: -27.46794
Longitude: 153.02809

Solution 20 - Php

There 2 broad approaches to perform IP geolocation: one is to download a dataset, host it on your infrastructure and maintain it up-to-date. This requires time and effort, especially if you need to support a high number of requests. Another solution is to use an existing API service that manages all the work for you and more.

There exist many API Geolocation services: Maxmind, Ip2location, Ipstack, IpInfo, etc. Recently, the company I work for has switched to Ipregistry (https://ipregistry.co) and I was involved in the decision and implementation process. Here are some elements you should consider while looking for an IP geolocation API:

  • Is the service accurate? are they using a single source of information?
  • Can they really handle your load?
  • Do they provide consistent and fast response times Worldwide (except if your users are country specific)?
  • What's their pricing model?

Here is an example to get IP geolocation information (but also threat and user agent data using one call):

$ip = $_SERVER['REMOTE_ADDR'];
$details = json_decode(file_get_contents("https://api.ipregistry.co/{$ip}?key=tryout"));
echo $details->location;

Note: I am not here to promote Ipregistry and say it's the best but I spent a long time analyzing existing solutions and their solution is really promising.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionkrishna KantView Question on Stackoverflow
Solution 1 - PhpBen DowlingView Answer on Stackoverflow
Solution 2 - PhpJamie HutberView Answer on Stackoverflow
Solution 3 - PhpKurt Van den BrandenView Answer on Stackoverflow
Solution 4 - PhpRaposoView Answer on Stackoverflow
Solution 5 - PhpnullView Answer on Stackoverflow
Solution 6 - PhpJaimesView Answer on Stackoverflow
Solution 7 - PhpjinzaiView Answer on Stackoverflow
Solution 8 - PhpIsaac WallerView Answer on Stackoverflow
Solution 9 - PhplpfavreauView Answer on Stackoverflow
Solution 10 - PhpIsaac AskewView Answer on Stackoverflow
Solution 11 - PhpttarikView Answer on Stackoverflow
Solution 12 - PhpJames CapeView Answer on Stackoverflow
Solution 13 - PhpIan HunterView Answer on Stackoverflow
Solution 14 - PhpMichael NilssonView Answer on Stackoverflow
Solution 15 - PhpJonathanView Answer on Stackoverflow
Solution 16 - PhpVindhyachal KumarView Answer on Stackoverflow
Solution 17 - PhpSpYk3HHView Answer on Stackoverflow
Solution 18 - PhpRoman PushkinView Answer on Stackoverflow
Solution 19 - PhpCrecketView Answer on Stackoverflow
Solution 20 - PhpBonieEView Answer on Stackoverflow