All the answers above are wrong. Except for @w3dk which is almost correct.
That would need to be JavaScript, not PHP.
Yes!
Why?
Assuming no JS is used then, the request is made to the server using the standard HTML form submission functionality which loads a new page. If a new page loads, then there is no issue. So this is absolutely a Javascript issue, because this can only happen if the form is being prevented from loading a new page, as with event.preventDefault(). The fix is simple, when the onClick event is triggered one should set the submit button attribute to disabled=true. In addition as suggested by @phparion, you can change the color of the bottom. This can easily be done using only CSS by styling the class with a the :disabled pseudo-class*.
Now since the request is ajax, there is a good chance that one would want/expect the user to submit the form multiple times during their time on page. (Eg: trying different values). The solution above wont allow that, since the button would be disabled on the first click and not re-enabled after. The best solution is that case would be to use the javascript promises. Where the button is disabled onClick, at the same time as the request is made (Fetch as a promise), then (using Then) when the request's response returns, one sets the button back to disabled="false". Like that the button only becomes active after the new data is shown on the page.
Handling this issue server side is not addressing the root cause of the problem, and yes the server side solutions will prevent duplicate writes to the database, but it is not addressing the duplicate and thus wasteful requests to the server.
*info on disabled pseudo-class see here:
[
developer.mozilla.org...]
Regarding W3dk's suggested solution.
You could also try (server-side):
1. Generate a "unique token" as you send the form to the client.
2. Store the token in a "hidden" form field (that is later submitted with the form) and in a session variable (server-side, unique to the user).
3. A form submission is only successful when the token in the form submission matches the token in the session variable. At which point the session variable is cleared.
4. Subsequent form submissions are invalid since the session variable has already been cleared.
It is good practice to implement this when your form is going to cause a write to your database. It ensures that the data is submitted from the actual page as opposed to simply by sending a request to the forms enpoint. This is particularly important if the user needs to be logged in to submit the form as it prevents CSRF attacks.
[
cheatsheetseries.owasp.org...]