Secure PHP Contact Form

I've written up an easy to use, secure, accessible and XHTML Strict compliant contact form, originally for someone to use on their site, but figured I'd post it up here as a bit of a PHP tutorial for anyone who wants to understand what's going on, or for others to just download, follow the instructions and use. I'll explain its usage today and then dissect the form for any PHP learners later in the week.

First off, download the contact form, unzip it and open it in your favourite coding editor. The best version of this form requires PHP 4.4+ however I've altered the line that depends on this version so that you can use it down to version 4.0 however foreign characters will not be checked in the name. Both are contained in the download file.

This won't work straight out of the box. You'll need to edit a few lines first plus add in your surrounding HTML markup.

Edit the Basics

To get this up and running with minimal effort you need to do the following (from top down in the file).

  1. Edit the $to_email variable to contain your email address. So replace 'you@yourdomain.com' with your own email address, ensuring the double quotes are still kept around the email address.
  2. Edit the $redirect variable to contain the address, relative to the root, of your thank you page. So if your thank you page is found at http://www.yourdomain.com/contact/thankyou.html this value will become "contact/thankyou.html".
  3. Edit the $subject variable to contain the text you want to appear in your email subject when you receive an email from the form.
  4. Locate the line >!– Your Header HTML code or include goes here –< and replace it with your standard site header markup. This could be a PHP include to include the header file, or plain HTML markup.
  5. Locate the line >!– Your footer HTML code or include goes here –< and replace it with your standard site footer markup. Again, this can be a PHP include or the plain HTML markup.

This should then leave you with a file that has the following sections:

  • PHP Script
  • HTML Header markup
  • Form in the content area
  • HTML Footer markup

At this point you should be able to upload this file to any PHP enabled server, view the file, complete the form and submit it. An email should then come through to your specified email account.

Advanced Options

There's two advanced options in this form. The first is to add additional fields into the form, and they'll still be picked up in the email. To do this, edit the form to include your additional form fields (checkboxes and file uploads are not supported in this form) using the following method (if you're not sure on working with forms, read up on accessible form layouts):

Form Code Excerpt
  1. <div>
  2. <label for="cftext">Title: </label>
  3. <input type="text" name="cftext" id="cftext" size="30" value="<?php get_value('cftext') ?>" />
  4. </div>

Where text makes up your input's fieldname. I would recommend keeping 'cf' at the start of all of your fieldnames as this means there is less potential for variables to clash in the PHP and it can help to reduce spam as spammers will often assume your field names are the general ones of 'name', 'email', message' etc. Title is then the value displayed on the page, so the form label.

The second advanced option is to also control your required fields. Near the top of the script there is a line:

PHP Code Excerpt
  1. // Specify the required fields
  2. $req_fields = array("cfname", "cfemail", "cfmessage");

This array lists the fields that are required to contain content. So if you added 3 extra fields, eg. cfurl, cftelephone and cfaddress and you want to make the telephone and address field required, but not the url field, then you can add these in by adding them to the end of the comma delimited list i.e.

PHP Code Excerpt
  1. $req_fields = array("cfname", "cfemail", "cfmessage", "cftelephone", "cfaddress");

This will then check that both the telephone and address fields have content in them, however the URL field can be left blank. Of course it will be wise to add

HTML Code Excerpt
  1. <em>Required</em>

After the label title and before the closing label tag, as I've done with the other required fields.

Guarantees

There are none! The form is secure to the best of my abilities. It checks against email header injection, it removes all html tags that may have been entered into the form, it checks the name entered contains just typical characters that a name would contain (including foreign characters)*, it checks your required fields contain content and it will email all details plus the user's given IP address and browser details through to your specified email address. By using less than general field names, spam should be reduced to human spam (I use this method elsewhere and rarely get any spam off my forms that's not human generated).

The form is accessible in that when you click a label title the cursor will be placed in the input box or textarea. It uses the correct markup of a fieldset and legends, and if you choose to extend the form I recommend you continue with these standards. Suggested CSS for the styling of a form and error warning is below.

Suggested CSS Code
  1. ul.warning {
  2. color: #c00;
  3. font-weight: bold;
  4. }
  5.  
  6. fieldset {
  7. width: 500px;
  8. border:none;
  9. border-top: 1px solid #999;
  10. padding: 10px;
  11. margin-top: 10px;
  12. }
  13.  
  14. legend {
  15. font-weight: bold;
  16. padding: 0 5px;
  17. }
  18.  
  19. label {
  20. width: 125px;
  21. float: left;
  22. text-align: right;
  23. margin-right: 5px;
  24. }
  25.  
  26. form div {
  27. clear: both;
  28. margin-bottom: 10px;
  29. }

So give it a go and let me know what you think. Any problems or comments, post them below and I'll do my best to help out or accommodate you :)

* Only in the PHP 4.4+ version.

52 Responses to “Secure PHP Contact Form”

  1. Hello Sarah,

    Though basically a nice solution, there are some problems with the PHP 4.4+ version of the contact form as it stands. (I have not checked the other version.)

    1) The most serious of these actually prevents the form from working at all. The statement on line 74 should be if(empty($error_msg) — NOT if(!empty($error_msg). The line at present means the email will be built only if errors are present!

    2) Non-empty but visually blank fields, i.e., containing one or more spaces, are not trapped. This is easily fixed by trimming $value in the block of code starting at line 43.

    I hope these observations are helpful.

    By normanw on Sun, 23 March, 2008

  2. Hey Norman, thanks for your pointers. I must have stared at that code so much I started going cross eyed and didn't spot the additional exclamation mark in the if statement. I'd tested it then typically altered something and didn't think to retest. I knew I should have got a fresh set of eyes on it!

    I've altered the required fields check too to include the trim. Not sure why I missed that out, that was another addition, trying to make it as easy for non PHP users as possible.

    Thanks again, much appreciated :)

    By Sarah on Sun, 23 March, 2008

  3. This is the best script I have found for ease of use, but as a php newbie I have found one aspect of the script really frustrating.

    That aspect is the fact that the submit button returns a value in the emailed form.

    How to stop this? It's a minor problem I know, but I would love to get rid of the submit: Submit value at the end of the email.

    By Steven W on Mon, 15 September, 2008

  4. Hi Steven, I'll amend the file to remove the submit info. Give me 24 hours :)

    By Sarah on Mon, 15 September, 2008

  5. This is so nice, clean and simple to implement, thanks.
    I needed a quick contact form for an upcoming friends site, and this looks the business. I was thinking of adding captcha, but then you have the problems with accessibility.

    Thanks for sharing!

    By Ryan on Mon, 10 November, 2008

  6. You're welcome Ryan :)

    By Sarah on Mon, 10 November, 2008

  7. Hi
    I'm trying to implement a form in the autopull page.
    I tried with yours but I just can't make it work.
    How do I know if I can use php in the site?
    Because maybe that is the reason why the form does not work…
    Also the css, do I have to add it to the same file or can I use the same external sheet I use for the rest of the site (if so… where do I link it?)
    I have no idea of php, but I need to place a form and plain html will get me tons of spam :/

    By nimraithkar on Wed, 26 November, 2008

  8. To check if you can use PHP, create a simple PHP page eg. a blank file with

    <?php echo "Hello World" ?>

    in it and save it as hello.php. Upload this to your site and go to it. If you see 'Hello World' then it's worked. If you see all the code, then it hasn't.

    The CSS code would go in an existing stylesheet, or a new one. You'd link to it via the header of the page.

    But check on whether you can run PHP first. If you can't, contact your host and see if they can allow it for you as you're on Apache, so the server should be capable of running it :)

    By Sarah on Wed, 26 November, 2008

  9. I uploaded the hello.php file and the browser (FF) tries to open or save the file…
    but lately when I try to open a php file directly in the browser without uploading, it makes the same.
    But I used to open them like that and visualize the page and with the code in it.
    Anyway. If I can't see the php as I should then I will better contact the host as you say.
    Thanks a lot. I'll keep your code and try to use it latter.

    By nimraithkar on Wed, 26 November, 2008

  10. Hi there – I'd sure like to use an image for the submit button. Am a PHP newby so am not quite sure how to do this. Any idea? Thanks.

    By Karen on Fri, 28 November, 2008

  11. Hi Karen,

    To use an image you'll need to change the submit button to be of type image (see http://htmldog.com/reference/htmltags/input/ for how to do this).

    Then you'll need to change the line of PHP code that's currently

    if (isset($_POST['cfsubmit']) && trim($_POST['cfsubmit']) != "") :

    to check for cfsubmit_x as an image input sends co-ordinates i.e.

    if (isset($_POST['cfsubmit_x']) && trim($_POST['cfsubmit_x']) != "") :

    Hope that helps. Let me know if you have any problems or questions with it :)

    By Sarah on Sun, 30 November, 2008

  12. Hi Sarah,

    Great little script..just what I was after!

    I've edited the actual form and styled it all as I want but the 'thank you' page doesn't seem to work for me :(

    I'm using: $redirect = "thankyou.php";

    The file is in the dir and when I submit the email gets generated and arrives but the browser doesn't direct to the thank you page. Tried in both IE & FF.

    Any ideas?

    By awzm on Fri, 5 December, 2008

  13. Hi awzm. What happens when you submit the page. Does it display the form again or go to a blank page? What's the URL in the browser? If it has your thankyou.php file in the URL, is the URL correct, if not then you'll need to fix that. Otherwise, the other problem could be that you've managed to insert a space at the very top of the file, which would stop the redirect from working.

    However check the URL. If it's still the form's URL then the redirect isn't running so you need to check for white space or any output above the PHP, if it contains the thankyou.php in the URL, then you need to check that the path is correct.

    By Sarah on Sat, 6 December, 2008

  14. Very cool Sarah, thank you. Happy holidays…

    By Ned Eldredge on Fri, 12 December, 2008

  15. Thanks ever so much!!!!!

    By eddie on Wed, 17 December, 2008

  16. Hey Sarah–

    Thanks for the great script. I'm new to PHP and this is a great help.

    I just set this up and change the variables as necessary. I went to test it, and upon submission, I got an error saying that my name appears to be invalid. I just typed it in as Valerie Wininger. Any idea why this might happen? Thanks!

    By Valerie Wininger on Wed, 11 February, 2009

  17. Hi Valerie. What version of PHP are you running? You can check this by creating a file on your server with <?php phpinfo() ?> in it and going to it in your browser.

    By Sarah on Thu, 12 February, 2009

  18. Hello again–The server is running PHP 5.2.1.

    Thanks!
    Valerie

    By Valerie Wininger on Thu, 12 February, 2009

  19. Hi Valerie,

    Although it shouldn't be a problem, the only thing I can think of is that the 4.4+ version is causing the problem. Have you tried the 4.0+ version instead?

    By Sarah on Sat, 14 February, 2009

  20. Very nice tutorial. It's nice to see someone that actually explains along the way rather than just saying 'change this to this' without an explanation.

    I went to the link for Style:Phreak's form as you suggest and looked at the form there. Is your script easy to implement for that form? And, how difficult is it to incorporate 'captcha'?

    John

    By John on Sat, 21 February, 2009

  21. You specify that file uploads cannot be used. What changes would be necessary to allow them?

    Thanks for a great script!

    Steve

    By Steve on Sun, 22 February, 2009

  22. @John you could implement the Style:Phreak form yes. This script can easily be used as a starting point for any contact form if you understand the basics of PHP form processing. Again, a captcha can be integrated easily, however with all the checks in the form it's unlikely you would need one.

    @Steve You would need to add the enctype attribute to the form, add a file input box into the form and then upload it by accessing the $_FILE superglobal. Your best option is to have a look at the PHP function move_uploaded_file() as you'll probably find some code examples for that which will explain everything you need :)

    By Sarah on Wed, 25 February, 2009

  23. I'm in the process of rebuilding our site and have installed your form. It works great with no thank you page (other than a page not found error), but when I added a thank you page, I'm getting a nasty error that tells me I've messed up. Both the contact form page and the thank you page are in the same directory. This is the error:
    Warning: Cannot modify header information – headers already sent by (output started at D:\WWW\caravanbeads.net\wwwroot\test_site\pages\contact.php:9) in D:\WWW\caravanbeads.net\wwwroot\test_site\pages\contact.php on line 143

    Help greatly appreciated!
    bk

    By Barry on Sun, 29 March, 2009

  24. I should add that the forms are being submitted correctly; just the thank you page part is broken.

    The form submission I just noticed still includes this: cfsubmit: Submit
    as the last line.

    Thanks,
    bk

    By Barry on Sun, 29 March, 2009

  25. Hi Barry,

    The first error is due to output being on the page before the redirection comes in, so you'll need to check that you've not inserted any characters, including spaces, at the top of the file before the opening php tag.

    For the second issue, the submit is there because the submit button is clicked. You can stop this from coming through by going to line 78 in the code (or 78 in the original file), finding

    foreach ($formstuff AS $key => $value) :
    $message .= $key.": ".$value."\n\n";
    endforeach;

    and changing it to

    foreach ($formstuff AS $key => $value) :
    if ($key != "cfsubmit") :
    $message .= $key.": ".$value."\n\n";
    endif;
    endforeach;

    By Sarah on Sun, 29 March, 2009

  26. Hi Sarah,

    Great script, and I have got the form to work (mostly!) using the PHP 4.0 version.

    If I input info into a text field and then miss another in a required field and then click submit – I get the warning message okay, but in the text field that I have input info into instead of the text I get the following error message (without the quotes):-
    "Notice: Undefined variable: form_value in E:\domains\l\limousinlakes.co.uk\user\htdocs\contact\contact-form.php on line 113 "

    Any idea what is going wrong here?

    Many thanks for the script.

    Chris

    By Chris on Mon, 6 April, 2009

  27. Hi Chris, looks like I missed a bit in the get_value function. If you look at the end of the PHP code around line 110 (ish) you should see

    function get_value ($formvalue) {
    if (!empty($_POST[$formvalue])) :
    if (get_magic_quotes_gpc()) :
    $form_value = stripslashes($_POST[$formvalue]);
    endif;

    echo $form_value;
    endif;
    }

    change this to be

    function get_value ($formvalue) {
    if (!empty($_POST[$formvalue])) :
    if (get_magic_quotes_gpc()) :
    $form_value = stripslashes($_POST[$formvalue]);
    else :
    $form_value = $_POST[$formvalue];
    endif;

    echo $form_value;
    endif;
    }

    That should fix the problem. Cheers for letting me know.

    By Sarah on Mon, 6 April, 2009

  28. Great easy script for non-PHP expert. Only question I have is how can I remove the (aproximately) 1 px border that surrounds the form? Your time and efforts are greatly appreciated! :)

    By Renee on Wed, 15 April, 2009

  29. Okay, just figured out how to rid the border. One more favor? How can I move the Submit button to be centered under the TextArea? Right now it's way over to the left…I'm afraid no one will notice it. :)

    By Renee on Wed, 15 April, 2009

  30. To remove the fieldset border just use

    #contactformid fieldset { border: none }

    To move the submit button, target the submit button and give it a left margin eg.

    #cfsubmit { margin-left: 20px }

    By Sarah on Wed, 15 April, 2009

  31. great script! for some reason when I input an invalid email address, the fields don't stay filled in, though I assume they should with the get_value function.

    could it be that my site is on php 5?

    By keight on Sun, 26 April, 2009

  32. Hi keight, have you got the latest version of the script and did you check the comment a few above as I'd missed an else statement out of the get_value function. I think I've updated the download script but I'll check in the morning

    By Sarah on Tue, 28 April, 2009

  33. That was it! I checked my code after seeing that comment, but guess I didn't compare closely enough. Thanks!

    By keight Bergmann on Tue, 28 April, 2009

  34. Awesome form, and easily implemented for a PHP newbie. Thank you very much!

    By Chris on Wed, 27 May, 2009

  35. Any reason you can think of that the form would redirect properly on my localhost running php 5.2.8, but not redirect on my website host running 4.4.8. It sends the email properly, but does not redirect, just continues to display the form. No change in the address bar either.

    Thanks!

    By Steve on Thu, 11 June, 2009

  36. Hi Sarah,

    I am completely new to PHP and found your tutorial extremely easy to follow. I keep receiving the following error though at the bottom of the page which my contact form features on – PHP Notice: Undefined index: REQUEST_URI in D:\WebsiteFilePathGoesHere\contact-us.php on line 161. As a result the e-mail does not seem to be sending. Having undertaken some research I believe this may be something to do with IIS. Any ideas how to overcome this issue?

    Many thanks,

    Joe

    By Joe P on Wed, 15 July, 2009

  37. Hi Joe, yes IIS doesn't work with the REQUEST_URI setting for some reason. On line 161 you should find the form tag. look along until you see action="…" and delete everything between the double quotes. To save on validation then just replace with a # so you'll have action="#". Should fix the error :)

    By Sarah on Thu, 16 July, 2009

  38. Sarah, you are a star! Thank you.

    By Joe P on Fri, 17 July, 2009

  39. Hi Sara,

    There is a problem with the regular expression for the field name. I am Greek and for Greek names, the script refuse to validate this field. Except to delete this pattern, i wonder if you have any other solution.

    Sincerely,
    Giannis

    By Giannis on Thu, 6 August, 2009

  40. Hi Giannis, Unfortunately I can't suggest much for the Greek letters. The regular expression should in theory cover those letters in the PHP 4.4+ version which I assume you're trying to use, but obviously it doesn't. I would just suggest to remove the check on line 65.

    If you still wanted a check you would need to code a pattern to check the name entered against. In the PHP 4.0 version there is a simple english character check which you could maybe look at, or try looking on Greek PHP sites to look for a typical pattern to check if one or more words entered just contain letters.

    The idea behind the check is to prevent characters that shouldn't be in a name eg. numbers, the @ sign, punctuation characters etc.

    PS. In reply to your second comment, I didn't delete your first, it was just in the moderation queue.

    By Sarah on Fri, 7 August, 2009

  41. Hi Sarah (By the way you have one of my favorite names),

    Thank you for your reply.
    As a FeedBack, after a lot of coffee and happy boring reading, finally I found a working solution. So if anybody else cares to display correct Greek characters, here it is:

    First step:

    In Line 65, Find:
    if (!preg_match('/^[p{L}-.\' ]+$/u', $formstuff['cfname'])) :
    Then, Replace:
    if (!preg_match('/^[x{0370}-x{03FF}]{3,15}$/u', $formstuff['cfname'])) :

    //Comments for reading: This Regexp, allows only greek characters. The numbers between the brackets {3,15} allows only a range From 3 to 15 characters. I Added this as an extra security option, but it's optional and you can remove it though.

    Second step:

    In line 128, Find:
    ?>
    After, Add:
    meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    Third Step and happily the last one:

    In Line 89, Change:
    charset=ISO-8859-1n"
    To:
    charset=utf-8n";

    However, I strongly believe that steps 2 and 3 (UTF-8 encoding) are useful, not only for the Greek language, but for everyone as well, and would constitute a better universal solution for non-latin characters and problems which arising from the different encodings, in generally.

    As last words, I would like to thank you Sarah, for your nicely Contact script.
    PS. Regarding to my second message, I figured out what was happening only when I submitted my second message and I noticed the moderation queue. I apologize for that.

    Sincerely,
    Giannis

    By Giannis on Sun, 9 August, 2009

  42. Hi Giannis, thanks for posting your solution :)

    By Sarah on Fri, 21 August, 2009

  43. Hell Sarah,
    Maybe I got things backwards? I also tried another contact form and so far none work.
    http://greenharmonyhome.com/contact.html

    I'm so so with html and CSS but PHP is totally new. Any help to point me in the right direction would be great.

    Mark

    By Mark Vios on Sat, 22 August, 2009

  44. Hi Mark, how is it that the form doesn't work? First off I'd recommend removing the brackets from the file name. contact-form.php would be fine. I just tried a test and it redirected to a 404. You need a thankyou.html page there.

    Do you get the form results? Have you modified the top variables to add your email address in? It looks like it's working so without knowing what is and isn't working I can't suggest much more :)

    By Sarah on Sat, 22 August, 2009

  45. Hi Sarah,

    I appreciate all your work and the clear instructions you have provided.

    The only area I am tripping up is how to add the contact-form.php to my html file.

    I tried bringing the contact form in via an iFrame and that worked, but I can't style the text.

    In Dreamweaver I also tried Insert/Form/Method-Post/Action-Browsed and choose the contact-form.php form, but that didn't work either.

    There has to be simple HTML coding in the Dreamweaver HTML file, to bring in the form, but I cant find it.

    Can you help me?

    Thanks!

    By Marty on Thu, 24 September, 2009

  46. Hi Marty,

    The form is PHP and is virtually a self contained page, you just need to either add the HTML code for your header and footer around it, or put them into PHP includes and include them into the page.

    I wouldn't try merging this in Dreamweaver as it's a manually written page and Dreamweaver will most likely change something and prevent the form from working.

    Just above the form I have a comment saying 'insert your header or link to a header include here' and the same at the bottom for the footer. Put the relevant HTML that is required for the page layout/design at these two points and save it as contact.php (or something similar) and then it should be fine.

    By Sarah on Mon, 28 September, 2009

  47. Thanks Sarah,

    I got it to work by pasting all the code into my HTML page (later renamed as a .php page) at the point you indicate (ie. comment saying 'insert your header or link to a header include here'), but at that point the form showed up below my CSS styled page.

    I got it to work by cutting and pasting just the form ID (ie. <form id= ….etc.) and inserting where I wanted in my page. Yes worked!

    Thanks for the tip on PHP includes which I will look into.

    Thanks for the form. I like it as you showed me how to edit it to add new fields, and I learned a little more about php.

    Thanks again!

    Marty

    By Marty on Mon, 28 September, 2009

  48. Hi Sarah!

    I just found your great blog…and this script.

    I've got everything to work..and added a field.
    Got the form pasted over some graphics background I wanted..and moved the fields around a bit…and maybe that's the problem.?

    The script takes the entries, gives me the TY page…but I never receive notification back that a message was written.
    I have the host email set to forward message back to personal email. T

    he email address DOES work on its own…had the host check for problems. There are none.
    So…I just can't get the email to notify me of a message received by forwarded mail.
    It's not server side per the host…and again, the email forward works outside of the script.

    Any ideas? I've been beating my head against the wall all day on this.

    And CONGRATUALTIONS! on your recent marriage!

    Thanks ever so much…this looks to be such a terrific script.
    Cathy

    By Cathy on Mon, 7 December, 2009

  49. Hi Cathy,

    Moving the fields is fine. Changing the PHP will cause it to stop working. Have you tried the basic original file again to see if that works for you? If it does then obviously a change you've made has caused the problem. If it doesn't then possibly it's missing something that your hosting requires in the code.

    My guess is the original will probably work if it's set up correctly, so I'd need to see the code you're now using to see what's wrong with it.

    By Sarah on Tue, 8 December, 2009

  50. Hi Sarah
    The form works great. I have been trying to delete the border but cannot find where to insert the code. On a new site I am building I want to keep the border but shorten it so it fits the page width.
    Your help appreciated.

    By Daviy on Sun, 20 December, 2009

  51. Hi Daviy, do you mean the fieldset border? If so then you'll need to control the border size/look in your CSS stylesheet eg.

    #contactform fieldset {
    border: 1px solid #666;
    width: 400px;
    }

    which will control the colour and the width.

    By Sarah on Sun, 20 December, 2009

Trackbacks/Pingbacks

  1. PHP Contact Form Dissected, Part 1 :: Stuff by Sarah
Leave a Comment

Please use your real name or nickname. Spam names will be changed.