Skip to content

Instantly share code, notes, and snippets.

@salvamomo
Last active July 22, 2016 11:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save salvamomo/7e4f01a96c7fd8b7422360c74aa78ce2 to your computer and use it in GitHub Desktop.
Save salvamomo/7e4f01a96c7fd8b7422360c74aa78ce2 to your computer and use it in GitHub Desktop.
Function flood prevention for Drupal 7.
<?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