vvb / yandex-smart-captcha
Yandex Smart Captcha integration for Laravel 10/11/12/13
Requires
- php: ^8.1
- laravel/framework: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.0
README
Пакет для интеграции Yandex Cloud Smart Captcha в Laravel приложения. Поддерживает Blade-компоненты, Vue 3 компонент, JS-хелпер для API-only проектов, валидацию через Rule, Facade и переводы.
Установка
composer require vvb/yandex-smart-captcha
Миграция с v0.x
Breaking Changes
- Конфиг: добавлены новые ключи (
script_url,validate_url,language,theme,test,http_timeout,enabled,validate_host). После обновления выполните:php artisan vendor:publish --tag=config --force
- Имя скрытого поля токена: теперь всегда
smart-token(ранее было настраиваемое) - Новые пропсы Blade-компонента:
container,formId,lang,theme,test,invisible,shieldPosition,hideShield,enabled - Конструктор Service: теперь принимает массив конфига вместо двух строк
- Синглтон привязан к строке
'yandex-smart-captcha'(исправлен баг с Facade/Rule)
Что продолжает работать без изменений
- Facade
YandexSmartCaptcha::verify() - Rule
new YandexSmartCaptchaRule() - Синглтон
app('yandex-smart-captcha')
What's New in v1.0
- Invisible-режим (execute/executePromise)
- Vue 3 компонент с v-model и lazy load
- JS-хелпер (ES-модуль) для SPA/API-only
- Опциональная валидация хоста (
validate_host) - Переводы сообщений валидации (ru/en)
- Тестовый режим (
test)
Настройка
- Получите ключи в Yandex Cloud Console
- Добавьте в
.env:
YANDEX_SMART_CAPTCHA_CLIENT_KEY=your_client_key YANDEX_SMART_CAPTCHA_SERVER_KEY=your_server_key # Опционально: YANDEX_SMART_CAPTCHA_SCRIPT_URL=https://smartcaptcha.cloud.yandex.ru/captcha.js YANDEX_SMART_CAPTCHA_VALIDATE_URL=https://smartcaptcha.cloud.yandex.ru/validate YANDEX_SMART_CAPTCHA_LANGUAGE=ru YANDEX_SMART_CAPTCHA_THEME=auto YANDEX_SMART_CAPTCHA_TEST=false YANDEX_SMART_CAPTCHA_HTTP_TIMEOUT=30 YANDEX_SMART_CAPTCHA_ENABLED=true YANDEX_SMART_CAPTCHA_VALIDATE_HOST=false
- Опубликуйте конфиг (при обновлении — с флагом
--force):
php artisan vendor:publish --tag=config --provider="vvb\YandexSmartCaptcha\YandexSmartCaptchaServiceProvider"
Использование
Blade-компонент
<form method="POST"> @csrf {{-- Стандартный вид --}} <x-yandex-smart-captcha::smart-captcha /> {{-- С кастомным контейнером --}} <div id="my-captcha-container"></div> <x-yandex-smart-captcha::smart-captcha container="my-captcha-container" /> {{-- Invisible режим (требует JS вызов executeWidget) --}} <x-yandex-smart-captcha::smart-captcha invisible form-id="my-form" /> {{-- С переопределением языка/темы --}} <x-yandex-smart-captcha::smart-captcha lang="en" theme="dark" /> <button type="submit">Отправить</button> </form>
Пропсы компонента:
| Пропс | Тип | По умолчанию | Описание |
|---|---|---|---|
container |
string | null | auto (uniqid) |
formId |
string | null | null |
lang |
string | config('yandex-smart-captcha.language') |
Язык виджета (ru, en, uk, tr, lv) |
theme |
string | config('yandex-smart-captcha.theme') |
Тема: light, dark, auto |
test |
bool | config('yandex-smart-captcha.test') |
Тестовый режим Яндекса |
invisible |
bool | false |
Невидимый режим (требует ручной вызов executeWidget) |
shieldPosition |
string | null | null |
hideShield |
bool | false |
Скрыть уведомление об обработке данных |
enabled |
bool | config('yandex-smart-captcha.enabled') |
Отключает рендер капчи (возвращает пустой div) |
Важно: Виджет создаёт <input type="hidden" name="smart-token" value="..."> внутри контейнера. Используйте имя поля smart-token при валидации.
Валидация (PHP Rule)
use vvb\YandexSmartCaptcha\Rules\YandexSmartCaptchaRule; public function store(Request $request) { $request->validate([ 'smart-token' => [new YandexSmartCaptchaRule], ]); // Ваша логика }
Кастомные сообщения:
new YandexSmartCaptchaRule( message: 'Неверная капча!', emptyMessage: 'Пожалуйста, пройдите проверку' )
Или через языковые файлы (resources/lang/{locale}/validation.php):
return [ 'yandex_smart_captcha_rule' => 'Капча не пройдена', 'yandex_smart_captcha_empty' => 'Требуется подтверждение капчи', ];
PHP API (Facade / Service)
use vvb\YandexSmartCaptcha\Facades\YandexSmartCaptcha; // Проверка токена YandexSmartCaptcha::verify($token, $ip = null); // Получить client_key YandexSmartCaptcha::getClientKey(); // Получить публичный конфиг (без server_key) YandexSmartCaptcha::getConfig();
Или через сервис:
$service = app('yandex-smart-captcha'); $service->verify($token); $service->getClientKey(); $service->getConfig();
Invisible-режим (Blade + JS)
<x-yandex-smart-captcha::smart-captcha invisible form-id="my-form" />
// В вашем JS перед отправкой формы const formId = 'my-form'; const widgetId = window.__smartcaptchaContainers[formId]?.widgetId; if (widgetId) { const token = await window.smartCaptcha.executePromise(widgetId); // token содержит одноразовый токен // добавьте его в форму и отправьте }
Vue 3 компонент
Установка и регистрация:
// resources/js/app.js import YandexSmartCaptcha from 'vvb/yandex-smart-captcha/resources/js/vue/YandexSmartCaptcha.vue'; app.component('YandexSmartCaptcha', YandexSmartCaptcha);
Или локально в компоненте:
<script setup> import YandexSmartCaptcha from 'vvb/yandex-smart-captcha/resources/js/vue/YandexSmartCaptcha.vue'; </script>
Использование:
<template> <YandexSmartCaptcha v-model="captchaToken" :enabled="true" :invisible="false" :lang="lang" :theme="theme" @success="onCaptchaSuccess" @token-expired="onTokenExpired" ref="captchaRef" /> </template> <script setup> import { ref } from 'vue'; import YandexSmartCaptcha from 'vvb/yandex-smart-captcha/resources/js/vue/YandexSmartCaptcha.vue'; const captchaToken = ref(''); const captchaRef = ref(null); const lang = 'ru'; const theme = 'auto'; const onCaptchaSuccess = (token) => { console.log('Token received:', token); }; const onTokenExpired = () => { captchaRef.value.resetToken(); }; // При ошибке валидации (422) const handleFormSubmit = async () => { try { await submitForm(); } catch (e) { if (e.response?.status === 422) { captchaRef.value.resetToken(); // сброс виджета + обнуление v-model } } }; </script>
Пропсы Vue:
| Пропс | Тип | По умолчанию | Описание |
|---|---|---|---|
modelValue (v-model) |
string | '' |
Токен капчи |
container |
string | auto | ID контейнера или CSS-селектор |
lang |
string | VITE_SMARTCAPTCHA_LANG или ru |
Язык |
theme |
string | VITE_SMARTCAPTCHA_THEME или auto |
Тема |
test |
bool | VITE_SMARTCAPTCHA_TEST |
Тестовый режим |
invisible |
bool | false |
Невидимый режим |
shieldPosition |
string | null | null |
hideShield |
bool | false |
Скрыть уведомление об обработке данных |
enabled |
bool | true |
Включить/выключить капчу |
formId |
string | null | null |
scriptUrl |
string | null | VITE_SMARTCAPTCHA_SCRIPT_URL |
Эмиты:
update:modelValue(token) — новый токенsuccess(token) — успешное прохождениеtoken-expired— токен устарелnetwork-error— ошибка сетиjavascript-error(error) — JS ошибкаchallenge-visible/challenge-hidden— состояние челленджа
Expose-методы (через ref):
getResponse()— текущий токенreset()— сброс виджетаresetToken()— сброс виджета + обнуление v-modelexecute()— запуск invisible капчиexecutePromise()— Promise с токеном (invisible)
Переменные окружения (Vite):
VITE_SMARTCAPTCHA_KEY=your_client_key VITE_SMARTCAPTCHA_SCRIPT_URL=https://smartcaptcha.cloud.yandex.ru/captcha.js VITE_SMARTCAPTCHA_LANG=ru VITE_SMARTCAPTCHA_THEME=auto VITE_SMARTCAPTCHA_TEST=false
JS-хелпер (ES-модуль)
Для API-only проектов или ручного управления:
import { loadSmartCaptchaScript, destroySmartCaptcha, getResponse, resetWidget, executeWidget, executeWidgetPromise } from 'vvb/yandex-smart-captcha/resources/js/captcha.js'; // Загрузка скрипта (один раз на приложение) await loadSmartCaptchaScript({ scriptUrl: 'https://smartcaptcha.cloud.yandex.ru/captcha.js', }); // Рендер виджета вручную const widgetId = window.smartCaptcha.render(container, { sitekey: 'your_client_key', hl: 'ru', theme: 'auto', }); // Invisible const token = await executeWidgetPromise(widgetId); // Получение токена const token = getResponse(widgetId); // Сброс resetWidget(widgetId); // Очистка при unmount destroySmartCaptcha(widgetId, containerId);
Важно — токены
- Токен SmartCaptcha можно использовать только один раз. После отправки формы токен сгорает.
- При ошибке валидации (422) необходим новый токен:
- Vue: используйте
resetToken()черезdefineExpose - Blade: перезагрузка страницы
- Vue: используйте
- Время жизни токена — 5 минут. По истечении токен недействителен.
Конфигурация (config/yandex-smart-captcha.php)
return [ 'client_key' => env('YANDEX_SMART_CAPTCHA_CLIENT_KEY'), 'server_key' => env('YANDEX_SMART_CAPTCHA_SERVER_KEY'), 'script_url' => env('YANDEX_SMART_CAPTCHA_SCRIPT_URL', 'https://smartcaptcha.cloud.yandex.ru/captcha.js'), 'validate_url' => env('YANDEX_SMART_CAPTCHA_VALIDATE_URL', 'https://smartcaptcha.cloud.yandex.ru/validate'), 'language' => env('YANDEX_SMART_CAPTCHA_LANGUAGE', 'ru'), 'theme' => env('YANDEX_SMART_CAPTCHA_THEME', 'auto'), 'test' => env('YANDEX_SMART_CAPTCHA_TEST', false), 'http_timeout' => env('YANDEX_SMART_CAPTCHA_HTTP_TIMEOUT', 30), 'enabled' => env('YANDEX_SMART_CAPTCHA_ENABLED', true), 'validate_host' => env('YANDEX_SMART_CAPTCHA_VALIDATE_HOST', false), ];
Логирование
При ошибках API логируется на уровень ERROR:
- HTTP ошибки (не 200)
- Некорректный JSON ответ
- Ошибки соединения (таймаут, DNS, SSL)
При status: failed с непустым message — WARNING (диагностика неверного ключа/токена).
При validate_host=true и несовпадении хоста — WARNING.
При enabled=false — никаких HTTP запросов и логирования.
Тестирование
Установлены dev-зависимости: pestphp/pest, orchestra/testbench.
./vendor/bin/pest
Лицензия
MIT License.