Как добавить ReCAPTCHA на свой сайт

Недавно  столкнулся с тем, что боты поумнели настолько, что начали обходить обычную CAPTCHA на одном из сайтов, поддержкой которых я занимаюсь. Пришлось искать альтернативные решения, и выбор пал на reCAPTCHA от Google. Как выяснилось, подключить ее достаточно просто. Нужно зарегистрировать свой сайт на странице ReCAPTCHA (нужно иметь учетную запись в Google) и получить пару ключей: публичный (он будет размещаться на сайте) и секретный, который будет храниться только на сервере.
Дальше в форму, для которой нужна проверка CAPTCHA вставляем код такого вида:
<script src='https://www.google.com/recaptcha/api.js'></script>
<div class="g-recaptcha" data-sitekey="ваш-публичный-ключ"></div>
Google рекомендует вставлять тег script после head, однако на самом деле это не обязательно, и можно вставить его и прямо в форму или вообще в конец страницы перед </body>. Последний вариант, пожалуй, даже предпочтительнее, так как в этом случае код будет загружаться в самом конце загрузки страницы и не будет ее замедлять.
Если вы все сделаете правильно, то в том месте сайта, куда вы вставили код, появится такой блок:

В нем же будет скрытое поле g-recaptcha-response, которое будет отправлено на сервер вместе с данными формы. Для проверки корректности прохождения CAPTCHA нам нужно сделать POST-запрос на сервер Google.Запрос делается на адрес https://www.google.com/recaptcha/api/siteverify, в нем в параметре secret передается секретный ключ, полученный при регистрации, а в параметре response — код ответа из поля g-recaptcha-response. В ответ возвращается JSON-объект, в котором нужно проверить поле success.
На PHP со включенной опцией allow_url_fopen код проверки будет выглядеть выглядеть так:
$valid_captcha = false;
if (!empty($_POST['g-recaptcha-response'])) {
 $postdata = http_build_query(
    array(
       'secret' =>  'ваш-секретный-ключ',
       'response' => $_POST['g-recaptcha-response']
     )
   );

   $opts = array('http' =>
       array(
           'method'  => 'POST',
           'header'  => 'Content-type: application/x-www-form-urlencoded',
           'content' => $postdata
       )
   );

   $context  = stream_context_create($opts);
   $result = file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context);
   $valid_captcha = strpos($result,'"success": true')!==false;
}
if (!valid_captcha) {
// выводим сообщение об ошибке
}
else {
// выполняем запрошенное пользователем действие
}

Если опция allow_url_fopen на сервере выключена, можно воспользоваться моей библиотекой Requests, которая делает запрос через модуль curl. В этом случае код приобретает вид:
require_once('Requests.php');
$valid_captcha = false;
if (!empty($_POST['g-recaptcha-response'])) {
 $rq = new Requests();
 $result = $rq->post('https://www.google.com/recaptcha/api/siteverify',  array(
     'secret' =>  'ваш-секретный-ключ',
     'response' => $_POST['g-recaptcha-response']
  ));
 $valid_captcha = strpos($result,'"success": true')!==false;
}
if (!valid_captcha) {
// выводим сообщение об ошибке
}
else {
// выполняем запрошенное пользователем действие
}

Отмечу, что в коде применяется такой трюк: вместо полноценного парсинга JSON-объекта этот объект рассматривается как строка, в которой проверяется наличие подстроки "success": true. Делается это для двух целей: экономия ресурсов сервера (поиск подстроки в строке — значительно менее затратная операция, чем полноценный разбор JSON) и независимость от наличия на сервере модуля JSON. Это уместно в случае простых API, где полей в ответе мало, и известно, что они не будут меняться, однако в более сложных случаях лучше к таким трюкам не прибегать.

Если проанализировать плюсы и минусы этого решения, получаем следующее.
Преимущества:
  1. Простота добавления в любой проект
  2. Высокая надежность с точки зрения защиты от ботов (а кроме того, по мере роста интеллекта ботов Google может вводить дополнительные меры по защите, при этом они будут применяться сразу же, без каких-либо дополнительных мер с вашей стороны)
  3. Статистика по доле пользователей, прошедших CAPTCHA и некоторые возможности регулировки ее сложности.
Недостатки:
  1. Критическая зависимость от внешнего сервиса: если по каким-то причинам перестанет работать ReCAPTCHA (например, очередные «ковровые блокировки» Роскомнадзора или взлом Google-аккаунта, на котором были получены публичный и приватный ключи), то станут недоступными ключевые действия на сайте (такие как регистрация или оформление заказа).
  2. Если с одного адреса ходит много пользователей (а это типичная ситуация для мобильных 3G-сетей и провайдеров, подключающие пользователей через NAT), reCAPTCHA потребует от пользователя довольно большого количества действий по распознаванию картинок, что вызовет его раздражение.
В общем, я все же придерживаюсь мнения, что reCAPTCHA уместна там, где требуется простое и быстрое решение, но на серьезных проектах все же лучше делать свое собственное решение, взяв за основу, например, KCAPTCHA.