Создаем CAPTCHA плагин для вашего WordPress сайта

14-12-23 Php, WordPress CAPTCHA, WordPress 1

Благодаря своей популярности, WordPress стал мишенью для спамеров.

Автоматизированные спам-боты ищут в сети сайты, работающие на популярных системах, таких как WordPress, и отправляют на них сотни и тысячи спам комментариев. Без надежной защиты спам становится большой проблемой для сайта.

Хороший способ борьбы со спамом — использование CAPTCHA в формах комментариев на вашем сайте.

В каталоге WordPress плагинов есть много плагинов для интеграции CAPTCHA. Но создавать очередной капча плагин мы не будем, цели этой статьи немного другие:

  1. Продемонстрировать работу с HTTP API в WordPress.
  2. Узнать как добавить собственные поля в форму для комментариев, использовать и валидировать их.

Разработка плагина

Перед тем как приступить к разработке плагина, перейдите на сайт reCAPTCHA, зарегистрируйте ваш сайт и получите ваши публичный и секретный ключи для использования API reCAPTCHA.

Подробнее об основах создания плагинов для WordPress вы можете узнать в статьях:

Напишем заголовок плагина:

/*
  Plugin Name: Add reCAPTCHA to comment form
  Plugin URI: http://easy-code.ru
  Description: Add Google's reCAPTCHA to WordPress comment form
  Version: 0.1
  License: GPL2
 */

Создайте плагин с тремя свойствами, в которых будут храниться ключи, а также сообщение об ошибке (это сообщение генерируется если форма не заполнена или заполнена не верно).

class Captcha_Comment_Form {

    /** @type string private key|public key */
    private $public_key, $private_key;

    /** @type string captcha errors */
    private static $captcha_error;

Конструктор класса будет добавлять две пары событий и фильтров.

    /** class constructor */
    public function __construct() {

        $this->public_key = '7Lcimv8SRFGYKOja-6WXmSllOz8fjYWfHxdsgMwz';
        $this->private_key = '7Lcimv8SQSDFTH9dgEOiUANLBIfd85Qr0Kv4NrSdV';

        // Добавим капчу в форму для комментариев
        add_action('comment_form', array($this, 'captcha_display'));

        // удаляем комментарии не прошедшие проверку
        add_action('wp_head', array($this, 'delete_failed_captcha_comment'));

        // проверка капчи
        add_filter('preprocess_comment', array($this, 'validate_captcha_field'));

        // редирект при отправке комментария
        add_filter('comment_post_redirect', array($this, 'redirect_fail_captcha_comment'), 10, 2);
    }

Капча будет выводится методом captcha_display(). Для того, чтобы форма выводилась в нужное нам место, надо чтобы WordPress вызвал этот метод во время вывода формы для комментариев. В этом поможет системное событие comment_form.

Событие wp_head будет вызывать функцию delete_failed_captcha_comment(), который будет удалять комментарии с неправильной капчей.

Фильтр preprocess_comment вызывает метод validate_captcha_field() для проверки, что CAPTCHA заполнена верно.

Фильтр comment_post_redirect вызовет метод redirect_fail_captcha_comment(), которая добавит необходимые параметры к строке запроса при редиректе.

Метод captcha_display():

    /** Output the reCAPTCHA form field. */
    public function captcha_display() {
        if (isset($_GET['captcha']) && $_GET['captcha'] == 'empty') {
            echo '<strong>ERROR</strong>: CAPTCHA should not be empty';
        } elseif (isset($_GET['captcha']) && $_GET['captcha'] == 'failed') {
            echo '<strong>ERROR</strong>: CAPTCHA response was incorrect';
        }

        echo <<<CAPTCHA_FORM
        <style type='text/css'>
            #submit {
                display: none;
            }
        </style>
        <script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=<?= $this->public_key; ?>">
        </script>
        <noscript>
            <iframe src="http://www.google.com/recaptcha/api/noscript?k=<?= $this->public_key; ?>" height="300" width="300" frameborder="0"></iframe>
            <br>
            <textarea name="recaptcha_challenge_field" rows="3" cols="40">
            </textarea>
            <input type="hidden" name="recaptcha_response_field" value="manual_challenge">
        </noscript>
        <input name="submit" type="submit" id="submit-alt" tabindex="6" value="Post Comment"/>
CAPTCHA_FORM;
    }

    /**
     * Add query string to the comment redirect location
     *
     * @param $location string location to redirect to after comment
     * @param $comment object comment object
     *
     * @return string
     */
    function redirect_fail_captcha_comment($location, $comment) {

        if (!empty(self::$captcha_error)) {

            $args = array('comment-id' => $comment->comment_ID);

            if (self::$captcha_error == 'captcha_empty') {
                $args['captcha'] = 'empty';
            } elseif (self::$captcha_error == 'challenge_failed') {
                $args['captcha'] = 'failed';
            }

            $location = add_query_arg($args, $location);
        }

        return $location;
    }

Также эта функция проверяет был ли передан параметр $_GET[‘captcha’] в функции redirect_fail_captcha_comment() и выводит соответствующее сообщение.

    /**
     * Verify the captcha answer
     *
     * @param $commentdata object comment object
     *
     * @return object
     */
    public function validate_captcha_field($commentdata) {

        // if captcha is left empty, set the self::$captcha_error property to indicate so.
        if (empty($_POST['recaptcha_response_field'])) {
            self::$captcha_error = 'captcha_empty';
        }

        // if captcha verification fail, set self::$captcha_error to indicate so
        elseif ($this->recaptcha_response() == 'false') {
            self::$captcha_error = 'challenge_failed';
        }

        return $commentdata;
    }

Метод validate_captcha_field(), как понятно по его названию, проверяет правильность заполнения капчи.

Обратите внимание на условие elseif, в нем происходит вызов функции recaptcha_response() для проверки CAPTCHA.

Метод recaptcha_response():

    /**
     * Get the reCAPTCHA API response.
     *
     * @return string
     */
    public function recaptcha_response() {

        // reCAPTCHA challenge post data
        $challenge = isset($_POST['recaptcha_challenge_field']) ? esc_attr($_POST['recaptcha_challenge_field']) : '';

        // reCAPTCHA response post data
        $response = isset($_POST['recaptcha_response_field']) ? esc_attr($_POST['recaptcha_response_field']) : '';

        $remote_ip = $_SERVER["REMOTE_ADDR"];

        $post_body = array(
            'privatekey' => $this->private_key,
            'remoteip' => $remote_ip,
            'challenge' => $challenge,
            'response' => $response
        );

        return $this->recaptcha_post_request($post_body);
    }

Разберемся в том, как работает recaptcha_response().

POST запрос отправляется по адресу http://www.google.com/recaptcha/api/verify со следующими параметрами:

  • privatekey: ваш секретный ключ.
  • remoteip: IP адрес комментатора.
  • challenge: значения поля recaptcha_challenge_field в форме для комментариев.
  • response: значение поля recaptcha_response_field в форме для комментариев.

IP адрес посетителя хранится в $_SERVER[«REMOTE_ADDR»].

В методе recaptcha_post_request() происходит работа с HTTP API. Эта функция принимает параметры POST запроса и делает запрос к API капчи и, в случае успеха возвращает true.

    /**
     * Send HTTP POST request and return the response.
     *
     * @param $post_body array HTTP POST body
     *
     * @return bool
     */
    public function recaptcha_post_request($post_body) {

        $args = array('body' => $post_body);

        // отправляем POST запрос на сервер reCaptcha
        $request = wp_remote_post('https://www.google.com/recaptcha/api/verify', $args);

        // получаем ответ
        $response_body = wp_remote_retrieve_body($request);
        $answers = explode("\n", $response_body);

        $request_status = trim($answers[0]);

        return $request_status;
    }

Любой комментарий, отправленный пользователем, который не прошел проверку, удаляется методом delete_failed_captcha_comment().

    /** Delete comment that fail the captcha test. */
    function delete_failed_captcha_comment() {
        if (isset($_GET['comment-id']) && !empty($_GET['comment-id'])) {

            wp_delete_comment(absint($_GET['comment-id']));
        }
    }

Плагин почти готов. Для его работы нам надо создать объект только что написанного класса:

new Captcha_Comment_Form();

После активации плагина CAPTCHA будет добавлена в форму для комментариев WordPress:

Разработка CAPTCHA плагина для WordPress.
Разработка CAPTCHA плагина для WordPress.

Заключение

В этой статье мы рассмотрели работу с формой комментариев в WordPress. С помощью системы событий и фильтров вы можете делать с комментариями на вашем сайте что угодно!

Для проверки работоспособности плагина скачайте исходники и поместите главный файл плагина в папку wp-content/plugins и замените ключи на свои.

На этом всё 🙂

Хочешь получать статьи на почту?

Подпишись на обновления!
* Ваш email не будет разглашен/продан. Вы сможете отписаться в любое время.

1 Комментарий

  1. MrVigner says:

    Плагин работает, но как и другие выводит каптчу после кнопки «Отправить», поэтому даже если не вводить каптчу комментарий все равно добавляется….

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *