1

I have a php 5.5 web app using the Symfony2 framework and would like to keep the server load at a minimum. A few pages on my site allows the user to retrieve a list of objects from a database and one set has several hundred thousand rows, and will be over a million soon. Unregistered users are able to use this page.

I want to prevent the user from performing a query too many times in a minute or some similar timespan and have seen this implemented on other websites, including stackoverflow for comments or voting.

How is this implemented? Do I need to create a cookie and check the session on each page load to see if the specific actions I want to limit have been used and prevent the form submission? Is there a standard way of handling this in php, or specifically for Symfony2? I have searched for this and found some similar questions, but no specific answer. This is for users directly on my site and not using an api.

How to throttle API requests using PHP

How do I throttle my site's API users?

Edit:

I know cookies are not the proper way to go and will try to implement a mechanism using a cache. I'm using php 5.5 and read that APC has some bugs with 5.5, therefore Zend OpCache is actually preferred along with APCu. Can anyone show an example of using Zend OpCache / APCu to log and track user requests?

Community
  • 1
  • 1
George
  • 1,478
  • 17
  • 28

1 Answers1

1

Cookies is not the secure way. When I did something of similar, I used APC or MongoDB to store the counter, with a key made with:

  • IP: $_SERVER['HTTP_X_FORWARDED_FOR'] | $_SERVER['REMOTE_ADDR']
  • Browser: $_SERVER['HTTP_USER_AGENT'])
  • absolute timestamp of this hour (or minutes if you want to check shortly)

So for example you can store an APC key named with: ip2long($ip), crc32($browser), time() - time() % 3600, and save there your hit value.

I put an example of code that made use only of the IP in a range of 1 hour.

// Time
$now = time();
$time = $now - $now%3600;

// IP
if(array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    $ip = $_SERVER['REMOTE_ADDR'];
}
$key = sprintf('%d-%u', $time, ip2long($ip));

if (apc_inc($key)) {
    echo "we have ". apc_fetch($key). " views in this hour";
}
M. Foti
  • 3,156
  • 2
  • 16
  • 14
  • I'm using postgresql and would use like to use APC. The is a very small amount of memory, but what size of user base would make it so large that I should shift this to the database? Should I manually clear this or let the cache manage itself? – George Sep 12 '14 at 15:17
  • It depends on how long you want maintain your log, if is only one minute you don't need to have this persistent – M. Foti Sep 12 '14 at 16:02
  • Do you know if these same functions work using APCu? There are very few documents on APCu that I can find. – George Sep 12 '14 at 19:51