├── 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 | 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="" 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 | [![Build Status](https://img.shields.io/github/actions/workflow/status/ctlabvn/Recaptcha/ci.yml?branch=master)](https://github.com/ctlabvn/Recaptcha/actions/workflows/ci.yml?query=branch%3Amaster) 2 | [![Latest Stable Version](https://img.shields.io/packagist/v/crabstudio/recaptcha)](https://packagist.org/packages/crabstudio/recaptcha) 3 | [![Total Downloads](https://img.shields.io/packagist/dt/crabstudio/recaptcha)](https://packagist.org/packages/crabstudio/recaptcha) 4 | [![License](https://img.shields.io/github/license/ctlabvn/Recaptcha)](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 | Form->create() ?> 103 | Form->control('email') ?> 104 | // Display recaptcha box in your template, if configure has enable = false, nothing will be displayed 105 | Recaptcha->display() ?> 106 | Form->button() ?> 107 | 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 | --------------------------------------------------------------------------------