Hey folks,
I was going to include a contact form on my website. Well, in the first place that seemed an easy thing to do with a form that prompts a PHP file validating the input vaiables and using it's mail () function to send the mail. However, as I got more into that topic I realized that one should be really concerned about the validation part to prevent spam abuse.
There are shiploads of 'mail scripts' available with each of them has it's pros and cons as widely discussed and even argued in various forums (e.g. an example on thescripts.com: http://www.thescripts.com/forum/thread640302-mail+form.html). With all that controversion about the mailform security issues I thought I'd start a forum thread that may help to understand relevant variable validation in a PHP driven contact mail form.
As an example I like to discuss the 'php from mailer' availabe on www.thedemosite.co.uk. It employs two files, an html file with the form including brief javascript validation for input data and as a second file php driven variable validation to prevent spam abuse through header injection.
The form and javascript validation part looks like this:
[HTML]
<form name="phpformmailer" action="contact.php" align="center" method="post">
<div align="center"><table>
<tr>
<td>Your name:</td>
<td ><input type="text" size="29" name="name"></td>
</tr>
<tr>
<td>* Your email address:</td>
<td ><input type="text" size="29"
name="email"></font></td>
</tr>
<tr align="middle">
<td>* Confirm email address:</td>
<td ><input type="text" size="29" name="email2"></td>
</tr>
<tr>
<td >* Subject:</td>
<td ><input type="text" size="29" name="thesubject"></td>
</tr>
<tr>
<td > <p>* Your request or query:</td>
<td ><textarea style="FONT-SIZE: 10pt" name="themessage" rows="7" cols="27"></textarea></td>
</tr>
<tr>
<td ></td>
<td ><script language="JavaScript"><!--
function validateForm()
{
var okSoFar=true
with (document.phpformmailer)
{
var foundAt = email.value.indexOf("@",0)
if (foundAt < 1 && okSoFar)
{
okSoFar = false
alert ("Please enter a valid email address.")
email.focus()
}
var e1 = email.value
var e2 = email2.value
if (!(e1==e2) && okSoFar)
{
okSoFar = false
alert ("Email addresses you entered do not match. Please re-enter.")
email.focus()
}
if (thesubject.value=="" && okSoFar)
{
okSoFar=false
alert("Please enter the subject.")
thesubject.focus()
}
if (themessage.value=="" && okSoFar)
{
okSoFar=false
alert("Please enter the details for your enquiry.")
themessage.focus()
}
if (okSoFar==true) submit();
}
}
// --></script><input type="button" value="Send" name="B1" ONCLICK="javascript:validateForm()">
You must fill in the fields marked with a *</td>
</tr>
</table>
</div>
</form>
[/HTML]
OK so far, I quite like the idea of checking whether all required fields are filled up with that little javascript function. At first check whether there is an email address with the variable 'foundAt'. Well, actually one might like to use even more validation and check the email address for accuracy using something like that instead:
var goodemail = email.value.match('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.
'@'.
'[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
'[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$')
if (goodemail == 1 && okSoFar) ...
So what's your impression 'bout that. Is it useful to check email address accuracy in detail, as we do not have any concern about any database issues? Anyway, it might be good thing to do. The remaining javascript code is selfevident.
Now the PHP code in the calling file that checks for spam abuse. It starts with three variables later on used to see whether the file was actually prompted from your website.
[PHP]
$valid_ref1="http://Your--domain/contact.html";
$valid_ref2="http://www.Your--domain/contact.html";
$replyemail="YOU@Your--domain";
[/PHP]
Then a function is defined validating header injection:
[PHP]
function clean_input_4email($value, $check_all_patterns = true)
{
$patterns[0] = '/content-type:/';
$patterns[1] = '/to:/';
$patterns[2] = '/cc:/';
$patterns[3] = '/bcc:/';
if ($check_all_patterns)
{
$patterns[4] = '/\r/';
$patterns[5] = '/\n/';
$patterns[6] = '/%0a/';
$patterns[7] = '/%0d/';
}
//NOTE: can use str_ireplace as this is case insensitive but only available on PHP version 5.0.
return preg_replace($patterns, "", strtolower($value));
}
$name = clean_input_4email($_POST["name"]);
$email = clean_input_4email($_POST["email"]);
$thesubject = clean_input_4email($_POST["thesubject"]);
$themessage = clean_input_4email($_POST["themessage"], false);
$error_msg='ERROR - not sent. Try again.';
[/PHP]
A confirmation text is outputed and a confirmation mail is send to the author of the message when the input passes this test and another one further down.
[PHP]
$success_sent_msg=' some message'
$replymessage='some message'
[/PHP]
Now the biscuits, what we wanted to do in the first place - send an email to the domain admin, support, CRM or what ever through the from. Again the PHP code checks for the email field to be set (see below) and if the form was actually submitted from your domain (here now are the three variables from the start kickin' in. If the referrer don't match you'll be asked to sent the form again, from the right site. If that's all right the mail to you and the inquiring person are sent and the webuser gets an message that verything was fine
[PHP]
if (!isset($_POST['email']))
{
echo "<script language=\"JavaScript\"><!--\n ";
echo "top.location.href = \"$valid_ref1\"; \n// --></script>";
exit;
}
$ref_page=$_SERVER["HTTP_REFERER"];
$valid_referrer=0;
if($ref_page==$valid_ref1) $valid_referrer=1;
elseif($ref_page==$valid_ref2) $valid_referrer=1;
if(!$valid_referrer)
{
echo "<script language=\"JavaScript\"><!--\n alert(\"$error_msg\");\n";
echo "top.location.href = \"$valid_ref1\"; \n// --></script>";
exit;
}
$themessage = "name: $name \nQuery: $themessage";
mail("$replyemail",
"$thesubject",
"$themessage",
"From: $email\nReply-To: $email");
mail("$email",
"Receipt: $thesubject",
"$replymessage",
"From: $replyemail\nReply-To: $replyemail");
echo $success_sent_msg;
[/PHP]
That's an awful lot of code to be posted here, but in comparison with other scipts it is actually quite few. To my rudimentary undestanding of programming and internet security I would assess it as: IT DOES THE JOB. But if I was without concern I wouldn't start a thread here and therefore 'd like to hear some of the advanced voices here on this php mailform.
Cheers,
Frank