<?php
//
//  A simple PHP CAPTCHA script
//
//  Copyright 2011 by Cory LaViska for A Beautiful Site, LLC
//
//  See readme.md for usage, demo, and licensing info
//
function simple_php_captcha($config = array()) {

    // Check for GD library
    if( !function_exists('gd_info') ) {
        throw new Exception('Required GD library is missing');
    }

    // Default values
    $captcha_config = array(
        'code' => '',
        'image_width' => 120,
        'image_height' => 70,
        'min_length' => 5,
        'max_length' => 5,
        'min_font_size' => 28,
        'max_font_size' => 28,
        'color' => '#666',
        'angle_min' => -10,
        'angle_max' => 10,
        'noise_number' => 30,
        'line_number' => 8
    );

    // Overwrite defaults with custom config values
    if( is_array($config) ) {
        foreach( $config as $key => $value ) $captcha_config[$key] = $value;
    }

    // Restrict certain values
    if( $captcha_config['min_length'] < 1 ) $captcha_config['min_length'] = 1;
    if( $captcha_config['angle_min'] < -20 ) $captcha_config['angle_min'] = -20;
    if( $captcha_config['angle_max'] > 20 ) $captcha_config['angle_max'] = 20;
    if( $captcha_config['angle_max'] < $captcha_config['angle_min'] ) $captcha_config['angle_max'] = $captcha_config['angle_min'];
    if( $captcha_config['min_font_size'] < 10 ) $captcha_config['min_font_size'] = 10;
    if( $captcha_config['max_font_size'] < $captcha_config['min_font_size'] ) $captcha_config['max_font_size'] = $captcha_config['min_font_size'];

    // Generate CAPTCHA code if not set by user
    if( empty($captcha_config['code']) ) {
        $captcha_config['code'] = '';
        $length = mt_rand($captcha_config['min_length'], $captcha_config['max_length']);
        while( strlen($captcha_config['code']) < $length ) {
            $captcha_config['code'] .= substr($captcha_config['characters'], mt_rand() % (strlen($captcha_config['characters'])), 1);
        }
    }

    // Generate HTML for image src
    if ( strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) ) {
        $image_src = substr(__FILE__, strlen( realpath($_SERVER['DOCUMENT_ROOT']) )) . '?_CAPTCHA&amp;t=' . urlencode(microtime());
        $image_src = '/' . ltrim(preg_replace('/\\\\/', '/', $image_src), '/');
    } else {
        $_SERVER['WEB_ROOT'] = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['SCRIPT_FILENAME']);
        $image_src = substr(__FILE__, strlen( realpath($_SERVER['WEB_ROOT']) )) . '?_CAPTCHA&amp;t=' . urlencode(microtime());
        $image_src = '/' . ltrim(preg_replace('/\\\\/', '/', $image_src), '/');
    }

    $_SESSION['_CAPTCHA']['config'] = serialize($captcha_config);

    return array(
        'code' => $captcha_config['code'],
        'image_src' => $image_src
    );

}


if( !function_exists('hex2rgb') ) {
    function hex2rgb($hex_str, $return_string = false, $separator = ',') {
        $hex_str = preg_replace("/[^0-9A-Fa-f]/", '', $hex_str); // Gets a proper hex string
        $rgb_array = array();
        if( strlen($hex_str) == 6 ) {
            $color_val = hexdec($hex_str);
            $rgb_array['r'] = 0xFF & ($color_val >> 0x10);
            $rgb_array['g'] = 0xFF & ($color_val >> 0x8);
            $rgb_array['b'] = 0xFF & $color_val;
        } elseif( strlen($hex_str) == 3 ) {
            $rgb_array['r'] = hexdec(str_repeat(substr($hex_str, 0, 1), 2));
            $rgb_array['g'] = hexdec(str_repeat(substr($hex_str, 1, 1), 2));
            $rgb_array['b'] = hexdec(str_repeat(substr($hex_str, 2, 1), 2));
        } else {
            return false;
        }
        return $return_string ? implode($separator, $rgb_array) : $rgb_array;
    }
}

// Draw the image
if( isset($_GET['_CAPTCHA']) ) {

    session_start();

    $captcha_config = unserialize($_SESSION['_CAPTCHA']['config']);
    if( !$captcha_config ) exit();

    if( isset($_GET['_RENDER']) ) {
        $_SESSION['_CAPTCHA']['config'] = simple_php_captcha();
    } else {
        unset($_SESSION['_CAPTCHA']);
    }

    // initialise image with dimensions of 160 x 45 pixels
    $image = @imagecreatetruecolor($captcha_config['image_width'], $captcha_config['image_height']) or die("Cannot Initialize new GD image stream");

    // set background and allocate drawing colours
    // $backgrounds = [];
    // $backgrounds[] = imagecolorallocate($image, 0x3E, 0xA8, 0xEC);
    // $backgrounds[] = imagecolorallocate($image, 0x07, 0xCF, 0x98);
    // $backgrounds[] = imagecolorallocate($image, 0xAA, 0xBF, 0x13);
    // $backgrounds[] = imagecolorallocate($image, 0xCC, 0x92, 0xCF);
    // $background = $backgrounds[array_rand($backgrounds)];
    $background = imagecolorallocate($image, 0xD6, 0xE2, 0xED);

    imagefill($image, 0, 0, $background);
 
    $linecolor1 = imagecolorallocate($image, 0x34, 0x3B, 0x40);
    $linecolor2 = imagecolorallocate($image, 0x65, 0x78, 0x83);

    $textcolor1 = imagecolorallocate($image, 0x65, 0x78, 0x83);
    $textcolor2 = imagecolorallocate($image, 0x34, 0x3B, 0x40);
    
    $font_path = dirname(__FILE__) ;
    // using a mixture of TTF fonts
    $fonts = [];
    $fonts[] = $font_path."/../fonts/type1.ttf";
    $fonts[] = $font_path."/../fonts/type2.ttf";
    //$fonts[] = $font_path."/../fonts/type3.ttf";

    // add random digits to canvas using random black/white colour
    $index = 0;
    $x = $captcha_config['max_font_size']/2;
    //for($x = $captcha_config['max_font_size']/2; $x <= $captcha_config['image_width']; $x += 30) {
    for($index = 0; $index <= 3; $index += 1) {
        $num = $captcha_config['code'][$index];
        $textcolor = (rand() % 2) ? $textcolor1 : $textcolor2;
        $size = rand($captcha_config['min_font_size'],$captcha_config['max_font_size']);
        $y = rand($size, $captcha_config['image_height']);
        $font = $fonts[array_rand($fonts)];
        $angle = rand($captcha_config['angle_min'],$captcha_config['angle_max']);
        imagettftext($image, $size, $angle, $x, $y, $textcolor, $font, $num);
        $x += 25;
    }
    // draw random lines on canvas
    for($i=0; $i < $captcha_config['line_number']; $i++) {
        $linecolor = (rand() % 2) ? $linecolor1 : $linecolor2;
        imagesetthickness($image, rand(1,1));
        imageline($image, rand(0,160), 0, rand(0,160), 45, $linecolor);
    }

    /* Generate random dots in background of the captcha image */
    for( $count=0; $count<$captcha_config['noise_number']; $count++ ) {
        $image_noise_color = (rand() % 2) ? $textcolor1 : $textcolor2;
        imagefilledellipse(
            $image,
            rand(0,$captcha_config['image_width']),
            rand(0,$captcha_config['image_height']),
            2,
            3,
            $image_noise_color
        );
    }

    // display image and clean up
    header('Content-type: image/png');
    imagepng($image);
    imagedestroy($image);
}
