php rides限制访问频率

php 复制代码
<?php

class FreqControl
{
    private $redis;
    private $max_freq;

    public function __construct($redis_client, $max_freq)
    {
        $this->redis = $redis_client;
        $this->max_freq = $max_freq;
    }

    public function get_freq($key_name, $time_unit = 'minute')
    {
        // 构建Redis键名
        $redis_key = "{$key_name}:{$time_unit}";

        // 尝试从Redis获取值
        $value = $this->redis->get($redis_key);

        // 如果值不存在或为null,返回0;否则返回转换成整数的值
        return $value !== null ? (int)$value : 0;
    }

    public function increment_freq($key_name, $time_unit = 'minute')
    {
        $key = "{$key_name}:{$time_unit}";
        $pipe = $this->redis->multi();
        $pipe->incr($key);

        if ($time_unit === 'minute') {
            $pipe->expire($key, 60);
        } elseif ($time_unit === 'hour') {
            $pipe->expire($key, 3600);
        }

        return $pipe->exec();
    }

    public function set_freq($key_name, $value, $time_unit = 'minute')
    {
        $key = "{$key_name}:{$time_unit}";
        $ttl = $this->redis->ttl($key);

        // 使用 MULTI/EXEC 块来确保原子性
        $pipe = $this->redis->multi();
        $pipe->set($key, $value);

        // 如果键存在并有TTL,则保留它
        if ($ttl > 0) {
            $pipe->expire($key, $ttl);
        } else {
            // 为新键设置默认的60秒TTL
            $pipe->expire($key, 60);
        }
        return $pipe->exec();
    }

    public function is_freq_exceeded($key_name, $time_unit = 'minute')
    {
        $current_freq = $this->get_freq($key_name, $time_unit);
        $max_freq = (int)($this->max_freq ?? 0);
        return $current_freq >= $max_freq;
    }

    public function control_freq($key_name, $time_unit = 'minute')
    {
        if ($this->is_freq_exceeded($key_name, $time_unit)) {
            return false; // 超过频率限制,不允许访问
        } else {
            $current_freq = $this->get_freq($key_name, $time_unit);
            if (!$current_freq) {
                $this->increment_freq($key_name, $time_unit);
            } else {
                $this->set_freq($key_name, ($current_freq + 1), $time_unit);
            }
            return true; // 允许访问
        }
    }
}

使用方法

php 复制代码
  $redis = new Redis();
    $redis->connect('127.0.0.1');
    // 选择数据库,例如数据库3
    $redis->select(4);
    $max_freq = 130;
    $freqControl = new FreqControl($redis, $max_freq);
    $key_name = $tongjiIp;
    if ($WXAPPOPENID) {
        $key_name = $tongjiIp . '_' . $WXAPPOPENID;
    }
    if ($freqControl->control_freq($key_name) == false) {
        json('请求频繁,请稍后再试', 200, 'error');
    }
相关推荐
BingoGo10 小时前
免费可商用 PHP 管理后台 CatchAdmin V5.4.0 发布,新增短信服务能力
后端·php
Interview Aid11212 小时前
TikTok OA 四题分享|半小时内 AC,题目基本都是实现题
java·开发语言·算法·面试·职场和发展
CoderIsArt20 小时前
C#中UI 线程与 Dispatcher
开发语言·ui·c#
AI情绪识别开源1 天前
检信 ALLEMOTION OS 加密打包可执行程序 — 全面测试报告版本: v1.3功能测试 / 性能测试 /
开发语言·数据结构·人工智能·功能测试
「QT(C++)开发工程师」1 天前
C++ auto 用法详解
开发语言·c++
OPEN-F1 天前
C++STL教程:容器适配器与实用工具
开发语言·c++
yaoxin5211231 天前
507. Java 反射 - 在 BeanFactory 中实现依赖注入
java·开发语言
OPEN-F1 天前
C++模板教程:变参模板、折叠表达式与SFINAE
java·开发语言·c++
有点。1 天前
C++二叉搜索树进阶
开发语言·c++