*/ class CaptchaValidator { /** @var SessionInterface */ private $session; /** * Session key to store the code * @var string */ private $key; /** * Error message text for non-matching submissions * @var string */ private $invalidMessage; /** * Configuration parameter used to bypass a required code match * @var string */ private $bypassCode; /** * Number of form that the user can submit without captcha * @var int */ private $humanity; /** * Translator * @var TranslatorInterface */ private $translator; /** * @param TranslatorInterface $translator * @param SessionInterface $session * @param string $key * @param string $invalidMessage * @param string $bypassCode * @param int $humanity */ public function __construct( TranslatorInterface $translator, SessionInterface $session, string $key, string $invalidMessage, string $bypassCode, int $humanity ) { $this->translator = $translator; $this->session = $session; $this->key = $key; $this->invalidMessage = $invalidMessage; $this->bypassCode = $bypassCode; $this->humanity = $humanity; } public function validate(FormEvent $event): void { $form = $event->getForm(); $code = $form->getData(); $expectedCode = $this->getExpectedCode(); if ($this->humanity > 0) { $humanity = $this->getHumanity(); if ($humanity > 0) { $this->updateHumanity($humanity-1); return; } } if (!($code !== null && is_string($code) && ($this->compare($code, $expectedCode) || $this->compare($code, $this->bypassCode)))) { $form->addError(new FormError($this->translator->trans($this->invalidMessage, array(), 'validators'))); } else { if ($this->humanity > 0) { $this->updateHumanity($this->humanity); } } $this->session->remove($this->key); if ($this->session->has($this->key . '_fingerprint')) { $this->session->remove($this->key . '_fingerprint'); } } /** * Retrieve the expected CAPTCHA code * * @return mixed|null */ protected function getExpectedCode() { $options = $this->session->get($this->key, array()); if (is_array($options) && isset($options['phrase'])) { return $options['phrase']; } return null; } /** * Retrieve the humanity * * @return mixed|null */ protected function getHumanity() { return $this->session->get($this->key . '_humanity', 0); } protected function updateHumanity(int $newValue): void { if ($newValue > 0) { $this->session->set($this->key . '_humanity', $newValue); } else { $this->session->remove($this->key . '_humanity'); } } protected function niceize(string $code): string { return strtr(strtolower($code), 'oil', '01l'); } /** * Run a match comparison on the provided code and the expected code * * @param $code * @param $expectedCode * * @return bool */ protected function compare($code, $expectedCode): bool { return ($expectedCode !== null && is_string($expectedCode) && $this->niceize($code) == $this->niceize($expectedCode)); } }