vd/app/Domains/Captcha/Services/CaptchaService.php
2018-12-10 18:54:06 +08:00

419 lines
8.8 KiB
PHP

<?php
namespace App\Domains\Captcha\Services;
use Exception;
use Illuminate\Support\Str;
use Illuminate\Config\Repository;
use Intervention\Image\ImageManager;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Session\Store as Session;
use Illuminate\Hashing\BcryptHasher as Hasher;
class CaptchaService
{
/**
* @var Filesystem
*/
protected $files;
/**
* @var Repository
*/
protected $config;
/**
* @var ImageManager
*/
protected $imageManager;
/**
* @var Hasher
*/
protected $hasher;
/**
* @var Str
*/
protected $str;
/**
* @var ImageManager->canvas
*/
protected $canvas;
/**
* @var ImageManager->image
*/
protected $image;
/**
* @var array
*/
protected $backgrounds = [];
/**
* @var array
*/
protected $fonts = [];
/**
* @var array
*/
protected $fontColors = [];
/**
* @var int
*/
protected $length = 5;
/**
* @var int
*/
protected $width = 120;
/**
* @var int
*/
protected $height = 36;
/**
* @var int
*/
protected $angle = 15;
/**
* @var int
*/
protected $lines = 3;
/**
* @var string
*/
protected $characters;
/**
* @var string
*/
protected $text;
/**
* @var int
*/
protected $contrast = 0;
/**
* @var int
*/
protected $quality = 90;
/**
* @var int
*/
protected $sharpen = 0;
/**
* @var int
*/
protected $blur = 0;
/**
* @var bool
*/
protected $bgImage = true;
/**
* @var string
*/
protected $bgColor = '#ffffff';
/**
* @var bool
*/
protected $invert = false;
/**
* @var bool
*/
protected $sensitive = false;
/**
* @var int
*/
protected $textLeftPadding = 4;
/**
* Constructor
*
* @param Filesystem $files
* @param Repository $config
* @param ImageManager $imageManager
* @param Hasher $hasher
* @param Str $str
* @throws Exception
* @internal param Validator $validator
*/
public function __construct(
Filesystem $files,
Repository $config,
ImageManager $imageManager,
Hasher $hasher,
Str $str
) {
$this->files = $files;
$this->config = $config;
$this->imageManager = $imageManager;
$this->hasher = $hasher;
$this->str = $str;
$this->characters = $this->config->get('captcha.characters', '2346789abcdefghjmnpqrtuxyzABCDEFGHJMNPQRTUXYZ');
}
/**
* @param string $config
* @return void
*/
protected function configure($config)
{
if ($this->config->has('captcha.' . $config)) {
foreach ($this->config->get('captcha.' . $config) as $key => $val) {
$this->{$key} = $val;
}
}
}
/**
* Create captcha image
*
* @param string $config
* @param boolean $api
* @return ImageManager->response
*/
public function create($config = 'default', $api = false)
{
$this->backgrounds = $this->files->files(__DIR__ . '/../Assets/backgrounds');
$this->fonts = $this->files->files(__DIR__ . '/../Assets/fonts');
$this->fonts = array_map(function ($file) {
return realpath($file->getPathName());
}, $this->fonts);
$this->fonts = array_values($this->fonts); //reset fonts array index
$this->configure($config);
$generator = $this->generate();
$this->text = $generator['value'];
$this->canvas = $this->imageManager->canvas(
$this->width,
$this->height,
$this->bgColor
);
if ($this->bgImage) {
$this->image = $this->imageManager->make($this->background())->resize(
$this->width,
$this->height
);
$this->canvas->insert($this->image);
} else {
$this->image = $this->canvas;
}
if ($this->contrast != 0) {
$this->image->contrast($this->contrast);
}
$this->text();
$this->lines();
if ($this->sharpen) {
$this->image->sharpen($this->sharpen);
}
if ($this->invert) {
$this->image->invert($this->invert);
}
if ($this->blur) {
$this->image->blur($this->blur);
}
return $api ? [
'sensitive' => $generator['sensitive'],
'key' => $generator['key'],
'img' => $this->image->encode('data-url')->encoded
] : $this->image->response('png', $this->quality);
}
/**
* Image backgrounds
*
* @return string
*/
protected function background()
{
return $this->backgrounds[rand(0, count($this->backgrounds) - 1)];
}
/**
* Generate captcha text
*
* @return string
*/
protected function generate()
{
$characters = str_split($this->characters);
$bag = '';
for ($i = 0; $i < $this->length; $i++) {
$bag .= $characters[rand(0, count($characters) - 1)];
}
$bag = $this->sensitive ? $bag : $this->str->lower($bag);
$hash = $this->hasher->make($bag);
return [
'value' => $bag,
'sensitive' => $this->sensitive,
'key' => $hash
];
}
/**
* Writing captcha text
*/
protected function text()
{
$marginTop = $this->image->height() / $this->length;
$i = 0;
foreach (str_split($this->text) as $char) {
$marginLeft = $this->textLeftPadding + ($i * ($this->image->width() - $this->textLeftPadding) / $this->length);
$this->image->text($char, $marginLeft, $marginTop, function ($font) {
$font->file($this->font());
$font->size($this->fontSize());
$font->color($this->fontColor());
$font->align('left');
$font->valign('top');
$font->angle($this->angle());
});
$i++;
}
}
/**
* Image fonts
*
* @return string
*/
protected function font()
{
return $this->fonts[rand(0, count($this->fonts) - 1)];
}
/**
* Random font size
*
* @return integer
*/
protected function fontSize()
{
return rand($this->image->height() - 10, $this->image->height());
}
/**
* Random font color
*
* @return array
*/
protected function fontColor()
{
if (! empty($this->fontColors)) {
$color = $this->fontColors[rand(0, count($this->fontColors) - 1)];
} else {
$color = [rand(0, 255), rand(0, 255), rand(0, 255)];
}
return $color;
}
/**
* Angle
*
* @return int
*/
protected function angle()
{
return rand((-1 * $this->angle), $this->angle);
}
/**
* Random image lines
*
* @return \Intervention\Image\Image
*/
protected function lines()
{
for ($i = 0; $i <= $this->lines; $i++) {
$this->image->line(
rand(0, $this->image->width()) + $i * rand(0, $this->image->height()),
rand(0, $this->image->height()),
rand(0, $this->image->width()),
rand(0, $this->image->height()),
function ($draw) {
$draw->color($this->fontColor());
}
);
}
return $this->image;
}
/**
* Captcha check
*
* @param $value
* @return bool
*/
public function check($value, $key)
{
return $this->hasher->check($value, $key);
}
/**
* Generate captcha image source
*
* @param null $config
* @return string
*/
public function src($config = null)
{
return url('captcha' . ($config ? '/' . $config : '/default')) . '?' . $this->str->random(8);
}
/**
* Generate captcha image html tag
*
* @param null $config
* @param array $attrs HTML attributes supplied to the image tag where key is the attribute
* and the value is the attribute value
* @return string
*/
public function img($config = null, $attrs = [])
{
$attrs_str = '';
foreach ($attrs as $attr => $value) {
if ($attr == 'src') {
//Neglect src attribute
continue;
}
$attrs_str .= $attr.'="'.$value.'" ';
}
return '<img src="' . $this->src($config) . '" '. trim($attrs_str).'>';
}
}