gregwar/captcha-bundle
Symfony bundle that adds a Captcha form type powered by gregwar/captcha. Simple Composer install, Flex auto-registration, and optional global YAML config. Supports inline embedded images by default or file-based captchas with cleanup/expiration options.
Installation:
composer require gregwar/captcha-bundle
(No manual registration needed if using Symfony Flex.)
First Use Case:
Add the GregwarCaptchaType to a form in your controller or entity:
use Gregwar\CaptchaBundle\Form\Type\CaptchaType;
$form = $this->createFormBuilder()
->add('name', TextType::class)
->add('captcha', CaptchaType::class, [
'mapped' => false, // Important: Captcha is not mapped to an entity
])
->getForm();
Display in Twig:
{{ form_row(form.captcha) }}
Validate Submission:
if ($form->isSubmitted() && $form->isValid()) {
// Captcha is automatically validated
$this->addFlash('success', 'Form submitted!');
}
config/packages/gregwar_captcha.yaml (default config)src/Form/Type/CaptchaType.php (customization entry point)vendor/gregwar/captcha/src/Captcha.php (core logic)// src/Form/RegistrationType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email')
->add('captcha', CaptchaType::class, [
'label' => 'Verify you are human',
'config' => [
'background' => '#f9f9f9',
],
]);
}
Override defaults per-form:
# config/packages/gregwar_captcha.yaml
gregwar_captcha:
default:
background: '#ffffff'
length: 6
width: 120
height: 40
Override for a specific form:
$builder->add('captcha', CaptchaType::class, [
'config' => [
'length' => 8,
'font' => '/path/to/custom_font.ttf',
],
]);
Extend the default validator:
// src/Validator/Constraints/CustomCaptcha.php
use Symfony\Component\Validator\Constraint;
class CustomCaptcha extends Constraint
{
public $message = 'Invalid captcha. Try again.';
}
// src/Validator/Constraints/CustomCaptchaValidator.php
use Symfony\Component\Validator\ConstraintValidator;
class CustomCaptchaValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
// Custom logic (e.g., rate-limiting)
}
}
Bind to the form:
$builder->add('captcha', CaptchaType::class, [
'constraints' => [
new CustomCaptcha(),
],
]);
Generate captcha without a form:
use Gregwar\Captcha\Captcha;
$captcha = new Captcha();
$captcha->setBackground($backgroundColor);
$captcha->setLength(6);
$image = $captcha->get();
// Save to file or return as response
header('Content-Type: image/jpeg');
echo $image;
Use Twig to localize labels:
{{ form_label(form.captcha, 'captcha.label'|trans) }}
{{ form_help(form.captcha, 'captcha.hint'|trans) }}
Translations in translations/messages.en.yaml:
captcha:
label: "Please enter the code above"
hint: "Letters are case-sensitive"
Listen for captcha generation:
// src/EventListener/CaptchaListener.php
use Gregwar\CaptchaBundle\Event\CaptchaEvent;
class CaptchaListener
{
public function onCaptchaGenerate(CaptchaEvent $event)
{
$captcha = $event->getCaptcha();
$captcha->setFont('/custom/path/font.ttf');
}
}
Register in services.yaml:
services:
App\EventListener\CaptchaListener:
tags:
- { name: kernel.event_listener, event: gregwar.captcha.generate, method: onCaptchaGenerate }
Extend Twig for reusable captcha logic:
// src/Twig/CaptchaExtension.php
use Gregwar\Captcha\Captcha;
class CaptchaExtension extends \Twig\Extension\AbstractExtension
{
public function getFunctions()
{
return [
new \Twig\TwigFunction('generate_captcha', [$this, 'generateCaptcha']),
];
}
public function generateCaptcha($config = [])
{
$captcha = new Captcha($config);
return $captcha->get();
}
}
Use in Twig:
<img src="{{ generate_captcha({'width': 150}) }}">
RateLimiter to prevent brute force.csrf_protection: true (default in Symfony).mapped => false Requirement
mapped: false causes the captcha to be treated as a form field in your entity.'mapped' => false in the form type options.Font Path Issues
%kernel.project_dir%/public/fonts/arial.ttf).Case Sensitivity
$userInput = strtolower($userInput);
$storedCode = strtolower($session->get('captcha_code'));
Session Expiry
lifetime in config:
gregwar_captcha:
lifetime: 3600 # 1 hour (default)
Image Output Corruption
gd or imagick extensions are missing.php -m | grep -E 'gd|imagick'
Caching Headaches
<img src="{{ path('app_captcha') }}?{{ 'now'|date('U') }}">
Log Captcha Codes Add a listener to log generated codes for debugging:
public function onCaptchaGenerate(CaptchaEvent $event)
{
$this->logger->debug('Generated captcha:', [
'code' => $event->getCaptcha()->getCode(),
]);
}
Inspect Session Data Check if the captcha code is stored correctly:
$session = $this->get('session');
$this->logger->debug('Session captcha:', $session->get('captcha_code'));
Validate PHP Extensions
Ensure gd or imagick is installed:
php -i | grep -A5 "gd\|imagick"
Test with Defaults First Start with default config to isolate issues:
gregwar_captcha: ~
Custom Captcha Generators
Extend the core Captcha class:
class CustomCaptcha extends Captcha
{
public function __construct()
{
$this->setBackground('#000000');
$this->setLength(8);
$this->setFont('/custom/font.ttf');
}
public function getCode()
{
return strtoupper(parent::getCode());
}
}
Use in the bundle config:
gregwar_captcha:
captcha_class: App\Service\CustomCaptcha
Override Twig Templates Customize the captcha widget template:
How can I help you explore Laravel packages today?