Last active
July 22, 2016 11:56
-
-
Save salvamomo/7e4f01a96c7fd8b7422360c74aa78ce2 to your computer and use it in GitHub Desktop.
Function flood prevention for Drupal 7.
This file contains 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 characters
<?php | |
/** | |
* Checks whether a function can be called without falling on "flood" usage. | |
* | |
* USAGE: This function returns TRUE if the call to the desired function can be | |
* safely made. If not, it will stop execution for 3 seconds. A caller function | |
* can then use it to check for a negative value, and make a recursive call to | |
* themselves until this returns TRUE. | |
* | |
* Example use: | |
* | |
* function my_dangerous_function() { | |
* // Don't execute more than 30 times every 5 seconds. If flooding is | |
* // detected, wait 5 seconds before trying again. | |
* if (flood_prevention(__FUNCTION__, 30, 5, 5) == FALSE) { | |
* return my_dangerous_function(); | |
* } | |
* // Do something if flood prevention was passed successfully. | |
* } | |
* | |
* @param string $function_name | |
* The function name for which to check usage. | |
* @param int $call_limit | |
* The limit of calls that can be made in a given time without being considered | |
* as flooding. | |
* @param int $limit_timeframe | |
* The time window in which the limit of calls can be made without considering | |
* it as flooding. | |
* @param int $waiting_time | |
* The time to wait if flood prevention is not passed. | |
* | |
* @return bool | |
* TRUE if the call to the function can be made without being considered | |
* flooding, or FALSE otherwise. | |
*/ | |
function flood_prevention($function_name, $call_limit = 100, $limit_timeframe = 60, $waiting_time = 3) { | |
$now = time(); | |
$request_counter = &drupal_static($function_name); | |
// Calculate requests on the last X seconds. | |
$timeframe_begin = $now - $limit_timeframe; | |
$timeframe_current = $now; | |
$requests_sent_in_last_timeframe = 0; | |
foreach ($request_counter as $timeframe => $count) { | |
// Unset frames older than the start section of the current limit timeframe. | |
if ($timeframe < $timeframe_begin) { | |
unset($request_counter[$timeframe]); | |
} | |
else { | |
$requests_sent_in_last_timeframe += $count; | |
} | |
} | |
// Limit about to be reached. Sleep for a few seconds | |
if ($requests_sent_in_last_timeframe > $call_limit - 1) { | |
sleep($waiting_time); | |
return FALSE; | |
} | |
$new_timeframe_value = isset($request_counter[$timeframe_current]) ? $request_counter[$timeframe_current] + 1 : 1; | |
$request_counter[$timeframe_current] = $new_timeframe_value; | |
return TRUE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment