FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Throttle.php
Go to the documentation of this file.
1 <?php
2 
4 
5 class Throttle extends \Rsi\Fred\Security\Check{
6 
7  public $mask = '/(\\.\\d+|(:\\d+){4})$/'; //!< IP address subnet mask (part to remove).
8  public $ext = '.tht'; //!< Extension for throttle registration file.
9  public $checkTtl = 300; //!< Re-use throttle info for this amount of time (seconds).
10  public $logPrio = \Rsi\Fred\Log::WARNING; //!< Log prio for the warning message.
11  public $limitLog = 3600; //!< Number of requests after which the subnet is added to the log.
12  public $limitBan = 7200; //!< Number of requests after which the subnet is banned.
13  public $interval = 3600; //!< Number of seconds after which the counter gets reset.
14  public $sleep = []; //!< Extra sleep time (value, milliseconds) if the counter gets above a certain value (key, ascending).
15 
16  protected $_path = null;
17  protected $_purgeLimit = null;
18 
19  protected function subnet($addr = null){
20  return preg_replace($this->mask,'',$addr ?: $this->component('security')->remoteAddr);
21  }
22 
23  protected function filename($addr = null){
24  return $this->path . str_replace(['.',':'],'-',$this->subnet($addr)) . $this->ext;
25  }
26 
27  protected function timeLine($filename){
28  $f = fopen($filename,'r');
29  $time = fgets($f);
30  fclose($f);
31  return $time;
32  }
33 
34  protected function purge(){
35  foreach((new \GlobIterator($this->path . '*' . $this->ext)) as $filename => $file)
36  if(trim($this->timeLine($filename)) < $this->purgeLimit) \Rsi\File::unlink($filename);
37  }
38 
39  protected function checkLimits($time,$count,$prev){
40  if($time < $this->purgeLimit){
41  $this->purge();
42  return null;
43  }
44  if($count > $this->limitBan) return false;
45  if($prev === null ? $count == $this->limitLog : ($count >= $this->limitLog) && ($prev < $this->limitLog))
46  $this->component('log')->add($this->logPrio,'Subnet ' . $this->subnet() . ' getting close to ban limit',__FILE__,__LINE__);
47  $sleep = null;
48  foreach($this->sleep as $limit => $time){
49  if($count < $limit) break;
50  $sleep = $time;
51  }
52  if($sleep) usleep($sleep * 1000);
53  return true;
54  }
55 
56  public function check($expected = false){
57  if(!$expected) try{
58  if($exists = is_file($filename = $this->filename())){
59  if((($result = $this->session->lastResult) === null) || ($this->session->lastCheck < $this->_fred->startTime - $this->checkTtl)){
60  $time = $this->timeLine($filename);
61  $this->session->lastResult = $result = $this->checkLimits(trim($time),$count = filesize($filename) - strlen($time),$this->session->prevCount);
62  $this->session->lastCheck = $this->_fred->startTime;
63  $this->session->prevCount = $count;
64  if($result === null) $exists = false;
65  }
66  if($result === false) return false;
67  }
68  $f = fopen($filename,$exists ? 'a' : 'w');
69  if(!$exists) fwrite($f,time() . "\n");
70  fwrite($f,substr($char = date('s'),0,1) == '0' ? substr($char,1,1) : chr($char + ($char < 35 ? 87 : 30)));
71  fclose($f);
72  if(!$exists) chmod($filename,0666);
73  }
74  catch(\Exception $e){
75  if($this->_fred->debug) throw $e;
76  }
77  return true;
78  }
79 
80  public function unBan($addr){
81  return \Rsi\File::unlink($this->filename($addr));
82  }
83 
84  protected function getPurgeLimit(){
85  if(!$this->_purgeLimit) $this->_purgeLimit = time() - $this->interval;
86  return $this->_purgeLimit;
87  }
88 
89  protected function getPath(){
90  if(!$this->_path) $this->_path = $this->component('security')->path;
91  return $this->_path;
92  }
93 
94 }
$logPrio
Log prio for the warning message.
Definition: Throttle.php:10
$interval
Number of seconds after which the counter gets reset.
Definition: Throttle.php:13
$ext
Extension for throttle registration file.
Definition: Throttle.php:8
checkLimits($time, $count, $prev)
Definition: Throttle.php:39
$checkTtl
Re-use throttle info for this amount of time (seconds).
Definition: Throttle.php:9
$sleep
Extra sleep time (value, milliseconds) if the counter gets above a certain value (key, ascending).
Definition: Throttle.php:14
$limitBan
Number of requests after which the subnet is banned.
Definition: Throttle.php:12
$mask
IP address subnet mask (part to remove).
Definition: Throttle.php:7
$limitLog
Number of requests after which the subnet is added to the log.
Definition: Throttle.php:11
component($name)
Get a component (local or default).
Definition: Component.php:80