0

I found a CAPTCHA script online for a self-made contact form on my site.

In my theme folder I have a file called captcha_code_file.php:

<?php 
/*
*
* this code is based on captcha code by Simon Jarvis 
* http://www.white-hat-web-design.co.uk/articles/php-captcha.php
*
* This program is free software; you can redistribute it and/or 
* modify it under the terms of the GNU General Public License 
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
* GNU General Public License for more details: 
* http://www.gnu.org/licenses/gpl.html
*/

session_start();

//Settings: You can customize the captcha here
$image_width = 110;
$image_height = 35;
$characters_on_image = 6;
$font = './monofont.ttf';

//The characters that can be used in the CAPTCHA code.
//avoid confusing characters (l 1 and i for example)
$possible_letters = '23456789bcdfghjkmnpqrstvwxyz';
$random_dots = 0;
$random_lines = 20;
$captcha_text_color="0x#B9B098";
$captcha_noice_color = "0x#CEC7BA";

$code = '';


$i = 0;
while ($i < $characters_on_image) { 
$code .= substr($possible_letters, mt_rand(0, strlen($possible_letters)-1), 1);
$i++;
}


$font_size = $image_height * 0.75;
$image = @imagecreate($image_width, $image_height);


/* setting the background, text and noise colours here */
$background_color = imagecolorallocate($image, 255, 255, 255);

$arr_text_color = hexrgb($captcha_text_color);
$text_color = imagecolorallocate($image, $arr_text_color['red'], 
        $arr_text_color['green'], $arr_text_color['blue']);

$arr_noice_color = hexrgb($captcha_noice_color);
$image_noise_color = imagecolorallocate($image, $arr_noice_color['red'], 
        $arr_noice_color['green'], $arr_noice_color['blue']);


/* generating the dots randomly in background */
for( $i=0; $i<$random_dots; $i++ ) {
imagefilledellipse($image, mt_rand(0,$image_width),
 mt_rand(0,$image_height), 2, 3, $image_noise_color);
}


/* generating lines randomly in background of image */
for( $i=0; $i<$random_lines; $i++ ) {
imageline($image, mt_rand(0,$image_width), mt_rand(0,$image_height),
 mt_rand(0,$image_width), mt_rand(0,$image_height), $image_noise_color);
}


/* create a text box and add 6 letters code in it */
$textbox = imagettfbbox($font_size, 0, $font, $code); 
$x = ($image_width - $textbox[4])/2;
$y = ($image_height - $textbox[5])/2;
imagettftext($image, $font_size, 0, $x, $y, $text_color, $font , $code);


/* Show captcha image in the page html page */
header('Content-Type: image/jpeg');// defining the image type to be shown in browser widow
imagejpeg($image);//showing the image
imagedestroy($image);//destroying the image instance
$_SESSION['6_letters_code'] = $code;

function hexrgb ($hexstr)
{
  $int = hexdec($hexstr);

  return array("red" => 0xFF & ($int >> 0x10),
               "green" => 0xFF & ($int >> 0x8),
               "blue" => 0xFF & $int);
}
?>

I can't seem to store the session created. What do I need to do to make this work? And how do I get the session in another file, e.g. if(empty($_SESSION['6_letters_code'])?

1
  • This question has absolutely nothing to do with WordPress.
    – Chris_O
    Apr 10 '14 at 23:45
4
+25

The definitive solution with session is.. do not use session.

As example in your form, you can output 3 fields:

  • an image field -> the captcha image
  • a text field -> to allow users to insert the characters
  • an hidden field -> contain the solution but encripted using wp_create_nonce

In this way when the form is submitted you can compare the user input with the hidden field input using wp_verify_nonce and you solve your problem without using session.

I'll write the code in a class, you can put all this code in a file, name it 'mycaptcha.php' and save it in the theme folder, after that, require_once it from functions.php.

<?php
class MyCaptcha {
  protected $code = '';
  protected $letters = '23456789bcdfghjkmnpqrstvwxyz';
  protected $chars_num;
  protected $tcolor;
  protected $ncolor;
  protected $width;
  protected $height;

  /**
   * Allow to configure some options, generate a random code and print the fields
   */
  function __construct( $args = array() ) {
    $defaults = array(
      'chars_num' => 6,
      'dots' => 0,
      'lines' => 20,
      'width' => 110,
      'height' => 35,
      'tcolor' => 'B9B098',
      'ncolor' => 'CEC7BA'
    );
    $args = wp_parse_args( $args, $defaults );
    foreach ( $args as $k => $v ) {
      $this->$k = $v;
    }
    $this->setCode();
    $this->fields();
  }

  /**
   * Print the fields
   */
  protected function fields() {
    echo $this->getHidden();
    echo $this->getImg();
    echo $this->getText();
  }

  /**
   * Generate a random code
   */    
  protected function setCode() {
    $i = 0;
    $len = strlen( $this->letters ) - 1;
    while ( $i < $this->chars_num ) { 
      $this->code .= substr( $this->letters, mt_rand( 0, $len ), 1 );
      $i++;
    }
  }

  /**
   * Print hidden field
   */ 
  protected function getHidden() {
    return wp_nonce_field( $this->code , md5(__CLASS__) . '_n', FALSE, FALSE );
  }

  /**
   * Print text field
   */     
  protected function getText() {
    $f = '<label>%s<input type="text" name="%s" value="" autocomplete="off" /></label>';
    return sprintf( $f, __('Type the captcha:', 'your-textdomain'),  md5(__CLASS__) );
  }

  /**
   * Print captcha image
   */      
  protected function getImg() {
    $f = '<img src="%s" width="%d" height="%d" alt="" />';
    $data = array(
      'c' => self::encode( $this->code ),
      'size' => "{$this->width}x{$this->height}",
      'dots' => "{$this->dots}",
      'lines' => "{$this->lines}",
      'tcolor' => "{$this->tcolor}",
      'ncolor' => "{$this->ncolor}"
    );
    $url = add_query_arg( $data, get_template_directory_uri() . '/captcha_img.php' );
    return sprintf( $f, $url, $this->width, $this->height );
  }

  /**
   * Verify the nonce
   */      
  static function verify() {
    $method = filter_input( INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_STRING );
    $type = strtoupper( $method ) === 'GET' ? INPUT_GET : INPUT_POST;
    $nonce = filter_input( $type, md5(__CLASS__) . '_n', FILTER_SANITIZE_STRING );
    $code = filter_input( $type, md5(__CLASS__), FILTER_SANITIZE_STRING );
    return ! empty($code) &&  ! empty($nonce) && wp_create_nonce( $code ) === $nonce;
  }

  /**
   * Convert an hexadecimal color to an rgb array color
   */      
  static function hexrgb( $hex ) {
    $int = hexdec( $hex );
    return array(
      "red" => 0xFF & ($int >> 0x10),
      "green" => 0xFF & ($int >> 0x8),
      "blue" => 0xFF & $int
    );
  }

  /**
   * encode the code to avoid put plan code in image url
   */
  private static function encode( $code ) {
    $iv_size = mcrypt_get_iv_size( MCRYPT_BLOWFISH , MCRYPT_MODE_ECB );
    $iv = mcrypt_create_iv( $iv_size, MCRYPT_RAND );
    $key = md5( __CLASS__ );
    $enc = mcrypt_encrypt( MCRYPT_BLOWFISH , $key, $code, MCRYPT_MODE_ECB, $iv);
    return urlencode( base64_encode( $enc ) );
  }

  /**
   * Decode the code
   */
  static function decode( $encoded ) {
    $code = urldecode( base64_decode( $encoded ) );
    $iv_size = mcrypt_get_iv_size( MCRYPT_BLOWFISH , MCRYPT_MODE_ECB );
    $iv = mcrypt_create_iv( $iv_size, MCRYPT_RAND );
    $key = md5( __CLASS__ );
    return mcrypt_decrypt( MCRYPT_BLOWFISH , $key, $code, MCRYPT_MODE_ECB, $iv );
  }

}

Please be sure there is no spaces or blank lines at the strat (before <?php) nor at the end of the file.

The class require another file in your theme folder captcha_img.php that should be put in your theme folder. This file will contain the code you posted, just a little modified:

<?php 
// require the class
@require_once __DIR__ . '/mycaptcha.php';

// defaults
$w = 110;
$h = 35; 
$random_dots = 0;
$random_lines = 20;
$captcha_text_color = "0x#B9B098";
$captcha_noice_color = "0x#CEC7BA";

/* get code */
$code = filter_input( INPUT_GET, 'c', FILTER_SANITIZE_STRING );
if ( empty( $code ) ) die( '' );
$code = MyCaptcha::decode( $code );

/* get settings */
$sizes = filter_input( INPUT_GET, 'size', FILTER_SANITIZE_STRING );
if ( ! empty( $sizes ) ) {
  $s = explode( 'x', $sizes );
  if ( is_numeric($s[0]) && (int) $s[0] > 0  ) $w = (int) $s[0];
  if ( isset($s[1]) && is_numeric($s[1]) && (int) $s[1] > 0  ) $h = (int) $s[1];
}
$dots = (int) filter_input( INPUT_GET, 'dots', FILTER_SANITIZE_NUMBER_INT );
if ( $dots > 0 ) $random_dots = $dots;
$lines = (int) filter_input( INPUT_GET, 'lines', FILTER_SANITIZE_NUMBER_INT );
if ( $dots > 0 ) $random_lines = $lines;
$tcolor = (string) filter_input( INPUT_GET, 'tcolor', FILTER_SANITIZE_STRING );
if ( strlen($tcolor) === 6 ) $captcha_text_color = "0x#{$tcolor}";
$ncolor = (string) filter_input( INPUT_GET, 'ncolor', FILTER_SANITIZE_STRING );
if ( strlen($ncolor) === 6 ) $captcha_noice_color = "0x#{$ncolor}";

/* prepare image */
$font = './monofont.ttf';
$font_size = $h * 0.75;
$image = @imagecreate($w, $h);
$bg_color = imagecolorallocate($image, 255, 255, 255);
$arr_text_color = MyCaptcha::hexrgb($captcha_text_color);
$text_color = imagecolorallocate(
  $image,
  $arr_text_color['red'], 
  $arr_text_color['green'],
  $arr_text_color['blue']
);
$arr_noice_color = MyCaptcha::hexrgb($captcha_noice_color);
  $image_noise_color = imagecolorallocate(
  $image,
  $arr_noice_color['red'], 
  $arr_noice_color['green'],
  $arr_noice_color['blue']
);

/* generating dots randomly in background of image */
for( $i=0; $i < $random_dots; $i++ ) {
  imagefilledellipse(
    $image,
    mt_rand(0, $w), mt_rand(0, $h),
    2, 3,
    $image_noise_color
  );
}

/* generating lines randomly in background of image */
for( $i=0; $i < $random_lines; $i++ ) {
  imageline(
    $image,
    mt_rand(0, $w), mt_rand(0, $h),
    mt_rand(0, $w), mt_rand(0, $h),
    $image_noise_color
  );
}

/* create a text box and add 6 letters code in it */
$textbox = imagettfbbox( $font_size, 0, $font, $code ); 
$x = ( $w - $textbox[4] ) / 2;
$y = ( $h - $textbox[5] ) / 2;
imagettftext( $image, $font_size, 0, $x, $y, $text_color, $font , $code);

/* output captcha image */
header('Content-Type: image/jpeg');
imagejpeg($image);
imagedestroy($image); 

Again, be sure there is no spaces or blank lines at the start (before <?php) nor at the end of the file.

How to use

Print fields

In the forms simple use <?php new MyCaptcha; ?> to output the 3 fields using default settings.

You can customize the number of letters, the width and the height of the image, the colors, the number of lines and dots passing an array of arguments to constructor, e.g.

 <div class="my_captcha">
   <?php
   $args = array(
     'chars_num'=> '8', // number of characters
     'tcolor' => 'FFFFFF', // text color
     'ncolor' => '999999', // noise color
     'dots' => 50, // number of dots
     'lines'=> 40 // number of lines,
     'width'=>'220' // number of width,
     'height'=>'70' // number of height
   );
   new MyCaptcha( $args );
   ?>
 </div>

Verify

In the file or in the function that process the form you can verify simply using:

$is_captcha_corrent = MyCaptcha::verify();

Nothing more. Of course, if you use an external file to process the form, this file have to bootstrap WordPress.

Both files are available in a Gist here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.