<?php
/**
 * Captcha library for PHP5
 * webpage: http://theba.hu/#projects
 *
 * Licence: LGPLv3
 * http://www.gnu.org/licenses/lgpl.html
 *
 * @author Amon
 * @version 1.0
 */
class Code {
    
/**
     * Placeholder for the singleton instance
     *
     */
    
private static $instance null;
    
/**
     * Placeholder for the hash
     *
     * @var string
     */
    
protected $hash_salt '';
    
/**
     * Placeholder for the image
     *
     * @var object
     */
    
protected $image null;
    
/**
     * Options array
     *
     * @var array
     */
    
public $options = array(
        
'imageWidth' => 150,
        
'imageHeight' => 36,
        
'ttf' => './antfarm.ttf',
        
'textColor' => 'AAAAAA',
        
'textTransparency' => 20,
        
'shadowColor' => 'DDDDDD',
        
'shadowText' => 100,
        
'textShadow' => 50,
        
'backgroundImage' => '',
        
'backgroundColor' => 'FFFFFF',
        
'lineColor' => 'ABCABC',
        
'angledLines' => true,
        
'linesOverText' => true,
        
'drawLines' => true,
        
'textStartX' => 15,
        
'lineAlpha' => 70,
        
'lineDistance' => 8,
        
'codeLength' => 4,
        
'fontSize' => 20,
        
'textAngleMin' => -20,
        
'textAngleMax' => 20,
        
'textDistanceMax' => 33,
        
'textDistanceMin' => 30,
    );
    
/**
     * Get an option from the options array
     *
     * @return mixed
     */
    
protected function get$key ) {
        if( isset( 
$this->options[$key] ) ) {
            return 
$this->options[$key];
        }
    }
    
/**
     * Convert hexa color code (XHTML) to RGB color
     *
     * @param string $color : hexadecimal string
     * @return array : array( 'red' => REDVALUE, 'green' => GREENVALUE, 'blue' => BLUEVALUE )
     */
    
public static function colorHexToDec$color ) {
        if( 
substr$color0) == '#' $color substr$color);
        
$red = @substr$color0);
        
$green = @substr$color,);
        
$blue = @substr$color4);
        return array(
            
'red' => hexdec$red ),
            
'green' => hexdec$green ),
            
'blue' => hexdec$blue )
        );
    }
    
/**
     * Create the image
     *
     */
    
protected function doCreateImage() {
        
$this->image imagecreatetruecolor$this->get'imageWidth' ), $this->get'imageHeight' ) );
        
$temp self::colorHexToDec$this->get'backgroundColor' ) );
        
$bgcolor imagecolorallocate$this->image$temp['red'], $temp['green'], $temp['blue'] );
        if( 
$this->get'textTransparency' ) || $this->get'backgroundImage' ) ) {
            
imagefilledrectangle$this->image00imagesx$this->image ), imagesy$this->image ), $bgcolor );
        }
    }
    
/**
     * Set the background image of the captcha
     *
     */
    
protected function doSetBackground() {
        
$imageFile $this->get'backgroundImage' );
        if( 
file_exists$imageFile ) ) {
            
$dat getimagesize$imageFile );
            switch( 
$dat[2] ) {
                    case 
1$newimg = @imagecreatefromgif$imageFile ); break;
                    case 
2$newimg = @imagecreatefromjpeg$imageFile ); break;
                    case 
3$newimg = @imagecreatefrompng$imageFile ); break;
                    case 
15$newimg = @imagecreatefromwbmp$imageFile ); break;
                    case 
16$newimg = @imagecreatefromxbm$imageFile ); break;
                    default: return;
            }
            if( !
$newimg ) {
                    return;
                }
            
imagecopy$this->image$newimg0000$this->get'imageWidth' ), $this->get'imageHeight' ) );
            
imagedestroy$newimg );
        } else exit( 
$imageFile.' does not exists' );
    }
    
/**
     * Draw lines to the captcha image
     *
     */
    
protected function drawLines() {
        
$alpha floor$this->get'lineAlpha' ) / 100 127 );
        
$temp self::colorHexToDec$this->get'lineColor' ) );
        
$linecolor imagecolorallocatealpha$this->image$temp['red'], $temp['green'], $temp['blue'], $alpha );
        
/**
         * For caching purposes
         */
        
$lineDistance $this->get'lineDistance' );
        
$imageHeight $this->get'imageHeight' );
        
$imageWidth $this->get'imageWidth' );

        for( 
$x=1$x $imageWidth$x += rand1$lineDistance ) ) {
            
imageline$this->image$x0$x$imageHeight$linecolor );
        }
        for( 
$y=11$y $imageHeight$y += rand1$lineDistance ) ) {
            
imageline$this->image0$y$imageWidth$y$linecolor );
        }
        if ( 
$this->get'angledLines' ) ) {
            for ( 
$x = -( $imageHeight ); $x $imageWidth$x += rand1$lineDistance ) ) {
                
imageline$this->image$x0$x $imageHeight$imageHeight$linecolor );
            }
            for ( 
$x $imageWidth $imageHeight$x 0$x -= rand1$lineDistance ) ) {
                
imageline$this->image$x0$x $imageHeight$imageHeight$linecolor );
            }
        }
    }
    
/**
     * Draw code to the captcha image
     *
     */
    
protected function drawText$code ) {
        
$temp self::colorHexToDec$this->get'textColor' ) );
        if( 
$this->get'textTransparency' ) ) {
            
$alpha floor$this->get'textTransparency' ) / 100 127 );
            
$font_color imagecolorallocatealpha$this->image$temp['red'], $temp['green'], $temp['blue'], $alpha );
            unset( 
$alpha );
        } else {
            
$font_color imagecolorallocate$this->image$temp['red'], $temp['green'], $temp['blue'] );
        }
        if( 
$this->get'shadowText' ) ) {
            
$alpha floor$this->get'shadowText' ) / 100 127 );
            
$temp self::colorHexToDec$this->get'shadowColor' ) );
            
$font_color_shadow imagecolorallocatealpha$this->image$temp['red'], $temp['green'], $temp['blue'], $alpha );
            unset( 
$alpha );
        }
        
$x $this->get'textStartX' );
        
$y_min = ( $this->get'imageHeight' ) / ) + ( $this->get'fontSize' ) / ) - 2;
        
$y_max = ( $this->get'imageHeight' ) / ) + ( $this->get'fontSize' ) / ) + 2;
        if( 
function_exists'str_split' ) ) {
            
$arr str_split$code );
        } else {
            
$arr preg_split('//'$code, -1PREG_SPLIT_NO_EMPTY);
        }
        
/**
         * For caching purposes
         */
        
$taMin $this->get'textAngleMin' );
        
$taMax $this->get'textAngleMax' );
        
$ttfFile $this->get'ttf' );
        
$shadowText $this->get'shadowText' );
        
$fontSize $this->get'fontSize' );
        
$tdMin $this->get'textDistanceMin' );
        
$tdMax $this->get'textDistanceMax' );
        foreach ( 
$arr as $txt ) {
            
$angle rand$taMin$taMax );
            
$y rand$y_min$y_max );
            if( 
$shadowText != ) {
                
$dx rand( -5);
                
$dy rand( -5);
                
imagettftext$this->image$fontSize$angle$x $dx$y $dy$font_color_shadow$ttfFile$txt );
            }
            
imagettftext$this->image$fontSize$angle$x$y$font_color$ttfFile$txt );
            
$x += rand$tdMin$tdMax );
        }
    }
    
/**
     * Send image to the client
     *
     */
    
protected function sendImage() {
        
header"Expires: Sun, 1 Jan 2000 12:00:00 GMT" );
        
header"Last-Modified: " gmdate"D, d M Y H:i:s" ) . "GMT" );
        
header"Cache-Control: no-store, no-cache, must-revalidate" );
        
header"Cache-Control: post-check=0, pre-check=0"false );
        
header"Pragma: no-cache" );
        
header"Content-Type: image/jpeg" );
        
imagejpeg$this->image );
        exit;
    }
    
/**
     * Generate captcha code
     *
     * @param int $length
     * @return string
     */
    
public function generateCode$length=) {
        if( 
$length 32 $length 32;
        if( 
$length $length 1;
        
$code substrmd5$this->hash_salt.time() ), 0$length );
        return  
$code;
    }
    
/**
     * Check the code
     *
     * @param string $code
     * @return boolean
     */
    
public function checkCode$code ) {
        return isset( 
$_SESSION['code'] ) && $_SESSION['code'] === strtolower$code );
    }
    
/**
     * Store code to the session
     *
     * @param string $code
     */
    
protected function storeCode$code ) {
        
$_SESSION['code'] = $code;
    }
    
/**
     * Show the code ( run all functions to generate captcha )
     *
     */
    
public function showCode() {
        
$this->storeCode$this->generateCode$this->get'codeLength' ) ) );
        
$this->doCreateImage();
        if( 
$this->get'backgroundImage' ) ) {
            
$this->doSetBackground();
        }
        if( 
$this->get'drawLines' ) && !$this->get'linesOverText' ) ) {
          
$this->drawLines();
        }
        
$this->drawText$_SESSION['code'] );
        if( 
$this->get'drawLines' ) && $this->get'linesOverText' ) ) {
            
$this->drawLines();
        }
        
$this->sendImage();
        
imagedestroy$this->image );
    }
    
/**
     * Constructor
     * Set the hash with unique string
     *
     */
    
protected function __construct$options ) {
        
$this->hash_salt md5$_SERVER['HTTP_HOST'].$_SERVER['HTTP_USER_AGENT'].time() );
        if( !empty( 
$options ) ) {
            
$this->options array_merge$this->options$options );
        }
    }
    
/**
     * Singleton Code Factory
     *
     */
    
public function getInstance$options=array() ) {
        if( !isset( 
self::$instance ) ) {
            
$class __CLASS__;
            
self::$instance = new $class$options );
        }
        return 
self::$instance;
    }
}