首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實作 IP 每日瀏覽頁面數量限制:資料庫設計與程式邏輯

     編輯:PHP 相關知識

PHP 實作 IP 每日瀏覽頁面數量限制:資料庫設計與程式邏輯

防止惡意爬蟲、濫用 API 或限制免費用戶每日存取次數,是常見的業務需求。本文提供基於 MySQL 的完整實作方案:資料表設計、記錄邏輯、限流判斷、定時清理。

資料表設計

CREATE TABLE `ip_log` (
    `ip_log_ip` VARCHAR(45) NOT NULL COMMENT 'IPv6 相容長度',
    `ip_log_date` DATE NOT NULL COMMENT '訪問日期',
    `ip_log_visits` SMALLINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '訪問次數',
    `ip_log_page` VARCHAR(255) NOT NULL COMMENT '訪問頁面/路由',
    PRIMARY KEY (`ip_log_page`, `ip_log_ip`, `ip_log_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP 訪問日誌限流表';

設計要點:

  • 複合主鍵 (page, ip, date) 確保同一 IP 同一天同一頁面只有一條記錄,避免重複插入。
  • VARCHAR(45) 支援 IPv6 (最長 45 字元)。
  • SMALLINT UNSIGNED 足夠儲存每日訪問上限 (65535)。
  • 索引天然支援「查詢某 IP 今日某頁面訪問次數」極快。

核心 PHP 實作邏輯

<?php
function checkIpLimit(PDO $pdo, string $ip, string $page, int $dailyLimit = 100): bool {
    $today = date('Y-m-d');
    
    // 1. 嘗試插入新記錄 (訪問次數 = 1)
    $sql = "INSERT INTO ip_log (ip_log_ip, ip_log_date, ip_log_visits, ip_log_page)
            VALUES (?, ?, 1, ?)
            ON DUPLICATE KEY UPDATE ip_log_visits = ip_log_visits + 1";
    
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$ip, $today, $page]);
    
    // 2. 查詢當前訪問次數
    $sql = "SELECT ip_log_visits FROM ip_log 
            WHERE ip_log_ip = ? AND ip_log_date = ? AND ip_log_page = ?";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$ip, $today, $page]);
    $visits = $stmt->fetchColumn();
    
    // 3. 判斷是否超過限制
    return $visits <= $dailyLimit;
}

// 使用範例
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass');
$clientIp = $_SERVER['REMOTE_ADDR'];
$currentPage = $_SERVER['REQUEST_URI'];

if (!checkIpLimit($pdo, $clientIp, $currentPage, 100)) {
    http_response_code(429); // Too Many Requests
    exit('今日訪問次數已超過限制 (100次/天)');
}

// 正常業務邏輯...
echo '歡迎訪問!';
?>

關鍵技術點解析

  1. ON DUPLICATE KEY UPDATE:MySQL 特有語法,主鍵衝突時自動更新計數,避免「先查再插/更新」的競態條件。
  2. 單一查詢完成記錄+計數:減少資料庫往返,提升效能。
  3. 參數化查詢:使用 PDO Prepared Statement 防 SQL 注入。

定時清理策略

建立 Cron 排程,每日凌晨清理歷史資料:

# crontab -e
0 0 * * * /usr/bin/php /path/to/cleanup_ip_log.php
<?php
// cleanup_ip_log.php
require 'db_config.php';
$pdo = new PDO(...);

// 保留最近 30 天,刪除更早資料
$cutoff = date('Y-m-d', strtotime('-30 days'));
$pdo->exec("DELETE FROM ip_log WHERE ip_log_date < '$cutoff'");
// 或截斷全表 (若不需歷史分析)
// $pdo->exec("TRUNCATE TABLE ip_log");
?>

進階優化方向

方案優點缺點適用場景
Redis 計數器 + 過期時間極高效能、原子操作、自動過期需額外基建、資料非持久高併發、海量存取
Memcached + 定時落地 DB緩衝寫入壓力複雜度高、可能丟失計數寫入極大、可容忍微小誤差
資料庫分區表 (按日期)查詢/清理效能好維護複雜長期保留全量日誌

安全性補充

  • 取得客戶端真實 IP 需考慮代理:$_SERVER['HTTP_X_FORWARDED_FOR']、$_SERVER['HTTP_CLIENT_IP'],並驗證格式。
  • 對管理員/白名單 IP 跳過限流檢查。
  • 回傳標準 HTTP 429 狀態碼,並附帶 Retry-After 標頭。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved