Implementing Rate Limiting in PHP with Redis

Learn how to implement rate limiting in PHP using Redis.

Redis is a data storage system that can be used for caching, session management, and more. It’s incredibly fast because it uses the RAM to store data. This makes it a great choice for applications that need to store a lot of data or need to access data quickly.

Rate limiting is a technology that limits the number of requests that can be made to a server over a given period of time. This can be used to protect servers from being overwhelmed by requests, or to ensure that requests from a given IP address are not made too frequently.

Prerequisites

  • A working PHP environment
  • Redis installed on your server
  • The php-redis extension installed

Writing the Rate Limit Logic

Let’s create a PHP file called rate.php in the root directory of the web server (e.g. /var/www/html/).

We will initialize a Redis connection:

<?php
// rate.php

$redis = new \Redis();
$redis->connect('localhost', 6379);
$redis->auth('YOUR_PASSWORD');

This code creates a new instance of the Redis class, and then connects to the Redis server on the localhost port 6379. The code then authenticates with the Redis server by providing the password.

Next, let’s retrieve the client’s IP address:

if(!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
    // For websites using cloudflare
    $ipAddress = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif(!empty($_SERVER['HTTP_CLIENT_IP'])) {
    $ipAddress = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ipAddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    $ipAddress = $_SERVER['REMOTE_ADDR'];
}

This code checks for a number of different variables that might contain the IP address of the website visitor. If any of these variables are not empty, then the IP address is stored in the $ipAddress variable.

For the purposes of this tutorial, we are using the client’s IP address for the rate limiter. You can use a user unique identifier as the rate limiter key.

Now let’s implement the rate limiter logic:

$timePeriod = 60;        // The time period in seconds (Default: 60 seconds)
$actionsPerPeriod = 5;   // Actions per period (E.g.: 5 actions per minute)

// The name of the Redis key.
// We use the client's IP address as the key.
$rateKeyName = "rate-limit-" . $ipAddress;

if(!$redis->exists($rateKeyName)) {
    // If the key doesn't exist then set it with the value of 1.
    $redis->set($rateKeyName, 1);
    // Make it expire after the set time period.
    $redis->expire($rateKeyName, $timePeriod);
} else {
    // Increment by one.
    $redis->incr($rateKeyName);
    // Get the number of total actions.
    $totalActions = $redis->get($rateKeyName);

    if($totalActions > $actionsPerPeriod) {
        http_response_code(429);
        echo "You're being rate limited";
        die();
    }
}

echo "Hello, welcome to my page.";

This code sets a limit on the number of actions that a user can take in a given time period. The time period is set in seconds and the number of actions that can be taken in that time period is set to 5. If the user exceeds the number of allowed actions, they are given an error message and the script terminates.

We can take a look at our keys inside the redis client after we visit the page:

127.0.0.1:6379> keys rate-limit-*
1) "rate-limit-192.168.1.101"
127.0.0.1:6379> get rate-limit-192.168.1.101
"1"
127.0.0.1:6379> 

Conclusion

In this article, we’ve explored how to implement a rate limiter using Redis and PHP to protect your server from being overwhelmed by excessive requests. Rate limiting is a crucial aspect of web application security and performance optimization, as it helps prevent abuse of your resources and ensures a fair distribution of your services.