├── .editorconfig
├── .gitattributes
├── .gitignore
├── .travis.yml
├── README.md
├── composer.json
├── config
├── bootstrap.php
└── routes.php
├── phpunit.xml.dist
├── src
├── Controller
│ ├── Component
│ │ └── RecaptchaComponent.php
│ └── ContactController.php
├── Form
│ └── ContactForm.php
├── Recaptcha
│ ├── Exception
│ │ └── MissingRecaptchaApiKey.php
│ ├── HttpClientInterface.php
│ ├── Recaptcha.php
│ ├── RecaptchaResponse.php
│ └── RecaptchaResponseInterface.php
├── Template
│ └── Contact
│ │ ├── index.ctp
│ │ └── multiple_widgets.ctp
├── Validation
│ ├── ConfigValidator.php
│ ├── GlobalValidator.php
│ └── RecaptchaValidator.php
└── View
│ └── Helper
│ └── RecaptchaHelper.php
└── tests
├── TestCase
├── Controller
│ ├── Component
│ │ └── RecaptchaComponentTest.php
│ └── ContactControllerTest.php
├── Recaptcha
│ ├── Exception
│ │ └── MissingRecaptchaApiKeyTest.php
│ ├── RecaptchaResponseTest.php
│ └── RecaptchaTest.php
├── Validation
│ ├── ConfigValidatorTest.php
│ ├── GlobalValidatorTest.php
│ └── RecaptchaValidatorTest.php
└── View
│ └── Helper
│ └── RecaptchaHelperTest.php
└── bootstrap.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | end_of_line = lf
8 | charset = utf-8
9 | indent_style = space
10 | indent_size = 4
11 | insert_final_newline = true
12 | trim_trailing_whitespace = true
13 |
14 | [*.bat]
15 | end_of_line = crlf
16 | [*.yml]
17 | indent_style = space
18 | indent_size = 2
19 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Define the line ending behavior of the different file extensions
2 | # Set default behaviour, in case users don't have core.autocrlf set.
3 | * text=auto
4 | * text eol=lf
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/*
2 | /composer.lock
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.5
5 | - 5.6
6 |
7 | sudo: false
8 |
9 | env:
10 | matrix:
11 | - DB=mysql db_dsn='mysql://travis@0.0.0.0/cakephp_test'
12 | - DB=pgsql db_dsn='postgres://travis@127.0.0.1/cakephp_test'
13 | - DB=sqlite db_dsn='sqlite:///:memory:'
14 |
15 | global:
16 | - DEFAULT=1
17 |
18 | matrix:
19 | fast_finish: true
20 |
21 | include:
22 | - php: 7.0
23 | env: PHPCS=1 DEFAULT=0
24 |
25 | - php: 7.0
26 | env: CODECOVERAGE=1 DEFAULT=0
27 |
28 | - php: hhvm
29 | env: HHVM=1 DB=sqlite db_dsn='sqlite:///:memory:'
30 |
31 | - php: hhvm
32 | env: HHVM=1 DB=mysql db_dsn='mysql://travis@0.0.0.0/cakephp_test'
33 |
34 | install:
35 | - composer self-update
36 | - composer install --prefer-dist --no-interaction
37 |
38 | before_script:
39 | - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi"
40 | - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE DATABASE cakephp_test;' -U postgres; fi"
41 | - sh -c "if [ '$PHPCS' = '1' ]; then composer require cakephp/cakephp-codesniffer:dev-master; fi"
42 |
43 | - phpenv rehash
44 | - set +H
45 |
46 | script:
47 | - sh -c "if [ '$DEFAULT' = '1' ]; then ./vendor/bin/phpunit; fi"
48 | - sh -c "if [ '$PHPCS' = '1' ]; then ./vendor/bin/phpcs -n -p --extensions=php --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests --ignore=vendor; fi"
49 |
50 | notifications:
51 | email: false
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Google reCAPTCHA for CakePHP 3
2 | ==============================
3 |
4 | [](https://travis-ci.org/cakephp-fr/recaptcha)
5 | [](https://packagist.org/packages/cakephp-fr/recaptcha)
6 | [](https://php.net/)
7 | [](https://packagist.org/packages/cakephp-fr/recaptcha)
8 | [](https://packagist.org/packages/cakephp-fr/recaptcha)
9 |
10 | Be careful version 1.0 is for CakePHP 3.6 minimum.
11 | For a previous CakePHP version please use the 0.4.2 version.
12 |
13 | ## Plugin's Objective ##
14 |
15 | This plugin adds functionalities to use the new reCAPTCHA API version 2.0 in
16 | CakePHP projects.
17 |
18 | This plugin is still under development... For now, multiple widgets on a single page is not available.
19 |
20 | ## Requirements ##
21 |
22 | - PHP >= 5.4.16
23 | - [CakePHP 3.x](http://book.cakephp.org/3.0/en/index.html)
24 | - Server under `localhost` name. Be aware that the widgets will not be displayed
25 | if you have a vhost named local.dev/dev/ for instance.
26 |
27 | ## Installation ##
28 |
29 | _[Using [Composer](http://getcomposer.org/)]_
30 |
31 | Add the plugin to your project's `composer.json` - something like this:
32 |
33 | ```bash
34 | composer require cakephp-fr/recaptcha:~1.0
35 | ```
36 |
37 | You then need to load the plugin, by running:
38 |
39 | ```bash
40 | bin/cake plugin load -rb Recaptcha
41 | ```
42 |
43 | You can check that this command has created the line `Plugin::load('Recaptcha', ['routes' => true, 'bootstrap' => true]);` at the bottom of your `config/boostrap.php` file.
44 |
45 | The `'routes' => true` should be deleted in production. It's only useful if you want to see the demo.
46 |
47 | ## Usage of plugin ##
48 |
49 | ### 1. Go to Google reCAPTCHA site
50 |
51 | Go [here](https://www.google.com/recaptcha/intro/index.html) to create a pair
52 | of keys for your website.
53 |
54 | ### 2. Configure the plugin
55 |
56 | The Easiest way is to add the recaptcha config to the `config/app.php`, something like:
57 |
58 | ```php
59 | return [
60 |
61 | .... (other configs before)
62 |
63 | 'Recaptcha' => [
64 | // Register API keys at https://www.google.com/recaptcha/admin
65 | 'sitekey' => 'your-sitekey',
66 | 'secret' => 'your-secret',
67 | // reCAPTCHA supported 40+ languages listed
68 | // here: https://developers.google.com/recaptcha/docs/language
69 | 'lang' => 'en',
70 | // either light or dark
71 | 'theme' => 'light',
72 | // either image or audio
73 | 'type' => 'image',
74 | // either normal or compact
75 | 'size' => 'normal'
76 | ]
77 | ]
78 | ```
79 |
80 | Make sure that `/config/app.php` file is in `.gitignore`. The secret key must stay secret.
81 |
82 | If you don't have a key and a secret, an exception will be raised.
83 |
84 | ### 3. Then add the component in your controller where you need the reCAPTCHA.
85 |
86 | For example:
87 |
88 | ```php
89 | public function initialize() {
90 | parent::initialize();
91 | if ($this->request->getParam('action') === 'contact') {
92 | $this->loadComponent('Recaptcha.Recaptcha');
93 | }
94 | }
95 | ```
96 |
97 | ```php
98 | public function contact() {
99 | if ($this->request->is('post')) {
100 | if ($this->Recaptcha->verify()) {
101 | // Here you can validate your data
102 | if (!empty($this->request->getData())) {
103 | $this->Flash->success(__('We will get back to you soon.'));
104 | return $this->redirect($this->referer());
105 | } else {
106 | $this->Flash->error(__('There was a problem submitting your form.'));
107 | }
108 | } else {
109 | // You can debug developers errors with
110 | // debug($this->Recaptcha->errors());
111 | $this->Flash->error(__('Please check your Recaptcha Box.'));
112 | }
113 | }
114 | }
115 | ```
116 |
117 | ### 4. Finally add `= $this->Recaptcha->display() ?>` in your view template inside the form.
118 |
119 | **No need** to add the helper: it will be added with the component.
120 |
121 | For example:
122 |
123 | ```php
124 | = $this->Form->create() ?>
125 |
126 | = $this->Form->control('name', [
127 | 'label' => __('Your Name'),
128 | // 'default' => $this->request->query('name'); // in case you add the Prg Component
129 | ]) ?>
130 | = $this->Form->control('message', [
131 | 'type' => 'textarea',
132 | // 'default' => $this->request->query('message'); // in case you add the Prg Component
133 | 'label' => __('Your Message')
134 | ]) ?>
135 |
136 | = $this->Recaptcha->display() ?>
137 |
138 | = $this->Form->button(__('OK')) ?>
139 | = $this->Form->end() ?>
140 | ```
141 |
142 | See another example of contact with no form in
143 | `src/Controller/ContactController.php`, `src/Template/Contact/index.ctp` and
144 | `src/Form/ContactForm.php`. You can test it by going to
145 | `http://localhost/recaptcha/contact`.
146 |
147 | ## What's inside ? ##
148 |
149 | **COMPONENT**
150 |
151 | - RecaptchaComponent
152 |
153 | **HELPERS**
154 |
155 | - RecaptchaHelper (Automatically added when the RecaptchaComponent is added)
156 |
157 | **EXAMPLE**
158 |
159 | - Controller : ContactController
160 | - Form : ContactForm
161 | - Template : Contact/index.ctp
162 |
163 | ## Tests ##
164 |
165 | To test the plugin, clone it and run `composer install`. Then run:
166 |
167 | ```bash
168 | ./vendor/bin/phpunit
169 | ./vendor/bin/phpcs -n -p --extensions=php --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests --ignore=vendor
170 | ```
171 |
172 | ## Support & Contribution ##
173 |
174 | For support and feature request, please contact me through Github issues
175 |
176 | Please feel free to contribute to the plugin with new issues, requests, unit
177 | tests and code fixes or new features. If you want to contribute some code,
178 | create a feature branch, and send us your pull request.
179 | Unit tests for new features and issues detected are mandatory to keep quality
180 | high.
181 |
182 | ## License ##
183 |
184 | Copyright (c) [2014-2018] [cakephp-fr]
185 |
186 | Permission is hereby granted, free of charge, to any person obtaining a copy of
187 | this software and associated documentation files (the "Software"), to deal in
188 | the Software without restriction, including without limitation the rights to
189 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
190 | of the Software, and to permit persons to whom the Software is furnished to do
191 | so, subject to the following conditions:
192 |
193 | The above copyright notice and this permission notice shall be included in all
194 | copies or substantial portions of the Software.
195 |
196 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
197 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
198 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
199 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
201 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
202 | SOFTWARE.
203 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cakephp-fr/recaptcha",
3 | "type": "cakephp-plugin",
4 | "description": "To easily use Google Recaptcha (free CAPTCHA service that protect websites from spam and abuse) in CakePHP projects",
5 | "keywords": [
6 | "cakephp",
7 | "bootstrap",
8 | "google",
9 | "recaptcha",
10 | "captcha"
11 | ],
12 | "homepage": "https://github.com/cakephp-fr/recaptcha",
13 | "license": "MIT",
14 | "authors": [
15 | {
16 | "name": "cake17",
17 | "email": "cake17@cake-websites.com"
18 | }
19 | ],
20 | "support": {
21 | "issues": "https://github.com/cake17/cakephp-recaptcha/issues",
22 | "source": "https://github.com/cake17/cakephp-recaptcha",
23 | "wiki": "https://github.com/google/ReCAPTCHA"
24 | },
25 | "require": {
26 | "php": ">=7.2",
27 | "cakephp/cakephp": "^4.0"
28 | },
29 | "require-dev": {
30 | "phpunit/phpunit": "*",
31 | "cakephp/cakephp-codesniffer": "2.*"
32 | },
33 | "suggest": {
34 | "friendsofcake/search": "dev-master"
35 | },
36 | "autoload": {
37 | "psr-4": {
38 | "Recaptcha\\": "src"
39 | }
40 | },
41 | "autoload-dev": {
42 | "psr-4": {
43 | "Recaptcha\\Test\\": "tests",
44 | "Cake\\Test\\": "./vendor/cakephp/cakephp/tests"
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | errors(Configure::read('Recaptcha'));
21 |
22 | if (!empty($errors)) {
23 | $errMsg = '';
24 | $it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($errors));
25 | foreach($it as $v) {
26 | $errMsg .= "- " . $v . "
";
27 | }
28 | throw new \Exception(__d('recaptcha', 'One of your recaptcha config value is incorrect:
' . $errMsg));
29 | }
30 |
--------------------------------------------------------------------------------
/config/routes.php:
--------------------------------------------------------------------------------
1 | true when plugin is
7 | * loaded
8 | *
9 | * @author cake17
10 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License
11 | * @link http://blog.cake-websites.com/
12 | */
13 | use Cake\Routing\Router;
14 |
15 | Router::plugin('Recaptcha', function ($routes) {
16 | $routes->connect(
17 | '/contact',
18 | ['controller' => 'Contact', 'action' => 'index']
19 | );
20 | $routes->connect(
21 | '/contact/multiple-widgets',
22 | ['controller' => 'Contact', 'action' => 'multiple-widgets']
23 | );
24 | });
25 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ./tests/TestCase
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | ./vendor/
36 | ./vendor/
37 |
38 | ./tests/
39 | ./tests/
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Controller/Component/RecaptchaComponent.php:
--------------------------------------------------------------------------------
1 | viewBuilder()->getHelpers())) {
53 | $controller->viewBuilder()->setHelpers(['Recaptcha.Recaptcha'], true);
54 | }
55 | }
56 |
57 | /**
58 | * startup callback
59 | *
60 | * @param \Cake\Event\Event $event Event.
61 | *
62 | * @return void
63 | */
64 | public function startup(Event $event)
65 | {
66 | $secret = Configure::consume('Recaptcha.secret');
67 | // throw an exception if the secret is not defined in config/recaptcha.php file
68 | if (empty($secret)) {
69 | throw new Exception(__d('recaptcha', "You must set the secret Recaptcha key in config/recaptcha.php file"));
70 | }
71 |
72 | // instantiate Recaptcha object that deals with retrieving data from google recaptcha
73 | $this->recaptcha = new Recaptcha(new RecaptchaResponse(), $secret);
74 | $controller = $event->getSubject();
75 |
76 | $this->setController($controller);
77 | }
78 |
79 | /**
80 | * Verify Response
81 | *
82 | * @return bool
83 | */
84 | public function verify()
85 | {
86 | $controller = $this->_registry->getController();
87 | $gRecaptchaResponse = $controller->getRequest()->getData("g-recaptcha-response");
88 | if (!empty($gRecaptchaResponse)) {
89 |
90 | $resp = $this->recaptcha->verifyResponse(
91 | new Client(),
92 | $gRecaptchaResponse
93 | );
94 |
95 | // if verification is correct,
96 | if ($resp) {
97 | return true;
98 | }
99 | }
100 | return false;
101 | }
102 |
103 | /**
104 | * Return an array with errors : missing secret, connexion issue, ...
105 | *
106 | * @return array
107 | */
108 | public function errors()
109 | {
110 | return $this->recaptcha->setErrors();
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/Controller/ContactController.php:
--------------------------------------------------------------------------------
1 | request->getParam('action'), ['index', 'multipleWidgets'])) {
31 | $this->loadComponent('Recaptcha.Recaptcha');
32 | }
33 | }
34 |
35 | /**
36 | * Contact Form Page
37 | *
38 | * @return void
39 | */
40 | public function index()
41 | {
42 | $contact = new ContactForm();
43 | if ($this->request->is('post')) {
44 | if ($this->Recaptcha->verify()) {
45 | // Here you can validate your data instead
46 | if ($contact->execute($this->request->getData())) {
47 | $this->Flash->success(__('We will get back to you soon.'));
48 | } else {
49 | $this->Flash->error(__('There was a problem submitting your form.'));
50 | }
51 | } else {
52 | // You can debug developers errors with
53 | // debug($this->Recaptcha->errors());
54 | $this->Flash->error(__('Please check your Recaptcha Box.'));
55 | }
56 | }
57 | $this->set(compact('contact'));
58 | }
59 |
60 | /**
61 | * Contact Form Page With multiple Widgets
62 | *
63 | * @return void
64 | */
65 | public function multipleWidgets()
66 | {
67 | $contact = new ContactForm();
68 | if ($this->request->is('post')) {
69 | if ($this->Recaptcha->verify()) {
70 | if ($contact->execute($this->request->getData())) {
71 | $this->Flash->success(__('We will get back to you soon.'));
72 | } else {
73 | $this->Flash->error(__('There was a problem submitting your form.'));
74 | }
75 | } else {
76 | // debug($contact);
77 | // debug($this->Recaptcha);
78 | $this->Flash->error(__('Please check your Recaptcha Box.'));
79 | }
80 | }
81 | $this->set(compact('contact'));
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Form/ContactForm.php:
--------------------------------------------------------------------------------
1 | addField('name', 'string')
31 | // ->addField('email', ['type' => 'string'])
32 | ->addField('body', ['type' => 'text']);
33 | }
34 |
35 | /**
36 | * Build Validator
37 | *
38 | * @param Validator $validator Validator.
39 | * @return validator
40 | */
41 | protected function _buildValidator(Validator $validator)
42 | {
43 | return $validator
44 | ->add('name', 'length', [
45 | 'rule' => ['minLength', 2],
46 | 'message' => 'A name is required'
47 | ])
48 | ->add('email', 'format', [
49 | 'rule' => 'email',
50 | 'message' => 'A valid email address is required',
51 | ]);
52 | }
53 |
54 | /**
55 | * Execute
56 | *
57 | * @param array $data Data.
58 | * @return bool
59 | */
60 | protected function _execute(array $data)
61 | {
62 | // Send an email.
63 | return true;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Recaptcha/Exception/MissingRecaptchaApiKey.php:
--------------------------------------------------------------------------------
1 | %s';
21 | }
22 |
--------------------------------------------------------------------------------
/src/Recaptcha/HttpClientInterface.php:
--------------------------------------------------------------------------------
1 | recaptchaResponse = $recaptchaResponse;
86 | if ($secret == null || $secret == "") {
87 | throw new MissingRecaptchaApiKey([
88 | 'link' => self::$signupUrl,
89 | 'name' => 'here'
90 | ]);
91 | }
92 | $this->secret = $secret;
93 | }
94 |
95 | /**
96 | * Calls the reCAPTCHA siteverify API to verify whether the user passes
97 | * CAPTCHA test.
98 | *
99 | * @param HttpClientInterface $httpClient Required. HttpClient.
100 | * @param string $response Required. The user response token provided by the reCAPTCHA to the user and provided to your site on.
101 | * @param string $remoteIp Optional. The user's IP address.
102 | *
103 | * @return bool
104 | */
105 | public function verifyResponse(Client $httpClient, $response, $remoteIp = null)
106 | {
107 | if (is_null($this->secret)) {
108 | $this->errors['missing-secret'] = __d('recaptcha', 'secret is null');
109 | return false;
110 | }
111 | // Get Json GRecaptchaResponse Obj from Google server
112 | $postOptions = [
113 | 'secret' => $this->secret,
114 | 'response' => $response
115 | ];
116 | if (!is_null($remoteIp)) {
117 | $postOptions['remoteip'] = $remoteIp;
118 | }
119 | $gRecaptchaResponse = $httpClient->post(self::$siteVerifyUrl, $postOptions);
120 |
121 | // problem while accessing remote
122 | if (!$gRecaptchaResponse->isOk()) {
123 | $this->errors['remote-not-accessible'] = __d('recaptcha', 'Remote is not accessible');
124 | return false;
125 | }
126 |
127 | $this->recaptchaResponse->setJson($gRecaptchaResponse->getJson());
128 |
129 | if ($this->recaptchaResponse->isSuccess()) {
130 | return true;
131 | }
132 | $this->errors['not-checked'] = __d('recaptcha', 'Recaptcha is not checked');
133 | return false;
134 | }
135 |
136 | /**
137 | * Return an array with errors : missing secret, connexion issue, ...
138 | *
139 | * @return array
140 | */
141 | public function errors()
142 | {
143 | return $this->errors;
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/Recaptcha/RecaptchaResponse.php:
--------------------------------------------------------------------------------
1 | 'The secret parameter is missing.',
64 | 'invalid-input-secret' => 'The secret parameter is invalid or malformed.',
65 | 'missing-input-response' => 'The response parameter is missing.',
66 | 'invalid-input-response' => 'The response parameter is invalid or malformed.'
67 | ];
68 |
69 | /**
70 | * Return true/false if Success/Fails.
71 | *
72 | * @return bool
73 | */
74 | public function isSuccess()
75 | {
76 | return $this->success;
77 | }
78 |
79 | /**
80 | * Return the Code Errors if any.
81 | *
82 | * @return array
83 | */
84 | public function errorCodes()
85 | {
86 | return $this->errorCodes;
87 | }
88 |
89 | /**
90 | * Sets the success.
91 | *
92 | * @param bool $success Success.
93 | *
94 | * @return void
95 | */
96 | public function setSuccess($success)
97 | {
98 | if ($this->_validateSuccess($success)) {
99 | $this->success = $success;
100 | }
101 | }
102 |
103 | /**
104 | * Validates the success
105 | * Only if success is a boolean.
106 | *
107 | * @param bool $success Success.
108 | *
109 | * @return bool
110 | */
111 | protected function _validateSuccess($success)
112 | {
113 | if (is_bool($success)) {
114 | return true;
115 | }
116 | return false;
117 | }
118 |
119 | /**
120 | * Sets the Code Errors.
121 | *
122 | * @param array $errorCodes Error Codes.
123 | *
124 | * @return void
125 | */
126 | public function setErrorCodes(array $errorCodes)
127 | {
128 | if ($this->_validateErrorCodes($errorCodes)) {
129 | $this->errorCodes = $this->_purifyErrorCodes($errorCodes);
130 | }
131 | }
132 |
133 | /**
134 | * Validates the errorCodes
135 | * Only if errorCodes is an array and is in available errorCodes.
136 | *
137 | * @param array $errorCodes Error Codes.
138 | *
139 | * @return bool
140 | */
141 | protected function _validateErrorCodes(array $errorCodes)
142 | {
143 | if (empty($errorCodes)) {
144 | return false;
145 | }
146 | if (!is_array($errorCodes)) {
147 | return false;
148 | }
149 |
150 | return true;
151 | }
152 |
153 | /**
154 | * Return a array with only the authorized errorCodes.
155 | *
156 | * @param array $errorCodes Error Codes.
157 | * @return array
158 | */
159 | protected function _purifyErrorCodes(array $errorCodes)
160 | {
161 | $errorCodesPurified = [];
162 | foreach ($errorCodes as $num => $errorCode) {
163 | if (key_exists($errorCode, self::$errorCodesAuthorized)) {
164 | $errorCodesPurified[$num] = $errorCode;
165 | }
166 | }
167 | return $errorCodesPurified;
168 | }
169 |
170 | /**
171 | * Hydrate the Object with $json data.
172 | *
173 | * @param array $json Json response of GRecaptcha server.
174 | *
175 | * @return void
176 | */
177 | public function setJson(array $json)
178 | {
179 | if (isset($json['error-codes']) && !empty($json['error-codes'])) {
180 | $this->setErrorCodes($json['error-codes']);
181 | }
182 | if (isset($json['success']) && !empty($json['success'])) {
183 | $this->setSuccess($json['success']);
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/src/Recaptcha/RecaptchaResponseInterface.php:
--------------------------------------------------------------------------------
1 |
17 | = $this->Form->create($contact) ?>
18 | = $this->Form->control('name') ?>
19 | = $this->Form->control('email') ?>
20 | = $this->Form->control('body') ?>
21 | = $this->Recaptcha->display([
22 | // This options override global configs
23 | 'theme' => 'dark',
24 | 'type' => 'image',
25 | 'size' => 'normal'
26 | ]) ?>
27 | = $this->Form->button('Submit') ?>
28 | = $this->Form->end() ?>
29 |
--------------------------------------------------------------------------------
/src/Template/Contact/multiple_widgets.ctp:
--------------------------------------------------------------------------------
1 |
17 | = $this->Form->create($contact) ?>
18 | = $this->Form->control('name') ?>
19 | = $this->Form->control('email') ?>
20 | = $this->Form->control('body') ?>
21 | = $this->Form->button('Submit') ?>
22 | = $this->Form->end() ?>
23 |
24 | Recaptcha->widget(['id' => 'widget']);
26 | $this->Recaptcha->widget(['id' => 'widget2']);
27 | ?>
28 | = $this->Recaptcha->render(); ?>
29 |
--------------------------------------------------------------------------------
/src/Validation/ConfigValidator.php:
--------------------------------------------------------------------------------
1 | requirePresence('secret')
29 | ->notEmptyString('secret', __d('recaptcha', 'A secret should not be blank.'));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Validation/GlobalValidator.php:
--------------------------------------------------------------------------------
1 | [
25 | 'ar',
26 | 'af',
27 | 'am',
28 | 'hy',
29 | 'az',
30 | 'eu',
31 | 'bn',
32 | 'bg',
33 | 'ca',
34 | 'zh-HK',
35 | 'zh-CN',
36 | 'zh-TW',
37 | 'hr',
38 | 'cs',
39 | 'da',
40 | 'nl',
41 | 'en-GB',
42 | 'en',
43 | 'et',
44 | 'fil',
45 | 'fi',
46 | 'fr',
47 | 'fr-CA',
48 | 'gl',
49 | 'ka',
50 | 'de',
51 | 'de-AT',
52 | 'de-CH',
53 | 'el',
54 | 'gu',
55 | 'iw',
56 | 'hi',
57 | 'hu',
58 | 'is',
59 | 'id',
60 | 'it',
61 | 'ja',
62 | 'kn',
63 | 'ko',
64 | 'lo',
65 | 'lv',
66 | 'lt',
67 | 'ms',
68 | 'ml',
69 | 'mr',
70 | 'mn',
71 | 'no',
72 | 'fa',
73 | 'pl',
74 | 'pt',
75 | 'pt-BR',
76 | 'pt-PT',
77 | 'ro',
78 | 'ru',
79 | 'sr',
80 | 'si',
81 | 'sk',
82 | 'sl',
83 | 'es',
84 | 'es-419',
85 | 'sw',
86 | 'sv',
87 | 'ta',
88 | 'te',
89 | 'th',
90 | 'tr',
91 | 'uk',
92 | 'ur',
93 | 'vi',
94 | 'zu'
95 | ],
96 | 'theme' => [
97 | 'light',
98 | 'dark'
99 | ],
100 | 'type' => [
101 | 'audio',
102 | 'image'
103 | ],
104 | 'size' => [
105 | 'normal',
106 | 'compact'
107 | ]
108 | ];
109 |
110 | /**
111 | * Constructor
112 | *
113 | * @return void
114 | */
115 | public function __construct()
116 | {
117 | parent::__construct();
118 | $this
119 | ->add('lang', [
120 | 'inLangList' => [
121 | 'rule' => ['inList', $this->validList['lang']],
122 | 'message' => __d('recaptcha', 'The lang should be in the following authorized lang ' . implode(',', $this->validList['lang'])),
123 | ]
124 | ])
125 | ->add('theme', [
126 | 'inThemeList' => [
127 | 'rule' => ['inList', $this->validList['theme']],
128 | 'message' => __d('recaptcha', 'The theme should be in the following authorized theme ' . implode(',', $this->validList['theme'])),
129 | ]
130 | ])
131 | ->add('type', [
132 | 'inTypeList' => [
133 | 'rule' => ['inList', $this->validList['type']],
134 | 'message' => __d('recaptcha', 'The type should be in the following authorized type ' . implode(',', $this->validList['type'])),
135 | ]
136 | ])
137 | ->add('size', [
138 | 'inSizeList' => [
139 | 'rule' => ['inList', $this->validList['size']],
140 | 'message' => __d('recaptcha', 'The size should be in the following authorized type ' . implode(',', $this->validList['size'])),
141 | ]
142 | ]);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/Validation/RecaptchaValidator.php:
--------------------------------------------------------------------------------
1 | 'en',
41 | // If no theme is found anywhere
42 | 'theme' => 'light',
43 | // If no type is found anywhere
44 | 'type' => 'image',
45 | // If no size is found anywhere
46 | 'size' => 'normal'
47 | ];
48 |
49 | /**
50 | * Constructor
51 | *
52 | * @param View $view View
53 | * @param array $config Config
54 | *
55 | * @return void
56 | */
57 | public function __construct(View $view, $config = [])
58 | {
59 | parent::__construct($view, $config);
60 |
61 | // Merge Options given by user in config/recaptcha
62 | $this->setConfig(Configure::read('Recaptcha'));
63 |
64 | $lang = $this->getConfig('lang');
65 | if (empty($lang)) {
66 | $this->setConfig('lang', I18n::locale());
67 | }
68 | // Validate the Configure Data
69 | $validator = new RecaptchaValidator();
70 | $errors = $validator->errors($this->getConfig());
71 | if (!empty($errors)) {
72 | throw new \Exception(__d('recaptcha', 'One of your recaptcha config value is incorrect'));
73 | // throw an exception with config error that is raised
74 | }
75 |
76 | // Make sure the secret param is
77 | $this->setConfig('secret', '');
78 | }
79 |
80 | /**
81 | * Render the recaptcha div and js script.
82 | *
83 | * @param array $options Options.
84 | * - sitekey
85 | * - lang
86 | * - theme
87 | * - type
88 | *
89 | * @return string HTML
90 | */
91 | public function display(array $options = [])
92 | {
93 | // merge options
94 | $options = array_merge($this->getConfig(), $options);
95 |
96 | // Validate the Configure Data
97 | $validator = new RecaptchaValidator();
98 | $errors = $validator->errors($options);
99 | if (!empty($errors)) {
100 | throw new \Exception(__d('recaptcha', 'One of your recaptcha config value is incorrect'));
101 | // throw an exception with config error that is raised
102 | }
103 |
104 | extract($options);
105 |
106 | return '
107 | ';
110 | }
111 |
112 | /**
113 | * Return html
114 | *
115 | * @return string
116 | */
117 | public function render()
118 | {
119 | return $this->html() . $this->script();
120 | }
121 |
122 | /**
123 | * Create a recaptcha widget (for multiple widgets)
124 | *
125 | * @param array $options Options
126 | * - id : Id
127 | * - sitekey : Site Key
128 | * - theme : Theme
129 | * - type : Type
130 | * - lang : Langue
131 | *
132 | * @return void
133 | */
134 | public function widget(array $options = [])
135 | {
136 | $options = array_merge($this->getConfig(), $options);
137 |
138 | // Validate the Configure Data
139 | $validator = new RecaptchaValidator();
140 | $errors = $validator->errors($options);
141 | if (!empty($errors)) {
142 | throw new \Exception(__d('recaptcha', 'One of your recaptcha config value is incorrect in a widget'));
143 | // throw an exception with config error that is raised
144 | }
145 | // add infos in widgets for script()
146 | $this->widgets[] = [
147 | 'id' => $options['id'],
148 | 'sitekey' => $options['sitekey'],
149 | 'theme' => $options['theme'],
150 | 'type' => $options['type'],
151 | 'lang' => $options['lang'],
152 | 'size' => $options['size']
153 | ];
154 | }
155 |
156 | /**
157 | * Define the html to render
158 | *
159 | * @return string html code
160 | */
161 | public function html()
162 | {
163 | $html = '';
164 |
165 | if (isset($this->widgets) && !empty($this->widgets)) {
166 | foreach ($this->widgets as $widget) {
167 | $actions = [
168 | 'getResponse' => "javascript:alert(grecaptcha.getResponse(id" . $widget['id'] . "));",
169 | 'reset' => "javascript:grecaptcha.reset(id" . $widget['id'] . ");",
170 | 'render' => '?'
171 | ];
172 | $html .= '';
173 | }
174 | }
175 | return $html;
176 | }
177 |
178 | /**
179 | * Define the script to render
180 | *
181 | * @return string js script
182 | */
183 | public function script()
184 | {
185 | $js = "";
207 | $js .= '';
208 | //debug($js);
209 | return $js;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/tests/TestCase/Controller/Component/RecaptchaComponentTest.php:
--------------------------------------------------------------------------------
1 | controller = $this->getMock(
50 | // 'Cake\Controller\Controller',
51 | // [],
52 | // [$request, $response]
53 | // );
54 |
55 | $registry = new ComponentRegistry();
56 | $this->Recaptcha = new RecaptchaComponent($registry);
57 | }
58 |
59 | /**
60 | * tearDown method
61 | *
62 | * @return void
63 | */
64 | public function tearDown()
65 | {
66 | unset($this->Recaptcha);
67 |
68 | parent::tearDown();
69 | }
70 |
71 | /**
72 | * Test StartupWithExistingConfigFile
73 | *
74 | * @return void
75 | */
76 | public function testStartupWithExistingConfigFile()
77 | {
78 | $this->markTestIncomplete("Not yet");
79 | }
80 | //
81 | // /**
82 | // * testVerify
83 | // *
84 | // * @return void
85 | // */
86 | // public function testVerify()
87 | // {
88 | // $response = new RecaptchaResponse();
89 | // // instantiate Recaptcha object that deals with retrieving data from google recaptcha
90 | // $recaptcha = new Recaptcha($response, 'good-secret');
91 | //
92 | // $this->controller->request->data([
93 | // "g-recaptcha-response" => "good-response"
94 | // ]);
95 | // $this->assertFalse($this->controller->verify());
96 | // $this->assertFalse($this->controller->verify());
97 | // $this->assertEmpty($this->controller->verify());
98 | // }
99 | }
100 |
--------------------------------------------------------------------------------
/tests/TestCase/Controller/ContactControllerTest.php:
--------------------------------------------------------------------------------
1 | get('/recaptcha/contact');
23 |
24 | // $this->assertResponseOk();
25 | // $this->assertResponseContains('form');
26 | // $this->assertResponseContains('recaptcha');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/TestCase/Recaptcha/Exception/MissingRecaptchaApiKeyTest.php:
--------------------------------------------------------------------------------
1 | markTestIncomplete('Not implemented yet.');
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/TestCase/Recaptcha/RecaptchaResponseTest.php:
--------------------------------------------------------------------------------
1 | RecaptchaResponse = new RecaptchaResponse();
28 | }
29 |
30 | /**
31 | * tearDown method
32 | *
33 | * @return void
34 | */
35 | public function tearDown()
36 | {
37 | unset($this->RecaptchaResponse);
38 |
39 | parent::tearDown();
40 | }
41 |
42 | /**
43 | * Test Success To True
44 | *
45 | * @return void
46 | */
47 | public function testSuccessTrue()
48 | {
49 | $this->RecaptchaResponse->setSuccess(true);
50 | $this->assertEquals(true, $this->RecaptchaResponse->isSuccess());
51 | }
52 |
53 | /**
54 | * Test Success To False
55 | *
56 | * @return void
57 | */
58 | public function testSuccessFalse()
59 | {
60 | $this->RecaptchaResponse->setSuccess(false);
61 | $this->assertEquals(false, $this->RecaptchaResponse->isSuccess());
62 | }
63 |
64 | /**
65 | * Test Success With Wrong Inputs
66 | *
67 | * @return void
68 | */
69 | public function testSuccessWithWrongInputs()
70 | {
71 | $this->RecaptchaResponse->setSuccess('ee');
72 | $this->assertEquals(null, $this->RecaptchaResponse->isSuccess());
73 |
74 | $this->RecaptchaResponse->setSuccess(['eee', 'e']);
75 | $this->assertEquals(null, $this->RecaptchaResponse->isSuccess());
76 | }
77 |
78 | /**
79 | * Test Error Codes
80 | *
81 | * @return void
82 | */
83 | public function testErrorCodesThatWorks()
84 | {
85 | $this->RecaptchaResponse->setErrorCodes(['invalid-input-response']);
86 | $this->assertEquals(['invalid-input-response'], $this->RecaptchaResponse->errorCodes());
87 | }
88 |
89 | /**
90 | * Test Error Codes With Wrong Inputs
91 | *
92 | * @return void
93 | */
94 | public function testErrorCodesWithWrongInputs()
95 | {
96 | $this->RecaptchaResponse->setErrorCodes(['eee', 'e']);
97 | $this->assertEquals([], $this->RecaptchaResponse->errorCodes());
98 | }
99 |
100 | /**
101 | * Test Set Response
102 | *
103 | * @return void
104 | */
105 | public function testSetJsonWithWrongInputs()
106 | {
107 | $this->RecaptchaResponse->setJson(['eee', 'e']);
108 | $this->assertEquals(null, $this->RecaptchaResponse->errorCodes());
109 | $this->assertEquals(null, $this->RecaptchaResponse->isSuccess());
110 | }
111 |
112 | /**
113 | * Test Set Response
114 | *
115 | * @return void
116 | */
117 | public function testSetResponseWithGoodInputs()
118 | {
119 | $this->RecaptchaResponse->setJson(['error-codes' => ['input-error'], 'success' => true]);
120 | $this->assertEquals([], $this->RecaptchaResponse->errorCodes());
121 | $this->assertEquals(true, $this->RecaptchaResponse->isSuccess());
122 |
123 | $this->RecaptchaResponse->setJson(['error-codes' => ['missing-input-secret'], 'success' => true]);
124 | $this->assertEquals(['missing-input-secret'], $this->RecaptchaResponse->errorCodes());
125 | $this->assertEquals(true, $this->RecaptchaResponse->isSuccess());
126 |
127 | $this->RecaptchaResponse->setJson(['error-codes' => ['missing-input-secret', 'invalid-input-secret', 'eee'], 'success' => true]);
128 | $this->assertEquals(['missing-input-secret', 'invalid-input-secret'], $this->RecaptchaResponse->errorCodes());
129 | $this->assertEquals(true, $this->RecaptchaResponse->isSuccess());
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/tests/TestCase/Recaptcha/RecaptchaTest.php:
--------------------------------------------------------------------------------
1 | Recaptcha = new Recaptcha($recaptchaResponse, $secret);
46 | //$this->assertEquals();
47 | unset($this->Recaptcha);
48 | }
49 |
50 | public function testWithExistingSecret()
51 | {
52 | $secret = 'goodSecret';
53 | $recaptchaResponse = new RecaptchaResponse();
54 | $this->Recaptcha = new Recaptcha($recaptchaResponse, $secret);
55 | //$this->assertEquals();
56 | unset($this->Recaptcha);
57 | }
58 |
59 | public function testVerifyResponse()
60 | {
61 | $secret = 'goodSecret';
62 | // $httpClient = new Client();
63 | $recaptchaResponse = new RecaptchaResponse();
64 | $this->Recaptcha = new Recaptcha($recaptchaResponse, $secret);
65 | // $this->assertEquals(false, $this->Recaptcha->verifyResponse($httpClient, 'good'));
66 | unset($this->Recaptcha);
67 | }
68 |
69 | public function testVerifyResponseWrong()
70 | {
71 | $secret = 'goodSecret';
72 | // $httpClient = new Client();
73 | $recaptchaResponse = new RecaptchaResponse();
74 | $this->Recaptcha = new Recaptcha($recaptchaResponse, $secret);
75 | // $this->assertEquals(false, $this->Recaptcha->verifyResponse($httpClient, 'wrong'));
76 | unset($this->Recaptcha);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/tests/TestCase/Validation/ConfigValidatorTest.php:
--------------------------------------------------------------------------------
1 | 'fr'];
29 | $errors = $validator->errors($data);
30 | $this->assertArrayHasKey('secret', $errors);
31 |
32 | $validator = new ConfigValidator();
33 | $data = ['theme' => 'light'];
34 | $errors = $validator->errors($data);
35 | $this->assertArrayHasKey('secret', $errors);
36 |
37 | $validator = new ConfigValidator();
38 | $data = ['type' => 'image'];
39 | $errors = $validator->errors($data);
40 | $this->assertArrayHasKey('secret', $errors);
41 |
42 | $validator = new ConfigValidator();
43 | $data = ['size' => 'normal'];
44 | $errors = $validator->errors($data);
45 | $this->assertArrayHasKey('secret', $errors);
46 | }
47 |
48 | /**
49 | * Test Config Validation with existing params
50 | *
51 | * @return void
52 | */
53 | public function testConfigValidationWithExistingParams()
54 | {
55 | $validator = new ConfigValidator();
56 | $data = ['secret' => 'fff', 'lang' => 'fr'];
57 | $errors = $validator->errors($data);
58 | $this->assertEmpty($errors);
59 |
60 | $validator = new ConfigValidator();
61 | $data = ['secret' => 'fff', 'theme' => 'light'];
62 | $errors = $validator->errors($data);
63 | $this->assertEmpty($errors);
64 |
65 | $validator = new ConfigValidator();
66 | $data = ['secret' => 'fff', 'type' => 'image'];
67 | $errors = $validator->errors($data);
68 | $this->assertEmpty($errors);
69 |
70 | $validator = new ConfigValidator();
71 | $data = ['secret' => 'fff', 'size' => 'normal'];
72 | $errors = $validator->errors($data);
73 | $this->assertEmpty($errors);
74 | }
75 |
76 | /**
77 | * Test Global Validation with non existing params
78 | *
79 | * @return void
80 | */
81 | public function testConfigValidationWithNonExistingParams()
82 | {
83 | $validator = new ConfigValidator();
84 | $data = ['secret' => 'fff', 'lang' => 'non-existing-lang'];
85 | $errors = $validator->errors($data);
86 | $this->assertArrayHasKey('lang', $errors);
87 |
88 | $validator = new ConfigValidator();
89 | $data = ['secret' => 'fff', 'theme' => 'non-existing-theme'];
90 | $errors = $validator->errors($data);
91 | $this->assertArrayHasKey('theme', $errors);
92 |
93 | $validator = new ConfigValidator();
94 | $data = ['secret' => 'fff', 'type' => 'non-existing-type'];
95 | $errors = $validator->errors($data);
96 | $this->assertArrayHasKey('type', $errors);
97 |
98 | $validator = new ConfigValidator();
99 | $data = ['secret' => 'fff', 'size' => 'non-existing-size'];
100 | $errors = $validator->errors($data);
101 | $this->assertArrayHasKey('size', $errors);
102 | }
103 |
104 | /**
105 | * Test Global Validation with block of existing params
106 | *
107 | * @return void
108 | */
109 | public function testConfigValidationWithBlockOfExistingParams()
110 | {
111 | $validator = new ConfigValidator();
112 | $data = [
113 | 'secret' => 'fff',
114 | 'lang' => 'fr',
115 | 'theme' => 'dark',
116 | 'type' => 'audio',
117 | 'size' => 'compact'
118 | ];
119 | $errors = $validator->errors($data);
120 | $this->assertEmpty($errors);
121 | }
122 |
123 | /**
124 | * Test Global Validation with block of non existing params
125 | *
126 | * @return void
127 | */
128 | public function testConfigValidationWithBlockOfNonExistingParams()
129 | {
130 | $validator = new ConfigValidator();
131 | $data = [
132 | 'secret' => 'fff',
133 | 'lang' => 'non-existing-lang',
134 | 'theme' => 'non-existing-theme',
135 | 'type' => 'non-existing-type',
136 | 'size' => 'non-existing-size'
137 | ];
138 | $errors = $validator->errors($data);
139 | $this->assertArrayHasKey('lang', $errors);
140 | $this->assertArrayHasKey('theme', $errors);
141 | $this->assertArrayHasKey('type', $errors);
142 | $this->assertArrayHasKey('size', $errors);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/tests/TestCase/Validation/GlobalValidatorTest.php:
--------------------------------------------------------------------------------
1 | 'fr'];
29 | $errors = $validator->errors($data);
30 | $this->assertEmpty($errors);
31 |
32 | $validator = new GlobalValidator();
33 | $data = ['theme' => 'light'];
34 | $errors = $validator->errors($data);
35 | $this->assertEmpty($errors);
36 |
37 | $validator = new GlobalValidator();
38 | $data = ['type' => 'image'];
39 | $errors = $validator->errors($data);
40 | $this->assertEmpty($errors);
41 |
42 | $validator = new GlobalValidator();
43 | $data = ['size' => 'normal'];
44 | $errors = $validator->errors($data);
45 | $this->assertEmpty($errors);
46 | }
47 |
48 | /**
49 | * Test Global Validation with non existing params
50 | *
51 | * @return void
52 | */
53 | public function testGlobalValidationWithNonExistingParams()
54 | {
55 | $validator = new GlobalValidator();
56 | $data = ['lang' => 'non-existing-lang'];
57 | $errors = $validator->errors($data);
58 | $this->assertArrayHasKey('lang', $errors);
59 |
60 | $validator = new GlobalValidator();
61 | $data = ['theme' => 'non-existing-theme'];
62 | $errors = $validator->errors($data);
63 | $this->assertArrayHasKey('theme', $errors);
64 |
65 | $validator = new GlobalValidator();
66 | $data = ['type' => 'non-existing-type'];
67 | $errors = $validator->errors($data);
68 | $this->assertArrayHasKey('type', $errors);
69 |
70 | $validator = new GlobalValidator();
71 | $data = ['size' => 'non-existing-size'];
72 | $errors = $validator->errors($data);
73 | $this->assertArrayHasKey('size', $errors);
74 | }
75 |
76 | /**
77 | * Test Global Validation with block of existing params
78 | *
79 | * @return void
80 | */
81 | public function testGlobalValidationWithBlockOfExistingParams()
82 | {
83 | $validator = new GlobalValidator();
84 | $data = [
85 | 'lang' => 'fr',
86 | 'theme' => 'dark',
87 | 'type' => 'audio',
88 | 'size' => 'compact'
89 | ];
90 | $errors = $validator->errors($data);
91 | $this->assertEmpty($errors);
92 | }
93 |
94 | /**
95 | * Test Global Validation with block of non existing params
96 | *
97 | * @return void
98 | */
99 | public function testGlobalValidationWithBlockOfNonExistingParams()
100 | {
101 | $validator = new GlobalValidator();
102 | $data = [
103 | 'lang' => 'non-existing-lang',
104 | 'theme' => 'non-existing-theme',
105 | 'type' => 'non-existing-type',
106 | 'size' => 'non-existing-size'
107 | ];
108 | $errors = $validator->errors($data);
109 | $this->assertArrayHasKey('lang', $errors);
110 | $this->assertArrayHasKey('theme', $errors);
111 | $this->assertArrayHasKey('type', $errors);
112 | $this->assertArrayHasKey('size', $errors);
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/tests/TestCase/Validation/RecaptchaValidatorTest.php:
--------------------------------------------------------------------------------
1 | 'fr'];
29 | $errors = $validator->errors($data);
30 | $this->assertEmpty($errors);
31 |
32 | $validator = new RecaptchaValidator();
33 | $data = ['theme' => 'light'];
34 | $errors = $validator->errors($data);
35 | $this->assertEmpty($errors);
36 |
37 | $validator = new RecaptchaValidator();
38 | $data = ['type' => 'image'];
39 | $errors = $validator->errors($data);
40 | $this->assertEmpty($errors);
41 |
42 | $validator = new RecaptchaValidator();
43 | $data = ['size' => 'normal'];
44 | $errors = $validator->errors($data);
45 | $this->assertEmpty($errors);
46 | }
47 |
48 | /**
49 | * Test Recaptcha Validation with non existing params
50 | *
51 | * @return void
52 | */
53 | public function testRecaptchaValidationWithNonExistingParams()
54 | {
55 | $validator = new RecaptchaValidator();
56 | $data = ['lang' => 'non-existing-lang'];
57 | $errors = $validator->errors($data);
58 | $this->assertArrayHasKey('lang', $errors);
59 |
60 | $validator = new RecaptchaValidator();
61 | $data = ['theme' => 'non-existing-theme'];
62 | $errors = $validator->errors($data);
63 | $this->assertArrayHasKey('theme', $errors);
64 |
65 | $validator = new RecaptchaValidator();
66 | $data = ['type' => 'non-existing-type'];
67 | $errors = $validator->errors($data);
68 | $this->assertArrayHasKey('type', $errors);
69 |
70 | $validator = new RecaptchaValidator();
71 | $data = ['size' => 'non-existing-size'];
72 | $errors = $validator->errors($data);
73 | $this->assertArrayHasKey('size', $errors);
74 | }
75 |
76 | /**
77 | * Test Recaptcha Validation with block of existing params
78 | *
79 | * @return void
80 | */
81 | public function testRecaptchaValidationWithBlockOfExistingParams()
82 | {
83 | $validator = new RecaptchaValidator();
84 | $data = [
85 | 'lang' => 'fr',
86 | 'theme' => 'dark',
87 | 'type' => 'audio',
88 | 'size' => 'compact'
89 | ];
90 | $errors = $validator->errors($data);
91 | $this->assertEmpty($errors);
92 | }
93 |
94 | /**
95 | * Test Recaptcha Validation with block of non existing params
96 | *
97 | * @return void
98 | */
99 | public function testRecaptchaValidationWithBlockOfNonExistingParams()
100 | {
101 | $validator = new RecaptchaValidator();
102 | $data = [
103 | 'lang' => 'non-existing-lang',
104 | 'theme' => 'non-existing-theme',
105 | 'type' => 'non-existing-type',
106 | 'size' => 'non-existing-size'
107 | ];
108 | $errors = $validator->errors($data);
109 | $this->assertArrayHasKey('lang', $errors);
110 | $this->assertArrayHasKey('theme', $errors);
111 | $this->assertArrayHasKey('type', $errors);
112 | $this->assertArrayHasKey('size', $errors);
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/tests/TestCase/View/Helper/RecaptchaHelperTest.php:
--------------------------------------------------------------------------------
1 | Recaptcha = new RecaptchaHelper($view);
32 | }
33 |
34 | /**
35 | * tearDown method
36 | *
37 | * @return void
38 | */
39 | public function tearDown()
40 | {
41 | unset($this->Recaptcha);
42 |
43 | parent::tearDown();
44 | }
45 |
46 | /**
47 | * testConstruct method
48 | *
49 | * @return void
50 | */
51 | public function testConstruct()
52 | {
53 | $expected = [
54 | // If no language is found anywhere
55 | 'lang' => 'en',
56 | // If no theme is found anywhere
57 | 'theme' => 'light',
58 | // If no type is found anywhere
59 | 'type' => 'image',
60 | 'secureApiUrl' => 'https://www.google.com/recaptcha/api',
61 | // reCAPTCHA supported 40+ languages listed here: https://developers.google.com/recaptcha/docs/language
62 | 'langAccepted' => [
63 | 'ar',
64 | 'bg',
65 | 'ca',
66 | 'zh-CN',
67 | 'zh-TW',
68 | 'hr',
69 | 'cs',
70 | 'da',
71 | 'nl',
72 | 'en-GB',
73 | 'en',
74 | 'fil',
75 | 'fi',
76 | 'fr',
77 | 'fr-CA',
78 | 'de',
79 | 'de-AT',
80 | 'de-CH',
81 | 'el',
82 | 'iw',
83 | 'hi',
84 | 'hu',
85 | 'id',
86 | 'it',
87 | 'ja',
88 | 'ko',
89 | 'lv',
90 | 'lt',
91 | 'no',
92 | 'fa',
93 | 'pl',
94 | 'pt',
95 | 'pt-BR',
96 | 'pt-PT',
97 | 'ro',
98 | 'ru',
99 | 'sr',
100 | 'sk',
101 | 'sl',
102 | 'es',
103 | 'es-419',
104 | 'sv',
105 | 'th',
106 | 'tr',
107 | 'uk',
108 | 'vi'
109 | ],
110 | 'themeAccepted' => [
111 | 'dark',
112 | 'light'
113 | ],
114 | 'typeAccepted' => [
115 | 'audio',
116 | 'image'
117 | ]
118 | ];
119 | // $this->assertEquals($expected, $this->Recaptcha->config());
120 | }
121 |
122 | /**
123 | * Test StartupWithEmptyOptions
124 | *
125 | * @return void
126 | */
127 | // public function testStartupWithEmptyOptions()
128 | // {
129 | // Configure::config([
130 | // 'Recaptcha' => [
131 | // 'sitekey' => 'goodkey',
132 | // 'secret' => 'goodsecret',
133 | // 'lang' => '',
134 | // 'theme' => '',
135 | // 'type' => '',
136 | // ]
137 | // ]);
138 | //
139 | // $this->assertEquals('goodkey', Configure::read('Recaptcha.sitekey'));
140 | // $this->assertEquals('goodsecret', Configure::read('Recaptcha.secret'));
141 | // $this->assertEquals('', Configure::read('Recaptcha.lang'));
142 | // $this->assertEquals('', Configure::read('Recaptcha.theme'));
143 | // $this->assertEquals('', Configure::read('Recaptcha.type'));
144 | // }
145 |
146 | public function testDisplay()
147 | {
148 | $options = [
149 | 'lang' => 'fr',
150 | 'sitekey' => 'goodkey',
151 | 'theme' => 'light',
152 | 'type' => 'image'
153 | ];
154 |
155 | $expected = '
156 | ';
159 |
160 | // $this->assertEquals($expected, $this->Recaptcha->display($options));
161 | }
162 |
163 | public function testDisplayWithEmptyValues()
164 | {
165 | $options = [];
166 |
167 | $expected = '
168 | ';
171 |
172 | // $this->assertEquals($expected, $this->Recaptcha->display($options));
173 | }
174 |
175 | // public function testMultipleWidgets()
176 | // {
177 | // $id = 1;
178 | // $siteKey = '';
179 | // $options = [
180 | // 'theme' => '',
181 | // 'type' => '',
182 | // 'lang' => '',
183 | // 'callback' => '',
184 | // 'action' => ''
185 | // ];
186 | //
187 | // $expected = '
188 | //
193 | //
194 | //
199 | //
200 | //
205 | // ';
206 | //
207 | // $actual = $this->Recaptcha->display($id, $siteKey, $options);
208 | //
209 | // //$this->assertEquals($expected, $actual);
210 | // }
211 | //
212 | // public function testMultipleWidgetsHeadScript()
213 | // {
214 | // // add widget
215 | // $id = 1;
216 | // $siteKey = '';
217 | // $options = [
218 | // 'theme' => '',
219 | // 'type' => '',
220 | // 'lang' => '',
221 | // 'callback' => '',
222 | // 'action' => ''
223 | // ];
224 | // $this->Recaptcha->display($id, $siteKey, $options);
225 | //
226 | // $expected = '';
227 | //
228 | // $actual = $this->Recaptcha->script();
229 | //
230 | // //$this->assertEquals($expected, $actual);
231 | // }
232 | }
233 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | 'App',
40 | 'paths' => [
41 | 'plugins' => [ROOT . 'Plugin' . DS],
42 | 'templates' => [ROOT . 'App' . DS . 'Template' . DS]
43 | ]
44 | ]);
45 |
46 | Cake\Cache\Cache::config([
47 | '_cake_core_' => [
48 | 'engine' => 'File',
49 | 'prefix' => 'cake_core_',
50 | 'serialize' => true,
51 | 'path' => '/tmp',
52 | ],
53 | '_cake_model_' => [
54 | 'engine' => 'File',
55 | 'prefix' => 'cake_model_',
56 | 'serialize' => true,
57 | 'path' => '/tmp',
58 | ]
59 | ]);
60 |
61 | if (!getenv('db_dsn')) {
62 | putenv('db_dsn=sqlite:///:memory:');
63 | }
64 | if (!getenv('DB')) {
65 | putenv('DB=sqlite');
66 | }
67 | ConnectionManager::config('test', ['url' => getenv('db_dsn')]);
68 | Plugin::load('Recaptcha', [
69 | 'path' => dirname(dirname(__FILE__)) . DS,
70 | ]);
71 |
--------------------------------------------------------------------------------