Spam Proof your Web Forms

Whether they be comment forms or contact forms, spam bots are crawling your website looking for forms to submit their links to. With comment forms this can be annoying to moderate and with contact forms, it can be annoying to receive nonsense emails designed to spam search engines. In most cases, these bots are “dumb” and are just submitting any form they find on the internet hoping something sticks. Because of this, there are several traps we can add to hopefully catch most of these bots and automatically filter out their junk.

One easy trap we can add is a fom element hidden by CSS. Humans won’t be able to see the element, but bots will find it in your form HTML and will submit something to it. Right there you will be able to distinguish a bot from a normal user and ignore the request.

<input type="text" name="email2" style="visibility: hidden;">
<?php if (!empty($_POST['email2'])) { return false; } ?>

Another check you can place is based on a “fingerprint” I detected from one seemingly popular spam bot. This particular bot would use your own domain in its email addresses. If it doesn’t make sense for someone within your organization to submit a form (such as a contact form) using your domain, you can ignore those posts.

<?php if (strpos($_POST['email'], 'YOURDOMAIN.COM') !== false) { return false; } ?>

Another trap we can use catches bots trying to hack your email forms. These bots will post mail headers to your email forms in an attempt to use your server to send out email spam. The way to catch these spam bots is to ensure that fields that should only be one line, particularly the email and subject fields, are in fact one line. This hack works by adding new lines into mail headers, and your form should be using one line text inputs for those fields. Any multi line data automatically gives away this attack.

<?php if (strpos($_POST['email'], "\n") !== false) { return false; } ?>

“Dumb” bots will also generally just crawl your pages to find forms, then submit to the form page using their own methods. More specifically, they won’t be actually submitting the page your form is on, they simply send their own request to make it seem like they did. This is useful to know for the next two traps.

The first trap is to use Javascript to insert elements into your form that the bot’s won’t know about. This is essentially the opposite of the first technique where we want bots to know about fields. In this case you can use Javascript to outut a real form field or hidden field that will be submitted when someone submits your form page, but not when a bot doesn’t use your form. The below code would go somewhere in between your <form></form> tags.

<script language="Javascript">document.write('<input type="text" name="Email"/>');</script>

The bot would never see this but you would expect to find it on your form page.

The next technique that takes advantage of the bots not actually submitting your form page is to set a session or cookie variable on the form page and verifying it in the submit code.

<?php
$strCode = md5($_SERVER['REMOTE_ADDR'] . date('YmdHms'));
session_start();
$_SESSION['check'] = $strCode;
?>

<input type="hidden" name="code" value="<?php echo $strCode; ?>"/>

Then on your form submit page you would check to see if the code field matched the session, like so:

<?php if ($_SESSION['code'] != $_POST['code']) { return false; } ?>

This method can be expanded upon so that the actual code isn’t being passed in the form, but pieces of it along with other identifying characteristics like User Agent. Your PHP code would then re-assemble the pieces to see if they matched the session. Another idea would be to set an expiration on the date, so that the form code is only valid for a certain period of time.

The following is an example of a page that employees several of the above techniques.

<?php
$strCode = md5($_SERVER['REMOTE_ADDR'] . date('YmdHms'));
session_start();
$_SESSION['code'] = $strCode;
?>

<html>

<head><title>Contact</title></head>

<body>

<form method="post" action="submitcontact.php">

<input type="hidden" name="code" value="<?php echo $strCode; ?>"/>

Name: <input type="text" name="Name"/><br/>
Email: <script language="Javascript">document.write('<input type="text" name="Email"/>');</script><br/>

<input type="text" name="Email2" style="visibility: hidden;"/>

Message: <textarea cols="40" rows="3"></textarea>

<input type="submit" value="Send"/>

</form>

</body>

</html>

And now the code that handles and validates your form:

<?php

Contact();

function Contact() {
 $strName = $_POST['Name'];
 $strEmail = $_POST['Email'];
 $strEmail2 = $_POST['Email2'];
 $strCode = $_POST['code'];
 
 // Catch Hidden Input
 if (!empty($strEmail2)) {
  return false;
 }
 
 // No Javascript Input?
 if (strlen($strEmail) < 1) {
  return false;
 }
 
 // Email Should be One Line
 if (strpos($strEmail, "\n") !== false) {
  return false;
 }

 // Email Shouldn't Be From Our Domain
 if (strpos($strEmail, 'infinetsoftware.com') !== false) {
  return false;
 }

 // Code Doesn't Match?
 if (empty($_SESSION['code']) || $_SESSION['code'] != $strCode) {
  return false;
 }
 
 // Passed All Tests, Carry on here...
}

?>

Other methods you can employ include Captchas like reCaptcha or tests like the Wordpress plugin Did You Pass Math? These methods are all traps to catch spam bots that crawl the internet and submit any form they find. If someone was determined to spam your particular site, some of these methods would easily be deafeted, but that little effort will deter almost all of the spam you will encounter.

Tags: ,
Posted in: Articles

Add AJAX to your PHP Login Form

One good place to sprinkle some AJAX functionality is your login forms. Login forms have two outcomes - either the user gets logged in and taken to protected area of your site or they get an error message. Why keep reloading your login page to show the user login errors when you can do it with Ajax?

We’ll use a simple login form for our example with a hardcoded username and password to keep things short. You’re on your own for adding the code to connect to your database to check login credentials.

First we’ll assume a basic, non AJAX PHP login page with the following code:

<?php
define('Username', 'ADMIN');
define('Password', 'ADMIN');
$strAction = $_GET['Action'];
if (strtoupper($strAction) == 'LOGIN') {
 TryLogin();
}
function TryLogin() {
 global $strUsernameVal, $blnLoginErr;
 $strUsernameVal = $_POST['Username'];
 $strPasswordVal = $_POST['Password'];
 if ($strUsernameVal == Username && $strPasswordVal == Password) {
  // Success
  header('Location: index.php');
 }
 else {
  // Invalid Login
  $blnLoginErr = true;
  return false;
 }
}
?>
<html>
<body>
<?php if ($blnLoginErr) { ?>
<p>Error: Invalid login details. Please try again.</p>
<?php } ?>
<form name="Login" method="post" action="login.php?Action=Login">
Username: <input type="text" name="Username" value="<?php echo htmlspecialchars($strUsernameVal); ?>"/><br/>
Password: <input type="password" name="Password"/><br/>
<input type="submit" value="Login">
</form>
</body>
</html>

This page will submit to itself and check the form login details against the defined username and password. If the credentials don’t check, it sets a global page error which is displayed when the page is displayed.

Now to add the Ajax part, we will be using the Prototype library and its Ajax classes. Download Prototype and include the script in the <head></head> section of your login page. Next add the following Javascript also to the head section of your page:

<script language="Javascript">
function TryLogin() {
 var objForm = document.forms['Login'];
 
 if (!objForm) {
  return true;
 }
 
 var strUsernameVal = objForm.elements['Username'].value;
 var strPasswordVal = objForm.elements['Password'].value;
 
 
 if (strUsernameVal.length < 1 || strPasswordVal.length < 1) {
  var strError = 'Please fill in all required fields.';
  alert(strError);
  return false;
 }
 
 var objParams = {
  method:'post',
  parameters: 'Username=' + strUsernameVal + '&Password=' + strPasswordVal
 }
 var objRequest = new Ajax.Request('ajaxlogin.php', objParams);
 return false;
}
</script>

This script grabs the login details from your login form and uses the Prototype Ajax class to post them to an Ajax login script appropriately named ajaxlogin.php. We will now link your login form to the Javascript TryLogin() function. Add the following code inside your <form> opening tag:

onSubmit="return TryLogin();"

This will direct your form to the Javascript function or fall back on the standard login if the Javascript is not supported.

You will now need to create a new PHP script called ajaxlogin.php with basically the same login function as login.php, only it will output Javascript that will be executed by the Prototype Ajax class. The following code should be the code for ajaxlogin.php.

<?php
define('Username', 'ADMIN');
define('Password', 'ADMIN');
header('Content-type: text/javascript');
TryLogin();
function TryLogin() {
 global $strUsernameVal, $blnLoginErr;
 $strUsernameVal = $_POST['Username'];
 $strPasswordVal = $_POST['Password'];
 if ($strUsernameVal == Username && $strPasswordVal == Password) {
  // Success
  echo("location.href='index.php';");
 }
 else {
  // Invalid Login
  echo("alert('Invalid login details. Please try again.');");
 }
}
?>

If you notice, the two key differences in this script than your original login page is where the ContentType is set to Javascript and the Javascript that is outputted on login success or failure. The Prototype Ajax class will execute this Javascript on your login page. Keep in mind that anything you want to send from this script must be outputted as Javascript.

The new login.php script would look like this:

<?php
define('Username', 'ADMIN');
define('Password', 'ADMIN');
$strAction = $_GET['Action'];
if (strtoupper($strAction) == 'LOGIN') {
 TryLogin();
}
function TryLogin() {
 global $strUsernameVal, $blnLoginErr;
 $strUsernameVal = $_POST['Username'];
 $strPasswordVal = $_POST['Password'];
 if ($strUsernameVal == Username && $strPasswordVal == Password) {
  // Success
  header('Location: index.php');
 }
 else {
  // Invalid Login
  $blnLoginErr = true;
  return false;
 }
}
?>
<html>
<head>
<title>Login</title>
<script language="Javascript" src="prototype.js"></script>
<script language="Javascript">
function TryLogin() {
 var objForm = document.forms['Login'];
 
 if (!objForm) {
  return true;
 }
 
 var strUsernameVal = objForm.elements['Username'].value;
 var strPasswordVal = objForm.elements['Password'].value;
 
 
 if (strUsernameVal.length < 1 || strPasswordVal.length < 1) {
  var strError = 'Please fill in all required fields.';
  alert(strError);
  return false;
 }
 
 var objParams = {
  method:'post',
  parameters: 'Username=' + strUsernameVal + '&Password=' + strPasswordVal
 }
 var objRequest = new Ajax.Request('ajaxlogin.php', objParams);
 return false;
}
</script>
</head>
<body>
<?php if ($blnLoginErr) { ?>
<p>Error: Invalid login details. Please try again.</p>
<?php } ?>
<form name="Login" method="post" action="login.php?Action=Login">
Username: <input type="text" name="Username" value="<?php echo htmlspecialchars($strUsernameVal); ?>"/><br/>
Password: <input type="password" name="Password"/><br/>
<input type="submit" value="Login">
</form>
</body>
</html>

You should now have a working Ajax powered login form. If Javascript is supported, the form will be submitted via Ajax to your ajaxlogin.php script, which will either direct the login user to the protected area of your site or alert them of invalid credentials. If Javascript is not supported, the old, boring login will be the fallback.

From here you will need to add the code to connect to your database for login credentials. You will also want to add the cookies or session code to actually log the user in. The script in its current state simply redirects the user on a successful login or alerts them of an unsuccessful one.

Tags: ,
Posted in: Articles

Scriptaculous AutoComplete with PHP

Looking to add an auto suggest box on your website that searches your database? This article shows you how to use the Scriptaculous Ajax.AutoCompleter with PHP and MySQL to build a database powered autosuggest box.
First make sure you have the Scriptaculous library downloaded and included in your webpage. After you have downloaded the library and placed it in your website’s folder, including it is as simple as adding the following script tags between your head tags.

<script src="prototype.js" type="text/javascript"></script>
<script src="scriptaculous.js" type="text/javascript"></script>

Now, on to create the autcompleter in your webpage. Add the following code in your page where the Autocompleter should appear:

<p>
<form>
<input type="text" name="q" id="Search" size="30"/>
<input type="submit" value="Search"/>
</form>
</p>
<div id="SuggestBox" style="border: 1px solid #808080; background-color: #FFFFFF;">&nbsp;</div>

The SuggestBox div is where the search results will appear. You don’t need to worry about CSS positioning, Scriptaculous will automatically display it appropriately below your suggest input.

You will now need to add some Javascript to your page to use the Scriptaculous AutoCompleter and link it to your form and suggest div. Place the following code at the end of your page to enable your autocompleter.

<script language="Javascript">
function AutoComp() {
  var myAutoCompleter = new Ajax.Autocompleter('Search', 'SuggestBox', 'autocompleter.php');
}
document.onLoad = AutoComp();
</script> 

This code creates a new Autocompleter and points it to the input with id “Search”, suggest div with id “SuggestBox”, and a PHP script named “autocompleter.php” located in the same folder on your site as the current page.

Now for the PHP/MySQL part of the article. Create the script named “autocompleter.php” as referenced above. Scriptaculous will use POST and the form input name to pass the search terms to your PHP script, so we will need to reference that for our search.

The following is an exampe of the PHP script you would use to search an “Articles” table in your database. Simply change the SQL as needed to search a different table.

<?php

$strSearchVal = $_POST['q'];
if (strlen($strSearchVal) < 1) {
 return false;
}
// Sanitize User Input for Security
$strSearchVal = mysql_real_escape_string($strSearchVal);
// Connect to your database here:
mysql_connect('localhost', 'user', 'pass') or die(mysql_error());
mysql_select_db('dbname');
$strSQL = 'SELECT ID, Name FROM Articles WHERE (Name LIKE \'%' . $strSearchVal . '%\')';
$result = mysql_query($strSQL);
echo '<ul>';
while ($arrThisRow = mysql_fetch_array($result)) {
 echo '<li>' . $arrThisRow['Name'] . '</li>';
}
echo '</ul>';
?>

And now you should have a working autocompleter powered by PHP and MySQL.

Tips:

  • You can better style the SuggestBox list with CSS.
  • When using the autocompleter as a search form, you can add links to the list items to take the user to the page when the item is selected, rather than simply populating the search input.

Tags: ,
Posted in: Articles