* @license BSD */ namespace Domframework; /** * The rate limit with file storage */ class Ratelimitfile extends Ratelimit { /** * The storage directory */ public $storageDir = "data/ratelimit/"; /** * Debug the ratelimiting process to screen */ public $debug = false; /** * The function set a rate-limit * @param string $name The rate-limit object to set * @return bool true if the rate-limit is not overloaded * false if the rate-limit is overloaded */ public function set($name) { $this->storageOK(); $nameFile = substr(rawurlencode($name), 0, 128); $file = $this->storageDir . "/$nameFile"; // Add the current timestamp $currentTimeStamp = microtime(true) . "\n"; if ($this->debug) { echo "Add entry : $currentTimeStamp"; } $user = posix_getpwuid(posix_getuid()); if (file_exists($file) && ! is_writeable($file)) { throw new \Exception(sprintf( dgettext( "domframework", "File '%s' not writeable for user '%s'" ), $file, $user["name"] ), 500); } file_put_contents($file, $currentTimeStamp, FILE_APPEND); $lock = new Lockfile(); $lock->storagelock = $this->storageDir . "/lockfile.lock"; $lock->lockRW(); $contents = file($file); // Look if there is deprecated entries in the file foreach ($contents as $key => $content) { $content = rtrim($content); if ($content + $this->unittime < microtime(true)) { if ($this->debug) { echo "Remove deprecated entry : $content\n"; } unset($contents[$key]); } else { if ($this->debug) { echo "Active entry : $content\n"; } } } file_put_contents($file, $contents); $lock->unlockRW(); unset($lock); $this->clean(); if (count($contents) > $this->maxEntries) { if ($this->debug) { echo "Ratelimiting for '$name'\n"; } return false; } return true; } /** * The function delete a rate-limit * @param string $name The rate-limit object to del * @return bool */ public function del($name) { $this->storageOK(); $nameFile = substr(rawurlencode($name), 0, 128); $file = $this->storageDir . "/$nameFile"; if (file_exists($file)) { if ($this->debug) { echo "Removing the rate-limiting for '$name'\n"; } unlink($file); } return true; } /** * The function clean the storage with expired entries * @return bool */ public function clean() { $this->storageOK(); $files = glob($this->storageDir . "/*"); foreach ($files as $file) { if (filemtime($file) + $this->unittime < time()) { if ($this->debug) { echo "Removing the deprecated rate-limiting for '" . rawurldecode(basename($file)) . "'\n"; } unlink($file); } } return true; } /** * Check the storageDir state */ private function storageOK() { if (file_exists($this->storageDir)) { if (! is_dir($this->storageDir)) { throw new \Exception(sprintf( dgettext( "domframework", "storageDir '%s' is not a directory" ), $this->storageDir ), 500); } if (! is_readable($this->storageDir)) { throw new \Exception(sprintf( dgettext( "domframework", "storageDir '%s' is not readable" ), $this->storageDir ), 500); } if (! is_writeable($this->storageDir)) { throw new \Exception(sprintf( dgettext( "domframework", "storageDir '%s' is not writeable" ), $this->storageDir ), 500); } } else { if (@mkdir($this->storageDir, 0777, true) === false) { throw new \Exception(sprintf( dgettext( "domframework", "Can't create '%s' storageDir" ), $this->storageDir ), 500); } } return true; } }