2015-12-26 11 views
5

Un utente richiederà un file per numero tramite un URL come script.php?userid=222. Questo esempio mostrerebbe il record del file # 222.Come limitare il numero di richieste degli utenti effettuate in un minuto

Ora voglio limitare il numero di file per utente (IP remoto) a un massimo di 5 record diversi in un minuto. Tuttavia, l'utente dovrebbe essere in grado di accedere allo stesso record ID per un numero qualsiasi di volte.

Quindi l'utente può accedere al file # 222 un numero qualsiasi di volte, ma se l'utente (IP remoto) accede a più di 5 altri diversi record in un minuto, allora dovrebbe mostrare un errore.

Ad esempio, supponiamo che in un minuto le seguenti richieste sono fatte:

script.php?userid=222 
script.php?userid=523 
script.php?userid=665 
script.php?userid=852 
script.php?userid=132 
script.php?userid=002 

poi all'ultimo richiesta dovrebbe mostrare il messaggio di errore.

Ecco il codice di base:

$id = $_GET['userid']; 
if (!isset($_GET['userid']) || empty($_GET['userid'])) { 
    echo "Please enter the userid"; 
    die(); 
} 

if (file_exists($userid.".txt") && 
     (filemtime($userid.".txt") > (time() - 3600 * $ttime))) { 
    $ffile = file_get_contents($userid.".txt");} else { 
    $dcurl = curl_init(); 
    $ffile = fopen($userid.".txt", "w+"); 
    curl_setopt($dcurl, CURLOPT_URL,"http://remoteserver.com/data/$userid"); 
    curl_setopt($dcurl, CURLOPT_RETURNTRANSFER, TRUE); 
    curl_setopt($dcurl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 
    curl_setopt($dcurl, CURLOPT_TIMEOUT, 50); 
    curl_setopt($dcurl, CURLOPT_FILE, $ffile); 
    $ffile = curl_exec($dcurl); 
    if(curl_errno($dcurl)) // check for execution errors 
    { 
     echo 'Script error: ' . curl_error($dcurl); 
     exit; 
    } 
    curl_close($dcurl); 
    $ffile = file_get_contents($userid.".txt"); 
} 
+0

Il modo più affidabile sarebbe per salvare l'indirizzo IP da qualche parte (come un file o database) con l'ID del file a cui si accede e un campo datetime. Ma questo genererà un po 'di traffico del server e un carico pesante su un server mysql se si hanno molti utenti. Un cookie o una sessione con un timeout richiederanno molte meno risorse. Ma sono anche abbastanza facili da aggirare. (eliminare i cookie o chiudere il browser per distruggere la sessione). Immagino che prima dovrai scegliere tra affidabilità e scalabilità. – icecub

+0

Sto dicendo * più affidabile * qui perché in questi giorni non è possibile fare affidamento su un indirizzo IP. Browser come * Tor * possono darti un nuovo indirizzo IP entro 5 secondi semplicemente premendo un pulsante. Quindi probabilmente mi chiederò se valga davvero la pena prima? – icecub

risposta

7

Invece di basarsi su l'indirizzo IP, è possibile utilizzare il meccanismo di sessione. È possibile creare un ambito di sessione tramite session_start() e quindi archiviare le informazioni che corrispondono alla stessa sessione utente.

Vorrei quindi suggerire di mantenere in questa sessione l'elenco di ID univoci utilizzati nelle richieste precedenti che l'utente ha effettuato, insieme al tempo della richiesta, ignorando eventuali richieste ripetute, che sono sempre consentite. Non appena questo elenco contiene 5 elementi con un timestamp nell'ultimo minuto e viene richiesto un nuovo ID, si mostra l'errore e si rifiuta la ricerca.

Ecco il codice che esegue questa operazione. Si dovrebbe posizionarlo a destra dopo aver verificato la presenza del argomento userid, e prima che il recupero del contenuto dei file:

// set the variables that define the limits: 
$min_time = 60; // seconds 
$max_requests = 5; 

// Make sure we have a session scope 
session_start(); 

// Create our requests array in session scope if it does not yet exist 
if (!isset($_SESSION['requests'])) { 
    $_SESSION['requests'] = array(); 
} 

// Create a shortcut variable for this array (just for shorter & faster code) 
$requests = &$_SESSION['requests']; 

$countRecent = 0; 
$repeat = false; 
foreach($requests as $request) { 
    // See if the current request was made before 
    if ($request["userid"] == $id) { 
     $repeat = true; 
    } 
    // Count (only) new requests made in last minute 
    if ($request["time"] >= time() - $min_time) { 
     $countRecent++; 
    } 
} 

// Only if this is a new request... 
if (!$repeat) { 
    // Check if limit is crossed. 
    // NB: Refused requests are not added to the log. 
    if ($countRecent >= $max_requests) { 
     die("Too many new ID requests in a short time"); 
    } 
    // Add current request to the log. 
    $countRecent++; 
    $requests[] = array("time" => time(), "userid" => $id); 
} 

// Debugging code, can be removed later: 
echo count($requests) . " unique ID requests, of which $countRecent in last minute.<br>"; 

// if execution gets here, then proceed with file content lookup as you have it. 
+0

Grazie mille, funziona come un fascino, incredibile! Sei un maestro, risolvi il mio problema! Buon anno e buon Natale in anticipo. – smallbee

+0

Prego. Felice anno nuovo! – trincot

Problemi correlati