محدد معدل الطلبات
محدد معدل الطلبات في 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، ويدعم الدقة سواء على الخادم الفردي أو الكلاستر. -
سيناريوهات الاستخدام
بيئة تطوير؛ بيئة الخادم الفردي؛ بيئة الكلاستر.