Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Spam Bundle Laravel Package

isometriks/spam-bundle

Symfony bundle to reduce spam on forms with simple protections like timed submission (min/max seconds between render and submit) and honeypot fields. Easy Composer install, configurable defaults, and per-form options to enable or override settings.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require isometriks/spam-bundle
    

    For Symfony Flex, no additional steps are needed. For non-Flex projects, add to config/bundles.php:

    Isometriks\Bundle\SpamBundle\IsometriksSpamBundle::class => ['all' => true],
    
  2. First Use Case: Enable timed spam prevention on a form by adding the option in your form type:

    $builder->add('name');
    // Enable timed spam with default settings (7s min delay)
    $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
        $event->getForm()->add('timed_spam', HiddenType::class, [
            'mapped' => false,
            'data' => true, // Enable timed spam
        ]);
    });
    

    Or via form options when creating the form:

    $form = $this->createForm(MyType::class, null, [
        'timed_spam' => true,
    ]);
    
  3. First Honeypot Use Case: Add a hidden field to your form template (e.g., contact.html.twig):

    <input type="text" name="email_address" class="hidden" />
    

    Enable honeypot in your form type:

    $builder->add('honeypot', HiddenType::class, [
        'mapped' => false,
        'required' => false,
        'constraints' => [
            new NotBlank(['message' => 'Form fields are invalid']),
        ],
    ]);
    

    Or via form options:

    $form = $this->createForm(MyType::class, null, [
        'honeypot' => true,
        'honeypot_field' => 'email_address',
    ]);
    
  4. Verify Setup:

    • Submit the form manually to ensure it works.
    • Test with a bot (e.g., a script that submits instantly) to confirm timed spam prevention blocks it.
    • Fill the honeypot field manually to ensure the form rejects it.

Implementation Patterns

Usage Patterns

1. Global Configuration (Recommended for Consistency)

Configure spam protection globally in config/packages/isometriks_spam.yaml:

isometriks_spam:
    timed:
        min: 10 # seconds
        max: 3600
        global: true # Apply to all forms
        message: 'Please wait 10 seconds before submitting.'
    honeypot:
        field: 'email_address'
        use_class: true
        hide_class: 'hidden-spam-field'
        global: true
        message: 'Invalid form submission.'
  • Pros: Centralized control, easier maintenance.
  • Cons: Less granularity; all forms inherit the same settings.

2. Per-Form Overrides (Recommended for Flexibility)

Override global settings on a per-form basis:

// In your controller
$form = $this->createForm(MyType::class, null, [
    'timed_spam' => true,
    'timed_spam_min' => 5, // Override global min
    'honeypot' => false, // Disable honeypot for this form
]);
  • Pros: Tailor protection to form-specific needs (e.g., stricter for contact forms, looser for internal tools).
  • Cons: More configuration overhead.

3. Dynamic Form Types (Advanced)

Use FormEvents::PRE_SET_DATA to dynamically enable/disable spam protection based on runtime logic (e.g., user role):

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
        $data = $event->getData();
        if ($data && $data->isAdmin()) {
            $event->getForm()->add('timed_spam', HiddenType::class, [
                'data' => false, // Disable for admins
            ]);
        }
    });
}

4. Combining Both Methods

Enable both timed spam and honeypot on the same form:

$form = $this->createForm(MyType::class, null, [
    'timed_spam' => true,
    'timed_spam_min' => 7,
    'honeypot' => true,
    'honeypot_field' => 'phone_number',
]);
  • Template Tip: Ensure the honeypot field is hidden via CSS or the hidden-spam-field class:
    <input type="text" name="phone_number" class="hidden-spam-field" />
    

5. Handling Form Errors

Display form errors in Twig:

{% if form.vars.errors is not empty %}
    <div class="alert alert-danger">
        {{ form_errors(form) }}
    </div>
{% endif %}
  • Customize error messages in your form options or globally in isometriks_spam.yaml.

Workflows

1. Form Submission Workflow with Timed Spam

  1. User loads the form → bundle stores the render timestamp in the form.
  2. User submits the form → bundle checks the time elapsed since render.
  3. If elapsed time < min, the form is marked invalid with the configured message.
  4. If valid, proceed with submission.

Edge Case Handling:

  • Page Refresh: If the user refreshes the page, the form’s timestamp is lost, and the form becomes invalid. To mitigate:
    • Set min: 0 to disable timing checks (but keep the feature for other forms).
    • Re-render the form with $form->createView() to reset the timestamp.

2. Honeypot Workflow

  1. User loads the form → honeypot field is rendered (hidden via CSS/class).
  2. User submits the form → bundle checks if the honeypot field is filled.
  3. If filled, the form is marked invalid.
  4. If empty, proceed with submission.

Bot Detection:

  • Bots often fill all fields, including hidden ones. Humans typically ignore hidden fields.

3. AJAX/SPA Integration

For AJAX-heavy forms (e.g., React/Vue frontends), ensure:

  • The form is re-rendered after errors to reset the timestamp (for timed spam).
  • Honeypot fields are dynamically hidden via JavaScript:
    document.querySelectorAll('.hidden-spam-field').forEach(el => {
        el.style.display = 'none';
    });
    

Integration Tips

1. Symfony Form Events

Extend the bundle’s behavior by listening to form events:

use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class CustomSpamSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            FormEvents::PRE_SUBMIT => 'onPreSubmit',
        ];
    }

    public function onPreSubmit(FormEvent $event)
    {
        $form = $event->getForm();
        if ($form->has('custom_field')) {
            // Add custom logic (e.g., rate limiting)
        }
    }
}

Register the subscriber in your bundle or controller.

2. Custom Validation

Combine with Symfony’s validators for layered protection:

use Symfony\Component\Validator\Constraints as Assert;

$builder->add('email', EmailType::class, [
    'constraints' => [
        new Assert\NotBlank(),
        new Assert\Email(),
    ],
]);

3. Logging Spam Attempts

Log invalid submissions for analytics:

use Psr\Log\LoggerInterface;

class SpamLogger implements EventSubscriberInterface
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public static function getSubscribedEvents()
    {
        return [
            FormEvents::SUBMIT => 'onSubmit',
        ];
    }

    public function onSubmit(FormEvent $event)
    {
        if (!$event->getForm()->isValid()) {
            $this->logger->warning('Spam attempt detected', [
                'form' => $event->getForm()->getName(),
                'errors' => $event->getForm()->getErrors(true),
            ]);
        }
    }
}

4. Testing

Test spam protection with:

  • Timed Spam: Mock the current time to simulate rapid submissions.
    $this->container->get('kernel')->getContainer()->set('isometriks_spam.timed_spam_handler', $
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle