Ramjam Posted May 6, 2011 Share Posted May 6, 2011 Hi everyone I've successfully created a contact form with php that gives the various required messages. Now I would like to add a simple random arithmetic captcha (non-image). See the anonymised (working) html form and existing (working, but without arithmetic captcha) php below. The idea is to show "Incorrect answer" in the same way as the other error messages, or to pass to the Thankyou page for a correctly filled out form with correct answer. I've had a good go at this but can't quite get it to work. Any assistance much appreciated. ___ HTML: <div id="form" class="form"> <h3 class="title">Contact Form</h3> <p>Required fields are in <strong>bold</strong></p> <form action="contact.php" method="post" target="_blank"> <p><strong>Name:</strong><br /><input type="text" name="yourname" size="35" /></p> <p><strong>Email address:</strong><br /><input type="text" name="email" size="35"/></p> <p>Telephone number:<br /><input type="text" name="telephone" size="35"/></p> <p>Website (if applicable):<br /><input type="text" name="website" size="35"/></p> <p>Area of interest: <input type="radio" name="likeit" value="A" checked="checked" /> A <input type="radio" name="likeit" value="B" /> B <input type="radio" name="likeit" value="C" /> C</p> <p>How did you hear about us? <select name="how"> <option value=""> -- Please select -- </option> <option>Recommendation</option> <option>Internet</option> <option>Advertisement</option> <option>Other</option> </select></p> <p><strong>Your message subject:</strong><br /><input type="text" name="subject" size="35"/></p> <p><strong>Your message:</strong><br /> <textarea name="comments" rows="10" cols="40"></textarea></p> <p>Please answer the following arithmetic question: What is <?php echo $digit1;?> + <?php echo $digit2;?>? <input name="captcha" type="text" size="2" id="captcha"/></p> <p><input type="submit" value="Send" /></p> </form> PHP: <?php /* Contact form with arithmetic captcha */ $myemail = "enquiries@X.co.uk"; /* Check all form inputs using check_input function */ $yourname = check_input($_POST['yourname'], "Enter your name"); $email = check_input($_POST['email']); $telephone = check_input($_POST['telephone']); $website = check_input($_POST['website']); $likeit = check_input($_POST['likeit']); $how_find = check_input($_POST['how']); $subject = check_input($_POST['subject'], "Add a subject"); $comments = check_input($_POST['comments'], "Add your message"); /* If e-mail is not valid show error message */ if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/", $email)) { show_error("Email address is not valid"); } /* If URL is not valid set $website to empty */ if (!preg_match("/^(https?:\/\/+[\w\-]+\.[\w\-]+)/i", $website)) { $website = ''; } /* Message for the email */ $message = "Hello! Your contact form has been submitted by: Name: $yourname Email: $email Telephone: $telephone URL: $website Area of interest? $likeit How did they find us? $how_find Comments: $comments End of message "; /* Send the message using mail() function */ mail($myemail, $subject, $message); /* Redirect visitor to the thankyou page */ header('Location: thankyou.html'); exit(); /* Functions used */ function check_input($data, $problem='') { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); if ($problem && strlen($data) == 0) { show_error($problem); } return $data; } function show_error($myError) { ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- Head data in here --> <html xmlns="http://www.w3.org/1999/xhtml"> <body> <div id="mainheader"> <div id="mainlogo"> <h1><a href="http://www.X.co.uk/" title="X"> <img style="border:0;width: 260px; height: 160px;" src="images/X.jpg" alt="X" /></a></h1> </div> </div> <div id="content"> <div class="content"> <h2 class="title">Error!</h2> <p><strong>Please correct the following error:</strong></p> <p><?php echo $myError; ?></p> </div> </div> <div id="panel"> <div id="main" class="boxed"> <h2 class="heading">Main</h2> <ul> <li><a href="index.html">Home</a> </li> <li><a href="about.html">About</a> </li> <li><a href="contact.html">Contact</a> </li> </ul> </div> <div id="services" class="boxed"> <h2 class="heading">Services</h2> <ul> <li><a href="services.html">Services</a> </li> <li><a href="recent-projects.html">Recent projects</a> </li> </ul> </div> <div id="pricing" class="boxed"> <h2 class="heading">Pricing</h2> <ul> <li><a href="pricing.html">Pricing</a> </li> </ul> </div> <div id="info" class="boxed"> <h2 class="heading">Info</h2> <ul> <li><a href="tips-and-tricks.html">Tips and tricks</a> </li> <li><a href="useful-links.html">Useful links</a> </li> <li><a href="faq.html">Frequently asked questions</a> </li> <li><a href="site-map.html">Site map</a> </li> </ul> </div> <div id="contact" class="boxed"> <h2 class="heading">Contact</h2> <ul> <li><a href= "mailto:enquiries&#64;X.co.uk">Contact by email</a> </li> <li><strong>Telephone:<br />X</strong> </li> </ul> </div> </div> <div id="mainfooter"> <p> &#169; 2011 X<br />Designed by <a href="http://www.X.co.uk/" title="X"><strong>X</strong></a> </p> <a href="http://validator.w3.org/check?uri=referer" title="Valid XHTML 1.0"> <img style="border:0;width:88px;height:31px" src="images/valid-xhtml10.png" alt="Valid XHTML 1.0" /> </a> <a href="http://jigsaw.w3.org/css-validator/check/referer" title="Valid CSS!"> <img style="border:0;width:88px;height:31px" src="images/vcss.gif" alt="Valid CSS!" /> </a> </div> </body> </html> <?php exit(); } ?> Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/ Share on other sites More sharing options...
xyph Posted May 6, 2011 Share Posted May 6, 2011 Generally, the idea of captcha is to prevent automated form processing. Any non-image comparisons will be easily solved. Regardless, I would use sessions to solve this issue. Simply store the expected result in a session variable on the first page, and make sure it matches on the second page1.php: <?php session_start(); $digit1 = mt_rand(1,20); $digit2 = mt_rand(1,20); if( mt_rand(0,1) === 1 ) { $math = "$digit1 + $digit2"; $_SESSION['answer'] = $digit1 + $digit2; } else { $math = "$digit1 - $digit2"; $_SESSION['answer'] = $digit1 - $digit2; } ?> <form method="POST" action="page2.php"> What's <?php echo $math; ?> = <input name="answer" type="text" /><br /> <input type="submit" /> </form> page2.php <?php session_start(); echo "You entered ".htmlentities($_POST['answer'])." which is "; if ($_SESSION['answer'] == $_POST['answer'] ) echo 'correct'; else echo 'wrong. We expected '.$_SESSION['answer']; ?> Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1211678 Share on other sites More sharing options...
Ramjam Posted May 7, 2011 Author Share Posted May 7, 2011 To xyph: Thank you - everything is working perfectly! I compliment you on your elegant and concise code; exactly what I was hoping for. Your clear explanation helped me to see where I had been going wrong & you have saved me a page of code; my own clumsy solution had 3 pages whereas yours only needs 2. I agree with your observation re non-image code, but many of my site visitors are unable to decipher visual captchas & I reckon this dynamic maths captcha will surely confound my former spammers. Mods - case closed! - please mark this one as Solved. Excellent forum. All the best. Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1212082 Share on other sites More sharing options...
PFMaBiSmAd Posted May 7, 2011 Share Posted May 7, 2011 I reckon this dynamic maths captcha will surely confound my former spammers. Unlikely, as it only takes a few lines of php code to automate the solving of your text based math problem, i.e. scrape the string out of the form page, solve the math using an eval() statement, submit to your form processing page. However, if you output the whole math question ON an image, and use randomly worded questions with random values in them, it will become much more difficult for an automated script to solve this as it must first do OCR to even read the math question. Typical image captchas have 4-8 characters or a word or two to read and input. Doing the OCR to read a smaller number of characters is going to be more accurate than reading a larger number of characters, symbols, and numbers. If you output the whole math question with several words, numbers, and number names in it, just getting the OCR to accurately return all the words to even parse by a script will thwart all but a dedicated spammer. Also, you need to clear the $_SESSION variable after you successfully test it in the form processing code so that someone cannot enter the correct answer once and repeatedly submit to the form processing code and you need to check if the $_SESSION variable is NOT empty, because an empty session variable will be equal to an empty post variable every time. Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1212084 Share on other sites More sharing options...
xyph Posted May 8, 2011 Share Posted May 8, 2011 PFMaBiSmAd is correct as usual. I didn't include checks in my script, nor warn you about them in my post. Definitely make sure the session variable is defined, and clear it after the comparison. if ( isset($_SESSION['answer']) && $_SESSION['answer'] == $_POST['answer'] ) echo 'correct'; else echo 'wrong. We expected '.$_SESSION['answer']; unset($_SESSION['answer']); Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1212148 Share on other sites More sharing options...
Ramjam Posted May 8, 2011 Author Share Posted May 8, 2011 xyph, PFMaBiSmAd - Thanks to you both for the additional caveats. I'm on the case! All the best & keep up the good work. Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1212319 Share on other sites More sharing options...
Ramjam Posted May 10, 2011 Author Share Posted May 10, 2011 Hello again everyone. Update: The form is working nicely, and I've even had some incoming enquiries! The Session checks are doing their job well. A final tweak: I've currently got a few effective rules to sanitise the input and throw up appropriate error messages such as "Add your message title" or "Invalid email format", with the math captcha result message being generated independently. So the effect is: Once the form has been filled out correctly, the captcha result (either 'correct' or 'incorrect') is displayed as discussed. That's fine, but is there a simple way to make the captcha itself a rule so that it thows up an error message similarly to the other rules? Eg the email rule: /* Check all form inputs using check_input function */ ... $email = check_input($_POST['email']); ... /* If e-mail is not valid show error message */ if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/", $email)) { show_error("Email address is not valid."); } ... /* Functions used */ function check_input($data, $problem='') { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); if ($problem && strlen($data) == 0) { show_error($problem); } return $data; } function show_error($myError) Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1213305 Share on other sites More sharing options...
xyph Posted May 11, 2011 Share Posted May 11, 2011 if ( !isset($_SESSION['answer']) || $_SESSION['answer'] != $_POST['answer'] ) { show_error("Math Captcha Incorrect."); } Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1213893 Share on other sites More sharing options...
Ramjam Posted May 11, 2011 Author Share Posted May 11, 2011 Perfecto! Thanks again, xyph - job done. Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1214012 Share on other sites More sharing options...
sams1 Posted December 3, 2012 Share Posted December 3, 2012 (edited) Hi, I am using the script as posted by xyph. One moment the script is working absolutely fine although after a few hours of being uploaded to my webserver, on submitting the form, it says "Math Captcha Incorrect" even though it isn't incorrect. Can anyone explain why this might be occuring? I did have to modify the code slightly so that it follows through with my PHP form submission setup. The only way to get it working properly again is to delete the files from the webserver and reupload them. This is obviously causing users an inconvenience when they submit data through one of the forms, not just myself! <?php session_start(); if (!isset($_SESSION['answer']) || $_SESSION['answer'] != $_POST['answer'] ) { exit("<b><center>Math Captcha Incorrect. Please <a href='Javascript:history.go(-1)'>Go Back</a> and try again</center></b>"); } if (!$_POST['email']) { exit("<b><center>You did not supply an E-Mail address. We need this to reply to your E-Mails.<br /><br /><a href='Javascript:history.go(-1)'> < Go Back</a></center></b>"); } Thanks in advance! Edited December 3, 2012 by sams1 Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1397212 Share on other sites More sharing options...
mrMarcus Posted December 4, 2012 Share Posted December 4, 2012 (edited) Hi, I am using the script as posted by xyph. One moment the script is working absolutely fine although after a few hours of being uploaded to my webserver, on submitting the form, it says "Math Captcha Incorrect" even though it isn't incorrect. Can anyone explain why this might be occuring? I did have to modify the code slightly so that it follows through with my PHP form submission setup. The only way to get it working properly again is to delete the files from the webserver and reupload them. This is obviously causing users an inconvenience when they submit data through one of the forms, not just myself! session_start(); if (!isset($_SESSION['answer']) || $_SESSION['answer'] != $_POST['answer'] ) { exit("<b><center>Math Captcha Incorrect. Please <a href='Javascript:history.go(-1)'>Go Back</a> and try again</center></b>"); } if (!$_POST['email']) { exit("<b><center>You did not supply an E-Mail address. We need this to reply to your E-Mails.<br /><br /><a href='Javascript:history.go(-1)'> < Go Back</a></center></b>"); } Thanks in advance! People hate CAPTCHA's. They are annoying and slow down a process. On top of that, captcha's can be bypassed now by spam-bots. For beating bots, you can try some simple, yet highly effective, tactics. First, you need to understand the mindset of a bot: 1. Its all about spamming as many forms on as many sites as quickly as possible. The bot hits your site, locates any/all forms, and goes to work autopopulating any/all fields it can find. All of this within seconds (at most; and depending on how fast your HTML is rendered). Keeping that in mind, using a timer within the page/form to detect how quickly your form was submitted from time of page load is highly effective (actually, since I have implemented this tactic on several of my sites, all spam activity has been eliminated 100%). session_start(); $_SESSION['start_time'] = time(); if (isset($_POST['submit'])) { if (ctype_digit($_POST['start_time'])) { $now = time(); $seconds = 5; // this is the number of minimum seconds that must pass before the user can submit the form; change to whatever value is appropriate for your form, ie. if it takes approx 60 seconds to fill out your form, then increase this number accordingly. Remember that a bot will fill out the form as quickly as possible (talking near instantly) if (($_POST['start_time'] - $now) < $seconds) { // form submitted too quickly; do not allow processing } else { // OK; continue with processing } } else { // bot changed value of 'start_time'; stop processing } } <form action="" method="post"> <input type="hidden" name="start_time" value="<?php echo $_SESSION['start_time']; ?>"/> ... </form> 2. Bots will typically attempt to fill out any and all form inputs/textareas, etc. You can place a hidden <textarea name="info" style="display:none"></textarea> within your form to attract bots. Then, within your processing code, check to see if there is a value within this textarea. Since it is hidden to the user, there should be no value. If there is, then you know it was a bot that entered that value. Now, there are certain e-readers and such that might display this hidden field (devices for the visually impaired that will read all inputs out to the user), so you will want to ensure they don't get caught in a loop hole with text advising them not to enter any values within that box should it be made available to them. Edited December 4, 2012 by mrMarcus Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1397557 Share on other sites More sharing options...
mrMarcus Posted December 4, 2012 Share Posted December 4, 2012 Noticed typo in my code above... This line: if (($_POST['start_time'] - $now) < $seconds) { Should be: if (($now - $_POST['start_time']) < $seconds) { And: if (isset($_POST['submit'])) { Is relying on a submit button/input field with the name "submit". Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1397584 Share on other sites More sharing options...
mds1256 Posted April 5, 2013 Share Posted April 5, 2013 Hi Sorry to drag this topic up again, but a question regarding the below solution (which is quite a neat little trick!), however how does this work on the rare occasion when the clocks go forward / backwards? How does the below solution handle this, surely it will fail..... how can we get around this as I would really like to use this solution. Thanks session_start(); $_SESSION['start_time'] = time(); if (isset($_POST['submit'])) { if (ctype_digit($_POST['start_time'])) { $now = time(); $seconds = 5; // this is the number of minimum seconds that must pass before the user can submit the form; change to whatever value is appropriate for your form, ie. if it takes approx 60 seconds to fill out your form, then increase this number accordingly. Remember that a bot will fill out the form as quickly as possible (talking near instantly) if (($_POST['start_time'] - $now) < $seconds) { // form submitted too quickly; do not allow processing } else { // OK; continue with processing } } else { // bot changed value of 'start_time'; stop processing } } <form action="" method="post"> <input type="hidden" name="start_time" value="<?php echo $_SESSION['start_time']; ?>"/> ... </form> 2. Bots will typically attempt to fill out any and all form inputs/textareas, etc. You can place a hidden <textarea name="info" style="display:none"></textarea> within your form to attract bots. Then, within your processing code, check to see if there is a value within this textarea. Since it is hidden to the user, there should be no value. If there is, then you know it was a bot that entered that value.Now, there are certain e-readers and such that might display this hidden field (devices for the visually impaired that will read all inputs out to the user), so you will want to ensure they don't get caught in a loop hole with text advising them not to enter any values within that box should it be made available to them. Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1423060 Share on other sites More sharing options...
Jessica Posted April 5, 2013 Share Posted April 5, 2013 (edited) The unix timestamp will not go back or forward when the clocks change. Did you look at the time function? Edited April 5, 2013 by Jessica Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1423066 Share on other sites More sharing options...
mds1256 Posted April 5, 2013 Share Posted April 5, 2013 I see I didnt realise the time function was unix time stamp. Thanks for the quick answer. The unix timestamp will not go back or forward when the clocks change. Did you look at the time function? Quote Link to comment https://forums.phpfreaks.com/topic/235697-contact-form-with-math-captcha/#findComment-1423075 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.