
Besseres PHP-Rate-Limiting mit Redis.
<div align="center">
<a href="https://github.com/eddiejibson/limitrr-php"><img alt="chae" src="https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg" width="432.8" height="114.2"></a>
<br>
<br>
<!-- <img src="https://circleci.com/gh/eddiejibson/limitrr-php.svg?style=svg"></img> -->
<img src="https://www.codefactor.io/repository/github/eddiejibson/limitrr-php/badge">
<a href="https://paypal.me/eddiejibson/5"><img src="https://img.shields.io/badge/donate-PayPal-brightgreen.svg"></a>
<!-- <img src="https://requires.io/github/eddiejibson/chae-limitrr/requirements.svg?branch=master"> -->
<img src="https://img.shields.io/packagist/dt/eddiejibson/limitrr-php.svg">
Einfaches Rate-Limiting in PHP mit Redis.
</div>
Limitrr PHP ist stark von meiner anderen Bibliothek inspiriert, Limitrr, die für NodeJS erstellt wurde. Schauen Sie es sich [hier](http://github.com/eddiejibson/chae-limitrr) an.
Limitrr PHP ermöglicht es Benutzern, Rate-Limiting einfach in ihre Anwendung zu integrieren. Im Gegensatz zu anderen ähnlichen Paketen erlaubt dieses Dienstprogramm nicht nur die Begrenzung nach der Anzahl der Anfragen, sondern auch nach der Anzahl der abgeschlossenen Aktionen (z.B. das Erlauben einer bestimmten Anzahl erfolgreich erstellter Konten innerhalb eines Zeitraums) und die Einschränkung mit benutzerdefinierten Optionen. Darüber hinaus sind benutzerdefinierte Diskriminatoren möglich – Sie müssen nicht mehr nur nach der IP des Benutzers begrenzen.
Diese Bibliothek bietet auch eine Middleware-Funktion zum einfachen Ratelimiting verschiedener Routen innerhalb eines SlimPHP-Projekts.
Wenn Ihnen dieses Projekt gefällt, geben Sie ihm bitte einen 🌟 auf GitHub.
**Pull Requests sind willkommen**
## Installation
Sie können die limitrr-php-Bibliothek installieren, indem Sie den folgenden Befehl in Ihrem Terminal ausführen (vorausgesetzt, Sie haben Composer [installiert](https://getcomposer.org/download/))
```bash
composer require eddiejibson/limitrr-php "^1.0"
```
## Kurzanleitung
### Grundlegende Nutzung
```php
require "/vendor/autoload.php"; //Require composer's autoload
$options = [
//Redis keystore information
"redis" => [
"host" => "666.chae.sh",
"port" => 6379,
"password" => "supersecret",
],
"routes" => [
"default" => [
"requestsPerExpiry" => 5,
],
],
];
//Initialize the Limitrr class and pass the options defined above into it
//Note that the options are not required.
$limitrr = new \eddiejibson\limitrr\Limitrr($options);
//Various examples like this can be found further into the documentation,
//for each function.
$result = $limitrr->get(["discriminator" => $ip]);
echo $result["requests"] + " Requests";
echo $result["completed"] + " Completed";
//Note that this library is no means just for SlimPHP, it just happens to
//provide a middleware function for those who may need it.
//Usage within SlimPHP
$app = new Slim\App();
//Use the Limitrr SlimPHP middleware function, if you wish:
$app->add(new \eddiejibson\limitrr\RateLimitMiddleware($limitrr)); //Make sure to pass in the main Limitrr
//instance we defined above into the middleware function. This is mandatory.
//You can also add the get IP middleware function, it will append the user's real IP
//(behind Cloudflare or not) to the request.
$app->add(new \eddiejibson\limitrr\getIpMiddleware());
//Example usage within a route
$app->get("/hello/{name}", function ($request, $response, $args) {
$name = $args["name"];
$ip = $request->getAttribute('realip'); //Get the IP that was defined within Limitrr's get IP middleware function
return $response->getBody()->write("Hello, ${name}. Your IP is ${ip}.");
});
//You do not have to app the middleware function to every single route, globally.
//You can do it indivually, too - along with passing options into such. Like so:
$app->get("/createUser/{name}", function ($request, $response, $args) {
//Non intensive actions like simple verification will have a different limit to intensive ones.
//and will only be measured in terms of each request via the middleware.
//No further action is required.
if (strlen($args["name"]) < 5) {
//Dummy function creating user
$res = $someRandomClass->registerUser();
if ($res) {
//Intensive actions like actually registering a user should have a
//different limit to normal requests, hence the completedActionsPerExpiry option.
//and should only be added to once this task has been completed fully
//In this example, we will be limiting the amount of completed actions a certain IP can make.
//Anything can be passed in here, however. For example, a email address or user ID.
//$request->getAttribute('realip') was determined by calling the middleware earlier - getIpMiddleware()
$limitrr->complete(["discriminator"] => $ip);
}
}
})->add(new \eddiejibson\limitrr\RateLimitMiddleware($limitrr, ["route"=>"createUser"]));
//You can also pass the route name within the limitrr middleware function
$app->run();
```
### Wert eines bestimmten Schlüssels abrufen
#### limitrr->get()
**Rückgabe:** Array
```php
$limitrr->get([
"discriminator" => $discriminator, //Erforderlich
"route" => $route, //Nicht erforderlich, Standard wird angenommen
"type" => $type //Nicht erforderlich
]);
```
##### ->get()-Parameter
***Müssen als Array an die Funktion übergeben werden***
- **discriminator:** **Erforderlich** Wobei discriminator das ist, was begrenzt wird (z. B. x erledigte Aktionen pro Diskriminator)
- **route**: *String* Von welcher Route sollen die Werte abgerufen werden? Wenn nicht gesetzt, werden die Werte von der `default`-Route abgerufen.
- **type**: *String* Statt beide Werte abzurufen, können Sie in diesem Schlüssel entweder `requests` oder `completed` angeben, und nur dieser wird als Ganzzahl zurückgegeben.
##### ->get()-Beispiele
```php
$limitrr->get([
"discriminator" => $discriminator,
"type" => $type,
"route" => $route
]); //Außer discriminator sind alle Parameter optional.
//Wenn type nicht an die Funktion übergeben wird, gibt sie
//sowohl die Anzahl der Anfragen als auch der abgeschlossenen Aktionen zurück
//Wobei discriminator das ist, was begrenzt wird
//z. B. x abgeschlossene Aktionen/Anfragen pro Diskriminator
$limitrr->get(["discriminator" => $discriminator]);
//Dies ist in der Regel die IP des Benutzers.
$limitrr->get(["discriminator" => $ip]);
//Dies gibt sowohl die Anzahl der Anfragen als auch der abgeschlossenen Aktionen zurück, die unter dem
//angegebenen Diskriminator in einem Objekt gespeichert sind. Sie können so damit umgehen:
$result = $limitrr->get(["discriminator" => $ip]);
echo $result["requests"] + " Requests";
echo $result["completed"] + " Completed";
//Das obige Beispiel würde die Anzahl der Anfragen und erledigten Aufgaben von der Standardroute
//abrufen. Wenn Sie Werte von einer anderen Route abrufen möchten, können Sie
//diese ebenfalls angeben. Dies kann so erfolgen:
$result = $limitrr->get(["discriminator" => $ip, "route" => "exampleRouteName"]);
echo $result["requests"] . " Requests made through the route exampleRouteName";
echo $result["completed"] . " Completed Tasks made through the route exampleRouteName";
//Sie können auch nur einen einzigen Wert abrufen – statt sowohl Anfragen als auch Erledigte.
$result = $limitrr->get(["discriminator" => $ip, "route" => "exampleRouteName", "type" => "completed"]);
echo $result["completed"] . " Completed tasks made through the route exampleRouteName";
```
### Anzahl abgeschlossener Aktionen/Aufgaben
#### limitrr->complete()
**Rückgabe:** Integer
```php
$limitrr->get([
"discriminator" => $discriminator, //Erforderlich
"route" => $route, //Nicht erforderlich, Standard wird angenommen
]);
```
##### ->complete()-Parameter
***Müssen als Array an die Funktion übergeben werden***
- **discriminator:** **Erforderlich** Wobei discriminator das ist, was begrenzt wird (z. B. x erledigte Aktionen pro Diskriminator)
- **route**: *String* In welche Route sollen die Werte eingefügt werden? Wenn nicht gesetzt, werden die Werte von der `default`-Route eingefügt.
### Entfernung von Werten aus bestimmten Anfrage-/abgeschlossen-Schlüsseln
#### limitrr->reset()
**Rückgabe:** Boolean
```php
$limitrr->reset([
"discriminator" => $discriminator, //Erforderlich
"route" => $route, //Nicht erforderlich, Standard wird angenommen,
"type" => $type //Nicht erforderlich
]);
```
##### ->reset()-Parameter
***Müssen als Array an die Funktion übergeben werden***
- **discriminator:** **Erforderlich** Wobei discriminator das ist, was begrenzt wird (z. B. x erledigte Aktionen pro Diskriminator)
- **route**: *String* Von welcher Route sollen die Werte zurückgesetzt werden? Wenn nicht gesetzt, werden die Werte von der `default`-Route zurückgesetzt.
- **type**: *String* Welcher Zähler soll zurückgesetzt werden? `requests` oder `completed`? Wenn nicht gesetzt, werden beide entfernt.
```php
//Wobei discriminator das ist, was begrenzt wird
//z. B. x abgeschlossene Aktionen/Anfragen pro Diskriminator
//Dies entfernt sowohl die Anzahl der Anfragen als auch die Anzahl der abgeschlossenen Aktionen
$limitrr->reset(["discriminator" => $discriminator]);
//Dies ist in der Regel die IP des Benutzers.
$limitrr->reset(["discriminator" => $ip]);
//Wenn Sie Zähler von einer bestimmten Route zurücksetzen möchten, kann dies ebenfalls erfolgen.
//Da der Typ nicht angegeben ist, werden sowohl die Anfragen- als auch die abgeschlossenen Zähler entfernt.
$result = $limitrr->reset([
"discriminator" => $ip,
"route" => "exampleRouteName"
]);
if ($result) {
echo "Requests removed from the route exampleRouteName";
} else {
//Do something else
}
//Wenn Sie nur entweder die Anzahl der Anfragen oder die der abgeschlossenen Aktionen entfernen möchten,
//aber nicht die andere, kann dies ebenfalls erfolgen.
//Der übergebene Wert kann entweder "requests" oder "completed" sein.
//In diesem Beispiel entfernen wir die Anzahl der Anfragen für eine bestimmte IP.
$result = $limitrr->reset([
"discriminator" => $ip,
"type" => "requests"
]);
if ($result) {
echo "Request count for the specified IP were removed"
} else {
//do something else
}
```
## Konfiguration
### redis
**Erforderlich:** false
**Typ:** Array ODER String
**Beschreibung:** Redis-Verbindungsinformationen.
***Entweder einen String mit der URI der Redis-Instanz oder ein Objekt mit den Verbindungsinformationen übergeben:***
- **port**: *Integer* Redis-Port. Standardwert: `6379`
- **host**: *String* Redis-Hostname. Standardwert: `"127.0.0.1"`
- **password**: *String* Redis-Passwort. Standardwert: `""`
- **database**: *Integer* Redis-DB. Standardwert: `0`
#### Beispiel des redis-Arrays/-Strings, das an Limitrr übergeben werden könnte
```php
//Übergeben Sie einen String mit einer Redis-URI.
"redis" => "redis://127.0.0.1:6379/0"
//Alternativ ein Array mit den Verbindungsinformationen verwenden.
"redis" => [
"port" => 6379, //Redis-Port. Erforderlich: false. Standardwert: 6379
"host" => "127.0.0.1", //Redis-Hostname. Erforderlich: false. Standardwert: "127.0.0.1".
"password" => "mysecretpassword1234", //Redis-Passwort. Erforderlich: false. Standardwert: null.
"database" => 0 //Redis-Datenbank. Erforderlich: false. Standardwert: 0.
]
```
### options
**Erforderlich:** false
**Typ:** Array
**Beschreibung:** Verschiedene Optionen für Limitrr.
- **keyName:** String Der Schlüsselname, unter dem alle Anfragen gespeichert werden. Dies dient hauptsächlich ästhetischen Zwecken und hat keine großen Auswirkungen. Es sollte jedoch bei jeder Initialisierung der Hauptklasse geändert werden, um Konflikte zu vermeiden. Standardwert: `"limitrr"`
- **errorStatusCode:** Integer Statuscode, der zurückgegeben wird, wenn der Benutzer ratelimited wird. Standardwert: `429` (Too Many Requests)
#### Beispiel des options-Objekts, das an Limitrr übergeben werden könnte
```php
"options" => [
"keyName" => "myApp", //Der Schlüsselname, unter dem alle Anfragen gespeichert werden. Erforderlich: false. Standardwert: "limitrr"
"errorStatusCode" => 429 //Sollen wichtige Fehler wie Verbindungsfehler zum Redis-Keyspeicher abgefangen und angezeigt werden?
]
```
### routes
**Erforderlich:** false
**Typ:** Array
**Beschreibung:** Definieren Sie Routeneinschränkungen.
Im routes-Objekt können Sie viele separate Routen definieren und darin benutzerdefinierte Regeln festlegen. Die einstellbaren benutzerdefinierten Regeln sind:
- **requestsPerExpiry**: *Integer* Wie viele Anfragen werden akzeptiert, bis der Benutzer ratelimited wird? Standardwert: `100`
- **completedActionsPerExpiry**: *Integer* Wie viele abgeschlossene Aktionen werden akzeptiert, bis der Benutzer ratelimited wird? Dies ist nützlich für bestimmte Aktionen wie das Registrieren eines Benutzers – sie können eine bestimmte Anzahl von Anfragen haben, aber eine andere (offensichtlich kleinere) Anzahl von „abgeschlossenen Aktionen". Wenn also unter derselben IP (oder einem anderen Diskriminator) kürzlich mehrfach erfolgreich Benutzer registriert wurden, können sie ratelimited werden. Sie dürfen vielleicht 100 Anfragen pro bestimmter Ablaufzeit für allgemeine Validierungen und dergleichen, aber nur einen kleinen Bruchteil davon für intensive Verfahren. Standardwert: der Wert in `requestsPerExpiry` oder `5`, wenn nicht gesetzt.
- **expiry**: *Integer* Wie lange sollen die Anfragen gespeichert werden (in Sekunden), bevor sie auf 0 zurückgesetzt werden? Wenn auf -1 gesetzt, laufen Werte nie ab und bleiben auf unbestimmte Zeit so oder müssen manuell entfernt werden. Standardwert: `900` (15 Minuten)
- **completedExpiry**: *Integer* Wie lange sollen die „abgeschlossenen Aktionen" (wie die Anzahl der von einer bestimmten IP oder einem anderen Diskriminator registrierten Benutzer) gespeichert werden (in Sekunden), bevor sie auf 0 zurückgesetzt werden? Wenn auf -1 gesetzt, laufen solche Werte nie ab und bleiben auf unbestimmte Zeit so oder müssen manuell entfernt werden. Standardwert: der Wert in `expiry` oder `900` (15 Minuten), wenn nicht gesetzt.
- **errorMsgs**: *Objekt* Separate Fehlermeldungen für zu viele Anfragen und zu viele abgeschlossene Aktionen. Ihnen wurden die entsprechenden Schlüsselnamen „requests" und „actions" gegeben. Diese werden dem Benutzer zurückgegeben, wenn er ratelimited wird. Wenn in `requests` kein String festgelegt wurde, wird standardmäßig `„As you have made too many requests, you are being rate limited."` verwendet. Wenn in `completed` kein Wert festgelegt wurde, wird auf den String in `requests` zurückgegriffen. Oder, falls auch dieser nicht festgelegt wurde, wird `„As you performed too many successful actions, you have been rate limited."` als Wert verwendet.
#### Beispiel des routes-Arrays
```php
"routes" => [
//Standard-Routenregeln überschreiben – nicht alle Schlüssel müssen gesetzt sein,
//nur die, die Sie überschreiben möchten
"default" => [
"expiry": 1000
],
"exampleRoute" => [
"requestsPerExpiry" => 100,
"completedActionsPerExpiry" => 5,
"expiry" => 900,
"completedExpiry" => 900,
"errorMsgs" => [
"requests" => "As you have made too many requests, you are being rate limited.",
"completed" => "As you performed too many successful actions, you have been rate limited."
]
],
//Wenn nicht alle Schlüssel gesetzt sind, werden sie auf die
//Standardwerte zurückgesetzt
"exampleRoute2" => [
"requestsPerExpiry" => 500
]
]
```