diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
index b73e9cd..a11537e 100644
--- a/.github/workflows/php.yml
+++ b/.github/workflows/php.yml
@@ -6,7 +6,7 @@ on:
jobs:
sanity-check:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
env:
key: cache-v1
extensions: apc, redis, apcu, memcache, memcached
@@ -18,7 +18,7 @@ jobs:
id: extcache
uses: shivammathur/cache-extensions@v1
with:
- php-version: 7.4
+ php-version: 8.0
extensions: ${{ env.extensions }}
key: ${{ env.key }}
@@ -32,7 +32,7 @@ jobs:
- name: Setup PHP {{ matrix.php-versions }}
uses: shivammathur/setup-php@v2
with:
- php-version: 7.4
+ php-version: 8.0
tools: composer
extensions: ${{ env.extensions }}
ini-values: apc.enable_cli=1
@@ -54,7 +54,7 @@ jobs:
unit-test:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
needs: [sanity-check]
env:
key: cache-v1
@@ -72,7 +72,7 @@ jobs:
- 11211:11211
strategy:
matrix:
- php-versions: [ '7.2', '7.3', '7.4', '8.0', '8.1', '8.2' ]
+ php-versions: [ '8.0', '8.1', '8.2', '8.3' ]
steps:
diff --git a/.php_cs.dist b/.php_cs.dist
deleted file mode 100644
index 7a7ee91..0000000
--- a/.php_cs.dist
+++ /dev/null
@@ -1,11 +0,0 @@
-exclude('vendor')
- ->in(__DIR__);
-
-return PhpCsFixer\Config::create()
- ->setFinder($finder)
- ->setRules(array(
- '@PSR2' => true,
- ));
diff --git a/README.md b/README.md
index 6878edb..3aa02bf 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,6 @@
[![GitHub Build](https://github.com/DavidGoodwin/RateLimit/actions/workflows/php.yml/badge.svg)](https://github.com/DavidGoodwin/RateLimit/actions/workflows/php.yml)
-[![Travis Build](https://travis-ci.org/DavidGoodwin/RateLimit.svg)](https://travis-ci.org/DavidGoodwin/RateLimit/)
-
[![Coverage Status](https://coveralls.io/repos/github/DavidGoodwin/RateLimit/badge.svg?branch=master)](https://coveralls.io/github/DavidGoodwin/RateLimit?branch=master)
PHP Rate Limiting Library With Token Bucket Algorithm with minimal external dependencies.
diff --git a/composer.json b/composer.json
index 885c3a3..13ffb62 100644
--- a/composer.json
+++ b/composer.json
@@ -3,18 +3,18 @@
"name": "palepurple/rate-limit",
"description": "PHP rate limiting library with Token Bucket Algorithm, originally touhonoob/rate-limit",
"require": {
- "php": ">= 5.6"
+ "php": ">= 8.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^2.7",
"php-parallel-lint/php-parallel-lint": "^1.0",
"php-coveralls/php-coveralls": "^2.2",
- "phpunit/phpunit": "^8",
- "predis/predis": "^1.1",
+ "phpunit/phpunit": "^8|^9",
+ "predis/predis": "^1.1|2.0",
"psr/cache": "^1.0",
- "tedivm/stash": "^0.16",
+ "tedivm/stash": "^0.16|^1.0",
"psalm/phar": "*",
- "phpstan/phpstan": "*"
+ "phpstan/phpstan": "*",
+ "slevomat/coding-standard": "^8.15"
},
"suggest": {
"tedivm/stash": "^0.15",
@@ -45,8 +45,13 @@
"psalm" : "@php ./vendor/bin/psalm.phar src",
"phpstan" : "@php vendor/bin/phpstan analyse --level 6 src",
"lint": "@php ./vendor/bin/parallel-lint --exclude vendor/ .",
- "check-format": "@php ./vendor/bin/php-cs-fixer fix --ansi --dry-run --diff",
- "format": "@php ./vendor/bin/php-cs-fixer fix --ansi",
+ "check-format": "@php ./vendor/bin/phpcs src",
+ "format": "@php ./vendor/bin/phpcbf src",
"test": "@php ./vendor/bin/phpunit"
+ },
+ "config": {
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
}
}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..4b882c1
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/psalm.xml b/psalm.xml
index 97b2bd3..186ea8b 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -21,22 +21,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Adapter.php b/src/Adapter.php
index 228262c..981ee0e 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -14,23 +14,18 @@ abstract class Adapter
* @param float $value
* @param int $ttl - seconds after which this entry will expire e.g 50
*/
- abstract public function set($key, $value, $ttl);
-
- /**
- * @param string $key
- * @return float
- */
- abstract public function get($key);
-
+ abstract public function set(string $key, float $value, int $ttl);
+
/**
* @param string $key
- * @return bool
+ * @return float - the amount of request allowance left
*/
- abstract public function exists($key);
-
+ abstract public function get(string $key): float;
+
+ abstract public function exists(string $key): bool;
+
/**
- * @return bool
- * @param string $key
+ * @return bool - true if delete works
*/
- abstract public function del($key);
+ abstract public function del(string $key): bool;
}
diff --git a/src/Adapter/APC.php b/src/Adapter/APC.php
index 703af00..858f919 100644
--- a/src/Adapter/APC.php
+++ b/src/Adapter/APC.php
@@ -10,22 +10,22 @@
*/
class APC extends Adapter
{
- public function set($key, $value, $ttl)
+ public function set(string $key, float $value, int $ttl)
{
return apc_store($key, $value, $ttl);
}
- public function get($key)
+ public function get(string $key): float
{
- return apc_fetch($key);
+ return (float) apc_fetch($key);
}
- public function exists($key)
+ public function exists(string $key): bool
{
return apc_exists($key);
}
- public function del($key)
+ public function del(string $key): bool
{
return apc_delete($key);
}
diff --git a/src/Adapter/APCu.php b/src/Adapter/APCu.php
index 38b74c3..8a54d49 100644
--- a/src/Adapter/APCu.php
+++ b/src/Adapter/APCu.php
@@ -8,22 +8,22 @@
*/
class APCu extends \PalePurple\RateLimit\Adapter
{
- public function set($key, $value, $ttl)
+ public function set(string $key, float $value, int $ttl): bool
{
return apcu_store($key, $value, $ttl);
}
- public function get($key)
+ public function get(string $key): float
{
return apcu_fetch($key);
}
- public function exists($key)
+ public function exists(string $key): bool
{
return apcu_exists($key);
}
- public function del($key)
+ public function del(string $key): bool
{
return apcu_delete($key);
}
diff --git a/src/Adapter/Memcached.php b/src/Adapter/Memcached.php
index 4615db1..410949b 100644
--- a/src/Adapter/Memcached.php
+++ b/src/Adapter/Memcached.php
@@ -4,7 +4,6 @@
class Memcached extends \PalePurple\RateLimit\Adapter
{
-
/**
* @var \Memcached
*/
@@ -15,37 +14,36 @@ public function __construct(\Memcached $memcached)
$this->memcached = $memcached;
}
- public function set($key, $value, $ttl)
+ public function set(string $key, float $value, int $ttl): bool
{
return $this->memcached->set($key, $value, $ttl);
}
- /**
- * @return float
- * @param string $key
- */
- public function get($key)
+ public function get(string $key): float
{
- $val = $this->_get($key);
- return (float) $val;
+ $ret = $this->realGet($key);
+ if (is_float($ret)) {
+ return $ret;
+ }
+ throw new \InvalidArgumentException("Unexpected data type from memcache, expected float, got " . gettype($ret));
}
- /**
- * @return bool|float
- * @param string $key
- */
- private function _get($key)
+ private function realGet(string $key): bool|float
{
- return $this->memcached->get($key);
+ $ret = $this->memcached->get($key);
+ if (is_float($ret) || is_bool($ret)) {
+ return $ret;
+ }
+ throw new \InvalidArgumentException("Unsupported data type from memcache: " . gettype($ret));
}
- public function exists($key)
+ public function exists(string $key): bool
{
- $val = $this->_get($key);
+ $val = $this->realGet($key);
return $val !== false;
}
- public function del($key)
+ public function del(string $key): bool
{
return $this->memcached->delete($key);
}
diff --git a/src/Adapter/Predis.php b/src/Adapter/Predis.php
index cf575ad..dc179db 100644
--- a/src/Adapter/Predis.php
+++ b/src/Adapter/Predis.php
@@ -7,44 +7,30 @@
*/
class Predis extends \PalePurple\RateLimit\Adapter
{
-
- /**
- * @var \Predis\ClientInterface
- */
- protected $redis;
+ protected \Predis\ClientInterface $redis;
public function __construct(\Predis\ClientInterface $client)
{
$this->redis = $client;
}
-
- /**
- * @param string $key
- * @param float $value
- * @param int $ttl
- * @return bool
- */
- public function set($key, $value, $ttl)
+ public function set(string $key, float $value, int $ttl): bool
{
- return $this->redis->set($key, (string) $value, "ex", $ttl);
+ $this->redis->set($key, (string)$value, "ex", $ttl);
+ return true;
}
- /**
- * @return float
- * @param string $key
- */
- public function get($key)
+ public function get(string $key): float
{
return (float)$this->redis->get($key);
}
- public function exists($key)
+ public function exists(string $key): bool
{
return (bool)$this->redis->exists($key);
}
- public function del($key)
+ public function del(string $key): bool
{
return (bool)$this->redis->del([$key]);
}
diff --git a/src/Adapter/Redis.php b/src/Adapter/Redis.php
index 323512b..b3f4e28 100644
--- a/src/Adapter/Redis.php
+++ b/src/Adapter/Redis.php
@@ -8,7 +8,6 @@
*/
class Redis extends \PalePurple\RateLimit\Adapter
{
-
/**
* @var \Redis
*/
@@ -20,24 +19,18 @@ public function __construct(\Redis $redis)
}
/**
- * @param string $key
- * @param float $value
- * @param int $ttl
- * @return bool
* @throws \RedisException
*/
- public function set($key, $value, $ttl)
+ public function set(string $key, float $value, int $ttl): bool
{
$ret = $this->redis->set($key, (string)$value, $ttl);
return $ret == true; /* redis returns true OR \Redis (when in multimode). */
}
/**
- * @return float
- * @param string $key
* @throws \RedisException
*/
- public function get($key)
+ public function get(string $key): float
{
$ret = $this->redis->get($key);
if (is_numeric($ret)) {
@@ -47,22 +40,27 @@ public function get($key)
}
/**
- * @param string $key
- * @return bool
* @throws \RedisException
*/
- public function exists($key)
+ public function exists(string $key): bool
{
return $this->redis->exists($key) == true;
}
/**
- * @param string $key
- * @return bool
* @throws \RedisException
*/
- public function del($key)
+ public function del(string $key): bool
{
- return $this->redis->del($key) > 0;
+ $ret = $this->redis->del($key);
+ if (is_bool($ret)) {
+ return $ret;
+ }
+
+ if (is_int($ret)) {
+ return (bool) $ret;
+ }
+
+ return false;
}
}
diff --git a/src/Adapter/Stash.php b/src/Adapter/Stash.php
index 3d2fef3..fb8282a 100644
--- a/src/Adapter/Stash.php
+++ b/src/Adapter/Stash.php
@@ -11,18 +11,14 @@
*/
class Stash extends Adapter
{
-
- /**
- * @var \Stash\Pool
- */
- private $pool;
+ private \Stash\Pool $pool;
public function __construct(\Stash\Pool $pool)
{
$this->pool = $pool;
}
- public function get($key)
+ public function get(string $key): float
{
$item = $this->pool->getItem($key);
$item->setInvalidationMethod(Invalidation::OLD);
@@ -30,10 +26,10 @@ public function get($key)
if ($item->isHit()) {
return $item->get();
}
- return (float) 0;
+ return (float)0;
}
- public function set($key, $value, $ttl)
+ public function set(string $key, float $value, int $ttl): bool
{
$item = $this->pool->getItem($key);
$item->set($value);
@@ -41,14 +37,14 @@ public function set($key, $value, $ttl)
return $item->save();
}
- public function exists($key)
+ public function exists(string $key): bool
{
$item = $this->pool->getItem($key);
$item->setInvalidationMethod(Invalidation::OLD);
return $item->isHit();
}
- public function del($key)
+ public function del(string $key): bool
{
return $this->pool->deleteItem($key);
}
diff --git a/src/RateLimit.php b/src/RateLimit.php
index 0998ed5..4fa5136 100644
--- a/src/RateLimit.php
+++ b/src/RateLimit.php
@@ -8,38 +8,20 @@
*/
class RateLimit
{
+ protected string $name;
+ protected int $maxRequests;
+ protected int $period;
- /**
- *
- * @var string
- */
- protected $name;
-
- /**
- *
- * @var int
- */
- protected $maxRequests;
-
- /**
- *
- * @var int
- */
- protected $period;
-
- /**
- * @var Adapter
- */
- private $adapter;
+ private Adapter $adapter;
/**
* RateLimit constructor.
- * @param string $name - prefix used in storage keys.
- * @param int $maxRequests
+ * @param string $name - some unique identifying name for the rate limiter
+ * @param int $maxRequests how many requests (tokens) in $period before rate limiting kicks in
* @param int $period seconds
* @param Adapter $adapter - storage adapter
*/
- public function __construct($name, $maxRequests, $period, Adapter $adapter)
+ public function __construct(string $name, int $maxRequests, int $period, Adapter $adapter)
{
$this->name = $name;
$this->maxRequests = $maxRequests;
@@ -50,11 +32,11 @@ public function __construct($name, $maxRequests, $period, Adapter $adapter)
/**
* Rate Limiting
* http://stackoverflow.com/a/668327/670662
- * @param string $id
- * @param float $use
+ * @param string $id - e.g someone's login, ip address or otherwise thing you wish to possibly throttle
+ * @param float $use - each call to check uses this many tokens
* @return boolean - true if you're within your allowance, false if over allowance
*/
- public function check($id, $use = 1.0)
+ public function check(string $id, float $use = 1.0): bool
{
$rate = $this->maxRequests / $this->period;
@@ -93,11 +75,11 @@ public function check($id, $use = 1.0)
}
/**
- * @deprecated use getAllowance() instead.
* @param string $id
* @return int
+ * @deprecated use getAllowance() instead.
*/
- public function getAllow($id)
+ public function getAllow(string $id): int
{
return $this->getAllowance($id);
}
@@ -105,11 +87,9 @@ public function getAllow($id)
/**
* Get allowance left.
- *
- * @param string $id
* @return int number of requests that can be made before hitting a limit.
*/
- public function getAllowance($id)
+ public function getAllowance(string $id): int
{
$this->check($id, 0.0);
@@ -118,70 +98,44 @@ public function getAllowance($id)
if (!$this->adapter->exists($a_key)) {
return $this->maxRequests;
}
- return (int) max(0, floor($this->adapter->get($a_key)));
+ return (int)max(0, floor($this->adapter->get($a_key)));
}
/**
* Purge rate limit record for $id
- * @param string $id
- * @return void
*/
- public function purge($id)
+ public function purge(string $id): void
{
$this->adapter->del($this->keyTime($id));
$this->adapter->del($this->keyAllow($id));
}
- /**
- * @return string
- * @param string $id
- */
- private function keyTime($id)
+ private function keyTime(string $id): string
{
return $this->name . ":" . $id . ":time";
}
- /**
- * @return string
- * @param string $id
- */
- private function keyAllow($id)
+ private function keyAllow(string $id): string
{
return $this->name . ":" . $id . ":allow";
}
- /**
- * @param string $name
- * @return void
- */
- public function setName($name)
+ public function setName(string $name): void
{
$this->name = $name;
}
- /**
- * @param int $maxRequests
- * @return void
- */
- public function setMaxRequests($maxRequests)
+ public function setMaxRequests(int $maxRequests): void
{
$this->maxRequests = $maxRequests;
}
- /**
- * @param int $period
- * @return void
- */
- public function setPeriod($period)
+ public function setPeriod(int $period): void
{
$this->period = $period;
}
- /**
- * @param Adapter $adapter
- * @return void
- */
- public function setAdapter(Adapter $adapter)
+ public function setAdapter(Adapter $adapter): void
{
$this->adapter = $adapter;
}