<?php
/**
* @version	$Id: captcha_helper.php 15145 2012-03-04 09:04:08Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

defined('FULL_PATH') or die('restricted access!');

class kCaptchaHelper extends kHelper {

	var $width;
	var $height;

	function GenerateCaptchaCode($len = 5)
	{
		$chars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
		$s = '';
		for ($i = 0; $i < $len; $i++) {
			$s .= $chars[ rand(0, strlen($chars)-1) ];
		}
		return $s;
	}

	function graphics($w, $h)
	{
		$this->width = $w;
		$this->height = $h;
	}

	function GenerateCaptchaImage($rand, $width, $height, $filter_blur = false)
	{
		global $site_font_path;
		global $site_font_validation;

		$image = imagecreate($width, $height);
		$bgColor = imagecolorallocate ($image, 255, 255, 255);
		$textColor = imagecolorallocate ($image, 0, 0, 0);

		// add random noise
		for ($i = 0; $i < 20; $i++) {
			$rx1 = rand(0, $width);
			$rx2 = rand(0, $width);
			$ry1 = rand(0, $height);
			$ry2 = rand(0, $height);
			$rcVal = rand(0, 255);
			$rc1 = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(100, 255));
			imageline($image, $rx1, $ry1, $rx2, $ry2, $rc1);
		}

		// write the random number

		$dimensions = imagettfbbox($height*0.75, 0, KERNEL_PATH.'/fonts/monofont.ttf', $rand );

		imagettftext($image, $height*0.75, 0, floor(($width - $dimensions[4])/2),  floor(($height - $dimensions[5])/2), $textColor, KERNEL_PATH.'/fonts/monofont.ttf', $rand);

		//		$font = imageloadfont(KERNEL_PATH.'/fonts/monofont.ttf');
		//		imagestring($image, $font, 3, 0, $rand, $textColor);

		if ($filter_blur) $this->blur($image, 3);

		// send several headers to make sure the image is not cached
		// date in the past
		header("Expires: Mon, 23 Jul 1993 05:00:00 GMT");

		// always modified
		header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");

		// HTTP/1.1
		header("Cache-Control: no-store, no-cache, must-revalidate");
		header("Cache-Control: post-check=0, pre-check=0", false);

		// HTTP/1.0
		header("Pragma: no-cache");

		// send the content type header so the image is displayed properly
		header('Content-type: image/jpeg');

		imagejpeg($image);
		imagedestroy($image);
	}

	function blur(&$gdimg, $radius = 5.0)
	{
		// Taken from Torstein Hønsi's phpUnsharpMask (see phpthumb.unsharp.php)
		$radius = round(max(0, min($radius, 50)) * 2);
		if (!$radius) {
			return false;
		}

		$w = ImageSX($gdimg);
		$h = ImageSY($gdimg);
		$imgBlur = ImageCreateTrueColor($w, $h);

		if ($imgBlur) {
			// Gaussian blur matrix:
			//    1    2    1
			//    2    4    2
			//    1    2    1

			// Move copies of the image around one pixel at the time and merge them with weight
			// according to the matrix. The same matrix is simply repeated for higher radii.
			for ($i = 0; $i < $radius; $i++)    {
				ImageCopy     ($imgBlur, $gdimg, 0, 0, 1, 1, $w - 1, $h - 1);            // up left
				ImageCopyMerge($imgBlur, $gdimg, 1, 1, 0, 0, $w,     $h,     50.00000);  // down right
				ImageCopyMerge($imgBlur, $gdimg, 0, 1, 1, 0, $w - 1, $h,     33.33333);  // down left
				ImageCopyMerge($imgBlur, $gdimg, 1, 0, 0, 1, $w,     $h - 1, 25.00000);  // up right
				ImageCopyMerge($imgBlur, $gdimg, 0, 0, 1, 0, $w - 1, $h,     33.33333);  // left
				ImageCopyMerge($imgBlur, $gdimg, 1, 0, 0, 0, $w,     $h,     25.00000);  // right
				ImageCopyMerge($imgBlur, $gdimg, 0, 0, 0, 1, $w,     $h - 1, 20.00000);  // up
				ImageCopyMerge($imgBlur, $gdimg, 0, 1, 0, 0, $w,     $h,     16.666667); // down
				ImageCopyMerge($imgBlur, $gdimg, 0, 0, 0, 0, $w,     $h,     50.000000); // center
				ImageCopy     ($gdimg, $imgBlur, 0, 0, 0, 0, $w,     $h);
			}

			return true;
		}

		return false;
	}

	/**
	 * Generates captcha code for showing on form
	 *
	 * @param string $variable_name
	 */
	function prepareCode($variable_name)
	{
		if ($this->Application->isAdmin || $this->Application->RecallVar($variable_name)) {
			// when code found don't generate it 2nd time
			return $this->Application->RecallVar($variable_name);
		}

		$code = $this->GenerateCaptchaCode();
		$this->Application->StoreVar($variable_name, $code);

		return $code;
	}

	/**
	 * Validates captcha code on form
	 *
	 * @param kEvent $event
	 * @param bool $check_request
	 * @return bool
	 */
	function validateCode($event, $check_request = true)
	{
		if ($this->Application->isAdmin) {
			// no captcha codes in admin
			return true;
		}

		if ($check_request) {
			// perform validation only when field is found on form
			list ($id, $field_values) = each($this->Application->GetVar($event->getPrefixSpecial()));
			if (!array_key_exists('Captcha', $field_values)) {
				// when captcha code not submitted
				return true;
			}
		}

		$object = $event->getObject();
		/* @var $object kDBItem */

		$valid_code = $this->Application->RecallVar($event->getPrefixSpecial() . '_captcha_code');

		if (!$object->GetDBField('Captcha') || ($object->GetDBField('Captcha') != $valid_code)) {
			// empty code OR codes doesn't match
			$object->SetError('Captcha', 'captcha_error', 'lu_captcha_error');

			$this->Application->StoreVar($event->getPrefixSpecial() . '_captcha_code', $this->GenerateCaptchaCode());
			return false;
		}

		return true;
	}
}