/
home
/
faureele
/
idf
/
wp-content
/
plugins
/
broken-link-checker
/
includes
/
Upload File
HOME
<?php /** * This class implements a variant of the popular token bucket algorithm. */ class blcTokenBucketList { const MICROSECONDS_PER_SECOND = 1000000; /** @var float How many tokens each bucket can hold. */ private $capacity; /** @var float How long it takes to completely fill a bucket (in seconds). */ private $fillTime; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase /** @var float Minimum interval between taking tokens from a bucket (in seconds). */ private $minTakeInterval; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase /** @var int How many buckets we can manage, in total. */ private $maxBuckets = 200; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase private $buckets = array(); public function __construct( $capacity, $fillTime, $minInterval = 0 ) { $this->capacity = $capacity; $this->fillTime = $fillTime; $this->minTakeInterval = $minInterval; } /** * Take one token from a bucket. * This method will block until a token becomes available. * * @param string $bucketName */ //phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid public function takeToken( $bucketName ) { $this->createIfNotExists( $bucketName ); $this->waitForToken( $bucketName ); $this->buckets[ $bucketName ]['tokens']--; $this->buckets[ $bucketName ]['lastTokenTakenAt'] = microtime( true ); } /** * Wait until at a token is available. * * @param string $name Bucket name. */ //phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid private function waitForToken( $name ) { $now = microtime( true ); $timeSinceLastToken = $now - $this->buckets[ $name ]['lastTokenTakenAt']; $intervalWait = max( $this->minTakeInterval - $timeSinceLastToken, 0 ); $requiredTokens = max( 1 - $this->buckets[ $name ]['tokens'], 0 ); $refillWait = $requiredTokens / $this->getFillRate(); $totalWait = max( $intervalWait, $refillWait ); if ( $totalWait > 0 ) { usleep( $totalWait * self::MICROSECONDS_PER_SECOND ); } $this->refillBucket( $name ); return; } /** * Create a bucket if it doesn't exist yet. * * @param $name */ //phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid private function createIfNotExists( $name ) { if ( ! isset( $this->buckets[ $name ] ) ) { $this->buckets[ $name ] = array( 'tokens' => $this->capacity, 'lastRefill' => microtime( true ), 'lastTokenTakenAt' => 0, ); } //Make sure we don't exceed $maxBuckets. $this->cleanup(); } /** * Calculate how quickly each bucket should be refilled. * * @return float Fill rate in tokens per second. */ //phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid private function getFillRate() { return $this->capacity / $this->fillTime; } /** * Refill a bucket with fresh tokens. * * @param $name */ //phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid private function refillBucket( $name ) { $now = microtime( true ); $timeSinceRefill = $now - $this->buckets[ $name ]['lastRefill']; $this->buckets[ $name ]['tokens'] += $timeSinceRefill * $this->getFillRate(); if ( $this->buckets[ $name ]['tokens'] > $this->capacity ) { $this->buckets[ $name ]['tokens'] = $this->capacity; } $this->buckets[ $name ]['lastRefill'] = $now; } /** * Keep the number of active buckets within the $this->maxBuckets limit. */ private function cleanup() { if ( $this->maxBuckets > 0 ) { //Very simplistic implementation - just discard the oldest buckets. while ( count( $this->buckets ) > $this->maxBuckets ) { array_shift( $this->buckets ); } } } }