Passed
Push — 5.x ( 65a76f...3a1e20 )
by Enjoys
59s queued 13s
created

Defaults   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Test Coverage

Coverage 97.26%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 14
eloc 75
c 2
b 0
f 1
dl 0
loc 162
ccs 71
cts 73
cp 0.9726
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A createImage() 0 53 5
A getBase64Image() 0 5 1
A getCode() 0 3 1
A validate() 0 16 2
A __construct() 0 9 2
A generateCode() 0 19 2
A renderHtml() 0 30 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Enjoys\Forms\Captcha\Defaults;
6
7
use Enjoys\Forms\AttributeFactory;
8
use Enjoys\Forms\Captcha\CaptchaBase;
9
use Enjoys\Forms\Captcha\CaptchaInterface;
10
use Enjoys\Forms\Element;
11
use Enjoys\Forms\Interfaces\Ruleable;
12
use Enjoys\Session\Session as Session;
13
use Webmozart\Assert\Assert;
14
15
class Defaults extends CaptchaBase implements CaptchaInterface
16
{
17
    private string $code = '';
18
    private Session $session;
19
20 15
    public function __construct(?string $message = null)
21
    {
22 15
        $this->session = new Session();
23
24 15
        $this->setName('captcha_defaults');
25 15
        if (is_null($message)) {
26 14
            $message = 'Не верно введен код';
27
        }
28 15
        $this->setRuleMessage($message);
29
    }
30
31
    /**
32
     * @psalm-suppress PossiblyNullReference
33
     * @param Ruleable&Element $element
34
     * @return bool
35
     */
36 2
    public function validate(Ruleable $element): bool
37
    {
38 2
        $method = $this->getRequest()->getRequest()->getMethod();
39 2
        $requestData = match (strtolower($method)) {
40 2
            'get' => $this->getRequest()->getQueryData()->toArray(),
41
            'post' => $this->getRequest()->getPostData()->toArray(),
42
            default => []
43
        };
44
45 2
        $value = \getValueByIndexPath($element->getName(), $requestData);
0 ignored issues
show
Bug introduced by
The method getName() does not exist on Enjoys\Forms\Interfaces\Ruleable. Since it exists in all sub-types, consider adding an abstract or default implementation to Enjoys\Forms\Interfaces\Ruleable. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

45
        $value = \getValueByIndexPath($element->/** @scrutinizer ignore-call */ getName(), $requestData);
Loading history...
46
47 2
        if ($this->session->get($element->getName()) !== $value) {
48 2
            $element->setRuleError($this->getRuleMessage());
49 2
            return false;
50
        }
51 1
        return true;
52
    }
53
54 5
    public function renderHtml(Element $element): string
55
    {
56 5
        $element->setAttrs(
57 5
            AttributeFactory::createFromArray([
58
                'type' => 'text',
59
                'autocomplete' => 'off'
60
            ])
61
        );
62
63 5
        $this->generateCode($element);
64
65 5
        $w = $this->getOption('width', 150);
66 5
        Assert::integer($w, 'Width parameter must be integer');
67
68 4
        $h = $this->getOption('height', 50);
69 4
        Assert::integer($h, 'Height parameter must be integer');
70
71 3
        $img = $this->createImage($this->getCode(), $w, $h);
72
73
        //dump($this->session->get($this->getName()));
74
        //  $html = '';
75
76
//        if ($this->element->isRuleError()) {
77
//            $html .= "<p style=\"color: red\">{$this->element->getRuleErrorMessage()}</p>";
78
//        }
79
80 3
        return sprintf(
81
            '<img alt="captcha image" src="data:image/jpeg;base64,%s" /><br /><input%s>',
82 3
            $this->getBase64Image($img),
83 3
            $element->getAttributesString()
84
        );
85
    }
86
87 8
    private function generateCode(Element $element): void
88
    {
89 8
        $max = $this->getOption('size', 6);
90
91 8
        Assert::notEq(0, $max);
92 7
        Assert::integer($max);
93
94 6
        $chars = $this->getOption('chars', 'qwertyuiopasdfghjklzxcvbnm1234567890');
95 6
        $size = strlen($chars) - 1;
96
        // Определяем пустую переменную, в которую и будем записывать символы.
97 6
        $code = '';
98
        // Создаём пароль.
99 6
        while ($max--) {
100 6
            $code .= $chars[rand(0, $size)];
101
        }
102 6
        $this->code = $code;
103 6
        $this->session->set(
104
            [
105 6
                $element->getName() => $this->code
106
            ]
107
        );
108
    }
109
110 4
    public function getCode(): string
111
    {
112 4
        return $this->code;
113
    }
114
115
116 5
    private function createImage(string $code, int $width = 150, int $height = 50): \GdImage
117
    {
118
        // Создаем пустое изображение
119 5
        $img = \imagecreatetruecolor($width, $height);
120
121 5
        $background_color = [\mt_rand(200, 255), \mt_rand(200, 255), \mt_rand(200, 255)];
122
        // Заливаем фон белым цветом
123 5
        $background = \imagecolorallocate($img, $background_color[0], $background_color[1], $background_color[2]);
124 5
        \imagefill($img, 0, 0, $background);
125
126
127
        // Накладываем защитный код
128 5
        $x = 0;
129 5
        $letters = \str_split($code);
130 5
        $figures = [50, 70, 90, 110, 130, 150, 170, 190, 210];
131
132 5
        foreach ($letters as $letter) {
133
            //Ориентир
134 5
            $h = 1;
135
            //Рисуем
136 5
            $color = \imagecolorallocatealpha(
137
                $img,
138 5
                $figures[\rand(0, \count($figures) - 1)],
139 5
                $figures[\rand(0, \count($figures) - 1)],
140 5
                $figures[\rand(0, \count($figures) - 1)],
141 5
                rand(10, 30)
142
            );
143
144
145
            // Формируем координаты для вывода символа
146 5
            if (empty($x)) {
147 5
                $x = (int)($width * 0.08);
148
            } else {
149 5
                $x = (int)($x + ($width * 0.8) / \count($letters) + \rand(0, (int)($width * 0.01)));
150
            }
151
152 5
            if ($h == rand(1, 2)) {
153 5
                $y = (int)((($height * 1) / 4) + \rand(0, (int)($height * 0.1)));
154
            } else {
155 5
                $y = (int)((($height * 1) / 4) - \rand(0, (int)($height * 0.1)));
156
            }
157
158
159
            // Изменяем регистр символа
160 5
            if (rand(0, 1)) {
161 5
                $letter = \strtoupper($letter);
162
            }
163
            // Выводим символ на изображение
164 5
            \imagestring($img, 4, $x, $y, $letter, $color);
165 5
            $x++;
166
        }
167
168 5
        return $img;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $img could return the type resource which is incompatible with the type-hinted return GdImage. Consider adding an additional type-check to rule them out.
Loading history...
169
    }
170
171
172 4
    private function getBase64Image(\GdImage $img): string
173
    {
174 4
        ob_start();
175 4
        imagejpeg($img);
176 4
        return base64_encode(ob_get_clean());
177
    }
178
}
179