Link to home
Start Free TrialLog in
Avatar of ddantes
ddantesFlag for United States of America

asked on

Using PHP to submit a contact form only if a field is left empty

The contact form on my website has been abused by spam bots.  I'd like to try a captcha method, referred to as "honeypot", which presents an invisible text field that "tempts" a spam bot to populate it.  If the text field is filled in, the form will not be submitted, but a phoney acknowledgment page will appear.  If the text field is left blank, the form will be submitted, and an authentic acknowledgment page will appear.    The contact form has a section, styled "display:none" which asks the visitor to solve a simple arithmetic problem, and type the answer into a text field.  That field is named "captcha".

Below is php code for the contact form handler.  I'd appreciate help with adding code to detect whether the "captcha" field has been populated.  If it has been populated, the form should not really be submitted, but the visitor's browser should load a page which looks like an acknowledgment.  If the captcha field has been left blank, the form should be submitted, and the "thanyou.htm" page should load.


<?php 
$errors = '';
$myemail = 'stay@mauitradewinds.com';//<-----Put Your email address here.
if(empty($_POST['firstname'])  || 
   empty($_POST['lastname'])  ||
   empty($_POST['email']) || 
   empty($_POST['message']))
{
    $errors .= "\n Error: At a minimum, we need your name, Email address and message in order to transmit your form.";
}
else
{
    $firstname = array_key_exists('firstname',$_POST) ? $_POST['firstname']:''; 
    $lastname = array_key_exists('lastname',$_POST) ? $_POST['lastname']:''; 
    $Address = array_key_exists('Address',$_POST) ? $_POST['Address']:''; 
    $City = array_key_exists('City',$_POST) ? $_POST['City']:''; 
    $State = array_key_exists('State',$_POST) ? $_POST['State']:''; 
    $Zip = array_key_exists('Zip',$_POST) ? $_POST['Zip']:''; 
    $Country = array_key_exists('Country',$_POST) ? $_POST['Country']:''; 
    $Phone = array_key_exists('Phone',$_POST) ? $_POST['Phone']:''; 
    $email_address = array_key_exists('email',$_POST) ? $_POST['email']:''; 
    $message = array_key_exists('message',$_POST) ? $_POST['message']:''; 
    
    if (!preg_match(
    '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i', 
    $email_address))
    {
        $errors .= "\n Error: Invalid email address";
    }
}

if( empty($errors))
{
	$to = $myemail; 
	$email_subject = "Contact form";
	$email_body = "You have received a contact form from Site-1. ".
	" Here are the details:\n First Name: $firstname \n Last Name: $lastname \n Address: $Address \n City: $City \n State: $State \n Zip: $Zip \n Country: $Country \n Phone: $Phone \n Email: $email_address \n Message: $message \n captcha: $captcha"; 
	
	$headers = "From: $myemail\n"; 
	$headers .= "Reply-To: $email_address";
	
	mail($to,$email_subject,$email_body,$headers);
	//redirect to the 'thank you' page
	header('Location: thankyou.htm');
	exit;//You should always "exit" immediately after a redirection request
} 
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>
<head>
	<title>Contact form handler</title>
</head>

<body>
<!-- This page is displayed only if there is some error -->
<?php
echo nl2br($errors);
?>


</body>
</html>

Open in new window

Avatar of Dave Baldwin
Dave Baldwin
Flag of United States of America image

If it's a text field, it will always be submitted.  You check to see if it is not blank.  I would do that first.  Something like this and I would Not name it 'captcha' because that could cause someone to look at it and pay attention to what you're trying to do.
if($_POST['name2'] != '') //show fake display and exit.

Open in new window

Avatar of ddantes

ASKER

Thank you.  I'm unsure about a couple of things.  If the form will always be submitted, then this approach is not useful.  But it seems, if the field is not blank, then the form won't be submitted, because a fake form will appear, and the program will exit, correct?   If that's correct, could you supply the code for loading the fake form?   I'll use a different name for the "honeypot" field -- not "captcha".
You're not understanding.  The form is Always submitted to the PHP page.  The idea is to check the 'honeypot' field first and if they filled it in, put up the 'fake thank you' page and exit without sending it to the database or email.

As Gary pointed out in your previous question, there are people paying people to fill in forms now.  None of these methods prevent that.  'captcha' and 'honeypot' only work against automated spam that can't see what's going on.
Avatar of ddantes

ASKER

OK.  I was misusing the term "submit".  I understand that the form will always be submitted to the PHP page,  The objective is to serve the fake thank you page and exit, if the honeypot field is popupated.

So, to complete my understanding, after this:
if($_POST['name2'] != '') //show fake display and exit.

what code is required to actually show the fake display and exit?
If nothing else, you can do a 'header' redirect to a plain HTML page.  See the examples here: http://us1.php.net/manual/en/function.header.php
Avatar of ddantes

ASKER

OK.  So, the code would look like this?

<?php 
$errors = '';
$myemail = 'stay@mauitradewinds.com';//<-----Put Your email address here.
if(empty($_POST['firstname'])  || 
   empty($_POST['lastname'])  ||
   empty($_POST['email']) || 
   empty($_POST['message']))
{
$errors .= "\n Error: At a minimum, we need your name, Email address and message in order to transmit your form.";
}
else
{
    $firstname = array_key_exists('firstname',$_POST) ? $_POST['firstname']:''; 
    $lastname = array_key_exists('lastname',$_POST) ? $_POST['lastname']:''; 
    $Address = array_key_exists('Address',$_POST) ? $_POST['Address']:''; 
    $City = array_key_exists('City',$_POST) ? $_POST['City']:''; 
    $State = array_key_exists('State',$_POST) ? $_POST['State']:''; 
    $Zip = array_key_exists('Zip',$_POST) ? $_POST['Zip']:''; 
    $Country = array_key_exists('Country',$_POST) ? $_POST['Country']:''; 
    $Phone = array_key_exists('Phone',$_POST) ? $_POST['Phone']:''; 
    $email_address = array_key_exists('email',$_POST) ? $_POST['email']:''; 
    $message = array_key_exists('message',$_POST) ? $_POST['message']:''; 
    if($_POST['name2'] != '') //show fake display and exit.
    header("Location: http://www.fake.com/"); /* Redirect to fake thankyou page */
    exit;
}
else
{
    if (!preg_match(
    '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i', 
    $email_address))
    {
        $errors .= "\n Error: Invalid email address";
    }
}

if( empty($errors))
{
	$to = $myemail; 
	$email_subject = "Contact form";
	$email_body = "You have received a contact form from Site-1. ".
	" Here are the details:\n First Name: $firstname \n Last Name: $lastname \n Address: $Address \n City: $City \n State: $State \n Zip: $Zip \n Country: $Country \n Phone: $Phone \n Email: $email_address \n Message: $message \n captcha: $captcha"; 
	
	$headers = "From: $myemail\n"; 
	$headers .= "Reply-To: $email_address";
	
	mail($to,$email_subject,$email_body,$headers);
	//redirect to the 'thank you' page
	header('Location: thankyou.htm');
	exit;//You should always "exit" immediately after a redirection request
} 
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>
<head>
	<title>Contact form handler</title>
</head>

<body>
<!-- This page is displayed only if there is some error -->
<?php
echo nl2br($errors);
?>


</body>
</html>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Dave Baldwin
Dave Baldwin
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
the form will not be submitted, but a phoney acknowledgment page will appear
Don't bother.  The 'bot won't care and it's just more work for your server.  Instead test the fake field (named zipcode in this example) like this:

<?php if (!empty($_POST['zipcode'])) die();
/* REST OF NORMAL SCRIPT HERE... */

Open in new window

Regarding the code snippet above, there are some things you might want to "upgrade."

Learn about PHP coding standards and use them, always.

Learn about PHP filter_var() and get rid of regular expressions that you do not understand.  This one appears to be copied from some old, obsolete source on the internet.

Don't write a redirect.  It makes your original script nearly impossible to debug.  Instead build the "thank you" page into the action script right after the mail is sent.
Don't write a redirect.
I don't agree with that.  If you redirect from the PHP page to a 'thank you' page, users can 'refresh' the thank you page all day without affecting the database.  And they do.  For no reason what so ever.  

And I have one client that insists that I do that.  She doesn't want people to see 'php' in the address bar if she can help it.  Just 'html'.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ddantes

ASKER

Thanks to all experts for comments.  We're having a tropical storm here, in Hawaii, with power interruptions every few minutes.  I'll post again when we have the luxury of continuous A.C....
Avatar of ddantes

ASKER

In a perfect world, I would study PHP until I feel competent to write professional-quality code.  I would also debug the code before implementing it.  However, in weighing the importance of this project, versus the time and effort involved in doing it perfectly, I'm willing to make some compromises.  I hope that is understandable.

The 'honeypot' portion of the contact form is named "how".  There is text (styled "display:none"): "How did you learn about Maui Tradewinds?" followed by a text field (also styled "display:none") for entering a response.  The form is at www.mauivacationrental.com/contact.htm

Below is the PHP code, and I'd appreciate correction of any sytax errors.  I plan to revise the contact htm, making the submit button javascript-dependent.   Will this PHP accomplish the stated intention of loading a thankyou page and then exiting, if the "how" field is populated, but proceding with normal function if the "how" field is empty?  


<?php 
if($_POST['how'] != '') {  //show an acknowledgment page and exit.
    header("Location: thankyou.htm/"); /* Redirect to thankyou page */
    exit; }
$errors = '';
$myemail = 'stay@mauitradewinds.com';//<-----Put Your email address here.
if(empty($_POST['firstname'])  || 
   empty($_POST['lastname'])  ||
   empty($_POST['email']) || 
   empty($_POST['message']))
{
    $errors .= "\n Error: At a minimum, we need your name, Email address and message in order to transmit your form.";
}
else
{
    $firstname = array_key_exists('firstname',$_POST) ? $_POST['firstname']:''; 
    $lastname = array_key_exists('lastname',$_POST) ? $_POST['lastname']:''; 
    $Address = array_key_exists('Address',$_POST) ? $_POST['Address']:''; 
    $City = array_key_exists('City',$_POST) ? $_POST['City']:''; 
    $State = array_key_exists('State',$_POST) ? $_POST['State']:''; 
    $Zip = array_key_exists('Zip',$_POST) ? $_POST['Zip']:''; 
    $Country = array_key_exists('Country',$_POST) ? $_POST['Country']:''; 
    $Phone = array_key_exists('Phone',$_POST) ? $_POST['Phone']:''; 
    $email_address = array_key_exists('email',$_POST) ? $_POST['email']:''; 
    $message = array_key_exists('message',$_POST) ? $_POST['message']:''; 
    if (!preg_match(
    '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i', 
    $email_address))
    {
        $errors .= "\n Error: Invalid email address";
    }
}

if( empty($errors))
{
	$to = $myemail; 
	$email_subject = "Contact form";
	$email_body = "You have received a contact form from Site-1. ".
	" Here are the details:\n First Name: $firstname \n Last Name: $lastname \n Address: $Address \n City: $City \n State: $State \n Zip: $Zip \n Country: $Country \n Phone: $Phone \n Email: $email_address \n Message: $message"; 
	
	$headers = "From: $myemail\n"; 
	$headers .= "Reply-To: $email_address";
	
	mail($to,$email_subject,$email_body,$headers);
	//redirect to the 'thank you' page
	header('Location: thankyou.htm');
	exit;//You should always "exit" immediately after a redirection request
} 
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>
<head>
	<title>Contact form handler</title>
</head>

<body>
<!-- This page is displayed only if there is some error -->
<?php
echo nl2br($errors);
?>


</body>
</html>

Open in new window

The first four lines may be correct.  Not sure about the trailing slash on the URL in the header("Location...").  I would not do this part about displaying a page at all.  Instead I would use this:

<?php 
if(trim($_POST['how']) != '') 
{  
    // SLEEP A MOMENT and exit.
    sleep(4);
    die();
}

Open in new window

Avatar of ddantes

ASKER

Thank you.  Is there any way to test this?
Sure, make a test page copy of the regular page that doesn't hide the 'how' field and text and fill it it to see if it does what you want.
Avatar of ddantes

ASKER

Sorry for a stupid question.  It works just as I had hoped.  Before closing this question, I'm still wondering about not redirecting to an acknowledgment page.  I would think, if a spambot engineer employed a human visitor to test the form, it might be preferable to give the impression the form was transmitted successfully.   Your thoughts?
On most of my form pages, I just let them die if there is something wrong when they are submitted.  I was thinking that you didn't want to show a human a bad result...  but a human visitor isn't going to fill it out 'wrong' so I'm not sure that it matters.
Avatar of ddantes

ASKER

Thanks everyone!
Avatar of ddantes

ASKER

Gary:  In another question https://www.experts-exchange.com/questions/28480066/Activate-a-disabled-button-with-javascript.html   an Expert tells me that bots don't use the Submit button, so there's no point in disabling it.  I did disable it, based on your comment ID: 40207422, but I'd like to verify whether that is actually useful.  Thanks!
Like I said in that comment usually they don't visit the page and for the ones that do it will block them and even maybe make them think there is nothing to submit if they are harvesting forms.
It's just another tactic.
No matter what you do you will always be 2 steps behind the spammers.
Avatar of ddantes

ASKER

Understood.  Thanks again.
Upon rereading this question, I realize I should have posted a link to this article.  Sorry - not thinking...
https://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_9849-Making-CAPTCHA-Friendlier-with-PHP-Image-Manipulation.html
Avatar of ddantes

ASKER

Thanks, Ray.  I ended up using a combination of the "honeypot" method, along with a disabled
"Submit" button which requires javascript to activate.  There have been no instances of spambot submission of our contact forms since these were implemented.