محدد معدل الطلبات

محدد معدل الطلبات في webman يدعم تحديد المعدل باستخدام التعليقات.
يدعم محركات apcu و redis و memory.

عنوان المصدر

https://github.com/webman-php/rate-limiter

التثبيت

composer require webman/rate-limiter

الاستخدام

<?php
namespace app\controller;

use RuntimeException;
use Webman\RateLimiter\Annotation\RateLimiter;

class UserController
{

    #[RateLimiter(limit: 10)]
    public function index(): string
    {
        // بشكل افتراضي، يتم تحديد المعدل حسب IP، وفترة الوقت الافتراضية هي 1 ثانية
        return 'كل IP يمكنه إرسال 10 طلبات في الثانية كحد أقصى';
    }

    #[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
    public function search(): string
    {
        // key: RateLimiter::UID، يتم تحديد المعدل بناءً على معرّف المستخدم، يجب أن لا تكون session('user.id') فارغة
        return 'يستطيع كل مستخدم إجراء 100 عملية بحث في كل 60 ثانية';
    }

    #[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: 'يمكن لكل شخص إرسال بريد إلكتروني مرة واحدة في الدقيقة')]
    public function sendMail(): string
    {
        // key: RateLimiter::SID، يتم تحديد المعدل بناءً على session_id
        return 'تم إرسال البريد الإلكتروني بنجاح';
    }

    #[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'انتهت قسائم اليوم، يرجى العودة غدًا')]
    #[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: 'يمكن لكل مستخدم استلام قسيمة واحدة كل يوم')]
    public function coupon(): string
    {
        // key: 'coupon'، هنا coupon هي مفتاح مخصص، مما يعني أن تحديد المعدل سيكون عالميًا باستخدام "coupon" كمفتاح، بحد أقصى 100 قسيمة يوميًا
        // أيضًا يتم تحديد المعدل بناءً على معرف المستخدم، بحيث يمكن لكل مستخدم استلام قسيمة واحدة فقط يوميًا
        return 'تم إرسال القسيمة بنجاح';
    }

    #[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'يمكن لكل رقم هاتف تلقي 5 رسائل نصية فقط في اليوم')]
    public function sendSms2(): string
    {
        // عندما يكون المفتاح متغيرًا، يمكنك استخدام الطريقة [class, static method] للحصول على المفتاح، على سبيل المثال [UserController::class, 'getMobile'] ستكتشف القيمة المرجعة لطريقة getMobile() في UserController كمفتاح
        return 'تم إرسال الرسالة النصية بنجاح';
    }

    /**
     * مفتاح مخصص، الحصول على رقم الهاتف، يجب أن تكون الطريقة ثابتة
     * @return string
     */
    public static function getMobile(): string
    {
        return request()->get('mobile');
    }

    #[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: 'معدل التكرار مقيد', exception: RuntimeException::class)]
    public function testException(): string
    {
        // الاستثناء الافتراضي عند تجاوز القيود هو Webman\RateLimiter\RateLimitException، يمكنك تغيير الفئة الاستثنائية باستخدام parameter exception
        return 'ok';
    }

}

ملاحظات

  • الفترة الزمنية الافتراضية هي 1 ثانية.
  • يمكنك تعيين الفترة الزمنية باستخدام ttl، على سبيل المثال ttl:60 تعني 60 ثانية.
  • الأبعاد الافتراضية لتحديد المعدل هي IP (افتراضيًا 127.0.0.1 غير مقيد، راجع قسم التكوين أدناه).
  • يدعم تحديد المعدل بناءً على IP، UID (يتطلب أن لا تكون session('user.id') فارغة)، و SID (بناءً على session_id).
  • إذا كنت تستخدم وكيل nginx، فعند تحديد المعدل بناءً على IP، يجب تمرير رأس X-Forwarded-For، راجع وكيل nginx.
  • عندما تتجاوز القيود، سيتم تفعيل استثناء Webman\RateLimiter\RateLimitException، يمكنك ضبط exception:xx لتخصيص فئة الاستثناء.
  • عند تجاوز القيود، تكون الرسالة الافتراضية للخطأ هي Too Many Requests، يمكنك تخصيص رسالة الخطأ باستخدام message:xx.
  • يمكن أيضًا تعديل الرسالة الافتراضية باستخدام ترجمة متعددة اللغات ، مرجع أوامر Linux التالية:
    composer require symfony/translation
    mkdir resource/translations/zh_CN/ -p
    echo "<?php
    return [
    'Too Many Requests' => 'طلب معدل التكرار مقيد'
    ];" > resource/translations/zh_CN/messages.php
    php start.php restart

الواجهة

في بعض الأحيان، يرغب المطورون في استدعاء محدد المعدل مباشرة في الكود، راجع الكود أدناه

<?php
namespace app\controller;

use RuntimeException;
use Webman\RateLimiter\Limiter;

class UserController {

    public function sendSms(string $mobile): string
    {
        // هنا mobile كفتح
        Limiter::check($mobile, 5, 24*60*60, 'يمكن لكل رقم هاتف تلقي 5 رسائل نصية فقط في اليوم');
        return 'تم إرسال الرسالة النصية بنجاح';
    }
}

التكوين

config/plugin/webman/rate-limiter/app.php

<?php
return [
    'enable' => true,
    'driver' => 'auto', // auto, apcu, memory, redis
    'stores' => [
        'redis' => [
            'connection' => 'default',
        ]
    ],
    // هذه الـ IP لن تخضع لقيود التكرار (تنطبق فقط عند استخدام المفتاح RateLimiter::IP).
    'ip_whitelist' => [
        '127.0.0.1',
    ],
];
  • enable: هل تريد تفعيل تحديد المعدل؟
  • driver: إحدى القيم auto apcu memory redis، باستخدام auto سيتم الاختيار تلقائيًا بين apcu و memory.
  • stores: إعدادات redis، connection تشير إلى config/redis.php المفتاح المقابل.
  • ip_whitelist: الـ IP في القائمة البيضاء لن يخضع للتحديد (التحكم فقط عند استخدام المفتاح RateLimiter::IP).

اختيار المحرك

memory

  • المقدمة
    لا حاجة لتثبيت أي ملحقات، الأداء هو الأفضل.

  • قيود الاستخدام
    تحديد المعدل فعال فقط في العملية الحالية، ولا تتم مشاركة بيانات المعدل بين العمليات المتعددة، ولا تدعم أيضًا تحديد المعدل في الكلاستر.

  • سيناريوهات الاستخدام
    بيئة تطوير Windows؛ الأعمال التي لا تتطلب تحديد معدل صارم؛ مقاومة هجمات CC.

apcu

  • تثبيت الملحق
    تحتاج إلى تثبيت ملحق apcu، وضبط php.ini كما يلي

    apc.enabled=1
    apc.enable_cli=1

    إذا كنت لا تعرف موقع php.ini، يمكنك البحث عن موقع php.ini من خلال الأمر php --ini.

  • المقدمة
    الأداء أقل قليلاً من memory، ويدعم مشاركة بيانات المعدل بين عمليات متعددة.

  • قيود الاستخدام
    لا يدعم الكلاستر.

  • سيناريوهات الاستخدام
    أي بيئة تطوير؛ سيناريوهات تحديد المعدل على الخادم الفردي؛ سيناريوهات الكلاستر التي لا تحتاج لتحديد معدل صارم؛ مقاومة هجمات CC.

redis

  • الاعتماديات
    تحتاج إلى تثبيت ملحق redis، وتثبيت مكون Redis، أمر التثبيت

    composer require -W illuminate/redis illuminate/events
  • المقدمة
    الأداء أقل من apcu، ويدعم الدقة سواء على الخادم الفردي أو الكلاستر.

  • سيناريوهات الاستخدام
    بيئة تطوير؛ بيئة الخادم الفردي؛ بيئة الكلاستر.