Repository: davedevelopment/stiphle
Branch: master
Commit: 5d1c244f0525
Files: 22
Total size: 38.8 KB
Directory structure:
gitextract_npjvi3hh/
├── .gitignore
├── LICENCE
├── README.md
├── composer.json
├── phpunit.xml.dist
├── src/
│ └── Stiphle/
│ ├── Storage/
│ │ ├── Apc.php
│ │ ├── Apcu.php
│ │ ├── DoctrineCache.php
│ │ ├── LockWaitTimeoutException.php
│ │ ├── Memcached.php
│ │ ├── Process.php
│ │ ├── Redis.php
│ │ ├── StorageInterface.php
│ │ └── ZendStorage.php
│ └── Throttle/
│ ├── LeakyBucket.php
│ ├── ThrottleInterface.php
│ └── TimeWindow.php
└── tests/
└── src/
└── Stiphle/
├── Storage/
│ ├── ApcTest.php
│ ├── ProcessTest.php
│ └── RedisTest.php
└── Throttle/
├── LeakyBucketTest.php
└── TimeWindowTest.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/vendor
/phpunit.xml
/composer.lock
/.idea/
================================================
FILE: LICENCE
================================================
Copyright (C) 2012 Dave Marshall <dave.marshall@atstsolutions.co.uk>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
Stiphle
======
Install via Composer
-------
```
composer require davedevelopment/stiphle
```
What is it?
-----------
Stiphle is a little library to try and provide an easy way of throttling/rate limit requests, for those without fancy hardware etc.
How does it work?
-----------------
You create a throttle, and ask it how long you should wait. For example, given
that $identifier is some means of identifying whatever it is you're throttling,
and you want to throttle it to 5 requests per second:
``` php
<?php
$throttle = new Stiphle\Throttle\LeakyBucket;
$identifier = 'dave';
while(true) {
// the throttle method returns the amount of milliseconds it slept for
echo $throttle->throttle($identifier, 5, 1000);
}
# 0 0 0 0 0 200 200....
```
Use combinations of values to provide bursting etc, though use carefully as it
screws with your mind
``` php
<?php
$throttle = new Stiphle\Throttle\LeakyBucket;
$identifier = 'dave';
for(;;) {
/**
* Allow upto 5 per second, but limit to 20 a minute - I think
**/
echo "a:" . $throttle->throttle($identifier, 5, 1000);
echo " b:" . $throttle->throttle($identifier, 20, 60000);
echo "\n";
}
#a:0 b:0
#a:0 b:0
#a:0 b:0
#a:0 b:0
#a:0 b:0
#a:199 b:0
#a:200 b:0
#a:199 b:0
#a:200 b:0
#a:200 b:0
#a:199 b:0
#a:200 b:0
#a:199 b:0
#a:200 b:0
#a:200 b:0
#a:199 b:0
#a:200 b:0
#a:200 b:0
#a:199 b:0
#a:200 b:0
#a:199 b:0
#a:200 b:2600
#a:0 b:3000
#a:0 b:2999
```
Throttle Strategies
-------------------
There are currently two types of throttles, [Leaky
Bucket](http://en.wikipedia.org/wiki/Leaky_bucket) and a simple fixed time
window.
``` php
/**
* Throttle to 1000 per *rolling* 24 hours, e.g. the counter will not reset at
* midnight
*/
$throttle = new Stiphle\Throttle\LeakyBucket;
$throttle->throttle('api.request', 1000, 86400000);
/**
* Throttle to 1000 per calendar day, counter will reset at midnight
*/
$throttle = new Stiphle\Throttle\TimeWindow;
$throttle->throttle('api.request', 1000, 86400000);
```
__NB:__ The current implementation of the `TimeWindow` throttle will only work on 64-bit architectures!
Storage
-------
Stiphle currently ships with 5 storage engines
* In process
* APC
* Memcached
* Doctrine Cache
* Redis
Stiphle uses the in process storage by default. A different storage engine can
be injected after object creation.
``` php
$throttle = new Stiphle\Throttle\LeakyBucket();
$storage = new \Stiphle\Storage\Memcached(new \Memcached());
$throttle->setStorage($storage);
```
Todo
----
* More Tests!
* Decent *Unit* tests
* More throttling methods
* More storage adapters, the current ones are a little volatile, Mongo,
Cassandra, MemcacheDB etc
Copyright
---------
Copyright (c) 2011 Dave Marshall. See LICENCE for further details
================================================
FILE: composer.json
================================================
{
"name": "davedevelopment/stiphle",
"type": "library",
"description": "Simple rate limiting/throttling for php",
"keywords": ["throttle", "throttling", "rate limiting", "rate limit"],
"homepage": "http://github.com/davedevelopment/stiphle",
"license": "MIT",
"authors": [{
"name": "Dave Marshall",
"email": "dave.marshall@atstsolutions.co.uk",
"homepage": "http://davedevelopment.co.uk"
}],
"require": {
"php": "^5.6.0|^7.0|^8.0"
},
"suggest": {
"doctrine/cache": "~1.0",
"predis/predis": "~1.1",
"zendframework/zend-cache": "^2.8"
},
"autoload": {
"psr-0": {
"Stiphle": "src/"
}
},
"require-dev": {
"phpunit/phpunit": "^6.5|^7.5|^8.4",
"predis/predis": "^1.1",
"doctrine/cache": "^1.0",
"zendframework/zend-cache": "^2.8"
}
}
================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit
backupGlobals = "false"
backupStaticAttributes = "false"
colors = "true"
convertErrorsToExceptions = "true"
convertNoticesToExceptions = "true"
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
syntaxCheck = "false"
bootstrap = "./vendor/autoload.php" >
<testsuites>
<testsuite name="Stiphle">
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
================================================
FILE: src/Stiphle/Storage/Apc.php
================================================
<?php
/**
* @package Stiphle
* @subpackage Stiphle\Throttle\LeakyBucket\Storage
*/
namespace Stiphle\Storage;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Use Apc as the storage, I hope apc_add is atomic and therefore we wont get
* any race conditions with the locking....
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class Apc implements StorageInterface
{
/**
* @var int
*/
protected $lockWaitTimeout = 1000;
/**
* @var int Time to sleep when attempting to get lock in microseconds
*/
protected $sleep = 100;
/**
* @var int
*/
protected $ttl = 10000000;
/**
* Set lock wait timeout
*
* @param int $milliseconds
*/
public function setLockWaitTimeout($milliseconds)
{
$this->lockWaitTimeout = $milliseconds;
return;
}
/**
* Set the sleep time in microseconds
*
* @param int
* @return void
*/
public function setSleep($microseconds)
{
$this->sleep = $microseconds;
return;
}
/**
* Set the ttl for the apc records in seconds
*
* @param int $seconds
* @return void
*/
public function setTtl($microseconds)
{
$this->ttl = $microseconds;
return;
}
/**
* Lock
*
* If we're using storage, we might have multiple requests coming in at
* once, so we lock the storage
*
* @return void
*/
public function lock($key)
{
$key = $key . "::LOCK";
$start = microtime(true);
while(!apc_add($key, true, $this->ttl)) {
$passed = (microtime(true) - $start) * 1000;
if ($passed > $this->lockWaitTimeout) {
throw new LockWaitTimeoutException();
}
usleep($this->sleep);
}
return;
}
/**
* Unlock
*
* @return void
*/
public function unlock($key)
{
$key = $key . "::LOCK";
apc_delete($key);
}
/**
* Get last modified
*
* @param string $key
* @return int
*/
public function get($key)
{
return apc_fetch($key);
}
/**
* set
*
* @param string $key
* @param mixed $value
* @return void
*/
public function set($key, $value)
{
apc_store($key, $value, $this->ttl);
return;
}
}
================================================
FILE: src/Stiphle/Storage/Apcu.php
================================================
<?php
/**
* @package Stiphle
* @subpackage Stiphle\Throttle\LeakyBucket\Storage
*/
namespace Stiphle\Storage;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Apcu implements StorageInterface
{
/**
* @var int
*/
protected $lockWaitTimeout = 1000;
/**
* @var int Time to sleep when attempting to get lock in microseconds
*/
protected $sleep = 100;
/**
* @var int
*/
protected $ttl = 10000000;
/**
* Set lock wait timeout
*
* @param int $milliseconds
*/
public function setLockWaitTimeout($milliseconds)
{
$this->lockWaitTimeout = $milliseconds;
return;
}
/**
* Set the sleep time in microseconds
*
* @param int
* @return void
*/
public function setSleep($microseconds)
{
$this->sleep = $microseconds;
return;
}
/**
* Set the ttl for the apc records in seconds
*
* @param int $seconds
* @return void
*/
public function setTtl($microseconds)
{
$this->ttl = $microseconds;
return;
}
/**
* Lock
*
* If we're using storage, we might have multiple requests coming in at
* once, so we lock the storage
*
* @return void
*/
public function lock($key)
{
$key = $key . "::LOCK";
$start = microtime(true);
while(!apcu_add($key, true, $this->ttl)) {
$passed = (microtime(true) - $start) * 1000;
if ($passed > $this->lockWaitTimeout) {
throw new LockWaitTimeoutException();
}
usleep($this->sleep);
}
return;
}
/**
* Unlock
*
* @return void
*/
public function unlock($key)
{
$key = $key . "::LOCK";
apcu_delete($key);
}
/**
* Get last modified
*
* @param string $key
* @return int
*/
public function get($key)
{
return apcu_fetch($key);
}
/**
* set
*
* @param string $key
* @param mixed $value
* @return void
*/
public function set($key, $value)
{
apcu_store($key, $value, $this->ttl);
return;
}
}
================================================
FILE: src/Stiphle/Storage/DoctrineCache.php
================================================
<?php
namespace Stiphle\Storage;
use Doctrine\Common\Cache\Cache;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class DoctrineCache implements StorageInterface
{
/** @var Cache */
protected $cache;
/** @var int */
protected $lockWaitTimeout;
/** @var int */
protected $lockWaitInterval;
public function __construct(Cache $cache, $lockWaitTimeout = 1000, $lockWaitInterval = 100)
{
$this->cache = $cache;
$this->lockWaitTimeout = $lockWaitTimeout;
$this->lockWaitInterval = $lockWaitInterval;
}
public function setLockWaitTimeout($milliseconds)
{
$this->lockWaitTimeout = $milliseconds;
}
public function setSleep($microseconds)
{
$this->lockWaitInterval = $microseconds;
}
public function lock($key)
{
$key = $key . "::LOCK";
$start = microtime(true);
while ($this->cache->contains($key)) {
$passed = (microtime(true) - $start) * 1000;
if ($passed > $this->lockWaitTimeout) {
throw new LockWaitTimeoutException();
}
usleep($this->lockWaitInterval);
}
$this->cache->save($key, true);
}
public function unlock($key)
{
$key = $key . "::LOCK";
$this->cache->delete($key);
}
public function get($key)
{
return $this->cache->fetch($key);
}
public function set($key, $value)
{
$this->cache->save($key, $value);
}
}
================================================
FILE: src/Stiphle/Storage/LockWaitTimeoutException.php
================================================
<?php
/**
* @package Stiphle
* @subpackage Stiphle\Storage
*/
namespace Stiphle\Storage;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Thrown when a request for a lock timesout
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class LockWaitTimeoutException extends \Exception {}
================================================
FILE: src/Stiphle/Storage/Memcached.php
================================================
<?php
/**
* @package Stiphle
* @subpackage Stiphle\Storage
*/
namespace Stiphle\Storage;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Use memcached via PHP's memcached extension
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class Memcached implements StorageInterface
{
/**
* @var int
*/
protected $lockWaitTimeout = 1000;
/**
* @var int Time to sleep when attempting to get lock in microseconds
*/
protected $sleep = 100;
/**
* @var int
*/
protected $ttl = 3600;
/**
* Memcached instance
*/
protected $memcached;
/**
* Constructor
*
*/
public function __construct(\Memcached $memcached)
{
$this->memcached = $memcached;
}
/**
* Set lock wait timeout
*
* @param int $milliseconds
*/
public function setLockWaitTimeout($milliseconds)
{
$this->lockWaitTimeout = $milliseconds;
return;
}
/**
* Set the sleep time in microseconds
*
* @param int
* @return void
*/
public function setSleep($microseconds)
{
$this->sleep = $microseconds;
return;
}
/**
* Set the ttl for the apc records in seconds
*
* @param int $seconds
* @return void
*/
public function setTtl($microseconds)
{
$this->ttl = $microseconds;
return;
}
/**
* Lock
*
* If we're using storage, we might have multiple requests coming in at
* once, so we lock the storage
*
* @return void
*/
public function lock($key)
{
$key = $key . "::LOCK";
$start = microtime(true);
while(!$this->memcached->add($key, true, $this->ttl)) {
$passed = (microtime(true) - $start) * 1000;
if ($passed > $this->lockWaitTimeout) {
throw new LockWaitTimeoutException();
}
usleep($this->sleep);
}
return;
}
/**
* Unlock
*
* @return void
*/
public function unlock($key)
{
$key = $key . "::LOCK";
$this->memcached->delete($key);
}
/**
* Get last modified
*
* @param string $key
* @return int
*/
public function get($key)
{
return $this->memcached->get($key);
}
/**
* set
*
* @param string $key
* @param mixed $value
* @return void
*/
public function set($key, $value)
{
$this->memcached->set($key, $value, $this->ttl);
return;
}
}
================================================
FILE: src/Stiphle/Storage/Process.php
================================================
<?php
/**
* @package Stiphle
* @subpackage Stiphle\Storage
*/
namespace Stiphle\Storage;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Basic in-process storage of values
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class Process implements StorageInterface
{
/**
* @var int
*/
protected $lockWaitTimeout = 1000;
/**
* @var array
*/
protected $locked = array();
/**
* @var array
*/
protected $values = array();
/**
* Set lock wait timeout
*
* @param int $milliseconds
*/
public function setLockWaitTimeout($milliseconds)
{
$this->lockWaitTimeout = $milliseconds;
}
/**
* Lock
*
* If we're using storage, we might have multiple requests coming in at
* once, so we lock the storage
*
* @return void
*/
public function lock($key)
{
if (!isset($this->locked[$key])) {
$this->locked[$key] = false;
}
$start = microtime(true);
while($this->locked[$key]) {
$passed = (microtime(true) - $start) * 1000;
if ($passed > $this->lockWaitTimeout) {
throw new LockWaitTimeoutException();
}
}
$this->locked[$key] = true;
return;
}
/**
* Unlock
*
* @return void
*/
public function unlock($key)
{
$this->locked[$key] = false;
}
/**
* Get
*
* @param string $key
* @return int
*/
public function get($key)
{
if (isset($this->values[$key])) {
return $this->values[$key];
}
return null;
}
/**
* set
*
* @param string $key
* @param mixed $value
* @return void
*/
public function set($key, $value)
{
$this->values[$key] = $value;
}
}
================================================
FILE: src/Stiphle/Storage/Redis.php
================================================
<?php
namespace Stiphle\Storage;
/**
* Redis storage via Predis package
*
* @author Jacob Christiansen <jacob@colourbox.com>
*/
class Redis implements StorageInterface
{
protected $lockWaitTimeout = 1000;
protected $redisClient;
public function __construct(\Predis\Client $redisClient)
{
$this->redisClient = $redisClient;
}
/**
* {@inheritDoc}
*/
public function setLockWaitTimeout($milliseconds)
{
$this->lockWaitTimeout = $milliseconds;
}
/**
* {@inheritDoc}
*/
public function lock($key)
{
$start = microtime(true);
while (is_null($this->redisClient->set($this->getLockKey($key), 'LOCKED', 'PX', 3600, 'NX'))) {
$passed = (microtime(true) - $start) * 1000;
if ($passed > $this->lockWaitTimeout) {
throw new LockWaitTimeoutException();
}
usleep(100);
}
}
/**
* {@inheritDoc}
*/
public function unlock($key)
{
$this->redisClient->del($this->getLockKey($key));
}
/**
* {@inheritDoc}
*/
public function get($key)
{
return $this->redisClient->get($key);
}
/**
* {@inheritDoc}
*/
public function set($key, $value)
{
$this->redisClient->set($key, $value);
}
private function getLockKey($key)
{
return $key . "::LOCK";
}
}
================================================
FILE: src/Stiphle/Storage/StorageInterface.php
================================================
<?php
/**
* @package Stiphle
* @subpackage Stiphle\Throttle\LeakyBucket\Storage
*/
namespace Stiphle\Storage;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface describing a persistant storage mechanism for the LeakyBucket
* throttle
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
interface StorageInterface
{
/**
* Set lock wait timout
*
* @param int $milliseconds
*/
public function setLockWaitTimeout($milliseconds);
/**
* Lock
*
* We might have multiple requests coming in at once, so we lock the storage
*
* @return void
*/
public function lock($key);
/**
* Unlock
*
* @return void
*/
public function unlock($key);
/**
* Get
*
* @param string $key
* @return int
*/
public function get($key);
/**
* set last modified
*
* @param string $key
* @param mixed $value
* @return void
*/
public function set($key, $value);
}
================================================
FILE: src/Stiphle/Storage/ZendStorage.php
================================================
<?php
use Stiphle\Storage\LockWaitTimeoutException;
use Stiphle\Storage\StorageInterface;
use Zend\Cache\Storage\StorageInterface as ZendStorageInterface;
class ZendStorage implements StorageInterface
{
/** @var ZendStorageInterface $cache */
protected $cache;
/** @var int */
protected $lockWaitTimeout;
/** @var int */
protected $lockWaitInterval;
public function __construct(ZendStorageInterface $cache, $lockWaitTimeout = 1000, $lockWaitInterval = 100)
{
$this->cache = $cache;
$this->lockWaitTimeout = $lockWaitTimeout;
$this->lockWaitInterval = $lockWaitInterval;
}
public function setLockWaitTimeout($lockWaitTimeout)
{
$this->lockWaitTimeout = $lockWaitTimeout;
}
public function lock($key)
{
$key = sprintf('%s::LOCK', $key);
$start = microtime(true);
while ($this->cache->hasItem($key)) {
$passed = (microtime(true) - $start) * 1000;
if ($passed > $this->lockWaitTimeout) {
throw new LockWaitTimeoutException();
}
usleep($this->lockWaitInterval);
}
$this->cache->setItem($key, true);
}
public function unlock($key)
{
$key = sprintf('%s::LOCK', $key);
$this->cache->removeItem($key);
}
public function get($key)
{
return $this->cache->getItem($key);
}
public function set($key, $value)
{
$this->cache->setItem($key, $value);
}
}
================================================
FILE: src/Stiphle/Throttle/LeakyBucket.php
================================================
<?php
/**
* @package Stiphle
* @subpackage Stiphle\Throttle
*/
namespace Stiphle\Throttle;
use Stiphle\Storage\LockWaitTimeoutException;
use Stiphle\Storage\Process;
use Stiphle\Storage\StorageInterface;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A 'leaky bucket' style rate limiter
*
* @see http://stackoverflow.com/questions/1375501/how-do-i-throttle-my-sites-api-users
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class LeakyBucket implements ThrottleInterface
{
/**
* @var StorageInterface
*/
protected $storage;
/**
*
*/
public function __construct()
{
$this->storage = new Process();
}
/**
* Throttle
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return int
* @throws LockWaitTimeoutException
*/
public function throttle($key, $limit, $milliseconds)
{
/**
* Try and do our waiting without a lock
*/
$key = $this->getStorageKey($key, $limit, $milliseconds);
$wait = 0;
$newRatio = $this->getNewRatio($key, $limit, $milliseconds);
if ($newRatio > $milliseconds) {
$wait = ceil($newRatio - $milliseconds);
}
usleep($wait * 1000);
/**
* Lock, record and release
*/
$this->storage->lock($key);
$newRatio = $this->getNewRatio($key, $limit, $milliseconds);
$this->setLastRatio($key, $newRatio);
$this->setLastRequest($key, microtime(1));
$this->storage->unlock($key);
return $wait;
}
/**
* Get Estimate (doesn't require lock)
*
* How long would I have to wait to make a request?
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return int - the number of milliseconds before this request should be allowed
* to pass
*/
public function getEstimate($key, $limit, $milliseconds)
{
$key = $this->getStorageKey($key, $limit, $milliseconds);
$newRatio = $this->getNewRatio($key, $limit, $milliseconds);
$wait = 0;
if ($newRatio > $milliseconds) {
$wait = ceil($newRatio - $milliseconds);
}
return $wait;
}
/**
* Get new ratio
*
* Assuming we're making a request, get the ratio of requests made to
* requests allowed
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return float
*/
protected function getNewRatio($key, $limit, $milliseconds)
{
$lastRequest = $this->getLastRequest($key) ?: 0;
$lastRatio = $this->getLastRatio($key) ?: 0;
$diff = (microtime(1) - $lastRequest) * 1000;
$newRatio = $lastRatio - $diff;
$newRatio = $newRatio < 0 ? 0 : $newRatio;
$newRatio+= $milliseconds/$limit;
return $newRatio;
}
/**
* Get storage key
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return string
*/
protected function getStorageKey($key, $limit, $milliseconds)
{
return $key . '::' . $limit . '::' . $milliseconds;
}
/**
* Set Storage
*
* @param StorageInterface $storage
* @return LeakyBucket
*/
public function setStorage(StorageInterface $storage)
{
$this->storage = $storage;
return $this;
}
/**
* Get Last Ratio
*
* @param string $key
* @return float
*/
protected function getLastRatio($key)
{
return $this->storage->get($key . '::LASTRATIO');
}
/**
* Set Last Ratio
*
* @param string $key
* @param float $ratio
* @return void
*/
protected function setLastRatio($key, $ratio)
{
$this->storage->set($key . '::LASTRATIO', $ratio);
}
/**
* Get Last Request
*
* @param string $key
* @return float
*/
protected function getLastRequest($key)
{
return $this->storage->get($key . '::LASTREQUEST');
}
/**
* Set Last Request
*
* @param string $key
* @param float $request
* @return void
*/
protected function setLastRequest($key, $request)
{
$this->storage->set($key . '::LASTREQUEST', $request);
}
}
================================================
FILE: src/Stiphle/Throttle/ThrottleInterface.php
================================================
<?php
/**
* @package Stiphle
* @subpackage
*/
namespace Stiphle\Throttle;
use Stiphle\Storage\LockWaitTimeoutException;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface describing a throttle
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
interface ThrottleInterface
{
/**
* Throttle
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return int
* @throws LockWaitTimeoutException
*/
public function throttle($key, $limit, $milliseconds);
/**
* Get Estimate
*
* If I were to throttle now, how long would I be waiting
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return int - the number of milliseconds before this request should be allowed
*/
public function getEstimate($key, $limit, $milliseconds);
}
================================================
FILE: src/Stiphle/Throttle/TimeWindow.php
================================================
<?php
namespace Stiphle\Throttle;
use Stiphle\Storage\LockWaitTimeoutException;
use Stiphle\Storage\StorageInterface;
use Stiphle\Storage\Process;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A throttle based on a fixed time window
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class TimeWindow implements ThrottleInterface
{
/**
* @var StorageInterface
*/
protected $storage;
/**
*
*/
public function __construct()
{
$this->storage = new Process();
}
/**
* Throttle
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return int
* @throws LockWaitTimeoutException
*/
public function throttle($key, $limit, $milliseconds)
{
/**
* Try do our waiting without a lock, so may sneak through because of
* this...
*/
$wait = $this->getEstimate($key, $limit, $milliseconds);
if ($wait > 0) {
usleep($wait * 1000);
}
$key = $this->getStorageKey($key, $limit, $milliseconds);
$this->storage->lock($key);
$count = $this->storage->get($key);
$count++;
$this->storage->set($key, $count);
$this->storage->unlock($key);
return $wait;
}
/**
* Get Estimate (doesn't require lock)
*
* How long would I have to wait to make a request?
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return int - the number of milliseconds before this request should be allowed
* to pass
*/
public function getEstimate($key, $limit, $milliseconds)
{
$key = $this->getStorageKey($key, $limit, $milliseconds);
$count = $this->storage->get($key);
if ($count < $limit) {
return 0;
}
return $milliseconds - ((microtime(1) * 1000) % (float) $milliseconds);
}
/**
* Get storage key
*
* @param string $key - A unique key for what we're throttling
* @param int $limit - How many are allowed
* @param int $milliseconds - In this many milliseconds
* @return string
*/
protected function getStorageKey($key, $limit, $milliseconds)
{
$window = $milliseconds * (floor((microtime(1) * 1000)/$milliseconds));
$date = date('YmdHis', $window/1000);
return $date . '::' . $key . '::' . $limit . '::' . $milliseconds . '::COUNT';
}
/**
* Set Storage
*
* @param StorageInterface $storage
* @return TimeWindow
*/
public function setStorage(StorageInterface $storage)
{
$this->storage = $storage;
return $this;
}
}
================================================
FILE: tests/src/Stiphle/Storage/ApcTest.php
================================================
<?php
/**
* @package
* @subpackage
*/
namespace Stiphle\Storage;
use \PHPUnit_Framework_TestCase;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* TITLE
*
* DESCRIPTION
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class ApcTest extends PHPUnit_Framework_TestCase
{
protected $storage = null;
public function setup()
{
$this->storage = new Apc();
}
public function tearDown()
{
apc_delete('dave::LOCK');
}
/**
* @expectedException Stiphle\Storage\LockWaitTimeoutException
*/
public function testLockThrowsLockWaitTimeoutException()
{
if (!ini_get('apc.enable_cli') && !ini_get('apcu.enable_cli')) {
$this->markTestSkipped('APC and APCu needs enabling for the cli via apc.enable_cli=1 or apcu.enable_cli=1');
}
$this->storage->lock('dave');
$this->storage->lock('dave');
}
public function testLockRespectsLockWaitTimeoutValue()
{
if (!ini_get('apc.enable_cli') && !ini_get('apcu.enable_cli')) {
$this->markTestSkipped('APC and APCu needs enabling for the cli via apc.enable_cli=1 or apcu.enable_cli=1');
}
/**
* Test we can do this
*/
$this->storage->lock('dave');
try {
$start = microtime(1);
$this->storage->lock('dave');
} catch (LockWaitTimeoutException $e) {
$caught = microtime(1);
$diff = $caught - $start;
if (round($diff) != 1) {
$this->markTestSkipped("Don't think the timings will be accurate enough, expected exception after 1 second, was $diff");
}
}
$this->storage->setLockWaitTimeout(2000);
try {
$start = microtime(1);
$this->storage->lock('dave');
$this->fail("should not get to this point");
} catch (LockWaitTimeoutException $e) {
$caught = microtime(1);
$diff = $caught - $start;
$this->assertEquals(2, round($diff), "Exception thrown after approximately 2000 milliseconds");
}
}
}
================================================
FILE: tests/src/Stiphle/Storage/ProcessTest.php
================================================
<?php
/**
* @package
* @subpackage
*/
namespace Stiphle\Storage;
use \PHPUnit_Framework_TestCase;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* TITLE
*
* DESCRIPTION
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class ProcessTest extends PHPUnit_Framework_TestCase
{
protected $storage = null;
public function setup()
{
$this->storage = new Process();
}
/**
* @expectedException Stiphle\Storage\LockWaitTimeoutException
*/
public function testLockThrowsLockWaitTimeoutException()
{
$this->storage->lock('dave');
$this->storage->lock('dave');
}
public function testLockRespectsLockWaitTimeoutValue()
{
/**
* Test we can do this
*/
$this->storage->lock('dave');
try {
$start = microtime(1);
$this->storage->lock('dave');
} catch (LockWaitTimeoutException $e) {
$caught = microtime(1);
$diff = $caught - $start;
if (round($diff) != 1) {
$this->markTestSkipped("Don't think the timings will be accurate enough, expected exception after 1 second, was $diff");
}
}
$this->storage->setLockWaitTimeout(2000);
try {
$start = microtime(1);
$this->storage->lock('dave');
$this->fail("should not get to this point");
} catch (LockWaitTimeoutException $e) {
$caught = microtime(1);
$diff = $caught - $start;
$this->assertEquals(2, round($diff), "Exception thrown after approximately 2000 milliseconds");
}
}
}
================================================
FILE: tests/src/Stiphle/Storage/RedisTest.php
================================================
<?php
/* vim: set ts=4 sw=4 tw=0 et :*/
namespace Stiphle\Storage;
use \PHPUnit_Framework_TestCase;
class RedisTest extends PHPUnit_Framework_TestCase
{
public function testLockThrowsLockWaitTimeoutException()
{
$redisClient = $this->getMockBuilder(\Predis\Client::class)
->setMethods(['set'])
->getMock();
$redisClient->expects($this->at(0))
->method('set')
->with('dave::LOCK', 'LOCKED', 'PX', 3600, 'NX')
->will($this->returnValue(1));
$redisClient->expects($this->any())
->method('set')
->with('dave::LOCK', 'LOCKED', 'PX', 3600, 'NX')
->will($this->returnValue(null));
$this->expectException(\Stiphle\Storage\LockWaitTimeoutException::class);
$storage = new Redis($redisClient);
$storage->lock('dave');
$storage->lock('dave');
}
public function testStorageCanBeUnlocked()
{
$redisClient = $this->getMockBuilder(\Predis\Client::class)
->setMethods(['del'])
->getMock();
$redisClient->expects($this->once())
->method('del')
->with('dave::LOCK');
$storage = new Redis($redisClient);
$storage->unlock('dave');
}
}
================================================
FILE: tests/src/Stiphle/Throttle/LeakyBucketTest.php
================================================
<?php
/**
* @package
* @subpackage
*/
namespace Stiphle\Throttle;
use \PHPUnit_Framework_TestCase;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* TITLE
*
* DESCRIPTION
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class LeakyBucketTest extends PHPUnit_Framework_TestCase
{
/** @var LeakyBucket */
protected $throttle;
public function setup()
{
$this->throttle = new LeakyBucket();
}
/**
* This test assumes your machine is capable of processing the first five
* calls in less that a second :)
*
* Nothing special here, ideally we need to mock the storage out and test it
* with different values etc
*/
public function testGetEstimate()
{
$this->assertEquals(0, $this->throttle->throttle('dave', 5, 1000));
$this->assertEquals(0, $this->throttle->throttle('dave', 5, 1000));
$this->assertEquals(0, $this->throttle->throttle('dave', 5, 1000));
$this->assertEquals(0, $this->throttle->throttle('dave', 5, 1000));
$this->assertEquals(0, $this->throttle->throttle('dave', 5, 1000));
$this->assertGreaterThan(0, $this->throttle->getEstimate('dave', 5, 1000));
$this->assertGreaterThan(0, $this->throttle->throttle('dave', 5, 1000));
}
}
================================================
FILE: tests/src/Stiphle/Throttle/TimeWindowTest.php
================================================
<?php
namespace Stiphle\Throttle;
use \PHPUnit_Framework_TestCase;
/**
* This file is part of Stiphle
*
* Copyright (c) 2011 Dave Marshall <dave.marshall@atstsolutuions.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* TITLE
*
* DESCRIPTION
*
* @author Dave Marshall <david.marshall@atstsolutions.co.uk>
*/
class TimeWindowTest extends PHPUnit_Framework_TestCase
{
/** @var TimeWindow */
protected $throttle;
public function setup()
{
$this->throttle = new TimeWindow();
}
/**
* Really crap test here, without mocking the system time, it's difficult to
* know when you're going to throttled...
*/
public function testGetEstimate()
{
$timeout = strtotime('+5 seconds', microtime(1));
$count = 0;
while (microtime(1) < $timeout) {
$wait = $this->throttle->throttle('dave', 5, 1000);
if (microtime(1) < $timeout) {
$count++;
}
}
$this->assertEquals(25, $count);
}
}
gitextract_npjvi3hh/
├── .gitignore
├── LICENCE
├── README.md
├── composer.json
├── phpunit.xml.dist
├── src/
│ └── Stiphle/
│ ├── Storage/
│ │ ├── Apc.php
│ │ ├── Apcu.php
│ │ ├── DoctrineCache.php
│ │ ├── LockWaitTimeoutException.php
│ │ ├── Memcached.php
│ │ ├── Process.php
│ │ ├── Redis.php
│ │ ├── StorageInterface.php
│ │ └── ZendStorage.php
│ └── Throttle/
│ ├── LeakyBucket.php
│ ├── ThrottleInterface.php
│ └── TimeWindow.php
└── tests/
└── src/
└── Stiphle/
├── Storage/
│ ├── ApcTest.php
│ ├── ProcessTest.php
│ └── RedisTest.php
└── Throttle/
├── LeakyBucketTest.php
└── TimeWindowTest.php
SYMBOL INDEX (99 symbols across 17 files)
FILE: src/Stiphle/Storage/Apc.php
class Apc (line 23) | class Apc implements StorageInterface
method setLockWaitTimeout (line 45) | public function setLockWaitTimeout($milliseconds)
method setSleep (line 57) | public function setSleep($microseconds)
method setTtl (line 69) | public function setTtl($microseconds)
method lock (line 83) | public function lock($key)
method unlock (line 103) | public function unlock($key)
method get (line 115) | public function get($key)
method set (line 127) | public function set($key, $value)
FILE: src/Stiphle/Storage/Apcu.php
class Apcu (line 17) | class Apcu implements StorageInterface
method setLockWaitTimeout (line 39) | public function setLockWaitTimeout($milliseconds)
method setSleep (line 51) | public function setSleep($microseconds)
method setTtl (line 63) | public function setTtl($microseconds)
method lock (line 77) | public function lock($key)
method unlock (line 97) | public function unlock($key)
method get (line 109) | public function get($key)
method set (line 121) | public function set($key, $value)
FILE: src/Stiphle/Storage/DoctrineCache.php
class DoctrineCache (line 16) | class DoctrineCache implements StorageInterface
method __construct (line 27) | public function __construct(Cache $cache, $lockWaitTimeout = 1000, $lo...
method setLockWaitTimeout (line 34) | public function setLockWaitTimeout($milliseconds)
method setSleep (line 39) | public function setSleep($microseconds)
method lock (line 44) | public function lock($key)
method unlock (line 58) | public function unlock($key)
method get (line 64) | public function get($key)
method set (line 69) | public function set($key, $value)
FILE: src/Stiphle/Storage/LockWaitTimeoutException.php
class LockWaitTimeoutException (line 22) | class LockWaitTimeoutException extends \Exception {}
FILE: src/Stiphle/Storage/Memcached.php
class Memcached (line 22) | class Memcached implements StorageInterface
method __construct (line 48) | public function __construct(\Memcached $memcached)
method setLockWaitTimeout (line 58) | public function setLockWaitTimeout($milliseconds)
method setSleep (line 70) | public function setSleep($microseconds)
method setTtl (line 82) | public function setTtl($microseconds)
method lock (line 96) | public function lock($key)
method unlock (line 117) | public function unlock($key)
method get (line 129) | public function get($key)
method set (line 141) | public function set($key, $value)
FILE: src/Stiphle/Storage/Process.php
class Process (line 22) | class Process implements StorageInterface
method setLockWaitTimeout (line 44) | public function setLockWaitTimeout($milliseconds)
method lock (line 57) | public function lock($key)
method unlock (line 81) | public function unlock($key)
method get (line 92) | public function get($key)
method set (line 108) | public function set($key, $value)
FILE: src/Stiphle/Storage/Redis.php
class Redis (line 9) | class Redis implements StorageInterface
method __construct (line 14) | public function __construct(\Predis\Client $redisClient)
method setLockWaitTimeout (line 22) | public function setLockWaitTimeout($milliseconds)
method lock (line 30) | public function lock($key)
method unlock (line 46) | public function unlock($key)
method get (line 54) | public function get($key)
method set (line 62) | public function set($key, $value)
method getLockKey (line 67) | private function getLockKey($key)
FILE: src/Stiphle/Storage/StorageInterface.php
type StorageInterface (line 23) | interface StorageInterface
method setLockWaitTimeout (line 30) | public function setLockWaitTimeout($milliseconds);
method lock (line 39) | public function lock($key);
method unlock (line 46) | public function unlock($key);
method get (line 54) | public function get($key);
method set (line 63) | public function set($key, $value);
FILE: src/Stiphle/Storage/ZendStorage.php
class ZendStorage (line 7) | class ZendStorage implements StorageInterface
method __construct (line 18) | public function __construct(ZendStorageInterface $cache, $lockWaitTime...
method setLockWaitTimeout (line 25) | public function setLockWaitTimeout($lockWaitTimeout)
method lock (line 30) | public function lock($key)
method unlock (line 47) | public function unlock($key)
method get (line 53) | public function get($key)
method set (line 58) | public function set($key, $value)
FILE: src/Stiphle/Throttle/LeakyBucket.php
class LeakyBucket (line 27) | class LeakyBucket implements ThrottleInterface
method __construct (line 37) | public function __construct()
method throttle (line 51) | public function throttle($key, $limit, $milliseconds)
method getEstimate (line 87) | public function getEstimate($key, $limit, $milliseconds)
method getNewRatio (line 109) | protected function getNewRatio($key, $limit, $milliseconds)
method getStorageKey (line 131) | protected function getStorageKey($key, $limit, $milliseconds)
method setStorage (line 142) | public function setStorage(StorageInterface $storage)
method getLastRatio (line 154) | protected function getLastRatio($key)
method setLastRatio (line 166) | protected function setLastRatio($key, $ratio)
method getLastRequest (line 177) | protected function getLastRequest($key)
method setLastRequest (line 189) | protected function setLastRequest($key, $request)
FILE: src/Stiphle/Throttle/ThrottleInterface.php
type ThrottleInterface (line 25) | interface ThrottleInterface
method throttle (line 37) | public function throttle($key, $limit, $milliseconds);
method getEstimate (line 49) | public function getEstimate($key, $limit, $milliseconds);
FILE: src/Stiphle/Throttle/TimeWindow.php
class TimeWindow (line 23) | class TimeWindow implements ThrottleInterface
method __construct (line 33) | public function __construct()
method throttle (line 47) | public function throttle($key, $limit, $milliseconds)
method getEstimate (line 78) | public function getEstimate($key, $limit, $milliseconds)
method getStorageKey (line 97) | protected function getStorageKey($key, $limit, $milliseconds)
method setStorage (line 110) | public function setStorage(StorageInterface $storage)
FILE: tests/src/Stiphle/Storage/ApcTest.php
class ApcTest (line 26) | class ApcTest extends PHPUnit_Framework_TestCase
method setup (line 30) | public function setup()
method tearDown (line 35) | public function tearDown()
method testLockThrowsLockWaitTimeoutException (line 43) | public function testLockThrowsLockWaitTimeoutException()
method testLockRespectsLockWaitTimeoutValue (line 54) | public function testLockRespectsLockWaitTimeoutValue()
FILE: tests/src/Stiphle/Storage/ProcessTest.php
class ProcessTest (line 26) | class ProcessTest extends PHPUnit_Framework_TestCase
method setup (line 30) | public function setup()
method testLockThrowsLockWaitTimeoutException (line 38) | public function testLockThrowsLockWaitTimeoutException()
method testLockRespectsLockWaitTimeoutValue (line 45) | public function testLockRespectsLockWaitTimeoutValue()
FILE: tests/src/Stiphle/Storage/RedisTest.php
class RedisTest (line 8) | class RedisTest extends PHPUnit_Framework_TestCase
method testLockThrowsLockWaitTimeoutException (line 10) | public function testLockThrowsLockWaitTimeoutException()
method testStorageCanBeUnlocked (line 34) | public function testStorageCanBeUnlocked()
FILE: tests/src/Stiphle/Throttle/LeakyBucketTest.php
class LeakyBucketTest (line 26) | class LeakyBucketTest extends PHPUnit_Framework_TestCase
method setup (line 31) | public function setup()
method testGetEstimate (line 43) | public function testGetEstimate()
FILE: tests/src/Stiphle/Throttle/TimeWindowTest.php
class TimeWindowTest (line 23) | class TimeWindowTest extends PHPUnit_Framework_TestCase
method setup (line 28) | public function setup()
method testGetEstimate (line 37) | public function testGetEstimate()
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (43K chars).
[
{
"path": ".gitignore",
"chars": 44,
"preview": "/vendor\n/phpunit.xml\n/composer.lock\n/.idea/\n"
},
{
"path": "LICENCE",
"chars": 1093,
"preview": "Copyright (C) 2012 Dave Marshall <dave.marshall@atstsolutions.co.uk>\n\nPermission is hereby granted, free of charge, to a"
},
{
"path": "README.md",
"chars": 2765,
"preview": "Stiphle\n======\n\nInstall via Composer\n-------\n\n```\ncomposer require davedevelopment/stiphle\n```\n\nWhat is it?\n-----------\n"
},
{
"path": "composer.json",
"chars": 912,
"preview": "{\n \"name\": \"davedevelopment/stiphle\",\n \"type\": \"library\",\n \"description\": \"Simple rate limiting/throttling for "
},
{
"path": "phpunit.xml.dist",
"chars": 769,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html -->\n<p"
},
{
"path": "src/Stiphle/Storage/Apc.php",
"chars": 2645,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage Stiphle\\Throttle\\LeakyBucket\\Storage\n */\nnamespace Stiphle\\Storage;\n\n/**"
},
{
"path": "src/Stiphle/Storage/Apcu.php",
"chars": 2446,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage Stiphle\\Throttle\\LeakyBucket\\Storage\n */\nnamespace Stiphle\\Storage;\n\n/**"
},
{
"path": "src/Stiphle/Storage/DoctrineCache.php",
"chars": 1705,
"preview": "<?php\n\nnamespace Stiphle\\Storage;\n\nuse Doctrine\\Common\\Cache\\Cache;\n\n/**\n * This file is part of Stiphle\n *\n * Copyright"
},
{
"path": "src/Stiphle/Storage/LockWaitTimeoutException.php",
"chars": 519,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage Stiphle\\Storage\n */\nnamespace Stiphle\\Storage;\n\n/**\n * This file is part"
},
{
"path": "src/Stiphle/Storage/Memcached.php",
"chars": 2830,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage Stiphle\\Storage\n */\nnamespace Stiphle\\Storage;\n\n/**\n * This file is part"
},
{
"path": "src/Stiphle/Storage/Process.php",
"chars": 2114,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage Stiphle\\Storage\n */\nnamespace Stiphle\\Storage;\n\n/**\n * This file is part"
},
{
"path": "src/Stiphle/Storage/Redis.php",
"chars": 1430,
"preview": "<?php\nnamespace Stiphle\\Storage;\n\n/**\n * Redis storage via Predis package\n *\n * @author Jacob Christiansen <jacob@colour"
},
{
"path": "src/Stiphle/Storage/StorageInterface.php",
"chars": 1243,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage Stiphle\\Throttle\\LeakyBucket\\Storage\n */\nnamespace Stiphle\\Storage;\n\n/**"
},
{
"path": "src/Stiphle/Storage/ZendStorage.php",
"chars": 1515,
"preview": "<?php\n\nuse Stiphle\\Storage\\LockWaitTimeoutException;\nuse Stiphle\\Storage\\StorageInterface;\nuse Zend\\Cache\\Storage\\Storag"
},
{
"path": "src/Stiphle/Throttle/LeakyBucket.php",
"chars": 4983,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage Stiphle\\Throttle\n */\nnamespace Stiphle\\Throttle;\n\nuse Stiphle\\Storage\\Lo"
},
{
"path": "src/Stiphle/Throttle/ThrottleInterface.php",
"chars": 1300,
"preview": "<?php\n/**\n * @package Stiphle\n * @subpackage \n */\n\nnamespace Stiphle\\Throttle;\n\nuse Stiphle\\Storage\\LockWaitTimeoutEx"
},
{
"path": "src/Stiphle/Throttle/TimeWindow.php",
"chars": 3131,
"preview": "<?php\n\nnamespace Stiphle\\Throttle;\n\nuse Stiphle\\Storage\\LockWaitTimeoutException;\nuse Stiphle\\Storage\\StorageInterface;\n"
},
{
"path": "tests/src/Stiphle/Storage/ApcTest.php",
"chars": 2375,
"preview": "<?php\n/**\n * @package\n * @subpackage\n */\nnamespace Stiphle\\Storage;\n\nuse \\PHPUnit_Framework_TestCase;\n\n/**\n * This file "
},
{
"path": "tests/src/Stiphle/Storage/ProcessTest.php",
"chars": 1895,
"preview": "<?php\n/**\n * @package\n * @subpackage\n */\nnamespace Stiphle\\Storage;\n\nuse \\PHPUnit_Framework_TestCase;\n\n/**\n * This file "
},
{
"path": "tests/src/Stiphle/Storage/RedisTest.php",
"chars": 1347,
"preview": "<?php\n/* vim: set ts=4 sw=4 tw=0 et :*/\n\nnamespace Stiphle\\Storage;\n\nuse \\PHPUnit_Framework_TestCase;\n\nclass RedisTest e"
},
{
"path": "tests/src/Stiphle/Throttle/LeakyBucketTest.php",
"chars": 1507,
"preview": "<?php\n/**\n * @package\n * @subpackage\n */\nnamespace Stiphle\\Throttle;\n\nuse \\PHPUnit_Framework_TestCase;\n\n/**\n * This file"
},
{
"path": "tests/src/Stiphle/Throttle/TimeWindowTest.php",
"chars": 1134,
"preview": "<?php\n\nnamespace Stiphle\\Throttle;\n\nuse \\PHPUnit_Framework_TestCase;\n\n/**\n * This file is part of Stiphle\n *\n * Copyrigh"
}
]
About this extraction
This page contains the full source code of the davedevelopment/stiphle GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (38.8 KB), approximately 11.0k tokens, and a symbol index with 99 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.