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.