Skip to content
This repository was archived by the owner on Feb 25, 2026. It is now read-only.

Commit 2e436ca

Browse files
authored
Merge pull request #256 from manuxi/master
Recaptcha v3 integration
2 parents 3f347b3 + 178495a commit 2e436ca

16 files changed

Lines changed: 824 additions & 107 deletions

README.md

100644100755
Lines changed: 224 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,63 +32,91 @@ $bundles = array(
3232

3333
### Step2: Configure the bundle's
3434

35+
> **NOTE**: The configuration options differ between Version 2 and Version 3 of the reCAPTCHA system. Some of the previous options have no effect on Version 3.
36+
3537
Add the following to your config file:
3638

37-
**NOTE**: If you're using symfony 4, the config will be in `config/packages/ewz_recaptcha.yaml`. The local dev enviroment has its own config in `config/packages/dev/ewz_recaptcha.yaml`.
39+
> **NOTE**: If you're using symfony 4, the config will be in `config/packages/ewz_recaptcha.yaml`. The local dev enviroment has its own config in `config/packages/dev/ewz_recaptcha.yaml`.
40+
41+
#### Main configuration for both v2 and v3
42+
43+
The version setting determines which configuration options are available. Set the version corresponding to your Google reCAPTCHA settings (valid values: 2 or 3):
3844

3945
``` yaml
4046
# app/config/config.yml
4147

4248
ewz_recaptcha:
43-
public_key: here_is_your_public_key
44-
private_key: here_is_your_private_key
45-
# Not needed as "%kernel.default_locale%" is the default value for the locale key
46-
locale_key: %kernel.default_locale%
49+
// ...
50+
version: 2
4751
```
4852
49-
**NOTE**: This Bundle lets the client browser choose the secure https or unsecure http API.
53+
You can easily disable reCAPTCHA (for example in a local or test environment):
5054
51-
If you want to use the language default for the reCAPTCHA the same as the
52-
request locale you must activate the resolver (deactivated by default):
55+
``` yaml
56+
# app/config/config.yml
57+
58+
ewz_recaptcha:
59+
// ...
60+
enabled: false
61+
```
62+
63+
Enter the public and private keys here:
5364
5465
``` yaml
5566
# app/config/config.yml
5667

5768
ewz_recaptcha:
5869
// ...
59-
locale_from_request: true
70+
public_key: here_is_your_public_key
71+
private_key: here_is_your_private_key
72+
6073
```
6174

62-
You can easily disable reCAPTCHA (for example in a local or test environment):
75+
`www.google.com` is blocked in Mainland China, you can override the default server like this (See https://developers.google.com/recaptcha/docs/faq#can-i-use-recaptcha-globally for further information):
6376

6477
``` yaml
6578
# app/config/config.yml
6679

6780
ewz_recaptcha:
6881
// ...
69-
enabled: false
82+
api_host: recaptcha.net
7083
```
7184
72-
Or even load reCAPTCHA using Ajax:
85+
#### v2 only Configuration
86+
87+
Sets the default locale:
7388
7489
``` yaml
7590
# app/config/config.yml
7691

7792
ewz_recaptcha:
7893
// ...
79-
ajax: true
94+
# Not needed as "%kernel.default_locale%" is the default value for the locale key
95+
locale_key: %kernel.default_locale%
8096
```
8197
82-
`www.google.com` is blocked in Mainland China, you can override the default server like this:
98+
**NOTE**: This Bundle lets the client browser choose the secure https or unsecure http API.
99+
100+
If you want to use the language default for the reCAPTCHA the same as the
101+
request locale you must activate the resolver (deactivated by default):
83102
84103
``` yaml
85104
# app/config/config.yml
86105

87106
ewz_recaptcha:
88107
// ...
89-
api_host: recaptcha.net
108+
locale_from_request: true
90109
```
91110
111+
You can load the reCAPTCHA using Ajax:
112+
113+
``` yaml
114+
# app/config/config.yml
115+
116+
ewz_recaptcha:
117+
// ...
118+
ajax: true
119+
```
92120
You can add HTTP Proxy configuration:
93121
94122
``` yaml
@@ -101,7 +129,6 @@ ewz_recaptcha:
101129
port: 3128
102130
auth: proxy_username:proxy_password
103131
```
104-
105132
In case you have turned off the domain name checking on reCAPTCHA's end, you'll need to check the origin of the response by enabling the ``verify_host`` option:
106133
107134
``` yaml
@@ -131,10 +158,36 @@ return static function (ContainerConfigurator $configurator): void
131158
};
132159
```
133160

161+
#### v3 only Configuration
162+
163+
For the v3 reCAPTCHA an information badge is shown. If you inform your users about using the reCAPTCHA on another way, you can hide it with the following option (see https://developers.google.com/recaptcha/docs/faq#hiding-badge for further information):
164+
165+
``` yaml
166+
# app/config/config.yml
167+
168+
ewz_recaptcha:
169+
// ...
170+
hide_badge: true
171+
```
172+
173+
To modify the default threshold score of 0.5 set this option (see https://developers.google.com/recaptcha/docs/v3#interpreting_the_score for further information):
174+
175+
``` yaml
176+
# app/config/config.yml
177+
178+
ewz_recaptcha:
179+
// ...
180+
score_threshold: 0.6
181+
```
182+
134183
Congratulations! You're ready!
135184
136185
## Basic Usage
137186
187+
> **NOTE**: The basic usage differs between Version 2 and Version 3 of the reCAPTCHA system.
188+
189+
### v2 Usage
190+
138191
When creating a new form class add the following line to create the field:
139192
140193
``` php
@@ -276,7 +329,6 @@ public function buildForm(FormBuilder $builder, array $options)
276329
// ...
277330
```
278331

279-
280332
The form template resource is now auto registered via an extension of the container.
281333
However, you can always implement your own custom form widget.
282334

@@ -372,3 +424,158 @@ If you want to use a custom theme, put your chunk of code before setting the the
372424
},
373425
} }) }}
374426
```
427+
428+
### v3 Usage
429+
430+
When creating a new form class add the following line to create the field:
431+
432+
``` php
433+
<?php
434+
435+
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaV3Type;
436+
437+
public function buildForm(FormBuilder $builder, array $options)
438+
{
439+
// ...
440+
$builder->add('recaptcha', EWZRecaptchaV3Type::class);
441+
// ...
442+
}
443+
```
444+
445+
You can pass the action to reCAPTCHA with the "action_name" option (see https://developers.google.com/recaptcha/docs/v3#actions for further information)::
446+
447+
``` php
448+
<?php
449+
450+
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaType;
451+
452+
public function buildForm(FormBuilder $builder, array $options)
453+
{
454+
// ...
455+
$builder->add('recaptcha', EWZRecaptchaType::class, array(
456+
'action_name' => 'contact'
457+
));
458+
// ...
459+
}
460+
```
461+
462+
To validate the field use:
463+
464+
``` php
465+
<?php
466+
467+
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints as Recaptcha;
468+
469+
/**
470+
* @Recaptcha\IsTrueV3
471+
*/
472+
public $recaptcha;
473+
```
474+
475+
Another method would consist to pass the validation constraints as an options of your FormType. This way, your data class contains only meaningful properties.
476+
If we take the example from above, the buildForm method would look like this. You have to also set ```constraints```:
477+
478+
``` php
479+
<?php
480+
481+
use EWZ\Bundle\RecaptchaBundle\Form\Type\EWZRecaptchaV3Type;
482+
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\IsTrueV3;
483+
484+
public function buildForm(FormBuilder $builder, array $options)
485+
{
486+
// ...
487+
$builder->add('recaptcha', EWZRecaptchaV3Type::class, array(
488+
'action_name' => 'contact',
489+
'constraints' => array(
490+
new IsTrueV3()
491+
)
492+
));
493+
// ...
494+
```
495+
496+
## Advanced Usage
497+
498+
It is possible to register reCAPTCHA form services. To accomplish this, enter the service definition as follows (in this example we did it in PHP):
499+
500+
``` php
501+
<?php
502+
503+
$ewzRecaptchaConfiguration = array();
504+
$ewzRecaptchaConfiguration['enabled'] = isset($_ENV['RECAPTCHA_PUBLIC'], $_ENV['RECAPTCHA_PRIVATE']);
505+
$ewzRecaptchaConfiguration['public_key'] = $_ENV['RECAPTCHA_PUBLIC'] ?? null;
506+
$ewzRecaptchaConfiguration['private_key'] = $_ENV['RECAPTCHA_PRIVATE'] ?? null;
507+
$ewzRecaptchaConfiguration['api_host'] = 'recaptcha.net';
508+
$ewzRecaptchaConfiguration['version'] = 3;
509+
510+
$ewzRecaptchaConfiguration['service_definition'] = array();
511+
$ewzRecaptchaConfiguration['service_definition'][] = [
512+
'service_name' => 'ContactRecaptchaService',
513+
'options' => [
514+
'action_name' => 'form'
515+
]
516+
];
517+
518+
// Add more form services here
519+
520+
// ...
521+
$container->loadFromExtension('ewz_recaptcha', $ewzRecaptchaConfiguration);
522+
// ...
523+
```
524+
525+
Now the services are now accessible with ```ewz_recaptcha.[service_name]```. They can be registered to your form type class:
526+
527+
``` php
528+
<?php
529+
530+
namespace MyNamespace\DependencyInjection;
531+
532+
use MyNamespace\Form\ContactType;
533+
use Symfony\Component\DependencyInjection\ContainerBuilder;
534+
use Symfony\Component\DependencyInjection\Reference;
535+
use Symfony\Component\DependencyInjection\Extension\Extension;
536+
537+
class ContactFormExtension extends Extension
538+
{
539+
540+
public function load(array $configs, ContainerBuilder $container)
541+
{
542+
$container->register(ContactType::class)
543+
->addArgument(new Reference('ewz_recaptcha.ContactRecaptchaService'))
544+
->addTag('form.type');
545+
}
546+
}
547+
// ...
548+
```
549+
550+
The form type class itself uses the injected service this way:
551+
552+
``` php
553+
<?php
554+
555+
namespace MyNamespace\Form;
556+
557+
use Symfony\Component\Form\AbstractType;
558+
use Symfony\Component\Form\FormBuilderInterface;
559+
560+
class ContactType extends AbstractType
561+
{
562+
/**
563+
* @var FormBuilderInterface
564+
*/
565+
private $recaptcha;
566+
567+
public function __construct(?FormBuilderInterface $recaptcha)
568+
{
569+
$this->recaptcha = $recaptcha;
570+
}
571+
572+
public function buildForm(FormBuilderInterface $builder, array $options)
573+
{
574+
// ...
575+
if(null !== $this->recaptcha) {
576+
$builder->add($this->recaptcha);
577+
}
578+
// ...
579+
}
580+
581+
```

src/DependencyInjection/Configuration.php

100644100755
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,18 @@ public function getConfigTreeBuilder()
3535
->scalarNode('locale_key')->defaultValue('%kernel.default_locale%')->end()
3636
->scalarNode('api_host')->defaultValue('www.google.com')->end()
3737
->booleanNode('locale_from_request')->defaultFalse()->end()
38+
39+
->integerNode('version')->min(2)->max(3)->defaultValue(2)->end()
40+
->booleanNode('hide_badge')->defaultValue(false)->end()
41+
->floatNode('score_threshold')->min(0.0)->max(1.0)->defaultValue(0.5)->end()
42+
3843
->integerNode('timeout')->min(0)->defaultNull()->end()
3944
->arrayNode('trusted_roles')->prototype('scalar')->treatNullLike(array())->end()
4045
->end()
4146
;
4247

4348
$this->addHttpClientConfiguration($rootNode);
49+
$this->addServiceDefinitionConfiguration($rootNode);
4450

4551
return $treeBuilder;
4652
}
@@ -60,4 +66,24 @@ private function addHttpClientConfiguration(ArrayNodeDefinition $node)
6066
->end()
6167
;
6268
}
69+
70+
private function addServiceDefinitionConfiguration(ArrayNodeDefinition $node) {
71+
$node
72+
->children()
73+
->arrayNode('service_definition')
74+
->prototype('array')
75+
->children()
76+
->scalarNode('service_name')->isRequired()->end()
77+
->arrayNode('options')
78+
->children()
79+
->scalarNode('action_name')->end()
80+
->scalarNode('script_nonce_csp')->end()
81+
->end()
82+
->end()
83+
->end()
84+
->end()
85+
->end()
86+
->end()
87+
;
88+
}
6389
}

0 commit comments

Comments
 (0)