Sé que hay una gran cantidad de encabezados de variables $ _SERVER disponibles para la recuperación de direcciones IP. Me preguntaba si hay un consenso general sobre cómo recuperar con mayor precisión la dirección IP real de un usuario (sabiendo que ningún método es perfecto) utilizando dichas variables.
Pasé algún tiempo tratando de encontrar una solución en profundidad y se me ocurrió el siguiente código basado en varias fuentes. Me encantaría que alguien pudiera hacer agujeros en la respuesta o arrojar algo de luz sobre algo tal vez más preciso.
editar incluye optimizaciones de @Alix
/**
* Retrieves the best guess of the client's actual IP address.
* Takes into account numerous HTTP proxy headers due to variations
* in how different ISPs handle IP addresses in headers between hops.
*/
public function get_ip_address() {
// Check for shared internet/ISP IP
if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
return $_SERVER['HTTP_CLIENT_IP'];
// Check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Check if multiple IP addresses exist in var
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip) {
if ($this->validate_ip($ip))
return $ip;
}
}
}
if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
return $_SERVER['HTTP_X_FORWARDED'];
if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
return $_SERVER['HTTP_FORWARDED_FOR'];
if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
return $_SERVER['HTTP_FORWARDED'];
// Return unreliable IP address since all else failed
return $_SERVER['REMOTE_ADDR'];
}
/**
* Ensures an IP address is both a valid IP address and does not fall within
* a private network range.
*
* @access public
* @param string $ip
*/
public function validate_ip($ip) {
if (filter_var($ip, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 |
FILTER_FLAG_IPV6 |
FILTER_FLAG_NO_PRIV_RANGE |
FILTER_FLAG_NO_RES_RANGE) === false)
return false;
self::$ip = $ip;
return true;
}
Palabras de advertencia (actualización)
REMOTE_ADDR
todavía representa la fuente más confiable de una dirección IP. Las otras $_SERVER
variables mencionadas aquí pueden ser suplantadas por un cliente remoto muy fácilmente. El propósito de esta solución es intentar determinar la dirección IP de un cliente sentado detrás de un proxy. Para sus propósitos generales, puede considerar usar esto en combinación con la dirección IP devuelta directamente $_SERVER['REMOTE_ADDR']
y almacenar ambos.
Para el 99.9% de los usuarios, esta solución se adaptará perfectamente a sus necesidades. No lo protegerá del 0.1% de los usuarios maliciosos que buscan abusar de su sistema al inyectar sus propios encabezados de solicitud. Si confía en las direcciones IP para algo crítico, recurra aREMOTE_ADDR
y no se moleste en atender a quienes están detrás de un proxy.