diff --git a/core/lib/Drupal/Core/Flood/MemoryBackend.php b/core/lib/Drupal/Core/Flood/MemoryBackend.php index 9899e35e7ee..062471b3db8 100644 --- a/core/lib/Drupal/Core/Flood/MemoryBackend.php +++ b/core/lib/Drupal/Core/Flood/MemoryBackend.php @@ -41,7 +41,7 @@ class MemoryBackend implements FloodInterface { // We can't use REQUEST_TIME here, because that would not guarantee // uniqueness. $time = microtime(TRUE); - $this->events[$name][$identifier][$time + $window] = $time; + $this->events[$name][$identifier][] = ['expire' => $time + $window, 'time' => $time]; } /** @@ -65,8 +65,8 @@ class MemoryBackend implements FloodInterface { return $threshold > 0; } $limit = microtime(TRUE) - $window; - $number = count(array_filter($this->events[$name][$identifier], function ($timestamp) use ($limit) { - return $timestamp > $limit; + $number = count(array_filter($this->events[$name][$identifier], function ($entry) use ($limit) { + return $entry['time'] > $limit; })); return ($number < $threshold); } @@ -76,12 +76,10 @@ class MemoryBackend implements FloodInterface { */ public function garbageCollection() { foreach ($this->events as $name => $identifiers) { - foreach ($this->events[$name] as $identifier => $timestamps) { - // Filter by key (expiration) but preserve key => value associations. - $this->events[$name][$identifier] = array_filter($timestamps, function () use (&$timestamps) { - $expiration = key($timestamps); - next($timestamps); - return $expiration > microtime(TRUE); + foreach ($this->events[$name] as $identifier => $entries) { + // Remove expired entries. + $this->events[$name][$identifier] = array_filter($entries, function ($entry) { + return $entry['expire'] > microtime(TRUE); }); } } diff --git a/core/modules/system/tests/src/Kernel/System/FloodTest.php b/core/modules/system/tests/src/Kernel/System/FloodTest.php index cf32fd9fed7..97b78aa974e 100644 --- a/core/modules/system/tests/src/Kernel/System/FloodTest.php +++ b/core/modules/system/tests/src/Kernel/System/FloodTest.php @@ -74,6 +74,18 @@ class FloodTest extends KernelTestBase { $this->assertFalse($flood->isAllowed($name, $threshold)); } + /** + * Tests memory backend records events to the nearest microsecond. + */ + public function testMemoryBackendThreshold() { + $request_stack = \Drupal::service('request_stack'); + $flood = new MemoryBackend($request_stack); + $flood->register('new event'); + $this->assertTrue($flood->isAllowed('new event', '2')); + $flood->register('new event'); + $this->assertFalse($flood->isAllowed('new event', '2')); + } + /** * Tests flood control database backend. */