HEX
Server: Apache
System: Linux server3230.server-vps.com 5.15.0-46-generic #49-Ubuntu SMP Thu Aug 4 18:03:25 UTC 2022 x86_64
User: lzgqnjwu (1002)
PHP: 7.4.33
Disabled: NONE
Upload Files
File: //proc/1122/cwd/common/components/BotPushRateLimiter.php
<?php

namespace common\components;

use Yii;
use yii\base\Component;

/**
 * Fixed-window rate limits for Push API (cache-backed).
 */
class BotPushRateLimiter extends Component
{
    /** @var int Max requests per IP per window (0 = disabled) */
    public int $ipLimit = 60;

    /** @var int Max requests per bot API key per window */
    public int $botLimit = 60;

    /** @var int Max requests to the same recipient (chat_id / phone) per bot per window */
    public int $recipientLimit = 6;

    /** @var int Window size in seconds */
    public int $windowSec = 60;

    public function init(): void
    {
        parent::init();
        $this->ipLimit = (int) env('BOT_PUSH_RATE_IP', $this->ipLimit);
        $this->botLimit = (int) env('BOT_PUSH_RATE_BOT', $this->botLimit);
        $this->recipientLimit = (int) env('BOT_PUSH_RATE_RECIPIENT', $this->recipientLimit);
        $this->windowSec = max(1, (int) env('BOT_PUSH_RATE_WINDOW', $this->windowSec));
    }

    public function isIpAllowed(string $ip): bool
    {
        return $this->isAllowed('ip', $ip, $this->ipLimit);
    }

    public function isBotAllowed(int $botId): bool
    {
        return $this->isAllowed('bot', (string) $botId, $this->botLimit);
    }

    public function isRecipientAllowed(int $botId, string $recipientKey): bool
    {
        $scope = 'rcpt:' . $botId . ':' . hash('sha256', $recipientKey);

        return $this->isAllowed($scope, '1', $this->recipientLimit);
    }

    private function isAllowed(string $scope, string $id, int $max): bool
    {
        if ($max <= 0) {
            return true;
        }

        $bucket = (int) floor(time() / $this->windowSec);
        $cacheKey = ['bot_push_rate', $scope, $id, $bucket];
        $cache = Yii::$app->cache;
        $count = (int) $cache->get($cacheKey);
        if ($count >= $max) {
            Yii::warning("BotPush rate limit hit: {$scope}={$id}", __METHOD__);

            return false;
        }

        $cache->set($cacheKey, $count + 1, $this->windowSec + 5);

        return true;
    }
}