Как решить reCAPTCHA v2 в PHP, включая Invisible

solve recaptcha v2 in php - How to Solve reCAPTCHA v2 in PHP, Including Invisible

У reCAPTCHA v2 три варианта, и в PHP это один метод с массивом опций. Checkbox — это вызов без параметров, Invisible и Enterprise — флаги, причём оба можно задать вместе. PHP — также единственный SDK CapSkip, в котором вовсе нет асинхронности, что упрощает код, но меняет то, как следует организовывать массовую обработку.

Настройка

# PHP 8.0 or newer. Needs the curl and json extensions,
# both of which ship with almost every PHP install.
composer require capskip/capskip

CapSkip решает капчи на вашей машине, поэтому десктопное приложение должно быть запущено. Направьте клиент на порт из его настроек:

use CapSkip\CapSkip;

$solver = new CapSkip([
    'apiKey' => 'capskip',        // any string when key validation is off
    'host' => '127.0.0.1',
    'port' => 8080,
    'recaptchaTimeout' => 300,    // seconds
]);

В продакшене считывайте их из окружения:

use CapSkip\CapSkip;

$solver = new CapSkip([
    'apiKey' => getenv('CAPSKIP_API_KEY') ?: 'capskip',
    'host' => getenv('CAPSKIP_HOST') ?: '127.0.0.1',
    'port' => (int) (getenv('CAPSKIP_PORT') ?: 8080),
]);

Три варианта

ВариантВозможность добавить
Checkboxнет
Invisible['invisible' => 1]
Enterprise['enterprise' => 1]
Невидимая Enterpriseоба ключа
// Checkbox: sitekey and page URL only.
$result = $solver->recaptcha(
    '6Lc...YOUR_SITEKEY',
    'https://example.com/login'
);

echo $result['code'];   // g-recaptcha-response token

// Invisible.
$result = $solver->recaptcha($sitekey, $pageUrl, ['invisible' => 1]);

// Enterprise, and both together.
$result = $solver->recaptcha($sitekey, $pageUrl, ['enterprise' => 1]);
$result = $solver->recaptcha($sitekey, $pageUrl, [
    'enterprise' => 1,
    'invisible' => 1,
]);

Возвращаемое значение — это ассоциативный массив, поэтому $result['code'] это токен. $result['captchaId'] тоже присутствует, если вы хотите записать, какое решение его произвело.

Как правильно задать входные данные

Sitekey — это data-sitekey атрибут на контейнере виджета или первый аргумент для grecaptcha.render когда режим Invisible означает, что нет контейнера, на который можно было бы взглянуть. Он всегда начинается с 6L и является публичным.

URL должен указывать на страницу, где отображается виджет. Передача обработчика вашей формы или редиректа после входа — обычная причина того, что токен успешно решается, а затем не проходит проверку.

Отправка токена

$ch = curl_init('https://example.com/login');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => http_build_query([
        'g-recaptcha-response' => $result['code'],
        'username' => '...',
        'password' => '...',
    ]),
]);

$response = curl_exec($ch);
curl_close($ch);

Токены одноразовые и действуют около двух минут, поэтому решайте как можно позже в процессе. Если сайт передаёт токен в JavaScript-callback, а не в поле формы, решение выполняется точно так же, но отправка отличается. Наше решатель callback для reCAPTCHA v2 странице рассмотрен этот формат.

Ошибки и пространство имён, которое упускают

PHP помещает свои исключения в отдельное пространство имён, что сбивает с толку всех, кто копирует импорты из примеров для Python или Node:

use CapSkip\CapSkip;
use CapSkip\Exceptions\ValidationException;
use CapSkip\Exceptions\NetworkException;
use CapSkip\Exceptions\ApiException;
use CapSkip\Exceptions\TimeoutException;

try {
    $result = $solver->recaptcha($sitekey, $pageUrl);
} catch (ValidationException $e) {
    // missing or malformed arguments
} catch (NetworkException $e) {
    // CapSkip is not running on the configured port
} catch (ApiException $e) {
    // the sitekey or pageurl was rejected
} catch (TimeoutException $e) {
    // exceeded recaptchaTimeout
}

Все четыре расширяют CapSkip\Exceptions\CapSkipError, так что один catch на базовом классе обрабатывает всё, если вы предпочитаете разбираться с ошибками в одном месте.

Решение нескольких

PHP выполняется синхронно, поэтому каждое решение блокирует выполнение, пока не завершится:

use CapSkip\CapSkip;

$solver = new CapSkip();

foreach ($targets as $target) {
    $results[] = $solver->recaptcha($target['sitekey'], $target['url']);
}

Пакет экспортирует AsyncCapSkip, но в PHP это лишь псевдоним, чтобы код, перенесённый из других SDK, продолжал работать. Он не добавляет параллелизма. Для настоящего параллелизма запускайте несколько рабочих процессов или используйте очередь, а не ждите, что SDK будет выполнять решения внахлёст.

Использование прокси

$result = $solver->recaptcha($sitekey, $pageUrl, [
    'proxy' => ['type' => 'HTTPS', 'uri' => 'user:[email protected]:3128'],
]);

Прокси поддерживаются для reCAPTCHA, Turnstile и GeeTest, но не для картиночных капч, которые решаются из байтов изображения и никогда не достигают целевого сайта.

Часто задаваемые вопросы

Нужно ли опрашивать результат?

Нет. SDK опрашивает внутренне и возвращает готовый токен, поэтому CAPCHA_NOT_READY никогда не доходит до вашего кода. Он начинает проверку через 250 мс и далее снижает частоту.

Заблокирует ли решение мой веб-запрос?

Да, и в PHP это важно. Решение reCAPTCHA может занять несколько секунд, поэтому его выполнение во время рендеринга страницы занимает воркер. Перенесите решение в задачу из очереди или CLI-воркер вместо блокировки потока запроса.

Каковы системные требования?

PHP 8.0 или новее с curl и json расширения, оба входят в большинство установок. Других зависимостей во время выполнения нет, поэтому он встраивается в существующий проект, не подтягивая дерево пакетов.

Сводка

Один метод, три варианта, выбираемые с помощью invisible и enterprise в массиве options. Читайте $result['code'], отправьте его как g-recaptcha-response, импортируйте исключения из CapSkip\Exceptions, и не занимайте решениями потоки ваших запросов.

Более широкий набор для PHP — Решатель капчи для PHP странице, другие языки на Решатель reCAPTCHA v2 страница, и есть живая демонстрация v2 для тестирования. CapSkip — это локальный сервис распознавания капчи, поэтому ничего не тарифицируется за каждое решение.