PHP封禁IP代码怎么写

wen PHP项目 1

本文目录导读:

PHP封禁IP代码怎么写

  1. 基于文件存储的简单封禁
  2. 基于数据库的封禁(推荐)
  3. 基于Redis的高性能方案
  4. .htaccess方式(Apache服务器)
  5. 综合使用的最佳实践
  6. 注意事项

在PHP中实现IP封禁有多种方法,以下是几种常见的实现方式:

基于文件存储的简单封禁

<?php
class IPBan {
    private $banFile = 'banned_ips.txt';
    private $cacheFile = 'banned_cache.php';
    // 获取用户IP
    public function getClientIP() {
        $ipAddress = '';
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ipAddress = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $ipAddress = trim($ipList[0]);
        } else {
            $ipAddress = $_SERVER['REMOTE_ADDR'];
        }
        return $ipAddress;
    }
    // 检查IP是否被封禁
    public function isBanned($ip) {
        $bannedIps = $this->getBannedIPs();
        return in_array($ip, $bannedIps);
    }
    // 获取所有被封禁的IP列表
    private function getBannedIPs() {
        if (file_exists($this->cacheFile)) {
            $cached = include($this->cacheFile);
            if (isset($cached['expire']) && $cached['expire'] > time()) {
                return $cached['ips'];
            }
        }
        $ips = [];
        if (file_exists($this->banFile)) {
            $lines = file($this->banFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
            foreach ($lines as $line) {
                if (!empty($line)) {
                    $ips[] = trim($line);
                }
            }
        }
        // 缓存结果,减少文件读取
        $this->cacheBannedIPs($ips);
        return $ips;
    }
    // 缓存封禁IP列表
    private function cacheBannedIPs($ips) {
        $cacheData = [
            'ips' => $ips,
            'expire' => time() + 300 // 5分钟缓存
        ];
        file_put_contents($this->cacheFile, '<?php return ' . var_export($cacheData, true) . ';');
    }
    // 添加IP到封禁列表
    public function banIP($ip, $reason = '') {
        $bannedIps = $this->getBannedIPs();
        if (!in_array($ip, $bannedIps)) {
            $line = $ip . ($reason ? ' # ' . $reason : '') . PHP_EOL;
            file_put_contents($this->banFile, $line, FILE_APPEND);
            // 清除缓存
            if (file_exists($this->cacheFile)) {
                @unlink($this->cacheFile);
            }
            return true;
        }
        return false;
    }
    // 解除IP封禁
    public function unbanIP($ip) {
        $bannedIps = $this->getBannedIPs();
        if (in_array($ip, $bannedIps)) {
            $newList = array_diff($bannedIps, [$ip]);
            file_put_contents($this->banFile, implode(PHP_EOL, $newList) . PHP_EOL);
            // 清除缓存
            if (file_exists($this->cacheFile)) {
                @unlink($this->cacheFile);
            }
            return true;
        }
        return false;
    }
}
// 使用示例
$banner = new IPBan();
$clientIP = $banner->getClientIP();
if ($banner->isBanned($clientIP)) {
    http_response_code(403);
    die('您的IP已被封禁!');
}
// 封禁IP示例
// $banner->banIP('192.168.1.100', '恶意攻击');
// $banner->unbanIP('192.168.1.100');
?>

基于数据库的封禁(推荐)

<?php
class IPBanDB {
    private $pdo;
    public function __construct($host, $dbname, $user, $pass) {
        try {
            $this->pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->createTable();
        } catch (PDOException $e) {
            die('数据库连接失败: ' . $e->getMessage());
        }
    }
    // 创建封禁表
    private function createTable() {
        $sql = "CREATE TABLE IF NOT EXISTS banned_ips (
            id INT AUTO_INCREMENT PRIMARY KEY,
            ip VARCHAR(45) NOT NULL UNIQUE,
            reason VARCHAR(255),
            banned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            expires_at DATETIME DEFAULT NULL,
            INDEX idx_ip (ip)
        )";
        $this->pdo->exec($sql);
    }
    // 获取用户IP
    public function getClientIP() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return trim(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]);
        }
        return $_SERVER['REMOTE_ADDR'];
    }
    // 检查IP是否被封禁
    public function isBanned($ip) {
        $sql = "SELECT COUNT(*) FROM banned_ips 
                WHERE ip = :ip 
                AND (expires_at IS NULL OR expires_at > NOW())";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':ip' => $ip]);
        return $stmt->fetchColumn() > 0;
    }
    // 添加封禁
    public function banIP($ip, $reason = '', $hours = null) {
        $expires = $hours ? date('Y-m-d H:i:s', strtotime("+$hours hours")) : null;
        $sql = "INSERT INTO banned_ips (ip, reason, expires_at) 
                VALUES (:ip, :reason, :expires)
                ON DUPLICATE KEY UPDATE reason = :reason2, expires_at = :expires2";
        $stmt = $this->pdo->prepare($sql);
        return $stmt->execute([
            ':ip' => $ip,
            ':reason' => $reason,
            ':expires' => $expires,
            ':reason2' => $reason,
            ':expires2' => $expires
        ]);
    }
    // 解除封禁
    public function unbanIP($ip) {
        $sql = "DELETE FROM banned_ips WHERE ip = :ip";
        $stmt = $this->pdo->prepare($sql);
        return $stmt->execute([':ip' => $ip]);
    }
    // 清除过期记录
    public function cleanExpired() {
        $sql = "DELETE FROM banned_ips WHERE expires_at IS NOT NULL AND expires_at < NOW()";
        return $this->pdo->exec($sql);
    }
    // 获取封禁信息
    public function getBanInfo($ip) {
        $sql = "SELECT * FROM banned_ips WHERE ip = :ip";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':ip' => $ip]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
}
// 使用示例
$banner = new IPBanDB('localhost', 'mydb', 'user', 'password');
$clientIP = $banner->getClientIP();
if ($banner->isBanned($clientIP)) {
    $banInfo = $banner->getBanInfo($clientIP);
    http_response_code(403);
    echo "您的IP已被封禁!";
    if ($banInfo['expires_at']) {
        echo " 封禁到期时间: " . $banInfo['expires_at'];
    }
    if ($banInfo['reason']) {
        echo " 原因: " . $banInfo['reason'];
    }
    die();
}
// 封禁操作
// $banner->banIP('192.168.1.100', '恶意攻击', 24); // 封禁24小时
// $banner->unbanIP('192.168.1.100'); // 解除封禁
// $banner->cleanExpired(); // 清理过期记录
?>

基于Redis的高性能方案

<?php
class IPBanRedis {
    private $redis;
    private $prefix = 'ip_ban:';
    public function __construct($host = 'localhost', $port = 6379, $password = null) {
        $this->redis = new Redis();
        $this->redis->connect($host, $port);
        if ($password) {
            $this->redis->auth($password);
        }
    }
    // 获取用户IP
    public function getClientIP() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return trim(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]);
        }
        return $_SERVER['REMOTE_ADDR'];
    }
    // 检查IP是否被封禁
    public function isBanned($ip) {
        return (bool)$this->redis->exists($this->prefix . $ip);
    }
    // 添加封禁
    public function banIP($ip, $seconds = 3600) {
        return $this->redis->set($this->prefix . $ip, time(), $seconds);
    }
    // 永久封禁
    public function banIPForever($ip) {
        return $this->redis->set($this->prefix . $ip, -1);
    }
    // 解除封禁
    public function unbanIP($ip) {
        return $this->redis->del($this->prefix . $ip);
    }
    // 获取封禁信息
    public function getBanInfo($ip) {
        $key = $this->prefix . $ip;
        if ($this->redis->exists($key)) {
            $value = $this->redis->get($key);
            return [
                'banned' => true,
                'permanent' => $value == -1,
                'banned_at' => $value == -1 ? null : date('Y-m-d H:i:s', $value)
            ];
        }
        return ['banned' => false];
    }
}
// 使用示例
$banner = new IPBanRedis();
$clientIP = $banner->getClientIP();
if ($banner->isBanned($clientIP)) {
    http_response_code(403);
    die('您的IP已被封禁!');
}
// 封禁操作
// $banner->banIP('192.168.1.100', 3600); // 封禁1小时
// $banner->banIPForever('192.168.1.101'); // 永久封禁
// $banner->unbanIP('192.168.1.100'); // 解除封禁
?>

.htaccess方式(Apache服务器)

# .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
# 封禁单个IP
Deny from 192.168.1.100
# 封禁多个IP
Deny from 192.168.1.101 192.168.1.102 192.168.1.103
# 封禁IP段
Deny from 192.168.1.0/24
# 封禁域名
Deny from bad-domain.com
</IfModule>

综合使用的最佳实践

<?php
// ipban.php - 综合使用示例
require_once 'IPBanDB.php';
session_start();
class IPBanManager {
    private $banManager;
    private $maxAttempts = 5;
    private $lockoutTime = 900; // 15分钟
    public function __construct() {
        $config = [
            'host' => 'localhost',
            'dbname' => 'mydb',
            'user' => 'user',
            'pass' => 'password'
        ];
        $this->banManager = new IPBanDB(
            $config['host'],
            $config['dbname'],
            $config['user'],
            $config['pass']
        );
    }
    public function checkAccess() {
        $ip = $this->banManager->getClientIP();
        // 检查是否被封禁
        if ($this->banManager->isBanned($ip)) {
            $this->denyAccess();
        }
        // 监控登录失败次数
        if (isset($_SESSION['login_attempts'][$ip])) {
            $attempts = $_SESSION['login_attempts'][$ip];
            if ($attempts >= $this->maxAttempts) {
                // 自动封禁
                $this->banManager->banIP($ip, '多次登录失败', $this->lockoutTime / 3600);
                unset($_SESSION['login_attempts'][$ip]);
                $this->denyAccess();
            }
        }
    }
    public function recordFailedLogin() {
        $ip = $this->banManager->getClientIP();
        if (!isset($_SESSION['login_attempts'][$ip])) {
            $_SESSION['login_attempts'][$ip] = 0;
        }
        $_SESSION['login_attempts'][$ip]++;
    }
    private function denyAccess() {
        http_response_code(403);
        die('访问被拒绝:您的IP已被封禁。');
    }
    // 管理员功能
    public function adminUnban($ip) {
        return $this->banManager->unbanIP($ip);
    }
    public function adminBan($ip, $reason, $hours = null) {
        return $this->banManager->banIP($ip, $reason, $hours);
    }
}
// 使用
$manager = new IPBanManager();
$manager->checkAccess();
?>

注意事项

  1. IP获取安全HTTP_X_FORWARDED_FOR可能被伪造,建议只信任已知代理的此字段
  2. IP格式验证:使用filter_var($ip, FILTER_VALIDATE_IP)验证IP格式
  3. 性能优化:使用缓存或Redis避免频繁数据库查询
  4. 批量操作:管理员操作页面建议添加批量封禁/解封功能
  5. 日志记录:记录所有封禁/解封操作,便于审计

根据你的需求选择合适的方案,对于小型项目,文件存储即可;对于生产环境,建议使用数据库或Redis方案。

抱歉,评论功能暂时关闭!