Location based content in PHP using IP addresses →
Posted on April 30, 2012 in Development with 0 comments.
With the internet being a globally accessible resource, there may come a time when you want to display different content to your website visitors based on their location. For instance, if you are a consultant you may want to display a US dollar hourly rate to people viewing your site from the United States and a euro hourly rate to those who are viewing your site from Europe. Doing this in PHP is rather easy, let’s look at how.
We’re going to base our script on IP addresses. It’ll involve looking up the visitors IP address and then matching it against a set of IP addresses specific to a country. Based on that we can easily show our visitor content that is locally relevant to them.
For the sake of simpleness, let’s build our application to detect if a visitor is from South Africa and then display a relevant message to them, otherwise we’ll display a generic message.
To start off, we need to build an array of IP ranges to match against. This method isn’t 100% fool-proof and in a real life application, if you are dealing with multiple countries or even provinces, I’d recommend that you use a location matching library like DeviceAtlas. But for a small application like ours, an array is perfect.
Here is the array with the IP address ranges for South Africa:
<?php
$ranges = array(
array( '41.0.0.0', '41.31.255.255' ),
array( '41.75.224.0', '41.75.239.255' ),
array( '41.112.0.0', '41.127.255.255' ),
array( '41.144.0.0', '41.151.255.255' ),
array( '41.154.0.0', '41.154.255.255' ),
array( '41.156.0.0', '41.157.255.255' ),
array( '41.160.0.0', '41.175.255.255' ),
array( '41.177.0.0', '41.177.255.255' ),
array( '41.180.0.0', '41.180.255.255' ),
array( '41.181.0.0', '41.181.255.255' ),
array( '41.183.0.0', '41.183.255.255' ),
array( '41.185.0.0', '41.185.255.255' ),
array( '41.188.192.0', '41.188.255.255' ),
array( '41.189.64.0', '41.189.95.255' ),
array( '41.191.128.0', '41.191.191.255' ),
array( '41.192.0.0', '41.192.255.255' ),
array( '41.193.0.0', '41.193.255.255' ),
array( '41.194.0.0', '41.194.255.255' ),
array( '41.195.0.0', '41.195.255.255' ),
array( '41.198.0.0', '41.198.255.255' ),
array( '41.202.32.0', '41.202.63.255' ),
array( '41.203.0.0', '41.203.31.255' ),
array( '41.203.32.0', '41.203.63.255' ),
array( '41.203.160.0', '41.203.175.255' ),
array( '41.204.192.0', '41.204.223.255' ),
array( '41.206.160.0', '41.206.191.255' ),
array( '41.206.192.0', '41.206.223.255' ),
array( '41.207.224.0', '41.207.255.255' ),
array( '41.208.0.0', '41.208.63.255' ),
array( '41.208.192.0', '41.208.255.255' ),
array( '41.213.0.0', '41.213.127.255' ),
array( '41.216.128.0', '41.216.143.255' ),
array( '41.216.192.0', '41.216.207.255' ),
array( '41.221.0.0', '41.221.15.255' ),
array( '41.221.224.0', '41.221.239.255' ),
array( '41.240.0.0', '41.247.255.255' ),
array( '66.8.0.0', '66.8.127.255' ),
array( '66.18.64.0', '66.18.95.255' ),
array( '69.67.32.0', '69.67.47.255' ),
array( '137.158.0.0', '137.158.255.255' ),
array( '137.214.0.0', '137.214.255.255' ),
array( '137.215.0.0', '137.215.255.255' ),
array( '139.53.0.0', '139.53.255.255' ),
array( '143.128.0.0', '143.128.255.255' ),
array( '143.160.0.0', '143.160.255.255' ),
array( '146.64.0.0', '146.64.255.255' ),
array( '146.141.0.0', '146.141.255.255' ),
array( '146.182.0.0', '146.182.255.255' ),
array( '146.230.0.0', '146.230.255.255' ),
array( '146.231.0.0', '146.231.255.255' ),
array( '146.232.0.0', '146.232.255.255' ),
array( '147.110.0.0', '147.110.255.255' ),
array( '152.106.0.0', '152.106.255.255' ),
array( '152.107.0.0', '152.107.255.255' ),
array( '152.108.0.0', '152.108.255.255' ),
array( '152.109.0.0', '152.109.255.255' ),
array( '152.110.0.0', '152.110.255.255' ),
array( '152.111.0.0', '152.111.255.255' ),
array( '152.112.0.0', '152.112.255.255' ),
array( '155.159.0.0', '155.159.255.255' ),
array( '155.232.0.0', '155.232.255.255' ),
array( '155.233.0.0', '155.233.255.255' ),
array( '155.234.0.0', '155.234.255.255' ),
array( '155.235.0.0', '155.235.255.255' ),
array( '155.236.0.0', '155.236.255.255' ),
array( '155.237.0.0', '155.237.255.255' ),
array( '155.238.0.0', '155.238.255.255' ),
array( '155.239.0.0', '155.239.255.255' ),
array( '155.240.0.0', '155.240.255.255' ),
array( '156.8.0.0', '156.8.255.255' ),
array( '160.115.0.0', '160.115.255.255' ),
array( '160.116.0.0', '160.116.255.255' ),
array( '160.117.0.0', '160.117.255.255' ),
array( '160.118.0.0', '160.118.255.255' ),
array( '160.121.0.0', '160.121.255.255' ),
array( '160.122.0.0', '160.122.255.255' ),
array( '160.123.0.0', '160.123.255.255' ),
array( '160.124.0.0', '160.124.255.255' ),
array( '163.195.0.0', '163.195.255.255' ),
array( '163.196.0.0', '163.196.255.255' ),
array( '163.197.0.0', '163.197.255.255' ),
array( '163.198.0.0', '163.198.255.255' ),
array( '163.199.0.0', '163.199.255.255' ),
array( '163.200.0.0', '163.200.255.255' ),
array( '163.201.0.0', '163.201.255.255' ),
array( '163.202.0.0', '163.202.255.255' ),
array( '163.203.0.0', '163.203.255.255' ),
array( '164.88.0.0', '164.88.255.255' ),
array( '164.146.0.0', '164.151.255.255' ),
array( '164.155.0.0', '164.155.255.255' ),
array( '165.3.0.0', '165.5.255.255' ),
array( '165.8.0.0', '165.11.255.255' ),
array( '165.25.0.0', '165.25.255.255' ),
array( '165.143.0.0', '165.149.255.255' ),
array( '165.165.0.0', '165.165.255.255' ),
array( '165.180.0.0', '165.180.255.255' ),
array( '165.233.0.0', '165.233.255.255' ),
array( '166.85.0.0', '166.85.255.255' ),
array( '168.76.0.0', '168.76.255.255' ),
array( '168.80.0.0', '168.81.255.255' ),
array( '168.89.0.0', '168.89.255.255' ),
array( '168.128.0.0', '168.128.255.255' ),
array( '168.142.0.0', '168.142.255.255' ),
array( '168.155.0.0', '168.155.255.255' ),
array( '168.164.0.0', '168.164.255.255' ),
array( '168.172.0.0', '168.172.255.255' ),
array( '168.206.0.0', '168.206.255.255' ),
array( '168.209.0.0', '168.210.255.255' ),
array( '169.129.0.0', '169.129.255.255' ),
array( '169.202.0.0', '169.202.255.255' ),
array( '196.1.32.0', '196.1.51.255' ),
array( '196.1.144.0', '196.1.159.255' ),
array( '196.2.16.0', '196.2.31.255' ),
array( '196.2.32.0', '196.2.63.255' ),
array( '196.2.64.0', '196.2.79.255' ),
array( '196.2.96.0', '196.2.127.255' ),
array( '196.2.128.0', '196.2.159.255' ),
array( '196.2.160.0', '196.2.191.255' ),
array( '196.3.164.0', '196.3.179.255' ),
array( '196.3.224.0', '196.3.255.255' ),
array( '196.4.0.0', '196.4.19.255' ),
array( '196.4.100.0', '196.4.149.255' ),
array( '196.4.173.0', '196.4.188.255' ),
array( '196.4.212.0', '196.4.231.255' ),
array( '196.5.0.0', '196.5.255.255' ),
array( '196.6.1.0', '196.6.100.255' ),
array( '196.6.133.0', '196.6.172.255' ),
array( '196.7.0.0', '196.7.255.255' ),
array( '196.8.0.0', '196.8.255.255' ),
array( '196.9.0.0', '196.9.255.255' ),
array( '196.10.1.0', '196.10.50.255' ),
array( '196.10.61.0', '196.10.95.255' ),
array( '196.10.150.0', '196.10.199.255' ),
array( '196.11.0.0', '196.11.30.255' ),
array( '196.12.16.0', '196.12.31.255' ),
array( '196.13.1.0', '196.13.30.255' ),
array( '196.13.31.0', '196.13.80.255' ),
array( '196.13.81.0', '196.13.100.255' ),
array( '196.14.0.0', '196.14.255.255' ),
array( '196.15.64.0', '196.15.127.255' ),
array( '196.15.128.0', '196.15.255.255' ),
array( '196.16.0.0', '196.19.255.255' ),
array( '196.21.0.0', '196.21.255.255' ),
array( '196.22.16.0', '196.22.31.255' ),
array( '196.22.32.0', '196.22.47.255' ),
array( '196.22.64.0', '196.22.127.255' ),
array( '196.22.160.0', '196.22.191.255' ),
array( '196.22.192.0', '196.22.239.255' ),
array( '196.22.240.0', '196.22.255.255' ),
array( '196.23.0.0', '196.23.255.255' ),
array( '196.24.0.0', '196.24.255.255' ),
array( '196.25.0.0', '196.25.255.255' ),
array( '196.26.0.0', '196.26.255.255' ),
array( '196.28.16.0', '196.28.47.255' ),
array( '196.28.64.0', '196.28.127.255' ),
array( '196.28.128.0', '196.28.223.255' ),
array( '196.29.0.0', '196.29.31.255' ),
array( '196.29.128.0', '196.29.159.255' ),
array( '196.29.240.0', '196.29.255.255' ),
array( '196.30.0.0', '196.30.255.255' ),
array( '196.31.0.0', '196.31.255.255' ),
array( '196.32.160.0', '196.32.191.255' ),
array( '196.33.0.0', '196.33.255.255' ),
array( '196.34.0.0', '196.35.255.255' ),
array( '196.36.0.0', '196.39.255.255' ),
array( '196.40.96.0', '196.40.111.255' ),
array( '196.41.0.0', '196.41.31.255' ),
array( '196.41.96.0', '196.41.127.255' ),
array( '196.41.128.0', '196.41.159.255' ),
array( '196.41.160.0', '196.41.191.255' ),
array( '196.41.192.0', '196.41.223.255' ),
array( '196.43.0.0', '196.43.63.255' ),
array( '196.44.0.0', '196.44.31.255' ),
array( '196.44.32.0', '196.44.47.255' ),
array( '196.44.64.0', '196.44.95.255' ),
array( '196.44.192.0', '196.44.207.255' ),
array( '196.44.208.0', '196.44.223.255' ),
array( '196.44.224.0', '196.44.239.255' ),
array( '196.45.16.0', '196.45.31.255' ),
array( '196.45.64.0', '196.45.95.255' ),
array( '196.45.96.0', '196.45.111.255' ),
array( '196.46.160.0', '196.46.175.255' ),
array( '196.47.0.0', '196.47.63.255' ),
array( '196.47.64.0', '196.47.95.255' ),
array( '196.207.32.0', '196.207.47.255' ),
array( '196.208.0.0', '196.211.255.255' ),
array( '196.212.0.0', '196.215.255.255' ),
array( '196.220.32.0', '196.220.63.255' ),
array( '198.54.22.0', '198.54.37.255' ),
array( '204.12.128.0', '204.12.143.255' ),
array( '209.203.0.0', '209.203.63.255' ),
array( '209.212.96.0', '209.212.127.255' ),
array( '213.193.32.0', '213.193.63.255' ),
array( '216.236.176.0', '216.236.191.255' )
);
?php>
Before we go any further, we need to write a function to check if the IP address we have got from the visitors user agent is valid.
<?php
function checkValidIp( $ip ) {
$invalid = array(
array( '10.0.0.0', '10.255.255.255' ),
array( '127.0.0.0', '127.255.255.255' ),
array( '169.254.0.0', '169.254.255.255' ),
array( '172.16.0.0', '172.31.255.255' ),
array( '192.0.2.0', '192.0.2.255' ),
array( '192.168.0.0', '192.168.255.255' ),
array( '255.255.255.0', '255.255.255.255' )
);
$ip = ip2long( $ip );
foreach( $invalid as $ips ) {
if ( ip2long( $ips[0] ) <= $ip && $ip <= ip2long( $ips[1] ) )
return false;
}
return true;
}
?php>
As you can see, we accept an IP address in our checkValidIP function. We then setup an array of invalid IP address (which are mostly local IP address ranges), run through them and if we find a match we return false i.e. it is not a valid IP address.
You will have noticed one important PHP function that was used in the code snippet. That is the ip2long function. It takes an IP address and converts it to the type of a long integer. We can then easily check if the IP address falls within the invalid range. We're going to use this function again below.
The next step is to fetch the IP address of the visitor and match it against our ranges array. Here is a small function that does exactly that.
<?php
function isSouthAfrican() {
// Range array goes here
$ranges = array()
if ( checkValidIp( $_SERVER['HTTP_CLIENT_IP'] ) ) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
if ( ! isset( $ip ) ) {
if ( $ips = count( explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) > 0 ) {
foreach ( $ips as $i ) {
if ( checkValidIp( trim( $i ) ) ) {
$ip = $i;
break;
}
}
}
}
if ( ! isset( $ip ) ) {
if ( checkValidIp( $_SERVER['HTTP_X_FORWARDED'] ) ) {
$ip = $_SERVER['HTTP_X_FORWARDED'];
} else if ( checkValidIp( $_SERVER['HTTP_FORWARDED_FOR'] ) ) {
$ip = $_SERVER['HTTP_FORWARDED_FOR'];
} else if ( checkValidIp( $_SERVER['HTTP_FORWARDED'] ) ) {
$ip = $_SERVER['HTTP_FORWARDED'];
} else if ( checkValidIp( $_SERVER['HTTP_X_FORWARDED'] ) ) {
$ip = $_SERVER['HTTP_X_FORWARDED'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
}
$ip = ip2long( $ip );
foreach ( $ranges as $range ) {
if ( ip2long( $range[0] ) <= $ip && $ip <= ip2long( $range[1] ) )
return true;
}
return false;
}
?php>
In this snippet we check numerous user agent variables for the IP address to try and bypass proxies and weird browser behavior. Finally we run through our IP ranges and see if we get a match. If so, we naturally return true. Include this code in your project and then simply call the isSouthAfrican function and voila!
<?php
if ( isSouthAfrican() ) {
echo "We're in South Africa baby!";
} else {
echo "Hello world";
}
?php>
To test this code out, you'll need to use a proxy. Just do a Google search and you'll find thousands of international proxies that you can use. Change the IP ranges based on the country you want to check against.
You can download a full working version of the code here.
Tagged with Device Atlas, IP, Location, PHP








