diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 7100f07..7be444d 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -36,6 +36,7 @@ class Configuration implements ConfigurationInterface ->scalarNode('invalid_message')->defaultValue('Bad code value')->end() ->scalarNode('bypass_code')->defaultValue(null)->end() ->scalarNode('whitelist_key')->defaultValue('captcha_whitelist_key')->end() + ->scalarNode('humanity')->defaultValue(0)->end() ->end() ; diff --git a/README.md b/README.md index c8d11f7..4f36641 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ You can define the following configuration options globally or on the CaptchaTyp * **invalid_message**: error message displayed when an non-matching code is submitted (default="Bad code value") * **bypass_code**: code that will always validate the captcha (default=null) * **whitelist_key**: the session key to use for keep the session keys that can be used for captcha storage, when using as_url (default=captcha_whitelist_key) +* **humanity**: number of extra forms that the user can submit after a correct validation, if set to a value different of 0, only 1 over (1+humanity) forms will contain a CAPTCHA (default=0, i.e each form will contain the CAPTCHA) Example : diff --git a/Resources/views/captcha.html.twig b/Resources/views/captcha.html.twig index 0f5bb9f..e7ac34d 100644 --- a/Resources/views/captcha.html.twig +++ b/Resources/views/captcha.html.twig @@ -1,7 +1,11 @@ {% block captcha_widget %} +{% if is_human %} +- +{% else %} {% spaceless %} {{ form_widget(form) }} {% endspaceless %} +{% endif %} {% endblock %} diff --git a/Type/CaptchaType.php b/Type/CaptchaType.php index 00c48a6..78ba23c 100644 --- a/Type/CaptchaType.php +++ b/Type/CaptchaType.php @@ -66,7 +66,8 @@ class CaptchaType extends AbstractType $this->session, $this->key, $options['invalid_message'], - $options['bypass_code'] + $options['bypass_code'], + $options['humanity'] ); $builder->addEventListener(FormEvents::POST_BIND, array($validator, 'validate')); @@ -79,11 +80,21 @@ class CaptchaType extends AbstractType */ public function buildView(FormView $view, FormInterface $form, array $options) { + $isHuman = false; + + if ($options['humanity'] > 0) { + $humanityKey = $this->key.'_humanity'; + if ($this->session->get($humanityKey, 0) > 0) { + $isHuman = true; + } + } + $view->vars = array_merge($view->vars, array( 'captcha_width' => $options['width'], 'captcha_height' => $options['height'], 'captcha_code' => $this->generator->getCaptchaCode($this->key, $options), 'value' => '', + 'is_human' => $isHuman )); } diff --git a/Validator/CaptchaValidator.php b/Validator/CaptchaValidator.php index dedaf33..dcfe520 100644 --- a/Validator/CaptchaValidator.php +++ b/Validator/CaptchaValidator.php @@ -33,18 +33,25 @@ class CaptchaValidator */ private $bypassCode; + /** + * Number of form that the user can submit without captcha + * @var int + */ + private $humanity; + /** * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session * @param string $key * @param string $invalidMessage * @param string|null $bypassCode */ - public function __construct(SessionInterface $session, $key, $invalidMessage, $bypassCode) + public function __construct(SessionInterface $session, $key, $invalidMessage, $bypassCode, $humanity) { $this->session = $session; $this->key = $key; $this->invalidMessage = $invalidMessage; $this->bypassCode = $bypassCode; + $this->humanity = $humanity; } /** @@ -53,12 +60,26 @@ class CaptchaValidator public function validate(FormEvent $event) { $form = $form = $event->getForm(); + $humanityKey = $this->key . '_humanity'; $code = $form->getData(); $expectedCode = $this->getExpectedCode(); + if ($this->humanity > 0) { + if ($this->session->get($humanityKey, 0) > 0) { + $this->session->set($humanityKey, $this->session->get($humanityKey, 0)-1); + return; + } else { + $this->session->remove($humanityKey); + } + } + if (!($code && is_string($code) && ($this->compare($code, $expectedCode) || $this->compare($code, $this->bypassCode)))) { $form->addError(new FormError($this->invalidMessage)); + } else { + if ($this->humanity > 0) { + $this->session->set($humanityKey, $this->humanity); + } } $this->session->remove($this->key);