Simple PHP math captcha to minimize bots sending you junky emails?

We have built a responsive site using Twitter Bootstap, only to find that off-the-shelf Contact Forms don’t work so well with responsive designs :mad:

I also discovered that all webhosting services handle transmitting emails from Contact Forms in different ways. :eek:

I use Yahoo Webhosting (which is great) and for that service your form’s action is a specific URL that processes and emails you the form’s content. Their system is sort of a “closed circuit” that supposedly can only send emails to the address you designate in their Web Hosting Control Panel. So with Yahoo there is no need to take extra steps to prevent your Contact Form from being hijacked (or so they tell me…)

But it has no method of stopping bots from using your own form to send junky emails to you. That’s what I’m hoping you all can help with…

The methods I have discovered are:

  1. turning off autocomplete on the form
  2. using unconventional phrases or random numbers for name=“xx” and id=“xx” ( like “online-address” instead or “email”)
  3. using some sort of question/answer system to make sure they are humans not bots ( like “Which animal barks? Dog or Cat?”)

So on this test page… http://easydigging.com/Contact/Contact-4.html
…I have a Contact Form that is wide open. As long as you put something in at least one of the fields it will transmit an email. (Yes, we are OK with people not filling out all the fields)

I have already done Steps 1 and 2, but really need help with step 3.

Here are some ideas for Step 3. Either would be acceptable. We prefer something easy that works with at most a simple Javascript…

A) the method currently in place is supposed to check for the number 12 (in answer to 6 + 6 = ?), but it doesn’t work. I tried modeling it off the approach in this article: http://alittlecode.com/files/jQuery-Validate-Demo/#html Maybe I screwed up the equalTo part, or just am not calling the JS properly?

B) use a few Radio Buttons with a multiple choice question. Like this article: http://stackoverflow.com/questions/6921680/jquery-quiz-compare-correct-answer-in-array

Either way, we also need to somehow prevent the email from being sent until the answer is correct. I thought of maybe hiding or disabling the Submit button until the correct answer is entered (but have no idea how to do so)
Or even submitting the form as soon as the correct answer is entered (which may work really really simply with the radio button idea if it doubles as a stealth Submit button…)

Any help or ideas is greatly appreciated :slight_smile:

Oops, I guess some copies of the code would help…:lol:

HTML:

<!-- Contact Form -->
<form id="edf" method="post" autocomplete="off" action="http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxxx" >
     <fieldset>
         
		 <legend> Contact Form </legend>
		 <p> We never sell or share your information. </p>		
		 		 
         <label>Message</label>
         <textarea class="input-block-level" rows="3" name="reporting" id="reporting" maxlength="1000">
		 </textarea>
		 
		 <span class="help-block">
		 If you would like us to reply to your message, please enter at least two of the following questions.
		 </span>
		 
		 <label>Name</label>
         <input class="input-block-level" type="text"
             name="person" id="person">
	     
		 <label>Email</label>
         <input class="input-block-level" type="text" 
	         name="onlineaddress" id="onlineaddress">
	
	     <label>Phone Number</label>
         <input class="input-block-level" type="text" 
	         name="ringer" id="ringer">
         
		 <div class="control-group" style=text-align:center; >
	     <label class="control-label" for="checker"><strong>To prevent automated spam, you must answer this question:</strong>
	     <br />What is 6 + 6 ?</label>		 
	         <div class="controls">
		         <input class="input-mini" type="text" name="quiz" id="quiz" >
			 </div>
		 </div>	 
	     <br />
		 <div class="form-actions" style=text-align:center;>
             <button class="btn btn-large btn-primary" type="submit">&nbsp; Send Message &nbsp;</button>
		 </div> 
	 
     </fieldset>
</form>

JAVASCRIPT:

<!-- Scripts for ContactForm -->
    <script src="../assets/js/jquery.validate.js"></script>
	<script>
	$(document).ready(function(){
     
    $('#edf').validate(
    {
    rules: {
    quiz: { equalTo: '12', required: true }
    },
    highlight: function(label) {
    $(label).closest('.control-group').addClass('error');
    },
    success: function(label) {
    label
    .text('OK!').addClass('valid')
    .closest('.control-group').addClass('success');
    }
    });
    }); // end document.ready
	</script> 

 </head>

Special CSS: (much is specific to Twitter Bootstrap)

<style type="text/css">
    label.valid {
    width: 24px;
    height: 24px;
    background: url(../assets/img/Done.png) center center no-repeat;
    display: inline-block;
    text-indent: -9999px;
    }
    label.error {
    font-weight: bold;
    color: red;
    padding: 2px 8px;
    margin-top: 2px;
    }
	</style>


Hi Greg,

Does this suit your needs?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <script src="http://code.jquery.com/jquery-latest.js"></script>

    <link href="http://easydigging.com/assets/css/bootstrap.css" rel="stylesheet">
    <link href="http://easydigging.com/assets/css/bootstrap-responsive.css" rel="stylesheet">
    <link href="http://easydigging.com/assets/css/easydigging.css" rel="stylesheet">
  </head>

  <body>

    <div class="container-fluid">
      <div class="span12">
        <div class="row-fluid">
          <div class="span5">
            <form id="edf" method="post" autocomplete="off" action="http://us.1.p10.webhosting.yahoo.com/forms?login=bakaspecialtiesllc" >
              <fieldset>
                <legend>Contact Form</legend>
                <label for="reporting">Message</label>

                <textarea class="input-block-level" rows="3" name="reporting" id="reporting" maxlength="1000"></textarea>

                <span class="help-block">
                  If you would like us to reply to your message, please enter at least two of the following questions.
                </span>

                <label for="person">Name</label>
                <input class="input-block-level" type="text" name="person" id="person">

                <label for="onlineaddress">Email</label>
                <input class="input-block-level" type="text" name="onlineaddress" id="onlineaddress">

                <label for="ringer">Phone Number</label>
                <input class="input-block-level" type="text" name="ringer" id="ringer">

                <label>Please enter the following number into the field below: <span id="verifyNum"></span></label>
                <input type="hidden" value="701469" id="verifyNumHidden" name="verifyNumHidden" />
                <input type="text" id="enterVerify" name="enterVerify" />

                <button class="btn btn-large btn-primary" type="submit" style="display:block;margin-top:15px;">Send Message</button>
              </fieldset>
            </form>
          </div>	
        </div>
      </div>
    </div>

    <script>
      $(document).ready(function(){
        function randomgen()
        {
          var rannumber='';
          for(ranNum=1; ranNum<=6; ranNum++){
            rannumber+=Math.floor(Math.random()*10).toString();
          }
          $('#verifyNum').html(rannumber);
          $('#verifyNumHidden').val(rannumber);
        }
        randomgen();

        $('#edf').submit(function() {
          if($('#enterVerify').val() != $('#verifyNumHidden').val() ) {
            alert("Please Enter Correct Verification Number");
            randomgen();
            $('#enterVerify').select();
            $('#enterVerify').focus();
            return false;
          }
        });
      });
    </script>
  </body>
</html>

I can’t take all of the credit for this, I found some of the code here: http://asisolve.com/jquery-captcha-anti-spam-without-php-or-server-side-code/

JavaScript cannot solve your form spam problem, because such spam bots don’t have javascript enabled when they submit your form.

The most viable solution for you is to implement some manner of server-side CAPTCHA system, such as http://www.google.com/recaptcha

Evening Paul,

So you are saying that a spam bot comes along, finds a form, and sends a POST request to whatever URL is specified in the action attribute, which contains values relating to whatever fields it found in the form?

And like a user with JavaScript disabled it bypasses any client side checks that may have been put in place.

That is the common situation, yes. And because you want your site to be able to be used by genuine people both with scripting and without (for accessibility reasons), a Completely Automated Public Turing test to tell Computers and Humans Apart (CAPTCHA) is the most standard way to resolve such issues.

OK, thanks.

What do you think of this solution that I heard about somewhere?

On your form, hide one input field using CSS.
When a human comes along, he or she fills out everything except for the hidden field -> all good.

When a bot comes along, it fills out everything including the hidden field and gives itself away as being a bot.

You can then effectively discard any form submissions (on the server side) which have the hidden field filled out, as they were made by a bot.

Yes that’s possible, but ensure that a human is capable of suceesing at that whether they have scripting enabled or not, and also when people have accessibility issues, such as when they’re blind or hard of vision, or have language issues, etc…

Yeah, I’d had this approach in the back of my mind since hearing about it, but there was a bit more to it than what I described.
For example, there was an extra hint for people using screen readers so that they would not get classed as bots.
Maybe this is something that it’s worth Greg looking into?

Remember that a field that is “hidden” from view using CSS may still be “visible” to some genuine visitors so you’d need to tell them to ignore the field.

One idea for telling whether it is a real person who filled out the form would be to have a hidden field in the form that contains the time the page was loaded. After the form is submitted you test if sufficient time elapsed for a person to fill out the form. Many bots would fill out the form too quickly and so could be detected that way.

Pullo and Paul, thanks for the information above. There is an old discussion somewhere on this forum about “honeypots” which are the hidden field “traps” that bots fill in although people never see them.

Pullo, I have not had time yet to try the code you supplied, but I will :slight_smile:

I’ve been having some fun with this by taking a whole different JS-free approach. But from the comments above…

So you are saying that a spam bot comes along, finds a form, and sends a POST request to whatever URL is specified in the action attribute, which contains values relating to whatever fields it found in the form?

…I may not have completely avoided the email bots :frowning:

I used the Option B approach:

B) use a few Radio Buttons with a multiple choice question…

…or even submitting the form as soon as the correct answer is entered (which may work really simply with the radio button idea if it doubles as a stealth Submit button…)

and came up with the Contact Form that is working on this page: http://www.easydigging.com/Contact/contact_us.html

I had to turn off the ENTER key function on the single line entries because hitting ENTER in any of them automatically submitted the form. I used this in the single line “input” code: onkeypress=“return event.keyCode != 13;”

Not sure if I will keep the incorrect buttons as type=“reset” since that may piss off a few customers on small devices that accidently hit the wrong buttons. :rolleyes:

But overall I think it may confuse and avoid a few email bots :stuck_out_tongue: Please share any observations or ideas you may have…

Here is the HTML code (no JS was needed):

<form id="edf" method="post" autocomplete="off" action="http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx" >
         <fieldset>
    		 <legend> Contact Form </legend>
    		 		 		
             <label>Message</label>
             <textarea class="input-block-level" rows="3" name="reporting" id="reporting" maxlength="1000">
    		 </textarea>
    		
    		 <span class="help-block">
    		 If you would like us to reply to your message, please provide a good email or phone number.
    		 </span>
    		
    		 <label>Name</label>
             <input class="input-block-level" type="text"
                 name="person" id="person" onkeypress="return event.keyCode != 13;">
    	
    		 <label>Email</label>
             <input class="input-block-level" type="text"
    	         name="onlineaddress" id="onlineaddress" onkeypress="return event.keyCode != 13;">
    	
    	     <label>Phone Number</label>
             <input class="input-block-level" type="text"
    	         name="ringer" id="ringer" onkeypress="return event.keyCode != 13;">
    		
    		 <label>Country &nbsp; <small class="muted"> If not USA, we can only email or text you.</small>
    		 </label>
             <input class="input-block-level" type="text"
    	         name="ringer" id="ringer" onkeypress="return event.keyCode != 13;">

    		 <div class="form-actions" style=text-align:center; >
    	     <label><strong>Click the <u>right answer</u> button below to send your message.</strong>
    	     <br />What is 6 + 6 ?</label>		
    	         <div class="btn-group" data-toggle="buttons-radio">
                     <button class="btn" type="reset" >&nbsp; 3 &nbsp;</button>
                     <button class="btn" type="reset" >&nbsp; 7 &nbsp;</button>
                     <button class="btn" type="submit" >&nbsp; 12 &nbsp;</button>
    		 <button class="btn" type="reset" >&nbsp; 55 &nbsp;</button>
                 </div>
    		 <span class="help-block">
    		 Clicking the wrong answer will erase everything. This step helps us avoid automated email bots.
    		 </span>
    	     </div>	
         </fieldset>
    </form>

There may be a misunderstanding here. Spam bots don’t click buttons - they just send to where the form is designated to be sent to:

action=“http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx

So in this particular case, you are providing the illusion of more security, without there actually being any at all.

That’s a good idea. I’ll bear that one in mind.

Honeypots! That’s what they were called. Thanx

Please don’t (seriously). Fromn what I’ve learned from Paul (which is actually logical when you think about it), this is just a nice JavScript method to separate your real visitors who can type numbers into a box, from your real visitors who can’t :slight_smile:

Aside from the fact that this will not stop bots, this is not a good idea! If I pressed the wrong button by accident and it wiped everything I’d just typed in (especially if I was an older user), I would not send you a message. In fact, I’d probably be inclined to leave the site. I don’t mean to sound harsh, but it annoys me enough when the “submit” and “reset” buttons are next to each other an I click the wrong one by mistake.

Nonetheless, keep us posted. I would be interested to see your final solution.

It sounds like the only REAL solution is to NOT have this information action=“http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx located anywhere that a bot will find it. True?

So do these emailing bots only look for forms and for pages titled Contact Us, or do they search every file in your webhosting account?

If they search every file in your webhosting account, then there doesn’t seem to be anything you can do except deal with the junky emails.

But if they only look for forms, then a couple of possibilities come to mind…

  1. change the form to have the action=“http://domain.com/non-public/new-page.something” and create /non-public/new-page.something to have a bit of code that sends the form data to “http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx

  2. change the form to use some script (JS or PHP) directly to send the form data to “http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx

Anybody know if the email bots search everything in your webhosting account? If so, I’ll just learn to love the spam…:nono:

That is why systems such as captcha have been created, where information comes from the server, the human enters that information, and the firm plus info gets sent back to the serve for validation.

Recaptcha is one of the more popular ones, because it serves a beneficial public interest too, in helping to transcribe difficult parts from books, and it also deals with many common usability issues.

That’s quite a black or white view. As we’ve been discussing a couple of moderate checks should solve the problem.
It’s just that it makes no sense to do this on the client side.

Who knows? I don’t think anyone could answer this definitively.
It is certainly very easy for a bot to crawl every linked page on your website.

So to summarize:
We have learned that client side validation is useless (this was new for me, too).
You have to submit your form to “http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx” for the mail to work.

Solution:
How about making a PHP script which sits between your form and Yahoo, which has the sole purpose of validating an anti spam question?

You could have:

Form ->
User or bot fills it in and submits it ->
New script checks if anti-spam question ok (you could use felgall’s timestamp idea here) ->
If so it forwards everything (minus the spam question) to yahoo ->
If not it re-renders your original form.

Edit:
Or simply use a captcha, as Paul suggests (I always think in too complicated terms :)).
Here’s a good list of free ones: http://www.saynotes.com/21-free-captcha-sources/

Thanks again to Paul and Pullo :slight_smile:

About CAPTCHA:
If the majority of my customers were 30 or younger, I would just use a generic Contact Form service like wufoo.com that utilizes captcha.
But the majority of my customers are 50 and up - they really don’t like captcha because they have a hard time reading it. That’s why I went looking for a more “bifocal glasses friendly” method like “6+6=?” :wink:

For that reason, I’m hoping we can pursue Pullo’s idea:

How about making a PHP script which sits between your form and Yahoo, which has the sole purpose of validating an anti spam question?
Form ->
User or bot fills it in and submits it ->
New script checks if anti-spam question ok (you could use felgall’s timestamp idea here) ->
If so it forwards everything (minus the spam question) to yahoo ->
If not it re-renders your original form.

But I see problems with:

a) Pullo’s line #3 (User or bot fills it in and submits it) because from what Paul says, the bots do not “fill in the form” - instead they just search out “http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx” and submit their own information to that HTTP address.

b) this piece of line #4: “(you could use felgall’s timestamp idea here)” because of problems noted on a past thread saying that servers doing different parts of the process are located in different time zones making seconds look like hours, or even like negative time {but maybe GMT could be used since it doesn’t vary}

Please share your thoughts?

*in the meantime, I am going to go strip some of the silly things I did back out of my Contact Form :blush:

Hi Greg,

Okay, but a bot cannot read or think as a human can.
So, (discounting the timestamp idea) if you have a few simple questions, like “What colour is grass”, then that’s something that is very easy for a human to answer, but something a bot can only know if it has been programmed to look for this type of question.
In my opinion that would be a sensible middle ground between implementing a CAPTCHA that might present problems to your elderly visitors (I know that my parents can’t handle them and have even asked me for help filling them in in the past) and between you getting bombarded with a load of spam.
Plus the fact, if it doesn’t work and you get lots of mails trying to sell you Viagara, you haven’t really lost anything as you could still look for another solution.

If you want to press forward with this idea, then let me know.

I would like to press forward with the idea of “6+6=?” type question.

Their does seem to be details out there for different ways to check for the correct answer (12) using JS or PHP.

But before we tackle the “how to check” part I think it is really important to figure out where this http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx will be located…

The JavaScript type methods of checking for a correct answer appear to have the http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx right there on the form page - which is not so good.:frowning:

And I don’t know where the PHP type methods of checking for a correct answer locate the http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx part. Can it be in the PHP file?:confused:

If it can be in a PHP file, then I would be really interested in first doing a test to see if we can make the action of my simplest form (no 6+6 checking at all) just be triggering the PHP file that takes the form contents and submits it to http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx

I don’t understand PHP at all yet. But I do know how to uload files to my Yahoo webhosting account and it does allow the running of PHP files. Are you able to create the simple test program to see if we can submit the form indirectly through PHP?

Hi Greg,

The way I imagine such a thing could work (and please someone tell me if I am wrong), would be this.

You have a form, which submits to something like “mysript.php”.
If a bot finds this form, it can’t do anything with it.
“myscript.php” then evaluates the anti spam question.
If it has been answered correctly, it then sends the rest of the data over to “http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx
If it has been answered incorrectly, it simply re-renders the form with a comment that the anti-spam question was wrong.
This of course means that the Yahoo address never appears in plain text on your webpage and is thus protected from spam bots.

Sound good?

Anyone else have any thoughts on this approach?