Solved

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

Posted on 2014-07-19
25
3,545 Views
Last Modified: 2014-10-07
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

0
Comment
Question by:ddantes
  • 11
  • 7
  • 5
  • +1
25 Comments
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
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

0
 

Author Comment

by:ddantes
Comment Utility
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".
0
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
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.
0
 

Author Comment

by:ddantes
Comment Utility
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?
0
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
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
0
 

Author Comment

by:ddantes
Comment Utility
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

0
 
LVL 82

Accepted Solution

by:
Dave Baldwin earned 300 total points
Comment Utility
No.  This should be the first 3 lines on that page (after <?php).
if($_POST['name2'] != '') {  //show fake display and exit.
    header("Location: http://www.fake.com/"); /* Redirect to fake thankyou page */
    exit; }

Open in new window

Actually, I would send them to your regular thankyou page so they can't tell that anything was wrong.
0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
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

0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
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.
0
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
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'.
0
 
LVL 108

Assisted Solution

by:Ray Paseur
Ray Paseur earned 100 total points
Comment Utility
Good point, Dave.  My sense of this question is that the Author has not yet debugged the action script.  In order to get the right debugging information, the action script would need to run, display the data, and stop.  The redirect kind of defeats the ability to see the display of data.  It would make sense to add it back into the script after the debugging is complete.

It's also possible to prevent multiple submissions from updating a data base.  Most modern browsers will warn the client about this.  And a bit of code like this will usually solve the problem.
http://iconoun.com/demo/prevent_multi_submit.php

<?php // prevent_multi_submit.php
error_reporting(E_ALL);

/**
 * PREVENT REPEATED DATA SUBMISSIONS DUE TO BROWSER REFRESH
 * RE-CLICK ON SUBMIT, OR BROWSER BACK BUTTON
 *
 * GET-METHOD REQUESTS SHOULD BE IDEMPOTENT AND (IN THEORY)
 * MUST NOT DISRUPT THE DATA MODEL.  THIS FUNCTION CAN TEST
 * EITHER $_GET OR $_POST REQUEST VARIABLES
 *
 * EXAMPLE:
 *    if ( multi_submit() )
 *    {
 *       handle error
 *    }
 *    else
 *    {
 *       normal processing
 *    }
 */


// ALWAYS START THE PHP SESSION ON EVERY PAGE
session_start();


// A FUNCTION TO RETURN TRUE OR FALSE ABOUT MULTI-SUBMIT CONDITIONS
function multi_submit($type="POST")
{
    // MAKE THE FUNCTION WORK FOR EITHER GET OR POST SUBMITS
    $input_array = (strtoupper($type) == "GET") ? $_GET : $_POST;

    // GATHER THE CONTENTS OF THE SUBMITTED FIELDS AND MAKE A MESSAGE DIGEST
    $string = NULL;
    foreach ($input_array as $val)
    {
        $string .= $val;
    }
    $string = md5($string);

    // IF THE SESSION VARIABLE IS NOT SET THIS IS NOT A MULTI-SUBMIT
    if (!isset($_SESSION["multi_submit"]))
    {
        $_SESSION['multi_submit'] = $string;
        return FALSE;
    }

    // IF THE SESSION DATA MATCHES THE MESSAGE DIGEST THIS IS A MULTI-SUBMIT
    if ($_SESSION['multi_submit'] == $string)
    {
        return TRUE;
    }
    else
    {
        $_SESSION['multi_submit'] = $string;
        return FALSE;
    }
}


// SHOW HOW TO USE THE FUNCTION
if (!empty($_POST))
{
    if (multi_submit())
    {
        echo "ALREADY GOT THAT";
    }
}


// CREATE THE FORM FOR THE DEMONSTRATION
$form = <<<FORM
<form method="post">
ENTER SOMETHING, THEN REENTER IT
<input name="mydata" />
<input type="submit" />
</form>
FORM;

echo $form;

Open in new window

0
 
LVL 58

Assisted Solution

by:Gary
Gary earned 100 total points
Comment Utility
Remember a real bot will not actually visit your page (in most cases) it will just post the data to your site once it knows the form structure.
One way around this type of posting is to use a session, when a visitor visits your site you set a session and check it exists on your contact/post submission page, if it doesn't exist (which it won't for a bot) then block the submission.  The bot won't care what happens it just makes the post and moves on.
Another option is make the submit button disabled, and use javascript to enable it at the client - bots don't (usually) execute javascript so the button will never become available - there are a few different methods using javascript

But nothing is 100% guaranteed to stop spam.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:ddantes
Comment Utility
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....
0
 

Author Comment

by:ddantes
Comment Utility
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

0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
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

0
 

Author Comment

by:ddantes
Comment Utility
Thank you.  Is there any way to test this?
0
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
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.
0
 

Author Comment

by:ddantes
Comment Utility
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?
0
 
LVL 82

Expert Comment

by:Dave Baldwin
Comment Utility
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.
0
 

Author Closing Comment

by:ddantes
Comment Utility
Thanks everyone!
0
 

Author Comment

by:ddantes
Comment Utility
Gary:  In another question http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_28480066.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!
0
 
LVL 58

Expert Comment

by:Gary
Comment Utility
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.
0
 

Author Comment

by:ddantes
Comment Utility
Understood.  Thanks again.
0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
Upon rereading this question, I realize I should have posted a link to this article.  Sorry - not thinking...
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/A_9849-Making-CAPTCHA-Friendlier-with-PHP-Image-Manipulation.html
0
 

Author Comment

by:ddantes
Comment Utility
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.
1

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Part of the Global Positioning System A geocode (https://developers.google.com/maps/documentation/geocoding/) is the major subset of a GPS coordinate (http://en.wikipedia.org/wiki/Global_Positioning_System), the other parts being the altitude and t…
This article discusses four methods for overlaying images in a container on a web page
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now