<?php
/**
 * CAPTCHA class For XOOPS
 *
 * You may not change or alter any portion of this comment or credits
 * of supporting developers from this source code or any supporting source code
 * which is considered copyrighted (c) material of the original comment or credit authors.
 * 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.
 *
 * @copyright       The XOOPS project http://sourceforge.net/projects/xoops/
 * @license         GNU GPL 2 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
 * @since           2.3.0
 * @author          Taiwen Jiang <phppp@users.sourceforge.net>
 * @version         $Id: image.php 4941 2010-07-22 17:13:36Z beckmi $
 * @package         class
 * @subpackage      CAPTCHA
 */

include "../../../../mainfile.php";

error_reporting(0);
$xoopsLogger->activated = false;

/*
if (empty($_SERVER['HTTP_REFERER']) || !preg_match("/^" . preg_quote(XOOPS_URL, '/') . "/", $_SERVER['HTTP_REFERER'])) {
    exit();
}
*/

class XoopsCaptchaImageHandler
{
    var $config    = array();
    var $code;
    var $mode = 'gd';
    var $invalid = false;

    var $font;
    var $spacing;
    var $width;
    var $height;

    var $captcha_handler;

    function __construct()
    {
        xoops_load('XoopsCaptcha');
        $this->captcha_handler = XoopsCaptcha::getInstance();
        $this->config = $this->captcha_handler->loadConfig("image");
    }

    function XoopsCaptchaImageHandler()
    {
        $this->__construct();
    }

    function loadImage()
    {
        $this->generateCode();
        $this->createImage();
    }

    /**
    * Create Code
    */
    function generateCode()
    {
        if ($this->invalid) {
            return false;
        }

        if ($this->mode == "bmp") {
            $this->config["num_chars"] = 4;
            $this->code = rand( pow(10, $this->config["num_chars"] - 1), intval( str_pad("9", $this->config["num_chars"], "9") ) );
        } else {
            $raw_code = md5(uniqid(mt_rand(), 1));
            if (!empty($this->config["skip_characters"])) {
                $valid_code = str_replace($this->config["skip_characters"], "", $raw_code);
                $this->code = substr( $valid_code, 0, $this->config["num_chars"] );
            } else {
                $this->code = substr( $raw_code, 0, $this->config["num_chars"] );
            }
            if (!$this->config["casesensitive"]) {
                $this->code = strtoupper( $this->code );
            }
        }
        $this->captcha_handler->setCode($this->code);
        return true;
    }

    function createImage()
    {
        if ($this->invalid) {
            header("Content-type: image/gif");
            readfile(XOOPS_ROOT_PATH."/images/subject/icon2.gif");
            return;
        }

        if ($this->mode == "bmp") {
            return $this->createImageBmp();
        } else {
            return $this->createImageGd();
        }
    }

    function getList($name, $extension = "")
    {
        $items = array();
        xoops_load('XoopsCache');
        if ($items = XoopsCache::read("captcha_captcha_{$name}")) {
            return $items;
        }

        require_once XOOPS_ROOT_PATH."/class/xoopslists.php";
        $file_path = $this->config["rootpath"]."/{$name}";
        $files = XoopsLists::getFileListAsArray($file_path);
        foreach( $files as $item ) {
            if ( empty($extension) || preg_match("/(\.{$extension})$/i",$item) ) {
                $items[] = $item;
            }
        }
        XoopsCache::write("captcha_captcha_{$name}", $items);
        return $items;
    }

    /**#@+
     *  Create CAPTCHA iamge with GD
     *  Originated by DuGris' SecurityImage
     */
    //  --------------------------------------------------------------------------- //
    // Class : SecurityImage 1.5                                                    //
    // Author: DuGris aka L. Jen <http://www.dugris.info>                            //
    // Email : DuGris@wanadoo.fr                                                    //
    // Licence: GNU                                                                    //
    // Project: The XOOPS Project                                                    //
    //  --------------------------------------------------------------------------- //
    function createImageGd()
    {
        $this->loadFont();
        $this->setImageSize();

        $this->oImage = imagecreatetruecolor($this->width, $this->height);
        $background = imagecolorallocate($this->oImage, 255, 255, 255);
        imagefilledrectangle($this->oImage, 0, 0, $this->width, $this->height, $background);

        switch ($this->config["background_type"]) {
            default:
            case 0:
                $this->drawBars();
                break;

            case 1:
                $this->drawCircles();
                break;

            case 2:
                $this->drawLines();
                break;

            case 3:
                $this->drawRectangles();
                break;

            case 4:
                $this->drawEllipses();
                break;

            case 5:
                $this->drawPolygons();
                break;

            case 100:
                $this->createFromFile();
                break;
        }
        $this->drawBorder();
        $this->drawCode();

        header("Content-type: image/jpeg");
        imagejpeg ($this->oImage);
        imagedestroy($this->oImage);
    }

    function loadFont()
    {
        $fonts = $this->getList("fonts", "ttf");
        $this->font = $this->config["rootpath"] . "/fonts/" . $fonts[array_rand($fonts)];
    }

    function setImageSize()
    {
        $MaxCharWidth = 0;
        $MaxCharHeight = 0;
        $oImage = imagecreatetruecolor(100, 100);
        $text_color = imagecolorallocate($oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
        $FontSize = $this->config["fontsize_max"];
        for ($Angle = -30; $Angle <= 30; $Angle++) {
            for ($i = 65; $i <= 90; $i++) {
                $CharDetails = imageftbbox($FontSize, $Angle, $this->font, chr($i), array());
                $_MaxCharWidth  = abs($CharDetails[0] + $CharDetails[2]);
                if ($_MaxCharWidth > $MaxCharWidth ) {
                    $MaxCharWidth = $_MaxCharWidth;
                }
                $_MaxCharHeight  = abs($CharDetails[1] + $CharDetails[5]);
                if ($_MaxCharHeight > $MaxCharHeight ) {
                    $MaxCharHeight = $_MaxCharHeight;
                }
            }
        }
        imagedestroy($oImage);

        $this->height = $MaxCharHeight + 2;
        $this->spacing = intval( ($this->config["num_chars"] * $MaxCharWidth) / $this->config["num_chars"] );
        $this->width = ($this->config["num_chars"] * $MaxCharWidth) + ($this->spacing/2);
    }

    /**
    * Return random background
    *
    * @return array
    */
    function loadBackground()
    {
        $RandBackground = null;
        if ( $backgrounds = $this->getList("backgrounds", "(gif|jpg|png)") ) {
            $RandBackground = $this->config["rootpath"] . "/backgrounds/" . $backgrounds[array_rand($backgrounds)];
        }
        return $RandBackground;
    }

    /**
    * Draw Image background
    */
    function createFromFile()
    {
        if ( $RandImage = $this->loadBackground() ) {
            $ImageType = @getimagesize($RandImage);
            switch ( @$ImageType[2] ) {
            case 1:
                $BackgroundImage = imagecreatefromgif($RandImage);
                break;

            case 2:
                $BackgroundImage = imagecreatefromjpeg($RandImage);
                break;

            case 3:
                $BackgroundImage = imagecreatefrompng($RandImage);
                break;
            }
        }
        if (!empty($BackgroundImage)) {
            imagecopyresized($this->oImage, $BackgroundImage, 0, 0, 0, 0, imagesx($this->oImage), imagesy($this->oImage), imagesx($BackgroundImage), imagesy($BackgroundImage));
            imagedestroy($BackgroundImage);
        } else {
            $this->drawBars();
        }
    }

    /**
    * Draw Code
    */
    function drawCode()
    {
        for ($i = 0; $i < $this->config["num_chars"] ; $i++) {
            // select random greyscale colour
            $text_color = imagecolorallocate($this->oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));

            // write text to image
            $Angle = mt_rand(10, 30);
            if (($i % 2)) {
                $Angle = mt_rand(-10, -30);
            }

            // select random font size
            $FontSize = mt_rand($this->config["fontsize_min"], $this->config["fontsize_max"]);

            $CharDetails = imageftbbox($FontSize, $Angle, $this->font, $this->code[$i], array());
            $CharHeight = abs( $CharDetails[1] + $CharDetails[5] );

            // calculate character starting coordinates
            $posX = ($this->spacing/2) + ($i * $this->spacing);
            $posY = 2 + ($this->height / 2) + ($CharHeight / 4);

            imagefttext($this->oImage, $FontSize, $Angle, $posX, $posY, $text_color, $this->font, $this->code[$i], array());
        }
    }

    /**
    * Draw Border
    */
    function drawBorder()
    {
        $rgb = rand(50, 150);
        $border_color = imagecolorallocate ($this->oImage, $rgb, $rgb, $rgb);
        imagerectangle($this->oImage, 0, 0, $this->width-1, $this->height-1, $border_color);
    }

    /**
     * Draw Circles background
     */
    function drawCircles()
    {
        for($i = 1; $i <= $this->config["background_num"]; $i++) {
            $randomcolor = imagecolorallocate ($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
            imagefilledellipse($this->oImage, mt_rand(0, $this->width - 10), mt_rand(0, $this->height - 3), mt_rand(10, 20), mt_rand(20, 30), $randomcolor);
        }
    }

    /**
     * Draw Lines background
     */
    function drawLines()
    {
        for ($i = 0; $i < $this->config["background_num"]; $i++) {
            $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
            imageline($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
        }
    }

    /**
     * Draw Rectangles background
     */
    function drawRectangles()
    {
        for ($i = 1; $i <= $this->config["background_num"]; $i++) {
            $randomcolor = imagecolorallocate ($this->oImage , mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
            imagefilledrectangle($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
        }
    }

    /**
     * Draw Bars background
     */
    function drawBars()
    {
        for ($i= 0; $i <= $this->height;) {
            $randomcolor = imagecolorallocate ($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
            imageline( $this->oImage, 0, $i, $this->width, $i, $randomcolor );
            $i = $i + 2.5;
        }
        for ($i = 0; $i <= $this->width;) {
            $randomcolor = imagecolorallocate ($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
            imageline( $this->oImage, $i, 0, $i, $this->height, $randomcolor );
            $i = $i + 2.5;
        }
    }

    /**
    * Draw Ellipses background
    */
    function drawEllipses()
    {
        for ($i = 1; $i <= $this->config["background_num"]; $i++){
            $randomcolor = imagecolorallocate ($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
            imageellipse($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
        }
    }

    /**
    * Draw polygons background
    */
    function drawPolygons()
    {
        for ($i = 1; $i <= $this->config["background_num"]; $i++){
            $randomcolor = imagecolorallocate ($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
            $coords = array();
            for ($j = 1; $j <= $this->config["polygon_point"]; $j++) {
                $coords[] = mt_rand(0, $this->width);
                $coords[] = mt_rand(0, $this->height);
            }
            imagefilledpolygon($this->oImage, $coords, $this->config["polygon_point"], $randomcolor);
        }
    }
    /**#@-*/

    /**
     *  Create CAPTCHA image with BMP
     *
     *  TODO
     */
    function createImageBmp($file = "")
    {
        $image = "";

        if (empty($file)) {
            header("Content-type: image/bmp");
            echo $image;
        } else {
            return $image;
        }
    }
}

$image_handler = new XoopsCaptchaImageHandler();
$image_handler->loadImage();

?>