<?php
/********************
# KCAPTCHA PROJECT VERSION 1.2.6
# Automatic test to tell computers and humans apart
# Copyright by Kruglov Sergei, 2006, 2007, 2008
# www.captcha.ru, www.kruglov.ru
# System requirements: PHP 4.0.6+ w/ GD
# KCAPTCHA is a free software. You can freely use it for building own site or software.
# If you use this software as a part of own sofware, you must leave copyright notices intact or add KCAPTCHA copyright notices to own.
# As a default configuration, KCAPTCHA has a small credits text at bottom of CAPTCHA image.
# You can remove it, but I would be pleased if you left it. ; )
# See kcaptcha_config.php for customization
********************/

class KCAPTCHA{

  // generates keystring and image
  function image(){
    require( dirname( __FILE__ ).'/kcaptcha_config.php' );

    $fonts=array();
    $fontsdir_absolute=dirname( __FILE__ ).'/'.$fontsdir;
    
    if ( $handle = opendir( $fontsdir_absolute ) )
    {
      while ( false !== ( $file = readdir( $handle ) ) )
        if ( preg_match( '/\.png$/i', $file ) )
          $fonts[]=$fontsdir_absolute.'/'.$file;

      closedir( $handle );
    }
    $alphabet_length = strlen( $alphabet );

    do
    {
      $font_file = $fonts[mt_rand( 0, count( $fonts )-1 )];
      $font      = imagecreatefrompng( $font_file );
      imagealphablending( $font, true );
      $fontfile_width  = imagesx( $font );
      $fontfile_height = imagesy( $font )-1;
      $font_metrics    = array(  );
      $symbol          = 0;
      $reading_symbol  = false;

      // loading font
      for( $i=0; $i<$fontfile_width && $symbol<$alphabet_length; $i++ )
      {
        $transparent = ( imagecolorat( $font, $i, 0 ) >> 24 ) == 127;

        if( !$reading_symbol && !$transparent )
        {
          $font_metrics[$alphabet{$symbol}] = array( 'start'=>$i );
          $reading_symbol = true;
          continue;
        }

        if( $reading_symbol && $transparent )
        {
          $font_metrics[$alphabet{$symbol}]['end'] = $i;
          $reading_symbol = false;
          $symbol++;
          continue;
        }
      }

      $img   = imagecreatetruecolor( $width, $height );
      $white = imagecolorallocate( $img, 255, 255, 255 );
      $black = imagecolorallocate( $img, 0, 0, 0 );
      imagealphablending( $img, true );
      imagefilledrectangle( $img, 0, 0, $width-1, $height-1, $white );

      // draw text
      $x = 1;
      for( $i = 0; $i<strlen( $this->keystring ); $i++ )
      {
        $m=$font_metrics[$this->keystring{$i}];
        $y=mt_rand( -$fluctuation_amplitude, $fluctuation_amplitude ) + ( $height-$fontfile_height ) / 2+2;

        if( $no_spaces )
        {
          $shift = 0;
          if( $i>0 )
          {
            $shift = 10000;
            for( $sy=7; $sy<$fontfile_height-20; $sy += 1 )
            {
              for( $sx = $m['start']-1; $sx<$m['end']; $sx += 1 )
              {
                $rgb     = imagecolorat( $font, $sx, $sy );
                $opacity = $rgb >> 24;
                if( $opacity<127 )
                {
                  $left = $sx-$m['start']+$x;
                  $py   = $sy+$y;
                  if( $py>$height ) break;
                  for( $px = min( $left,$width-1 ); $px>$left-12 && $px>=0; $px -= 1 )
                  {
                    $color = imagecolorat( $img, $px, $py ) & 0xff;
                    if( $color+$opacity<190 )
                    {
                      if( $shift>$left-$px )
                        $shift=$left-$px;

                      break;
                    }
                  }
                  break;
                }
              }
            }
            if( $shift===10000 )
              $shift = mt_rand( 4,6 );
          }
        }
        else
          $shift = 1;

        imagecopy( $img, $font, $x-$shift, $y, $m['start'], 1, $m['end']-$m['start'], $fontfile_height );
        $x += $m['end']-$m['start']-$shift;
      }
    }
    while( $x>=$width-10 ); // while not fit in canvas

    $center = $x/2;

    // credits. To remove, see configuration file
    $img2       = imagecreatetruecolor( $width, $height+( $show_credits ? 12 : 0 ) );
    $foreground = imagecolorallocate( $img2, $foreground_color['0'], $foreground_color['1'], $foreground_color['2'] );
    $background = imagecolorallocate( $img2, $background_color['0'], $background_color['1'], $background_color['2'] );
    $credits    = empty( $credits ) ? $_SERVER['HTTP_HOST'] : $credits;
    imagefilledrectangle( $img2, 0, 0, $width-1, $height-1, $background );
    imagefilledrectangle( $img2, 0, $height, $width-1, $height+12, $foreground );
    imagestring( $img2, 2, $width/2-imagefontwidth( 2 )*strlen( $credits )/2, $height-2, $credits, $background );

    // periods
    $rand1 = mt_rand( 750000,1200000 )/10000000;
    $rand2 = mt_rand( 750000,1200000 )/10000000;
    $rand3 = mt_rand( 750000,1200000 )/10000000;
    $rand4 = mt_rand( 750000,1200000 )/10000000;

    // phases
    $rand5 = mt_rand( 0,31415926 )/10000000;
    $rand6 = mt_rand( 0,31415926 )/10000000;
    $rand7 = mt_rand( 0,31415926 )/10000000;
    $rand8 = mt_rand( 0,31415926 )/10000000;

    // amplitudes
    $rand9  = mt_rand( 330,420 )/110;
    $rand10 = mt_rand( 330,450 )/110;

    //wave distortion
    for( $x = 0; $x<$width; $x++ )
    {
      for( $y = 0; $y<$height; $y++ )
      {
        if ( $wave )
        {
          $sx = $x+( sin( $x*$rand1+$rand5 )+sin( $y*$rand3+$rand6 ) )*$rand9-$width/2+$center+1;
          $sy = $y+( sin( $x*$rand2+$rand7 )+sin( $y*$rand4+$rand8 ) )*$rand10;
        }
        else
        {
          $sx = $x-$width/2+$center+1;
          $sy = $y+( sin( $x*$rand2+$rand7 )+sin( $y*$rand4+$rand8 ) )*1.5;
        }

        if( $sx<0 || $sy<0 || $sx>=$width-1 || $sy>=$height-1 )
        {
          continue;
        }
        else
        {
          $color    = imagecolorat( $img, $sx, $sy ) & 0xFF;
          $color_x  = imagecolorat( $img, $sx+1, $sy ) & 0xFF;
          $color_y  = imagecolorat( $img, $sx, $sy+1 ) & 0xFF;
          $color_xy = imagecolorat( $img, $sx+1, $sy+1 ) & 0xFF;
        }

        if( $color==255 && $color_x==255 && $color_y==255 && $color_xy==255 )
        {
          continue;
        }
        else if( $color==0 && $color_x==0 && $color_y==0 && $color_xy==0 )
        {
          $newred   = $foreground_color['0'];
          $newgreen = $foreground_color['1'];
          $newblue  = $foreground_color['2'];
        }
        else
        {
          $frsx  = $sx-floor( $sx );
          $frsy  = $sy-floor( $sy );
          $frsx1 = 1-$frsx;
          $frsy1 = 1-$frsy;

          $newcolor = ($color*$frsx1*$frsy1+
                       $color_x*$frsx*$frsy1+
                       $color_y*$frsx1*$frsy+
                       $color_xy*$frsx*$frsy
                      );

          if( $newcolor>255 )
            $newcolor = 255;

          $newcolor  = $newcolor/255;
          $newcolor0 = 1-$newcolor;

          $newred   = $newcolor0*$foreground_color['0']+$newcolor*$background_color['0'];
          $newgreen = $newcolor0*$foreground_color['1']+$newcolor*$background_color['1'];
          $newblue  = $newcolor0*$foreground_color['2']+$newcolor*$background_color['2'];
        }

        imagesetpixel( $img2, $x, $y, imagecolorallocate( $img2, $newred, $newgreen, $newblue ) );
      }
    }

    header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
    header( 'Cache-Control: no-store, no-cache, must-revalidate' );
    header( 'Cache-Control: post-check=0, pre-check=0', FALSE );
    header( 'Pragma: no-cache' );

    if( function_exists( "imagejpeg" ) )
    {
      header( "Content-Type: image/jpeg" );
      imagejpeg( $img2, null, $jpeg_quality );
    }
    else if( function_exists( "imagegif" ) )
    {
      header( "Content-Type: image/gif" );
      imagegif( $img2 );
    }
    else if( function_exists( "imagepng" ) )
    {
      header( "Content-Type: image/x-png" );
      imagepng( $img2 );
    }
  }

  // returns keystring
  function getKeyString(  )
  {
    return $this->keystring;
  }

  function setKeyString( $str )
  {
    $this->keystring = $str;
  }
}
?>
