给 Typecho 评论区适配 Cloudflare Turnstile

尚寂新
2024/08/10 22:12

一直以来,本站评论区都饱受 Spam 的烦扰,于是 TE 水友群里就有小伙伴提议用一下 Cloudflare Turnstile 来解决一下。这个就是类似于 Google reCAPTCHA 吧,但区别与 Google 的是,Turnstile 没有那些烦人的找红绿灯找自行车啊什么的,几乎属于无感的。于是便着手考虑给自己站点的评论区也安排上这个。

PS:情人节大家都在牵手,我在这里改BUG...

获取 Key

首先,要到 Cloudflare Turnstile 官网注册一下,创建好 Turnstile 站点,获取到两个密钥(一个 Key 是放在前台的,另一个打码的是放在后台的)

免费的额度肯定够用,具体可以详见官网。但免费的版本“仅限托管模式”,也就是不能无痕插入,肯定会在前端留出一个验证状态的框,可能会对美观性造成一定影响(比如说我这边就是)

前端部分

在主题目录的 comments.php 中,找到 <form> 表单,把下面的代码放到表单里面。如果实在确定不好位置,那就放在评论提交按钮的上面就好。记得把上面的前台密钥给填写进去(不是打码的那个)。

<div class="cf-turnstile" data-sitekey="写你自己站点的KEY"></div>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" defer></script>

对于进行过评论区 Ajax 提交改造的站点,需要让验证器在每次提交之后,进行一次刷新的操作。可以在适当位置添加如下代码。

// 也可以不用 try 包裹
try {
    turnstile.reset();
} catch (e) {}

后端部分

直接在主题目录的 functions.php 中,追加如下内容。

Typecho_Plugin::factory('Widget_Feedback')->comment = ['XComment', 'feedbackFilter'];
class XComment {
    /**
     * 评论发布钩子
     * @param $comment
     * @param $archive
     * @return mixed
     * @throws \Typecho\Widget\Exception
     */
    public static function feedbackFilter($comment, $archive)
    {
        // 如果已登录,直接返回,不进行处理
        if (Typecho_Widget::widget('Widget_User')->hasLogin()) {
            return $comment;
        }
        
        $secret = '打码的密钥填在这里'; /* Store this somewhere secure */
        $remote_addr = $_SERVER['REMOTE_ADDR'];
        $cf_url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
        $token = $_POST['cf-turnstile-response'];
        $msg = '';
        $isPass = false;
    
        // Request data
        $data = array(
            "secret" => $secret,
            "response" => $token,
            "remoteip" => $remote_addr
        );
    
        // Initialize cURL
        $curl = curl_init();
    
        // Set the cURL options
        curl_setopt($curl, CURLOPT_URL, $cf_url);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    
        // Execute the cURL request
        $response = curl_exec($curl);
    
        // Check for errors
        if (curl_errno($curl)) {
            $error_message = curl_error($curl);
            // Handle the error the way you like it
            $msg = '[Turnstile]cURL Error: ' . $error_message;
        }else{
            /* Parse Cloudflare's response and check if there are any validation errors */
            $response = json_decode($response,true);
            if ($response['error-codes'] && count($response['error-codes']) > 0){
                $msg = '此评论已被 Cloudflare Turnstile 拦截。Error codes: ';
                foreach($response['error-codes'] as $e){
                    $msg .= $e;
                }
            }else{
                $isPass = true;
            }
        }
    
        // Close cURL
        curl_close($curl);
    
        if ($isPass) {
            return $comment;
        } else {
            throw new \Typecho\Widget\Exception(_t($msg, '评论失败'));
        }
    }
}

这样下来,应该就可以了。

参考链接

已有 2 条评论 (旧评论在前)
  1. 森木志 友链
    回复
    2024-08-11 21:05 广东省 Windows NT10

    测试一下嘿嘿

  2. 叶开
    回复
    2024-08-12 19:46 福建省 Windows NT10

    我来测试一下,这个CF验证!非常快!

添加新评论 (Markdown Supported)
(ノ°ο°)ノ