You cannot. It's in the nature of how web servers, PHP, and databases work.
Web servers are multi-threaded. They can process multiple requests simultaneously, including malicious requests coming at roughly the same time from the same IP address.
Each PHP thread works independently of each other. There is no inter-process communication in PHP, at least in a way which can be used in a mass-distributed piece of software (technically there's the shmop
extension, but it's disabled on most commercial hosts for good reason). As a result of that, the only way to communicate that an IP has been blocked is to use the database.
When an IP address is blocked we write that information to the database. However, there are two minor problems with that. One is that there is always a small amount of time (milliseconds) between asking the database to store some information and being able to read it from the database. Moreover, there is always some temporal distance in the PHP code execution points of reading whether an IP address is blocked, and effecting a block.
This all means that when your site is under heavy attack there will be a few PHP threads running in parallel which will all try to block the same IP address and send you an email. This is usually between 2 and 10 threads on typical server configurations. So, it's completely normal to see this, and we've written the code in such a way that it does not cause any problems with the IP blocking itself. As you said, there's only ever one database record per blocked IP address (this is intentional, and how we prevent issues with the IP blocking itself).
Working around that is possible, but it's also impractical. One solution would be using an in-memory, disk-backed key-value database with atomic read/write operations such as Redis (or its newer open source re-implementation, Valkey) to store the list of blocked IP addresses instead of using a generic RDBMS with no atomicity such as MySQL and PostgreSQL; obviously, the problem here is that virtually no commercial host offers that. Another solution would be holding a copy of the blocked IPs in shared memory using the shmop
extension, but this is not only something that's usually not available on commercial hosting, but also comes with the added risk of causing breakage which requires service restarts on the server; not exactly suitable for mass-distributed software.
In the grand scheme of things, having a few emails more is a far better experience than requiring a very particular server setup that's nigh impossible for the average person to have, or risking bringing down parts of your server if we mistype a character.
Nicholas K. Dionysopoulos
Lead Developer and Director
🇬🇷Greek: native 🇬🇧English: excellent 🇫🇷French: basic • 🕐 My time zone is Europe / Athens
Please keep in mind my timezone and cultural differences when reading my replies. Thank you!