diff --git a/lib/Controller.php b/lib/Controller.php index 72bd5b2..095bbeb 100644 --- a/lib/Controller.php +++ b/lib/Controller.php @@ -198,6 +198,7 @@ class Controller try { // Ensure last paste from visitors IP address was more than configured amount of seconds ago. TrafficLimiter::setConfiguration($this->_conf); + TrafficLimiter::setStore($this->_model->getStore()); if (!TrafficLimiter::canPass()) { $this->_return_message( 1, I18n::_( diff --git a/lib/Data/AbstractData.php b/lib/Data/AbstractData.php index 0508bc0..3de4bab 100644 --- a/lib/Data/AbstractData.php +++ b/lib/Data/AbstractData.php @@ -130,6 +130,16 @@ abstract class AbstractData */ abstract public function existsComment($pasteid, $parentid, $commentid); + /** + * Purge outdated entries. + * + * @access public + * @param string $namespace + * @param int $time + * @return void + */ + abstract public function purgeValues($namespace, $time); + /** * Save a value. * diff --git a/lib/Data/Database.php b/lib/Data/Database.php index 5a0f369..2a1bbcb 100644 --- a/lib/Data/Database.php +++ b/lib/Data/Database.php @@ -423,6 +423,23 @@ class Database extends AbstractData ); } + /** + * Purge outdated entries. + * + * @access public + * @param string $namespace + * @param int $time + * @return void + */ + public function purgeValues($namespace, $time) + { + switch ($namespace) { + case 'traffic_limiter': + ; + break; + } + } + /** * Save a value. * diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php index f24691b..3a481d9 100644 --- a/lib/Data/Filesystem.php +++ b/lib/Data/Filesystem.php @@ -38,6 +38,15 @@ class Filesystem extends AbstractData */ private static $_path = 'data'; + /** + * cache for the traffic limiter + * + * @access private + * @static + * @var array + */ + private static $_traffic_limiter_cache = array(); + /** * get instance of singleton * @@ -240,6 +249,27 @@ class Filesystem extends AbstractData ); } + /** + * Purge outdated entries. + * + * @access public + * @param string $namespace + * @param int $time + * @return void + */ + public function purgeValues($namespace, $time) + { + switch ($namespace) { + case 'traffic_limiter': + foreach (self::$_traffic_limiter_cache as $key => $last_access) { + if ($last_access <= $time) { + unset(self::$_traffic_limiter_cache[$key]); + } + } + break; + } + } + /** * Save a value. * @@ -262,7 +292,11 @@ class Filesystem extends AbstractData ; break; case 'traffic_limiter': - ; + self::$_traffic_limiter_cache[$key] = $value; + return self::_storeString( + self::$_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php', + 'exists(); } + /** + * Purge outdated entries. + * + * @access public + * @param string $namespace + * @param int $time + * @return void + */ + public function purgeValues($namespace, $time) + { + switch ($namespace) { + case 'traffic_limiter': + ; + break; + } + } + /** * This is the simplest thing that could possibly work. * will be to tested for runtime performance. diff --git a/lib/Model.php b/lib/Model.php index 1a23653..8aebd79 100644 --- a/lib/Model.php +++ b/lib/Model.php @@ -54,7 +54,7 @@ class Model */ public function getPaste($pasteId = null) { - $paste = new Paste($this->_conf, $this->_getStore()); + $paste = new Paste($this->_conf, $this->getStore()); if ($pasteId !== null) { $paste->setId($pasteId); } @@ -67,9 +67,9 @@ class Model public function purge() { PurgeLimiter::setConfiguration($this->_conf); - PurgeLimiter::setStore($this->_getStore()); + PurgeLimiter::setStore($this->getStore()); if (PurgeLimiter::canPurge()) { - $this->_getStore()->purge($this->_conf->getKey('batchsize', 'purge')); + $this->getStore()->purge($this->_conf->getKey('batchsize', 'purge')); } } @@ -78,7 +78,7 @@ class Model * * @return Data\AbstractData */ - private function _getStore() + public function getStore() { if ($this->_store === null) { $this->_store = forward_static_call( diff --git a/lib/Persistence/TrafficLimiter.php b/lib/Persistence/TrafficLimiter.php index 299c7a6..f6bc07f 100644 --- a/lib/Persistence/TrafficLimiter.php +++ b/lib/Persistence/TrafficLimiter.php @@ -169,35 +169,18 @@ class TrafficLimiter extends AbstractPersistence } } - $file = 'traffic_limiter.php'; - if (self::_exists($file)) { - require self::getPath($file); - $tl = $GLOBALS['traffic_limiter']; - } else { - $tl = array(); - } - - // purge file of expired hashes to keep it small - $now = time(); - foreach ($tl as $key => $time) { - if ($time + self::$_limit < $now) { - unset($tl[$key]); - } - } - // this hash is used as an array key, hence a shorter algo is used $hash = self::getHash('sha256'); - if (array_key_exists($hash, $tl) && ($tl[$hash] + self::$_limit >= $now)) { + $now = time(); + $tl = self::$_store->getValue('traffic_limiter', $hash); + self::$_store->purgeValues('traffic_limiter', $now - self::$_limit); + if ($tl > 0 && ($tl + self::$_limit >= $now)) { $result = false; } else { - $tl[$hash] = time(); - $result = true; + $tl = time(); + $result = true; } - self::_store( - $file, - 'setValue((string) $tl, 'traffic_limiter'); return $result; } } diff --git a/tst/ControllerTest.php b/tst/ControllerTest.php index 6e7ec4c..92683ce 100644 --- a/tst/ControllerTest.php +++ b/tst/ControllerTest.php @@ -17,6 +17,7 @@ class ControllerTest extends PHPUnit_Framework_TestCase /* Setup Routine */ $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; $this->_data = Filesystem::getInstance(array('dir' => $this->_path)); + TrafficLimiter::setStore($this->_data); $this->reset(); }