Today we will be creating a simple yet secure contact form with PHP and Javascript. I have used this contact form on multiple websites, and I find it to be very easy to use and install, so you should enjoy it.

See the final result in action.

Download the files for this tutorial.

Step 1 – Download the Files

Before we get started, go download the following javascript files:

  1. The latest minified version of jQuery
  2. The jQuery Validate plugin (click the Download link on the page, unzip the downloaded file, and then copy out the jquery.validate.min.js file)
  3. The jQuery Form plugin

After you have downloaded those three files, place them in a folder named js in the directory where you want to have your contact form. Now you’re ready to start crafting the contact form!

Step 2 – HTML

First off, make sure that you have a basic understanding of HTML, PHP, and Javascript. W3schools.com is a great resource for quickly getting up to speed with these languages. Once you have a grip of these technologies, you should be able to understand what is going on in this tutorial much better.

To start off, create a new file on your server named contact.html. It can be named whatever you want (or you can add the contact form to an existing file), but for the sake of this tutorial we will use contact.html.

In this file, add the following code:

<!DOCTYPE HTML>
<html>
	<head>
		<title>Contact Form</title>

		<link rel="stylesheet" href="style.css" type="text/css" />

		<script type="text/javascript" src="js/jquery.min.js"></script>
		<script type="text/javascript" src="js/jquery.validate.min.js"></script>
		<script type="text/javascript" src="js/jquery.form.js"></script>
		<script type="text/javascript" src="js/contact.js"></script>
	</head>
	<body>
		<div id="wrap">
			<h1>Contact Sweetness</h1>
			<form id="contactform" action="processForm.php" method="post">
				<table>
					<tr>
						<td><label for="name">Name:</label></td>
						<td><input type="text" id="name" name="name" /></td>
					</tr>
					<tr>
						<td><label for="email">Email:</label></td>
						<td><input type="text" id="email" name="email" /></td>
					</tr>
					<tr>
						<td><label for="message">Message:</label></td>
						<td><textarea id="message" name="message" rows="5" cols="20"></textarea></td>
					</tr>
					<tr>
						<td></td>
						<td><input type="submit" value="Send!" id="send" /></td>
					</tr>
				</table>
			</form>
			<div id="response"></div>
		</div>
	</body>
</html>

This code contains the structure for our contact form. Let’s take a look at what each section is doing.

<!DOCTYPE HTML>
<html>
	<head>
		<title>Contact Form</title>

These lines set up the basic structure of the HTML document, and they should be second nature to you.

		<link rel="stylesheet" href="style.css" type="text/css" />

		<script type="text/javascript" src="js/jquery.min.js"></script>
		<script type="text/javascript" src="js/jquery.validate.min.js"></script>
		<script type="text/javascript" src="js/jquery.form.js"></script>
		<script type="text/javascript" src="js/contact.js"></script>

First we include the CSS stylesheet that we will be creating shortly, and then we proceed to include all three of the javascript files that we just downloaded into the js folder. The last line is including <strong>contact.js</strong>, a file we will create later on.

	</head>
	<body>
		<div id="wrap">
			<h1>Contact Sweetness</h1>
			<form id="contactform" action="processForm.php" method="post">

This ends the head and starts the body of the page. We set up a “wrap” div that will be used to style the contact form with CSS later on, and add a heading at the top of the new div. Then we start the form that will contain all of the inputs where the user will type in their info and message. The action of the form is set to processForm.php, another file which we will create later on. The reason we add this file to the action attribute of the form instead of just doing all of the processing with javascript is that someone without javascript enabled will be able to use the form as well as someone with javascript enabled. The key here is progressive enhancement, or making sure that users with less capabilities will still be able to use your website. Always start by coding for the lowest common denominator – users who don’t have javascript in this case – and then adding better functionality for users with better browsers/more capable systems.

				<table>
					<tr>
						<td><label for="name">Name:</label></td>
						<td><input type="text" id="name" name="name" /></td>
					</tr>
					<tr>
						<td><label for="email">Email:</label></td>
						<td><input type="text" id="email" name="email" /></td>
					</tr>
					<tr>
						<td><label for="message">Message:</label></td>
						<td><textarea id="message" name="message" rows="5" cols="20"></textarea></td>
					</tr>
					<tr>
						<td></td>
						<td><input type="submit" value="Send!" id="send" /></td>
					</tr>
				</table>

These lines contain the actual input areas for the contact form. As you can see, I am using a table to format the form, even though tables are typically frowned upon in the design community. I find that in certain situations, when I want to easily align different elements in nice grids, tables are just the easiest option, but you can of course use divs if that’s what you prefer. Each input element has both an id and a name which are needed for processing the input with javascript and PHP and for styling the form with CSS. We’ll see how all of these values work together soon.

			</form>
			<div id="response"></div>
		</div>
	</body>
</html>

Here we are basically just closing all of the tags that we opened up above. However, line 36 contains a new “response” div that will contain the response of the processForm.php file when we try to submit a message to it. Again, you will see how this comes into play soon.

Now that you have this basic HTML structure, you should see something like this when you open up contact.html in your browser:

It’s not too pretty yet, but that’s where the next step comes in…

Step 3 – CSS

I always love it when I get to the CSS portion of my designing. There’s something about taking an ugly and deformed hunk of content and crafting it to beautiful pixel perfection that just sets my heart to racing. Okay, that might be going a bit far, but that’s not really all that far off.

Start by creating a new file next to contact.html named style.css. Remember that line in the head of contact.html where we included style.css? Yup, this is the very same one. What a funny coincidence. Anyway, in this new css file, put in this code:

body {
	background: #24333d;
	color: #4a606f;
	font: 21px 'Helvetica', 'Arial', sans-serif;
	margin: 0;
	padding: 50px 0 0;
}

h1 {
	color: #24333c;
	font-size: 48px;
	font-weight: normal;
	margin: 25px 0 15px;
	text-align: center;
}

#wrap {
	background: #eaf0f4;
	border: 5px solid #7a91a1;
	margin: auto;
	width: 500px;
}

form {
	padding: 0;
	margin: 0 0 20px;
}
table {
	margin: 0 auto;
}
tr, td, input, textarea {
	margin: 0;
	padding: 0;
}
td {
	padding: 0 0 5px;
}
tr td:first-child {
	padding-right: 10px;
	padding-top: 11px;
	text-align: right;
	vertical-align: top;
}
.error[generated=true] {
	color: #dc0000;
	font-size: 16px;
	padding: 5px 0 2px 5px;
}
tr.error td {
	padding: 0;
}
input, textarea {
	background: #FFF;
	border: 3px solid #7a91a1;
	font: inherit;
	font-size: 16px;
	line-height: 29px;
	min-height: 30px;
	padding: 5px 10px;
	width: 300px;
}
input:focus, textarea:focus {
	border-color: #b0c3d0;
	outline: none;
}
textarea {
	height: 240px;
	resize: vertical;
}
input[type=submit] {
	background: #24333d;
	color: #FFF;
	font: inherit;
	padding: 7px 20px;
	width: auto;
}

#response {
	margin-bottom: 20px;
	text-align: center;
}
#response .success {
	color: #08a300;
}
#response .failure {
	color: #dc0000;
}

Now I could go through each selector and tell you exactly what everything in here does, but that would ruin the fun of you figuring it out yourself (plus it would take a long time for me to write and for you to read, which would be boring for everyone). So take a look at it yourself and see if you can figure out everything that’s going on. If you run into something you don’t understand, there’s this amazing tool that can help you with basically every aspect of coding that you should take a look at. It’s a lifesaver and you should learn to use it if you ever want to get anywhere with your web design.

Some of the things in that CSS have to do with errors and responses, and you probably don’t know what those mean yet. Don’t fret, my friend, for soon you will be an expert on errors and responses – just as soon as we take a look at the javascript portion of this contact form. Now you should have something that looks like this if you refresh contact.html:

Not too bad!

Step 4 – Javascript

Now we get to the fun part – making everything actually work (to some extent)! More specifically, by adding javascript to this contact form, we will be adding validation (making sure the user enters acceptable things into the different fields) and ajax in a nice blend of usefulness. You’ll see what I mean soon enough.

Remember when we referenced contact.js in the HTML file? That’s right, now it’s time to create it! Here we go: inside the js folder that you created in step 1, create a new file and name it contact.js. This will hold all of our jQuery goodness. More specifically, it will look like this:

$(function() {
	// Validate the contact form
  $('#contactform').validate({
  	// Specify what the errors should look like
  	// when they are dynamically added to the form
  	errorElement: "label",
  	wrapper: "td",
  	errorPlacement: function(error, element) {
  		error.insertBefore( element.parent().parent() );
  		error.wrap("<tr class='error'></tr>");
  		$("<td></td>").insertBefore(error);
  	},

  	// Add requirements to each of the fields
  	rules: {
  		name: {
  			required: true,
  			minlength: 2
  		},
  		email: {
  			required: true,
  			email: true
  		},
  		message: {
  			required: true,
  			minlength: 10
  		}
  	},

  	// Specify what error messages to display
  	// when the user does something horrid
  	messages: {
  		name: {
  			required: "Please enter your name.",
  			minlength: jQuery.format("At least {0} characters required.")
  		},
  		email: {
  			required: "Please enter your email.",
  			email: "Please enter a valid email."
  		},
  		message: {
  			required: "Please enter a message.",
  			minlength: jQuery.format("At least {0} characters required.")
  		}
  	},

  	// Use Ajax to send everything to processForm.php
  	submitHandler: function(form) {
  		$("#send").attr("value", "Sending...");
  		$(form).ajaxSubmit({
  			target: "#response",
  			success: function(responseText, statusText, xhr, $form) {
  				$(form).slideUp("fast");
  				$("#response").html(responseText).hide().slideDown("fast");
  			}
  		});
  		return false;
  	}
  });
});

Yes, that’s a lot of code to wade through. Let’s get into it.

$(function() {

If you have used jQuery before, this should look very familiar. This is jQuery’s way of waiting until the page is loaded to execute something. Anything inside the function’s curly brackets will run as soon as the page has finished loading.

// Validate the contact form
  $('#contactform').validate({

This is telling the Validate plugin that we downloaded and included earlier to validate the #contactform form. By using a plugin instead of validating everything ourselves, everything is just easier for everyone.

// Specify what the errors should look like
  	// when they are dynamically added to the form
  	errorElement: "label",
  	wrapper: "td",
  	errorPlacement: function(error, element) {
  		error.insertBefore( element.parent().parent() );
  		error.wrap("<tr class='error'></tr>");
  		$("<td></td>").insertBefore(error);
  	},

Though the validate() function works great without any help, we need to give it some extra info so that it will display everything nicely. These first few options deal with where we should display errors when the user types in something they shouldn’t. You can read about all of the possible options on this page.

Here’s what the different arguments do:

  • errorElement: What element the error message will be placed in. The reason I chose to put it in a label is so that if the user clicks on the error, it will automatically focus the correct text box for them.
  • wrapper: Basically like errorElement – it wraps the error, including the label, in a td tag.
  • errorPlacement: A function that specifies where the error should be placed after it is generated. It looks complicated, but really all we are doing is putting it in a tr element next to the tr that the input box is in, and adding an empty td tag before the error to push the error to the right. You’ll see what I mean if you take a look at the code of the page after an error is generated.
  	// Add requirements to each of the fields
  	rules: {
  		name: {
  			required: true,
  			minlength: 2
  		},
  		email: {
  			required: true,
  			email: true
  		},
  		message: {
  			required: true,
  			minlength: 10
  		}
  	},

The rules option specifies the details of each input element in the contact form. As you can see, every one of the inputs is required, and the name and message text boxes have minimum amounts of characters allowed. The email text box has a special parameter which tells the Validate plugin that it is an email element. This ensures that any email entered into the form will truly be an email and not just something like “asdf.”

  	// Specify what error messages to display
  	// when the user does something horrid
  	messages: {
  		name: {
  			required: "Please enter your name.",
  			minlength: jQuery.format("At least {0} characters required.")
  		},
  		email: {
  			required: "Please enter your email.",
  			email: "Please enter a valid email."
  		},
  		message: {
  			required: "Please enter a message.",
  			minlength: jQuery.format("At least {0} characters required.")
  		}
  	},

As you can see, this messages option looks suspiciously like the rules option we just looked at. The reason for this is that in this option we specify what error messages to show the user when they break one of the rules we just set up. For example, if the name that they enter doesn’t meet the minimum length requirement, it will say “At least 2 characters required.”

  	// Use Ajax to send everything to processForm.php
  	submitHandler: function(form) {

This line of code is yet another option that we’re passing the Validate plugin, this time specifying what should happen when the form is submitted (with no errors). Let’s take a look at what’s going to happen when the Send button is clicked:

$("#send").attr("value", "Sending...");

So when the form is submitted, we begin by changing the text in the submit button from “Send!” to “Sending….” The reason for this is that the Ajax server request takes a few seconds, so we want to make sure that the user knows something’s going on.

  		$(form).ajaxSubmit({
  			success: function(responseText, statusText, xhr, $form) {
  				$(form).slideUp("fast");
  				$("#response").html(responseText).hide().slideDown("fast");
  			}
  		});

The cool thing about this form is that it doesn’t reload the page when the Send button is pressed, it just sends the email asynchronously (in the background). It’s called using Ajax, and it’s pretty nifty. These lines of code use the other plugin we downloaded at the start – the Form plugin – to do all the Ajax kungfooery. We pass just one parameter to the ajaxSubmit function: success. This tells the form what to do when the form is submitted successfully. In there we tell the entire form to hide itself by sliding up, and we then insert the response text into the #response div.

Here’s how it works: The user fills in the form and hits the send button, and the content is sent to processForm.php to be emailed. If there are no errors with the sending of the email and it is sent successfully, the processForm file sends back a message to contact.html saying “Success!” However, if there is an error along the way, it sends back a “Failed!” message. This message (either success or failure) is then put into the #response div.

That’s it for the javascript! Now the form should validate correctly, and if you type in some bogus information, it will give you pretty errors like this:

Step 5 – PHP

We’re onto the final section of our little contact form – PHP! The purpose of the PHP is first off to actually send the message that the user typed into the form, and secondly to do some additional error validation. Why do we need to do more validation, you ask? Why can’t we just rely on the javascript to catch everything? Well, think about what would happen if the user doesn’t have javascript enabled when they submit the form – no errors will occur! All of their data, including anything that might be erroneous, will be emailed to you, and that’s not what you want. So we’re forced to repeat all of the validating that we did before in javascript, this time in PHP. Here we go!

Create another file – the final file – and name it processForm.php. In it, put the following code:

<?php

// Clean up the input values
foreach($_POST as $key => $value) {
	if(ini_get('magic_quotes_gpc'))
		$_POST[$key] = stripslashes($_POST[$key]);

	$_POST[$key] = htmlspecialchars(strip_tags($_POST[$key]));
}

// Assign the input values to variables for easy reference
$name = $_POST["name"];
$email = $_POST["email"];
$message = $_POST["message"];

// Test input values for errors
$errors = array();
if(strlen($name) < 2) {
	if(!$name) {
		$errors[] = "You must enter a name.";
	} else {
		$errors[] = "Name must be at least 2 characters.";
	}
}
if(!$email) {
	$errors[] = "You must enter an email.";
} else if(!validEmail($email)) {
	$errors[] = "You must enter a valid email.";
}
if(strlen($message) < 10) {
	if(!$message) {
		$errors[] = "You must enter a message.";
	} else {
		$errors[] = "Message must be at least 10 characters.";
	}
}

if($errors) {
	// Output errors and die with a failure message
	$errortext = "";
	foreach($errors as $error) {
		$errortext .= "<li>".$error."</li>";
	}
	die("<span class='failure'>The following errors occured:<ul>". $errortext ."</ul></span>");
}

// Send the email
$to = "YOUR_EMAIL";
$subject = "Contact Form: $name";
$message = "$message";
$headers = "From: $email";

mail($to, $subject, $message, $headers);

// Die with a success message
die("<span class='success'>Success! Your message has been sent.</span>");

// A function that checks to see if
// an email is valid
function validEmail($email)
{
   $isValid = true;
   $atIndex = strrpos($email, "@");
   if (is_bool($atIndex) && !$atIndex)
   {
      $isValid = false;
   }
   else
   {
      $domain = substr($email, $atIndex+1);
      $local = substr($email, 0, $atIndex);
      $localLen = strlen($local);
      $domainLen = strlen($domain);
      if ($localLen < 1 || $localLen > 64)
      {
         // local part length exceeded
         $isValid = false;
      }
      else if ($domainLen < 1 || $domainLen > 255)
      {
         // domain part length exceeded
         $isValid = false;
      }
      else if ($local[0] == '.' || $local[$localLen-1] == '.')
      {
         // local part starts or ends with '.'
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $local))
      {
         // local part has two consecutive dots
         $isValid = false;
      }
      else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
      {
         // character not valid in domain part
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $domain))
      {
         // domain part has two consecutive dots
         $isValid = false;
      }
      else if(!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/',
                 str_replace("\\\\","",$local)))
      {
         // character not valid in local part unless
         // local part is quoted
         if (!preg_match('/^"(\\\\"|[^"])+"$/',
             str_replace("\\\\","",$local)))
         {
            $isValid = false;
         }
      }
      if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A")))
      {
         // domain not found in DNS
         $isValid = false;
      }
   }
   return $isValid;
}

?>

That’s definitely the biggest file we’ve had yet. Let’s take a look at what’s going on.

<?php

// Clean up the input values
foreach($_POST as $key => $value) {
	if(ini_get('magic_quotes_gpc'))
		$_POST[$key] = stripslashes($_POST[$key]);

	$_POST[$key] = htmlspecialchars(strip_tags($_POST[$key]));
}

This foreach statement is reading all of the variables in the $_POST array and sanitizing them. When you sanitize data, you make sure that it doesn’t contain anything harmful that could potentially hurt your website.

// Assign the input values to variables for easy reference
$name = $_POST["name"];
$email = $_POST["email"];
$message = $_POST["message"];

As the comment states, all we are doing here is putting each $_POST option into its own variable. That way it will be easier to access the variables later on (less typing).

// Test input values for errors
$errors = array();
if(strlen($name) < 2) {
	if(!$name) {
		$errors[] = "You must enter a name.";
	} else {
		$errors[] = "Name must be at least 2 characters.";
	}
}
if(!$email) {
	$errors[] = "You must enter an email.";
} else if(!validEmail($email)) {
	$errors[] = "You must enter a valid email.";
}
if(strlen($message) < 10) {
	if(!$message) {
		$errors[] = "You must enter a message.";
	} else {
		$errors[] = "Message must be at least 10 characters.";
	}
}

Here we have the actual error testing for each of the variables we just initiated. As you can see, we are basically just performing all of the tests that we did in the Javascript. Every time we encounter an error, we pass the appropriate error message to the $errors array so that we can output all of the errors to the user.

if($errors) {
	// Output errors and die with a failure message
	$errortext = "";
	foreach($errors as $error) {
		$errortext .= "<li>".$error."</li>";
	}
	die("<span class='failure'>The following errors occured:<ul>". $errortext ."</ul></span>");
}

If there were any errors, we output them to the screen in a nicely formatted list, and then we kill the page using the handy die() function.

// Send the email
$to = "YOUR_EMAIL";
$subject = "Contact Form: $name";
$message = "$message";
$headers = "From: $email";

mail($to, $subject, $message, $headers);

// Die with a success message
die("<span class="success">Success! Your message has been sent.</span>");

Now we get to actually send the email! Whoop! First we set all the appropriate variables (change “YOUR_EMAIL” to whatever email address you want the messages to be sent to), and then we use PHP’s built-in mail() function to send the email.

That last line (the die function) is very important. It tells the scrip to kill itself once the email is sent, which does one of two things. If the user has javascript enabled, this die function will send the success message contained in itself back to the javascript file we created in the last step, which will in turn update the #response div with the success text. However, if the user doesn’t have javascript enabled, the script will simply die and output the success message. It’s kind of like killing two birds with one stone, isn’t it?

// A function that checks to see if
// an email is valid
function validEmail($email)
{
   $isValid = true;
   $atIndex = strrpos($email, "@");
   if (is_bool($atIndex) && !$atIndex)
   {
      $isValid = false;
   }
   else
   {
      $domain = substr($email, $atIndex+1);
      $local = substr($email, 0, $atIndex);
      $localLen = strlen($local);
      $domainLen = strlen($domain);
      if ($localLen < 1 || $localLen > 64)
      {
         // local part length exceeded
         $isValid = false;
      }
      else if ($domainLen < 1 || $domainLen > 255)
      {
         // domain part length exceeded
         $isValid = false;
      }
      else if ($local[0] == '.' || $local[$localLen-1] == '.')
      {
         // local part starts or ends with '.'
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $local))
      {
         // local part has two consecutive dots
         $isValid = false;
      }
      else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
      {
         // character not valid in domain part
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $domain))
      {
         // domain part has two consecutive dots
         $isValid = false;
      }
      else if(!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/',
                 str_replace("\\\\","",$local)))
      {
         // character not valid in local part unless
         // local part is quoted
         if (!preg_match('/^"(\\\\"|[^"])+"$/',
             str_replace("\\\\","",$local)))
         {
            $isValid = false;
         }
      }
      if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A")))
      {
         // domain not found in DNS
         $isValid = false;
      }
   }
   return $isValid;
}

?>

This is a function that I found online (in this article) that validates email addresses. It is very handy, and I use it in a lot of my projects because it covers so many different possibilities. If you want to, you can look through and see what it’s doing, but if you’re like me and don’t really care, you can just treat it like a black box and feed it email addresses. It works, believe me.

Conclusion

And that’s it! Now you know how to code a simple and secure contact form that you can easily implement on your own websites. It looks great, is very functional, and has good error checking – what more could you want?

See the final result in action.

Download the files for this tutorial.