Используем «Яндекс.Чистый Веб» для защиты от спама

в 3:28, , рубрики: php, спам, Спам (и антиспам), яндекс, Яндекс API, метки: , ,

Уже достаточно долгое время Яндекс предоставляет бесплатный сервис обнаружения спама в сообщениях под названием «Яндекс.Чистый Веб», однако до сих пор он остаётся малопопулярным.

В этом посте я продемонстрирую основные методы работы с API «Яндекс.Чистый Веб» на примере PHP-класса.

Итак, сервис поддерживает четыре метода — обнаружение спама, получение CAPTCHA, проверка введённой CAPTCHA и обжалование решения детектора спама. Мы рассмотрим работу с первыми тремя методами.

Для удобства оформим всё это в виде простого статического класса.

  1. class YandexCW
  2.  {
  3.         public static $api_key          = '12345';
  4.  
  5.         /* URL-адреса */
  6.  
  7.         const check_data_url            = 'http://cleanweb-api.yandex.ru/1.0/check-spam';
  8.         const get_captcha_url           = 'http://cleanweb-api.yandex.ru/1.0/get-captcha';
  9.         const check_captcha_url         = 'http://cleanweb-api.yandex.ru/1.0/check-captcha';
  10.  }

Приступим к реализации методов класса. API «Чистого Веба» принимает GET и POST запросы в зависимости от необходимого метода, и отдаёт результат в формате XML. Поэтому сперва мы напишем в нашем классе несложный приватный метод для отправки запросов и чтения ответов. Будем использовать SimpleXML для чтения ответов, а вот CURL применять не станем — благо, стандартная функция file_get_contents позволяет совершать и GET- и POST-запросы с помощью контекстов.

  1.         /* Отправка запроса сервису */
  2.  
  3.         private function xml_query($url, $parameters = array(), $post = false)
  4.          {
  5.                 if (!isset($parameters['key'])) $parameters['key'] = self::$api_key;
  6.  
  7.                 $parameters_query = http_build_query($parameters);
  8.  
  9.                 if ($post)
  10.                  {
  11.                         $http_options = array(
  12.                                         'http'  => array (
  13.                                                 'method'        => 'POST',
  14.                                                 'content'       => $parameters_query
  15.                                          )
  16.                          );
  17.  
  18.                         $context = stream_context_create($http_options);
  19.                         $contents = file_get_contents($url, false, $context);
  20.  
  21.                  } else $contents = file_get_contents($url.'?'.$parameters_query);
  22.  
  23.                 if (!$contents) return false;
  24.  
  25.                 $xml_data = new SimpleXMLElement($contents);
  26.  
  27.                 return $xml_data;
  28.          }

Этот метод существенно упростит нам работу с API — он автоматически подставляет ключ, формирует контекст для file_get_contents, если нам понадобится сделать POST-запрос, а также возвращает ответ уже в виде объекта SimpleXML. Думаю, код не нуждается в более подробном комментировании. Так что перейдём непосредственно к методам для работы с API.

Проверка сообщения на спам

В первую очередь реализуем метод для отправки содержимого сообщения Яндексу и последующей проверки его на спам. Однако перед тем, как просто привести код, следует кое-что уточнить. Согласно описанию метода check-spam, он может принимать следующие параметры, касающиеся содержимого сообщения:

  • ip — IP-адрес отправителя.
  • email — Адрес электронной почты отправителя.
  • name — Имя отправителя, отображаемое в подписях к сообщениям.
  • login — Имя учетной записи пользователя на ресурсе.
  • realname — ФИО пользователя взятые, например, из его регистрационных данных.
  • subject-plain — Тема поста в формате text/plain.
  • subject-html — Тема поста в формате text/html.
  • subject-bbcode — Тема поста в формате BBCode.
  • body-plain — Содержимое (тело) комментария или поста в формате text/plain.
  • body-html — Содержимое (тело) комментария или поста в формате text/html.
  • body-bbcode — Содержимое (тело) комментария или поста в формате BBCode.

Набор отправляемых на проверку данных может быть произвольным, за исключением того, что из семейства параметров body и subject может быть указан лишь один тип — или plain, или html, или bbcode. Обязательных параметров также нет. Поэтому передавать все эти данные нашему методу мы будем не идущими последовательно параметрами, а одним массивом с произвольным набором данных.

  1.         /* Проверка на спам */
  2.  
  3.         public function is_spam($message_data, $return_full_data = false)
  4.          {
  5.                 if (!isset($message_data['ip'])) $ip = $_SERVER['REMOTE_ADDR'];
  6.  
  7.                 $response = self::xml_query(self::check_data_url, $message_data, true);
  8.                 $spam_detected = (isset($response->text['spam-flag']) && $response->text['spam-flag'] == 'yes');
  9.  
  10.                 if (!$return_full_data) return $spam_detected;
  11.  
  12.                 return array(
  13.                                         'detected'     =>  $spam_detected,
  14.                                         'request_id'    => (isset($response->id))? $response->id : null,
  15.                                         'spam_links'    => (isset($response->links))? $response->links : array()
  16.                  );
  17.          }

Данный метод позволит нам отправлять данные на проверку с автоматической подстановкой IP-адреса пользователя. В зависимости от второго параметра, функция может возвращать либо просто true или false, либо массив с подробной информацией, содержащий список ссылок, заподозренных как спамерские, а также сгенерированный Яндексом id запроса. Он нам, кстати, далее пригодится.

Получение CAPTCHA

Яндекс предлагает нам воспользоваться его собственной «капчей» и надо сказать, что у этого решения есть очевидные плюсы — во-первых, снижается нагрузка на наш сервер, а во-вторых, забота о «взломоустойчивости» CAPTCHA ложится на плечи «Яндекса». Метод будет предельно простым:

  1.         /* Получение CAPTCHA */
  2.  
  3.         public function get_captcha($id = null)
  4.          {
  5.                 $response = self::xml_query(self::get_captcha_url, array('id' => $id));
  6.  
  7.                 if (!$response || !isset($response->captcha)) return false;
  8.  
  9.                 return array('captcha_id' => $response->captcha, 'captcha_url' => $response->url);
  10.          }

Как видно из предпоследней строки, метод возвращает ID «капчи» и ссылку на само изображение.
Ссылка, как правило, имеет следующий вид:
u.captcha.yandex.net/image?key=ID_CAPTCHA

Лучше использовать оба выдаваемых параметра, чтобы защита не сломалась, если Яндекс что-нибудь изменит в формате ссылки.

Проверка CAPTCHA

Наконец, третий метод класса будет использоваться для проверки введённого пользователем значения CAPTCHA.
Чтобы им воспользоваться, нам надо будет передать ему id «капчи», выданный предыдущим методом, а также то, что ввёл пользователь. Не лишним будет также передать и id запроса, который мы получили, когда отправляли сообщение на проверку, однако это необязательно.

  1.         /* Проверка CAPTCHA */
  2.  
  3.         public function check_captcha($captcha_id, $captcha_value, $id = null)
  4.          {
  5.                 $parameters = array(
  6.                                                         'captcha'               => $captcha_id,
  7.                                                         'value'            => $captcha_value,
  8.                                                         'id'                    => $id
  9.                  );
  10.  
  11.                 $response = self::xml_query(self::check_captcha_url, $parameters);
  12.  
  13.                 return isset($response->ok);
  14.          }

Примеры использования

Для полноценной проверки системы «Чистого Веба» можно загрузить простой демонстрационный скрипт. Перед проверкой не забудьте получить свой ключ API «Чистого Веба» и указать его в скрипте!
Можно также скачать класс отдельно или посмотреть его полный код в браузере.

Проверка содержимого формы:

  1. // Вызываем класс и задаём свой ключ API
  2.  
  3. require('YandexCW.class.php');
  4. YandexCW::$api_key = '12345';
  5.  
  6. // Отправляем данные формы на проверку
  7.  
  8. $post_data = array(
  9.  
  10.         'email'         => (isset($_POST['email']))? $_POST['email'] : null,
  11.         'name'          => (isset($_POST['name']))? $_POST['name'] : null,
  12.         'login'         => (isset($_POST['login']))? $_POST['login'] : null,
  13.         'realname'      => (isset($_POST['realname']))? $_POST['realname'] : null,
  14.         'subject-plain' => (isset($_POST['subject']))? $_POST['subject'] : null,
  15.         'body-plain'    => (isset($_POST['body']))? $_POST['body'] : null
  16.  
  17.  );
  18.  
  19. $is_spam = YandexCW::is_spam($post_data, true);
  20.  
  21. // Выводим итоги проверки
  22.  
  23. var_dump($is_spam);
  24.  

Особенности

Большинство параметров при вызове методов API являются необязательными.
Например, можно не использовать проверку на спам, а просто подключить себе CAPTCHA «Яндекса», аналогично тому, как подключают ReCAPTCHA.
Подробнее — на api.yandex.ru.

Автор: empr

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js