├── LICENSE
├── src
├── RecaptchaPlugin.php
├── View
│ └── Helper
│ │ └── RecaptchaHelper.php
└── Controller
│ └── Component
│ └── RecaptchaComponent.php
├── composer.json
├── templates
└── element
│ └── recaptcha.php
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 anhtuank7c
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/RecaptchaPlugin.php:
--------------------------------------------------------------------------------
1 | =8.1",
34 | "cakephp/cakephp": "^5.0"
35 | },
36 | "require-dev": {
37 | "phpunit/phpunit": "^10.5.5 || ^11.1.3",
38 | "cakephp/cakephp-codesniffer": "^4.1"
39 | },
40 | "autoload": {
41 | "psr-4": {
42 | "Recaptcha\\": "src"
43 | }
44 | },
45 | "autoload-dev": {
46 | "psr-4": {
47 | "Recaptcha\\Test\\": "tests"
48 | }
49 | },
50 | "config": {
51 | "allow-plugins": {
52 | "dealerdirect/phpcodesniffer-composer-installer": true
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/View/Helper/RecaptchaHelper.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | protected array $_defaultConfig = [
24 | // This is test only key
25 | 'sitekey' => '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI',
26 | 'theme' => 'light',
27 | 'type' => 'image',
28 | 'callback' => null,
29 | 'enable' => true,
30 | 'lang' => null,
31 | 'size' => 'normal',
32 | 'scriptBlock' => true,
33 | ];
34 |
35 | /**
36 | * Helpers
37 | *
38 | * @var array
39 | */
40 | protected array $helpers = ['Form'];
41 |
42 | /**
43 | * initialize
44 | *
45 | * @param array $config config
46 | * @return void
47 | */
48 | public function initialize(array $config = []): void
49 | {
50 | $config += Configure::read('Recaptcha', []);
51 | $this->setConfig($config);
52 |
53 | if (!$this->getConfig('lang')) {
54 | $this->setConfig('lang', Locale::getPrimaryLanguage(I18n::getLocale()));
55 | }
56 | }
57 |
58 | /**
59 | * Display recaptcha function
60 | *
61 | * @param array $config Config
62 | * @return string
63 | */
64 | public function display(array $config = []): string
65 | {
66 | $recaptcha = $config + $this->getConfig();
67 | if (!(bool)$recaptcha['enable']) {
68 | return '';
69 | }
70 |
71 | return $this->_View->element('Recaptcha.recaptcha', compact('recaptcha'));
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/templates/element/recaptcha.php:
--------------------------------------------------------------------------------
1 | Form->unlockField('g-recaptcha-response');
9 | } catch (CakeException) {
10 | // If FormProtectorComponent is not loaded, an exception in thrown in older CakePHP versions.
11 | }
12 | ?>
13 | = $this->Html->script(
14 | 'https://www.google.com/recaptcha/api.js?hl=' . $recaptcha['lang'],
15 | [
16 | 'block' => $recaptcha['scriptBlock'],
17 | 'async' => true,
18 | 'defer' => true,
19 | ]
20 | ) ?>
21 |
28 | data-callback="= $recaptcha['callback'] ?>"
29 |
30 | >
31 |
32 |
53 |
--------------------------------------------------------------------------------
/src/Controller/Component/RecaptchaComponent.php:
--------------------------------------------------------------------------------
1 |
27 | */
28 | protected array $_defaultConfig = [
29 | // This is test only key/secret
30 | 'sitekey' => '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI',
31 | 'secret' => '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe',
32 | 'theme' => 'light',
33 | 'type' => 'image',
34 | 'callback' => null,
35 | 'enable' => true,
36 | 'lang' => null,
37 | 'size' => 'normal',
38 | 'httpClientOptions' => [],
39 | 'scriptBlock' => true,
40 | ];
41 |
42 | /**
43 | * initialize
44 | *
45 | * @param array $config config
46 | * @return void
47 | */
48 | public function initialize(array $config = []): void
49 | {
50 | $config += Configure::read('Recaptcha', []);
51 | $this->setConfig($config);
52 |
53 | if (!$this->getConfig('lang')) {
54 | $this->setConfig('lang', Locale::getPrimaryLanguage(I18n::getLocale()));
55 | }
56 | }
57 |
58 | /**
59 | * beforeRender
60 | *
61 | * @param \Cake\Event\EventInterface $event Controller.beforeRender event
62 | * @return void
63 | */
64 | public function beforeRender(EventInterface $event): void
65 | {
66 | $config = $this->getConfig();
67 | unset($config['secret'], $config['httpClientOptions']);
68 |
69 | $this->getController()->viewBuilder()->addHelpers(['Recaptcha.Recaptcha' => $config]);
70 | }
71 |
72 | /**
73 | * verify recaptcha
74 | *
75 | * @return bool
76 | */
77 | public function verify(): bool
78 | {
79 | if (!(bool)$this->_config['enable']) {
80 | return true;
81 | }
82 |
83 | $controller = $this->_registry->getController();
84 | if ($controller->getRequest()->getData('g-recaptcha-response')) {
85 | try {
86 | $response = json_decode($this->apiCall(), flags: JSON_THROW_ON_ERROR);
87 | } catch (Exception $e) {
88 | return false;
89 | }
90 |
91 | if (isset($response->success)) {
92 | return (bool)$response->success;
93 | }
94 | }
95 |
96 | return false;
97 | }
98 |
99 | /**
100 | * Call reCAPTCHA API to verify
101 | *
102 | * @return string
103 | * @codeCoverageIgnore
104 | */
105 | protected function apiCall(): string
106 | {
107 | $controller = $this->_registry->getController();
108 | $client = new Client($this->_config['httpClientOptions']);
109 | $data = [
110 | 'secret' => $this->_config['secret'],
111 | 'response' => $controller->getRequest()->getData('g-recaptcha-response'),
112 | 'remoteip' => $controller->getRequest()->clientIp(),
113 | ];
114 |
115 | return (string)$client->post(static::VERIFY_ENDPOINT, $data)->getBody();
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/ctlabvn/Recaptcha/actions/workflows/ci.yml?query=branch%3Amaster)
2 | [](https://packagist.org/packages/crabstudio/recaptcha)
3 | [](https://packagist.org/packages/crabstudio/recaptcha)
4 | [](https://github.com/ctlabvn/Recaptcha/blob/master/LICENSE)
5 |
6 | # Integrate Google Recaptcha v2 to your CakePHP project
7 |
8 | ## Installation
9 |
10 | You can install this plugin into your CakePHP application using [composer](http://getcomposer.org).
11 |
12 | The recommended way to install composer packages is:
13 |
14 | ```bash
15 | composer require crabstudio/recaptcha
16 | ```
17 |
18 | ## Load plugin
19 |
20 | From command line:
21 |
22 | ```bash
23 | bin/cake plugin load Recaptcha
24 | ```
25 |
26 | ## Load Component and Configure
27 |
28 | Override default configure from loadComponent:
29 |
30 | ```php
31 | $this->loadComponent('Recaptcha.Recaptcha', [
32 | 'enable' => true, // true/false
33 | 'sitekey' => 'your_site_key', //if you don't have, get one: https://www.google.com/recaptcha/intro/index.html
34 | 'secret' => 'your_secret',
35 | 'type' => 'image', // image/audio
36 | 'theme' => 'light', // light/dark
37 | 'lang' => 'en', // default 'en'
38 | 'size' => 'normal' // normal/compact
39 | 'callback' => null, // `callback` data attribute for the recaptcha div, default `null`
40 | 'scriptBlock' => true // Value for `block` option for HtmlHelper::script() call
41 | ]);
42 | ```
43 |
44 | Override default config from app config file:
45 |
46 | ```php
47 | // file: config/app.php
48 |
49 | /**
50 | * Recaptcha configuration.
51 | */
52 | 'Recaptcha' => [
53 | 'sitekey' => 'your_site_key',
54 | 'secret' => 'your_secret',
55 | 'type' => 'image',
56 | 'theme' => 'light',
57 | 'lang' => 'es',
58 | 'size' => 'normal'
59 | ]
60 | ```
61 |
62 | Override default configure from recaptcha config file:
63 |
64 | ```php
65 | // file: config/recaptcha.php
66 |
67 | return [
68 | /**
69 | * Recaptcha configuration.
70 | *
71 | */
72 | 'Recaptcha' => [
73 | 'enable' => true,
74 | 'sitekey' => 'your_site_key',
75 | 'secret' => 'your_secret',
76 | 'type' => 'image',
77 | 'theme' => 'light',
78 | 'lang' => 'es',
79 | 'size' => 'normal'
80 | ]
81 | ];
82 | ```
83 |
84 | Load recaptcha config file:
85 |
86 | ```php
87 | // file: config/bootstrap.php
88 |
89 | Configure::load('recaptcha', 'default', true);
90 | ```
91 |
92 | Config preference:
93 | 1. loadComponent config options
94 | 2. recaptcha config file
95 | 3. app config file
96 |
97 | ## Usage
98 |
99 | Display recaptcha in your template:
100 |
101 | ```php
102 | = $this->Form->create() ?>
103 | = $this->Form->control('email') ?>
104 | // Display recaptcha box in your template, if configure has enable = false, nothing will be displayed
105 | = $this->Recaptcha->display() ?>
106 | = $this->Form->button() ?>
107 | = $this->Form->end() ?>
108 | ```
109 |
110 | Verify in your controller function
111 |
112 | ```php
113 | public function forgotPassword()
114 | {
115 | if ($this->request->is('post')) {
116 | if ($this->Recaptcha->verify()) { // if configure enable = false, it will always return true
117 | //do something here
118 | }
119 | $this->Flash->error(__('Please pass Google Recaptcha first'));
120 | }
121 | }
122 | ```
123 |
124 | Done.
125 |
--------------------------------------------------------------------------------