session = Singleton::class('ZN\Storage\Session'); $this->key = md5('SystemCaptchaCodeData'); } /** * The image specifies the path to save. * * @param string $path * * @return Captcha */ public function path(string $path) : Render { $this->path = Base::suffix($path); return $this; } /** * Adjust the size of the captcha. * * @param int $width * @param int $height * * @return Captcha */ public function size(int $width, int $height) : Render { $this->sets['size']['width'] = $width; $this->sets['size']['height'] = $height; return $this; } /** * Sets the character type. * * @param string $type = 'alnum' - options[alnum|numeric|string|alpha|special|all] * * @return Captcha */ public function type(string $type = 'alnum') : Render { $this->sets['text']['type'] = $type; return $this; } /** * Sets the character width. * * @param int $param * * @return Captcha */ public function length(int $param) : Render { $this->sets['text']['length'] = $param; return $this; } /** * Sets the character angle. * * @param int $param * * @return Captcha */ public function angle(Float $param) : Render { $this->sets['text']['angle'] = $param; return $this; } /** * Add ttf fonts. * * @param array $fonts * * @return Captcha */ public function ttf(array $fonts) : Render { $this->sets['text']['ttf'] = $fonts; return $this; } /** * Sets the border color. * * @param string $color = NULL * * @return Captcha */ public function borderColor(?string $color = NULL) : Render { $this->sets['border']['status'] = true; if( ! empty($color) ) { $this->sets['border']['color'] = $this->convertColor($color); } return $this; } /** * Sets the background color. * * @param string $color = NULL * * @return Captcha */ public function bgColor(string $color) : Render { $this->sets['background']['color'] = $this->convertColor($color); return $this; } /** * Add background pictures. * * @param array $image * * @return Captcha */ public function bgImage(array $image) : Render { $this->sets['background']['image'] = $image; return $this; } /** * Sets the text size. * * @param int $size * * @return Captcha */ public function textSize(int $size) : Render { $this->sets['text']['size'] = $size; return $this; } /** * Sets the text coordiante. * * @param int $x * @param int $y * * @return Captcha */ public function textCoordinate(int $x = 0, int $y = 0) : Render { $this->sets['text']['x'] = $x; $this->sets['text']['y'] = $y; return $this; } /** * Sets the text color. * * @param string $color * * @return Captcha */ public function textColor(string $color) : Render { $this->sets['text']['color'] = $this->convertColor($color); return $this; } /** * Sets the grid color. * * @param string $color * * @return Captcha */ public function gridColor(?string $color = NULL) : Render { $this->sets['grid']['status'] = true; if( ! empty($color) ) { $this->sets['grid']['color'] = $this->convertColor($color); } return $this; } /** * Sets the grid space. * * @param int $x = 0 * @param int $y = 0 * * @return Captcha */ public function gridSpace(int $x = 0, int $y = 0) : Render { if( ! empty($x) ) { $this->sets['grid']['spaceX'] = $x; } if( ! empty($y) ) { $this->sets['grid']['spaceY'] = $y; } return $this; } /** * Completes the captcha creation process. * * @param bool $img = false * * @return string */ public function create(bool $img = false) : string { # Create Session $this->session(); if( ! $this->getCode() ) { return ''; // @codeCoverageIgnore } # Clean Captcha Images $this->clean(); # Create Directory $this->directory(); # Create Color $this->color($file); # Background Image $this->background($file); # Text $this->text($file); # Grid $this->grid($file); # Border $this->border($file); # Output return $this->output($img, $file); } /** * Returns the current captcha code. * * @param void * * @return string */ public function getCode() : string { return $this->session->select($this->key); } /** * Protected Color */ protected function color(& $file = NULL) { $sizeset = $this->sets['size']; $this->sizeWidthC = $sizeset['width'] ?? 100; $this->sizeHeightC = $sizeset['height'] ?? 30; $file = imagecreatetruecolor($this->sizeWidthC, $this->sizeHeightC); } /** * Protected Create Directory */ protected function directory() { if( ! is_dir($this->path) ) { mkdir($this->path); // @codeCoverageIgnore } } /** * Protected Session Insert */ protected function session() { $this->sets = array_merge ( Config::default('ZN\Captcha\CaptchaDefaultConfiguration') ::get('ViewObjects', 'captcha'), $this->sets ); $this->session->insert($this->key, Encode\RandomPassword::create($this->sets['text']['length'] ?? 6, $this->sets['text']['type'] ?? 'alnum')); } /** * Protected Output */ protected function output($img, & $file) { $filePath = $this->path . $this->name(); imagepng($file, $filePath); $baseUrl = URL::base($filePath); if( $img === true ) { $captcha = ''; } else { $captcha = $baseUrl; } imagedestroy($file); $this->sets = []; return $captcha; } /** * Protected Border */ protected function border(& $file) { $borderset = $this->sets['border']; $borderStatusC = $borderset['status'] ?? true; if( $borderStatusC === true ) { $bordercolorC = $borderset['color'] ?? '200|200|200'; $borderColor = imagecolorallocate($file, ...explode('|', $bordercolorC)); # Top imageline($file, 0, 0, $this->sizeWidthC, 0, $borderColor); # Right imageline($file, $this->sizeWidthC - 1, 0, $this->sizeWidthC - 1, $this->sizeHeightC, $borderColor); # Bottom imageline($file, 0, $this->sizeHeightC - 1, $this->sizeWidthC, $this->sizeHeightC - 1, $borderColor); # Left imageline($file, 0, 0, 0, $this->sizeHeightC - 1, $borderColor); } } /** * Protected Grid */ protected function grid(& $file) { $gridset = $this->sets['grid']; $gridStatusC = $gridset['status'] ?? false; if( $gridStatusC === true ) { $gridSpaceXC = $gridset['spaceX'] ?? 12; $gridSpaceYC = $gridset['spaceY'] ?? 4; $gridColorC = $gridset['color'] ?? '240|240|240'; $gridIntervalX = $this->sizeWidthC / $gridSpaceXC; if( ! isset($gridSpaceYC)) { $gridIntervalY = (($this->sizeHeightC / $gridSpaceXC) * $gridIntervalX / 2); // @codeCoverageIgnore } else { $gridIntervalY = $this->sizeHeightC / $gridSpaceYC; } $gridColor = imagecolorallocate($file, ...explode('|', $gridColorC)); for( $x = 0 ; $x <= $this->sizeWidthC ; $x += $gridIntervalX ) { imageline($file, $x, 0, $x, $this->sizeHeightC - 1, $gridColor); } for( $y = 0 ; $y <= $this->sizeWidthC; $y += $gridIntervalY ) { imageline($file, 0, $y, $this->sizeWidthC, $y, $gridColor); } } } /** * Protected Text */ protected function text(& $file) { $textset = $this->sets['text']; $textSizeC = $textset['size'] ?? 10; $textXC = $textset['x'] ?? 23; $textYC = $textset['y'] ?? 9; $textAngleC = $textset['angle'] ?? 0; $textTTFC = $textset['ttf'] ?? []; $textColorC = $textset['color'] ?? '0|0|0'; $fontColor = imagecolorallocate($file, ...explode('|', $textColorC)); if( ! empty($textTTFC) ) { $textTTFC = $textTTFC[rand(0, count($textTTFC) - 1)]; $textTTFC = Base::suffix($textTTFC, '.ttf'); if( is_file($textTTFC) ) { imagettftext ( $file, $textSizeC, $textAngleC, $textXC, $textYC + $textSizeC, $fontColor, $textTTFC, $this->getCode() ); } } else { imagestring($file, $textSizeC, $textXC, $textYC, $this->getCode(), $fontColor); } } /** * Protected Background Image */ protected function background(& $file) { $bgset = $this->sets['background']; $backgroundImageC = $bgset['image'] ?? []; if( ! empty($backgroundImageC) ) { if( is_array($backgroundImageC) ) { $backgroundImageC = $backgroundImageC[rand(0, count($backgroundImageC) - 1)]; } if( is_file($backgroundImageC) ) { $infoExtension = strtolower(pathinfo($backgroundImageC, PATHINFO_EXTENSION)); switch( $infoExtension ) { case 'jpeg': case 'jpg' : $file = imagecreatefromjpeg($backgroundImageC); break; case 'webp': $file = imagecreatefromwebp($backgroundImageC); break; case 'png' : $file = imagecreatefrompng($backgroundImageC); break; case 'gif' : $file = imagecreatefromgif($backgroundImageC); break; // @codeCoverageIgnore default : $file = imagecreatefromjpeg($backgroundImageC); } } } else { $backgroundColorC = $bgset['color'] ?? '255|255|255'; $color = imagecolorallocate($file, ...explode('|', $backgroundColorC)); imagefill($file, 0, 0, $color); } } /** * protected clean captcha * * @param void * * @return void */ protected function clean() { $captcha = $this->path . $this->name(); $getCaptchaImages = preg_grep('/captcha\-\w+\.png/', Filesystem::getFiles($this->path, 'png')); foreach( $getCaptchaImages as $image) { if( $this->name() !== $image ) { $captcha = $this->path . $image; if( is_file($captcha) ) { unlink($captcha); } } } } /** * protected captcha name * * @param void * * @return string */ protected function name() { return 'captcha-' . $this->getCode() . '.png'; } /** * protected conver color * * @param string $color * * @return string */ protected function convertColor($color) { if( $convert = (Image\Properties::$colors[$color] ?? NULL) ) { return $convert; // @codeCoverageIgnore } return $color; } }