yiirocks / recaptcha
Google reCAPTCHA v2 and v3 field + server-side validator for Yii3.
Requires
- php: >=8.3
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0 || ^2.0
- yiisoft/form-model: ^1.1
- yiisoft/html: ^3.13 || ^4.0
- yiisoft/request-provider: ^1.3
- yiisoft/translator: ^3.0
- yiisoft/validator: ^2.5
- yiisoft/widget: ^2.2
Requires (Dev)
- friendsofphp/php-cs-fixer: @stable
- nyholm/psr7: @stable
- phpunit/phpunit: @stable
- psr/container: ^2.0
- vimeo/psalm: @stable
- yiisoft/translator-message-php: ^1.1
This package is auto-updated.
Last update: 2026-06-13 15:39:35 UTC
README
Google reCAPTCHA v2 and v3 field + server-side validator for Yii3.
Requirements
- PHP 8.3+
- PSR-18 HTTP client
- PSR-17 request + stream factories
Installation
composer require yiirocks/recaptcha
A PSR-18 client and PSR-17 factories are required. If your application already has them configured (e.g. via Guzzle, Symfony HTTP Client, or any other implementation), no further setup is needed.
If not, install any compatible library, for example:
composer require guzzlehttp/guzzle nyholm/psr7
Configuration
Set your site keys and secrets either via environment variables or directly in
your application's config/params.php:
Environment variables (recommended)
// config/params.php return [ 'yiirocks/recaptcha' => [ 'siteKeyV2' => $_ENV['RECAPTCHA_SITE_KEY_V2'] ?? '', 'secretV2' => $_ENV['RECAPTCHA_SECRET_V2'] ?? '', 'siteKeyV3' => $_ENV['RECAPTCHA_SITE_KEY_V3'] ?? '', 'secretV3' => $_ENV['RECAPTCHA_SECRET_V3'] ?? '', ], ];
If the env vars are not set the values fall back to empty strings — override
them in your config/params.php as needed (the config-plugin merges them).
All parameters
| Parameter | Default | Description |
|---|---|---|
siteKeyV2 |
'' (or $_ENV) |
reCAPTCHA v2 site key |
secretV2 |
'' (or $_ENV) |
reCAPTCHA v2 secret |
siteKeyV3 |
'' (or $_ENV) |
reCAPTCHA v3 site key |
secretV3 |
'' (or $_ENV) |
reCAPTCHA v3 secret |
verifyUrl |
https://www.google.com/recaptcha/api/siteverify |
Google verification endpoint |
sendRemoteIp |
false |
Send the user's IP to Google for abuse analysis |
translation.category |
yii3-recaptcha |
Translation category used by message sources |
Tip: Once your site keys are set, fields will pull them from the registry automatically — no need to call
withSiteKey()in your view code.
DI Configuration
The config-plugin (config-plugin in composer.json) wires everything
automatically:
RecaptchaClientreceivesRecaptchaConfigplus PSR services from the containerRecaptchaV2RuleHandlerandRecaptchaV3RuleHandlerare wired with optional client, request provider, and translator- The translation category source is registered with the
translation.categorySourcetag - The bootstrap callback populates
RecaptchaRegistrywith the client, request provider, and translator. This means fields and handlers work out of the box — no explicitwithSiteKey()needed.
Usage
All fields are rendered with a form model via the ::field() static method —
the standard Yii3 form field pattern. Validation errors are shown automatically.
reCAPTCHA v2
use Yiisoft\FormModel\FormModel; use YiiRocks\Recaptcha\RecaptchaV2Field; use YiiRocks\Recaptcha\RecaptchaV2Theme; use YiiRocks\Recaptcha\RecaptchaV2Size; use YiiRocks\Recaptcha\RecaptchaV2Type; echo RecaptchaV2Field::field($form, 'captcha') ->withTheme(RecaptchaV2Theme::Dark) ->withSize(RecaptchaV2Size::Compact) ->withType(RecaptchaV2Type::Audio) ->withId('my-captcha') ->withCallback('onSuccess') ->render();
Available options:
| Method | Default | Description |
|---|---|---|
withSiteKey(string) |
from config | Google reCAPTCHA v2 site key |
withId(string) |
'g-recaptcha-{uniqid}' |
Widget element ID |
withTheme(RecaptchaV2Theme) |
Light |
Light or Dark |
withType(RecaptchaV2Type) |
Image |
Image or Audio |
withSize(RecaptchaV2Size) |
Normal |
Normal, Compact, or Invisible |
withJsApiUrl(string) |
Google CDN | Custom JS API URL |
withCallback(string) |
— | JavaScript callback on success |
withExpiredCallback(string) |
— | JavaScript callback on expiry |
withErrorCallback(string) |
— | JavaScript callback on error |
reCAPTCHA v3
The reCAPTCHA token is fetched on form submit (not on page load), preventing unexpected challenge popups:
use Yiisoft\FormModel\FormModel; use YiiRocks\Recaptcha\RecaptchaV3Field; use YiiRocks\Recaptcha\RecaptchaV3Badge; echo RecaptchaV3Field::field($form, 'captcha') ->withAction('login') ->withFormId('login-form') ->withBadge(RecaptchaV3Badge::Hidden) ->render();
Available options:
| Method | Default | Description |
|---|---|---|
withSiteKey(string) |
from config | Google reCAPTCHA v3 site key |
withAction(string) |
'' |
Action name sent to Google (must match the rule's action if set) |
withFormId(string) |
— | Explicit form ID (auto-resolved via closest("form") if omitted) |
withBadge(RecaptchaV3Badge) |
BottomRight |
BottomRight, BottomLeft, or Hidden |
withJsApiUrl(string) |
Google CDN | Custom JS API URL |
withTranslator(?TranslatorInterface) |
from registry | Translator for the hidden badge legal notice |
withExecuteTimeout(?int) |
15000 (ms) |
Fallback form submission timeout (null = disabled) |
Inherited from InputField:
->name(string)— override the hidden input name (default: auto-derived from form model asFormName[attribute])->inputId(?string)— override the hidden input ID (default: auto-generated unique ID)
Container (inherited from BaseField):
->containerTag(string)— wrapper tag (default:div)->containerClass(string ...)— wrapper CSS class(es) (default:mb-3)->useContainer(bool)— enable/disable wrapper (default:true)->containerAttributes(array)— set all wrapper attributes->addContainerAttributes(array)— merge additional wrapper attributes
Hidden badge: When
Badge::Hiddenis selected, the legal notice text ("This site is protected by reCAPTCHA…") is displayed automatically and translated when a translator is available (either viawithTranslator()or throughRecaptchaRegistry).
Server-side validation
v2
use YiiRocks\Recaptcha\RecaptchaV2Rule; final class ContactForm { #[RecaptchaV2Rule] public string $gRecaptchaResponse = ''; }
v3
use YiiRocks\Recaptcha\RecaptchaV3Rule; final class LoginForm { #[RecaptchaV3Rule( threshold: 0.5, action: 'login', )] public string $gRecaptchaResponse = ''; }
Important: If you set
->withAction('...')on the field, you must also setaction: '...'on the rule with the same value. Otherwise Google will return a different action and validation will fail with "The CAPTCHA action does not match." If neither is set, no action is sent and the check is skipped entirely.
| v3 rule parameter | Default | Description |
|---|---|---|
threshold |
0.5 |
Minimum score (0.0 – 1.0) |
action |
null |
Expected action name (skipped if null) |
message |
'The CAPTCHA verification failed.' |
Error message (translatable) |
scoreTooLowMessage |
'The CAPTCHA score is too low.' |
Error when score is below threshold |
actionMismatchMessage |
'The CAPTCHA action does not match.' |
Error when action doesn't match |
secret |
null |
Custom secret (uses config default if null) |
sendRemoteIp |
false |
Whether to include the user's IP in verification |
License
MIT. See LICENSE.md.