PHP получить реальный IP (обнаружение прокси)
Я действительно отслеживаю "реальный" IP-адрес пользователя, если у него есть прокси-сервер, который отправляет заголовок реального IP-адреса... У кого-нибудь есть лучшее решение или даже больше заголовков?
Поскольку эта функция очень часто используется в сценарии, она должна быть очень быстрой, и в этом созвездии ее нет:/
Несколько предложений, которые я предложил, но не смог понять:
- Расположите заголовки в порядке, который используется чаще всего "в дикой природе", так что функции завершаются быстро
- ускорение определения pre_match для IP
===
function get_real_ip()
{
$proxy_headers = array(
'CLIENT_IP',
'FORWARDED',
'FORWARDED_FOR',
'FORWARDED_FOR_IP',
'HTTP_CLIENT_IP',
'HTTP_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED_FOR_IP',
'HTTP_PC_REMOTE_ADDR',
'HTTP_PROXY_CONNECTION',
'HTTP_VIA',
'HTTP_X_FORWARDED',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED_FOR_IP',
'HTTP_X_IMFORWARDS',
'HTTP_XROXY_CONNECTION',
'VIA',
'X_FORWARDED',
'X_FORWARDED_FOR'
);
foreach($proxy_headers as $proxy_header)
{
if(isset($_SERVER[$proxy_header]) && preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $_SERVER[$proxy_header])) /* HEADER ist gesetzt und dies ist eine gültige IP */
{
return $_SERVER[$proxy_header];
}
else if(stristr(',', $_SERVER[$proxy_header]) !== FALSE) /* Behandle mehrere IPs in einer Anfrage(z.B.: X-Forwarded-For: client1, proxy1, proxy2) */
{
$proxy_header_temp = trim(array_shift(explode(',', $_SERVER[$proxy_header]))); /* Teile in einzelne IPs, gib die letzte zurück und entferne Leerzeichen */
if(($pos_temp = stripos($proxy_header_temp, ':')) !== FALSE) $proxy_header_temp = substr($proxy_header_temp, 0, $pos_temp); /* Entferne den Port */
if(preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $proxy_header_temp) return $proxy_header_temp;
}
}
return $_SERVER['REMOTE_ADDR'];
}
2 ответа
Если прокси-сервер отправляет заголовок, вы можете получить исходный IP-адрес клиента. Если прокси не делает, то вы не можете. К сожалению (или, к счастью, в зависимости от вашей точки зрения), все так просто.
То, что я сделал в нашей интрасети, это перенаправление "intranet.mydomain.com" на "интрасеть" на веб-сервере, последний не использует прокси из-за внутренней конфигурации сети /DNS... Не знаю, чего вы хотите делать, но это может быть полезно.
Вы также можете установить список исключений в браузере...
Проверка правильности регулярного выражения потерпит неудачу для адресов ipv6; поэтому я предпочел бы удалить это (или попытаться найти лучший RegEX).
также stripos($proxy_header_temp, ':')
приведет к непредвиденному поведению, например, для "::1" (localhost, ipv6).
мое предложение с указанными модификациями:
function getIp()
{
$proxy_headers = array(
'CLIENT_IP',
'FORWARDED',
'FORWARDED_FOR',
'FORWARDED_FOR_IP',
'HTTP_CLIENT_IP',
'HTTP_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED_FOR_IP',
'HTTP_PC_REMOTE_ADDR',
'HTTP_PROXY_CONNECTION',
'HTTP_VIA',
'HTTP_X_FORWARDED',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED_FOR_IP',
'HTTP_X_IMFORWARDS',
'HTTP_XROXY_CONNECTION',
'VIA',
'X_FORWARDED',
'X_FORWARDED_FOR'
);
$regEx = "/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/";
foreach ($proxy_headers as $proxy_header) {
if (isset($_SERVER[$proxy_header])) {
/* HEADER ist gesetzt und dies ist eine gültige IP */
return $_SERVER[$proxy_header];
} else if (stristr(',', $_SERVER[$proxy_header]) !== false) {
// Behandle mehrere IPs in einer Anfrage
//(z.B.: X-Forwarded-For: client1, proxy1, proxy2)
$proxy_header_temp = trim(
array_shift(explode(',', $_SERVER[$proxy_header]))
); /* Teile in einzelne IPs, gib die letzte zurück und entferne Leerzeichen */
// if IPv4 address remove port if exists
if (preg_match($regEx, $proxy_header_temp)
&& ($pos_temp = stripos($proxy_header_temp, ':')) !== false
) {
$proxy_header_temp = substr($proxy_header_temp, 0, $pos_temp);
}
return $proxy_header_temp;
}
}
return $_SERVER['REMOTE_ADDR'];
}