SPAM Filterについて

基本的にはここのです。 導入にあたって、一部直しています。

lib/spam_filter.php

reCAPTCHA v2 と reCAPTCHA v3 が逆になっている気がしたので修正。あと次いでにremoteipをパラメータに追加。 あとはAkismetを無効にしてブラックリストを有効に。 そのうちAkismetも有効にしたい。

--- lib/spam_filter.php.orig   2021-02-07 21:44:46.000000000 +0900
+++ lib/spam_filter.php        2021-02-07 22:57:08.000000000 +0900
@@ -61,7 +61,8 @@
 //define('SPAM_FILTER_COND', ''#useragent() or #filename() or #atag() or (#onlyeng() and #urlnum()) or #urlnsbl() or (#onlyeng() and #url() and #akismet()) or #recaptcha()');
 
 // ※デフォルトでempty(空)入力チェック・Akismet・reCAPTCHAフィルタをセット
-define('SPAM_FILTER_COND', '#ngempty() or #akismet() or #recaptcha()');
+//define('SPAM_FILTER_COND', '#ngempty() or #akismet() or #recaptcha()');
+define('SPAM_FILTER_COND', '#ngempty() or #recaptcha() or #urlnsbl()');
 
 //// CAPTCHAでのチェックをする条件を指定する
 // ※SPAM_FILTER_CONDで明示的に「#recaptcha()」を指定することにより廃止
@@ -849,12 +850,12 @@
 
               $secret_key = SPAM_FILTER_RECAPTCHA_SECRETKEY;
 
-              if (SPAM_FILTER_RECAPTCHA_CHECK =='v2') {
-                      // reCAPTCHA v2
-                      $response=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$_POST['g-recaptcha-response']}");
-              } elseif (SPAM_FILTER_RECAPTCHA_CHECK =='v3') {
+              if (SPAM_FILTER_RECAPTCHA_CHECK =='v3') {
                       // reCAPTCHA v3
-                      $response=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$_POST['recaptchaResponse']}");
+                      $response=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$_POST['g-recaptcha-response']}&remoteip={$_SERVER['REMOTE_ADDR']}");
+              } elseif (SPAM_FILTER_RECAPTCHA_CHECK =='v2') {
+                      // reCAPTCHA v2
+                      $response=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$_POST['recaptchaResponse']}&remoteip={$_SERVER['REMOTE_ADDR']}");
               } else {
                       // SPAM_FILTER_RECAPTCHA_CHECKが設定されていない場合はチェックしない
                       return FALSE;

plugin/edit.inc.php

reCAPTCHA 関係のJS読み込みを追加。

--- plugin/edit.inc.php.orig   2021-02-07 22:05:14.000000000 +0900
+++ plugin/edit.inc.php        2021-02-07 22:05:43.000000000 +0900
@@ -13,6 +13,8 @@
 {
       global $vars, $_title_edit;
 
+      plugin_edit_insert_recaptcha_script_tag();
+
       if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
 
       // Create initial pages
@@ -288,3 +290,12 @@
               init_autoalias_def_page();
       }
 }
+
+function plugin_edit_insert_recaptcha_script_tag() {
+    global $head_tags;
+
+    $head_tags[] = '<!-- reCAPTHA -->';
+    $head_tags[] = sprintf('<script src="https://www.google.com/recaptcha/api.js?render=%s"></script>', SPAM_FILTER_RECAPTCHA_SITEKEY);
+    $head_tags[] = sprintf('<script>const RECAPTCHA_SITEKEY = "%s"</script>', SPAM_FILTER_RECAPTCHA_SITEKEY);
+    $head_tags[] = '<script src="./skin/recaptcha.js"></script>';
+}

skin/recaptcha.js

もうIE対応は必要ないよね、ということで雑に実装。 プレビューボタンと更新ボタンにイベントハンドラを設定して、 reCAPTCHA実行後に、hidden を追加して、submit。 なんだけど、これだとページ遷移時にダイアログが出てしまう。 そのうち、もうちょっと真面目な実装に切り替えるかもしれない。

window.addEventListener('DOMContentLoaded', function() {
    function getForm(node) {
        if (node === null || node.tagName === 'FORM') {
            return node;
        }
        return getForm(node.parentNode);
    }

    ['preview', 'write'].forEach(function(action) {
        document.getElementsByName(action).forEach(function(element) {
            const form = getForm(element);
            const name = element.name;
            const value = element.value;
            element.addEventListener('click', function(e) {
                e.preventDefault();
                grecaptcha.ready(function() {
                    grecaptcha.execute(RECAPTCHA_SITEKEY, { action: 'submit' }).then(function(token) {
                        const submit = document.createElement('input');
                        submit.type = 'hidden';
                        submit.name = name;
                        submit.value = value;
                        form.appendChild(submit);

                        const tokenElement = document.createElement('input');
                        tokenElement.type = 'hidden';
                        tokenElement.name = 'g-recaptcha-response';
                        tokenElement.value = token;
                        form.appendChild(tokenElement);

                        window.onbeforeunload = null;
                        form.submit();
                    });
                });
            });
        });
    });
});

変更した。reCAPTCHA のトークンは2分で切れるので、110秒ごとにトークンを発行する方式。

window.addEventListener('DOMContentLoaded', function() {
    const forms = document.getElementsByClassName('_plugin_edit_edit_form');
    for (let i = 0; i < forms.length; i++) {
        const form = forms[i];
        const hidden = document.createElement('input');
        hidden.type = 'hidden';
        hidden.name = 'g-recaptcha-response';

        form.appendChild(hidden);
    }

    grecaptcha.ready(function() {
        function recaptchaExecute() {
            grecaptcha.execute(RECAPTCHA_SITEKEY, { action: 'submit' }).then(function(token) {
                document.getElementsByName('g-recaptcha-response').forEach(function(element) {
                    element.value = token;
                });

                // retry after 110 sec because reCAPTCHA tokens expires after 2 min.
                setTimeout(recaptchaExecute, 110 * 1000);
            });
        }

        recaptchaExecute();
    });
});

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-02-07 (日) 23:00:49