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

Yes! That sounds great :cool:

But since your time is valuable, and the Yahoo system is a little weird, let’s still first test that a PHP program can actually get the Yahoo emailing system to work. After that we will add in the validation parts.

I have temporarily removed the 6+6 question from my Contact Form and replaced it with a simple Send button. You can see all the current code here: http://www.easydigging.com/Contact/contact_us.html

Just let me know what I need to change in the form to make it talk to the PHP program. And of course we need a PHP program that talks to Yahoo.

When you post the PHP code, please just make the HTTP address have all the x’s like this: “http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxxx” I’ll add in the real login info. We don’t want the email bots picking up my entry code from these posts :eek:

What I do on my sites and seems to work perfect is just ask a basic question of 2 + 2 =. I don’t randomize it or anything. On the client side and php back end side they have to answer 4 to post.

Here is what I use for the spam question on the php side


// Spam Question
if ($spam == 4){
    // success, continue processing
}
else{
    header( "Location: $errorurl" );
	exit ;
}

Thread moved to the PHP forum as this is now moving on to a (more appropriate) PHP script to deal with the captcha issue by solving a simple math puzzle.

I found just asking people to enter a specific value into a field is quite effective against most spambots.

So, I’ve made a trial script which works fine on my servers.
Here it is:

<?php 
$url = "http://us.1.p10.webhosting.yahoo.com/forms?login=xxx";  
$post_data = array (  
    "person" => "Pullo",  
    "onlineaddress" => "pullo@gmail.com",  
    "ringer" => "12345678",  
    "action" => "Submit"  
);  
$ch = curl_init();  
curl_setopt($ch, CURLOPT_URL, $url);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
curl_setopt($ch, CURLOPT_POST, 1);  
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);  
curl_exec($ch);  
curl_close($ch);  
?>

What you need to do is to create a blank PHP file on your PC and name it “test.php”
Copy the above code into this file.
Change the url in the first line accordingly.
Upload the PHP file to your webserver.
Access the file in your browser by navigating to address you uploaded it to (e.g. http://easydigging.com/Contact/test.php).

If everything is good, shortly afterwards you’ll receive a mail from me.

Let me know how you get on.

It works!
:smiley:
The only thing it did not do was bring up the Confirmation page after sending. What it does bring up is a blank page with the same URL as the PHP test file.

Here is what messages from my current Contact Form look like:

reporting = test from live page
with big plain button
person = Greg Baka
onlineaddress = hope@fird.com
ringer = 789-564-2540
country = Canada
REMOTE_HOST: 72.xxx.xxx.92

And here is what a message from the PHP file looks like: (I added a message to see if that would make it be a “success”)

reporting = adding a little to the message to trigger the confirm
person = Pullo
onlineaddress = pullo@test.com
ringer = 12345678
action = Submit
REMOTE_HOST: 74.xxx.xxx.184

The messages have different REMOTE_HOST numbers, but all the old Contact Form messages in my Inbox have different ones. So that is probably OK.

Your PHP message did have “action = Submit” which mine doesn’t. I experimented with removing that line. The email transmitted fine, but it still didn’t trigger the Confirmation page.

So how about this for the next step: Change the Contact Form just a little so the big SEND button triggers the PHP program? I guess the little PHP program will also need to be changed to transmit the form info.

Thank you very much

Here is roughly the same script I use. Just add the spam question stuff I posted earlier directly above $message = near the bottom. http://www.visibilityinherit.com/code/php-form-validation.php

Yay!

This is entirely correct. I didn’t want to put any effort into fleshing this out if Yahoo blocked it or didn’t have the cURL library installed.
Like we discussed, this was just a bare bones example.

REMOTE_HOST is probably the IP address of the sender or similar. These are meant to be different.

No drama, just remove it. As long as the email still fires, that’s fine.

Well, seeing as we know that it works, I’ll change your form to incorporate a simple spam question, then post the altered code later on today. It won’t take long to get working now :slight_smile:

Thanks Eric, I’ll look into that as a next step.

I found felgall’s suggestion of setting a timer on the form—made in a thread not so long ago—quite inspiring, so I experimented with it and came up with a pretty simple solution (which is all I can come up with anyway). It basically consists of this in the HTML:

<input type="hidden" name="loadtime" value="<?php echo time(); ?>">

and then this in the processing script:

$loadtime = $_POST["loadtime"];

$totaltime = time() - $loadtime;

if($totaltime < 7) {
   echo("Please fill in the form before submitting!");
   exit;
}

Works well for me, anyhow. I’ve just written a bit more about it here, with an example.

Hi Ralph,

Thanks for that.
I’ve just read your post and bookmarked it. I can imagine coming back to that at a future date.

As I’ve understood the situation here however, the OP has to submit his form to a predefined address if he wants to use it to send mail, thus giving him no room to implement any checks of his own.
My idea was to crowbar a PHP script between the form and the predefined address, then if everything is good to use the cURL library to forward all of the submitted data accordingly.

I’ll leave it up to the OP to decide which anti-spam method to use.

Hi Greg,

So here is the reworked code.

This is your contact form:

<form id="edf" method="post" autocomplete="off" action="myScript.php" >
  <fieldset>
    <legend> Contact Form </legend>
    <p> We never sell or share your information. </p>		
    
    <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">
    
    <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>

I have tidied it up a little by adding for attributes to the labels.
This means that when someone clicks on the label text, focus is transfered to the corresponding form element.
I have also put quotation marks around the in-line style declarations, e.g. style=[B]"[/B]text-align:center;[B]"[/B]

Now myScript.php. This needs to be in the same folder as the contact form.

<?php 
$quiz = $_POST['quiz'];
if ($quiz != 12){
  echo "The anti-spam question was wrong.<br />Please press the back button in your browser and try again";
  exit();
}

$url = "http://us.1.p10.webhosting.yahoo.com/forms?login=xxx";  
$post_data = array (  
    "person" => $_POST['person'],  
    "onlineaddress" => $_POST['onlineaddress'],  
    "ringer" => $_POST['ringer']  
);  
$ch = curl_init();  
curl_setopt($ch, CURLOPT_URL, $url);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
curl_setopt($ch, CURLOPT_POST, 1);  
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);  
curl_exec($ch);  
curl_close($ch); 

//It's all good brother. POST data submitted, let's redirect!
header('Location: http://easydigging.com/thankyou.html');  
?>

This is the same as before with the addition that the spam check now works and upon successful completion, the script redirects to “http://easydigging.com/thankyou.html”, which you’ll presumably have to create.

Let me know how you get on.

It all works :slight_smile: except the confirmation page :confused:

When 12 is NOT used for the answer, it does not send an email but instead displays a bright whight page with the error message.

When 12 is used for the answer, it sends an email but displays a blank page (the URL is that of the PHP file)

So it appears we just need to fix the Confirmation page redirect.

I modified both codes a bit to include missing fields and for visual appearance. You can see the test page here: http://easydigging.com/Contact/contact_test.html

Here is the code:

HTML

<form id="edf" method="post" autocomplete="off" action="pullo.php" >
     <fieldset>

	 <div class="form-actions" >
		 <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 provide a good email or phone number.
		 </span>
		
		 <label for="person">Name</label>
         <input class="input-block-level" type="text"
             name="person" id="person" onkeypress="return event.keyCode != 13;">
	
		 <label for="onlineaddress">Email</label>
         <input class="input-block-level" type="text"
	         name="onlineaddress" id="onlineaddress" onkeypress="return event.keyCode != 13;">
	
	     <label for="ringer">Phone Number</label>
         <input class="input-block-level" type="text"
	         name="ringer" id="ringer" onkeypress="return event.keyCode != 13;">
		
		 <label for="country">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="country" id="country" onkeypress="return event.keyCode != 13;">

	     <div  style=text-align:center;>
             <label for="checker">
             <strong>To prevent automated emails, you must answer this question:</strong><br />
                     What is 6 + 6 ?
             </label>	
             <input class="input-mini" type="text" name="checker" id="checker" >
             <p> &nbsp; </p>
             <button class="btn btn-large btn-primary" type="submit">&nbsp; Send Message &nbsp;</button>
             <p> &nbsp; </p>
		 </div>
     </div>
		
     </fieldset>
</form>

PHP

<?php
$checker = $_POST['checker'];
if ($checker != 12){
  echo "The automated email prevention question was wrong.<br />Please press the <b>BACK</b> button in your browser and try again.";
  exit();
}

$url = "http://us.1.p10.webhosting.yahoo.com/forms?login=xxxxx";
$post_data = array (
    "person" => $_POST['person'],
    "onlineaddress" => $_POST['onlineaddress'],
    "ringer" => $_POST['ringer'],
    "country" => $_POST['country'],
    "reporting" => $_POST['reporting']  	
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_exec($ch);
curl_close($ch);

//It's all good brother. POST data submitted, let's redirect!
header("http://easydigging.com/Contact/confirmcontact.html");
?> 

I did experiment with the header at the end of the PHP file. I tried both ‘http…’ and “http…” neither worked and neither broke the program. I also tried appending &confirm=http… to the end of the email submittal URL (which is what my current simple form does) but that DID break the program (no emails, no confirmation page).

Any ideas on how to fix the Confirmation page thing?

Try this instead (note the Location):

header('Location: http://easydigging.com/Contact/confirmcontact.html');

Any joy?

Edit: looking at my code, this was what I recommended in the first place.
It should work.

That fixed it :cool:

I thought that the word Location: was a comment telling me to put the URL there :blush:

Here is what an email from the new form looks like:

person = Greg
onlineaddress = test8@testing123.com
ringer = 789-789-7899
country = Atlantis
reporting = changed header to include \"Location: \"
REMOTE_HOST: 74.6.53.181

The messages do not display symbols like " and &. Any thoughts on how to let them transmit?

Also I am curious why you changed style commands from style=text-align:center; -to- style=“text-align:center;” ?
Notepad++ doesn’t seem to like the " in styles.

Hi Greg,

Try this:

$post_data = array (   
    "person" => html_entity_decode($_POST['person']),   
    "onlineaddress" => html_entity_decode($_POST['onlineaddress']),   
    "ringer" => html_entity_decode($_POST['ringer']), 
    "country" => html_entity_decode($_POST['country']), 
    "reporting" => html_entity_decode($_POST['reporting'])       
);

Any joy?

I’ll try the html_entity_decode in a second.

Is there any way to make the Error message display in Large text (text is virtually unreadable on a small device), or have the user go to my own error page? Sending them to my own error page would be great :slight_smile:

I would probably send them to a custom error page.
Just do it with this:

if ($checker != 12){ 
  header('Location: http://easydigging.com/ohdear.html');  
}

Oh! That was just how I learnt it and what I have seen from virtually every web page on the net.
If you’re not sure, try validating a simple page with a random element with this in-line style style=color:black and another random element with this in-line style style="color:black".
If the validator don’t complain, then take your pick.

http://jigsaw.w3.org/css-validator/

Edit:
Also when you hit the back button in the case of an error, everything which had been entered into the form vanishes.
I would change this.

The html_entity_decode does not seem to work. At least not for " and &. Here is a test message I sent:

person = Yosemite Sam
onlineaddress = test9@testing123.com
ringer = 456-456-1234
country = Looney Tunes Land
reporting = Angry words:
#*&^ )^% &% ^_&% \"+&@~
:slight_smile:

But I can live with it if just " and & :wink:

Inline Style commands:
…well that explains why I was never able to put multiple rules after a single style= :blush:

Now to try the Error Page!

The Error page change broke the program. :frowning:

Now when I put in an incorrect answer, it sends the message AND takes me to the confirmation page.

I’m guessing we are just missing a bit of puncuation somewhere?

Here is the current code:

<?php
$checker = $_POST['checker'];
if ($checker != 12){
  header('Location: http://easydigging.com/Contact/contacterror.html');
}

$url = "http://us.1.p10.webhosting.yahoo.com/forms?login=xxxx";
$post_data = array (
    "person" => $_POST['person'],
    "onlineaddress" => $_POST['onlineaddress'],
    "ringer" => html_entity_decode($_POST['ringer']),
    "country" => $_POST['country'],
    "reporting" => html_entity_decode($_POST['reporting']) 	
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_exec($ch);
curl_close($ch);

//It's all good brother. POST data submitted, let's redirect!
header('Location: http://easydigging.com/Contact/confirmcontact.html');
?>