Get real IP address of user in php

By | December 4, 2008

Client IP address

Php applications are mostly web based and often need to get the ip address of the user who is connecting to the application. Ip address is required for various logging purpose, geolocation service etc.

The most common way to get the ip address of a remote user is by using the superglobal variable $_SERVER. Here is a quick example

//Get the ip address of a user
$ip = $_SERVER['REMOTE_ADDR'];

The above approach is quite simple and works fine in most cases. But ocassionaly there are users who are behind proxy servers. When a user is behind a proxy server, the php request is send by the proxy server and therefore the
REMOTE_ADDR value is not the same as user's real ip address. If the proxy is highly anonymous (like tor) it might be impossible to find the user's real ip address. However if the proxy is transparent then the real ip address can be retrieved.

When using a transparent proxy, the HTTP_X_FORWARDED_FOR value in $_SERVER can hold the real ip address of the user.

function real_ip()
{
	//check proxy
	if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
	{
		$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
	}
	else
	{
		$ip = $_SERVER['REMOTE_ADDR'];
	}
	
	return $ip;
}

Now HTTP_X_FORWARDED_FOR is not the alternative variable that can hold the real ip of the user. There are a couple more. Here is a list

HTTP_PRAGMA
HTTP_XONNECTION
HTTP_CACHE_INFO
HTTP_XPROXY
HTTP_PROXY
HTTP_PROXY_CONNECTION
HTTP_CLIENT_IP
HTTP_VIA
HTTP_X_COMING_FROM
HTTP_X_FORWARDED_FOR
HTTP_X_FORWARDED
HTTP_COMING_FROM
HTTP_FORWARDED_FOR
HTTP_FORWARDED
ZHTTP_CACHE_CONTROL

Therefore the above parameters should also be included in our function real_ip. Here is a quick example

function real_ip()
{
	$ipaddress = '';

	if ($_SERVER['HTTP_CLIENT_IP'])
		$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
	else if($_SERVER['HTTP_X_FORWARDED_FOR'])
		$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
	else if($_SERVER['HTTP_X_FORWARDED'])
		$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
	else if($_SERVER['HTTP_FORWARDED_FOR'])
		$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
	else if($_SERVER['HTTP_FORWARDED'])
		$ipaddress = $_SERVER['HTTP_FORWARDED'];
	else if($_SERVER['REMOTE_ADDR'])
		$ipaddress = $_SERVER['REMOTE_ADDR'];
	else
		$ipaddress = 'UNKNOWN';

	return $ipaddress;
}

The above function can be written in a more elegant manner like this

function real_ip()
{
	$header_checks = array(
		'HTTP_CLIENT_IP',
		'HTTP_PRAGMA',
		'HTTP_XONNECTION',
		'HTTP_CACHE_INFO',
		'HTTP_XPROXY',
		'HTTP_PROXY',
		'HTTP_PROXY_CONNECTION',
		'HTTP_VIA',
		'HTTP_X_COMING_FROM',
		'HTTP_COMING_FROM',
		'HTTP_X_FORWARDED_FOR',
		'HTTP_X_FORWARDED',
		'HTTP_X_CLUSTER_CLIENT_IP',
		'HTTP_FORWARDED_FOR',
		'HTTP_FORWARDED',
		'ZHTTP_CACHE_CONTROL',
		'REMOTE_ADDR'
	);

	foreach ($header_checks as $key)
	{
		if (array_key_exists($key, $_SERVER) === true)
		{
			foreach (explode(',', $_SERVER[$key]) as $ip)
			{
				$ip = trim($ip);
				
				//filter the ip with filter functions
				if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false)
				{
					return $ip;
				}
			}
		}
	}
}

The above function checks various variables inside $_SERVER variable and also validates the ip address to be valid using the filter_var function.

Note

But the extra fields like $_SERVER['HTTP_X_FORWARDED_FOR'] cannot be relied upon to be the real IP of the user incase they appear to be set to a valid IP address. For e.g. a user can send false HTTP headers with these values set to a random IP address say 10.0.0.1 . Now if the server checks them and ignores the value of $_SERVER['REMOTE_ADDR'] then it is likely to detect a wrong IP.

One idea could be that in case any of the extra fields is set to valid IP address value then check whether the IP given by $_SERVER['REMOTE_ADDR'] is that of a proxy server or not.

About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

Leave a Reply

Your email address will not be published. Required fields are marked *