<?php
/*
 * @author: CloudZA(云之安) <2922619853@qq.com>
 * @hitokoto: 一场秋雨一场凉，秋心酌满泪为霜。
 * Copyright (c) 2022 by CloudZA, All Rights Reserved.
 */

/**
 * 检查 Redis 扩展是否安装并进行速率限制
 * 作者：云之安
 * 时间：2023年3月5日
 * 网站：http://osuu.cc
 */
class CheckRedis
{
    /**
     * Run method
     * 运行速率限制检查
     *
     * @param int $limit    允许的请求次数
     * @param int $interval 速率限制的时间间隔
     * @param int $timeout  连接 Redis 的超时时间（单位：秒）
     *
     * @return string JSON 格式的成功或错误信息
     */
    public static function Run(int $limit = 60, int $interval = 60, int $timeout = 2)
    {
        // 检查是否安装 Redis 扩展
        if (!extension_loaded('redis')) {
            return self::ReturnError('未安装 Redis 扩展，请安装后再运行');
        }

        // 连接 Redis 数据库
        try {
            $redis = new Redis();
            $redis->connect('127.0.0.1', 6379, $timeout);
            // 设置 Redis 数据库密码，如果需要的话
            // $redis->auth('your_redis_password');
        } catch (\Exception $e) {
            return self::ReturnError('无法连接 Redis 数据库，请检查配置');
        }

        // 构造速率限制键
        $key = "rate_limit:{$_SERVER['REMOTE_ADDR']}";

        // 开启 Redis 事务
        $redis->multi();

        // 增加计数器并设置过期时间
        $redis->incr($key);
        $redis->expire($key, $interval);

        // 执行 Redis 事务
        $result = $redis->exec();

        // 检查执行结果
        if (!$result) {
            return self::ReturnError('执行 Redis 事务出错');
        }

        // 获取计数器的值
        $count = $result[0];

        // 检查计数器是否超过限制
        if ($count > $limit) {
            // 计数器已超过限制，返回错误信息
            return self::ReturnError('访问次数太多啦，休息会儿吧');
        }

        // 返回成功信息和计数器的值
        return self::ReturnSuccess(['count' => $count]);
    }

    /**
     * ReturnSuccess method
     * 返回成功信息
     * @param mixed $data 返回的数据
     * @return string JSON 格式的成功信息
     */
    public static function ReturnSuccess($data)
    {
        $result = ['code' => 200, 'data' => $data];
        return json_encode($result);
    }

    /**
     * ReturnError method
     * 返回错误信息
     * @param string $msg 错误消息
     * @return string JSON 格式的错误信息
     */
    public static function ReturnError($msg)
    {
        $result = ['code' => 201, 'msg' => $msg];
        return json_encode($result);
    }
}