controller/captcha.php
<?php
$digit = 4; //验证码位数
$digit_width = 55;// 单位验证码宽度
$height = 100;// 验证码高度
$letter_list = str_split("123456789"); // 预设字符,0容易跟O混淆,就不要了,字母和符号也是支持的,汉字支持需要更换字体包。
//$letter_list = str_split("abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
$width = $digit_width * $digit;
$code_list = array(); // 验证码字符数组
$block_list = array(); // 背景色块数组
for ($i = 0; $i < $digit; $i++) {
$code_list[$i] = $letter_list[mt_rand(0, count($letter_list) - 1)];
$block_list[$i * 2] = $i * 2;
$block_list[$i * 2 + 1] = $i * 2 + 1;
}
$verification_code = implode('', $code_list); // 最终的验证码
// for debug only
//header("X-Verification-Code: " . $verification_code);
session_start();
$_SESSION[PREFIX . 'VerificationCode'] = $verification_code;
session_write_close();
$background = imagecreatetruecolor($width, $height);
//全透明背景
imagesavealpha($background, true);
$background_alpha = imagecolorallocatealpha($background, 255, 255, 255, 127);
imagefill($background, 0, 0, $background_alpha);
//抗锯齿
if (function_exists('imageantialias')) {
imageantialias($background, true);
}
$material_design_color = array(
array(
255,
235,
238
),
array(
255,
205,
210
),
array(
239,
154,
154
),
array(
229,
115,
115
),
array(
239,
83,
80
),
array(
244,
67,
54
),
array(
229,
57,
53
),
array(
211,
47,
47
),
array(
198,
40,
40
),
array(
183,
28,
28
),
array(
255,
138,
128
),
array(
255,
82,
82
),
array(
255,
23,
68
),
array(
213,
0,
0
),
array(
252,
228,
236
),
array(
248,
187,
208
),
array(
244,
143,
177
),
array(
240,
98,
146
),
array(
236,
64,
122
),
array(
233,
30,
99
),
array(
216,
27,
96
),
array(
194,
24,
91
),
array(
173,
20,
87
),
array(
136,
14,
79
),
array(
255,
128,
171
),
array(
255,
64,
129
),
array(
245,
0,
87
),
array(
197,
17,
98
),
array(
243,
229,
245
),
array(
225,
190,
231
),
array(
206,
147,
216
),
array(
186,
104,
200
),
array(
171,
71,
188
),
array(
156,
39,
176
),
array(
142,
36,
170
),
array(
123,
31,
162
),
array(
106,
27,
154
),
array(
74,
20,
140
),
array(
234,
128,
252
),
array(
224,
64,
251
),
array(
213,
0,
249
),
array(
170,
0,
255
),
array(
237,
231,
246
),
array(
209,
196,
233
),
array(
179,
157,
219
),
array(
149,
117,
205
),
array(
126,
87,
194
),
array(
103,
58,
183
),
array(
94,
53,
177
),
array(
81,
45,
168
),
array(
69,
39,
160
),
array(
49,
27,
146
),
array(
179,
136,
255
),
array(
124,
77,
255
),
array(
101,
31,
255
),
array(
98,
0,
234
),
array(
232,
234,
246
),
array(
197,
202,
233
),
array(
159,
168,
218
),
array(
121,
134,
203
),
array(
92,
107,
192
),
array(
63,
81,
181
),
array(
57,
73,
171
),
array(
48,
63,
159
),
array(
40,
53,
147
),
array(
26,
35,
126
),
array(
140,
158,
255
),
array(
83,
109,
254
),
array(
61,
90,
254
),
array(
48,
79,
254
),
array(
227,
242,
253
),
array(
187,
222,
251
),
array(
144,
202,
249
),
array(
100,
181,
246
),
array(
66,
165,
245
),
array(
33,
150,
243
),
array(
30,
136,
229
),
array(
25,
118,
210
),
array(
21,
101,
192
),
array(
13,
71,
161
),
array(
130,
177,
255
),
array(
68,
138,
255
),
array(
41,
121,
255
),
array(
41,
98,
255
),
array(
225,
245,
254
),
array(
179,
229,
252
),
array(
129,
212,
250
),
array(
79,
195,
247
),
array(
41,
182,
252
),
array(
3,
169,
244
),
array(
3,
155,
229
),
array(
2,
136,
209
),
array(
2,
119,
189
),
array(
1,
87,
155
),
array(
128,
216,
255
),
array(
64,
196,
255
),
array(
0,
176,
255
),
array(
0,
145,
234
),
array(
224,
247,
250
),
array(
178,
235,
242
),
array(
128,
222,
234
),
array(
77,
208,
225
),
array(
38,
198,
218
),
array(
0,
188,
212
),
array(
0,
172,
193
),
array(
0,
151,
167
),
array(
0,
131,
143
),
array(
0,
96,
100
),
array(
132,
255,
255
),
array(
24,
255,
255
),
array(
0,
229,
255
),
array(
0,
184,
212
),
array(
224,
242,
241
),
array(
178,
223,
219
),
array(
128,
203,
196
),
array(
77,
182,
172
),
array(
38,
166,
154
),
array(
0,
150,
136
),
array(
0,
137,
123
),
array(
0,
121,
107
),
array(
0,
105,
92
),
array(
0,
77,
64
),
array(
167,
255,
235
),
array(
100,
255,
218
),
array(
29,
233,
182
),
array(
0,
191,
165
),
array(
232,
245,
233
),
array(
200,
230,
201
),
array(
165,
214,
167
),
array(
129,
199,
132
),
array(
102,
187,
106
),
array(
76,
175,
80
),
array(
67,
160,
71
),
array(
56,
142,
60
),
array(
46,
125,
50
),
array(
27,
94,
32
),
array(
185,
246,
202
),
array(
105,
240,
174
),
array(
0,
230,
118
),
array(
0,
200,
83
),
array(
241,
248,
233
),
array(
220,
237,
200
),
array(
197,
225,
165
),
array(
174,
213,
129
),
array(
156,
204,
101
),
array(
139,
195,
74
),
array(
124,
179,
66
),
array(
104,
159,
56
),
array(
85,
139,
47
),
array(
51,
105,
30
),
array(
204,
255,
144
),
array(
178,
255,
89
),
array(
118,
255,
3
),
array(
100,
221,
23
),
array(
249,
251,
231
),
array(
240,
244,
195
),
array(
230,
238,
156
),
array(
220,
231,
117
),
array(
212,
225,
87
),
array(
205,
220,
57
),
array(
192,
202,
51
),
array(
164,
180,
43
),
array(
158,
157,
36
),
array(
130,
119,
23
),
array(
244,
255,
129
),
array(
238,
255,
65
),
array(
198,
255,
0
),
array(
174,
234,
0
),
array(
255,
253,
231
),
array(
255,
249,
196
),
array(
255,
245,
144
),
array(
255,
241,
118
),
array(
255,
238,
88
),
array(
255,
235,
59
),
array(
253,
216,
53
),
array(
251,
192,
45
),
array(
249,
168,
37
),
array(
245,
127,
23
),
array(
255,
255,
130
),
array(
255,
255,
0
),
array(
255,
234,
0
),
array(
255,
214,
0
),
array(
255,
248,
225
),
array(
255,
236,
179
),
array(
255,
224,
130
),
array(
255,
213,
79
),
array(
255,
202,
40
),
array(
255,
193,
7
),
array(
255,
179,
0
),
array(
255,
160,
0
),
array(
255,
143,
0
),
array(
255,
111,
0
),
array(
255,
229,
127
),
array(
255,
215,
64
),
array(
255,
196,
0
),
array(
255,
171,
0
),
array(
255,
243,
224
),
array(
255,
224,
178
),
array(
255,
204,
128
),
array(
255,
183,
77
),
array(
255,
167,
38
),
array(
255,
152,
0
),
array(
251,
140,
0
),
array(
245,
124,
0
),
array(
239,
108,
0
),
array(
230,
81,
0
),
array(
255,
209,
128
),
array(
255,
171,
64
),
array(
255,
145,
0
),
array(
255,
109,
0
),
array(
251,
233,
167
),
array(
255,
204,
188
),
array(
255,
171,
145
),
array(
255,
138,
101
),
array(
255,
112,
67
),
array(
255,
87,
34
),
array(
244,
81,
30
),
array(
230,
74,
25
),
array(
216,
67,
21
),
array(
191,
54,
12
),
array(
255,
158,
128
),
array(
255,
110,
64
),
array(
255,
61,
0
),
array(
221,
38,
0
),
array(
239,
235,
233
),
array(
215,
204,
200
),
array(
188,
170,
164
),
array(
161,
136,
127
),
array(
141,
110,
99
),
array(
121,
85,
72
),
array(
109,
76,
65
),
array(
93,
64,
55
),
array(
78,
52,
46
),
array(
62,
39,
35
),
array(
250,
250,
250
),
array(
245,
245,
245
),
array(
238,
238,
238
),
array(
224,
224,
224
),
array(
189,
189,
189
),
array(
158,
158,
158
),
array(
117,
117,
117
),
array(
97,
97,
97
),
array(
66,
66,
66
),
array(
33,
33,
33
),
array(
0,
0,
0
),
array(
255,
255,
255
),
array(
236,
239,
241
),
array(
207,
216,
220
),
array(
176,
187,
197
),
array(
144,
164,
174
),
array(
120,
144,
156
),
array(
96,
125,
139
),
array(
84,
110,
122
),
array(
69,
90,
100
),
array(
55,
71,
79
),
array(
38,
50,
56
)
);
// 填充背景方块,防止基于灰度的简易二值化算法
$background_color = array();
foreach ($block_list as $offset => $code) {
$material_design_color_index = count($material_design_color) - 1;
$background_color_index = mt_rand(0, $material_design_color_index);
$background_color[$offset] = imagecolorallocate($background, $material_design_color[$background_color_index][0], $material_design_color[$background_color_index][1], $material_design_color[$background_color_index][2]);
//画一个背景色块
imagefilledrectangle($background, $digit_width * $offset / 2, 0, $digit_width * ($offset / 2 + 0.5), $height, $background_color[$offset]);
//var_dump($font_color);
}
// 填充验证码,加入随机的字体大小和旋转和位移,以实现大概率字符重叠,防止被轻易切割
foreach ($code_list as $offset => $code) {
$font_height = $height * mt_rand(7, 11) / 10;
$font_color_index = mt_rand(0, $material_design_color_index);
$font_color = imagecolorallocate($background, $material_design_color[$font_color_index][0], $material_design_color[$font_color_index][1], $material_design_color[$font_color_index][2]);
imagettftext($background, $font_height, // 字体大小
mt_rand(-25, 25), // 扭曲角度
$digit_width * $offset + mt_rand(0, $digit_width * 0.5), //x轴位置
mt_rand($font_height * 0.9, $font_height * 1.1), //y轴位置
$font_color, //颜色
LibraryPath . 'fonts/SourceCodePro-Black.ttf', //字体
$code //字符
);
}
// 填充噪点和线
$noise_number = 0.3 * $digit_width * $height / 2; //噪点比例
$line_number = min(0.1 * $height, 3); //线段比例,最多出现三条
$line_width = 0.03 * $height; //线段宽度
foreach ($background_color as $offset => $color) {
//imageellipse($background ,mt_rand($offset * $digit_width, ($offset+1) * $digit_width) , mt_rand(0, $height), mt_rand(0, $height*0.3), $color);
for ($i = 0; $i < $line_number; $i++) {
$line_x1 = $offset / 2 * $digit_width;
$line_y1 = mt_rand(0, $height);
$line_x2 = ($offset / 2 + 0.5) * $digit_width;
$line_y2 = mt_rand(0, $height);
for ($j = 0; $j < $line_width; $j++) {
imageline($background, $line_x1 + $j, $line_y1, $line_x2 + $j, $line_y2, $color);
}
}
for ($i = 0; $i < $noise_number; $i++) {
imagesetpixel($background, mt_rand($offset / 2 * $digit_width, ($offset / 2 + 0.5) * $digit_width), mt_rand(0, $height), $color);
}
}
header('Content-Type: image/png');
imagepng($background);
imagedestroy($background);