Limit time between connections with PHP

in Programming

Say you have a script/api that you want to host on your own server, but would like to set a minimum period of time between calls. If you don’t have access to your Apache settings, there are few simple ways to do it with a bit of PHP code.

First, you could use PHP’s sleep() function to delay execution of the script. This option, however, artificially delays each call: the user connects to your api and has to wait until the specified delay expires to get any results. It works, but it isn’t perfect.

Second, you could simply start a session and store the time of the request in a session variable (i.e. $_SESSION[‘time’]) and then compare the current time with the stored time. Let’s say you want to halt the script if the connections are less than 5 seconds apart:


session_start();

if (isset($_SESSION['time'] !== false)) { // Check to see if variable is set
$_SESSION['time'] = date('His'); // Format of time is 24hminsec (183412)
}

else {
// Is span less than 5 sec?
if (abs(_SESSION['time'] - date('His')) < 5) {
exit("You must wait at least 5 seconds between requests.");
}

else {
$_SESSION['time'] = date('His'); // Update time of last request
}
}

You must use the ABS function on the subtraction, otherwise any subsequent request after midnight will fail because it will return a negative value: (12:01 AM = 000100) – (11:59 pm = 235,900) = -235,800. Using ABS converts any negative results value into a positive value. Of course, this also means that in order to prevent any calls shorter than 5 seconds apart just after midnight requires that we check for values greater than 230,000, but this isn’t really important because once the new post-midnight time is recorded, subtractions will return positive results.

The above code works well for calls from a browser, but what if someone is accessing your script via some other means, like Google Refine‘s fetch via URL tool? No session will be opened and connections will be made based on whatever delay the user sets within Refine’s settings.

Another option uses the requester’s IP instead, as well as time, to verify the frequency of these api calls. The best way would be to store the user’s IP in a table in your database using the $_SERVER[‘REMOTE_ADDR’] global variable. If, for some reason, you don’t want to store it in your database (because you’re not comfortable with SQL, for instance), you can simply create a text file and store the information in that file. But if more than one user connects to your script simultaneously, this method will not work properly as both users will be accessing the same file. Instead, you can store the connection time by creating a unique file using the IP address as the file name (this method is only recommended if you don’t think many people will use your script as it will create a unique file for each unique IP–otherwise, you should store this info in a database).


// Open/create a file using the user's IP as the file name.
// c+b flag opens new file if file doesn't exist.
// Allows for both read and write without resetting file size to 0.
$ipfh = fopen("logs/".$_SERVER['REMOTE_ADDR'].".txt", 'c+b');

// Look for time in file (read first 6 bytes/characters).
$storedtime = fread($ipfh, 6);

// If current time minus stored time is smaller than 5 seconds
if (abs(date('His') - $storedtime) < 5) {
fclose($ipfh); // Close file
exit("You must wait 5 seconds between requests.");
}

else {
fseek($ipfh, 0); // Reset pointer to beginning of file.
fwrite($ipfh, date('His')); // Write time
fclose($ipfh); // Close file
}

This last method will of course work for any regular browser request, as well as calls made from other sources.

1 Comment