Welcome to ANDROID Developer!

Friday, May 23, 2014

Ajax Contact Form with an Attachment (jQuery & PHP)


By on 6:15 AM

Today we are going to create an Ajax based contact form, which will allow visitors to upload and attach a file to the e-mail message. This example is based on my previous post (Simple Ajax Contact form), but here I have modified few things so that visitors can upload and attach file to email using contact form.

Take a look at the picture below, this is how our Ajax contact form is going to appear on the browser. Only difference here is the extra file input field, rest is exactly the same as previous example.
ajax-contact-with-attachment

Mark Up

In order to send file as an attachment, first we must allow users to upload file using contact form. Let’s add file input field called “file_attach” to our markup along with other inputs. Notice we have <form> tag missing from the code? don’t worry we don’t need typical HTML form setting here, we can just collect fields value using jQuery .val() and files.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<fieldset id="contact_form">
<legend>My Contact Form</legend>
    <div id="result"></div>
    <label for="name"><span>Name</span>
    <input type="text" name="name" id="name" placeholder="Enter Your Name" />
    </label>
   
    <label for="email"><span>Email Address</span>
    <input type="email" name="email" id="email" placeholder="Enter Your Email" />
    </label>
   
    <label for="phone"><span>Phone</span>
    <input type="text" name="phone" id="phone" placeholder="Phone Number" />
    </label>
   
    <label for="phone"><span>Attachment</span>
    <input type="file" name="file_attach" id="file_attach" />
    </label>
   
    <label for="message"><span>Message</span>
    <textarea name="message" id="message" placeholder="Enter Your Name"></textarea>
    </label>
   
    <label><span>&nbsp;</span>
    <button class="submit_btn" id="submit_btn">Submit</button>
    <img src="ajax-loader.gif" class="loading-img" style="display:none">
    </label>
</fieldset>

jQuery and Ajax

Let’s write some jQuery code for our contact form. The code below is similar to Simple Ajax Contact form, the difference is $.ajax(), we will be using jQuery $.ajax() instead of $.post(), simply because it has more options, and allows us to have more control while uploading file to the server.
 
1
2
3
4
5
6
7
8
9
10
11
$.ajax({
    url: 'contact_me.php',
    data: post_data,
    contentType: false,
    processData: false,
    type: 'POST',
    dataType:'json',
    success: function(data){
        //do stuff
    }
});
For example, the default jQuery contentType is set to application/x-www-form-urlencoded; charset=UTF-8, which means all characters will be encoded before sending to server, but it doesn’t work with file uploads. Hence, we need to turn this encoding off, so that data will be sent as multipart/form-data. Another option to turn off here is the processData, because we don’t want jQuery desperately trying to transform file data into a huge query string, we want non-processed data to be sent to server.
But before sending data to the server using XMLHttpRequest, we need to build a FormData object appending fields to it by calling append() method. The transmitted data is sent in the same format that the form’s submit() method would use to send the data if the form’s encoding type were set to “multipart/form-data”.
 
1
2
3
4
5
6
7
//data to be sent to server        
var post_data = new FormData();  
post_data.append( 'userName', user_name );
post_data.append( 'userEmail', user_email );
post_data.append( 'userPhone', user_phone );
post_data.append( 'userMessage',user_message);
post_data.append( 'file_attach', attach_file );
Now let’s combine everything, and here’s the jQuery code for our contact form, which lets us upload file to server. As you can see there’s also simple validation code taken from previous example, which will just turn field border into red in case of empty fields.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
$(document).ready(function() {
    $("#submit_btn").click(function() {
        //get input field values
       
        var user_name       = $('input[name=name]').val();
        var user_email      = $('input[name=email]').val();
        var user_phone      = $('input[name=phone]').val();
        var attach_file     = $('input[name=file_attach]')[0].files[0];
        var user_message    = $('textarea[name=message]').val();
       
        //simple validation at client's end
        //we simply change border color to red if empty field using .css()
        var proceed = true;
        if(user_name==""){
            $('input[name=name]').css('border-color','red');
            proceed = false;
        }
        if(user_email==""){
            $('input[name=email]').css('border-color','red');
            proceed = false;
        }
        if(user_phone=="") {  
            $('input[name=phone]').css('border-color','red');
            proceed = false;
        }
        if(user_message=="") {
            $('textarea[name=message]').css('border-color','red');
            proceed = false;
        }

        //everything looks good! proceed...
        if(proceed)
        {
            $(".loading-img").show(); //show loading image
            $(".submit_btn").hide(); //hide submit button
           
            //data to be sent to server        
            var post_data = new FormData();  
            post_data.append( 'userName', user_name );
            post_data.append( 'userEmail', user_email );
            post_data.append( 'userPhone', user_phone );
            post_data.append( 'userMessage',user_message);
            post_data.append( 'file_attach', attach_file );
           
            //instead of $.post() we are using $.ajax()
            //that's because $.ajax() has more options and can be used more flexibly.
            $.ajax({
              url: 'contact_me.php',
              data: post_data,
              processData: false,
              contentType: false,
              type: 'POST',
              dataType:'json',
              success: function(data){
                    //load json data from server and output message    
                    if(data.type == 'error')
                    {
                        output = '<div class="error">'+data.text+'</div>';
                    }else{
                        output = '<div class="success">'+data.text+'</div>';
                       
                        //reset values in all input fields
                        $('#contact_form input').val('');
                        $('#contact_form textarea').val('');
                    }
                   
                    $("#result").hide().html(output).slideDown(); //show results from server
                    $(".loading-img").hide(); //hide loading image
                    $(".submit_btn").show(); //show submit button
              }
            });

        }
    });
   
    //reset previously set border colors and hide all message on .keyup()
    $("#contact_form input, #contact_form textarea").keyup(function() {
        $("#contact_form input, #contact_form textarea").css('border-color','');
        $("#result").slideUp();
    });
   
});
Once the form data is sent to server successfully, the server should return JSON data, which we will grab and output message within the #result div element.

PHP Email

In our PHP page which is contact_me.php, the most tricky part could be the Mail header, because while writing this tutorial I realized that most mail header examples (with attachment) just don’t work with most client. So I looked inside a working Gmail message source and borrowed it’s mail header for this tutorial. Here’s what I came up with.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
# Mail headers should work with most clients (including thunderbird)
$headers = "MIME-Version: 1.0\r\n";
$headers = "X-Mailer: PHP/" . phpversion()."\r\n";
$headers .= "From: SENDER_EMAIL@domain.com\r\n";
$headers .= "Subject: Email subject\r\n";
$headers .= "Reply-To: RECIPIENT_EMAIL@domain.com" . "\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=".md5('boundary1')."\r\n\r\n";

$headers .= "--".md5('boundary1')."\r\n";
$headers .= "Content-Type: multipart/alternative;  boundary=".md5('boundary2')."\r\n\r\n";

$headers .= "--".md5('boundary2')."\r\n";
$headers .= "Content-Type: text/plain; charset=ISO-8859-1\r\n\r\n";
$headers .= $user_Message."\r\n\r\n";

$headers .= "--".md5('boundary2')."--\r\n";
$headers .= "--".md5('boundary1')."\r\n";
$headers .= "Content-Type:  ".$file_type."; ";
$headers .= "name=\"".$file_name."\"\r\n";
$headers .= "Content-Transfer-Encoding:base64\r\n";
$headers .= "Content-Disposition:attachment; ";
$headers .= "filename=\"".$file_name."\"\r\n";
$headers .= "X-Attachment-Id:".rand(1000,9000)."\r\n\r\n";
$headers .= $encoded_content."\r\n";
$headers .= "--".md5('boundary1')."--";
Some clients such as thunderbird seem to like double linebreaks between headers as shown above, otherwise the mail will appear blank and only way to view message is using view source. Also note that PHP mail tested on Windows ignored more than one linebreaks “\r\n\r\n“, and no inserting empty spaces doesn’t work.
So here’s complete code of contact_me.php, we will do simple server-side validation and play with PHP $_FILES (HTTP File Upload variable) before attaching file to mail header. Since attachment may not be mandatory in most cases, we will just switch to plain email header if we do not find $_FILES['file_attach'] variable.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php
if($_POST)
{
    $to_Email       = "recipient_email@example.com"; //Replace with recipient email address
    $subject        = 'Ah!! My email from Somebody out there...'; //Subject line for emails
   
    //check if its an ajax request, exit if not
    if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) AND strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') {
   
        //exit script outputting json data
        $output = json_encode(
        array(
            'type'=>'error',
            'text' => 'Request must come from Ajax'
        ));
       
        die($output);
    }
   
    //check $_POST vars are set, exit if any missing
    if(!isset($_POST["userName"]) || !isset($_POST["userEmail"]) || !isset($_POST["userPhone"]) || !isset($_POST["userMessage"]))
    {
        $output = json_encode(array('type'=>'error', 'text' => 'Input fields are empty!'));
        die($output);
    }

    //Sanitize input data using PHP filter_var().
    $user_Name        = filter_var($_POST["userName"], FILTER_SANITIZE_STRING);
    $user_Email       = filter_var($_POST["userEmail"], FILTER_SANITIZE_EMAIL);
    $user_Phone       = filter_var($_POST["userPhone"], FILTER_SANITIZE_STRING);
    $user_Message     = filter_var($_POST["userMessage"], FILTER_SANITIZE_STRING);
   
    //additional php validation
    if(strlen($user_Name)<4) // If length is less than 4 it will throw an HTTP error.
    {
        $output = json_encode(array('type'=>'error', 'text' => 'Name is too short or empty!'));
        die($output);
    }
    if(!filter_var($user_Email, FILTER_VALIDATE_EMAIL)) //email validation
    {
        $output = json_encode(array('type'=>'error', 'text' => 'Please enter a valid email!'));
        die($output);
    }
    if(!is_numeric($user_Phone)) //check entered data is numbers
    {
        $output = json_encode(array('type'=>'error', 'text' => 'Only numbers allowed in phone field'));
        die($output);
    }
    if(strlen($user_Message)<5) //check emtpy message
    {
        $output = json_encode(array('type'=>'error', 'text' => 'Too short message! Please enter something.'));
        die($output);
    }
   
    ### Attachment Preparation ###
    $file_attached = false; //initially file is not attached
   
    if(isset($_FILES['file_attach'])) //check uploaded file
    {
        //get file details we need
        $file_tmp_name    = $_FILES['file_attach']['tmp_name'];
        $file_name        = $_FILES['file_attach']['name'];
        $file_size        = $_FILES['file_attach']['size'];
        $file_type        = $_FILES['file_attach']['type'];
        $file_error       = $_FILES['file_attach']['error'];
       
        //exit script and output error if we encounter any
        if($file_error>0)
        {
            $mymsg = array(
            1=>"The uploaded file exceeds the upload_max_filesize directive in php.ini",
            2=>"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form",
            3=>"The uploaded file was only partially uploaded",
            4=>"No file was uploaded",
            6=>"Missing a temporary folder" );
           
            $output = json_encode(array('type'=>'error', 'text' => $mymsg[$file_error]));
            die($output);
        }
   
        //read from the uploaded file & base64_encode content for the mail
        $handle = fopen($file_tmp_name, "r");
        $content = fread($handle, $file_size);
        fclose($handle);
        $encoded_content = chunk_split(base64_encode($content));
       
        //now we know we have the file for attachment, set $file_attached to true
        $file_attached = true;
    }

    if($file_attached) //continue if we have the file
    {
        # Mail headers should work with most clients (including thunderbird)
        $headers = "MIME-Version: 1.0\r\n";
        $headers .= "X-Mailer: PHP/" . phpversion()."\r\n";
        $headers .= "From:".$user_Email."\r\n";
        $headers .= "Subject:".$subject."\r\n";
        $headers .= "Reply-To: ".$user_Email."" . "\r\n";
        $headers .= "Content-Type: multipart/mixed; boundary=".md5('boundary1')."\r\n\r\n";
   
        $headers .= "--".md5('boundary1')."\r\n";
        $headers .= "Content-Type: multipart/alternative;  boundary=".md5('boundary2')."\r\n\r\n";
       
        $headers .= "--".md5('boundary2')."\r\n";
        $headers .= "Content-Type: text/plain; charset=ISO-8859-1\r\n\r\n";
        $headers .= $user_Message."\r\n\r\n";
   
        $headers .= "--".md5('boundary2')."--\r\n";
        $headers .= "--".md5('boundary1')."\r\n";
        $headers .= "Content-Type:  ".$file_type."; ";
        $headers .= "name=\"".$file_name."\"\r\n";
        $headers .= "Content-Transfer-Encoding:base64\r\n";
        $headers .= "Content-Disposition:attachment; ";
        $headers .= "filename=\"".$file_name."\"\r\n";
        $headers .= "X-Attachment-Id:".rand(1000,9000)."\r\n\r\n";
        $headers .= $encoded_content."\r\n";
        $headers .= "--".md5('boundary1')."--";
    }else{
        # Mail headers for plain text mail
        $headers = 'From: '.$user_Email.'' . "\r\n" .
        'Reply-To: '.$user_Email.'' . "\r\n" .
        'X-Mailer: PHP/' . phpversion();
    }
   
    //send the mail
    $sentMail = @mail($to_Email, $subject, $user_Message, $headers);
   
    if(!$sentMail) //output success or failure messages
    {
        $output = json_encode(array('type'=>'error', 'text' => 'Could not send mail! Please check your PHP mail configuration.'));
        die($output);
    }else{
        $output = json_encode(array('type'=>'message', 'text' => 'Hi '.$user_Name .' Thank you for your email'));
        die($output);
    }
}
That’s it, please remember some old unsupported browsers such as IE 8 may require some tweaking with jQuery code to work properly. You can just download the sample file and start testing out the script, but sorry I can not show you demo because it involves file uploading and sending email, you can try out the other demo here which works exactly same but without file uploading feature. Good luck!

Download Script

About Theavuth NHEL

Faizan is a 17 year old young guy who is blessed with the art of Blogging,He love to Blog day in and day out,He is a Website Designer and a Certified Graphics Designer.

0 comments:

Post a Comment