Back
Featured image of post 给Cloudreve添加化学式/矩阵/大事件验证码

给Cloudreve添加化学式/矩阵/大事件验证码

这个验证码可以完美的过滤人类

2020/9/12 更新: 此文章内容仅适用于 Cloudreve 1.X 版本

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

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

效果展示

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

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

化学式.png
化学式.png

部署方法

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}后追加:

<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中追加:

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结尾的}前追加:

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 ...前追加:

use GDText\Box;
use GDText\Color;

31行左右Register方法替换为:

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' => "信息不完整"]);
    }
}