Location: PHPKode > projects > phpBB Smith - Modifications/Hacks > Photo Visual Confirmation/root/includes/captcha/captcha_photo.php
<?php
/*-----------------------------------------------------------------------------
	Photo Visual Confirmation - A phpBB Add-On
  ----------------------------------------------------------------------------
	captcha_photo.php
		Captcha Image Output File
	File Version: 2.0.2
	Begun: May 29, 2007
	Last Modified: April 12, 2010
  ----------------------------------------------------------------------------
	Copyright 2009, 2010 by Jeremy Rogers.
	License: GNU General Public License v2
-----------------------------------------------------------------------------*/

/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
	exit;
}

class captcha
{
	var $tmpimage		= false;
	var $colors			= array();
	var $order			= array();
	var $width;
	var $height;
	var $targetx;
	var $targety;
	var $fail;
	var $pass;
	var $image;
	var $filters;
	var $digit;

	function captcha($width = 100, $height = 100, $pass_path = '', $fail_path = '')
	{
		global $config, $phpbb_root_path;

		$this->width	= $width;
		$this->height	= $height;

		$path = $this->prep_path($phpbb_root_path . $config['photo_captcha_img_path']);

		$this->pass		= $this->prep_path($path . $pass_path);
		$this->fail		= $this->prep_path($path . $fail_path);

		// Init the random generator.
		// You may be tempted to use a seed in this. Don't. It breaks the
		// image adjustments performed later.
		mt_srand();

		/*
		Define the order in which affects are applied to images
		and some extra info for calling functions. The structure is:
			0	=> Effect/function name
			1	=> Run a 1 in X check? true/false
			2	=> Optional; Function to call. If omitted, 0 is used.
		Other entries are used for arguments when the functions are called.
		*/
		$this->order = array(
			array('mirror',			true),
			array('copy_cropped',	false),
			array('gamma',			false),
			array('rotate',			true),
			array('gray',			true,	'filter', IMG_FILTER_GRAYSCALE),
			array('color',			true),
			array('blur',			true,	'filter', IMG_FILTER_SELECTIVE_BLUR),
			array('gblur',			true,	'filter', IMG_FILTER_GAUSSIAN_BLUR),
			array('mean',			true,	'filter', IMG_FILTER_MEAN_REMOVAL),
			array('smooth',			true,	'filter', IMG_FILTER_SMOOTH, mt_rand(-1, 8)),
			array('wave',			true),
			array('noise',			true),
			array('interlace',		true),
		);

		$this->digit	= request_var('idx', 0);
	}

	function prep_path($path)
	{
		if( substr($path, -1) != '/' )
		{
			$path .= '/';
		}
		return $path;
	}

	function get_img_list($directory, $single = false)
	{
		$options	= array();
		$dirlist = opendir($directory);
		while( ($filename = readdir($dirlist)) !== false)
		{
			if( $this->test_file($filename) )
			{
				$options[] = $filename;
				if( $single )
				{
					break;
				}
			}
		}
		closedir($dirlist);

		if( $single && !empty($options) )
		{
			return $options[0];
		}
		return $options;
	}

	function execute($code)
	{
		$code = substr($code, $this->digit, 1);

		$directory = ( $code == 0 ) ? $this->fail: $this->pass;

		// Get images
		$options = $this->get_img_list($directory);

		if (empty($options))
		{
			return; // No usable images!
		}

		// Select a random image from available options
		$selindex		= intval(base_convert(gen_rand_string(7), 16, 10));
		$selindex		= $selindex % count($options);
		$fullpath		= $directory . $options[$selindex];
		$this->image	= @imagecreatefromjpeg($fullpath);
		if (!$this->image)
		{
			return;  // Image creation failed :(
		}

		$this->get_targets();

		// Apply image transformations
		foreach($this->order as $v)
		{
			$name	= array_shift($v);
			$test	= array_shift($v);
			$func	= array_shift($v);
			if( $test )
			{
				if( !$this->test($name) )
				{
					continue;
				}
			}
			if( empty($func) )
			{
				$func = $name;
			}
			call_user_func_array(array(&$this, $func), $v);
		}

		// Print the image
		$this->print_image();
	}

	function execute_filter($filter, $mode)
	{
		// Get the first valid image to preview
		$preview_image = $this->get_img_list($this->pass, true);
		if (empty($preview_image))
		{
			return;	// No usable images!
		}

		$this->image	= @imagecreatefromjpeg($this->pass . $preview_image);
		if (!$this->image)
		{
			return;  // Image creation failed :(
		}
		$this->tmpimage		= imagecreatetruecolor($this->width, $this->height);
		$this->get_targets();

		imagecopyresampled($this->tmpimage, $this->image, 0, 0, 0, 0, $this->width, $this->height, $this->targetx, $this->targety);
		$this->swap();

		if( !$mode )
		{
			// Return the simple image
			$this->print_image();
			return;
		}
		switch( $filter )
		{
			case 'mirror':
				$this->targetx	= $this->width;
				$this->targety	= $this->height;
				$this->mirror();
			break;
			case 'rotate':
				$this->image = imagerotate($this->image, 90, 0);
			break;
			case 'color':
				imagefilter($this->image, IMG_FILTER_COLORIZE, 50, 0, 0);
			break;
			case 'blur':
				imagefilter($this->image, IMG_FILTER_SELECTIVE_BLUR);
			break;
			case 'gblur':
				imagefilter($this->image, IMG_FILTER_GAUSSIAN_BLUR);
			break;
			case 'mean':
				imagefilter($this->image, IMG_FILTER_MEAN_REMOVAL);
			break;
			case 'gray':
				imagefilter($this->image, IMG_FILTER_GRAYSCALE);
			break;
			case 'smooth':
				imagefilter($this->image, IMG_FILTER_SMOOTH, mt_rand(-1, 8));
			break;
			default:
				if( method_exists($this, $filter) )
				{
					$this->$filter();
				}
			break;
		}
		$this->print_image();
	}

/*	print_image
		Prints a captcha image.
*/
	function print_image()
	{
		// Print the image
		header('Content-Type: image/jpeg');
		header('Cache-control: no-cache, no-store');
		imagejpeg($this->image);
		imagedestroy($this->image);
		if( is_resource($this->tmpimage) )
		{
			imagedestroy($this->tmpimage);
		}
	}

/*	test
		Used to test if an image transformation is to be applied based on ACP
		configuration settings. See _do_test for setting details.

	$mode
		Shortened form of configuration key for the image transformation
		setting, e.g. "blur" or "rotate."
*/
	function test($mode)
	{
		global $config;
		$result = 0;
		$result = $this->_do_test('photo_captcha_filter_' . $mode);
		if( $result === false )
		{
			$result = $this->_do_test('photo_captcha_' . $mode);
		}
		return ( $result === 1 ) ? true: false;
	}

/*	_do_test
		Computes a 1 in X chance based on a config var. Special cases are values
		of 0 or 1 in the config var: 0 forces disabled, 1 forces enabled.
		Returns false if the config var does not exist.

	$mode
		Key in global $config for the image transformation setting.
*/
	function _do_test($mode)
	{
		global $config;
		if( !isset($config[$mode]) )
		{
			return false;
		}
		if( !$config[$mode] )
		{
			return 0;
		}
		if( $config[$mode] == 1 )
		{
			return 1;
		}
		// Use 0 instead of 1 to start; ACP allows entry of 99 as a max
		return mt_rand(0, $config[$mode]-1);
	}

/*	swap
		Destroys an old image resource, assigns a temporary resource to
		$this->image in it's place.
*/
	function swap()
	{
		imagedestroy($this->image);
		$this->image = $this->tmpimage;
		// Cannot use imagedestroy on tmpimage here.
		// It will break image generation.
	}

	function test_file($filename)
	{
		if( ($ext_pos = strrpos($filename, '.')) !== false )
		{
			// Get extension, in lowercase; check against allowed extensions.
			$extension = strtolower(substr($filename, $ext_pos + 1));
			if( in_array($extension, array('jpg', 'jpeg')) )
			{
				// Good image.
				return true;
			}
		}

		// If we get here, it's not an allowable image
		return false;
	}

/* wave
		Wave distortion effect. Borrowed from phpBB 3.0.5's GD captcha
		with minor adjustments.
*/
	function wave()
	{
		$period_x		= mt_rand(12,18);
		$period_y		= mt_rand(7,14);
		$amp_x			= mt_rand(5,10);
		$amp_y			= mt_rand(2,4);
		$socket			= mt_rand(0,100);
		$dampen_x		= mt_rand($this->width/5, $this->width/2);
		$dampen_y		= mt_rand($this->height/5, $this->height/2);
		$direction_x	= (mt_rand (0, 1));
		$direction_y	= (mt_rand (0, 1));

		for ($i = 0; $i < $this->width; $i++)
		{
			$dir = ($direction_x) ? $i : ($this->width - $i);
			imagecopy($this->image, $this->image, $i-1, sin($socket+ $i/($period_x + $dir/$dampen_x)) * $amp_x, $i, 0, 1, $this->height);
		}
		$socket = mt_rand(0,100);
		for ($i = 0; $i < $this->height; $i++)
		{
			$dir = ($direction_y) ? $i : ($this->height - $i);
			imagecopy($this->image, $this->image ,sin($socket + $i/($period_y + ($dir)/$dampen_y)) * $amp_y, $i-1, 0, $i, $this->width, 1);
		}
	}

/* set_color
		Allocates a color in an image and stores the resulting resource
		for later use.
*/
	function set_color($name, $red = 0, $green = 0, $blue = 0)
	{
		if( isset($this->colors[$name]) )
		{
			return;
		}
	    $this->colors[$name] = imagecolorallocate($this->image, $red, $green, $blue);
	}

/* interlace
		Applies the interlace effect to an image.
*/
	function interlace()
	{
		$this->set_color('black');
		$this->set_color('grey', 192, 192, 192);

		$color		= ( mt_rand(0,1) ) ? $this->colors['black'] : $this->colors['grey'];
		$start		= mt_rand(0,1);
		$skip		= mt_rand(2,4);
		// Randomly choose horizontal or vertical lines
		if( mt_rand(0,1) )
		{
			for ($y = $start; $y < $this->height; $y += $skip)
			{
				imageline($this->image, 0, $y, $this->width, $y, $color);
			}
		}
		else
		{
			for ($x = $start; $x < $this->width; $x += $skip)
			{
				imageline($this->image, $x, 0, $x, $this->height, $color);
			}
		}
	}

/* mirror
		Reflects an image.
*/
	function mirror()
	{
		$this->tmpimage	= imagecreatetruecolor($this->targetx, $this->targety);
		imagecopyresampled($this->tmpimage, $this->image, 0, 0, $this->targetx, 0, $this->targetx, $this->targety, -$this->targetx, $this->targety);
		$this->swap();
	}

/* noise
		Adds noise to an image by altering the color of each pixel randomly.
*/
	function noise()
	{
		$min_rand = mt_rand(-50, -25);
		$max_rand = mt_rand(25, 50);
		for ($x = 0; $x < $this->width; $x++)
		{
			for ($y = 0; $y < $this->height; $y++)
			{
				if (mt_rand(0,1))
				{
					$rgb		= imagecolorat($this->image, $x, $y);
					$red		= ($rgb >> 16) & 0xFF;
					$green		= ($rgb >> 8) & 0xFF;
					$blue		= $rgb & 0xFF;
					$modifier	= mt_rand($min_rand,$max_rand);
					$red		= $this->check_rgb($red, $modifier);
					$green		= $this->check_rgb($green, $modifier);
					$blue		= $this->check_rgb($blue, $modifier);
					$newcol		= imagecolorallocate($this->image, $red, $green, $blue);
					imagesetpixel($this->image, $x, $y, $newcol);
				}
			}
		}
	}

/* check_rgb
		Modifies an RGB number and makes sure the number is still valid
		in the 0-255 range.

	$val
		The RGB number.
	$modifier
		The number added to the RGB number.
*/
	function check_rgb($val, $modifier = 0)
	{
		$val += $modifier;
		if ($val > 255)
		{
			return 255;
		}
		if ($val < 0)
		{
			return 0;
		}
		return $val;
	}

/* copy_cropped
		Resizes and crops an image into the size that would be output as
		part of a CAPTCHA.
*/
	function copy_cropped()
	{
		$sourcex			= mt_rand(($this->targetx * 7)/10, ($this->targetx * 9)/10);
		$sourcey			= mt_rand(($this->targety * 7)/10, ($this->targety * 9)/10);
		$offx				= mt_rand(0, $this->targetx - $sourcex);
		$offy				= mt_rand(0, $this->targety - $sourcey);
		$this->tmpimage		= imagecreatetruecolor($this->width, $this->height);
		imagecopyresampled($this->tmpimage, $this->image, 0, 0, $offx, $offy, $this->width, $this->height, $sourcex, $sourcey);
		$this->swap();
	}

/* gamma
		Changes the gamma value of an image.
*/
	function gamma()
	{
		imagegammacorrect($this->image, 1.0, (0.5 + mt_rand(0,1200)*0.001));
	}

/* rotate
		Turns an image 90 degrees left or right.
*/
	function rotate()
	{
		$degrees = ( mt_rand(0,1) ) ? 90: -90;
		$this->image = imagerotate($this->image, $degrees, 0);
	}

/* color
		Tints an image in red, green, or blue.
*/
	function color()
	{
		$red = $green = $blue = 0;
		switch( mt_rand(1, 3) )
		{
			case 1:
				$red = mt_rand(10, 50);
			break;
			case 2:
				$green = mt_rand(10, 50);
			break;
			case 3:
				$blue = mt_rand(10, 50);
			break;
		}
		if( $red || $green || $blue )
		{
			imagefilter($this->image, IMG_FILTER_COLORIZE, $red, $blue, $green);
		}
	}

/* filter
		Interface for calling imagefilter().
*/
	function filter()
	{
		$args = func_get_args();
		array_unshift($args, $this->image);
		call_user_func_array('imagefilter', $args);
	}

/* get_targets
		Gets the width/height of an image for later use.
*/
	function get_targets()
	{
		$this->targetx	= imagesx($this->image);
		$this->targety	= imagesy($this->image);
	}
}

?>
Return current item: phpBB Smith - Modifications/Hacks