In just a few lines of PHP code, this CAPTCHA will allow you to block most spambots. I developed this after some spammers discovered this web site’s contact form. There already were protections to avoid certain exploits (e.g., hijacking the form to send spam to third parties), but they still were able to send me spam emails.
This one is also accessible—instead of showing a difficult-to-read word, this one gives some instructions that must be followed (and thus requires a human) to succeed. Because there is a vulnerability in this code (a spammer could just use a human to answer correctly once, then send the page repeatedly with the correct answer and hash), this is not suitable for major spammer targets, but should work well on small sites.
On the form page, this will show up as instructions ("Enter the first three letters…") and a string of six capital letters with spaces between so they are read as individual letters by a screen reader. A hidden field is filled with the hash of the correct three letters. If the hash was only made from the three letters, a spammer could figure out the hash algorithm, then fill the two fields correctly without having to follow the instructions. By adding a secret string to the three letters, the hash function is extremely hard to duplicate. The secret string must be duplicated on the receiving page in order for it to calculate the same hash.
To best protect your site, you should change the string in this example (hard to guess the hash function) to something of your own choice. Also, you can change the number of letters needed in the response: change the digit ‘3’ in substr($ranstr,0,3) to the desired quantity (and/or change the first letter used by changing the digit ‘0’), and change the user instructions to match.
In your user form, add the following:
<label>Please enter the first three letters of the following:<?php# Make a random string of 6 capital letters$ranstr = chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90));# Print the capital letters with a space between eachecho chunk_split($ranstr,1,' ');?><!-- User enters the response in the ranstr field --><input name="ranstr" type="text" size="90" maxlength="75" /></label><!-- The following hidden field contains the hash of the first three letters plus a string to confuse hackers --><input name="checkran" type="hidden" id="checkran" value="<?php echo hash('sha1',substr($ranstr,0,3).'hard to guess the hash function');?>" />On the back end, the following PHP code cleans up the user input (remove leading and trailing spaces; capitalize all letters), and calculates the hash with the same appended string. If the hashes agree, the user has entered the correct letters. If you submit your form with a GET instead of a POST, change $_POST to $_GET.
<?php# hash the user's response after taking out leading or trailing spaces and capitalizing any lower-case letters; see if it matches the passed hashif ($_POST['checkran']!=hash('sha1',strtoupper(trim($_POST['ranstr'])).'hard to guess the hash function'))# if it doesn't match, print out an error page and request user try again{?> <html><head><title>Error</title></head><body><h1>Error</h1><p>Oops, it appears that you didn't type the correct three letters in the last box. Please go back to the form and try again.</p><form><input type="button" value="Back" onClick="history.go(-1);return true;" /></form></body></html><?phpdie(); } //didn't succeed with CAPTCHA?>See this web site’s contact page for an example. This software is licensed under the CC-GNU GPL. 