PHP 屏蔽单个 IP 与 IP 段访问的实现方法
在 Web 开发中,有时需要临时或永久屏蔽某些恶意 IP 或特定网段的访问。PHP 可以通过读取服务器环境变量获取用户 IP,并利用逻辑判断或网络地址转换函数来实现精确的访问控制。
1. 原理:获取客户端真实 IP
在通过代理、负载均衡器访问时,客户端 IP 通常不会直接出现在 REMOTE_ADDR 中,而是记录在 X-Forwarded-For 或 HTTP_CLIENT_IP 等头字段中。为了准确获取用户 IP,建议按以下优先级判断:
HTTP_CLIENT_IP:代理传输过来的客户端 IP。HTTP_X_FORWARDED_FOR:经过多级代理后的 IP 列表(取第一个)。REMOTE_ADDR:正在浏览页面的当前最可能的 IP。
注意:如果这些值为 unknown 则视为无效,需依次向后兼容检查。
2. 禁止单个 IP 访问
通过定义一个包含待屏蔽 IP 的数组,使用 in_array 进行比对,若命中则终止脚本执行。
第一步:引入 IP 检测逻辑
在 PHP 文件头部添加以下代码,确保在输出任何内容前完成拦截:
<?php
// 获取用户真实 IP
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');
// 如果有多个代理,取第一个 IP
if (strpos($userip, ',') !== false) {
$userip = substr($userip, 0, strpos($userip, ','));
}
} 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'];
}
// 定义要屏蔽的 IP 列表
$banned_ip = array (
"127.0.0.1",
"203.0.0.1",
"56.12.50.65"
);
// 判断是否在黑名单中
if (in_array($userip, $banned_ip)) {
die("Your IP is blocked to connect!");
}
// 正常业务逻辑...
echo "本站测试";
?>
3. 禁止 IP 段(子网)访问
当需要屏蔽一个网段(如 217.0.0.0/16)时,逐个列出所有 IP 不现实。PHP 提供了 ip2long() 函数可将 IP 地址转换为无符号长整型,从而实现数值区间的比较。
第二步:计算 IP 区间并拦截
将目标 IP 段的起始和结束地址转为整数,再将被拦截的用户 IP 转为整数进行比较:
<?php
// ... 此处复用上方的获取 $userip 的代码 ...
// 定义要屏蔽的 IP 段范围
$ban_range_low = ip2long("217.0.0.0");
$ban_range_up = ip2long("217.255.255.255");
// 将用户 IP 转换为长整型
$user_ip_long = ip2long($userip);
// 判断用户 IP 是否在范围内
// 注意:ip2long 在有符号系统上可能返回负数,建议使用 strcmp 或 unsigned comparison
if ($user_ip_long && $user_ip_long >= $ban_range_low && $user_ip_long <= $ban_range_up) {
print "Access Banned from this IP range";
exit();
}
// 正常业务逻辑...
?>
4. 注意事项与优化建议
- IP 伪造风险:
HTTP_X_FORWARDED_FOR可被客户端随意修改。对于高安全性要求的应用,应结合服务器日志或 CDN 提供的可信 IP 头进行校验。 - 性能考量:对于海量 IP 黑名单,
in_array线性查找效率较低。建议将 IP 存入 Redis 或数据库,或使用哈希结构优化查询速度。 - IPv6 支持:上述代码主要基于 IPv4。若需支持 IPv6,可使用
inet_pton()和inet_ntop()处理二进制 IP 地址的比较。 - 错误修复:原文示例中
ip2long($userip]存在语法错误(括号不匹配),实际使用时需确保函数调用参数闭合正确。
以上就是 PHP 中禁止单个 IP 与 IP 段访问的详细内容,更多关于 PHP 安全防护的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













