After an upgrade from Cake 3.10 to 4.5.x and an upgrade from “dereuromark/cakephp-captcha” to 1.4, the Honeypot Captcha no longer works.
I have customized my setup based on the docs: cakephp-captcha/docs/Passive.md at cake4 · dereuromark/cakephp-captcha · GitHub
But every POST request throws “Validations Errors”
[
'measure' => [
'captcha_result' => [
'_required' => 'This field is required',
],
],
]
However, the field “captcha_result” is part of the active captcha, which I do not load anywhere in my app.
Here is one of the controllers where I used this
MeasuresController, action “add”
class MeasuresController extends AppController
{
public function initialize(): void
{
parent::initialize();
$this->_setCustomerVars();
$this->loadComponent('Captcha.Captcha');
$this->viewBuilder()->addHelper('Captcha.Captcha');
}
public function add(?string $env = null): ?Response
{
$measure = $this->Measures->newEmptyEntity();
$contactMeasure = new ContactFormMeasure();
//$contactMeasure->addBehavior('Captcha.PassiveCaptcha');
if ($this->getRequest()->is('post')) {
$this->Captcha->addValidation($contactMeasure->getValidator(), 'Passive');
if ($contactMeasure->execute($this->request->getData())) {
$measure = $this->Measures->patchEntity($measure, $this->request->getData());
if ($this->Measures->save($measure)) {
$redirect = ['action' => 'success'];
if (!empty($env)) {
$redirect[] = $env;
}
return $this->redirect($redirect);
} else {
$this->Flash->error(__('Error Message');
}
} else {
$this->Flash->error(__('formContainsErrors'));
}
}
$countries = $this->Measures->Countries->find('list');
$this->set(compact('measure', 'countries'));
$this->set('_serialize', ['measure']);
if ($env == 'facebook') {
$this->viewBuilder()->setLayout('default_fb');
$this->render('add_fb');
} elseif ($env == 'my-ringsize') {
$this->render('my_ringsize');
}
return null;
}
}
ContactFormMeasure
class ContactFormMeasure extends Form
{
use FormBehaviorTrait;
protected function _buildSchema(Schema $schema): Schema
{
return $schema
->addField('first_name', ['type' => 'string', 'length' => 128])
->addField('last_name', ['type' => 'string', 'length' => 128])
->addField('txtlastname', ['type' => 'string', 'length' => 128])
->addField('email', ['type' => 'string', 'length' => 128])
->addField('repeat_email', ['type' => 'string', 'length' => 128])
->addField('street', ['type' => 'string', 'length' => 128])
->addField('house_no', ['type' => 'string', 'length' => 128])
->addField('zip', ['type' => 'string', 'length' => 128])
->addField('city', ['type' => 'string', 'length' => 128]);
}
public function validationDefault(Validator $validator): Validator
{
return $validator
->requirePresence('first_name')
->notEmptyString('first_name', __('This field cannot be left empty'))
->requirePresence('last_name')
->notEmptyString('last_name', __('This field cannot be left empty'))
->requirePresence('email')
->add('email', 'format', [
'rule' => 'email',
'message' => __('A valid email address is required'),
])
->requirePresence('repeat_email')
->add('repeat_email', 'format', [
'rule' => 'email',
'message' => __('A valid email address is required'),
])
->add('email', 'equalTo', [
'rule' => function ($value, $context) {
return $value === $context['data']['repeat_email'];
},
'message' => __('Mail must be equal'),
])
->requirePresence('street')
->notEmptyString('street', __('This field cannot be left empty'))
->requirePresence('house_no')
->notEmptyString('house_no', __('This field cannot be left empty'))
->requirePresence('zip')
->notEmptyString('zip', __('This field cannot be left empty'))
->requirePresence('city')
->notEmptyString('city', __('This field cannot be left empty'));
}
protected function _execute(array $data): bool
{
// Overwrite in your extending class
return true;
}
}
FormBehaviorTrait
trait FormBehaviorTrait
{
private BehaviorRegistry $_behaviors;
/**
* @param \Cake\Event\EventManager|null $eventManager EventManager instance.
*/
public function __construct(?EventManager $eventManager = null)
{
parent::__construct($eventManager);
$this->_behaviors = new BehaviorRegistry();
$this->_behaviors->setTable(new Table()); // We fake this
}
public function addBehavior(string $name, array $options = [])
{
$this->_behaviors->load($name, $options);
return $this;
}
public function behaviors(): BehaviorRegistry
{
return $this->_behaviors;
}
}
Within Template
<?= $this->Captcha->passive(); ?>
Application
public function bootstrap(): void
{
parent::bootstrap();
if (PHP_SAPI === 'cli') {
$this->bootstrapCli();
$this->addPlugin('IdeHelper');
} else {
FactoryLocator::add(
'Table',
(new TableLocator())->allowFallbackClass(false)
);
}
$this->addPlugin('Authentication');
$this->addPlugin('Authorization');
if (Configure::read('debug')) {
Configure::write('DebugKit.safeTld', ['de', 'com']);
Configure::write('DebugKit.variablesPanelMaxDepth', 20);
Configure::write('DebugKit.ignoreAuthorization', true);
$this->addPlugin('DebugKit');
}
$this->addPlugin('Captcha');
}
Am I missing something, or is this a bug?