-
-
Save joeyboli/559a9e3de23200b7b4e227beefc564d7 to your computer and use it in GitHub Desktop.
Revisions
-
freekrai revised this gist
Oct 26, 2016 . 2 changed files with 19 additions and 9 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,18 +6,15 @@ // in this sample, we are using the originating IP, but you can modify to use API keys, or tokens or what-have-you. $rateLimiter = new RateLimiter($_SERVER["REMOTE_ADDR"]); $limit = 100; // number of connections to limit user to per $minutes $minutes = 1; // number of $minutes to check for. $seconds = floor($minutes * 60); // retry after $minutes in seconds. try { $rateLimiter->limitRequestsInMinutes($limit, $minutes); } catch (RateExceededException $e) { header("HTTP/1.1 429 Too Many Requests"); header(sprintf("Retry-After: %d", $seconds)); $data = 'Rate Limit Exceeded '; die (json_encode($data)); } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,10 +1,23 @@ <?php /* This is a really simple plug and play rate limiter class meant to be used with APIs. Using sessions means we can throw this into any PHP API quickly. $token can be anything to uniquely identify a user, either an IP address, an API key, a JWT token, anything that is unique to a single user. $prefix can be whatever you want, we default it to "rate" On init, we create a md5 hash of our $prefix and our $token, this becomes the prefix throughout the class. We then append a timestamp to this prefix */ class RateExceededException extends Exception {} class RateLimiter { private $prefix; public function __construct($token, $prefix = "rate") { $this->prefix = md5($prefix . $token); if( !isset($_SESSION["cache"]) ){ $_SESSION["cache"] = array(); -
freekrai created this gist
Oct 26, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,28 @@ <?php date_default_timezone_set('America/Los_Angeles'); session_start(); include("ratelimiter.php"); // in this sample, we are using the originating IP, but you can modify to use API keys, or tokens or what-have-you. $rateLimiter = new RateLimiter($_SERVER["REMOTE_ADDR"]); // how many connections to allow per session within the number of $minutes specified. $limit = 100; // how many minutes to limit the $limit connections to // For example if we set it to 100 connections over 2 minutes, then at 101 connections we tell them too many. $minutes = 2; try { $rateLimiter->limitRequestsInMinutes($limit, $minutes); } catch (RateExceededException $e) { header("HTTP/1.1 429 Too Many Requests"); header(sprintf("Retry-After: %d", (60 * $minutes))); $data = 'Rate Limit Exceeded '; die (json_encode($data)); } // ok, they were within their limit, so let's continue with our app.... $data = "Data Returned from API "; header('Content-Type: application/json'); die(json_encode($data)); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,71 @@ <?php class RateExceededException extends Exception {} class RateLimiter { private $prefix; public function __construct($ip, $prefix = "rate") { $this->prefix = md5($prefix . $ip); if( !isset($_SESSION["cache"]) ){ $_SESSION["cache"] = array(); } if( !isset($_SESSION["expiries"]) ){ $_SESSION["expiries"] = array(); }else{ $this->expireSessionKeys(); } } public function limitRequestsInMinutes($allowedRequests, $minutes) { $this->expireSessionKeys(); $requests = 0; foreach ($this->getKeys($minutes) as $key) { $requestsInCurrentMinute = $this->getSessionKey($key); if (false !== $requestsInCurrentMinute) $requests += $requestsInCurrentMinute; } if (false === $requestsInCurrentMinute) { $this->setSessionKey( $key, 1, ($minutes * 60 + 1) ); } else { $this->increment($key, 1); } if ($requests > $allowedRequests) throw new RateExceededException; } private function getKeys($minutes) { $keys = array(); $now = time(); for ($time = $now - $minutes * 60; $time <= $now; $time += 60) { $keys[] = $this->prefix . date("dHi", $time); } return $keys; } private function increment( $key, $inc){ $cnt = 0; if( isset($_SESSION['cache'][$key]) ){ $cnt = $_SESSION['cache'][$key]; } $_SESSION['cache'][$key] = $cnt + $inc; } private function setSessionKey( $key, $val, $expiry ){ $_SESSION["expiries"][$key] = time() + $expiry; $_SESSION['cache'][$key] = $val; } private function getSessionKey( $key ){ return isset($_SESSION['cache'][$key]) ? $_SESSION['cache'][$key] : false; } private function expireSessionKeys() { foreach ($_SESSION["expiries"] as $key => $value) { if (time() > $value) { unset($_SESSION['cache'][$key]); unset($_SESSION["expiries"][$key]); } } } }