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 ‘’ 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 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.


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. }
  6. fieldset {
  7. width: 500px;
  8. border:none;
  9. border-top: 1px solid #999;
  10. padding: 10px;
  11. margin-top: 10px;
  12. }
  14. legend {
  15. font-weight: bold;
  16. padding: 0 5px;
  17. }
  19. label {
  20. width: 125px;
  21. float: left;
  22. text-align: right;
  23. margin-right: 5px;
  24. }
  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.

You may also like...

72 Responses

  1. Renee says:

    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. 🙂

  2. keight says:

    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?

  3. Sarah says:

    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

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

  5. Chris says:

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

  6. Steve says:

    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.


  7. Joe P says:

    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,


    • Sarah says:

      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 🙂

  8. Joe P says:

    Sarah, you are a star! Thank you.

  9. Giannis says:

    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.


  10. Sarah says:

    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.

  11. Giannis says:

    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:

    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.


  12. Mark Vios says:

    Hell Sarah,
    Maybe I got things backwards? I also tried another contact form and so far none work.

    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.


    • Sarah says:

      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 🙂

  13. Marty says:

    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?


  14. Sarah says:

    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.

  15. Marty says:

    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!


  16. Cathy says:

    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.

    • Sarah says:

      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.

  17. Daviy says:

    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.

    • Sarah says:

      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.

  18. Ben says:

    Hi Sarah, I love this script – have used it a few times and it does exactly what I need it to do. 🙂

    I have replaced the submit button with a custom image for my latest site: but the resulting email is suffixed with:

    submit_x: 74

    submit_y: 18

    Is there any way to avoid this, or is it a necessary side effect of using an image submit button?

    Many thanks,


  19. Chris says:

    Hi Sarah, great contact form, it’s been very helpful, as I know very little about php.

    I’m trying to complicate things vastly by using jquery to submit the form without page refresh.

    I’ve separated the form from the php. I’ve got some usability verification going on. That’s all fine. The problem is when I submit the data. This is my .js

    var dataString = “name=”+ name + “&email=” + email + “&subject=” + subject + “&message=” + message;
    type: “POST”,
    url: “php/emailication.php”,
    data: dataString,
    error: function() {
    do some error stuff
    success: function() {
    do some success stuff

    It fails because I believe it can’t get past if (isset($_POST[‘cfsubmit’]) && trim($_POST[‘cfsubmit’]) != “”) :

    if I remove [‘cfsubmit’] it works fine. Any ideas what I need to add to get things working without removing it?

    On a similar theme, I’m wondering how I can show an error if the php has a verification error?

    I’m guessing I can leverage the $error_msg using error: function() { spit out $error_msg if it exists } but I’m not sure how.



    • Sarah says:

      Hi Chris, glad you like the form. Sorry for the late response.

      There’s no harm in removing the if statement from the additional PHP processing page. It’s only in the main page really, because otherwise it would try to submit the form on first load (which is obviously not what you want). However, if you would rather keep the PHP intact, then simply pass the cfsubmit value through in your dataString too or just pass a value of 1 through (which will satisfy the if condition).

      For the error, you would need to pass the error back to your jQuery and then get this written to a message div for example. I don’t usually use the .ajax method so I’m not familiar with passing errors back, however with the .post method in the PHP I set it to echo the error, and this is then captured by the jQuery, and then echoed out into a div for the user to see.

      I hope that helps 🙂

  20. Dustin says:

    I have got the form working to the extent that the “thank you, your message has been sent!” is displayed but I receive no messages in my inbox. I am using godaddy and I have heard people are having issues using godaddy.

    any suggestions, I am desperate!

    • Sarah says:

      Hi Dustin, you need to check if you can just simply send an email from your site first, and if you can’t then contact your host to get them to investigate.

      If you create a simple PHP page with just

      Change the to be your receiving email address, and the should be an email address on the server (sometimes servers won’t send email if the address isn’t known to it by way of pop3 or a forwarder).

      If no email arrives then it’s a server issue. If it does then check your settings in the script. Also check your error_log via FTP, if you have one, or your error logs in your control panel.

  21. Sara says:

    Hi Sarah, 🙂

    Guess what? I’m Sara too just without the (H)!

    Anyhow, now I’ve done with being cheesy… I have a question: If I were to implement this form and PHP code (I’m a total amateur so forgive any thick remarks that I may say :-S) would the form itself resize if I resize the browser window?

    The current form that I am using unfortunately spills the contact form outside my div layer if I resize the window – it also for some silly reason isn’t allowing me to resize the form table itself.

    Any suggestions on how/where I am going wrong and/if your form would be more suited for this?

    Sorry for rambling – thanks in advance!

    • Sarah says:

      Hi Sara, to allow a form to resize itself then it’s down to the CSS. You need to set up your form to be a percentage width of the containing div (eg. 95%) and then set your inputs, textareas etc. to be percentage widths too. Your existing form, if coded nicely, should be able to accommodate this, however if it’s coded using tables (not nicely!), then it would be best to redo the HTML.

      My form is coded using plain, modern markup and the CSS can be adjusted to do what you need, however if your form is quite restricted, you may find the rest of the site code could conflict too if it’s not really up to standard.

      So potentially you can do what you need with your existing form, but the HTML code may need adjusting to suit that.

  22. Chris says:

    Thanks Sarah,

    Ah, I thought the if statement was there to lock that php to that specific form as well as checking post/empty. Would I add “&cfsubmit=” + cfsubmit to the end of my datastring?

    I’m haven’t found a solution to $.ajax showing php echos so far. So you use $.post? Do you have an example of this in action?

    Another thing I’ve noticed is if I submit the form using a made up email address, no email is sent. Can you elaborate on why this is? I’m assuming it’s to do with the return-path?

    Thanks again, you’re very generous responding to all these queries.

  23. Sarah says:

    Hi Chris,

    Yes you could just add cfsubmit to the end as you suggested.

    I keep Remy Sharp’s jQuery API lookup bookmarked and it’s a great way to get a syntax reminder and/or examples – just look under P and you’ll find examples of the $.post

    If you’re using a made up email address then possibly your server is designed to look and see if that email address exists. If you look at my reply to Dustin above (about 2 or 3 comments up) you’ll see my explanation on this. Best option is to use real email addresses, and then if something doesn’t work, look into why. There’s an example in that comment to test your mail() function, if that works then the email should send 🙂

  24. Mandy says:

    Hi Sarah,

    Thank you for all of your hard work! I am getting this error after submitting: Warning: Cannot modify header information – headers already sent by (output started at /home/content/a/d/v/advanced1720/html/testingform.php:1) in /home/content/a/d/v/advanced1720/html/testingform.php on line 97.

    Looks like it has to do with the redirect to the thank you page. Any ideas?

    • Sarah says:

      Hi Mandy,

      You’ll be getting that error if something is being output on the page before all of the PHP processing occurs. So you need to make sure that there is no HTML or whitespace of any kind before the opening PHP tag.

      Let me know if that solves your problem 🙂

      • Mandy says:

        Maybe it’s a server issue, because I put both versions of your form up, unchanged except for my email, thank you page and subject. They both do the same thing. Strange :/

        Thanks for the suggestions!

    • Sarah says:

      Hi Mandy, according to your error there is output of some kind on line 1. This may be a whole blank line, a dot before the opening php tag, just anything. This isn’t a server issue as the error is saying that output has already started.

      You need to ensure that nothing at all is before that opening PHP tag. Possibly the upload is somehow corrupting? Can you check it on the server via a control panel file editor? If so I would do that too.

      Also, if the error still appears, open up the source code and see what is showing before the PHP error comes up as you may see either a character or space there.

      • Mandy says:

        Hi Sarah,

        I tried to view the source code, but you can’t see the PHP once it gets to
        the browser. I pulled the page off of the server and opened it in notepad
        and there is nothing before that opening line. I really appreciate your
        attention to my issue. If you get a chance, the url is I do get the
        emails, it just won’t redirect. I’m just not sure what i’m doing wrong
        here. Thanks!!


      • Sarah says:

        Hi Mandy, I’ve taken a look at that page and there’s no opening HTML or anything around the form? It’s looking very incomplete.

        I’ve put up a completepage version of the form at for you to copy and try. I’ve made one minor modification which may fix your problem too.

        Let me know if that works 🙂

        PS Steve you’re welcome to give that a try. If not drop me a link to your form and I’ll take a look for you 🙂

  25. Steve says:


    I have had a similar issue with the contact form on my site, and have searched diligently for an improper character to no avail. The form functions fine and redirects on my development server, but fails to redirect (although it sends the email) on my actual site. The only difference I can find is that the website runs an older version of PHP than my computer. I finally gave up and just accepted that everyone was going to email me twice before giving up.