• Stars
    star
    328
  • Rank 124,299 (Top 3 %)
  • Language
    PHP
  • License
    MIT License
  • Created about 10 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Add rate limits to your controllers / actions easily through annotations

NoxlogicRateLimitBundle

Build Status Code Coverage Scrutinizer Code Quality

Latest Stable Version Total Downloads Latest Unstable Version License

This bundle provides enables the @RateLimit annotation which allows you to limit the number of connections to actions. This is mostly useful in APIs.

The bundle is prepared to work by default in cooperation with the FOSOAuthServerBundle. It contains a listener that adds the OAuth token to the cache-key. However, you can create your own key generator to allow custom rate limiting based on the request. See Create a custom key generator below.

This bundle is partially inspired by a GitHub gist from Ruud Kamphuis: https://gist.github.com/ruudk/3350405

Features

  • Simple usage through annotations
  • Customize rates per controller, action and even per HTTP method
  • Multiple storage backends: Redis, Memcached and Doctrine cache

Installation

Installation takes just few easy steps:

Step 1: Add the bundle to your composer.json

If you're not yet familiar with Composer see http://getcomposer.org. Add the NoxlogicRateLimitBundle in your composer.json:

{
    "require": {
        "noxlogic/ratelimit-bundle": "1.x"
    }
}

Now tell composer to download the bundle by running the command:

php composer.phar update noxlogic/ratelimit-bundle

Step 2: Enable the bundle

Enable the bundle in the kernel:

<?php
// app/AppKernel.php

public function registerBundles()
{
    $bundles = array(
        // ...
        new Noxlogic\RateLimitBundle\NoxlogicRateLimitBundle(),
    );
}

Step 3: Install a storage engine

Redis

If you want to use Redis as your storage engine, you might want to install SncRedisBundle:

Memcache

If you want to use Memcache, you might want to install LswMemcacheBundle

Doctrine cache

If you want to use Doctrine cache as your storage engine, you might want to install DoctrineCacheBundle:

Referer to their documentations for more details. You can change your storage engine with the storage_engine configuration parameter. See Configuration reference.

Configuration

Enable bundle only in production

If you wish to enable the bundle only in production environment (so you can test without worrying about limit in your development environments), you can use the enabled configuration setting to enable/disable the bundle completely. It's enabled by default:

# config_dev.yml
noxlogic_rate_limit:
    enabled: false

Configuration reference

This is the default bundle configuration:

noxlogic_rate_limit:
    enabled:              true

    # The storage engine where all the rates will be stored
    storage_engine:       ~ # One of "redis"; "memcache"; "doctrine"; "php_redis"; "php_redis_cluster"

    # The redis client to use for the redis storage engine
    redis_client:         default_client
    
    # The Redis service, use this if you dont use SncRedisBundle and want to specify a service to use
    # Should be instance of \Predis\Client
    redis_service:    null # Example: project.predis

    # The Redis client to use for the php_redis storage engine
    # Depending on storage_engine an instance of \Redis or \RedisCluster
    php_redis_service:    null # Example: project.redis

    # The memcache client to use for the memcache storage engine
    memcache_client:      default
    
    # The Memcached service, use this if you dont use LswMemcacheBundle and want to specify a service to use
    # Should be instance of \Memcached
    memcache_service:    null # Example: project.memcached

    # The Doctrine Cache provider to use for the doctrine storage engine
    doctrine_provider:    null # Example: my_apc_cache
    
    # The Doctrine Cache service, use this if you dont use DoctrineCacheBundle and want to specify a service to use
    # Should be an instance of \Doctrine\Common\Cache\Cache
    doctrine_service:    null # Example: project.my_apc_cache

    # The HTTP status code to return when a client hits the rate limit
    rate_response_code:   429

    # Optional exception class that will be returned when a client hits the rate limit
    rate_response_exception:  null

    # The HTTP message to return when a client hits the rate limit
    rate_response_message:  'You exceeded the rate limit'

    # Should the ratelimit headers be automatically added to the response?
    display_headers:      true

    # What are the different header names to add
    headers:
        limit:                X-RateLimit-Limit
        remaining:            X-RateLimit-Remaining
        reset:                X-RateLimit-Reset

    # Rate limits for paths
    path_limits:
        path:                 ~ # Required
        methods:

            # Default:
            - *
        limit:                ~ # Required
        period:               ~ # Required
        
    # - { path: /api, limit: 1000, period: 3600 }
    # - { path: /dashboard, limit: 100, period: 3600, methods: ['GET', 'POST']}

    # Should the FOS OAuthServerBundle listener be enabled 
    fos_oauth_key_listener: true

Usage

Simple rate limiting

To enable rate limiting, you only need to add the annotation to the docblock of the specified action

<?php

use Noxlogic\RateLimitBundle\Annotation\RateLimit;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

/**
 * @Route(...)
 *
 * @RateLimit(limit=1000, period=3600)
 */
public function someApiAction()
{
}

Limit per method

It's possible to rate-limit specific HTTP methods as well. This can be either a string or an array of methods. When no method argument is given, all other methods not defined are rated. This allows to add a default rate limit if needed.

<?php

use Noxlogic\RateLimitBundle\Annotation\RateLimit;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

/**
 * @Route(...)
 *
 * @RateLimit(methods={"PUT", "POST"}, limit=1000, period=3600)
 * @RateLimit(methods={"GET"}, limit=1000, period=3600)
 * @RateLimit(limit=5000, period=3600)
 */
public function someApiAction()
{
}

Limit per controller

It's also possible to add rate-limits to a controller class instead of a single action. This will act as a default rate limit for all actions, except the ones that actually defines a custom rate-limit.

<?php

use Noxlogic\RateLimitBundle\Annotation\RateLimit;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

/**
 * @Ratelimit(methods={"POST"}, limit=100, period=10); // 100 POST requests per 10 seconds
 */
class DefaultController extends Controller
{
    /**
     * @Ratelimit(method="POST", limit=200, period=10); // 200 POST requests to indexAction allowed.
     */
    public function indexAction()
    {
    }
}

Create a custom key generator

NOTE

Note that this bundle by default does not perform rate-limiting based on user's IP. If you wish to enable IP-based rate limiting or any other strategy, custom key generators are the way to go.

If you need to create a custom key generator, you need to register a listener to listen to the ratelimit.generate.key event:

services:
    mybundle.listener.rate_limit_generate_key:
        class: MyBundle\Listener\RateLimitGenerateKeyListener
        tags:
            - { name: kernel.event_listener, event: 'ratelimit.generate.key', method: 'onGenerateKey' }
<?php

namespace MyBundle\Listener;

use Noxlogic\RateLimitBundle\Events\GenerateKeyEvent;

class RateLimitGenerateKeyListener
{
    public function onGenerateKey(GenerateKeyEvent $event)
    {
        $key = $this->generateKey();

        $event->addToKey($key);
        // $event->setKey($key); // to overwrite key completely
    }
}

Make sure to generate a key based on what is rate limited in your controllers.

And example of a IP-based key generator can be:

<?php

namespace MyBundle\Listener;

use Noxlogic\RateLimitBundle\Events\GenerateKeyEvent;

class IpBasedRateLimitGenerateKeyListener
{
    public function onGenerateKey(GenerateKeyEvent $event)
    {
        $request = $event->getRequest();
        $event->addToKey($request->getClientIp());
    }
}

Throwing exceptions

Instead of returning a Response object when a rate limit has exceeded, it's also possible to throw an exception. This allows you to easily handle the rate limit on another level, for instance by capturing the kernel.exception event.

Running tests

If you want to run the tests use:

./vendor/bin/phpunit ./Tests

More Repositories

1

Transphpile

PHP 7 to PHP 5.6 Transpiler
PHP
176
star
2

HTRouter

HTRouter a PHP 5.4 Internal Webserver .htaccess parser and interpreter.
PHP
119
star
3

traceroute

A PHP Traceroute example
PHP
43
star
4

c64php

C64 emulator written in PHP
PHP
35
star
5

SFConsole

Symfony2 console completion script
Shell
27
star
6

symfony2-puppet

A simple layout of your Vagrant / puppet manifests that you can drop into your root directory of your symfony2 project
Puppet
26
star
7

symfony2-puppet-new

A generic symfony2 project managed with vagrant / puppet
Puppet
20
star
8

MultiParamBundle

MultiParam Annotation Bundle
PHP
16
star
9

RealTimePHPUnit

Get realtime phpunit feedback when files change.
Shell
13
star
10

CFP

CFP
PHP
11
star
11

TLS-decoder

Proof of concept TLS decoder
PHP
11
star
12

CybOS

The CybOS operating system
C
10
star
13

phpshout

Shoutcast / iceCast / LibShout2 php extention
C
8
star
14

gitstash

A simple GitHub clone called GitStash
PHP
7
star
15

Autotools

Autotools
C
7
star
16

bgphpsnake

PHP
7
star
17

puppet-facter-zendserver

ZendServer fact for puppet's facter
Ruby
5
star
18

MCollectivePHP

PoC on using PHP for MCollective agents
PHP
5
star
19

switchbox

implementation of a PHP client for the v2 telehash protocol
PHP
5
star
20

boxconfig

A simple site that allows you to setup / display your development box configurations
PHP
5
star
21

GPSFix

Simple GPS Locator service for Android
5
star
22

restifony

Rest API framework based on Symfony2
4
star
23

asn1

PHP ASN.1 extension
C
4
star
24

PuzzleChess

puzzlechess
Java
3
star
25

mastodon

POC mastodon server
PHP
3
star
26

changecase

2
star
27

virtualpacman

Using Google Maps for a virtual pacman game.
PHP
2
star
28

vimrc

vim syntax
Vim Script
2
star
29

xdbgprxy

Go
2
star
30

TinyMCE-Keyword-plugin

TinyMCE Keyword plugin
JavaScript
2
star
31

otas

Open Text Adventure System (OTAS)
PHP
2
star
32

collection_test

PHP
1
star
33

TermBox

PHP native TermBox
PHP
1
star
34

phpt-vim-syntax-file

Vim syntax file for phpt files (php testfiles)
Vim Script
1
star
35

Project-Aquarius

Arduino aquarius
C
1
star
36

Wyg

Wyg
PHP
1
star
37

joindin_symfony2

Joind.in in symfony2
JavaScript
1
star
38

test

test
PHP
1
star
39

wolf3d

Python version of a raycaster
Python
1
star
40

til-generator

Today I learned
Twig
1
star
41

saffire_tests

tests and examples for saffire
C
1
star
42

saffire-intellij-plugin

Java
1
star
43

ShortId

ShortID generator that serves as an alternative for UUIDs
1
star
44

typearray

Typed Array
PHP
1
star
45

dotfiles

1
star
46

DbalKeyRotate

DBAL driver for AWS secrets manager key rotation
PHP
1
star
47

CFP-1

PHP
1
star
48

domain-grabber

Shell
1
star
49

broodhub.nl

Broodhub site
HTML
1
star
50

Phpoton

Phpoton
PHP
1
star
51

jungle

BASIC
1
star
52

TLSRate-chrome

Chrome extension that rates your TLS connection
JavaScript
1
star
53

Sencha-Touch-Commander-2

Conversion of Sencha-Command to the Sencha Touch 2 framework
1
star
54

SpamDing

SpamDing - Personal mailinator clone written in Silex
JavaScript
1
star
55

RestAPI

Restfull API
PHP
1
star
56

symfony-security-autologin

PHP
1
star
57

uzi-acme-client

PHP
1
star
58

WhoToUnfollow

Gives a list of status from friends sorted on time. Makes is easy to get rid of old/idle users.
PHP
1
star
59

jaytaph.github.com

jaytaph.github.com
1
star