Securimage
[ class tree: Securimage ] [ index: Securimage ] [ all elements ]

Source for file securimage.php

Documentation is available at securimage.php

  1. <?php
  2.  
  3. /**
  4.  * Project:     Securimage: A PHP class for creating and managing form CAPTCHA images<br />
  5.  * File:        securimage.php<br />
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or any later version.<br /><br />
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.<br /><br />
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA<br /><br />
  20.  * 
  21.  * Any modifications to the library should be indicated clearly in the source code
  22.  * to inform users that the changes are not a part of the original software.<br /><br />
  23.  *
  24.  * If you found this script useful, please take a quick moment to rate it.<br />
  25.  * http://www.hotscripts.com/rate/49400.html  Thanks.
  26.  *
  27.  * @link http://www.phpcaptcha.org Securimage PHP CAPTCHA
  28.  * @link http://www.phpcaptcha.org/latest.zip Download Latest Version
  29.  * @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation
  30.  * @copyright 2007 Drew Phillips
  31.  * @author drew010 <drew@drew-phillips.com>
  32.  * @version 1.0.2 (January 6, 2008)
  33.  * @package Securimage
  34.  *
  35.  */
  36.  
  37. /**
  38.   ChangeLog
  39.  
  40.   1.0.1
  41.   - Audible CAPTCHA Code wav files
  42.   - Create codes from a word list instead of random strings
  43.  
  44.   1.0
  45.   - Added the ability to use a selected character set, rather than a-z0-9 only.
  46.   - Added the multi-color text option to use different colors for each letter.
  47.   - Switched to automatic session handling instead of using files for code storage
  48.   - Added GD Font support if ttf support is not available.  Can use internal GD fonts or load new ones.
  49.   - Added the ability to set line thickness
  50.   - Added option for drawing arced lines over letters
  51.   - Added ability to choose image type for output
  52.  
  53. */
  54.  
  55. /**
  56.  * Output images in JPEG format
  57.  */
  58. define('SI_IMAGE_JPEG'1);
  59. /**
  60.  * Output images in PNG format
  61.  */
  62. define('SI_IMAGE_PNG',  2);
  63. /**
  64.  * Output images in GIF format
  65.  * Must have GD >= 2.0.28!
  66.  */
  67. define('SI_IMAGE_GIF',  3);
  68.  
  69. /**
  70.  * Securimage CAPTCHA Class.
  71.  *
  72.  * @package    Securimage
  73.  * @subpackage classes
  74.  *
  75.  */
  76. class Securimage {
  77.  
  78.   /**
  79.    * The desired width of the CAPTCHA image.
  80.    *
  81.    * @var int 
  82.    */
  83.   var $image_width = 175;
  84.  
  85.   /**
  86.    * The desired width of the CAPTCHA image.
  87.    *
  88.    * @var int 
  89.    */
  90.   var $image_height = 45;
  91.  
  92.   /**
  93.    * The image format for output.<br />
  94.    * Valid options: SI_IMAGE_PNG, SI_IMAGE_JPG, SI_IMAGE_GIF
  95.    *
  96.    * @var int 
  97.    */
  98.   var $image_type = SI_IMAGE_PNG;
  99.  
  100.   /**
  101.    * The length of the code to generate.
  102.    *
  103.    * @var int 
  104.    */
  105.   var $code_length = 4;
  106.  
  107.   /**
  108.    * The character set for individual characters in the image.<br />
  109.    * Letters are converted to uppercase.<br />
  110.    * The font must support the letters or there may be problematic substitutions.
  111.    *
  112.    * @var string 
  113.    */
  114.   var $charset = 'ABCDEFGHKLMNPRSTUVWYZ23456789';
  115.   //var $charset = '0123456789';
  116.   
  117.   
  118.   
  119.   /**
  120.    * Create codes using this word list
  121.    *
  122.    * @var string  The path to the word list to use for creating CAPTCHA codes
  123.    */
  124.   var $wordlist_file = 'words/words.txt';
  125.   
  126.   /**
  127.    * True to use a word list file instead of a random code
  128.    *
  129.    * @var bool 
  130.    */
  131.   var $use_wordlist  = true;
  132.  
  133.   /**
  134.    * Whether to use a GD font instead of a TTF font.<br />
  135.    * TTF offers more support and options, but use this if your PHP doesn't support TTF.<br />
  136.    *
  137.    * @var boolean 
  138.    */
  139.   var $use_gd_font = false;
  140.  
  141.   /**
  142.    * The GD font to use.<br />
  143.    * Internal gd fonts can be loaded by their number.<br />
  144.    * Alternatively, a file path can be given and the font will be loaded from file.
  145.    *
  146.    * @var mixed 
  147.    */
  148.   var $gd_font_file = 'gdfonts/bubblebath.gdf';
  149.  
  150.   /**
  151.    * The approximate size of the font in pixels.<br />
  152.    * This does not control the size of the font because that is determined by the GD font itself.<br />
  153.    * This is used to aid the calculations of positioning used by this class.<br />
  154.    *
  155.    * @var int 
  156.    */
  157.   var $gd_font_size = 20;
  158.  
  159.   // Note: These font options below do not apply if you set $use_gd_font to true with the exception of $text_color
  160.  
  161.   
  162.  
  163.   /**
  164.    * The path to the TTF font file to load.
  165.    *
  166.    * @var string 
  167.    */
  168.   var $ttf_file = "./elephant.ttf";
  169.  
  170.   /**
  171.    * The font size.<br />
  172.    * Depending on your version of GD, this should be specified as the pixel size (GD1) or point size (GD2)<br />
  173.    *
  174.    * @var int 
  175.    */
  176.   var $font_size = 24;
  177.  
  178.   /**
  179.    * The minimum angle in degrees, with 0 degrees being left-to-right reading text.<br />
  180.    * Higher values represent a counter-clockwise rotation.<br />
  181.    * For example, a value of 90 would result in bottom-to-top reading text.
  182.    *
  183.    * @var int 
  184.    */
  185.   var $text_angle_minimum = -20;
  186.  
  187.   /**
  188.    * The minimum angle in degrees, with 0 degrees being left-to-right reading text.<br />
  189.    * Higher values represent a counter-clockwise rotation.<br />
  190.    * For example, a value of 90 would result in bottom-to-top reading text.
  191.    *
  192.    * @var int 
  193.    */
  194.   var $text_angle_maximum = 20;
  195.  
  196.   /**
  197.    * The X-Position on the image where letter drawing will begin.<br />
  198.    * This value is in pixels from the left side of the image.
  199.    *
  200.    * @var int 
  201.    */
  202.   var $text_x_start = 8;
  203.  
  204.   /**
  205.    * Letters can be spaced apart at random distances.<br />
  206.    * This is the minimum distance between two letters.<br />
  207.    * This should be <i>at least</i> as wide as a font character.<br />
  208.    * Small values can cause letters to be drawn over eachother.<br />
  209.    *
  210.    * @var int 
  211.    */
  212.   var $text_minimum_distance = 30;
  213.  
  214.   /**
  215.    * Letters can be spaced apart at random distances.<br />
  216.    * This is the maximum distance between two letters.<br />
  217.    * This should be <i>at least</i> as wide as a font character.<br />
  218.    * Small values can cause letters to be drawn over eachother.<br />
  219.    *
  220.    * @var int 
  221.    */
  222.   var $text_maximum_distance = 33;
  223.  
  224.   /**
  225.    * The background color for the image.<br />
  226.    * This should be specified in HTML hex format.<br />
  227.    * Make sure to include the preceding # sign!
  228.    *
  229.    * @var string 
  230.    */
  231.   var $image_bg_color = "#e3daed";
  232.  
  233.   /**
  234.    * The text color to use for drawing characters.<br />
  235.    * This value is ignored if $use_multi_text is set to true.<br />
  236.    * Make sure this contrasts well with the background color.<br />
  237.    * Specify the color in HTML hex format with preceding # sign
  238.    *
  239.    * @see Securimage::$use_multi_text
  240.    * @var string 
  241.    */
  242.   var $text_color = "#ff0000";
  243.  
  244.   /**
  245.    * Set to true to use multiple colors for each character.
  246.    *
  247.    * @see Securimage::$multi_text_color
  248.    * @var boolean 
  249.    */
  250.   var $use_multi_text = true;
  251.  
  252.   /**
  253.    * String of HTML hex colors to use.<br />
  254.    * Separate each possible color with commas.<br />
  255.    * Be sure to precede each value with the # sign.
  256.    *
  257.    * @var string 
  258.    */
  259.   var $multi_text_color = "#0a68dd,#f65c47,#8d32fd";
  260.  
  261.   /**
  262.    * Set to true to make the characters appear transparent.
  263.    *
  264.    * @see Securimage::$text_transparency_percentage
  265.    * @var boolean 
  266.    */
  267.   var $use_transparent_text = true;
  268.  
  269.   /**
  270.    * The percentage of transparency, 0 to 100.<br />
  271.    * A value of 0 is completely opaque, 100 is completely transparent (invisble)
  272.    *
  273.    * @see Securimage::$use_transparent_text
  274.    * @var int 
  275.    */
  276.  
  277.  
  278.   // Line options
  279.   
  280.   /**
  281.    * Draw vertical and horizontal lines on the image.
  282.    *
  283.    * @see Securimage::$line_color
  284.    * @see Securimage::$line_distance
  285.    * @see Securimage::$line_thickness
  286.    * @see Securimage::$draw_lines_over_text
  287.    * @var boolean 
  288.    */
  289.   var $draw_lines = true;
  290.  
  291.   /**
  292.    * The color of the lines drawn on the image.<br />
  293.    * Use HTML hex format with preceding # sign.
  294.    *
  295.    * @see Securimage::$draw_lines
  296.    * @var string 
  297.    */
  298.   var $line_color = "#80BFFF";
  299.  
  300.   /**
  301.    * How far apart to space the lines from eachother in pixels.
  302.    *
  303.    * @see Securimage::$draw_lines
  304.    * @var int 
  305.    */
  306.   var $line_distance = 5;
  307.  
  308.   /**
  309.    * How thick to draw the lines in pixels.<br />
  310.    * 1-3 is ideal depending on distance
  311.    *
  312.    * @see Securimage::$draw_lines
  313.    * @see Securimage::$line_distance
  314.    * @var int 
  315.    */
  316.   var $line_thickness = 1;
  317.  
  318.   /**
  319.    * Set to true to draw angled lines on the image in addition to the horizontal and vertical lines.
  320.    *
  321.    * @see Securimage::$draw_lines
  322.    * @var boolean 
  323.    */
  324.   var $draw_angled_lines = false;
  325.  
  326.   /**
  327.    * Draw the lines over the text.<br />
  328.    * If fales lines will be drawn before putting the text on the image.<br />
  329.    * This can make the image hard for humans to read depending on the line thickness and distance.
  330.    *
  331.    * @var boolean 
  332.    */
  333.   var $draw_lines_over_text = false;
  334.  
  335.   /**
  336.    * For added security, it is a good idea to draw arced lines over the letters to make it harder for bots to segment the letters.<br />
  337.    * Two arced lines will be drawn over the text on each side of the image.<br />
  338.    * This is currently expirimental and may be off in certain configurations.
  339.    *
  340.    * @var boolean 
  341.    */
  342.   var $arc_linethrough = true;
  343.  
  344.   /**
  345.    * The colors or color of the arced lines.<br />
  346.    * Use HTML hex notation with preceding # sign, and separate each value with a comma.<br />
  347.    * This should be similar to your font color for single color images.
  348.    *
  349.    * @var string 
  350.    */
  351.   var $arc_line_colors = "#8080ff";
  352.  
  353.   /**
  354.    * Full path to the WAV files to use to make the audio files, include trailing /.<br />
  355.    * Name Files  [A-Z0-9].wav
  356.    *
  357.    * @since 1.0.1
  358.    * @var string 
  359.    */
  360.   var $audio_path = './audio/';
  361.  
  362.  
  363.   //END USER CONFIGURATION
  364.   //There should be no need to edit below unless you really know what you are doing.
  365.  
  366.   
  367.  
  368.   /**
  369.    * The gd image resource.
  370.    *
  371.    * @access private
  372.    * @var resource 
  373.    */
  374.   var $im;
  375.  
  376.   /**
  377.    * The background image resource
  378.    *
  379.    * @access private
  380.    * @var resource 
  381.    */
  382.   var $bgimg;
  383.  
  384.   /**
  385.    * The code generated by the script
  386.    *
  387.    * @access private
  388.    * @var string 
  389.    */
  390.   var $code;
  391.  
  392.   /**
  393.    * The code that was entered by the user
  394.    *
  395.    * @access private
  396.    * @var string 
  397.    */
  398.   var $code_entered;
  399.  
  400.   /**
  401.    * Whether or not the correct code was entered
  402.    *
  403.    * @access private
  404.    * @var boolean 
  405.    */
  406.   var $correct_code;
  407.  
  408.   /**
  409.    * Class constructor.<br />
  410.    * Because the class uses sessions, this will attempt to start a session if there is no previous one.<br />
  411.    * If you do not start a session before calling the class, the constructor must be called before any
  412.    * output is sent to the browser.
  413.    *
  414.    * <code>
  415.    *   $securimage = new Securimage();
  416.    * </code>
  417.    *
  418.    */
  419.   function Securimage()
  420.   {
  421.     if session_id(== '' // no session has been started yet, which is needed for validation
  422.       session_start();
  423.     }
  424.   }
  425.  
  426.   /**
  427.    * Generate a code and output the image to the browser.
  428.    *
  429.    * <code>
  430.    *   <?php
  431.    *   include 'securimage.php';
  432.    *   $securimage = new Securimage();
  433.    *   $securimage->show('bg.jpg');
  434.    *   ?>
  435.    * </code>
  436.    *
  437.    * @param string $background_image  The path to an image to use as the background for the CAPTCHA
  438.    */
  439.   function show($background_image "")
  440.   {
  441.     if($background_image != "" && is_readable($background_image)) {
  442.       $this->bgimg $background_image;
  443.     }
  444.  
  445.     $this->doImage();
  446.   }
  447.  
  448.   /**
  449.    * Validate the code entered by the user.
  450.    *
  451.    * <code>
  452.    *   $code = $_POST['code'];
  453.    *   if ($securimage->check($code) == false) {
  454.    *     die("Sorry, the code entered did not match.");
  455.    *   } else {
  456.    *     $valid = true;
  457.    *   }
  458.    * </code>
  459.    * @param string $code  The code the user entered
  460.    * @return boolean  true if the code was correct, false if not
  461.    */
  462.   function check($code)
  463.   {
  464.     $this->code_entered $code;
  465.     $this->validate();
  466.     return $this->correct_code;
  467.   }
  468.  
  469.   /**
  470.    * Generate and output the image
  471.    *
  472.    * @access private
  473.    *
  474.    */
  475.   function doImage()
  476.   {
  477.     if($this->use_transparent_text == true || $this->bgimg != ""{
  478.       $this->im imagecreatetruecolor($this->image_width$this->image_height);
  479.       $bgcolor imagecolorallocate($this->imhexdec(substr($this->image_bg_color12))hexdec(substr($this->image_bg_color32))hexdec(substr($this->image_bg_color52)));
  480.       imagefilledrectangle($this->im00imagesx($this->im)imagesy($this->im)$bgcolor);
  481.     else //no transparency
  482.       $this->im imagecreate($this->image_width$this->image_height);
  483.       $bgcolor imagecolorallocate($this->imhexdec(substr($this->image_bg_color12))hexdec(substr($this->image_bg_color32))hexdec(substr($this->image_bg_color52)));
  484.     }
  485.  
  486.     if($this->bgimg != ""$this->setBackground()}
  487.  
  488.     $this->createCode();
  489.  
  490.     if (!$this->draw_lines_over_text && $this->draw_lines$this->drawLines();
  491.  
  492.     $this->drawWord();
  493.  
  494.     if ($this->arc_linethrough == true$this->arcLines();
  495.  
  496.     if ($this->draw_lines_over_text && $this->draw_lines$this->drawLines();
  497.  
  498.     $this->output();
  499.  
  500.   }
  501.  
  502.   /**
  503.    * Set the background of the CAPTCHA image
  504.    *
  505.    * @access private
  506.    *
  507.    */
  508.   function setBackground()
  509.   {
  510.     $dat @getimagesize($this->bgimg);
  511.     if($dat == falsereturn}
  512.  
  513.     switch($dat[2]{
  514.       case 1:  $newim @imagecreatefromgif($this->bgimg)break;
  515.       case 2:  $newim @imagecreatefromjpeg($this->bgimg)break;
  516.       case 3:  $newim @imagecreatefrompng($this->bgimg)break;
  517.       case 15$newim @imagecreatefromwbmp($this->bgimg)break;
  518.       case 16$newim @imagecreatefromxbm($this->bgimg)break;
  519.       defaultreturn;
  520.     }
  521.  
  522.     if(!$newimreturn;
  523.  
  524.     imagecopy($this->im$newim0000$this->image_width$this->image_height);
  525.   }
  526.  
  527.   /**
  528.    * Draw arced lines over the text
  529.    *
  530.    * @access private
  531.    *
  532.    */
  533.   function arcLines()
  534.   {
  535.     $colors explode(','$this->arc_line_colors);
  536.     imagesetthickness($this->im3);
  537.  
  538.     $color $colors[rand(0sizeof($colors1)];
  539.     $linecolor imagecolorallocate($this->imhexdec(substr($color12))hexdec(substr($color32))hexdec(substr($color52)));
  540.  
  541.     $xpos   $this->text_x_start + ($this->font_size * 2rand(-55);
  542.     $width  $this->image_width / 2.66 rand(310);
  543.     $height $this->font_size * 2.14 rand(310);
  544.  
  545.     if rand(0,100== {
  546.       $start rand(0,66);
  547.       $ypos  $this->image_height / rand(515);
  548.       $xpos += rand(515);
  549.     else {
  550.       $start rand(180246);
  551.       $ypos  $this->image_height / rand(515);
  552.     }
  553.  
  554.     $end $start rand(75110);
  555.  
  556.     imagearc($this->im$xpos$ypos$width$height$start$end$linecolor);
  557.  
  558.     $color $colors[rand(0sizeof($colors1)];
  559.     $linecolor imagecolorallocate($this->imhexdec(substr($color12))hexdec(substr($color32))hexdec(substr($color52)));
  560.  
  561.     if rand(1,75== {
  562.       $start rand(45111);
  563.       $ypos  $this->image_height / rand(515);
  564.       $xpos += rand(515);
  565.     else {
  566.       $start rand(200250);
  567.       $ypos  $this->image_height / rand(515);
  568.     }
  569.  
  570.     $end $start rand(75100);
  571.  
  572.     imagearc($this->im$this->image_width * .75$ypos$width$height$start$end$linecolor);
  573.   }
  574.  
  575.   /**
  576.    * Draw lines on the image
  577.    *
  578.    * @access private
  579.    *
  580.    */
  581.   function drawLines()
  582.   {
  583.     $linecolor imagecolorallocate($this->imhexdec(substr($this->line_color12))hexdec(substr($this->line_color32))hexdec(substr($this->line_color52)));
  584.     imagesetthickness($this->im$this->line_thickness);
  585.  
  586.     //vertical lines
  587.     for($x 1$x $this->image_width$x += $this->line_distance{
  588.       imageline($this->im$x0$x$this->image_height$linecolor);
  589.     }
  590.  
  591.     //horizontal lines
  592.     for($y 11$y $this->image_height$y += $this->line_distance{
  593.       imageline($this->im0$y$this->image_width$y$linecolor);
  594.     }
  595.  
  596.     if ($this->draw_angled_lines == true{
  597.       for ($x = -($this->image_height)$x $this->image_width$x += $this->line_distance{
  598.         imageline($this->im$x0$x $this->image_height$this->image_height$linecolor);
  599.       }
  600.  
  601.       for ($x $this->image_width + $this->image_height$x 0$x -= $this->line_distance{
  602.         imageline($this->im$x0$x $this->image_height$this->image_height$linecolor);
  603.       }
  604.     }
  605.   }
  606.  
  607.   /**
  608.    * Draw the CAPTCHA code over the image
  609.    *
  610.    * @access private
  611.    *
  612.    */
  613.   function drawWord()
  614.   {
  615.     if ($this->use_gd_font == true{
  616.       if (!is_int($this->gd_font_file)) //is a file name
  617.         $font @imageloadfont($this->gd_font_file);
  618.         if ($font == false{
  619.           trigger_error("Failed to load GD Font file {$this->gd_font_file", E_USER_WARNING);
  620.           return;
  621.         }
  622.       } else { //gd font identifier