You can protect your form with the form keys technique:
- When displaying the form to the user, generate a random ID ("form key") just for this single form submission. Store the form key in a session variable. Submit the "form key" in a hidden input field.
- On the server side, check the submitted form key against the one stored in the session variable. Immediately invalidate it after use. (delete it from the session)
Without a captcha or something comparable, it is impossible to really protect a form from abuse.
However, using this technique a malicious spammer would have to
- request for form via HTTP for each single form submission to obtain a valid unique forkey
- parse the DOM tree / HTML code to obtain the form key
- submit it in the correct format
This technique also protects your form from multiple accidential submissions.
Here is a code example:
<?php
session_start();
if (isset($_POST['form_submit'])) {
// do stuff
if (isset($_POST['formkey']) && isset($_SESSION['formkeys'][$_POST['formkey']])) {
echo "valid, doing stuff now ... "; flush();
// delete formkey from session
unset($_SESSION['formkeys'][$_POST['formkey']]);
// release session early - after committing the session data is read-only
session_write_close();
// do whatever you like with the form data here
send_contact_mail($_POST);
}
else {
echo "request invalid or timed out.";
}
}
else {
// show form with formkey
$formkey = md5("foo".microtime().rand(1,999999));
// put current formkey into list of valid form keys for the user session
if (!is_array($_SESSION['formkeys']) {
$_SESSION['formkeys'] = array();
]
$_SESSION['formkeys'][$formkey] = now();
?>
<html>
<head><title>form key</title></head>
<body>
<form method="POST">
<input type="hidden" name="PHPSESSID" value="<?=session_id()?>">
<input type="text" name="formkey"
value="<?= $formkey ?>">
<input type="submit" name="form_submit" value="Contact us!">
</form>
</body>
</html>
<?php } ?>