2

I want to prevent my script, from being flooded - if user hit F5 it is executing the script every time.

I want to prevent from this and allow one script execution per 2 seconds, is there any solution for that?

Lucas
  • 3,517
  • 13
  • 46
  • 75
  • I know you have selected my answer but ... felt like writing an improved version for you ... see answer for updated script – Baba Apr 14 '12 at 17:42

5 Answers5

14

You can use memcache to do this ..

Simple Demo Script

$memcache = new Memcache ();
$memcache->connect ( 'localhost', 11211 );
$runtime = $memcache->get ( 'floodControl' );

if ((time () - $runtime) < 2) {
    die ( "Die! Die! Die!" );
} 

else {
    echo "Welcome";
    $memcache->set ( "floodControl", time () );
}

This is just a sample code .. there are also other thing to consider such as

A. Better IP address detection (Proxy , Tor )

B. Current Action

C. Maximum execution per min etc ...

D. Ban User after max flood etc

EDIT 1 - Improved Version

Usage

$flood = new FloodDetection();
$flood->check();

echo "Welcome" ;

Class

class FloodDetection {
    const HOST = "localhost";
    const PORT = 11211;
    private $memcache;
    private $ipAddress;

    private $timeLimitUser = array (
            "DEFAULT" => 2,
            "CHAT" => 3,
            "LOGIN" => 4 
    );
    private $timeLimitProcess = array (
            "DEFAULT" => 0.1,
            "CHAT" => 1.5,
            "LOGIN" => 0.1 
    );

    function __construct() {
        $this->memcache = new Memcache ();
        $this->memcache->connect ( self::HOST, self::PORT );
    }

    function addUserlimit($key, $time) {
        $this->timeLimitUser [$key] = $time;
    }

    function addProcesslimit($key, $time) {
        $this->timeLimitProcess [$key] = $time;
    }

    public function quickIP() {
        return (empty ( $_SERVER ['HTTP_CLIENT_IP'] ) ? (empty ( $_SERVER ['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER ['REMOTE_ADDR'] : $_SERVER ['HTTP_X_FORWARDED_FOR']) : $_SERVER ['HTTP_CLIENT_IP']);
    }

    public function check($action = "DEFAULT") {
        $ip = $this->quickIP ();
        $ipKey = "flood" . $action . sha1 ( $ip );

        $runtime = $this->memcache->get ( 'floodControl' );
        $iptime = $this->memcache->get ( $ipKey );

        $limitUser = isset ( $this->timeLimitUser [$action] ) ? $this->timeLimitUser [$action] : $this->timeLimitUser ['DEFAULT'];
        $limitProcess = isset ( $this->timeLimitProcess [$action] ) ? $this->timeLimitProcess [$action] : $this->timeLimitProcess ['DEFAULT'];

        if ((microtime ( true ) - $iptime) < $limitUser) {
            print ("Die! Die! Die! $ip") ;
            exit ();
        }

        // Limit All request
        if ((microtime ( true ) - $runtime) < $limitProcess) {
            print ("All of you Die! Die! Die! $ip") ;
            exit ();
        }

        $this->memcache->set ( "floodControl", microtime ( true ) );
        $this->memcache->set ( $ipKey, microtime ( true ) );
    }

}
Baba
  • 94,024
  • 28
  • 166
  • 217
  • 1
    I was considering to upvote. Until the moment you used that Singleton. – Madara's Ghost Apr 14 '12 at 18:37
  • haaaa.. i would change it right away .. +1 thanks for the observation – Baba Apr 14 '12 at 18:43
  • @truth .. one more thing .. why do you think Singleton was such a bad idea .. for the example ... – Baba Apr 14 '12 at 18:47
  • 2
    Singletons have no benefits over static classes or instance objects. They only impose constrains and in later stages of the project, trouble. Hard to test, hard to maintain code (tight coupling blah blah blah). [Read all about it](http://programmers.stackexchange.com/questions/40373/so-singletons-are-bad-then-what) – Madara's Ghost Apr 14 '12 at 19:19
4
  1. Store the last execution time of your script in a database or a file.
  2. Read from that file/database and compare to the current time.
  3. If the difference is under 2 seconds, terminate the script.
  4. Else, continue normally.
Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
2

you can either use cookies (which can be disabled) so not a very good idea, or you can use store his ip address in the database, so if more then X tries from the same IP address then do not execute the code, just an if else statement, you will need a table with ip addresses time of request, number of tries

IF you do not want to use databases then you can use the following code

$file = "file.txt";
$file_content = file_get_contents($file);
$fh = fopen($file, 'w') or die("could not open file");
$now = time();
if($now - $file_content > 60){
// your code here
fwrite($fh, $now);
}else{
echo "Try again later";
}
fclose($fh);

but in this case, it won't be for each visitor but rather for all of them (so say user A came and execute the script, user B won't be able to execute it until 60 seconds pass.

AL-Kateb
  • 2,914
  • 3
  • 20
  • 24
0

The best way would be to store the time on serverside. If you leave the information on client side it would be easy to by pass.

I would for example save the timestamp in a table. That inputs and checks against spamming your script. And would be easy to set tolerence.

Harry
  • 725
  • 3
  • 7
  • 19
0

use either apc cache or mencache to store information storing to database or reading from file i believe is time/resource consuming

Gntem
  • 6,949
  • 2
  • 35
  • 48