考量 Proxy、負載平衡器等情境,依優先序取得 IP:
<?php
if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$userip = getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$userip = getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$userip = getenv('REMOTE_ADDR');
} elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$userip = $_SERVER['REMOTE_ADDR'];
}
if ($userip === '27.37.188.128') {
header('Location: https://blocked.example.com');
exit;
}
$ip_arr = explode('.', $userip);
// 只有 192.168.x.x 才允許存取
if (!($ip_arr[0] === '192' && $ip_arr[1] === '168')) {
header('Location: https://blocked.example.com');
exit;
} else {
header('Location: https://allowed.example.com');
exit;
}
實務上建議封裝為函式支援 CIDR 表示法(如 192.168.0.0/16):
function ipInRange($ip, $cidr) {
list($subnet, $mask) = explode('/', $cidr);
$mask = $mask ?: 32;
return (ip2long($ip) & ~((1 << (32 - $mask)) - 1)) === ip2long($subnet);
}
// 使用範例
if (!ipInRange($userip, '192.168.0.0/16')) {
// 拒絕存取
}
index.php 或共用 config.php)最前端X-Forwarded-For 信任清單