<commit_before><?php

/**
 * @description: 圖形驗證碼的建立和驗證
 * @package NyarukoLogin
 */

use Gregwar\Captcha\CaptchaBuilder;
use Gregwar\Captcha\PhraseBuilder;

class nyacaptcha {
    function __construct() {
    }
    /**
     * @description: 创建验证码
     * @param Bool extnow 是否立即将信息返回给客户端
     * @param Bool showcaptcha 是否直接返回验证码明码，而不是图片
     * @param Bool showimage 是否直接输出验证码图片
     * @return Array<String> 验证码相关信息：
     * code 状态码
     * time 验证码生成时间
     * img 验证码文件名（不包括扩展名和路径）
     * captcha 验证码内容
     * file 验证码图片本地存储路径(extnow 时不输出)
     * url 验证码图片网址
     */
    function getcaptcha($extnow = true, $showcaptcha = false, $showimage = false) {
        global $nlcore;
        $debug = $nlcore->cfg->verify->debug;
        $appToken = $nlcore->sess->appToken;
        $captchaconf = $nlcore->cfg->verify->captcha;
        $imgfname = $nlcore->safe->randhash();
        $phpfiledir = pathinfo(__FILE__)["dirname"] . DIRECTORY_SEPARATOR;
        $imgfile = $captchaconf["imgname"] . $imgfname . ".jpg";
        $time = $nlcore->safe->getnowtimestr();
        //生成验证码
        $phraseBuilder = new PhraseBuilder($captchaconf["codelen"], $captchaconf["charset"]);
        $builder = new CaptchaBuilder(null, $phraseBuilder);
        if (!$showcaptcha) $builder->build();
        if ($showimage) {
            header('Content-type: image/jpeg');
            exit($builder->output());
        }
        if (!$showcaptcha) {
            $imgpath = $phpfiledir . ".." . DIRECTORY_SEPARATOR . $captchaconf["imgdir"] . DIRECTORY_SEPARATOR . $imgfile;
            $imgurl = $nlcore->cfg->app->appurl . $captchaconf["imgdir"] . '/' . $imgfile;
            $builder->save($imgpath);
        }
        $vc1code = $builder->getPhrase();
        //写入数据库
        $updateDic = [
            "vc1code" => $vc1code,
            "vc2time" => $time
        ];
        $tableStr = $nlcore->cfg->db->tables["encryption"];
        $whereDic = [
            "apptoken" => $appToken
        ];
        $dbreturn = $nlcore->db->update($updateDic, $tableStr, $whereDic);
        $retuenarr = [
            "code" => 1000000,
            "img" => $imgurl
        ];
        if ($showcaptcha) {
            $retuenarr["captcha"] = $vc1code;
        }
        if ($debug) {
            $retuenarr["debug"] = $debug;
        }
        if ($extnow) {
            echo $nlcore->sess->encryptargv($retuenarr);
        } else {
            return $retuenarr;
        }
        return null;
    }

    /**
     * @description: 验证码验证失败后用此函数重新创建一个
     * @param String code 错误代码
     * @return Array<String> 验证码相关信息（其中code、msg会不同）
     */
    function verifyfailgetnew($code) {
        global $nlcore;
        $retuenarr = $this->getcaptcha(false);
        $retuenarr["code"] = $code;
        $retuenarr["msg"] = $nlcore->msg->imsg[$code];
        echo $nlcore->sess->encryptargv($retuenarr);
        return $retuenarr;
    }

    /**
     * @description: 验证图形验证码是否正确
     * @param String captchacode 验证码
     * @param String totpsecret totp加密码
     * @return Bool 是否可以通行
     */
    function verifycaptcha($appToken, $captchacode) {
        global $nlcore;
        $columnArr = ["id", "vc1code", "vc1time"];
        $tableStr = $nlcore->cfg->db->tables["encryption"];
        $whereDic = [
            "apptoken" => $appToken
        ];
        $dbreturn = $nlcore->db->select($columnArr, $tableStr, $whereDic);
        if ($dbreturn[0] != 1010000) {
            die($nlcore->msg->m(2020501));
        }
        $cinfo = $dbreturn[2][0];
        $vc1time = strtotime($cinfo["vc1time"]);
        $endtime = $vc1time + $nlcore->cfg->verify->timeout["captcha"];
        if (time() > $endtime) {
            $this->verifyfailgetnew(2020502);
            return false;
        }
        if (strtolower($captchacode) != strtolower($cinfo["vc1code"])) {
            $this->verifyfailgetnew(2020503);
            return false;
        }
        //删除已经验证通过的信息
        $updateDic = [
            "vc1code" => null,
            "vc1time" => null
        ];
        $whereDic = [
            "id" => $cinfo["id"]
        ];
        $dbreturn = $nlcore->db->update($updateDic, $tableStr, $whereDic);
        return true;
    }<commit_msg>图形验证码支持从Redis存入和读出<commit_after><?php

/**
 * @description: 圖形驗證碼的建立和驗證
 * @package NyarukoLogin
 */

use Gregwar\Captcha\CaptchaBuilder;
use Gregwar\Captcha\PhraseBuilder;

class nyacaptcha {
    function __construct() {
    }
    /**
     * @description: 建立驗證碼
     * @param Bool extnow 是否立即將資訊返回給客戶端
     * @param Bool showcaptcha 是否直接返回驗證碼明碼，而不是圖片
     * @param Bool showimage 是否直接輸出驗證碼圖片
     * @return Array<String> 驗證碼相關資訊：
     * code 狀態碼
     * time 驗證碼生成時間
     * img 驗證碼檔名（不包括副檔名和路徑）
     * captcha 驗證碼內容
     * file 驗證碼圖片本地儲存路徑(extnow 時不輸出)
     * url 驗證碼圖片網址
     */
    function getcaptcha($extnow = true, $showcaptcha = false, $showimage = false) {
        global $nlcore;
        $debug = $nlcore->cfg->verify->debug;
        $appToken = $nlcore->sess->appToken;
        $captchaconf = $nlcore->cfg->verify->captcha;
        $imgfname = $nlcore->safe->randhash();
        $phpfiledir = pathinfo(__FILE__)["dirname"] . DIRECTORY_SEPARATOR;
        $imgfile = $captchaconf["imgname"] . $imgfname . ".jpg";
        $time = $nlcore->safe->getnowtimestr();
        //生成验证码
        $phraseBuilder = new PhraseBuilder($captchaconf["codelen"], $captchaconf["charset"]);
        $builder = new CaptchaBuilder(null, $phraseBuilder);
        if (!$showcaptcha) $builder->build();
        if ($showimage) {
            header('Content-type: image/jpeg');
            exit($builder->output());
        }
        if (!$showcaptcha) {
            $imgpath = $phpfiledir . ".." . DIRECTORY_SEPARATOR . $captchaconf["imgdir"] . DIRECTORY_SEPARATOR . $imgfile;
            $imgurl = $nlcore->cfg->app->appurl . $captchaconf["imgdir"] . '/' . $imgfile;
            $builder->save($imgpath);
        }
        $vc1code = $builder->getPhrase();
        if ($nlcore->db->initRedis()) {
            // 嘗試儲存到 Redis
            $timeout = $nlcore->cfg->verify->timeout["captcha"];
            $redis = $nlcore->db->redis;
            $key = $this->redisKeyName();
            // 檢查是否有驗證碼資料
            if ($redis->exists($key)) {
                $redis->del($key); // 有則刪除
            }
            // 儲存驗證碼
            $redis->setex($key, $timeout, $vc1code);
        } else {
            // 嘗試儲存到 MySQL
            $updateDic = [
                "vc1code" => $vc1code,
                "vc1time" => $time
            ];
            $tableStr = $nlcore->cfg->db->tables["encryption"];
            $whereDic = [
                "apptoken" => $appToken
            ];
            $result = $nlcore->db->update($updateDic, $tableStr, $whereDic);
            if ($result[0] >= 2000000) {
                $nlcore->msg->stopmsg(2020601);
            }
        }
        $retuenarr = [
            "code" => 1000000,
            "img" => $imgurl
        ];
        if ($showcaptcha) {
            $retuenarr["captcha"] = $vc1code;
        }
        if ($debug) {
            $retuenarr["debug"] = $vc1code;
        }
        if ($extnow) {
            echo $nlcore->sess->encryptargv($retuenarr);
        } else {
            return $retuenarr;
        }
        return null;
    }
    /**
     * @description: 建立 Redis 鍵名
     * @return String 鍵名
     */
    function redisKeyName(): string {
        global $nlcore;
        return $nlcore->cfg->db->redis_tables["vcode1"] . $nlcore->sess->appToken;
    }
    /**
     * @description: 驗證碼驗證失敗後用此函式重新建立一個
     * @param String code 錯誤程式碼
     * @return Array<String> 驗證碼相關資訊（其中code、msg會不同）
     */
    function verifyfailgetnew($code) {
        global $nlcore;
        $retuenarr = $this->getcaptcha(false);
        $retuenarr["code"] = $code;
        $retuenarr["msg"] = $nlcore->msg->imsg[$code];
        echo $nlcore->sess->encryptargv($retuenarr);
        return $retuenarr;
    }

    /**
     * @description: 驗證圖形驗證碼是否正確
     * @param String captchacode 驗證碼
     * @param String totpsecret totp加密碼
     * @return Bool 是否可以通行
     */
    function verifycaptcha($appToken, $captchacode) {
        if (strlen($captchacode) < 4) return false;
        global $nlcore;
        if ($nlcore->db->initRedis()) {
            // 嘗試從 Redis 載入
            $redis = $nlcore->db->redis;
            $key = $this->redisKeyName();
            // 檢查是否有驗證碼資料
            if ($redis->exists($key)) {
                $saveCode = $redis->get($key);
                // 檢查驗證碼是否匹配
                if (strtolower($captchacode) != strtolower($saveCode)) {
                    $this->verifyfailgetnew(2020505); // 不匹配
                    return false;
                }
                // 刪除已經驗證透過的資訊
                $redis->del($key);
            } else {
                $nlcore->msg->stopmsg(2020505);
            }
        } else {
            // 嘗試從 MySQL 載入
            $columnArr = ["id", "vc1code", "vc1time"];
            $tableStr = $nlcore->cfg->db->tables["encryption"];
            $whereDic = [
                "apptoken" => $appToken
            ];
            $dbreturn = $nlcore->db->select($columnArr, $tableStr, $whereDic);
            if ($dbreturn[0] != 1010000) {
                die($nlcore->msg->m(2020501));
            }
            $cinfo = $dbreturn[2][0];
            $vc1time = strtotime($cinfo["vc1time"]);
            $endtime = $vc1time + $nlcore->cfg->verify->timeout["captcha"];
            if (time() > $endtime) {
                $this->verifyfailgetnew(2020502);
                return false;
            }
            if (strtolower($captchacode) != strtolower($cinfo["vc1code"])) {
                $this->verifyfailgetnew(2020503);
                return false;
            }
            // 刪除已經驗證透過的資訊
            $updateDic = [
                "vc1code" => null,
                "vc1time" => null
            ];
            $whereDic = [
                "id" => $cinfo["id"]
            ];
            $dbreturn = $nlcore->db->update($updateDic, $tableStr, $whereDic);
        }
        return true;
    }
{'fraction_non_alphanumeric': 0.15369301214413697, 'fraction_numerical': 0.013438184351980888, 'mean_word_length': 1.8127099664053752, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 147, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5867329', 'n_tokens_mistral': 3826, 'n_tokens_neox': 3808, 'n_words': 535}