2015-12-26 5 views
5

Пользователь запросит файл по номеру через URL-адрес, например script.php?userid=222. В этом примере будет показана запись файла # 222.Как ограничить количество пользовательских запросов, сделанных в течение минуты

Теперь я хочу ограничить количество файлов на пользователя (удаленного IP) до пяти разных записей за минуту. Тем не менее, пользователь должен иметь возможность получать доступ к одной и той же записи id сколько угодно времени.

Таким образом, пользователь может получить доступ к файлу # 222 сколько угодно раз, но если пользователь (удаленный IP) получает доступ к более чем 5 другим записям за минуту, тогда он должен показывать ошибку.

Например, предположим, что в течение одной минуты следующие запросы сделаны:

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

затем в последнем запросе он должен показать сообщение об ошибке.

Вот основной код:

$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

Самым надежным способом было бы сохранить адрес IP-где (например, файл или базы данных) вместе с доступом к файлу и полем datetime. Но это создаст довольно некоторый трафик сервера и большую нагрузку на сервер mysql, если у вас много пользователей. Куки или сеанс с тайм-аутом потребуют гораздо меньше ресурсов. Но их также легко обойти. (удалите файлы cookie или закрыть браузер, чтобы уничтожить сеанс). Я думаю, вам придется выбирать между надежностью и масштабируемостью в первую очередь. – icecub

+0

Я говорю * самый надежный * здесь, потому что в эти дни вы не можете действительно полагаться на IP-адрес. Браузеры, такие как * Tor *, могут дать вам новый IP-адрес в течение 5 секунд, просто нажав кнопку. Поэтому я бы с уверенностью спросил себя, действительно ли это стоит проблемы? – icecub

ответ

7

Вместо того, чтобы полагаться на IP-адрес, вы можете использовать механизм сеанса. Вы можете создать область сеанса через session_start(), а затем сохранить информацию, которая хранится в том же сеансе пользователя.

Я предлагаю сохранить в этой области сеанса список уникальных идентификаторов, используемых в предыдущих запросах, которые пользователь сделал вместе с временем запроса, игнорируя любые повторяющиеся запросы, которые всегда разрешены. Как только этот список содержит 5 элементов с отметкой времени в течение последней минуты и запрашивается новый идентификатор, вы показываете ошибку и отказываетесь от поиска.

Вот код, который делает это. Вы должны поместить его сразу после того, как вы проверили наличие идента аргумента, а перед извлечением содержимого файла:

// 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

Большое спасибо, он работает как шарм, потрясающий! Вы мастер, вы решаете мою проблему! С Новым годом и Рождеством в продвижении. – smallbee

+0

Добро пожаловать. С новым годом! – trincot

Смежные вопросы