├── README.md
├── composer.json
├── example.png
├── examples
├── index.html
└── member.class.php
└── src
├── Captcha.php
└── images
├── 1.jpeg
├── 2.jpeg
├── 3.jpeg
├── 4.jpeg
└── 5.jpeg
/README.md:
--------------------------------------------------------------------------------
1 | # captcha
2 | ## PHP输出滑块旋转验证码
3 |
4 | ### 使用方式:
5 | `git clone https://github.com/ljj7410/captcha.git`
6 | #### 或
7 | `composer require ljj7410/captcha`
8 |
9 | ### 示例图片
10 |
11 | 
12 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ljj7410/captcha",
3 | "description": "PHP滑块旋转验证码",
4 | "keywords": ["captcha","滑块验证码"],
5 | "homepage": "https://github.com/ljj7410/captcha",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Dean.Lee",
10 | "email": "dean7410@163.com",
11 | "homepage": "",
12 | "role": "Developer"
13 | }
14 | ],
15 | "require": {
16 | "php": ">=7.2",
17 | "ext-gd": "*"
18 | },
19 | "autoload": {
20 | "psr-4": { "Util\\": "src/" }
21 | },
22 | "minimum-stability": "dev"
23 | }
24 |
--------------------------------------------------------------------------------
/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simoole/captcha/c9eae3700ade41a2bfef9a9126586fd7f3857038/example.png
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试
6 |
15 |
16 |
17 |
18 |
19 |
![]()
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
80 |
81 |
--------------------------------------------------------------------------------
/examples/member.class.php:
--------------------------------------------------------------------------------
1 | create();
16 |
17 | //记录验证码
18 | getRedis()->set('captcha_code', $cap->getCode());
19 |
20 | echo $bin;
21 | }
22 |
23 | public function verifyCode()
24 | {
25 | $code = $_POST['code'];
26 | $angle = getRedis()->get('captcha_code');
27 | //验证码比对,需要允许存在一些误差
28 | if(($code < $angle + 2) && ($code > $angle - 2)){
29 | echo '验证成功';
30 | }else{
31 | echo '验证失败';
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Captcha.php:
--------------------------------------------------------------------------------
1 | width = $option['width'];
16 | if(isset($option['height']))$this->height = $option['height'];
17 | if(isset($option['dir_path']))$this->dir_path = $option['dir_path'];
18 | }
19 |
20 | public function create(): string
21 | {
22 | //挑选一张原始图
23 | $files = scandir($this->dir_path);
24 | shuffle($files);
25 | foreach($files as $file){
26 | if(!strpos($file,'.'))continue;
27 | $arr = getimagesize($this->dir_path . $file);
28 | if(in_array($arr[2], [1,2,3]) && $arr[0] >= $this->width && $arr[1] >= $this->height){
29 | $this->orig_info = [
30 | 'width' => $arr[0],
31 | 'height' => $arr[1],
32 | 'type' => $arr[2],
33 | 'path' => $this->dir_path . $file
34 | ];
35 | break;
36 | }
37 | }
38 | if(empty($this->orig_info)){
39 | trigger_error('没有符合要求的图片库', E_USER_WARNING);
40 | return '';
41 | }
42 |
43 | //获取图片数据
44 | $im = null;
45 | switch ($this->orig_info['type']){
46 | case 1:
47 | $im = @imagecreatefromgif($this->orig_info['path']);
48 | break;
49 | case 2:
50 | $im = @imagecreatefromjpeg($this->orig_info['path']);
51 | break;
52 | case 3:
53 | $im = @imagecreatefrompng($this->orig_info['path']);
54 | break;
55 | }
56 | if(empty($im)){
57 | trigger_error('图片载入失败,请检查GD库版本', E_USER_WARNING);
58 | return '';
59 | }
60 |
61 | //随机裁切出一块
62 | $master_im = imagecrop($im, [
63 | 'x' => rand(0, $this->orig_info['width'] - $this->width),
64 | 'y' => rand(0, $this->orig_info['height'] - $this->height),
65 | 'width' => $this->width,
66 | 'height' => $this->height
67 | ]);
68 |
69 | //从裁切图片中再随机裁切一块方形出来
70 | //随机圆形半径
71 | $radius = rand(80,120);
72 | //随机圆形坐标
73 | $position = [
74 | rand(10 + $radius, $this->width - $radius - 10),
75 | rand(10 + $radius, $this->height - $radius - 10)
76 | ];
77 | //创建一张透明图片
78 | $sub_im = imagecreatetruecolor($radius * 2, $radius * 2);
79 | $mask_im = imagecreatetruecolor($radius * 2, $radius * 2);
80 | imagesavealpha($mask_im, true);
81 | $bg = imagecolorallocatealpha($mask_im, 255, 255, 255, 127);
82 | imagefill($mask_im, 0, 0, $bg);
83 | $black = imagecolorallocate($mask_im, 0, 0, 0);
84 |
85 | //在透明图片上绘制圆形图像
86 | for ($x = 0; $x < $radius * 2; $x++) {
87 | for ($y = 0; $y < $radius * 2; $y++) {
88 | $rgbColor = imagecolorat($master_im, $x + $position[0] - $radius, $y + $position[1] - $radius);
89 | if(pow($x - $radius,2) + pow($y - $radius, 2) < pow($radius, 2)){
90 | imagesetpixel($sub_im, $x, $y, $rgbColor);
91 | imagesetpixel($mask_im, $x, $y, $black);
92 | }
93 | }
94 | }
95 | //将黑色遮罩覆盖在原图上
96 | imagecopy($master_im, $mask_im, $position[0] - $radius, $position[1] - $radius, 0, 0, $radius * 2, $radius * 2);
97 |
98 | //将圆形图旋转任意角度
99 | $this->angle = rand(0, 36000) / 100;
100 | $sub_im = imagerotate($sub_im, $this->angle, 0);
101 | $x = imagesx($sub_im) / 2 - $radius;
102 | $sub_im = imagecrop($sub_im, [
103 | 'x' => $x,
104 | 'y' => $x,
105 | 'width' => $radius * 2,
106 | 'height' => $radius * 2
107 | ]);
108 |
109 | ob_start();
110 | //写入时间戳
111 | echo pack('I', time());
112 | //写入X坐标
113 | echo pack('v', $position[0]);
114 | //写入Y坐标
115 | echo pack('v', $position[1]);
116 | //写入主图
117 | imagejpeg($master_im);
118 | $size1 = ob_get_length() - 8;
119 | //写入分图
120 | imagejpeg($sub_im);
121 | $size2 = ob_get_length() - $size1 - 8;
122 | //写入主图大小
123 | echo pack('I', $size1);
124 | //写入分图大小
125 | echo pack('I', $size2);
126 | //输出缓冲区
127 | return ob_get_clean();
128 | }
129 |
130 | /**
131 | * 获取角度验证码
132 | * @return float
133 | */
134 | public function getCode() : float
135 | {
136 | return $this->angle;
137 | }
138 |
139 | /**
140 | * 验证code是否正确
141 | * @param int $code
142 | * @return bool
143 | */
144 | public function verify(int $code) : bool
145 | {
146 | return ($code < $this->angle + 2) && ($code > $this->angle - 2);
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/images/1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simoole/captcha/c9eae3700ade41a2bfef9a9126586fd7f3857038/src/images/1.jpeg
--------------------------------------------------------------------------------
/src/images/2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simoole/captcha/c9eae3700ade41a2bfef9a9126586fd7f3857038/src/images/2.jpeg
--------------------------------------------------------------------------------
/src/images/3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simoole/captcha/c9eae3700ade41a2bfef9a9126586fd7f3857038/src/images/3.jpeg
--------------------------------------------------------------------------------
/src/images/4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simoole/captcha/c9eae3700ade41a2bfef9a9126586fd7f3857038/src/images/4.jpeg
--------------------------------------------------------------------------------
/src/images/5.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simoole/captcha/c9eae3700ade41a2bfef9a9126586fd7f3857038/src/images/5.jpeg
--------------------------------------------------------------------------------