{"id":46116695,"url":"https://github.com/thamtech/yii2-ratelimiter-advanced","last_synced_at":"2026-03-01T23:30:26.623Z","repository":{"id":57067541,"uuid":"135616232","full_name":"thamtech/yii2-ratelimiter-advanced","owner":"thamtech","description":"Advanced Rate Limiter is a Yii2 filter to enforce or monitor request rate limits.","archived":false,"fork":false,"pushed_at":"2020-12-09T19:52:22.000Z","size":51,"stargazers_count":37,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-08-08T15:44:11.853Z","etag":null,"topics":["php","rate-limiting","yii2"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thamtech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"liberapay":"thamtech"}},"created_at":"2018-05-31T17:37:58.000Z","updated_at":"2024-04-22T02:26:38.000Z","dependencies_parsed_at":"2022-08-24T14:54:06.655Z","dependency_job_id":null,"html_url":"https://github.com/thamtech/yii2-ratelimiter-advanced","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/thamtech/yii2-ratelimiter-advanced","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thamtech%2Fyii2-ratelimiter-advanced","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thamtech%2Fyii2-ratelimiter-advanced/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thamtech%2Fyii2-ratelimiter-advanced/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thamtech%2Fyii2-ratelimiter-advanced/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thamtech","download_url":"https://codeload.github.com/thamtech/yii2-ratelimiter-advanced/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thamtech%2Fyii2-ratelimiter-advanced/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29987692,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T22:42:38.399Z","status":"ssl_error","status_checked_at":"2026-03-01T22:41:51.863Z","response_time":124,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","rate-limiting","yii2"],"created_at":"2026-03-01T23:30:25.973Z","updated_at":"2026-03-01T23:30:26.612Z","avatar_url":"https://github.com/thamtech.png","language":"PHP","funding_links":["https://liberapay.com/thamtech"],"categories":[],"sub_categories":[],"readme":"Yii2 Advanced Rate Limiter\n==========================\n\nAdvanced Rate Limiter is a [Yii2's](http://www.yiiframework.com) filter to\nenforce or monitor request rate limits.\n\nIn contrast to Yii2's built-in [RateLimiter](http://www.yiiframework.com/doc-2.0/guide-rest-rate-limiting.html),\nAdvanced Rate Limiter:\n\n* allows you to define multiple, independent rate limit definitions\n   * by controller action, and\n   * by an identifier such as an IP address, user ID, other identifiers relevant\n     to your application, or a combination thereof;\n* provides support for customizing the type of response to a checked or\n  exceeded rate limit such as:\n   * sending a `429 Too Many Requests` HTTP response,\n   * triggering a Yii2 [Event](http://www.yiiframework.com/doc-2.0/guide-concept-events.html),\n   * setting rate-limit HTTP headers, and/or\n   * executing your own [Callable](http://php.net/manual/en/language.types.callable.php) or\n     [anonymous function](http://php.net/manual/en/functions.anonymous.php);\n* provides support for storing and managing the `allowance` and `timestamp`\n  values for each rate limit (Yii2's built-in RateLimiter requires you to\n  implement the storage yourself);\n* allows you to customize the prefix of rate-limit HTTP headers instead of the\n  hardcoded `X-Rate-Limit-` prefix used by the built-in `RateLimiter`;\n* provides support for sending the `Retry-After` HTTP header indicating how many\n  seconds the client should wait before retrying.\n\nFor license information check the [LICENSE](LICENSE.md)-file.\n\n\nInstallation\n------------\n\nThe preferred way to install this extension is through [composer](http://getcomposer.org/download/).\n\n```\nphp composer.phar require --prefer-dist thamtech/yii2-ratelimiter-advanced\n```\n\nor add\n\n```\n\"thamtech/yii2-ratelimiter-advanced\": \"*\"\n```\n\nto the `require` section of your `composer.json` file.\n\n\nUsage\n-----\n\n### Introduction\n\nThis Rate Limiter is an implementation of the\n[leaky bucket algorithm](http://en.wikipedia.org/wiki/Leaky_bucket).\n\nIn general, you will configure the rate limiter as a behavior on\nany Controller class you want to rate limit. For example,\n\n```php\n\u003c?php\npublic function behaviors()\n{\n    $behaviors = parent::behaviors();\n    $behaviors['rateLimiter'] = [\n        'class' =\u003e 'thamtech\\ratelimiter\\RateLimiter',\n        'components' =\u003e [\n            'rateLimit' =\u003e [\n                'definitions' =\u003e [\n                    'ip' =\u003e [\n                        'limit' =\u003e 1000, // allowed hits per window\n                        'window' =\u003e 3600, // window in seconds\n                        \n                        // Callable or anonymous function returning some unique\n                        // identifier. A separate allowance will be tracked for\n                        // each identifier.\n                        // \n                        // Leave unset to make such a rate apply globally\n                        // to all requests coming in through the controller.\n                        // \n                        // @param \\thamtech\\ratelimiter\\Context $context the current\n                        //     request/action context\n                        // \n                        // @param string $rateLimitId The array key that defined the\n                        //     rate limit (\"ip\" in this case)\n                        'identifier' =\u003e function($context, $rateLimitId) {\n                            return $context-\u003erequest-\u003egetUserIP();\n                        }\n                    ],\n                ],\n            ],\n            'allowanceStorage' =\u003e [\n                'cache' =\u003e 'cache', // use Yii::$app-\u003ecache component\n            ],\n        ],\n        'as rateLimitHeaders' =\u003e [\n            'class' =\u003e 'thamtech\\ratelimiter\\handlers\\RateLimitHeadersHandler',\n            \n            // This can be a single string prefix, or an array of strings to duplicate\n            // the headers with multiple prefixes.\n            // The default prefix is 'X-Rate-Limit-' if this property is not specified\n            'prefix' =\u003e ['X-Rate-Limit-', 'X-RateLimit-'],\n        ],\n        'as retryAfterHeader' =\u003e 'thamtech\\ratelimiter\\handlers\\RateLimitHeadersHandler',\n        'as tooManyRequestsException' =\u003e 'thamtech\\ratelimiter\\handlers\\TooManyRequestsHttpExceptionHandler',\n    ];\n    return $behaviors;\n}\n```\n\nAdvanced Example:\n\n```php\n\u003c?php\npublic function behaviors()\n{\n    $behaviors = parent::behaviors();\n    $behaviors['rateLimiter'] = [\n        'class' =\u003e 'thamtech\\ratelimiter\\RateLimiter',\n        \n        // except and only work to limit the controller actions on which the\n        // rate limiter applies\n        'only' =\u003e ['login', 'register', 'info'],\n        'except' =\u003e ['info'],\n        \n        'components' =\u003e [\n            'rateLimit' =\u003e [\n                // class explicitly set, but defaults to this value otherwise\n                // \n                // you could provide your own implementation of\n                // RateLimitProviderInterface instead\n                'class' =\u003e 'thamtech\\ratelimiter\\limit\\DefaultRateLimitProvider',\n                \n                'definitions' =\u003e [\n                    'user' =\u003e 'app\\models\\User', // implements RateLimitInterface\n                    \n                    'ip' =\u003e [\n                        'class' =\u003e 'thamtech\\ratelimiter\\limit\\RateLimit',\n                        'limit' =\u003e 1000, // allowed hits per window\n                        'window' =\u003e 3600, // window in seconds\n                        \n                        // Callable or anonymous function returning some unique\n                        // identifier. A separate allowance will be tracked for\n                        // each identifier.\n                        // \n                        // Leave unset to make such a rate apply globally\n                        // to all requests coming in through the controller.\n                        // \n                        // @param \\thamtech\\ratelimiter\\Context $context the current\n                        //     request/action context\n                        // \n                        // @param string $rateLimitId The array key that defined the\n                        //     rate limit (\"ip\" in this case)\n                        'identifier' =\u003e function($context, $rateLimitId) {\n                            return $context-\u003erequest-\u003egetUserIP();\n                        }\n                    ],\n                    \n                    'user-admin' =\u003e [\n                        'limit' =\u003e 1000,\n                        'window' =\u003e 3600,\n                        'identifier' =\u003e Yii::$app-\u003euser-\u003egetIdentity()-\u003eid,\n                        \n                        // make a rate limit only be considered under certain conditions\n                        'active' =\u003e Yii::$app-\u003euser-\u003egetIdentity()-\u003eisAdmin(),\n                    ],\n                ],\n            ],\n            'allowanceStorage' =\u003e [\n                'cache' =\u003e 'cache', // use Yii::$app-\u003ecache component\n                \n                // The cache key will be made up of:\n                //   {cacheKeyPrefix - defaults to 'allowance'}\n                //   AllowanceCacheStorage::className() {or other storage component you might use}\n                //   RateLimiterComponent::className()\n                //   {your controller class}::className()\n                //   {rate limit id, like \"ip\" or \"User\" in this example}\n                //   {identifier, like 192.168.1.1 in this example}\n                //   \n                // The combination above already makes the key fairly specific to the\n                // desired scope, so you probably don't need to do anything\n                // special with this default value in most cases.\n                'cacheKeyPrefix' =\u003e 'allowance',\n            ],\n        ],\n        'as rateLimitHeaders' =\u003e [\n            'class' =\u003e 'thamtech\\ratelimiter\\handlers\\RateLimitHeadersHandler',\n            \n            // list of rateLimits to ignore\n            'except' =\u003e ['user'],\n            \n            // This can be a single string prefix, or an array of strings to duplicate\n            // the headers with multiple prefixes.\n            // The default prefix is 'X-Rate-Limit-' if this property is not specified\n            'prefix' =\u003e ['X-Rate-Limit-', 'X-RateLimit-'],\n        ],\n        \n        'as retryAfterHeader' =\u003e [\n            'class' =\u003e 'thamtech\\ratelimiter\\handlers\\RetryAfterHeaderHandler',\n            \n            // default's to 'Retry-After' if not set\n            'header' =\u003e 'Retry-After',\n        ],\n        \n        'as tooManyRequestsException' =\u003e [\n            'class' =\u003e 'thamtech\\ratelimiter\\handlers\\TooManyRequestsHttpExceptionHandler',\n            \n            // list of rateLimits this handler should apply to\n            'only' =\u003e ['ip'],\n            \n            // defaults to 'Rate limit exceeded.' if not set\n            'message' =\u003e 'There were too many requests',\n        ],\n    ];\n    return $behaviors;\n}\n```\n\n\n### Storage\n\nIn order to assign one or more rate limits, you must be able to store\nan integer `allowance` value and a `timestamp` for each configured\nrate limit.\n\n#### Default Allowance Storage in Cache\n\nThe RateLimiter uses an `allowanceStorage` component for storing the rate\nlimit values. By default, the `AllowanceCacheStorage` component stores the\nallowance data in the cache component you specify. If no cache\nis specified, an instance of `yii\\caching\\DummyCache` will be used.\n\nYou can specify a cache component in several ways:\n\n```php\n\u003c?php\n...\n'allowanceStorage' =\u003e [\n    // EXAMPLE `cache` definitions:\n    \n    // as a string referencing an application cache component\n    'cache' =\u003e 'cache', // refers to the Yii::$app-\u003ecache component\n    \n    // as a string referencing a Cache implementation class that\n    // needs no configuration\n    'cache' =\u003e 'app\\some\\implementation\\of\\Cache',\n    \n    // as a configuration array specifying a Cache class and\n    // necessary configuration settings\n    'cache' =\u003e [\n        'class' =\u003e 'yii\\caching\\DbCache',\n        'cacheTable' =\u003e 'allowance_cache',\n    ],\n    \n    // or as an already-instantiated Cache object\n    'cache' =\u003e Yii::createObject([\n        'class' =\u003e 'yii\\caching\\MemCache',\n        'servers' =\u003e [\n            [\n                'host' =\u003e 'server1',\n                'port' =\u003e 11211,\n                'weight' =\u003e 60,\n            ],\n            [\n                'host' =\u003e 'server2',\n                'port' =\u003e 11211,\n                'weight' =\u003e 40,\n            ],\n        ],\n    ]),\n],\n\n```\n\n#### Implement Your Own Storage Layer\n\nHowever, you may use your own storage layer implementation by implementing\n`AllowanceStorageInterface` and referencing your implementation in\n`RateLimiter`'s `allowanceStorage` component.\n\nFor example:\n\n```php\n\u003c?php\n...\n'components' =\u003e [\n    // EXAMPLE `allowanceStorage` definitions:\n    \n    // as a string referencing an AllowanceStorageInterface implementation class\n    // that needs no configuration\n    'allowanceStorage' =\u003e 'app\\components\\MyAllowanceStorage',\n    \n    // as a configuration array specifying an AllowanceStorageInterface implementation class\n    // and necessary configuration settings\n    'allowanceStorage' =\u003e [\n        'class' =\u003e 'app\\components\\MyAllowanceStorage',\n        'prefix' =\u003e 'my_allowances',\n        'tag' =\u003e 'my_controller_id',\n    ],\n],\n...\n```\n\n### Defining Rate Limits\n\nA single `RateLimiter` can have one or more separate rate limits defined. For example,\nyou may wish to provide one rate limit for each IP address and a different rate limit for\neach authenticated user, especially when this is not always a one-to-one mapping.\n\nA simple rate limit can be defined like the following:\n\n```php\n\u003c?php\n'components' =\u003e [\n    'rateLimit' =\u003e [\n        'ip' =\u003e [\n            'limit' =\u003e 1000, // allowed hits per window\n            'window' =\u003e 3600, // window in seconds\n            \n            // Callable or anonymous function returning some unique\n            // identifier. A separate allowance will be tracked for\n            // each identifier.\n            // \n            // Leave unset to make such a rate apply globally\n            // to all requests coming in through the controller\n            'identifier' =\u003e function($context, $rateLimitId) {\n                return $context-\u003erequest-\u003egetUserIP();\n            }\n        ],\n    ],\n],\n```\n\nBy returning an `identifier` value, you can enforce the defined rate limit on\na per-identifier basis, such as per IP address. Or you may leave the identifier\nunspecified in order to apply the defined rate limit globally.\n\nYou can also implement your own rate limit definition by referencing\nan implementation of the `RateLimitInterface`:\n\n```php\n\u003c?php\n'components' =\u003e [\n    'rateLimit' =\u003e [\n        'user' =\u003e [\n            'class' =\u003e 'app\\models\\User', // implements RateLimitInterface\n        ],\n    ],\n],\n```\n\nYou will need to implement the `getRateLimit($context)` method to return\na `RateLimit` object or an array of its properties (`limit`, `window`, and optionally\nan `identifier` such as a user ID, and optionally an `active` boolean).\n\n### Defining Responses\n\nThere can be any number of responses to an exceeded rate limit. A couple of predefined\nresponse types can be attached as behaviors of the `RateLimiter`. For example:\n```php\n\u003c?php\n...\n'as rateLimitHeaders' =\u003e [\n    'class' =\u003e 'thamtech\\ratelimiter\\handlers\\RateLimitHeadersHandler',\n],\n\n'as retryAfterHeader' =\u003e [\n    'class' =\u003e 'thamtech\\ratelimiter\\handlers\\RetryAfterHeaderHandler',\n],\n\n'as tooManyRequestsException' =\u003e [\n    'class' =\u003e 'thamtech\\ratelimiter\\handlers\\TooManyRequestsHttpExceptionHandler',\n],\n...\n```\n\nA more advanced example with some additional configuration options set:\n\n```php\n\u003c?php\n...\n'as rateLimitHeaders' =\u003e [\n    'class' =\u003e 'thamtech\\ratelimiter\\handlers\\RateLimitHeadersHandler',\n            \n    // list of rateLimits to ignore\n    'except' =\u003e ['user'],\n    \n    // single string prefix, or an array of strings to duplicate\n    // the headers with multiple prefixes.\n    // Default prefix is 'X-Rate-Limit-' if this property is not specified\n    'prefix' =\u003e ['X-Rate-Limit-', 'X-RateLimit-'],\n],\n\n'as retryAfterHeader' =\u003e [\n    'class' =\u003e 'thamtech\\ratelimiter\\handlers\\RetryAfterHeaderHandler',\n    \n    // defaults to 'Retry-After' if not set\n    'header' =\u003e 'Retry-After',\n],\n\n'as tooManyRequestsException' =\u003e [\n    'class' =\u003e 'thamtech\\ratelimiter\\handlers\\TooManyRequestsHttpExceptionHandler',\n    \n    // list of rateLimits this handler should apply to\n    'only' =\u003e ['ip'],\n    \n    // defaults to 'Rate limit exceeded.' if not set\n    'message' =\u003e 'There were too many requests',\n],\n...\n```\n\nYou may also attach your own event handlers to the `RateLimiter` object to look\nfor `RateLimiter::EVENT_RATE_LIMITS_EXCEEDED` or `RateLimiter::EVENT_RATE_LIMITS_CHECKED` events:\n\n```php\n\u003c?php\n...\n'on rateLimitsExceeded' =\u003e function($event) {\n    Yii::info('Rate limits exceeded: ' . $event-\u003erateLimit);\n},\n...\n```\n\nAlternatively, you can attach event handlers using the `on()` method:\n\n```php\n\u003c?php\nuse thamtech\\ratelimiter\\RateLimiter;\n$rateLimiter = $controller-\u003egetBehavior('rateLimiter');\n$rateLimiter-\u003eon(RateLimiter::EVENT_RATE_LIMITS_EXCEEDED, [$this, 'onRateLimitExceeded']);\n```\n\nSee [Yii's Events page](http://www.yiiframework.com/doc-2.0/guide-concept-events.html) for\nmore information about attaching Event handlers.\n\n##### Filtering Events\n\nIf the `only` and `except` properties of the handlers are not enough for filtering,\nyour custom event handler can set `$event-\u003ehandled` to true to prevent any other handler\nfrom being invoked.\n\nFor example, if you want to whitelist an IP address:\n\n```php\n\u003c?php\n...\n'on rateLimitsExceeded' =\u003e function($event) {\n    if ($event-\u003econtext-\u003erequest-\u003egetUserIp() == '127.0.0.1') {\n        $event-\u003ehandled = true;\n    }\n    // other handlers will not be invoked when IP is 127.0.0.1\n}\n...\n```\n\n#### Events\n\n#### RateLimitsCheckedEvent\n\nThe `RateLimitsCheckedEvent` is triggered whenever a set of defined rate limits\nare checked. The `RateLimitsExceededEvent` is triggered whenever one or more of the defined\nrate limits are exceeded. The predefined responses attached to the `RateLimiter` as\nbehaviors all work by registering themselves as event handlers and looking for\nthese events.\n\nBoth events include the following properties:\n* `$context` - the Context object containing the `yii\\web\\Request` and `$action`\n* `$time` - the current unix timestamp\n* `$rateLimits` - an array of `RateLimitResult` objects. Only those rate limits\n  that were exceeded are included in the `RateLimitsExceededEvent`.\n\nPredefined responses such as the `RateLimitHeadersHandler` will make use of the\nrate information in order to output the appropriate values in the HTTP headers.\nIn the case of `RateLimitHeadersHandler`, the information from multiple rate\nlimits may be combined together in order to compute one set of HTTP header values.\n\nOther responses, such as the `TooManyRequestsHttpExceptionHandler`, will not care\nwhat or how many rate limits were exceeded. It will just throw the\n`TooManyRequestsHttpException` no matter what.\n\nSome responses are triggered whenever rate limits are checked, such as the\n`RateLimitHeadersHandler` which will add its HTTP headers to every response\nto indicate to the client how it is doing with respect to its rate limits.\n\nOther responses, such as the `TooManyRequestsHttpExceptionHandler` will\nonly apply when rate limits are exceeded.\n\n#### Order of Responses\n\nThe order in which responses are added matters.\n\nResponse handlers are executed in the order in which they are attached to the\n`RateLimiter`. This means that an exception-throwing handler, like\n`TooManyRequestsHttpException`, must come after header-setting handlers, like\n`RateLimitHeadersHandler`.\n\n\nRecipes\n-------\n\nSee [Recipes](docs/recipes.md)\n\nSee Also\n--------\n\n* [Yii's Rate Limiter Docs](http://www.yiiframework.com/doc-2.0/guide-rest-rate-limiting.html)\n\n* [Yii's Event Docs](http://www.yiiframework.com/doc-2.0/guide-concept-events.html)\n\n* [Leaky Bucket Algorithm](http://en.wikipedia.org/wiki/Leaky_bucket)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthamtech%2Fyii2-ratelimiter-advanced","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthamtech%2Fyii2-ratelimiter-advanced","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthamtech%2Fyii2-ratelimiter-advanced/lists"}