Skip to content
This repository was archived by the owner on Jun 10, 2024. It is now read-only.

Commit 5d34f60

Browse files
committed
Merge branch 'develop' into release/v3
* develop: Google reCAPTCHA v3 full support skipByIp function optimization htmlScriptTagJsApi function: Google reCAPTCHA v3 full support/compatibility tests ReCaptchaBuilderInvisible fixed/optimized ReCaptchaBuilderInvisible optimized helpers optimization tests improved recaptcha.php config file comments ReCaptchaV3Test code cleaning routes.php removed double ";" Test improved and Test V3 added ReCaptchaBuilder improved ReCaptchaServiceProvider: - custom route added - registerReCaptchaBuilder method enhanced htmlScriptTagJsApiV3 helper added biscolab-recaptcha/validate custom route added recaptcha config file: - default_validation_route added (from env: RECAPTCHA_DEFAULT_VALIDATION_ROUTE) - default_token_parameter_name added (from env: RECAPTCHA_DEFAULT_TOKEN_PARAMETER_NAME) ReCaptchaBuilderV3 created, ReCaptchaBuilderInvisible and ReCaptchaBuilderV2 __constructor method changed Update README.md Moved API keys variables to .env file Edited README
2 parents 88c2315 + 327dfa1 commit 5d34f60

11 files changed

+350
-31
lines changed

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Simple Google reCAPTCHA package for Laravel 5
66
## System requirements
77
PHP 7.1 or greater
88

9-
Are you still using PHP 5.6? Please go to [V2](https://github.com/biscolab/laravel-recaptcha/tree/v2.0.4)
9+
Are you still using PHP 5.x or 7.0? Please go to [V2](https://github.com/biscolab/laravel-recaptcha/tree/v2.0.4)
1010

1111
## Installation
1212

@@ -36,11 +36,17 @@ php artisan vendor:publish --provider="Biscolab\ReCaptcha\ReCaptchaServiceProvid
3636
## Configuration
3737

3838
### Add your API Keys
39-
Open `config/recaptcha.php` configuration file and set `api_site_key`, `api_secret_key` and `version`:
39+
Open `.env` file and set `RECAPTCHA_SITE_KEY` and `RECAPTCHA_SECRET_KEY`:
40+
```php
41+
RECAPTCHA_SITE_KEY=YOUR_API_SITE_KEY
42+
RECAPTCHA_SECRET_KEY=YOUR_API_SECRET_KEY
43+
```
44+
45+
Open `config/recaptcha.php` configuration file and set `version`:
4046
```php
4147
return [
42-
'api_site_key' => 'YOUR_API_SITE_KEY',
43-
'api_secret_key' => 'YOUR_API_SECRET_KEY',
48+
'api_site_key' => env('RECAPTCHA_SITE_KEY', ''),
49+
'api_secret_key' => env('RECAPTCHA_SECRET_KEY', ''),
4450
'version' => 'v2' // supported: v2|invisible
4551
'skip_ip' => [] // array of IP addresses - String: dotted quad format e.g.: 127.0.0.1
4652
];

config/recaptcha.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,46 @@
1919
* get site key @ www.google.com/recaptcha/admin
2020
*
2121
*/
22-
'api_site_key' => '',
22+
'api_site_key' => env('RECAPTCHA_SITE_KEY', ''),
2323

2424
/**
2525
*
2626
* The secret key
2727
* get secret key @ www.google.com/recaptcha/admin
2828
*
2929
*/
30-
'api_secret_key' => '',
30+
'api_secret_key' => env('RECAPTCHA_SECRET_KEY', ''),
3131

3232
/**
3333
*
3434
* ReCATCHA version
35-
* Supported: "v2", "invisible",
35+
* Supported: "v2", "invisible", "v3",
3636
*
3737
* get more info @ https://developers.google.com/recaptcha/docs/versions
3838
*
3939
*/
40-
'version' => 'v2',
40+
'version' => env('RECAPTCHA_DEFAULT_VERSION', 'v2'),
4141

4242
/**
4343
*
4444
* IP addresses for which validation will be skipped
4545
*
4646
*/
47-
'skip_ip' => []
47+
'skip_ip' => [],
48+
49+
/**
50+
*
51+
* Default route called to check the Google reCAPTCHA token
52+
* @since v3.2.0
53+
*
54+
*/
55+
'default_validation_route' => env('RECAPTCHA_DEFAULT_VALIDATION_ROUTE', 'biscolab-recaptcha/validate'),
56+
57+
/**
58+
*
59+
* The name of the parameter used to send Google reCAPTCHA token to verify route
60+
* @since v3.2.0
61+
*
62+
*/
63+
'default_token_parameter_name' => env('RECAPTCHA_DEFAULT_TOKEN_PARAMETER_NAME', 'token')
4864
];

src/ReCaptchaBuilder.php

Lines changed: 123 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,40 +48,98 @@ class ReCaptchaBuilder {
4848

4949
public function __construct($api_site_key, $api_secret_key, $version = 'v2') {
5050

51+
$this->setApiSiteKey($api_site_key);
52+
$this->setApiSecretKey($api_secret_key);
53+
$this->setVersion($version);
54+
$this->setSkipByIp($this->skipByIp());
55+
}
56+
57+
/**
58+
* @param string $api_site_key
59+
*
60+
* @return ReCaptchaBuilder
61+
*/
62+
public function setApiSiteKey(string $api_site_key): ReCaptchaBuilder{
5163
$this->api_site_key = $api_site_key;
64+
65+
return $this;
66+
}
67+
68+
/**
69+
* @param string $api_secret_key
70+
*
71+
* @return ReCaptchaBuilder
72+
*/
73+
public function setApiSecretKey(string $api_secret_key): ReCaptchaBuilder{
5274
$this->api_secret_key = $api_secret_key;
75+
76+
return $this;
77+
}
78+
79+
/**
80+
* @param string $version
81+
*
82+
* @return ReCaptchaBuilder
83+
*/
84+
public function setVersion(string $version): ReCaptchaBuilder{
5385
$this->version = $version;
54-
$this->skip_by_ip = self::skipByIp();
86+
87+
return $this;
88+
}
89+
90+
/**
91+
* @return string
92+
*/
93+
public function getVersion(): string {
94+
return $this->version;
95+
}
96+
97+
/**
98+
* @param bool $skip_by_ip
99+
*
100+
* @return ReCaptchaBuilder
101+
*/
102+
public function setSkipByIp(bool $skip_by_ip): ReCaptchaBuilder {
103+
$this->skip_by_ip = $skip_by_ip;
104+
105+
return $this;
55106
}
56107

57108
/**
58109
* Checks whether the user IP address is among IPs "to be skipped"
59110
*
60111
* @return boolean
61112
*/
62-
public static function skipByIp() {
63-
64-
$skip_ip = (config('recaptcha.skip_ip')) ? config('recaptcha.skip_ip') : [];
113+
public function skipByIp(): bool {
65114

66-
return (in_array(request()->ip(), $skip_ip));
115+
return (in_array(request()->ip(), config('recaptcha.skip_ip', [])));
67116
}
68117

69118
/**
70119
* Write script HTML tag in you HTML code
71120
* Insert before </head> tag
72121
*
73-
* @param string $formId
122+
* @param string|null $formId
123+
* @param array|null $configuration
74124
*
75125
* @return string
76126
* @throws Exception
77127
*/
78-
public function htmlScriptTagJsApi($formId = '') {
128+
public function htmlScriptTagJsApi(?string $formId = '', ?array $configuration = []): string {
79129

80130
if ($this->skip_by_ip) {
81131
return '';
82132
}
83-
$html = "<script src='https://www.google.com/recaptcha/api.js' async defer></script>";
84-
if ($this->version != 'v2') {
133+
134+
switch ($this->version) {
135+
case 'v3':
136+
$html = "<script src=\"https://www.google.com/recaptcha/api.js?render={$this->api_site_key}\"></script>";
137+
break;
138+
default:
139+
$html = "<script src=\"https://www.google.com/recaptcha/api.js\" async defer></script>";
140+
}
141+
142+
if ($this->version == 'invisible') {
85143
if (!$formId) {
86144
throw new Exception("formId required", 1);
87145
}
@@ -91,10 +149,62 @@ function biscolabLaravelReCaptcha(token) {
91149
}
92150
</script>';
93151
}
152+
elseif ($this->version == 'v3') {
153+
154+
$action = array_get($configuration, 'action', 'homepage');
155+
156+
$js_custom_validation = array_get($configuration, 'custom_validation', '');
157+
158+
// Check if set custom_validation. That function will override default fetch validation function
159+
if($js_custom_validation) {
160+
161+
$validate_function = ($js_custom_validation) ? "{$js_custom_validation}(token);" : '';
162+
}
163+
else {
164+
165+
$js_then_callback = array_get($configuration, 'callback_then', '');
166+
$js_callback_catch = array_get($configuration, 'callback_catch', '');
167+
168+
$js_then_callback = ($js_then_callback) ? "{$js_then_callback}(response)" : '';
169+
$js_callback_catch = ($js_callback_catch) ? "{$js_callback_catch}(err)" : '';
170+
171+
$validate_function = "
172+
fetch('/" . config('recaptcha.default_validation_route', 'biscolab-recaptcha/validate') . "?" . config('recaptcha.default_token_parameter_name', 'token') . "=' + token, {
173+
headers: {
174+
\"X-Requested-With\": \"XMLHttpRequest\",
175+
\"X-CSRF-TOKEN\": csrfToken.content
176+
}
177+
})
178+
.then(function(response) {
179+
{$js_then_callback}
180+
})
181+
.catch(function(err) {
182+
{$js_callback_catch}
183+
});";
184+
}
185+
186+
$html .= "<script>
187+
var csrfToken = document.head.querySelector('meta[name=\"csrf-token\"]');
188+
grecaptcha.ready(function() {
189+
grecaptcha.execute('{$this->api_site_key}', {action: '{$action}'}).then(function(token) {
190+
{$validate_function}
191+
});
192+
});
193+
</script>";
194+
}
94195

95196
return $html;
96197
}
97198

199+
/**
200+
* @param array|null $configuration
201+
*
202+
* @return string
203+
*/
204+
public function htmlScriptTagJsApiV3(?array $configuration = []): string {
205+
return $this->htmlScriptTagJsApi('', $configuration);
206+
}
207+
98208
/**
99209
* Call out to reCAPTCHA and process the response
100210
*
@@ -131,6 +241,10 @@ public function validate($response) {
131241
}
132242
$response = json_decode(trim($curl_response), true);
133243

244+
if($this->version == 'v3') {
245+
return $response;
246+
}
247+
134248
return $response['success'];
135249

136250
}

src/ReCaptchaBuilderInvisible.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@
1616
*/
1717
class ReCaptchaBuilderInvisible extends ReCaptchaBuilder {
1818

19+
/**
20+
* ReCaptchaBuilderInvisible constructor.
21+
*
22+
* @param string $api_site_key
23+
* @param string $api_secret_key
24+
*/
25+
public function __construct(string $api_site_key, string $api_secret_key) {
26+
parent::__construct($api_site_key, $api_secret_key, 'invisible');
27+
}
28+
1929
/**
2030
* Write HTML <button> tag in your HTML code
2131
* Insert before </form> tag
@@ -24,7 +34,7 @@ class ReCaptchaBuilderInvisible extends ReCaptchaBuilder {
2434
*
2535
* @return string
2636
*/
27-
public function htmlFormButton($buttonInnerHTML = 'Submit') {
37+
public function htmlFormButton($buttonInnerHTML = 'Submit'): string {
2838

2939
return ($this->version == 'invisible') ? '<button class="g-recaptcha" data-sitekey="' . $this->api_site_key . '" data-callback="biscolabLaravelReCaptcha">' . $buttonInnerHTML . '</button>' : '';
3040
}

src/ReCaptchaBuilderV2.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,22 @@
1616
*/
1717
class ReCaptchaBuilderV2 extends ReCaptchaBuilder {
1818

19+
/**
20+
* ReCaptchaBuilderV2 constructor.
21+
*
22+
* @param string $api_site_key
23+
* @param string $api_secret_key
24+
*/
25+
public function __construct(string $api_site_key, string $api_secret_key) {
26+
parent::__construct($api_site_key, $api_secret_key, 'v2');
27+
}
28+
1929
/**
2030
* Write ReCAPTCHA HTML tag in your FORM
2131
* Insert before </form> tag
2232
* @return string
2333
*/
24-
public function htmlFormSnippet() {
34+
public function htmlFormSnippet(): string {
2535

2636
return ($this->version == 'v2') ? '<div class="g-recaptcha" data-sitekey="' . $this->api_site_key . '"></div>' : '';
2737
}

src/ReCaptchaBuilderV3.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
/**
3+
* Copyright (c) 2017 - present
4+
* LaravelGoogleRecaptcha - ReCaptchaBuilderV3.php
5+
* author: Roberto Belotti - [email protected]
6+
* web : robertobelotti.com, github.com/biscolab
7+
* Initial version created on: 22/1/2019
8+
* MIT license: https://github.com/biscolab/laravel-recaptcha/blob/master/LICENSE
9+
*/
10+
11+
namespace Biscolab\ReCaptcha;
12+
13+
/**
14+
* Class ReCaptchaBuilderV3
15+
* @package Biscolab\ReCaptcha
16+
*/
17+
class ReCaptchaBuilderV3 extends ReCaptchaBuilder {
18+
19+
/**
20+
* ReCaptchaBuilderV3 constructor.
21+
*
22+
* @param string $api_site_key
23+
* @param string $api_secret_key
24+
*/
25+
public function __construct(string $api_site_key, string $api_secret_key) {
26+
parent::__construct($api_site_key, $api_secret_key, 'v3');
27+
}
28+
29+
}

src/ReCaptchaServiceProvider.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@ class ReCaptchaServiceProvider extends ServiceProvider {
3232
public function boot() {
3333

3434
$this->addValidationRule();
35+
$this->loadRoutesFrom(__DIR__ . '/routes/routes.php');
36+
3537
$this->publishes([
3638
__DIR__ . '/../config/recaptcha.php' => config_path('recaptcha.php'),
3739
]);
40+
3841
}
3942

4043
/**
@@ -71,11 +74,22 @@ protected function registerReCaptchaBuilder() {
7174

7275
$this->app->singleton('recaptcha', function ($app) {
7376

74-
if (config('recaptcha.version') == 'v2') {
75-
return new ReCaptchaBuilderV2(config('recaptcha.api_site_key'), config('recaptcha.api_secret_key'), config('recaptcha.version'));
76-
} else {
77-
return new ReCaptchaBuilderInvisible(config('recaptcha.api_site_key'), config('recaptcha.api_secret_key'), config('recaptcha.version'));
77+
$recaptcha_class = '';
78+
79+
switch (config('recaptcha.version')) {
80+
case 'v3' :
81+
$recaptcha_class = ReCaptchaBuilderV3::class;
82+
break;
83+
case 'v2' :
84+
$recaptcha_class = ReCaptchaBuilderV2::class;
85+
break;
86+
case 'invisible':
87+
$recaptcha_class = ReCaptchaBuilderInvisible::class;
88+
break;
7889
}
90+
91+
return new $recaptcha_class(config('recaptcha.api_site_key'), config('recaptcha.api_secret_key'));
92+
7993
});
8094
}
8195

0 commit comments

Comments
 (0)