PHP and jQuery Contact Form

Introduction

Contact forms, are generally easy things to create. The issue that many people have with them is that they're not too sure about how to send an email out after the contact form has been filled in. Many people also want to make the form use AJAX, to make it all sexy but struggle when it gets to that section. This tutorial will guide you through how to firstly build a contact form that normally posts, but then also extends to introduce how to use the $.ajax() method of jQuery.

The Form

We'll throw in a few different types of fields here so that we can learn how to manipulate them all, nothing complex here, just a nice simple bit of HTML:

<form method='post' action='/contact.php'>
    Name: <input type='text' name='name' required><br>
    Email: <input type='email' name='email' required><br>
    Gender: <select name='gender'>
        <option value='m'>Male</option>
        <option value='b'>Bacon</option>
        <option value='f'>Female</option>
    </select><br>
    Bacon: <input type='radio' name='bacon' value='smoked' checked> <input type='radio' name='bacon' value='unsmoked'><br>
    Check Me: <input type='checkbox' name='checkme'><br>
    <input type='submit' value='Send'>
</form>

You'll see in there the addition of the required attribute, and also type='email', these are new in HTML5 and are a form of validation that is enforceed by the browser.

Receiving Data

Nothing here needs to be complex, we're going to be using the global array $_POST, and simply going through each field, checking that the fields that are required are provided, and then forming an email message to send out. There's no reason that you can't take the fields and store them in a database.

Check the required fields

Here we'll be using a method called empty() which checks, amongst other things, that the variable is both provided and not blank:

if(empty($_POST['name']) || empty($_POST['email'])){
    die('Please ensure name and email are provided.');
}

Dealing with the select

Dealing with a select is pretty easy, there's no validation or that to do in our case, however, if you have a default value for your select that shouldn't be selectable you will want to check that. Eg: If we had a default option with text 'Please Select' and a value of '-':

if($_POST['gender'] == '-'){
    die('Please ensure you have selected a gender.');
}

Checkboxes aren't normal

A checkbox is either sent, or it's not. This means that you'll want to check that the field is set within the $_POST array. So in this example, we'll alter a string if the checkbox is checked compared to if it's not. Using isset() we can see if the field has been sent through with the form or not:

if(isset($_POST['checkme'])){
    $checkString = 'I have been checked.';
}else{
    $checkString = 'I have not been checked.';
}

Compose The Email

Now we can begin to write the message that we're going to send off to ourselves letting us know that someone has contacted us, we'll do that using this code:

// Blank message to start with so we can append to it.
$message = '';

// Check that name & email aren't empty.
if(empty($_POST['name']) || empty($_POST['email'])){
    die('Please ensure name and email are provided.');
}

// Check the checkbox
$checkString = 'I have not been checked.';
if(isset($_POST['checkme'])){
    $checkString = 'I have been checked.';
}

// Construct the message
$message .= <<<TEXT
    Name: {$_POST['name']}
    Email: {$_POST['name']}
    Gender: {$_POST['gender']}
    Bacon: {$_POST['bacon']}    
    {$checkString}
TEXT;

Here you'll see some crazy syntax in the form of <<<TEXT and TEXT;, this is called Heredoc. I tend to use it because at times it looks neater, and cleaner, also Sublime Text 2 syntax highlights code in those blocks based on the word you put after the <<< eg: <<<XML as XML etc.

Send the Email

We'll be using the mail() function here, this is really simple, it takes a few parameters that let you specify email, subject, message and some additional headers. We are going to send an email to test@testdomain.com, with a subject You have been contacted, and our prewritten message above, and setting the email being sent from Your Site.

$to = 'test@testdomain.com';
$subject = 'You have been contacted!';
$from = 'Your Site';
$fromEmail = 'YourSite@domain.com';

$header = 'From: ' . $from . '<' . $fromEmail . '>';

if(!mail($to, $subject, $message, $header)){
    die('Error sending email.');
}else{
    die('Email sent!');
}

Security Thoughts

If you're going to be inserting data into your database, you want to make sure that you are fully aware of any potential issues with SQL injections, which you should be able to deal with by escaping dangerous characters. If you're using MySQLi you can do this by using the mysqli::escape_string() method.

One consideration to make is whether you want to strip out the html elements that may have been entered using the strip_tags() method. One other precaution you can make is to ensure that your email is sent strictly as plain text, instead of setting a HTML header.

Data validation is vital, while we're doing some client side validation through our use of type='email' in the email field, this isn't supported in all browsers. Also, you shouldn't rely on client side validation as being secure or anything as ultimately data being posted to a server can be spoofed. You might want to look at doing some regular expression checks on the email address that is submitted by the user - this will be covered in a future article on Codular.

A final consideration to make is the addition of a unique ID or something that gets sent across with the form. This would go someway to possibly posting malicious data over to you and causing issues. This unique ID could be a unique hash of a timestamp and the user's IP or something.

sha2(date('dmYHi') . $_SERVER['REMOTE_ADDR']);

You can then check that the submitted ID is the same on the recipient page - this token of course would only be valid for 1 minute, which is plenty of time to submit a simple contact form. You should of course look to throw in additional unique fields for the user, perhaps a unique ID that's also sent across with the form?

Allowing user's to do whatever they want (ie submitting a free text form) is a very risky business and is definitely something you should take extreme caution with, but with some basic steps you'll soon be more secure than you were to start with!

Complete

And just as quickly as we started, we have finished, the basic part anyway. The full PHP is available just below, read on to look at how we can make this form post using jQuery's $.post() function.

<?php

// Blank message to start with so we can append to it.
$message = '';

// Check that name & email aren't empty.
if(empty($_POST['name']) || empty($_POST['email'])){
    die('Please ensure name and email are provided.');
}

// Check the checkbox
$checkString = 'I have not been checked.';
if(isset($_POST['checkme'])){
    $checkString = 'I have been checked.';
}

// Construct the message
$message .= <<<TEXT
    Name: {$_POST['name']}
    Email: {$_POST['name']}
    Gender: {$_POST['gender']}
    Bacon: {$_POST['bacon']}    
    {$checkString}
TEXT;

// Email to send to
$to = 'test@testdomain.com';

// Email Subject
$subject = 'You have been contacted!';

// Name to show email from
$from = 'Your Site';

// Domain to show the email from
$fromEmail = 'YourSite@domain.com';

// Construct a header to send who the email is from
$header = 'From: ' . $from . '<' . $fromEmail . '>';

// Try sending the email
if(!mail($to, $subject, $message, $header)){
    die('Error sending email.');
}else{
    die('Email sent!');
}

jQuery-ify Your Form

Our PHP code that we wrote just before should work absolutely fine. We need to add an id to the form and all of its elements, except for the radio button which we'll give a class, so that we can access them through JS.

We can now use the following jQuery code:

$(function(){
    $('#form').submit(function(e){

        // Stop the form actually posting
        e.preventDefault();

        // Send the request
        $.post('/contact.php', {
            name: $('#name').val(),
            email: $('#email').val(),
            gender: $('#gender').val(),
            bacon: $('.bacon:checked').val(),
            checkme: $('#checkme').is(':checked')
        }, function(d){
            // Here we handle the response from the script
            // We are just going to alert the result for now
            alert(d);
        });
    });
});

Firstly, we're stopping the form from submitting using e.preventDefault() as it normally would because we're sending the request through the AJAX post instead.

We next use $.post() which takes 3 parameters, the first being the URL that we're posting to, the next being an object of data to send, and finally a callback function that will get the data from the script.

Getting the value of the fields is as simple as using .val() in two cases we have used the CSS selector of :checked which will only select the checked item - but in the case of the checkbox we are checking that it is checked by using .is().

We are just alerting out the response at the moment, but there's no reason you can't just put that in a div that has and id of result using some code like:

$('#result').html(d);

It might be worth looking at disabling the submit button when the user hits submit so that it's not submitted multiple times. You can do this using some jQuery similar to below if you give the submit button an id of submit-button:

$('#submit-button').attr('disabled', 'disabled')

The Final Frontier

And that is the end, hope you've found it helpful and it's solved some/any questions that you might have had. Find below the jQuery'd HTML, the PHP we use is exactly the same as above.

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Sample Contact Form</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
    <script>
    $(function(){
        $('#form').submit(function(e){

            // Stop the form actually posting
            e.preventDefault();

            // Send the request
            $.post('/contact.php', {
                name: $('#name').val(),
                email: $('#email').val(),
                gender: $('#gender').val(),
                bacon: $('.bacon:checked').val(),
                checkme: $('#checkme').is(':checked')
            }, function(d){
                console.log(d);
                // Here we handle the response from the script
                // We are just going to alert the result for now
                alert(d);
            });
        });
    });
    </script>
</head>
<body>  
    <form method='post' action='/contact.php' id='form'>
        Name: <input type='text' name='name' required id='name'><br>
        Email: <input type='email' name='email' required id='email'><br>
        Gender: <select name='gender' id='gender'>
            <option value='m'>Male</option>
            <option value='b'>Bacon</option>
            <option value='f'>Female</option>
        </select><br>
        Bacon: <input type='radio' class='bacon' name='bacon' value='smoked' checked> <input type='radio' class='bacon' name='bacon' value='unsmoked'><br>
        Check Me: <input type='checkbox' id='checkme' name='checkme'><br>
        <input type='submit' value='Send'>
    </form>
</body>
</html>
Tags: PHP, jQuery