How to set up hCaptcha with CakePHP
4 May 2020This is a how to secure CakePHP Forms with hCaptcha service.
I’m sure you know what a CAPTCHA is, and even if these can now be solved relatively easily by machine learning [1][2][3], it’s a good way to secure your web forms (e.g. registration/login).
First you need to create a hCaptcha account. You will obtain a sitekey and secret key, which you can store in your CakePHP App Config:
// config/app_local.php
'hCaptcha' => [
'sitekey' => 'YOUR_SITE_KEY',
'secret' => 'YOUR_SECRET_KEY',
],Next you need to include the js lib of hCaptcha in your Layout Template:
// templates/layout/default.php
// in html head or at the end of your body tag:
<script src="https://hcaptcha.com/1/api.js" async defer></script>In the form you want to secure you include the CAPTCHA and add the sitekey:
// e.g. templates/Articles/add.php
<?= $this->Form->create($article) ?>
<fieldset>
<legend><?= __('Add Article') ?></legend>
<?= $this->Form->control('user_id', ['options' => $users]) ?>
<?= $this->Form->control('title') ?>
<?= $this->Form->control('body') ?>
<?= $this->Form->control('published') ?>
<div class="h-captcha" data-sitekey="<?= Configure::read('hCaptcha.sitekey') ?>"></div>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>By solving the CAPTCHA and submitting the form, the corresponding controller receives the POST parameter h-captcha-response in the form of a token. This token must send to the hCaptcha API endpoint (https://hcaptcha.com/siteverify) via a POST request to verify the result. For this we use the HTTP Client of CakePHP:
// e.g. src/Controller/ArticlesController.php
use Cake\Core\Configure;
use Cake\Http\Client;
...
public function add()
{
$article = $this->Articles->newEmptyEntity();
if ($this->request->is('post')) {
// Get the token from request data
$token = $this->request->getData('h-captcha-response');
// create an httpClient and create a POST request for the API endpoint
$httpClient = new Client();
$response = $httpClient->post('https://hcaptcha.com/siteverify', [
'secret' => Configure::read('hCaptcha.secret'),
'response' => $token,
]);
// Get the response data as JSON
$hCaptchaResult = $response->getJson();
// Check if the result is *success* and save your article/go on wih your business logic
if ($hCaptchaResult['success']) {
$article = $this->Articles->patchEntity($article, $this->request->getData());
if ($this->Articles->save($article)) {
$this->Flash->success(__('The article has been saved.'));
return $this->redirect(['action' => 'index']);
}
} else {
// hCaptcha API returns error codes, f.e. if the CAPTCHA isn't filled out or not solved.
// Check out the error codes here: https://docs.hcaptcha.com/#server
}
$this->Flash->error(__('The article could not be saved. Please, try again.'));
}
$users = $this->Articles->Users->find('list', ['limit' => 200]);
$this->set(compact('article', 'users'));
}If you want to use hCaptcha API in multiple Controllers, you can put the Controllercode in a Component.
We're happy to get in touch with you