这个验证码最早是给树洞外链开发的,目的只是为了娱乐,并没有想到真的防机器人。后来被我迁移到了Cloudreve的演示站上,经过Twitter某大佬转发后就小小的火了一把,每天都有不少人为了体验这个验证码而注册,也有很多人在问如何将其整合到自己的Cloudreve上,今天就写了篇文章介绍下,顺便补下已经失效的验证码数据库文件。

关于此验证码的更多信息,可参考之前的文章:

效果展示

演示地址:https://pan.aoaoao.me/Login 点击“创建账号”

最基本的形式:输入上图物质分子式,看着复杂,其实挺简单的,数数各个原子个数,按照顺序堆起来就行了。此外还有计算矩阵、说出事件发生日期的验证码,三者随机出现。

化学式.png
化学式.png

部署方法

1.前期准备

安装需要的扩展库:

1
composer require zgldh/gd-text-for-chinese

然后从 https://drive.google.com/file/d/1jE5tM9PLnFszgp3Hv_vQzctSgmL8UUtA/view?usp=sharing (需爱国上网)下载数据库文件并导入到Cloudreve所在的数据库

2.修改代码

application/index/view/member/login.html 大概105行原有{/eq}后追加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<label>验证码(点击图像更换)</label><br>
<input type="text" name="ctype" id="ts" style="display: none" value="vcode">
<div id="fzs">
<div align="center">
<img style="max-width:100%" id="v" onclick="change()" src="/Member/Chemical">
</div>
<div class="form-group label-floating is-empty">
<label class="control-label" for="focusedInput1">请输入上图物质的分子式</label>
<input class="form-control" name="vcode" id="vcode" type="text">
</div>
</div>
<div id="ev" style="display:none;">
<div align="center">
<img style="max-width:100%" id="ve" onclick="change()">
</div>
<div class="form-group label-floating is-empty">
<label class="control-label" for="focusedInput1">请输入上图事件发生日期</label>
<input class="form-control" name="vcode1" id="vcode1" type="text">
<label>格式例如:19890604,公元前请加“-”表示</label>
</div>
</div>
<div id="jz" style="display:none;">
<div align="center">
<img style="max-width:100%" id="jzi" onclick="change()">
</div>
<div class="form-group label-floating is-empty">
<label class="control-label" for="focusedInput1">请输入上图结果的方阵的行列式的值</label>
<input class="form-control" name="vcode3" id="vcode3" type="text">
<label>请使用整数表示</label>
</div>
</div>

login.html的尾部<script>标签内或/static/js/login.js中追加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function change() {
r = Math.random();
if (r > 0.66) {
$("#fzs").hide();
$("#jz").hide();
$("#ev").show();
$("#ve").attr('src', '/Member/History?=' + Math.random());
ts = "vcode1";
} else if (r < 0.66 && r > 0.33) {
$("#ev").hide();
$("#jz").hide();
$("#fzs").show();
$("#v").attr('src', '/Member/Chemical?=' + Math.random());
ts = "vcode";
} else {
$("#jz").show();
$("#fzs").hide();
$("#ev").hide();
$("#jzi").attr('src', '/Member/Matrix?=' + Math.random());
ts = "vcode3";
}
$("#ts").val(ts);
}

application/index/controller/Member.php结尾的}前追加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public function Chemical(){
$id = rand(1,10186);
$results = Db::name("vcode")->where("id",$id)->find();
$url = "https://www.chemicalbook.com/CAS/GIF/".$results["cas"].".gif";
ob_end_clean();
Header("HTTP/1.1 303 See Other");
Header("Location: $url");
session('Checknum', $results["anwser"]);
}

public function History(){
$id = rand(1,30000);
$results1 = Db::table("event")->where("id",$id)->find();
$type = $results1['y'];
$year = $results1['d'];
$riqi = $results1['i'];
$info = $results1['p'];
if($type != "0"){
$id = rand(1,30000);
$results1 = Db::table("event")->where("id",$id)->find();
$type = $results1['y'];
$year = $results1['d'];
$riqi = $results1['i'];
$info = $results1['p'];
}
switch ($type) {
case '0':
$t="大事件发生";
break;
case '1':
$t="人物出生";
break;
case '2':
$t="人物逝世";
break;

default:

break;
}
$year = str_replace("前", "-", $year);
$year = str_replace("年", "", $year);
$month = explode("月",$riqi);
$m = sprintf("%02d", $month[0]);
$d = sprintf("%02d", str_replace("日","",$month[1]));
$ttt=$t.":\n".$info;
$width = (strlen($info)>=189) ? 500 : 250 ;
$im = imagecreatetruecolor(500, $width);
$backgroundColor = imagecolorallocate($im, 255, 255, 255);
imagefill($im, 0, 0, $backgroundColor);
$box = new Box($im);
$box->setFontFace(ROOT_PATH.'/SourceHanSansCN-Regular.otf');
$box->setFontColor(new Color(0, 0, 0));
$box->setTextShadow(new Color(0, 0, 0, 50), 0, 0);
$box->setFontSize(28);
$box->setLineHeight(1.5);
$box->setBox(20, 20, 460, 460);
$box->setTextAlign('left', 'top');
$box->draw($ttt
);
session('Checknum', $year.$m.$d);
header("Content-type: image/png;");
header("cache-control:no-cache,must-revalidate");
imagepng($im);
imagedestroy($im);
}

public function Matrix(){
$image = imagecreatefrompng(ROOT_PATH."/bg.png");
$black = imagecolorallocate($image, 0, 0, 0);
$id = rand(1,22523);
$size = 22;
$font = ROOT_PATH.'/SourceHanSansCN-Regular.otf';
$text="1";
$results1 = Db::table("m")->where("id",$id)->find();
$m1 = $results1['m1'];
$m2 = $results1['m2'];
$anwser = $results1['anwser'];
$m1_ex = explode(";",$m1);
$m2_ex = explode(";",$m2);
$row = "";
foreach ($m1_ex as $key => $value) {
foreach (explode(" ",$value) as $key1 => $value1) {
$row = $row.$value1." ";
}
imagettftext($image, $size, 0, 45, 130+$key*40, $black, $font, $row);
$row = "";
}
foreach ($m2_ex as $key => $value) {
foreach (explode(" ",$value) as $key1 => $value1) {
$row = $row.$value1." ";
}
imagettftext($image, $size, 0, 307, 130+$key*40, $black, $font, $row);
$row = "";
}
ob_end_clean();
header("cache-control:no-cache,must-revalidate");
session('Checknum', $anwser);
header('content-type: image/png');
imagepng($image);
imagedestroy($image);
}

Member.php 开头15行左右Class Member ...前追加:

1
2
use GDText\Box;
use GDText\Color;

31行左右Register方法替换为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function Register(){
$ctype = input("post.ctype");
if(empty(input("post.".$ctype)) || input("post.".$ctype)!= session("Checknum")){
return json(['code' => '1','message' => "验证码错误"]);
}
if(input('?post.username-reg') && input('?post.password-reg')){
$regAction = User::register(input('post.username-reg'),input('post.password-reg'),input('post.captchaCode'));
if ($regAction[0]){
return json(['code' => '200','message' => $regAction[1]]);
}else{
return json(['code' => '1','message' => $regAction[1]]);
}
}else{
return json(['code' => '1','message' => "信息不完整"]);
}
}