Как решить reCAPTCHA v2 в PHP, включая 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 — это локальный сервис распознавания капчи, поэтому ничего не тарифицируется за каждое решение.
