<?php

// Cache can be any sort of key/value cache: Memcached, Redis, or simple in memory cache
// Memory required per key should be about 40 - 50 bytes
// Thus one million users should require about 50MB or memory to watch

$m = new Memcached();
$m->addServer('127.0.0.1'11211);
$m->setOption(Memcached::OPT_BINARY_PROTOCOL1); // Required for increment()

$start microtime(1);

if (!empty(
$_GET['show_code'])) { highlight_file(__FILE__); exit; }

////////////////////////////////////////////////////////

$allowed_hits 5// Allowed number of hits per X seconds
$bucket_size  60// Number of seconds to check
$key          $_GET['api_key'] ?? $_SERVER['REMOTE_ADDR']; // Some unique key for the user

$debug   true;
$allowed is_allowed($key$allowed_hits$bucket_size$debug);

////////////////////////////////////////////////////////////////

function is_allowed($key$allowed_hits$bucket_size$debug false) {
    global 
$m;

    
$bucket time() - (time() % $bucket_size);

    
// Get the current number of hits for this key from the cache
    
$ckey "API_LIMIT:$bucket:$key";
    
$hits $m->increment($ckey11time() + $bucket_size);

    
// Uncomment this if you can't use increment()
    //$hits = intval($m->get($ckey));
    //$ok   = $m->set($ckey, ++$hits, time() + $bucket_size);

    
$ret true;
    if (
$hits $allowed_hits) {
        
$ret false;
    }

    if (
$debug) {
        
$remain $bucket_size - (time() % $bucket_size);

        
$out  "<h1>API Limit tester</h1>\n\n";
        
$out .= "<p>You are allowed to hit this API $allowed_hits times every $bucket_size seconds</p>\n";
        
$out .= "<p>You are $key and you've hit this API $hits times in the last $bucket_size seconds. Counter will reset in $remain seconds</p>\n";

        if (!
$ret) {
            
$out .= "<div style=\"color: red;\"><b>DENIED</b></div>\n";
        } else {
            
$out .= "<div style=\"color: green;\"><b>Allowed</b></div>\n";
        }

        
$out .= "<p><a href=\"?show_code=true\">[View code]</a></p>\n";

        
$text_only preg_match("/curl/"$_SERVER['HTTP_USER_AGENT']);
        if (
$text_only) {
            
$out strip_tags($out);
        }

        global 
$start;
        
$out .= sprintf("<p>%0.2f ms to process</p>\n", (microtime(1) - $start) * 1000);

        print 
$out;
    }

    return 
$ret;
}