A super easy PHP Framework for web development!
				https://github.com/exacti/phacil-framework
			
			
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							366 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
	
	
							366 lines
						
					
					
						
							14 KiB
						
					
					
				<?php
 | 
						|
/*
 | 
						|
 * Copyright © 2021 ExacTI Technology Solutions. All rights reserved.
 | 
						|
 * GPLv3 General License.
 | 
						|
 * https://exacti.com.br
 | 
						|
 * Phacil PHP Framework - https://github.com/exacti/phacil-framework
 | 
						|
 */
 | 
						|
 | 
						|
namespace Phacil\Framework;
 | 
						|
 | 
						|
class Captcha {
 | 
						|
	protected $code;
 | 
						|
	public $height = 40;
 | 
						|
    public $width = 220;
 | 
						|
    public $numChar = 8;
 | 
						|
    protected $iscale = 0.9;
 | 
						|
	protected $perturbation = 0.90;
 | 
						|
	protected $noise_level = 1;
 | 
						|
	protected $background = 'black';
 | 
						|
	public $fonts = "/fonts/*/*.ttf";
 | 
						|
	public $pos = 'ABCDEFGHJKLMNOPQRSTUWVXZ0123456789abcdefhijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWVXZ0123456789';
 | 
						|
 | 
						|
	function __construct($width = NULL, $height = NULL, $numChar = 6, $background = 'black') {
 | 
						|
 | 
						|
	    $this->fonts = __DIR__."/fonts/*/*.ttf";
 | 
						|
 | 
						|
        if(!extension_loaded('gd')){
 | 
						|
            throw new \Exception("The captcha function requires GD extension on PHP!");
 | 
						|
        }
 | 
						|
 | 
						|
		$this->numChar = $numChar;
 | 
						|
		$this->background = $background;
 | 
						|
 | 
						|
		$pos = str_split($this->pos);
 | 
						|
 | 
						|
 | 
						|
		for($i = 0; $i < $this->numChar; $i++) {
 | 
						|
			$this->code[] = $pos[mt_rand(0, (count($pos) -1))];
 | 
						|
		}
 | 
						|
 | 
						|
		
 | 
						|
		$this->width = ($width != NULL) ? $width : $this->width;
 | 
						|
		$this->height = ($height != NULL) ? $height : $this->height;
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	public function __help() {
 | 
						|
	    $helpTxt =
 | 
						|
            array(
 | 
						|
                "version" => "1.0",
 | 
						|
                "Description" => "Captcha module.",
 | 
						|
                "Use" => 'Declare new Captcha($width, $height, $numChar, $background) on a variable, use $variable->getCode() to obtain a plain text captcha code (prefer pass thos code to a SESSION) and return $variable->showImage(\'format\').',
 | 
						|
                "Formats" => "bmp, jpg, png, wbmp and gif."
 | 
						|
            );
 | 
						|
 | 
						|
	    var_dump($helpTxt, true);
 | 
						|
    }
 | 
						|
 | 
						|
	function getCode(){
 | 
						|
		return implode("", $this->code);
 | 
						|
	}
 | 
						|
 | 
						|
	function showImage($format = 'png') {
 | 
						|
        $image = imagecreatetruecolor($this->width, $this->height);
 | 
						|
 | 
						|
        $width = imagesx($image); 
 | 
						|
        $height = imagesy($image);
 | 
						|
		
 | 
						|
        $black = imagecolorallocate($image, 33, 33, 33); 
 | 
						|
        $white = imagecolorallocate($image, 255, 255, 255); 
 | 
						|
        $red = imagecolorallocatealpha($image, 255, 0, 0, 50); 
 | 
						|
        $green = imagecolorallocatealpha($image, 0, 255, 0, 75); 
 | 
						|
        $blue = imagecolorallocatealpha($image, 0, 0, 255, 50); 
 | 
						|
		$orange = imagecolorallocatealpha($image, 255, 136, 0, 50);
 | 
						|
		$yellow = imagecolorallocatealpha($image, 255, 255, 0, 50);
 | 
						|
		$punyWhite = imagecolorallocatealpha($image, 255, 255, 255, 40); 
 | 
						|
		$varYellow = imagecolorallocatealpha($image, 255, 255, 0, mt_rand(30,100));
 | 
						|
		$varBlue = imagecolorallocatealpha($image, 0, 0, 255, mt_rand(30,100));
 | 
						|
		$varBlack = imagecolorallocatealpha($image, 33, 33, 33, mt_rand(85,95));
 | 
						|
		$pureYellow = imagecolorallocate($image, 255, 255, 0); 
 | 
						|
		$pureGreen = imagecolorallocate($image, 0, 255, 0);
 | 
						|
		$softGreen = imagecolorallocate($image, 153, 241, 197);
 | 
						|
		$softBlue = imagecolorallocate($image, 180, 225, 245);
 | 
						|
		$softpink = imagecolorallocate($image, 250, 165, 215);
 | 
						|
		$pureRed = imagecolorallocate($image, 250, 0, 0);
 | 
						|
		$strongGreen = imagecolorallocate($image, 95, 115, 75);
 | 
						|
		$pureBlue = imagecolorallocate($image, 0, 0, 215);
 | 
						|
		$pureorange = imagecolorallocate($image, 255, 135, 0);
 | 
						|
		$strangePurple = imagecolorallocate($image, 0, 80, 90);
 | 
						|
		/*$pureBlue = imagecolorallocate($image, 200, 100, 245);*/
 | 
						|
 | 
						|
        $this->gdlinecolor = $yellow;
 | 
						|
		
 | 
						|
		switch($this->background) {
 | 
						|
			case 'black':
 | 
						|
				$fontColors = array($white, $pureYellow, $pureGreen, $softBlue, $softGreen, $softpink);
 | 
						|
				imagefilledrectangle($image, 0, 0, $width, $height, $black); 
 | 
						|
				break;
 | 
						|
			case 'white':
 | 
						|
				$fontColors = array($black, $pureRed, $strongGreen, $pureBlue, $pureorange, $strangePurple);
 | 
						|
				imagefilledrectangle($image, 0, 0, $width, $height, $white); 
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		
 | 
						|
         
 | 
						|
		if(mt_rand(0,2) == 2) {
 | 
						|
			imagefilledellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $red);
 | 
						|
		} else {
 | 
						|
			imagefilledrectangle($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(5, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(5, $this->height)), $red);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imagefilledellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $green);
 | 
						|
		} else {
 | 
						|
			imagefilledrectangle($image, ceil(mt_rand(5, 145)), ceil(mt_rand(0, 35)), ceil(mt_rand(5, 175)), ceil(mt_rand(0, 40)), $green);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imagefilledellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $varBlue);
 | 
						|
		} else {
 | 
						|
			imagefilledrectangle($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $varBlue);
 | 
						|
		}
 | 
						|
		/*if(mt_rand(1,2) == 2) {
 | 
						|
			imagefilledellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $orange);
 | 
						|
		} else {
 | 
						|
			imagefilledrectangle($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $orange);
 | 
						|
		}*/
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imagefilledellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $yellow);
 | 
						|
		} else {
 | 
						|
			imagefilledrectangle($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $yellow);
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
        imagefilledrectangle($image, 0, 0, $width, 0, $black);
 | 
						|
        imagefilledrectangle($image, $width - 1, 0, $width - 1, $height - 1, $black);
 | 
						|
        imagefilledrectangle($image, 0, 0, 0, $height - 1, $black);
 | 
						|
        imagefilledrectangle($image, 0, $height - 1, $width, $height - 1, $black);
 | 
						|
 | 
						|
 | 
						|
        $this->ttfFonts = glob($this->fonts);
 | 
						|
         
 | 
						|
        $space = ($this->width - 10) / $this->numChar;
 | 
						|
 | 
						|
		foreach($this->code as $key => $character) {
 | 
						|
            //$qualfonte = __DIR__."/gd_fonts/".mt_rand(0,8).".gdf";
 | 
						|
 | 
						|
            $qualfonte = mt_rand(0, (count($this->ttfFonts)-1));
 | 
						|
            $fonteCaptcha = $this->ttfFonts[$key];
 | 
						|
 | 
						|
            $tamanhoFonte = mt_rand(16, 26);
 | 
						|
 | 
						|
            //Carregar uma nova fonte
 | 
						|
            //$fonteCaptcha = imageloadfont($qualfonte);
 | 
						|
 | 
						|
			$y = ceil(mt_rand(($tamanhoFonte+5), $this->height-5 ));
 | 
						|
			$divisor = 1;
 | 
						|
			$plus = 10;
 | 
						|
			$incre = 0;
 | 
						|
			//$securityX = (isset($x)) ? $x + 18 : 0;
 | 
						|
			switch ($key) {
 | 
						|
				case "0":
 | 
						|
					$x = ceil(mt_rand(0, $space-$plus));
 | 
						|
					break;
 | 
						|
				case "1":
 | 
						|
					$x = ceil(mt_rand($x+$incre/$divisor+$plus, $space*2));
 | 
						|
					break;
 | 
						|
				case "2":
 | 
						|
					$x = ceil(mt_rand($x+$incre/$divisor+$plus, $space*3));
 | 
						|
					break;
 | 
						|
				case "3":
 | 
						|
					$x = ceil(mt_rand($x+$incre/$divisor+$plus, $space*4));
 | 
						|
					break;
 | 
						|
				case "4":
 | 
						|
					$x = ceil(mt_rand($x+$incre/$divisor+$plus, $space*5));
 | 
						|
					break;
 | 
						|
				case "5":
 | 
						|
					$x = ceil(mt_rand($x+$incre/$divisor+$plus, $space*5+$space/2));
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					$x = ceil(mt_rand($x+$incre/$divisor+$plus, $space*$key+$space/2));
 | 
						|
					break;
 | 
						|
			}
 | 
						|
 | 
						|
			if(isset($securityX) && $x < $securityX) {
 | 
						|
                $x = $securityX;
 | 
						|
			}
 | 
						|
 | 
						|
			$rotate = mt_rand(-20, 35);
 | 
						|
 | 
						|
 | 
						|
			//imagechar (  $image , $fonteCaptcha , $x , $y, $character , $fontColors[mt_rand(0,count($fontColors)-1)]);
 | 
						|
            $dadosChar = imagettftext ( $image , $tamanhoFonte, $rotate , $x ,  $y ,  $fontColors[mt_rand(0,count($fontColors)-1)], $fonteCaptcha , $character );
 | 
						|
 | 
						|
            if(mt_rand(0, 5) == 1)
 | 
						|
                $dadosChar = imagettftext ( $image , $tamanhoFonte, $rotate , $x+1 ,  $y+1 ,  $fontColors[mt_rand(0,count($fontColors)-1)], $fonteCaptcha , $character );
 | 
						|
 | 
						|
			$securityX = max([$dadosChar[2], $dadosChar[4]]);
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
        $image = $this->drawNoise($image);
 | 
						|
 | 
						|
		//imagefilter($image, IMG_FILTER_PIXELATE, 2,1);
 | 
						|
 | 
						|
		//exit;
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imageellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $red);
 | 
						|
		} else {
 | 
						|
			imagerectangle($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $red);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imageellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $green);
 | 
						|
		} else {
 | 
						|
			imageline($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $green);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imageellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $blue);
 | 
						|
		} else {
 | 
						|
			imagerectangle($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $blue);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imageellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $orange);
 | 
						|
		} else {
 | 
						|
			imageline($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $orange);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imageellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $varYellow);
 | 
						|
		} else {
 | 
						|
			imageline($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $varYellow);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imageellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $punyWhite);
 | 
						|
		} else {
 | 
						|
			imageline($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $punyWhite);
 | 
						|
		}
 | 
						|
		if(mt_rand(1,2) == 2) {
 | 
						|
			imagefilledellipse($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), 30, 30, $varBlack); 
 | 
						|
		} else {
 | 
						|
			imagefilledrectangle($image, ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width)), ceil(mt_rand(0, $this->height)), $varBlack); 
 | 
						|
		}
 | 
						|
		//imagearc (  $image , ceil(mt_rand(5, $this->width)) , ceil(mt_rand(0, $this->height)) ,ceil(mt_rand(5, $this->width)) , ceil(mt_rand(0, $this->height)), ceil(mt_rand(5, $this->width))/ceil(mt_rand(5, $this->height)) , ceil(mt_rand(5, $this->height))/ceil(mt_rand(0, $this->width)) , $pureYellow );
 | 
						|
			
 | 
						|
		header('Cache-Control: no-cache');
 | 
						|
		
 | 
						|
		if($format == 'jpeg' || $format == 'jpg') {
 | 
						|
			header('Content-type: image/jpeg');
 | 
						|
			imagejpeg($image);
 | 
						|
		} elseif ($format == 'png') {
 | 
						|
			header('Content-type: image/png');
 | 
						|
			imagepng($image);
 | 
						|
		} elseif ($format == 'bmp' || $format == 'bitmap') {
 | 
						|
			header('Content-type: image/bmp');
 | 
						|
			imagebmp($image);
 | 
						|
		} elseif ($format == 'gif' || $format == 'giff') {
 | 
						|
			header('Content-type: image/gif');
 | 
						|
			imagegif($image);
 | 
						|
		} elseif ($format == 'wbmp') {
 | 
						|
			header('Content-type: image/vnd.wap.wbmp');
 | 
						|
			imagewbmp($image);
 | 
						|
		}
 | 
						|
		
 | 
						|
		imagedestroy($image);		
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    protected function drawNoise($im)
 | 
						|
    {
 | 
						|
        if ($this->noise_level > 10) {
 | 
						|
            $noise_level = 10;
 | 
						|
        } else {
 | 
						|
            $noise_level = $this->noise_level;
 | 
						|
        }
 | 
						|
        $t0 = microtime(true);
 | 
						|
        $noise_level *= M_LOG2E;
 | 
						|
        for ($x = 1; $x < $this->width; $x += 20) {
 | 
						|
            for ($y = 1; $y < $this->height; $y += 20) {
 | 
						|
                for ($i = 0; $i < $noise_level; ++$i) {
 | 
						|
                    $x1 = mt_rand($x, $x + 20);
 | 
						|
                    $y1 = mt_rand($y, $y + 20);
 | 
						|
                    $size = mt_rand(1, 3);
 | 
						|
                    if ($x1 - $size <= 0 && $y1 - $size <= 0) continue; // dont cover 0,0 since it is used by imagedistortedcopy
 | 
						|
                    imagefilledarc($im, $x1, $y1, $size, $size, 0, mt_rand(180,360), $this->gdlinecolor, IMG_ARC_PIE);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $t = microtime(true) - $t0;
 | 
						|
 | 
						|
        return $im;
 | 
						|
        /*
 | 
						|
        // DEBUG
 | 
						|
        imagestring($this->im, 5, 25, 30, "$t", $this->gdnoisecolor);
 | 
						|
        header('content-type: image/png');
 | 
						|
        imagepng($this->im);
 | 
						|
        exit;
 | 
						|
        */
 | 
						|
    }
 | 
						|
 | 
						|
    protected function distortedCopy($im, $im2)
 | 
						|
    {
 | 
						|
        $this->tmpimg = $im2;
 | 
						|
        $this->im = $im;
 | 
						|
 | 
						|
        $numpoles = 3;       // distortion factor
 | 
						|
        $px       = array(); // x coordinates of poles
 | 
						|
        $py       = array(); // y coordinates of poles
 | 
						|
        $rad      = array(); // radius of distortion from pole
 | 
						|
        $amp      = array(); // amplitude
 | 
						|
        $x        = ($this->width / 4); // lowest x coordinate of a pole
 | 
						|
        $maxX     = $this->width - $x;  // maximum x coordinate of a pole
 | 
						|
        $dx       = mt_rand($x / 10, $x);     // horizontal distance between poles
 | 
						|
        $y        = mt_rand(20, $this->height - 20);  // random y coord
 | 
						|
        $dy       = mt_rand(20, $this->height * 0.7); // y distance
 | 
						|
        $minY     = 20;                                     // minimum y coordinate
 | 
						|
        $maxY     = $this->height - 20;               // maximum y cooddinate
 | 
						|
        // make array of poles AKA attractor points
 | 
						|
        for ($i = 0; $i < $numpoles; ++ $i) {
 | 
						|
            $px[$i]  = ($x + ($dx * $i)) % $maxX;
 | 
						|
            $py[$i]  = ($y + ($dy * $i)) % $maxY + $minY;
 | 
						|
            $rad[$i] = mt_rand($this->height * 0.4, $this->height * 0.8);
 | 
						|
            $tmp     = ((- $this->frand()) * 0.15) - .15;
 | 
						|
            $amp[$i] = $this->perturbation * $tmp;
 | 
						|
        }
 | 
						|
        $bgCol   = imagecolorat($this->tmpimg, 0, 0);
 | 
						|
        $width2  = $this->iscale * $this->width;
 | 
						|
        $height2 = $this->iscale * $this->height;
 | 
						|
        imagepalettecopy($this->im, $this->tmpimg); // copy palette to final image so text colors come across
 | 
						|
        // loop over $img pixels, take pixels from $tmpimg with distortion field
 | 
						|
        for ($ix = 0; $ix < $this->width; ++ $ix) {
 | 
						|
            for ($iy = 0; $iy < $this->height; ++ $iy) {
 | 
						|
                $x = $ix;
 | 
						|
                $y = $iy;
 | 
						|
                for ($i = 0; $i < $numpoles; ++ $i) {
 | 
						|
                    $dx = $ix - $px[$i];
 | 
						|
                    $dy = $iy - $py[$i];
 | 
						|
                    if ($dx == 0 && $dy == 0) {
 | 
						|
                        continue;
 | 
						|
                    }
 | 
						|
                    $r = sqrt($dx * $dx + $dy * $dy);
 | 
						|
                    if ($r > $rad[$i]) {
 | 
						|
                        continue;
 | 
						|
                    }
 | 
						|
                    $rscale = $amp[$i] * sin(3.14 * $r / $rad[$i]);
 | 
						|
                    $x += $dx * $rscale;
 | 
						|
                    $y += $dy * $rscale;
 | 
						|
                }
 | 
						|
                $c = $bgCol;
 | 
						|
                $x *= $this->iscale;
 | 
						|
                $y *= $this->iscale;
 | 
						|
                if ($x >= 0 && $x < $width2 && $y >= 0 && $y < $height2) {
 | 
						|
                    $c = imagecolorat($this->tmpimg, $x, $y);
 | 
						|
                }
 | 
						|
                if ($c != $bgCol) { // only copy pixels of letters to preserve any background image
 | 
						|
                    imagesetpixel($this->im, $ix, $iy, $c);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $this->im;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function frand()
 | 
						|
    {
 | 
						|
        return 0.0001 * mt_rand(0,9999);
 | 
						|
    }
 | 
						|
}
 | 
						|
 |