detain/rate-limit

PHP rate limiting library with Token Bucket and Leaky Bucket Algorithms, based on palepurple/rate-limit, grandson to touhonoob/rate-limit, and jeroenvisser101/LeakyBucket

3.0.1 2022-08-18 08:20 UTC

This package is auto-updated.

Last update: 2024-10-18 12:57:02 UTC


README

GitHub Build Travis Build Coverage Status Code Climate Scrutinizer Code Quality Codacy Badge

Latest Stable Version Total Downloads Latest Unstable Version License Monthly Downloads Daily Downloads

PHP Rate Limiting library with both Token Bucket and Leaky Bucket Algorithms, minimal external dependencies, and many storage backends.

Algorithms

  • Token Bucket Algorithm Token Bucket is an algorithm which works as follows:

    • There is a bucket.
    • A token is added to the bucket every 1/r seconds.
    • The bucket can hold at the most b tokens. If a token arrives when the bucket is full, it is discarded.
    • When a packet (network layer PDU) of n bytes arrives,
      • If at least n tokens are in the bucket, n tokens are removed from the bucket, and the packet is sent to the network.
      • if fewer than n tokens are available, no tokens are removed from the bucket, and the packet is considered to be non-conformant.
  • Leaky Bucket Algorithm Leaky Bucket is an algorithm which works as follows:

    • There is a bucket.
    • The bucket has a defined leak and defined capacity.
    • The bucket leaks at a constant rate.
    • Overflows when full, will not add other drops to the bucket.

Storage Adapters

The RateLimiter needs to know where to get/set data.

Depending on which adapter you install, you may need to install additional libraries (predis/predis or tedivm/stash) or PHP extensions (e.g. Redis, Memcache, APCu)

Installing via Composer

curl -sS https://getcomposer.org/installer | php
composer.phar require detain/rate-limit

Usage

Token Bucket

require 'vendor/autoload.php';

use \Detain\RateLimit\RateLimit;
use \Detain\RateLimit\Adapter\APCu as APCAdapter;
use \Detain\RateLimit\Adapter\Redis as RedisAdapter;
use \Detain\RateLimit\Adapter\Predis as PredisAdapter;
use \Detain\RateLimit\Adapter\Memcached as MemcachedAdapter;
use \Detain\RateLimit\Adapter\Stash as StashAdapter;


$adapter = new APCAdapter(); // Use APC as Storage
// Alternatives:
//
// $adapter = new RedisAdapter((new \Redis()->connect('localhost'))); // Use Redis as Storage
//
// $adapter = new PredisAdapter(new \Predis\Predis(['tcp://127.0.0.1:6379'])); // Use Predis as Storage
//
// $memcache = new \Memcached();
// $memcache->addServer('localhost', 11211);
// $adapter = new MemcacheAdapter($memcache); 
//
// $stash = new \Stash\Pool(new \Stash\Driver\FileSystem());
// $adapter = new StashAdapter($stash);

$rateLimit = new RateLimit("myratelimit", 100, 3600, $adapter); // 100 Requests / Hour

$id = $_SERVER['REMOTE_ADDR']; // Use client IP as identity
if ($rateLimit->check($id)) {
  echo "passed";
} else {
  echo "rate limit exceeded";
}

Leaky Bucket

Basic usage

<?php

use \Detain\RateLimit\LeakyBucket;
use \Detain\RateLimit\Adapter\Redis as RedisAdapter;

$adapter = new RedisAdapter((new \Redis()->connect('localhost'))); // Use Redis as Storage

// Define the bucket
$settings = [
	'capacity' => 10,
	'leak'     => 1
];

// Create the bucket
$bucket = new LeakyBucket('example-bucket', $storage, $settings);

// Fill the bucket
$bucket->fill();

// Check if it's full
if ($bucket->isFull()) {
	header('HTTP/1.1 429 Too Many Requests');
	exit '<!doctype html><html><body><h1>429 Too Many Requests</h1><p>You seem to be doing a lot of requests. You\'re now cooling down.</p></body></html>';
}

// ...

Other functionality

You can also do great stuff with it through the methods that LeakyBucket provides.

// Get capacity information
$capacityTotal = $bucket->getCapacity();
$capacityLeft  = $bucket->getCapacityLeft();
$capacityUsed  = $bucket->getCapacityUsed();

// Get the drops/second that the bucket leaks
$leakPerSecond = $bucket->getLeak();

// Get the last timestamp from when the bucket was updated
$timestamp = $bucket->getLastTimestamp();

// Set additional data
$bucket->setData(
	[
		'timeout' => 3600
	]
);

// Get additional data
$data = $bucket->getData();

// Update the bucket with the leaked drops
$bucket->leak();

// Remove excess drops
$bucket->overflow();

// Update the bucket's timestamp manually
$bucket->touch();

// Fill the bucket with one drop
$bucket->fill();

// Fill the bucket with 5 drops
$bucket->fill(5);

// Spill one drop from the bucket
$bucket->spill();

// Spill 5 drops from the bucket
$bucket->spill(5);

// Remove the bucket's content
$bucket->reset();

// Force save
$bucket->save();

References

Continuation or Expansion of these Projects

Knowledge

PSR-7 Middleware Handlers to Base the Future PSR7 Support Off Of

  • nikolaposa/rate-limit 🚔 Standalone component that facilitates rate-limiting functionality. Also provides a middleware designed for API and/or other application endpoints.
  • robwittman/leaky-bucket-rate-limiter PSR-7 Leaky Bucket Rate Limiter - This middleware enables API Rate-Limiting based on a Leaky Bucket algorithm.