PHP Security Pt 4 Set Up Captcha

PHP Set Up CaptchaIn this video / article on PHP Security I will show you how to create more secure new user registration scripts. I’ll show you how to:

  • Fight off SQL Injection by thinking about your queries
  • Set up a CAPTCHA system that will protect you from brute force attacks
  • Lock down authentication hacks by forcing proper user ids and passwords

This is a continuation of the code we created in PHP Security Pt 2. You should watch that video before you proceed. You will also find it easier to follow along if you print out the code that follows the video below.

The page where you can get the Captcha code is here reCaptcha. The code that follows the video is much more secure and you can use it however you like. I’m not claiming it is 100% secure, just that it is much more secure than most registration scripts I have seen.

If you have any questions or comments leave them below.

Code From the Video

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
<html xmlns=”” lang=”en” xml:lang=”en”>
<meta http-equiv=”Content-Type” content=”text/html; charset=ISO-8859-1″ />
<div id=”main”>
if (isset($_POST[‘submitted’])) { // Handle the form.
// Check for a first name.
// Unquote a quoted string with stripslashes
if (preg_match (‘%^[A-Za-z\.\’ \-]{2,15}$%’, stripslashes(trim($_POST[‘first_name’])))) {
$fn = escape_data($_POST[‘first_name’]);
} else {
$fn = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter your first name!</font></p>’;
// Check for a last name.
if (preg_match (‘%^[A-Za-z\.\’ \-]{2,30}$%’, stripslashes(trim($_POST[‘last_name’])))) {
$ln = escape_data($_POST[‘last_name’]);
} else {
$ln = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter your last name!</font></p>’;
// Check for an email address.
if (preg_match (‘%^[A-Za-z0-9._\%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$%’, stripslashes(trim($_POST[’email’])))) {
$e = escape_data($_POST[’email’]);
} else {
$e = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid email address!</font></p>’;
// Check for a street.
if (preg_match (‘%^[A-Za-z0-9\.\’ \-]{5,30}$%’, stripslashes(trim($_POST[‘street’])))) {
$s = escape_data($_POST[‘street’]);
} else {
$s = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter your street address!</font></p>’;
// Check for a city.
if (preg_match (‘%^[A-Za-z\.\’ \-]{2,25}$%’, stripslashes(trim($_POST[‘city’])))) {
$c = escape_data($_POST[‘city’]);
} else {
$c = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid city!</font></p>’;
// Check for a state.
if (preg_match (‘%^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N{CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$%’, stripslashes(trim($_POST[‘state’])))) {
$st = escape_data($_POST[‘state’]);
} else {
$st = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid state!</font></p>’;
// Check for a zip code.
if (preg_match (‘%^[0-9]{5}$%’, stripslashes(trim($_POST[‘zip’])))) {
$z = escape_data($_POST[‘zip’]);
} else {
$z = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid 5 digit zip code!</font></p>’;
// Check for a phone number.
// ‘)”;delete from users where user_id=”9″;
if (preg_match (‘%^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})$%’, stripslashes(trim($_POST[‘work_phone’])))) {
$ph = escape_data($_POST[‘work_phone’]);
} else {
$ph = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid phone number!</font></p>’;
// Check for a valid userid
if (preg_match (‘%\A(?=[-_a-zA-Z0-9]*?[A-Z])(?=[-_a-zA-Z0-9]*?[a-z])(?=[-_a-zA-Z0-9]*?[0-9])\S{8,}\z%’, stripslashes(trim($_POST[‘userid’])))) {
$ui = escape_data($_POST[‘userid’]);
} else {
$ui = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid userid!</font></p>’;
// Check for a password and match against the confirmed password.
if (preg_match (‘%\A(?=[-_a-zA-Z0-9]*?[A-Z])(?=[-_a-zA-Z0-9]*?[a-z])(?=[-_a-zA-Z0-9]*?[0-9])\S{8,}\z%’, stripslashes(trim($_POST[‘password1’])))) {
if (($_POST[‘password1’] == $_POST[‘password2’]) && ($_POST[‘password1’] != $_POST[‘userid’])) {
$p = escape_data($_POST[‘password1’]);
} elseif ($_POST[‘password1’] == $_POST[‘userid’]) {
$p = FALSE;
echo ‘<p><font color=”red” size=”+1″>Your password cannot be the same as the userid!</font></p>’;
} else {
$p = FALSE;
echo ‘<p><font color=”red” size=”+1″>Your password did not match the confirmed password!</font></p>’;
} else {
$p = FALSE;
echo ‘<p><font color=”red” size=”+1″>Please enter a valid password!</font></p>’;
// PHP Code for the CAPTCHA System
$captchchk = 1;
$privatekey = “Your-Private-Key”;
$resp = recaptcha_check_answer ($privatekey,
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
echo ‘<p><font color=”red” size=”+1″>The CAPTCHA Code wasn\’t entered correctly!</font></p>’;
$captchchk = 0;
if ($fn && $ln && $e && $p && $fn && $s && $c && $st && $z && $ph && $ui && $captchchk) { // If everything’s OK.
// Make sure the userid is available.
$query = “SELECT user_id FROM users WHERE userid=’$ui'”;
$result = mysql_query ($query) or trigger_error(“Sorry there is an account assigned to that userid”);
if (mysql_num_rows($result) == 0) { // Available.
// Create the activation code.
// Create a random number with rand.
// Use it as a seed for uniqid, which when set to true generates a random number 23 digits in length
// Use it to seed md5 that creates a random string 32 characters in length
$a = md5(uniqid(rand(), true));
// Add the user. By entering values in a different order from the form sql injection can be limited
$query = “INSERT INTO users (email, pass, first_name, last_name, active, registration_date, street, city, userid, zip, work_phone, state) VALUES (‘$e’, SHA(‘$p’), ‘$fn’, ‘$ln’, ‘$a’, NOW(), ‘$s’, ‘$c’, ‘$ui’, ‘$z’, ‘$ph’, ‘$st’)”;
// By using mysql_query I can make sure only one query is submitted blocking sql injection
// Never use the php multi_query function
$result = mysql_query ($query) or trigger_error(“Sorry an error occurred and the account could not be created”);
// Check that the effected rows was equal to 1 in the last query. Should log if greater than
if (mysql_affected_rows() == 1) { // If it ran OK.
// Send the email.
$body = “Thank you for registering. To activate your account, please click on this link:<br />”;
// mysql_insert_id() retrieves the value of the last auto_incremented id
// Attach the random activation code in the link sent to the email
$body .= “http://localhost/activate.php?x=” . mysql_insert_id() . “&y=$a”;
mail($_POST[’email’], ‘Registration Confirmation’, $body, ‘From:’);
// Finish the page.
echo ‘<br /><br /><h1>Thank you for registering! A confirmation email has been sent to your address. Please click on the link in that email in order to activate your account.</h1>’;
} else { // If it did not run OK.
echo ‘<p><font color=”red” size=”+1″>You could not be registered due to a system error. We apologize for any inconvenience.</font></p>’;
} else { // The email address is not available.
echo ‘<p><font color=”red” size=”+1″>That email address has already been registered. If you have forgotten your password, use the link to have your password sent to you.</font></p>’;
} else { // If one of the data tests failed.
echo ‘<p><font color=”red” size=”+1″>Please try again.</font></p>’;
// mysql_close(); // Close the database connection.
} // End of the main Submit conditional.
<form action=”register2.php” method=”post”>
<p><b>First Name:</b> <input type=”text” name=”first_name” size=”15″ maxlength=”15″ value=”<?php if (isset($_POST[‘first_name’])) echo $_POST[‘first_name’]; ?>” /></p>
<p><b>Last Name:</b> <input type=”text” name=”last_name” size=”30″ maxlength=”30″ value=”<?php if (isset($_POST[‘last_name’])) echo $_POST[‘last_name’]; ?>” /></p>
<p><b>Email Address:</b> <input type=”text” name=”email” size=”40″ maxlength=”40″ value=”<?php if (isset($_POST[’email’])) echo $_POST[’email’]; ?>” /> </p>
<p><b>Street:</b> <input type=”text” name=”street” size=”40″ maxlength=”40″ value=”<?php if (isset($_POST[‘street’])) echo $_POST[‘street’]; ?>” /> </p>
<p><b>City:</b> <input type=”text” name=”city” size=”25″ maxlength=”25″ value=”<?php if (isset($_POST[‘city’])) echo $_POST[‘city’]; ?>” /> </p>
<p><b>State:</b> <input type=”text” name=”state” size=”2″ maxlength=”2″ value=”<?php if (isset($_POST[‘state’])) echo $_POST[‘state’]; ?>” /> <small>Use only the two letter initials</small></p>
<p><b>Zip Code:</b> <input type=”text” name=”zip” size=”5″ maxlength=”5″ value=”<?php if (isset($_POST[‘zip’])) echo $_POST[‘zip’]; ?>” /> </p>
<p><b>Phone:</b> <input type=”text” name=”work_phone” size=”20″ maxlength=”20″ value=”<?php if (isset($_POST[‘work_phone’])) echo $_POST[‘work_phone’]; ?>” /> </p>
<p><b>User ID:</b> <input type=”password” name=”userid” size=”20″ maxlength=”20″ /> <small>Must contain a letter of both cases, a number and a minimum length of 8 characters.</small></p>
<p><b>Password:</b> <input type=”password” name=”password1″ size=”20″ maxlength=”20″ /> <small>Must contain a letter of both cases, a number and a minimum length of 8 characters.</small></p>
<p><b>Confirm Password:</b> <input type=”password” name=”password2″ size=”20″ maxlength=”20″ /></p>
$publickey = “Your-Public-Key”; // you got this from the signup page
echo recaptcha_get_html($publickey);
<div align=”center”><input type=”submit” name=”submit” value=”Register” /></div>
<input type=”hidden” name=”submitted” value=”TRUE” />

18 Responses to “PHP Security Pt 4 Set Up Captcha”

  1. Bill says:

    I have been working to get the login scripts working to provide a secure login area on my sites. I thought I had it when I completed the registration form and received the email. This line in the above script references a file I did not find in your zip file:
    // Attach the random activation code in the link sent to the email
    $body .= “http://localhost/activate.php?x=” . mysql_insert_id() . “&y=$a”;

    Do you have a link to the activate.php file?

    • admin says:

      I’m traveling right now and don’t have access to my computer. As soon as I can I’ll send you that script.

      • Bill says:

        Have you located the activate script?

        • admin says:

          Here is the code that would be needed to activate the account. Make sure you change the backquotes into normal quotes in the code below with a find and replace

          0) && (strlen($y) == 32)) {

          $query = “UPDATE users SET active=NULL WHERE (user_id=$x AND active='” . escape_data($y) . “‘) LIMIT 1”;

          $result = mysql_query ($query) or trigger_error(“Query: $query\nMySQL Error: ” . mysql_error());

          // Print a customized message.

          if (mysql_affected_rows() == 1) {

          echo “Your account is now active. You may now log in.”;

          } else {

          echo ‘Your account could not be activated. Please re-check the link or contact the system administrator.’;


          // mysql_close();

          } else { // Redirect.

          // Start defining the URL.

          $url = ‘http://’ . $_SERVER[‘HTTP_HOST’] . dirname($_SERVER[‘PHP_SELF’]);

          // Check for a trailing slash.

          if ((substr($url, -1) == ‘/’) OR (substr($url, -1) == ‘\\’) ) {

          $url = substr ($url, 0, -1); // Chop off the slash.


          // Add the page.

          $url .= ‘/index.php’;

          ob_end_clean(); // Delete the buffer.

          header(“Location: $url”);

          exit(); // Quit the script.

          } // End of main IF-ELSE.

          • bryan says:

            First – awesome tutorials. thanks for taking the time to do this.

            Secondly – is there a complete activation.php anywhere on the site or can you help out with what was cut from the script above?

            • admin says:

              Thank you. I have all of the code in that tutorial series. It works, but you have to change all of the back quotes into normal quotes because of a past security system I used.

  2. Bill says:

    Thank you. The front of the script seems to be missing, but I think I have it all now.

  3. Ura says:

    Thank you for all your tutorials.

    I used your php security code to verify my text fields (such as pass, username, first name) in the form, it works, BUT after it verifies the first text field in the form it submits the form without checking and making sure if the rest of the field are OK.

    And One more question? do you need to bee on the server to verify email conformation or you
    can do this on MAMP?

    Can you help?

    Thank You

    • admin says:

      Sorry I don’t use MAMP. I always wondered why Mac users use MAMP? Apache, mysql, and everything else is installed by default without MAMP. Your web server is located at /Library/WebServer/Documents on all Macs as far as I know

  4. Ura says:

    Do you have a tutorial how to make them work, because i tried several times to make mysql to work and it does not seems to wont cooperate with me.

  5. Ura says:

    Hello I was wondering is the any extra security required when you let the visitors upload pictures, vidioes
    And if yes if you please make a tutorial about.

    I would really appreciate that.

    By the way your tutorials are very usefull,
    I would say I am new to web development
    And I learnning alot from your tutorials.

    Thank you.

    • admin says:

      If you allow people to upload anything to your site you’re creating a potential security issue. Anything uploaded must undergo a name change, it has to be secured in a folder that has no access to important information on your server. You then must refer to it using a completely different hard to guess name from there after.

      I plan to cover how you can verify that an image really is an image in the future. I’ll also cover how to secure uploads. An encryption tutorial is also in the works

  6. Dave says:

    Derek, do you have a pagination tutorial with a form enabling the end user to search for a particular item. The reason I ask is I have the pagination sorted and working and in a separate project I have the search form working but I cannot seem to integrate the two. If you havent got a tutorial on this maybe you would consider it for a future project? Thanks

    • Derek Banas says:

      I’m sorry, but I haven’t made a pagination tutorial aside from what I did with the tools used in wordpress. I’m planning on making a pHP tutorial that lives up to the standards of my Java tutorial. I have to finish my Java tutorial first though. I’ll do my best to slip in that tutorial if possible

  7. violentzani says:

    I have to say that you are giving so much help in developing our skills in web programming… Thanx a lot . RESPECT 🙂

  8. JW says:

    Where do I type in the code for changing permission of recaptchalib.php?

    “Subo chmod 755 recaptchalib.php”

Leave a Reply

Your email address will not be published.