Ever wondered how to make one of those snazzy “Contact Us” forms to send someone’s comments to your E-mail when they are viewing your website? Your search is over, because I’m about to show you how to make one.

Requirements

  • Basic HTML Knowledge
  • Basic PHP Knowledge

Anyone can learn a good bit from this tutorial without knowing HTML or PHP. However, to be able to manipulate the code to fit your specific website and needs, you’ll need a basic understanding of those languages. Fortunately, you’ll pick up a fair amount of both as you follow along.

Before We Begin

Before you start any programming project, you need to flesh out a model of what you want to achieve. Depending on the size of the project, this could be simple pseudo code or a combination of BPMN and Class diagrams. Any way you go about it, you need to have a clear idea of the process the code you’re going to be coding will be progressing through. This is because computers are logical, some of the simplest errors that trip people up are often logic errors on the programmer’s part.

For this tutorial, I’ve written up some pseudo code. Take a look at it and you will see a general idea of what we will be writing.

If form submitted
    Get data from the form
    Clean any malicious scripts from the data
    Store data into variables

    If necessary data has been entered
    	Send Mail
    Else
    	Return a detailed error
End if

As you can see, it’s going to be a pretty logical process. We take information that someone enters into a form and pass that along to someone in an E-mail. Now, onto the fun part – coding it.

Coding

The first step to this is script will be to setup the PHP variables that are global to the entire script. I have made comments in the code to make it pretty easy to follow along.

Step 1

<?php
/*
 * Title: PHP Tutorial 1: Secure Contact Form
 * URL: http://www.matthewwatts.net/tutorials/php-tutorial-1-creating-a-secure-contact-form-for-your-website/
 * For: Processing form data and sending it to a specified E-mail address.
 * Site: matthewwatts.net
 * Author: Matthew Watts
 * Company: Rexibit Web Services - http://www.rexibit.com
 * Last Modified: 2010-09-05
 */

// Main Variables Used Throughout the Script
$domain = "http://" . $_SERVER["HTTP_HOST"]; // Root Domain - http://example.com
$siteName = "Your Website Name";
$siteEmail = "n...@example.com";
$er = "";

I start every script with a little information about what the title of the file is and what it is for. It’s good habit when you come back to something later and for keeping you on task. I like to modulate my code and not have a single script do a ton of things.

As you can see above, we setup four variables. The $domain variable will not be used in this script, but I have it there because you could use it to make notifications more specific, or include a link back to your site in the E-mail you send out. The next two variables are there for convenience. I like being able to reuse code and with this setup, I can quickly copy and paste the script for another site by only changing a couple lines. $er will hold any error messages. It’s global because it’s used in multiple parts of the script.

Step 2

// Check if the web form has been submitted
if (isset($_POST["contactEmail"])){

	/*
	 * Process the web form variables
	 * Strip out any malicious attempts at code injection, just to be safe.
	 * All that is stored is safe html entities of code that might be submitted.
	 */
	$contactName = htmlentities(substr($_POST["contactName"], 0, 100), ENT_QUOTES);
	$contactEmail = htmlentities(substr($_POST["contactEmail"], 0, 100), ENT_QUOTES);
	$messageSubject = htmlentities(substr($_POST["messageSubject"], 0, 100), ENT_QUOTES);
	$messageContent = htmlentities(substr($_POST["messageContent"], 0, 10000), ENT_QUOTES);

This if statement uses the isset PHP function to check if a form element with the name of contactEmail has any data. With contact forms, I use the E-mail because it’s one of the primary pieces of information needed.

The next four lines of code strips out malicious code, takes the form elements out of the POST array, and assigns them to variables all at the same time. htmlentities is a very useful function. Wherever it finds special characters that could be used to inject programing code, it turns the characters into special HTML characters. Inside that function, we use the substr function to limit the amount of characters stored. This is useful if you ever want to ensure you don’t send too much data into a database field.

Step 3

	/*
	 * Perform some logic on the form data
	 * If the form data has been entered incorrectly, return an Error Message
	 */

	 // Check if the data entered for the E-mail is formatted like an E-mail should be
	if (!eregi('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]{2,})+$', $contactEmail)){
		$er .= 'Please enter a valid e-mail address.<br />';
	}

	// Check if all of the form fields contain data before we allow it to be submitted successfully
	if ($contactName == "" || $contactEmail == "" || $messageSubject == "" || $messageContent == ""){
		$er .= 'Your Name, E-mail, Message Subject, and Message Content cannot be left blank.<br />';
	}

This bit of code is where the script really starts to be useful. The first if statement checks for a badly formed E-mail address. There are a lot of ways to check for valid E-mail addresses, this just checks for an @ and a domain name. If those aren’t found, it stores the error in the $er variable. Now, you may be wondering, “What’s that .= operator mean?” What that says is that the string is appended to the end of whatever’s already stored in the $er variable.

The next if statement says that if any of those variables are empty, throw the error. You can get more specific in breaking down your error notifications, but for the purpose of this script, that works.

Step 4

	// IF NO ERROR - START
	if ($er == ''){

		// Prepare the E-mail elements to be sent
		$subject = $messageSubject;
		$message =
		'<html>
			<head>
			<title>' . $siteName . ': A Contact Message</title>
			</head>
			.<body>
			' . wordwrap($messageContent, 100) . '
			</body>
		</html>';

Now that we’ve made sure the form data is secure and all the right fields have been filled in, we want to code how the E-mail will be sent. PHP offers several options for this, we’ll be using the mail function. Since would like people to be able to format their E-mail how they want, I’m going to go ahead and start it like an HTML E-mail.

The if statement here checks that the $er variable is empty. If it is, we go ahead and assign the $subject variable whatever was specified from the form. And, we populate the $message variable with the HTML.

Now, you may have noticed that we are using a function called wordwrap. This lets you specify how many characters will move along until a \n new line string formating character will be applied. 70-100 characters are what Outlook and most mobile phones use. You could also add the nl2br function here to add a <br> wherever a new line character is found.

Step 5

		/*
		 * We are sending the E-mail using PHP's mail function
		 * To make the E-mail appear more legit, we are adding several key headers
		 * You can add additional headers later to futher customize the E-mail
		 */

		$to = $siteName . ' Contact Form <' . $siteEmail . '>';

		// To send HTML mail, the Content-type header must be set
		$headers = 'MIME-Version: 1.0' . "\r\n";
		$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";

		// Additional Headers
		$headers .= 'From: ' . $contactName . ' <' . $contactEmail . '>' . "\r\n";
		$headers .= 'Reply-To: ' . $contactName . ' <' . $contactEmail . '>' . "\r\n";
		$headers .= 'Return-Path: ' . $contactName . ' <' . $contactEmail . '>' . "\r\n";
		$headers .= 'Date: ' . date("r") . "\r\n";
		$headers .= 'X-Mailer: ' . $siteName . "\r\n";

All that’s left now to use the mail function of PHP is to assign the to and headers. The as the name suggests, the to will be going to whatever E-mail we specified for the site. I normally label the name of the E-mail in the format Site Name + Contact Form. This lets me create a mail filter in Mozilla Thunderbird (or Outlook) to store all contact form messages in a folder.

Now, E-mail headers are what E-mail hosts and programs use to figure out where your E-mail goes and how it’s handled. This is the Meta Data. Spammers also use this to try and spoof where their E-mail has come from to perform phishing scams. We start the headers off by setting the MIME type and telling any E-mail server that it’s using HTML. You don’t have to set this if you aren’t using HTML in the E-mail.

To use the mail function, you must have a From header. So, we set it to the person filling out the contact form. To be thorough, we go ahead and add them to the reply-to and return-path header. This helps reduce the chance of our mail being caught as spam, and will usually auto-add them to any contact list in your E-mail program.

The last two headers I’ve added recently. I started noticing that some E-mails I got had wrong dates in them. This is because people were spoofing the time. So, I started going ahead and setting it. The X-Mailer just tells people where the E-mail originated or what program it came from. WordPress or other Content Managing Systems usually put their name. I put in my site’s name. Again, it helps reduce the chance of the E-mail being caught as spam.

Step 6

		// And now, mail it
		if (mail($to, $subject, $message, $headers)){
			echo '<div>Thank you for contacting ' . $siteName . '. We will read your message and contact you if necessary.</div>';
		}
		else {
			$er .= 'We weren't able to send your message. Please contact ' . $siteEmail . '.<br />';
		}
	}
	// IF NO ERROR - END
}

// If web form has not been submitted, show a blank form
else {
	showContactForm();
}

By now, our E-mail should be ready to send out. So, we pass the mail function those variables. Since the mail function returns true or false based on if it was able to send out the E-mail, it’s a good idea to place it inside an if statement. This allows you to create a visible error notification if it wasn’t able to be sent.

Since we got done with that scripting, we also close out the previous if statements we were in.

Now, at the bottom, you can see that we finished the if statement that checked if a form had been submitted. We want to create a default form on the website, so we add an else statement that calls a function which will display the contact form. Before we get to showing you how that works, we want to do something with those error messages.

Step 7

/*
 * If there have been errors, we want to return notification
 * We also want to be nice, and send any data already filled in back so they don't re-enter it
 */

// If there are errors, and the contact E-mail is filled in
if ($er != '' && isset($_POST["contactEmail"])){
	showContactForm($contactName, $contactEmail, $messageSubject, $messageContent, $er);
}

// If there are errors, and the contact E-mail isn't filled in
else if ($er != '' && !isset($_POST["contactEmail"])){
	showContactForm('', '', '', '', $er);
}

This is the last actual coding section of the script. This is the logic to handle showing errors to the person trying to send a contact message. The first if statement says that if there are errors and a contact E-mail has been entered, then it will display the contact form with whatever data has been entered already.

This data is what has already been taken from the form and is currently stored in the variables we first assigned in the if statement checking if the form has been submitted. This is where PHP differs from other programing languages. Usually, if you instantiate a variable inside of an if statement, you can’t access it’s data outside of the if statement unless it was previously instantiated outside of that if statement. For this particular application, I separated them this way to both prove a point, and make it easier on myself later when I come back to reuse the script.

The next if statement says that if there are no errors and a contact E-mail has not been entered, then it will display the contact form with no data. We could be nice and pass it the variables in the $_POST array, since PHP will pull all form data and store it inside the $_POST or $_GET global array, but I’m choosing not too. This is a personal preference, but I find that if people leave off an E-mail in contact forms, they probably didn’t really care about the message anyway and are usually spammers quickly pasting a message through a bot, or someone wanting to waste your time. Making them start fresh usually gets them to go away.

Step 8

// Setup a function to display a contact form
function showContactForm($contactName = "", $contactEmail = "", $messageSubject = "", $messageContent = "", $er = ''){
	echo '<div style="font-weight:bold; margin: 5px 0;">' . $er . '</div>
	<form action="' . $_SERVER["REQUEST_URI"] . '" method="post" name="contactForm">
		<fieldset>
			<ul>
				<li>
					<label for="contactName">Your Name</label>
					<input name="contactName" type="text" size="20" maxlength="100" value="' . $contactName . '" />
				</li>
				<li>
					<label for="contactEmail">Your E-Mail</label>
					<input name="contactEmail" type="text" size="20" maxlength="100" value="' . $contactEmail . '" />
				</li>
				<li>
					<label for="messageSubject">Subject</label>
					<input name="messageSubject" type="text" size="20" maxlength="100" value="' . $messageSubject . '" />
				</li>
				<li>
					<label for="messageContent">Comments</label>
					<textarea name="messageContent" cols="35" rows="8">' . $messageContent . '</textarea>
				</li>
			</ul>
		</fieldset>
		<fieldset class="submit">
			<input name="submitButton" type="submit" value="Send Message" />
		</fieldset>
	</form>';
}
?>

This is the end of the script. In the function for displaying the contact form, The variables used for the parameters are already defined with a default value of null. This enables it to be called earlier in step 6 in the else statement without passing it anything. It also ensures that if it’s used, those variables will always have a value and not throw an error.

After seeing the code, you can see that this script doesn’t have all of the HTML elements to form an entire HTML page. This is because this script can be embedded inside of another PHP script to be able to display a contact form anywhere in your website.

This function is pretty simple. It just outputs some HTML to the screen and if there are any error messages, will output whatever data is in the variables back for the visitor to revise and resend without having to retype it all.

Enhancing this script

As with any programing, it always has room for improvement. This script doesn’t utilize any CSS aside from formating the error message notification. The contact form uses a table-less layout and groups elements semantically using labels and fieldsets. The labels are there for screen readers. One added benefit is that it lets you format your forms really well with CSS. You can dress up your forms with it and create some very neat things. You can read more on CSS Forms at A List Apart.

Another enhancement to the form would be using JavaScript to also add real-time error checking. It’s a good idea to only use JavaScript to enhance the functionality of a website, but not use it to replace core functionality. Some visitors will have JavaScript disabled, so replacing the validation with JavaScript could seriously impair or cripple your site if that PHP validation didn’t strip out malicious code.

Get the Code

You can download the full Secure Contact Form script. All I ask is that you leave the comments at the top crediting me and the URL of the post in tact. Change the file extension to PHP to use.

Looking Ahead

I’m going to be adding more PHP tutorials in the future. I’ll be carrying on in the next tutorial by breaking this Contact Form into using PHP classes. There’s a lot of concepts that can be learned with this simple contact form, so stay tuned!

, , , ,
Trackback

7 comments untill now

  1. Nice tutorial, I had a book explaining this and it just vanished. The one thing about it, is the light gray on white background for the code makes it almost impossible to read. I think it would be a GREAT tutorial if there were some attention given to the color scheme. The border color for the fields for the reply are white on white – invisible.

  2. Magik. Thank you for this, very helpful, very useful. I now have to go hunting to see how to add in a checkbox and I’m done :)

  3. Kardo Brecht @ 2011-01-12 01:57

    Thanks for the the very clear described steps to build a secure form. Can you split this into two different files, the normal HTML file with the form fields, and the PHP script for the validation and sending the email and still display the error message(s) on the same HTML contact-form and keep the already entered data

  4. @Kardo

    You can split the PHP and HTML form up. As it stands, you could embed the PHP file into an existing HTML page wherever you need a contact form. However, you could just remove the function call for the form at the last “ELSE” statement and then use the PHP “include” or “require_once” functions to load a file of your choice.

    Keep in mind, it’s still best practice to have the variables for the already entered data to be included in the “value” attribute of the text fields and text area. This way they don’t have to renter it all. So you’ll be calling a file with PHP code if you split them up.

  5. [...] [...]

  6. works for godaddy but not yahoo hosting

  7. It should work on any PHP environment. You should check your sendmail/mail configuration in your php.ini file.

Add your comment now