Issues (8)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Captcha.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Vicens\Captcha;
4
5
use Illuminate\Support\Facades\Session;
6
7
class Captcha
8
{
9
    /**
10
     * 存储在session中的key
11
     */
12
    const SESSION_NAME = '_captcha';
13
14
    /**
15
     * 验证码配置
16
     * @var array
17
     */
18
    protected $config = [
19
        /**
20
         * 调试模型
21
         */
22
        'debug' => false,
23
        /**
24
         * 默认验证码长度
25
         * @var int
26
         */
27
        'length' => 4,
28
        /**
29
         * 验证码字符集
30
         * @var string
31
         */
32
        'charset' => 'abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ123456789',
33
        /**
34
         * 是否开启严格模式(区分大小写)
35
         * @var bool
36
         */
37
        'strict' => false,
38
        /**
39
         * 默认验证码宽度
40
         * @var int
41
         */
42
        'width' => 150,
43
        /**
44
         * 默认验证码高度
45
         * @var int
46
         */
47
        'height' => 40,
48
        /**
49
         * 指定文字颜色
50
         * @var string
51
         */
52
        'textColor' => null,
53
        /**
54
         * 文字字体文件
55
         * @var string
56
         */
57
        'textFont' => null,
58
        /**
59
         * 指定图片背景色
60
         * @var string
61
         */
62
        'backgroundColor' => null,
63
        /**
64
         * 开启失真模式
65
         * @var bool
66
         */
67
        'distortion' => true,
68
        /**
69
         * 最大前景线条数
70
         * @var int
71
         */
72
        'maxFrontLines' => null,
73
        /**
74
         * 最大背景线条数
75
         * @val int
76
         */
77
        'maxBehindLines' => null,
78
        /**
79
         * 文字最大角度
80
         * @var int
81
         */
82
        'maxAngle' => 8,
83
        /**
84
         * 文字最大偏移量
85
         * @var int
86
         */
87
        'maxOffset' => 5
88
    ];
89
90
    /**
91
     * Captcha constructor.
92
     * @param array $config
93
     */
94
    public function __construct(array $config = [])
95
    {
96
        $this->setConfig($config);
97
    }
98
99
    /**
100
     * 设置验证码配置
101
     *
102
     * @param array|string $config 配置数组或配置项key
103
     * @param mixed $value 配置项值
104
     * @return $this
105
     */
106
    public function setConfig($config, $value = null)
107
    {
108
109
        if (!is_array($config)) {
110
            $config = [$config => $value];
0 ignored issues
show
Consider using a different name than the parameter $config. This often makes code more readable.
Loading history...
111
        }
112
113
        foreach ($config as $key => $value) {
114
            if (array_key_exists($key, $this->config)) {
115
                $this->config[$key] = $value;
116
            }
117
        }
118
119
        return $this;
120
    }
121
122
    /**
123
     * 获取配置
124
     *
125
     * @param string|null $key 配置项key
126
     * @return string|number|array
127
     */
128
    public function getConfig($key = null)
129
    {
130
        if ($key !== null) {
131
            return $this->config[$key];
132
        }
133
134
        return $this->config;
135
    }
136
137
    /**
138
     * 生成验证码
139
     *
140
     * @return Image
141
     */
142
    public function make()
143
    {
144
        $code = $this->generate();
145
146
        $hash = password_hash($code, PASSWORD_BCRYPT, array('cost' => 10));
147
148
        if ($hash === false) {
149
            throw new \RuntimeException('Bcrypt hashing not supported.');
150
        }
151
152
        Session::put(self::SESSION_NAME, $hash);
153
154
        return new Image($this->build($code));
155
    }
156
157
    /**
158
     * 仅测试正确性, 不删除验证码
159
     *
160
     * @param string $input
161
     * @return bool
162
     */
163
    public function test($input)
0 ignored issues
show
function test() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
164
    {
165
        if ($this->config['debug']) {
166
            return true;
167
        } elseif (!(Session::has(self::SESSION_NAME) && $input)) {
168
            return false;
169
        }
170
171
        $code = Session::get(self::SESSION_NAME);
172
173
        if ($this->config['strict']) {
174
            // 开启严格模式
175
            password_verify($input, $code);
176
        }
177
178
        //返回验证结果
179
        return password_verify(strtoupper($input), $code);
180
    }
181
182
    /**
183
     * 检测正确性,并删除验证码
184
     *
185
     * @param string $input
186
     * @return bool
187
     */
188
    public function check($input)
0 ignored issues
show
function check() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
189
    {
190
        $result = $this->test($input);
191
        Session::forget(self::SESSION_NAME);
192
193
        return $result;
194
    }
195
196
    /**
197
     * 生成验证码
198
     *
199
     * @return string
200
     */
201
    protected function generate()
202
    {
203
        $characters = str_split($this->getConfig('charset'));
204
        $length = $this->getConfig('length');
205
206
        $code = '';
207
        for ($i = 0; $i < $length; $i++) {
208
            $code .= $characters[rand(0, count($characters) - 1)];
209
        }
210
211
        if ($this->config['strict']) {
212
            return $code;
213
        }
214
215
        return strtoupper($code);
216
    }
217
218
    /**
219
     * 创建验证码图片
220
     *
221
     * @param string $code
222
     * @return resource
223
     */
224
    protected function build($code)
225
    {
226
227
        // 图片宽
228
        $width = $this->getConfig('width');
229
        // 图片高
230
        $height = $this->getConfig('height');
231
        // 背景颜色
232
        $backgroundColor = $this->getConfig('backgroundColor');
233
234
        // 随机取一个字体
235
        $font = $this->getTextFont();
236
237
        // 根据宽高创建一个背景画布
238
        $image = imagecreatetruecolor($width, $height);
239
240
        if ($backgroundColor === null) {
241
            $backgroundColor = imagecolorallocate($image, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255));
242
        } else {
243
            $color = $backgroundColor;
244
            $backgroundColor = imagecolorallocate($image, $color[0], $color[1], $color[2]);
245
        }
246
        // 填充背景色
247
        imagefill($image, 0, 0, $backgroundColor);
248
249
        // 绘制背景干扰线
250
        $this->drawLines($image, $this->getConfig('maxBehindLines'));
251
252
        // 写入验证码文字
253
        $color = $this->renderText($image, $code, $font);
254
255
        // 绘制前景干扰线
256
        $this->drawLines($image, $this->getConfig('maxFrontLines'), $color);
257
258
        if ($this->getConfig('distortion')) {
259
            // 创建失真
260
            $image = $this->createDistortion($image, $width, $height, $backgroundColor);
261
        }
262
263
        //如果不指定字体颜色和背景颜色,则使用图像过滤器修饰
264
        if (function_exists('imagefilter') && is_null($backgroundColor) && is_null($this->getConfig('textColor'))) {
265
            // 颜色翻转 - 1/2几率
266
            if (mt_rand(0, 1) == 0) {
267
                imagefilter($image, IMG_FILTER_NEGATE);
268
            }
269
            // 用边缘检测来突出图像的边缘 - 1/11几率
270
            if (mt_rand(0, 10) == 0) {
271
                imagefilter($image, IMG_FILTER_EDGEDETECT);
272
            }
273
            // 改变图像的对比度
274
            imagefilter($image, IMG_FILTER_CONTRAST, mt_rand(-50, 10));
275
276
            if (mt_rand(0, 5) == 0) {
277
                // 用高斯算法和指定颜色模糊图像
278
                imagefilter($image, IMG_FILTER_COLORIZE, mt_rand(-80, 50), mt_rand(-80, 50), mt_rand(-80, 50));
279
            }
280
        }
281
        return $image;
282
    }
283
284
    /**
285
     * 创建失真
286
     *
287
     * @param resource $image
288
     * @param int $width
289
     * @param int $height
290
     * @param int $backgroundColor
291
     * @return resource
292
     */
293
    protected function createDistortion($image, $width, $height, $backgroundColor)
294
    {
295
        //创建失真
296
        $contents = imagecreatetruecolor($width, $height);
297
        $rWidth = mt_rand(0, $width);
298
        $rHeight = mt_rand(0, $height);
299
        $phase = mt_rand(0, 10);
300
        $scale = 1.1 + mt_rand(0, 10000) / 30000;
301
302
        for ($x = 0; $x < $width; $x++) {
303
            for ($y = 0; $y < $height; $y++) {
304
                $vX = $x - $rWidth;
305
                $vY = $y - $rHeight;
306
                $vN = sqrt($vX * $vX + $vY * $vY);
307
308
                if ($vN != 0) {
309
                    $vN2 = $vN + 4 * sin($vN / 30);
310
                    $nX = $rWidth + ($vX * $vN2 / $vN);
311
                    $nY = $rHeight + ($vY * $vN2 / $vN);
312
                } else {
313
                    $nX = $rWidth;
314
                    $nY = $rHeight;
315
                }
316
                $nY = $nY + $scale * sin($phase + $nX * 0.2);
317
318
                $pixel = $this->getColor($image, round($nX), round($nY), $backgroundColor);
319
320
                if ($pixel == 0) {
321
                    $pixel = $backgroundColor;
322
                }
323
324
                imagesetpixel($contents, $x, $y, $pixel);
325
            }
326
        }
327
328
        return $contents;
329
    }
330
331
    /**
332
     * 获取一个字体
333
     *
334
     * @return string
0 ignored issues
show
Should the return type not be string|integer|double|array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
335
     */
336
    protected function getTextFont()
337
    {
338
        // 指定字体
339
        if ($this->getConfig('textFont') && file_exists($this->getConfig('textFont'))) {
340
            return $this->getConfig('textFont');
341
        }
342
        // 随机字体
343
        return __DIR__ . '/../fonts/' . mt_rand(0, 5) . '.ttf';
344
    }
345
346
    /**
347
     * 写入验证码到图片中
348
     *
349
     * @param resource $image
350
     * @param string $phrase
351
     * @param string $font
352
     * @return int
353
     */
354
    protected function renderText($image, $phrase, $font)
355
    {
356
        $length = strlen($phrase);
357
        if ($length === 0) {
358
            return imagecolorallocate($image, 0, 0, 0);
359
        }
360
361
        // 计算文字尺寸
362
        $size = $this->getConfig('width') / $length - mt_rand(0, 3) - 1;
363
        $box = imagettfbbox($size, 0, $font, $phrase);
364
        $textWidth = $box[2] - $box[0];
365
        $textHeight = $box[1] - $box[7];
366
        $x = ($this->getConfig('width') - $textWidth) / 2;
367
        $y = ($this->getConfig('height') - $textHeight) / 2 + $size;
368
369
        if (!$this->getConfig('textColor')) {
370
            $textColor = array(mt_rand(0, 150), mt_rand(0, 150), mt_rand(0, 150));
371
        } else {
372
            $textColor = $this->getConfig('textColor');
373
        }
374
        $color = imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]);
375
376
        // 循环写入字符,随机角度
377
        for ($i = 0; $i < $length; $i++) {
378
            $box = imagettfbbox($size, 0, $font, $phrase[$i]);
379
            $w = $box[2] - $box[0];
380
            $angle = mt_rand(-$this->getConfig('maxAngle'), $this->getConfig('maxAngle'));
381
            $offset = mt_rand(-$this->getConfig('maxOffset'), $this->getConfig('maxOffset'));
382
            imagettftext($image, $size, $angle, $x, $y + $offset, $color, $font, $phrase[$i]);
383
            $x += $w;
384
        }
385
386
        return $color;
387
    }
388
389
    /**
390
     * 画线
391
     *
392
     * @param resource $image
393
     * @param int $width
394
     * @param int $height
395
     * @param int|null $color
396
     */
397
    protected function renderLine($image, $width, $height, $color = null)
398
    {
399
        $color = $color ?: imagecolorallocate($image, mt_rand(100, 255), mt_rand(100, 255), mt_rand(100, 255));
0 ignored issues
show
Consider using a different name than the parameter $color. This often makes code more readable.
Loading history...
400
401
        if (mt_rand(0, 1)) {
402
            // 横向
403
            $xA = mt_rand(0, $width / 2);
404
            $yA = mt_rand(0, $height);
405
            $xB = mt_rand($width / 2, $width);
406
            $yB = mt_rand(0, $height);
407
        } else {
408
            // 纵向
409
            $xA = mt_rand(0, $width);
410
            $yA = mt_rand(0, $height / 2);
411
            $xB = mt_rand(0, $width);
412
            $yB = mt_rand($height / 2, $height);
413
        }
414
        imagesetthickness($image, mt_rand(1, 3));
415
        imageline($image, $xA, $yA, $xB, $yB, $color);
416
    }
417
418
    /**
419
     * 画线
420
     *
421
     * @param resource $image
422
     * @param int $max
423
     * @param int|null $color
424
     */
425
    protected function drawLines($image, $max, $color = null)
426
    {
427
        $square = $this->getConfig('width') * $this->getConfig('height');
428
        $effects = mt_rand($square / 3000, $square / 2000);
429
430
        // 计算线条数
431
        if ($max != null && $max > 0) {
432
            $effects = min($max, $effects);
433
        }
434
435
        if ($max !== 0) {
436
            for ($e = 0; $e < $effects; $e++) {
437
438
                if ($color !== null) {
439
                    $this->renderLine($image, $this->getConfig('width'), $this->getConfig('height'), $color);
440
                } else {
441
                    $this->renderLine($image, $this->getConfig('width'), $this->getConfig('height'));
442
                }
443
444
            }
445
        }
446
    }
447
448
    /**
449
     * 获取颜色
450
     *
451
     * @param resource $image
452
     * @param int $width
453
     * @param int $height
454
     * @param int $background
455
     * @return int
456
     */
457
    protected function getColor($image, $width, $height, $background)
458
    {
459
        $sWidth = imagesx($image);
460
        $sHeight = imagesy($image);
461
        if ($width < 0 || $width >= $sWidth || $height < 0 || $height >= $sHeight) {
462
            return $background;
463
        }
464
465
        return imagecolorat($image, $width, $height);
466
    }
467
468
    /**
469
     * @param string $name
470
     * @param array $arguments
471
     * @return $this
472
     */
473
    public function __call($name, $arguments)
474
    {
475
        if (array_key_exists($name, $this->config)) {
476
            $this->config[$name] = $arguments[0];
477
        }
478
479
        return $this;
480
    }
481
}
482