PHP Captcha Scripts and Tutorial with Arithmetic Question
- PHP Captcha Scripts and Tutorials
- PHP Captcha Scripts and Tutorial with Arithmetic Question
- PHP Captcha Scripts and Tutorial with Text Copying
- PHP Captcha Scripts and Tutorial with Simple Question Answering
- PHP Captcha Scripts and Tutorial with reCAPTCHA
- PHP Captcha Scripts and Tutorial with Google reCAPTCHA

PHP Captcha Scripts and Tutorial with Arithmetic Question

PHP Captcha Scripts and Tutorial with Text Copying

PHP Captcha Scripts and Tutorial with Simple Question Answering

PHP Captcha Scripts and Tutorial with reCAPTCHA

PHP Captcha Scripts and Tutorial with Google reCAPTCHA
This page is a tutorial on "PHP Captcha Scripts and Tutorial with Arithmetic Question". Our overall method is to use the PHP GD Library and a TrueType font and PHP to make captchas.
To be clear, you do NOT need write permissions to create captcha pictures with GD and display them and you do not need write permissions to store captcha pictures in MySQL and use our scripts to display them. (Happily, none of our captcha scripts require MySQL or any other database. However, even though the captcha aspect needs only PHP scripts and no database use, the part where the registrations store user data surely does need MySQL.) Using Google reCAPTCHA is the safest free way to do captchas, and it's popular as well as effective. But it's more fun to make your own captcha system, like the ones we supply.
The rest of this page assumes you wish to use our arithmetic captcha script, and that you are willing to use a TrueType font in the process. We dug up a TrueType font the same way you can: go to your WINDOWS folder and search. We found 389 files to choose from, such as times.ttf, comic.ttf, arial.ttf, etc. Put this and a few others in the folder your script is in so you can experiment. The hans.ttf file we found that is the Invite SF True Type Font bundled with Serif PagePlus (get at fonts101.com) was perfect for PHP Captcha Scripts and Tutorial with Text Copying. The Holisb__.ttf file we found that is the Holiday Springs BTN True Type Font (get at MyFonts.com) was perfect for our captcha-with-sessions.php captcha script, which is below.
Our PHP Captcha Scripts and Tutorial with Arithmetic Question script uses sessions to keep track of what user is doing what. It does not monitor how many login attempts the user has used. If you want that, use the code from the PHP Captcha Scripts and Tutorial with Text Copying script. We use the PHP GD Library and a TrueType font and PHP to create the captcha, which changes each time it is used. This type of captcha uses a simple arithmetic question in which the user is asked to solve what the result will be of either adding or subtracting a one digit number from a two digit number, like 56+9 or 84-3. There are 1638 possible puzzles, since the one digit numbers are limited to 1 through 9 and the two digit numbers are limited to 10 through 90. We know of no bots that are able to solve these puzzles, but there could be some either today or in a year or two. Or maybe not (?)
Okay, let's check out the scripts:
The first one is checkid.php. It merely starts/continues a session, then checks the sessionid. It was stored in the login-with-captcha.php script, so if we find it set now, the session is logged so we go on. Go on where? Well, at the bottom of this page we include this checkid.php script at the end of the captcha-with-sessions.php script so we can send the correct captcha answer back to the login-with-captcha.php script, since the captcha image used in that script is the captcha-with-sessions.php script run from the image tag in login-with-captcha.php. If you are hollering that we goofed and need to follow the sacred sessions rule of always starting them at the beginning of a script, we feel you. But it doesn't work—it merely creates errors to start a session at the start of a header('Content-Type: image/png') script, since these types of PHP pages have an even more sacred rule of always putting the image headers at the beginning of a script. So it gets down to a contest of two things that need to be first, and header('Content-Type: image/png') wins. In metaphysics, impenetrability is the name given to that quality of matter whereby two bodies cannot occupy the same space at the same time. Obviously the PHP gurus had this firmly in mind when they allowed us to start a session at the end of a PHP script (wink wink nudge nudge). The bottom line is it is the only way that worked, since we absolutely needed that variable created so our login script had access to the right captcha answer.
If the user did not visit the login script before encountering this checkid.php script, the session will be unset and destroyed and the user will be sent to the login script.
The next script is login-with-captcha.php, which is set up to be about logins but you could adjust it so it's about registering if the spirit moves you. It starts a session and then grabs the session id and stores it in a session variable—the same one we just tested in our checkid.php script.
Next we do some JavaScript input validation of the user's entered user name and password. PHP input filtering is better, but the page is set up to not allow the user to get to the login destination—administrator-page.php—unless JavaScript is turned on. The user may go around this (?) but will run into user name checking at that page, so why bother?
Now we include the configure.php file which has the magic words that allows the MySQL database to be interacted with. Then we grab the POSTed value entry, flag, username, password, and answer. In truth, once the password and username have been entered, the form that solicits these values POSTs the page right back to itself. The script then looks at whether this is the correct password and user name, and even whether or not such a user name exists. If the user has submitted the form, the $Entry flag will be set and his data will be located in the "members" table as long as this user name exists—a warning will pop up if it is not found, or if the username/password pair is invalid. Note that in checking through the "members" table for the record in which the user's user name matches the one entered into the form, we use MySQL's SELECT statement in PHP. The $N flag is set if their entry attempt is NO GOOD—which returns them to try again. $Z temporarily gets the table's users password to compare with their input.
Of course we recommend password hashing, salts, etc. but this script is just general login code focusing on captchas, not passwords. Login scripts with hashing are here: message-login.html, chat-room-login.html, forum-login.html, and blog-login.html, just to name a few.
The main point here is captchas, so we check if the answer the user gives is equal to the session variable $_SESSION['a__________a']). (Pretty cool variable name, right?) If it's correct and the user name and password match what we find in the members table, we send the user on to the administrator-page.php. How? And where? Simple—we use an extra form for that, which POSTs the user name and gets submitted via JavaScript. The administrator-page.php script is the action URL of that form.
So, "formpw" (its name) is the form that receives the user input for logging in. Note the hidden fields that are used to POST flags to the PHP POST function, requiring a page reload. It's very convenient that forms can send data to their own pages like this, since JavaScript cannot send data to PHP without POST, GET, or cookies. PHP, on the other hand, can send anything to JavaScript, on the same page as the PHP, with the use of JSON, or if it's simple numbers, without need of JSON. Note that JSON was used to get the POSTed username converted from its PHP variable $U. This value was stuck in the hidden field named username in the form named "MyForm" before submission.
Note the links to pages to help you recover lost user names or passwords. It's important to give users options if they forget something, and this automatic way requires no administrative work at your end, answering emails with "forgot password" stories of woe. Our site has scripts for not just that but tons more, if you look. There are links to http://www.css-resources.com/contact.html and http://www.css-resources.com/Administrator-PHP-Code-for-Multiple-PSB-Hosts.html which you will want to change to your own links. The link to "../index.html" is just a guess about where your Home page might be. Tweak it as needed.
Note that the captcha image used in this script is the captcha-with-sessions.php script run from the image tag in login-with-captcha.php:
<div style='margin:0px 0 0 30px'>
<IMG SRC="captcha-with-sessions.php" alt='captcha'>
</div>
It's nice to know that the HTML gurus don't mind a PHP script instead of an image file whose extension is png, jpg, or gif. It's sure convenient!
The next script was fun to write but we must confess that the "sessions at the end of the script" necessity threw us for quite a while! Who knew? The header('Content-Type: image/png') declaration limits what you can do in your PHP scripting as long as the created image is among the living. So, nuts to sessions and the echo() function while the image's heart is still beating. Once you drive a stake through it, you can program normally. Echo() is about outputting text to the browser screen. PHP doesn't like to see that you are outputting text if you told it you're outputting an image. But once the image is kaput, you may output normally. There may be a few restrictions because of that header, but sessions (after image destruction) is not one of them.
In the script, we are trying for a random captcha. So we use the PHP function mt_rand(). The mt_rand() function returns a random integer using the Mersenne Twister algorithm. The two numbers one usually puts into the parameters are the lowest and highest integers, inclusively, that you want the function to return. Our first two uses of the function give us the digits we will be adding or subtracting, while the third use is to get a number to help us decide whether we will add or subtract. So we stick "minus" or "plus" into $a, depending on whether the number is greater than 4, since we limited it to 0 through 9. So, depending on whether $a is "minus" or "plus", we add or subtract the numbers and put the result in $s. Then we build the captcha question and put this result in $w.
In informing PHP about our font choice, $font = 'Holisb__.ttf' is used. This assumes you loaded the font into the folder your script is in. We use the PHP GD Library function imagecreatetruecolor() after defining its size. Then we use the function imagecolorallocate() to define some RGB colors. We fill the image with gray using imagefill(). Then we use imageline() to draw a border. Next we use imagettftext() to draw the captcha text into the image using TrueType fonts. We output the image with imagepng(), then kill it in memory—but not its output in the browser—with imagedestroy().
We start up sessions, stick our correct captcha answer in our session variable $_SESSION['a__________a'], and that's it. The image is on the screen and out of memory and the correct answer is now available to the login-with-captcha.php script via that session variable, which we will be comparing with the user's input. So here are the three scripts:
The first script needed is: checkid.php
<?php
session_start();
if(!isset($_SESSION['sessionid'])){
session_unset();
session_destroy();
header('location: login-with-captcha.php');
}else{
// session logged
}
?>
The second script needed is: login-with-captcha.php
<?php
session_start();
$_SESSION['sessionid'] = session_id();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<TITLE>Login</TITLE>
<meta name="description" content="Login Script">
<meta name="keywords" content="Login Script,login,php,javascript, dhtml, DHTML">
<style type="text/css">
BODY {margin-left:0; margin-right:0; margin-top:0;text-align:left}
p, li {font:13px Verdana; color:black;text-align:left}
h1 {font:bold 28px Verdana; color:black;text-align:center}
h2 {font:bold 24px Verdana;text-align:center}
h3 {font:bold 15px Verdana;}
</style>
<script language="javascript">
function validatepassword(){
var ck_password = /^[A-Za-z0-9!@#$%^&*()_]{4,20}$/;
if (document.formpw.password.value.search(ck_password)==-1)
{alert("Please only enter letters, numbers and these for password: !@#$%^&*()_");return false}
var ck_username = /^[A-Za-z0-9_]{1,20}$/;
if (document.formpw.username.value.search(ck_username)==-1)
{alert("Please only enter letters, numbers and underline for user name.");return false}
return true;}
</script>
</head>
<body>
<?php
include_once"configure.php";
$Entry=$_POST['entry'];
$FLAG=$_POST['flag'];
$U=$_POST['username'];
$P=$_POST['password'];
$A=$_POST['answer'];
$N=0;
$Z='';
$_SESSION['username'] = $U;
if($Entry==1 && $A<>$_SESSION['a__________a']){echo '<script language="javascript">alert("Wrong captcha answer. Please try again.");window.location="login-with-captcha.php";</script>;';$N=1;unset($U);
}else{
if($Entry==1 && $A==$_SESSION['a__________a']){
$check_user_data = mysql_query("SELECT * FROM members WHERE username = '$U'") or die(mysql_error());
if(mysql_num_rows($check_user_data) == 0)
{echo '<script language="javascript">alert("This user name does not exist. Please try again.")</script>;';$N=1;unset($U);}
else {$get_user_data = mysql_fetch_array($check_user_data);}
}
if($N==0 && $Entry==1){$Z=$get_user_data['admin_password'];}
if($Z != $P && $Entry==1)
{echo '<script language="javascript">alert("Username/password pair is invalid. Please try again.")</script>;';$N=1;unset($U);}
if(($N==1||$Entry==0) && empty($FLAG)){ ?>
<h1>Login</h1>
<div id='pw' style='position:absolute;top:210px;left:200px;width:300px'><table style="background-color:#8aa;border-color:#00f" border='6' cellspacing=0 cellpadding=6><tr><td>
<form id='formpw' name="formpw" method="post" action="login-with-captcha.php" onsubmit="return validatepassword()">
<label for="User Name"><b>User Name: </b><input type="text" name="username" size="20" maxlength="30" value=""></label>
<label for="Password"><b>Password: </b><input type="password" name="password" size="20" maxlength="20" value=""></label><br><br>
<input type="hidden" name="flag" value="0">
<input type="hidden" name="entry" value="1">
<div style='margin:0px 0 0 30px'>
<IMG SRC="captcha-with-sessions.php" alt='captcha'>
</div>
<label for="Captcha answer"><b>Captcha answer: </b><input type="text" name="answer" size="20" maxlength="20" value=""></label>
<input type="submit" value="Submit">
<input type="reset" value="Reset"></form></td></tr></table>
</div>
<div id='pw' style='position:absolute;top:210px;left:570px;width:360px'><BR>
<a href="../index.html">Home</a><BR>
<a href="http://www.css-resources.com/contact.html">Contact us</a><BR>
<a href='forgot-password.php'>I forgot my password</a><BR>
<a HREF='forgot-user-name.php'>I forgot my user name</a><BR>
<a HREF="http://www.css-resources.com/Administrator-PHP-Code-for-Multiple-PSB-Hosts.html">Administrator PHP Code for Multiple PSB™ Hosts</a>
</div>
<?php
} else {
?>
<form name="MyForm" method="POST" action="administrator-page.php">
<input type="hidden" name="username" value=" ">
</form>
<script language="javascript">
var u = <?php echo json_encode($U); ?>;
document.MyForm.username.value=u;
document.MyForm.submit();
</script>
<?php
}}
?>
The third script needed is: captcha-with-sessions.php
<?php
header('Content-Type: image/png');
$r=mt_rand(10,90);$i=mt_rand(1,9);$d=mt_rand(0,9);
if($d>4){$a="minus";}else{$a="plus";}
if($a=="minus"){$s=$r-$i;}else{$s=$r+$i;}
$w="What is ".$r." ".$a." ".$i." ? ";
$font = 'Holisb__.ttf';//Holiday Springs BTN True Type Font (get at MyFonts.com)
$wide = 210;
$high = 41;
$picture = imagecreatetruecolor($wide,$high);
$gray = imagecolorallocate($picture,223,223,223);
$red = imagecolorallocate($picture,255,128,128);
imagefill($picture,0,0,$gray);
$black=imagecolorallocate($picture, 0, 0, 0);
imageline($picture, 0, 0, 0, $high, $black);
imageline($picture, 0, 0, $wide, 0, $black);
imageline($picture, $wide-1, 0, $wide-1, $high-1, $black);
imageline($picture, 0, $high-1, $wide-1, $high-1, $black);
imagettftext($picture, 20, 0, 11, 27, $red, $font, $w);
imagettftext($picture, 20, 0, 10, 26, $black, $font, $w);
imagepng($picture);
imagedestroy($picture);
include_once"checkid.php";
$_SESSION['a__________a'] = $s;
?>