Build Your Own Captcha and Contact Form

Build Your Own Captcha and Contact Form

Ever get hit with spam through the contact form on your personal site? Well, here is a short tutorial on how to build a custom captcha to keep the bad guys out.

Step 1: captcha.php and the Session

First we need to build a new PHP page and save it as captcha.php. Then, in out new script, open a server session by using the session_start() command. Also, code an empty variable named “string”. We will use this variable later to hold our randomly generated captcha text.

<?php

session_start();

$string = '';

?>

Step 2: Random String

Next, we need to write a for loop that will generate a random string. We will then take this random string and set it in a session variable called “random_code“.

<?php

session_start();

$string = '';

for ($i = 0; $i < 5; $i++) {
	$string .= chr(rand(97, 122));
}

$_SESSION['random_code'] = $string;

This for loop, you'll notice, adds a lower case ascii character, using the chr() function, to our $string variable on every pass. My example generates 5 characters, but you can adjust that number by changing "$i < 5" in the loop statement to something more custom, like "$i < 7". Once your loop is complete, make sure you define your session variable.

Step 3: Storage Folder and Colors

This is where the tutorial gets a little more complicated. Next we need to define a storage folder for the font we are going to use, build the base captcha image, and define the colors we'll use to fill our image. This is all simple code, but they're functions that don't get used often by developers.

$dir = 'fonts/';

$image = imagecreatetruecolor(170, 60);
$black = imagecolorallocate($image, 0, 0, 0);
$color = imagecolorallocate($image, 200, 100, 90); // red
$white = imagecolorallocate($image, 255, 255, 255);

Initially, I'm just defining the folder where my fonts are stored in the $dir variable. The $image variable, where we use the imagecreatetruecolor() function is the money spot. This is where the base captcha image is built using PHP. The function imagecreatetruecolor() returns an image identifier representing a black image of the specified size. As you can see, I'm making my image 170px wide by 60px tall.

Finally, in this step, I define some colors we can use in our final image. The numbers passed to the imagecolorallocate() function are RGB values.

Step 4: Building the Image

Next, we're going to fill our image with a white rectangle, which will act as the image background, and then add our random text string to the image.

imagefilledrectangle($image,0,0,200,100,$white);
imagettftext($image, 30, 0, 10, 40, $alt, $dir."arial.ttf", $_SESSION['rand_code']);

The imagefilledrectangle() function draws a rectangle in the specified image. The four numbers passed in the function represent coordinates for the corners of the rectangle. Make sure the rectangle you draw here is larger than the base image. You'll notice my rectangle is 200px wide and 100px tall.

The imagettftext() lets us add text to an image using True Type fonts. And you'll see that this function that can handle quite a few parameters. I'd like to highlight all of the different parameters in this function, but you'll only need to remember a few.

imagettftext($image, $font_size, $angle, $x, $y, $color ,$font_file ,$text);

Once you compare my example to the code immediately above, you'll see that the values passed to the imagettftext() function are easy to understand. First is the image, then font size, angle of the text, the x and y coordinates of the text (starting with the top left corner), text color, the location of the font file, and finally the text (our random string).

Step 5: Image Final

Next, with our script, we need to tell our browser what type of image we are using, with a header() function, and build the final image. These functions are so straight-forward, not much can be explained about them. Also, don't forget to close your PHP script.

header("Content-type: image/png");
imagepng($image);

?>

Once previewed in a browser, you script should generate a png image that contains some text. If you receive errors, make sure your script can link to your .ttf font file, and that you have created the empty $string variable from earlier in the tutorial.

This is what the final code for your captcha.php page should look like:

<?php
session_start();

$string = '';

for ($i = 0; $i < 5; $i++) {
	// this numbers refer to numbers of the ascii table (lower case)
	$string .= chr(rand(97, 122));
}

$_SESSION['rand_code'] = $string;

$dir = 'fonts/';

$image = imagecreatetruecolor(170, 60);
$black = imagecolorallocate($image, 0, 0, 0);
$color = imagecolorallocate($image, 200, 100, 90); // red
$white = imagecolorallocate($image, 255, 255, 255);

imagefilledrectangle($image,0,0,399,99,$white);
imagettftext ($image, 30, 0, 10, 40, $color, $dir."arial.ttf", $_SESSION['random_code']);

header("Content-type: image/png");
imagepng($image);
?>

Step 6: contact.php

Build a new PHP contact page and save it as contact.php. This page will contain our contact form that will validate using our captcha.

Step 7: HTML & CSS

Let's add an HTML form to our contact.php page. Pay particular attention to the image source we use for the random text.

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data">
	<p><input type="text" name="name" /></p>
	<p><input type="text" name="email" /></p>
	<p><textarea name="message"></textarea></p>
	<img src="captcha.php"/>
	<p><input type="text" name="code" /></p>
	<p><input type="reset" name="submit" value="Send" /></p>
</form>

You can also add the following bit of CSS to your page to make it look better than default.

<style type="text/css">
form {
	margin:0;
	padding:0;
}
input {
	padding:2px;
	width:200px;
}
textarea {
	padding:2px;
	width:200px;
	height:100px;
}
.button {
	width:60px;
}
p {
	margin:0 0 5px 0;
	padding:0;
}
.error {
	color:#FF0000;
	margin:0 0 10px 0;
}
.accept {
	color:#339966;
	margin:0 0 10px 0;
}
</style>

Step 8: Validate with PHP

Now that our form is built and we have out captcha image displaying, all we need to do now is validate our form, being sure to include some validation rules for out captcha.

Below is what the final validation PHP should look like. Two important features required for this validation process are session_start(); and the if($_POST['code'] == $_SESSION['rand_code']) elements. These allow us to access out session variable and check it against the text someone writes in the code field of our form. Without these, our captcha would be useless.

<?php
session_start();

if(isset($_POST['submit'])) {
	
	if(!empty($_POST['name']) && !empty($_POST['email']) && !empty($_POST['message']) && !empty($_POST['code'])) {
	
		if($_POST['code'] == $_SESSION['rand_code']) {
		
			// send email
			$accept = "Thank you for contacting me.";
		
		} else {
		
			$error = "Please verify that you typed in the correct code.";
		
		}
		
	} else {
	
		$error = "Please fill out the entire form.";
	
	}

}
?>

If you know much about PHP, the rest of this validation should be easy to understand. We are essentially looking to make sure none of our form fields are empty. If they are empty, errors are thrown to make sure our user inputs information. You'll also notice I am not validating whether the email is well formed, which is something your should should include. Email validation is done using regular expressions.

Here is what your final contact.php file should look like. I am including the CSS, which you may want to drop in its own CSS file.

<?php

session_start();

if(isset($_POST['submit'])) {
	
	if(!empty($_POST['name']) && !empty($_POST['email']) && !empty($_POST['message']) && !empty($_POST['code'])) {
	
		if($_POST['code'] == $_SESSION['rand_code']) {
		
			// send email
			$accept = "Thank you for contacting me.";
		
		} else {
		
			$error = "Please verify that you typed in the correct code.";
		
		}
		
	} else {
	
		$error = "Please fill out the entire form.";
	
	}

}

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Contact Us</title>
<style type="text/css">
form {
	margin:0;
	padding:0;
}
input {
	padding:2px;
	width:200px;
}
textarea {
	padding:2px;
	width:200px;
	height:100px;
}
.button {
	width:60px;
}
p {
	margin:0 0 5px 0;
	padding:0;
}
.error {
	color:#FF0000;
	margin:0 0 10px 0;
}
.accept {
	color:#339966;
	margin:0 0 10px 0;
}
</style>
</head>

<body>

<?php if(!empty($error)) echo '<div class="error">'.$error.'</div>'; ?>
<?php if(!empty($accept)) echo '<div class="accept">'.$accept.'</div>'; ?>

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data">
	<p><input type="text" name="name" /> Name</p>
	<p><input type="text" name="email" /> Email</p>
	<p><textarea name="message"></textarea></p>
	<img src="captcha.php"/>
	<p><input type="text" name="code" /> Are you human?</p>
   <p><input type="submit" name="submit" value="Send" class="button" /></p>
</form>

</body>
</html>

You're Done

Once your validation is working, your captcha contact form should be working great. What are your thoughts? Thanks so much for reading.


Tags: security
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://jacob.bearce.me Jacob Bearce

    Not sure that people are still commenting on this, but is there a way to make it pull the form fields from the page itself? I want to be able to add whatever form fields I add to the page dynamically instead of having to specify each field in the script. I build a ton of sites, so having something that’s adaptable is very important to me.

  • http://www.trica-jus.com/ tricajus

    thanks for sharing this tutorial. but i’m looking tutorial make web form with captcha for blogspot..

  • http://templatz.co Kev

    Not bad but one problem. It is not responsive design.

    Check out our Responsive Contact Forms With Image and Audio Security Captcha, six to choose from.

    http://templatz.co/contact-forms.php

    • nicob

      Your forms may be responsive but your website…well…a mother cat wont find her kittens in it

      • Kev

        That’s a good one. I have redesigned my site now and things are much easier to find.

    • Paul

      Not bad, but one problem. They’re not free,

    • bad

      your website is horrible

  • http://www.minicontent.com miniContent

    Thanks for sharing, this is what I am looking for!

  • steve

    I downloaded the source files and get a broken image when I upload to my server. Do I just need to put Arial.ttf font in the Font folder?

    • http://trippingcoolgroup.com axelcureno

      Yes you do have tu put the Arial.ttf in the font folder in order to get it work.

      • Neon

        Yes I put the arail.ttf font in the font folder but still broken image

  • http://www.nicob.co.za NicoB

    Please tell me how to send this form details to the clients email and auto respond to user. My php is beginner stage

  • gyit

    awesome tutorial! this was exactly what i was looking for….

  • http://net.tutsplus.com/tutorials/php/build-your-own-captcha-and-contact-form/comment-page-3/#comments Alex

    I cant get the image to show, there was no arial.ttf file in the font folder so I got one from somewhere else but still the image wont show ??

  • http://tworzeniewww4u.pl camelos

    but what if i have the same page with captcha on many tabs?
    only one page will work with this code

  • http://www.dreamspand.com/ Alpha Wolf

    Doesn’t work. I created a fonts folder and moved arial.ttf to it, but I get told that your image cannot be display because it contains image. I have everything done exactly as said to do. A fix would be nice.

    <?php
    session_start();
    $string = '';
    for ($i = 0; $i

    • sadpanda

      the captcha image works for, but it doesn’t validate for some reason

  • Chuck

    Zac;

    Thanks for such a great “captcha” alternative that is very easy to use. I am using it on my site, now.
    I have but one suggestion.

    You might want to convert the “code” from the user input to lowercase or the test will fail.

    if($_POST['code'] == $_SESSION['rand_code']) should be

    if(strtolower($_POST['code']) == $_SESSION['rand_code'])

    Without this: If the user inputs one or more capital letters, the form will not work.

    Thanks again,

    Chuck

  • Tom

    for some reason my cptcha image is broken? Do I need to have anything enabled for PHP on the server side?

    thanks

  • http://www.facebook.com/profile.php?id=100001970394698 Kul Rain Rine

    blank image shown