<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sneakybox Blog &#187; contact form</title>
	<atom:link href="http://sneakybox.com/blog/tag/contact-form/feed/" rel="self" type="application/rss+xml" />
	<link>http://sneakybox.com/blog</link>
	<description>Ramblings from the founder of Sneakybox...</description>
	<lastBuildDate>Thu, 18 Mar 2010 09:54:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>How to create a secure PHP contact form for your website</title>
		<link>http://sneakybox.com/blog/tutorial/secure-php-contact-form/</link>
		<comments>http://sneakybox.com/blog/tutorial/secure-php-contact-form/#comments</comments>
		<pubDate>Sun, 04 Oct 2009 22:13:59 +0000</pubDate>
		<dc:creator>Aaron Rice</dc:creator>
				<category><![CDATA[tutorial]]></category>
		<category><![CDATA[aaron]]></category>
		<category><![CDATA[contact form]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[secure contact form]]></category>

		<guid isPermaLink="false">http://sneakybox.com/blog/?p=35</guid>
		<description><![CDATA[I consider myself a very security conscious person. In fact, I&#8217;d say that I&#8217;m just a tin-foil hat away from paranoia. Naturally, when I wanted a way for clients to contact Sneakybox without having to write an email I was a little wary of keeping my PHP code secure. After all, Spammers would love access [...]]]></description>
			<content:encoded><![CDATA[<p><em>I consider myself a very security conscious person. In fact, I&#8217;d say that I&#8217;m just a tin-foil hat away from paranoia. Naturally, when I wanted a way for clients to contact Sneakybox without having to write an email I was a little wary of keeping my PHP code secure. After all, Spammers would love access to the PHP mail function on my web server. </em></p>
<p>  <em>In this tutorial I will show you how I stopped them getting their viagra pushing paws on my contact form as well and how to create one of your own.</em>
</p>
<p><span style="text-decoration: underline;"><strong>How the script works</strong></span>
</p>
<ol>
<li>User  ticks what service they are interested in, then submits their name, email address, phone number and any extra notes via a HTML form.</li>
<li>PHP script receives the submitted data</li>
<li>PHP script strips off any invalid characters.</li>
<li>Script makes sure the user&#8217;s IP address hasn&#8217;t posted a contact request in the past hour.</li>
<li>If everything checks out, the script compiles the received data in to an email using the PHP mail function and sends it to a specified email address.</li>
</ol>
<p>If the received data fails any of the checks the script will alert the user then exit.</p>
<h2>Step One: The boring HTML bit</h2>
<p>OK first we need to create our HTML form. I&#8217;m assuming you already have a basic grasp of HTML, otherwise you&#8217;re probably going to run in to some problems that aren&#8217;t covered in the tutorial&#8230;</p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;form action=&quot;contact_form.php&quot; method=&quot;post&quot;&gt;</div></div>
</pre>
<p>&nbsp;</p>
<p>The form tag contains our whole HTML form. We need to specify two parameters:</p>
<p style="padding-left: 30px; "><strong><u>Method</u></strong><u>: How we&#8217;d like to send our user&#8217;s data &#8211; Our options are GET or POST.</u></p>
<p style="padding-left: 30px; "><em>GET submits the user&#8217;s data as part of the URL. There&#8217;s a long standing myth that GET requests are limited to 256 characters. It&#8217;s not true. </em></p>
<p style="padding-left: 30px; "><em>POST submits data after the HTTP header, out of the user&#8217;s view. There are several reasons why we&#8217;re using POST in this case, but my official reasoning is that <a href="http://www.w3.org/2001/tag/doc/whenToUseGet.html#examples">W3C</a></em> recommends using POST to submit user data. We want to stay within W3C&#8217;s guidelines as much as possible.</p>
<p style="padding-left: 30px; "><strong><u>Action</u></strong><u>: Where to send the user&#8217;s data &#8211; We&#8217;re going to specify our PHP script&#8217;s location here. Let&#8217;s call it contact_form.php. Original eh?</u></p>
<p style="padding-left: 30px; "><em>It is possible to include the PHP script on the same page as the HTML but it&#8217;s good practice to keep them separate in that your HTML page is less cluttered it&#8217;s easier to make changes to either file.</em></p>
<p style="padding-left: 30px; ">
<p>Then it&#8217;s just a case of adding our form fields as below:</p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &lt;input name=&quot;contact_web&quot; type=&quot;checkbox&quot; value=&quot;Web Design&quot; /&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;label&gt;Web Design&lt;/label&gt;<br />
&nbsp; &nbsp; &lt;input name=&quot;contact_dev&quot; type=&quot;checkbox&quot; value=&quot;Web Development&quot; /&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;label&gt;Web Development&lt;/label&gt;<br />
&nbsp; &nbsp; &lt;input name=&quot;contact_media&quot; type=&quot;checkbox&quot; value=&quot;Media Production&quot; /&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;label&gt;Media Design&lt;/label&gt;<br />
&nbsp; &nbsp; &lt;input name=&quot;contact_name&quot; type=&quot;text&quot; value=&quot;Your name...&quot; /&gt;<br />
&nbsp; &nbsp; &lt;input name=&quot;contact_email&quot; type=&quot;text&quot; value=&quot;Your email address...&quot; /&gt;<br />
&nbsp; &nbsp; &lt;input name=&quot;contact_phone&quot; type=&quot;text&quot; value=&quot;A contact number...&quot; /&gt;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &lt;textarea cols=&quot;3&quot; rows=&quot;3&quot; name=&quot;contact_desc&quot;&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; If you have anything else to add, please do so here.<br />
&nbsp; &nbsp; &nbsp; &lt;/textarea&gt;<br />
&nbsp; &nbsp; &lt;input name=&quot;contact_submit&quot; type=&quot;submit&quot; value=&quot;Contact Me!&quot; /&gt;<br />
&nbsp; &nbsp; &lt;/form&gt;</div></div>
</pre>
<p>&nbsp;</p>
<p>One thing to note about adding form fields is that our script will identify each field using the <strong>name </strong>attribute, so it&#8217;s important to give every one a unique name.</p>
<h2>Step Two: The Database</h2>
<p>In order to stop people sending more than one request an hour we need to keep a database of user IP addresses and timestamps which we can reference when a request is made. A simple MySQL database will do the job.  Create a new database and paste the following  in to your MySQL query window of choice:</p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">CREATE TABLE `contact` (<br />
&nbsp; `ip` char(15) NOT NULL,<br />
&nbsp; `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP<br />
&nbsp; &nbsp;on update CURRENT_TIMESTAMP,<br />
&nbsp; PRIMARY KEY &nbsp;(`ip`)<br />
) ENGINE=MyISAM DEFAULT CHARSET=latin1;</div></div>
</pre>
<pre><span style="font-family: monospace;">
</span></pre>
<h2>Step Three: PHP</h2>
<p>OK now we&#8217;re all set up, it&#8217;s time for the PHP script! </p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;?php<br />
require_once 'htmlpurifier/library/HTMLPurifier.auto.php';<br />
$purifier = new HTMLPurifier();</div></div>
</pre>
<p></p>
<p>After starting the script with &lt;?php we&#8217;re basically saying <em>&quot;Make the HTMLPurifier functions available for use, and call them using $purifier.&quot; </em></p>
<p>HTMLpurifier is an awesome tool for cleaning up user input data to eliminate <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">XSS</a> attack threats. I highly recommend you use it when cleansing data coming from a user. <a href="http://htmlpurifier.org/">You can download it here</a>. Upload it to your web server then alter the above &#8220;require_once&#8221; line to match your path.</p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mysql_connect(&quot;server&quot;, &quot;username&quot;, &quot;password&quot;)<br />
or die(&quot;cannot connect to database.&quot; .mysql_error());<br />
mysql_select_db(&quot;database&quot;)<br />
or die(&quot;Cannot select Database:&quot; . mysql_error());</div></div>
</pre>
<p>&nbsp;</p>
<p>Next we need to define our MySQL database connection details. The first line is where you put your server info (normally localhost but check with your hosting provider), database username and password. The second line is where you define what database to use. Use the database you created the contact table in.</p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$clean_name = addslashes($purifier-&gt;purify($_POST['contact_name']));<br />
$clean_phone = addslashes($purifier-&gt;purify($_POST['contact_phone']));<br />
$clean_email = addslashes($purifier-&gt;purify($_POST['contact_email']));<br />
$clean_desc = addslashes($purifier-&gt;purify($_POST['contact_desc']));<br />
<br />
$clean_check_web = addslashes($purifier-&gt;purify( $_POST['contact_web'])) ;<br />
$clean_check_dev = addslashes($purifier-&gt;purify( $_POST['contact_dev']));<br />
$clean_check_media = addslashes($purifier-&gt;purify( $_POST['contact_media']));<br />
<br />
$clean_desc_wrapped = wordwrap($clean_desc, 100, &quot;\n&quot;, true);<br />
$ip= mysql_real_escape_string($purifier-&gt;purify($_SERVER['REMOTE_ADDR']));</div></div>
</pre>
<p>&nbsp;</p>
<p>Here&#8217;s our variables! We need somewhere to put the data that users send us, and we need to make sure it&#8217;s clean from dodgey characters when we do so. Each line is first adding an <a href = "http://en.wikipedia.org/wiki/Escape_character">escape character</a> with &#8216;addslashes&#8217; to any characters which could cause us XSS problems, then HTMLpurifier works its magic.</p>
<p>wordwrap is used to wrap the &#8216;extra&#8217; box text to a new line every 100 characters. &#8216;\n&#8217; is a newline character. We also pull the user&#8217;s IP address in the bottom line.</p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$body = &nbsp;<br />
&nbsp; &quot;A new web form contact request has been receieved:<br />
&nbsp; \n Name: &quot;.$clean_name.&quot;<br />
&nbsp; \n Phone Number: &quot;.$clean_phone.&quot;<br />
&nbsp; \n Email Address: &quot;.$clean_email.&quot;<br />
&nbsp; \n Interested registered in: <br />
&nbsp; \n&quot;.$clean_check_web.&quot;,<br />
&nbsp; &quot;.$clean_check_dev.&quot;,<br />
&nbsp; &quot;.$clean_check_media.&quot;<br />
&nbsp; \n&quot;.$clean_desc_wrapped;</div></div>
</pre>
<p>&nbsp;</p>
<p>Above is the body of the email that will be sent to us if the user is sucessful in their request. It&#8217;s a very simple mashup of all the variables used and a few new line characters. </p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">if ($clean_name &amp;&amp; $clean_phone &amp;&amp; $clean_email) {<br />
&nbsp; &nbsp; <br />
&nbsp; $check = mysql_query(&quot;<br />
&nbsp; SELECT timestamp FROM contact WHERE ip = '&quot;.$ip.&quot;';<br />
&nbsp; &quot;);<br />
&nbsp; if (mysql_num_rows($check)){<br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; $last_post = strtotime(mysql_result($check,0));<br />
&nbsp; $time_now = time();</div></div>
</pre>
<p>Here is where the important stuff starts happening:</p>
<ul>
<li> Obviously we dont want a user being able to send us a blank form, so we first say <em>&quot;If the variables clean_name, clean_phone, and clean_email exist (and are not empty in this case), move on&#8230;&quot;</em></li>
<li>Next we run an SQL query to see if there is a timestamp in our contact table that corresponds to the user&#8217;s IP address. We use mysql_num_rows to see if any results are returned. If a result is returned, move on&#8230;</li>
</ul>
<p>If there was a result, it means the user has already sent a contact request in the past. Great! Now we need to know how recently it was.</p>
<p>MySQL and PHP store timestamps in completely different formats. MySQL will generally store a timestamp like     &quot;2009-10-04 06:38:10&quot;, whereas PHP uses the UNIX format, such as   1254701898 &#8211; that&#8217;s the number of seconds that have passed since Jan 1st 1970! </p>
<p>Luckily for us, PHP has a great function to convert the easily read MySQL timestamp in to UNIX time. That&#8217;s the strtotime() line, above. We&#8217;re basically saying,<em> &quot;convert the timestamp found in the first row of the SQL query $check to UNIX time and place it in the last_post variable.&quot;</em></p>
<p>We then need to know what the current UNIX time is, by calling the time() function and placing it in the time_now variable.</p>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">if(($time_now - $last_post) &gt;= 3600 ) {<br />
<br />
&nbsp; mail('Sales@sneakybox.com', &quot;WEBSITE REQUEST FORM FROM $ip&quot;, $body);<br />
&nbsp; mysql_query(&quot;<br />
&nbsp; UPDATE contact SET timestamp = CURRENT_TIMESTAMP WHERE ip = '&quot;.$ip.&quot;';<br />
&nbsp; &quot;);<br />
&nbsp; echo &quot;Thanks! A memeber of our team will be in touch as soon as possible!<br />
&nbsp; &lt;a href = 'http://www.sneakybox.com'&gt;Back to Sneakybox&lt;/a&gt;&quot;;<br />
&nbsp; die;<br />
&nbsp; }<br />
&nbsp;<br />
else { <br />
<br />
&nbsp; echo &quot;You've already sent a request! <br />
&nbsp; If you'd like to add any further information please email<br />
&nbsp; &lt;a href = 'mailto:info@sneakybox.com'&gt;info@sneakybox.com&lt;/a&gt;&lt;br /&gt;<br />
&nbsp; &lt;a href = 'http://www.sneakybox.com'&gt;Back to Sneakybox&lt;/a&gt;&quot;;<br />
&nbsp; die;<br />
&nbsp; }</div></div>
</pre>
<p>Here&#8217;s our spam-stopper! We&#8217;ll take the time the user last made a request in seconds, and subtract it from the current time. If the remaining seconds are over 3600, or one hour, let the user send another request. If not, let them know that they&#8217;ve got to wait longer or send an email directly.</p>
<p>If the user has waited an hour since their last post, we need to:</p>
<ul>
<li>Send our contact request via the PHP mail function. Assuming your webhost has this set up, it will automatically send an email to the defined email address, using the defined subject, with the defined body &#8211; in that order.</li>
<li>Update our contact table entry for the current user&#8217;s IP address with the current timestamp using an SQL query. &#8216;CURRENT_TIMESTAMP&#8217; is a built in MySQL function. It does what it says on the tin.</li>
<li>Let the user know they were sucessful in their request.</li>
<li>Kill the script.</li>
</ul>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; }<br />
&nbsp; else {<br />
&nbsp; &nbsp; mail('Sales@sneakybox.com', &quot;WEBSITE REQUEST FORM FROM $ip&quot;, $body);<br />
&nbsp; &nbsp; mysql_query(&quot;<br />
&nbsp; &nbsp; INSERT INTO contact(timestamp,ip) VALUES(CURRENT_TIMESTAMP,'&quot;.$ip.&quot;');<br />
&nbsp; &nbsp; &quot;);<br />
&nbsp; &nbsp; echo &quot;<br />
&nbsp; &nbsp; Thanks! A memeber of our team will be in touch as soon as possible! <br />
&nbsp; &nbsp; &lt;a href = 'http://www.sneakybox.com'&gt;Back to Sneakybox&lt;/a&gt;&quot;;<br />
&nbsp; &nbsp; die;<br />
&nbsp; }</div></div>
</pre>
<p>The first &#8216;}&#8217; is to close the IF statement that checks whether the current user has posted a contact request before. If they haven&#8217;t:</p>
<ul>
<li>We can safely send the user&#8217;s request in the same way as above.</li>
<li>We also need to add this information to our contact table. However, as the IP address hasn&#8217;t been in the table before we need to run an SQL &#8216;insert&#8217; query rather than an &#8216;update&#8217;. We&#8217;re inserting the user&#8217;s IP address in to the table along with the current time.</li>
<li>Let the user know they were sucessful.</li>
<li>Kill the script.</li>
</ul>
<pre>
<div class="codecolorer-container text dawn" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">}<br />
echo &quot;<br />
Sorry, All fields in the form are required <br />
Our Javascript validator should have picked this up before <br />
submitting but it looks like you have javascript disabled. <br />
&lt;a href = 'http://www.sneakybox.com'&gt;Back to Sneakybox&lt;/a&gt;&quot;;<br />
die;<br />
?&gt;</div></div>
</pre>
<p>The &#8216;}&#8217; is to close off the first IF statement. The one that makes sure the submitted user fields aren&#8217;t blank, remember?</p>
<p>If the user didn&#8217;t meet these conditions, let them know then die. Done!</p>
<p><a href="http://www.sneakybox.com/tutorials/aaron1/contact_form.txt">You can download the full PHP script here.</a></p>
<p>If you have any questions etc please let me know in the comments. </p>
<p>Aaron</p>
]]></content:encoded>
			<wfw:commentRss>http://sneakybox.com/blog/tutorial/secure-php-contact-form/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
	</channel>
</rss>
