90 lines
2.3 KiB
PHP
90 lines
2.3 KiB
PHP
<?php
|
|
/**
|
|
* CDN / 反代场景下解析访客真实 IP
|
|
*/
|
|
class ClientIpResolver
|
|
{
|
|
/**
|
|
* @return string
|
|
*/
|
|
public static function resolve()
|
|
{
|
|
static $resolved = null;
|
|
if ($resolved !== null) {
|
|
return $resolved;
|
|
}
|
|
|
|
$candidates = [];
|
|
|
|
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
|
|
$candidates[] = (string) $_SERVER['HTTP_CF_CONNECTING_IP'];
|
|
}
|
|
if (!empty($_SERVER['HTTP_TRUE_CLIENT_IP'])) {
|
|
$candidates[] = (string) $_SERVER['HTTP_TRUE_CLIENT_IP'];
|
|
}
|
|
if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
|
|
$candidates[] = (string) $_SERVER['HTTP_X_REAL_IP'];
|
|
}
|
|
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
|
foreach (explode(',', (string) $_SERVER['HTTP_X_FORWARDED_FOR']) as $part) {
|
|
$part = trim($part);
|
|
if ($part !== '' && strcasecmp($part, 'unknown') !== 0) {
|
|
$candidates[] = $part;
|
|
}
|
|
}
|
|
}
|
|
if (!empty($_SERVER['REMOTE_ADDR'])) {
|
|
$candidates[] = (string) $_SERVER['REMOTE_ADDR'];
|
|
}
|
|
|
|
foreach ($candidates as $candidate) {
|
|
$ip = self::normalizeIp($candidate);
|
|
if ($ip === null) {
|
|
continue;
|
|
}
|
|
if (self::isPublicIp($ip)) {
|
|
$resolved = $ip;
|
|
return $resolved;
|
|
}
|
|
}
|
|
|
|
foreach ($candidates as $candidate) {
|
|
$ip = self::normalizeIp($candidate);
|
|
if ($ip !== null) {
|
|
$resolved = $ip;
|
|
return $resolved;
|
|
}
|
|
}
|
|
|
|
$resolved = '0.0.0.0';
|
|
return $resolved;
|
|
}
|
|
|
|
/**
|
|
* @param string $ip
|
|
*/
|
|
public static function normalizeIp($ip)
|
|
{
|
|
$ip = trim($ip);
|
|
if ($ip === '' || strcasecmp($ip, 'unknown') === 0) {
|
|
return null;
|
|
}
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6) === false) {
|
|
return null;
|
|
}
|
|
return $ip;
|
|
}
|
|
|
|
/**
|
|
* @param string $ip
|
|
*/
|
|
private static function isPublicIp($ip)
|
|
{
|
|
return filter_var(
|
|
$ip,
|
|
FILTER_VALIDATE_IP,
|
|
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
|
) !== false;
|
|
}
|
|
}
|