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

Commit 1b3c8ca

Browse files
authored
Merge pull request #245 from pulzarraider/cache_response
Enable caching recaptcha verify response in array cache
2 parents 21fea6d + cfd42a4 commit 1b3c8ca

7 files changed

Lines changed: 232 additions & 56 deletions

File tree

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"symfony/framework-bundle": "^2.8 || ^3.0 || ^4.0 || ^5.0",
2222
"symfony/security-bundle": "^2.8 || ^3.0 || ^4.0 || ^5.0",
2323
"symfony/validator": "^2.8 || ^3.0 || ^4.0 || ^5.0",
24+
"symfony/yaml": "^2.8 || ^3.0 || ^4.0 || ^5.0",
2425
"twig/twig": "^1.40 || ^2.9 || ^3.0"
2526
},
2627
"require-dev": {

src/DependencyInjection/EWZRecaptchaExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Symfony\Component\DependencyInjection\ContainerBuilder;
66
use Symfony\Component\Config\FileLocator;
7+
use Symfony\Component\DependencyInjection\Reference;
78
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
89
use Symfony\Component\DependencyInjection\Loader;
910

@@ -28,6 +29,11 @@ public function load(array $configs, ContainerBuilder $container)
2829
}
2930

3031
$this->registerWidget($container);
32+
33+
if (null !== $config['http_proxy']['host'] && null !== $config['http_proxy']['port']) {
34+
$recaptchaService = $container->findDefinition('ewz_recaptcha.recaptcha');
35+
$recaptchaService->replaceArgument(1, new Reference('ewz_recaptcha.extension.recaptcha.request_method.proxy_post'));
36+
}
3137
}
3238

3339
/**

src/Extension/ReCaptcha/RequestMethod/Post.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,37 @@ class Post implements RequestMethod
2525
private $timeout;
2626

2727
/**
28-
* Constructor
28+
* @var array
29+
*/
30+
private $cache;
31+
32+
/**
33+
* Constructor.
2934
*
30-
* @param string $recaptchaVerifyServer
35+
* @param string $recaptchaVerifyServer
36+
* @param int|null $timeout
3137
*/
3238
public function __construct($recaptchaVerifyServer, $timeout)
3339
{
3440
$this->recaptchaVerifyUrl = ($recaptchaVerifyServer ?: 'https://www.google.com').'/recaptcha/api/siteverify';
3541
$this->timeout = $timeout;
42+
$this->cache = [];
3643
}
3744

3845
/**
3946
* Submit the POST request with the specified parameters.
4047
*
4148
* @param RequestParameters $params Request parameters
49+
*
4250
* @return string Body of the reCAPTCHA response
4351
*/
4452
public function submit(RequestParameters $params)
4553
{
54+
$cacheKey = $params->toQueryString();
55+
if (isset($this->cache[$cacheKey])) {
56+
return $this->cache[$cacheKey];
57+
}
58+
4659
/**
4760
* PHP 5.6.0 changed the way you specify the peer name for SSL context options.
4861
* Using "CN_name" will still work, but it will raise deprecated errors.
@@ -63,6 +76,10 @@ public function submit(RequestParameters $params)
6376
$options['http']['timeout'] = $this->timeout;
6477
}
6578
$context = stream_context_create($options);
66-
return file_get_contents($this->recaptchaVerifyUrl, false, $context);
79+
$result = file_get_contents($this->recaptchaVerifyUrl, false, $context);
80+
81+
$this->cache[$cacheKey] = $result;
82+
83+
return $result;
6784
}
6885
}

src/Extension/ReCaptcha/RequestMethod/ProxyPost.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,45 @@ class ProxyPost implements RequestMethod
3131
*/
3232
private $timeout;
3333

34+
/**
35+
* @var array
36+
*/
37+
private $cache;
38+
3439
/**
3540
* Constructor
3641
*
37-
* @param array $httpProxy proxy data to connect to
38-
* @param string $recaptchaVerifyServer
42+
* @param array $httpProxy
43+
* @param string $recaptchaVerifyServer
44+
* @param int|null $timeout
3945
*/
4046
public function __construct(array $httpProxy, $recaptchaVerifyServer, $timeout)
4147
{
4248
$this->httpProxy = $httpProxy;
4349
$this->recaptchaVerifyUrl = ($recaptchaVerifyServer ?: 'https://www.google.com').'/recaptcha/api/siteverify';
4450
$this->timeout = $timeout;
51+
$this->cache = [];
4552
}
4653

4754
/**
4855
* Submit the POST request with the specified parameters.
4956
*
5057
* @param RequestParameters $params Request parameters
58+
*
5159
* @return string Body of the reCAPTCHA response
5260
*/
5361
public function submit(RequestParameters $params)
5462
{
63+
$cacheKey = $params->toQueryString();
64+
if (isset($this->cache[$cacheKey])) {
65+
return $this->cache[$cacheKey];
66+
}
67+
5568
/**
5669
* PHP 5.6.0 changed the way you specify the peer name for SSL context options.
5770
* Using "CN_name" will still work, but it will raise deprecated errors.
5871
*/
59-
$peer_key = version_compare(PHP_VERSION, '5.6.0', '<') ? 'CN_name' : 'peer_name';
72+
$peerKey = version_compare(PHP_VERSION, '5.6.0', '<') ? 'CN_name' : 'peer_name';
6073
$options = array(
6174
'http' => array(
6275
'header' => "Content-type: application/x-www-form-urlencoded\r\n".sprintf('Proxy-Authorization: Basic %s', base64_encode($this->httpProxy['auth'])),
@@ -65,7 +78,7 @@ public function submit(RequestParameters $params)
6578
// Force the peer to validate (not needed in 5.6.0+, but still works)
6679
'verify_peer' => true,
6780
// Force the peer validation to use www.google.com
68-
$peer_key => 'www.google.com',
81+
$peerKey => 'www.google.com',
6982

7083
'proxy' => sprintf('tcp://%s:%s', $this->httpProxy['host'], $this->httpProxy['port']),
7184
// While this is a non-standard request format, some proxy servers require it.
@@ -76,6 +89,11 @@ public function submit(RequestParameters $params)
7689
$options['http']['timeout'] = $this->timeout;
7790
}
7891
$context = stream_context_create($options);
79-
return file_get_contents($this->recaptchaVerifyUrl, false, $context);
92+
93+
$result = file_get_contents($this->recaptchaVerifyUrl, false, $context);
94+
95+
$this->cache[$cacheKey] = $result;
96+
97+
return $result;
8098
}
8199
}

src/Resources/config/services.yml

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,32 @@ services:
2424
public: true
2525
arguments:
2626
- '%ewz_recaptcha.enabled%'
27-
- '%ewz_recaptcha.private_key%'
27+
- '@ewz_recaptcha.recaptcha'
2828
- '@request_stack'
29-
- '%ewz_recaptcha.http_proxy%'
3029
- '%ewz_recaptcha.verify_host%'
3130
- '@?security.authorization_checker'
3231
- '%ewz_recaptcha.trusted_roles%'
33-
- '%ewz_recaptcha.api_host%'
34-
- '%ewz_recaptcha.timeout%'
3532
tags:
3633
- { name: validator.constraint_validator, alias: 'ewz_recaptcha.true' }
34+
35+
ewz_recaptcha.recaptcha:
36+
class: ReCaptcha\ReCaptcha
37+
public: false
38+
arguments:
39+
- '%ewz_recaptcha.private_key%'
40+
- '@ewz_recaptcha.extension.recaptcha.request_method.post'
41+
42+
ewz_recaptcha.extension.recaptcha.request_method.post:
43+
class: EWZ\Bundle\RecaptchaBundle\Extension\ReCaptcha\RequestMethod\Post
44+
public: false
45+
arguments:
46+
- 'https://%ewz_recaptcha.api_host%'
47+
- '%ewz_recaptcha.timeout%'
48+
49+
ewz_recaptcha.extension.recaptcha.request_method.proxy_post:
50+
class: EWZ\Bundle\RecaptchaBundle\Extension\ReCaptcha\RequestMethod\ProxyPost
51+
public: false
52+
arguments:
53+
- '%ewz_recaptcha.http_proxy%'
54+
- 'https://%ewz_recaptcha.api_host%'
55+
- '%ewz_recaptcha.timeout%'

src/Validator/Constraints/IsTrueValidator.php

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ class IsTrueValidator extends ConstraintValidator
2121
protected $enabled;
2222

2323
/**
24-
* Recaptcha Private Key.
24+
* Recaptcha.
2525
*
26-
* @var string
26+
* @var ReCaptcha
2727
*/
28-
protected $privateKey;
28+
protected $recaptcha;
2929

3030
/**
3131
* Request Stack.
@@ -34,13 +34,6 @@ class IsTrueValidator extends ConstraintValidator
3434
*/
3535
protected $requestStack;
3636

37-
/**
38-
* HTTP Proxy informations.
39-
*
40-
* @var array
41-
*/
42-
protected $httpProxy;
43-
4437
/**
4538
* Enable serverside host check.
4639
*
@@ -62,51 +55,28 @@ class IsTrueValidator extends ConstraintValidator
6255
*/
6356
protected $trustedRoles;
6457

65-
/**
66-
* The reCAPTCHA verify server URL.
67-
*
68-
* @var string
69-
*/
70-
protected $recaptchaVerifyServer;
71-
72-
/**
73-
* The timeout for the reCAPTCHA verification.
74-
*
75-
* @var int|null
76-
*/
77-
private $timeout;
78-
7958
/**
8059
* @param bool $enabled
81-
* @param string $privateKey
60+
* @param ReCaptcha $recaptcha
8261
* @param RequestStack $requestStack
83-
* @param array $httpProxy
8462
* @param bool $verifyHost
8563
* @param AuthorizationCheckerInterface|null $authorizationChecker
8664
* @param array $trustedRoles
87-
* @param string $apiHost
88-
* @param int|null $timeout
8965
*/
9066
public function __construct(
9167
$enabled,
92-
$privateKey,
68+
ReCaptcha $recaptcha,
9369
RequestStack $requestStack,
94-
array $httpProxy,
9570
$verifyHost,
9671
AuthorizationCheckerInterface $authorizationChecker = null,
97-
array $trustedRoles = array(),
98-
$apiHost = 'www.google.com',
99-
$timeout = null)
72+
array $trustedRoles = array())
10073
{
10174
$this->enabled = $enabled;
102-
$this->privateKey = $privateKey;
75+
$this->recaptcha = $recaptcha;
10376
$this->requestStack = $requestStack;
104-
$this->httpProxy = $httpProxy;
10577
$this->verifyHost = $verifyHost;
10678
$this->authorizationChecker = $authorizationChecker;
10779
$this->trustedRoles = $trustedRoles;
108-
$this->recaptchaVerifyServer = 'https://'.$apiHost;
109-
$this->timeout = $timeout;
11080
}
11181

11282
/**
@@ -132,13 +102,7 @@ public function validate($value, Constraint $constraint)
132102
$answer = $masterRequest->get('g-recaptcha-response');
133103

134104
// Verify user response with Google
135-
if (null !== $this->httpProxy['host'] && null !== $this->httpProxy['port']) {
136-
$requestMethod = new ProxyPost($this->httpProxy, $this->recaptchaVerifyServer, $this->timeout);
137-
} else {
138-
$requestMethod = new Post($this->recaptchaVerifyServer, $this->timeout);
139-
}
140-
$recaptcha = new ReCaptcha($this->privateKey, $requestMethod);
141-
$response = $recaptcha->verify($answer, $remoteip);
105+
$response = $this->recaptcha->verify($answer, $remoteip);
142106

143107
if (!$response->isSuccess()) {
144108
$this->context->addViolation($constraint->message);

0 commit comments

Comments
 (0)