PHPackages                             irabbi360/laravel-goal-captcha - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. irabbi360/laravel-goal-captcha

ActiveLibrary[Security](/categories/security)

irabbi360/laravel-goal-captcha
==============================

A football goal slider CAPTCHA system for Laravel — anti-bot, mobile-friendly, themeable.

014↓100%PHPCI failing

Since May 28Pushed 1w agoCompare

[ Source](https://github.com/irabbi360/laravel-goal-captcha)[ Packagist](https://packagist.org/packages/irabbi360/laravel-goal-captcha)[ RSS](/packages/irabbi360-laravel-goal-captcha/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

⚽ GoalCaptcha — Laravel Football Goal Slider CAPTCHA
====================================================

[](#-goalcaptcha--laravel-football-goal-slider-captcha)

[![Tests](https://github.com/irabbi360/laravel-goal-captcha/actions/workflows/tests.yml/badge.svg)](https://github.com/irabbi360/laravel-goal-captcha/actions)[![Latest Version](https://camo.githubusercontent.com/0527157dcc30eb3af9f2870e041aae81fee9c6cb22aaad19b6abf579b8b8e372/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6972616262693336302f6c61726176656c2d676f616c2d636170746368612e737667)](https://packagist.org/packages/irabbi360/laravel-goal-captcha)[![License](https://camo.githubusercontent.com/c4fc78f9aee8aeb8e66ae271e459ce0976805c4c04536dc64dc7ad483fa7fda1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6972616262693336302f6c61726176656c2d676f616c2d636170746368612e737667)](LICENSE.md)

A production-ready, anti-bot football-goal slider CAPTCHA for Laravel — built like **Sanctum / Telescope / Pulse**.

Users drag a football into the goal net. The backend verifies alignment, drag speed, and human motion patterns. Bots are rejected.

---

Features
--------

[](#features)

- ⚽ **Football goal canvas scene** — randomised stadium, goalkeeper, weather, decoys
- 🖱 **Drag slider interaction** — mouse + touch, fully accessible (keyboard)
- 🤖 **Anti-bot motion analysis** — speed variance, jerk, micro-corrections, interval consistency
- 🔒 **Replay attack protection** — token deleted after first use
- ⏱ **Auto-expiring challenges** — configurable TTL (default 2 min)
- 🎨 **Theme system** — football theme included, extendable
- 📱 **Mobile responsive** — works on touch devices
- 🧩 **Blade component** ``
- 🖼 **Vue 3 component** ``
- 🔌 **Inertia / SPA / Nuxt** compatible
- 🗃 **Pluggable storage** — Redis, Cache (array/file/database)
- 🎉 **Event system** — `CaptchaGenerated`, `CaptchaVerified`, `CaptchaFailed`

---

Installation
------------

[](#installation)

```
composer require irabbi360/laravel-goal-captcha
```

Publish assets and config:

```
php artisan goal-captcha:install
```

---

Quick Start — Blade
-------------------

[](#quick-start--blade)

Add the component anywhere in your form:

```

    @csrf

    Login

```

Protect the route with the middleware:

```
Route::middleware('goal-captcha')->post('/login', LoginController::class);
```

---

Quick Start — Vue 3 / Inertia
-----------------------------

[](#quick-start--vue-3--inertia)

```
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'
import goalCaptcha from './vendor/irabbi360/laravel-goal-captcha/vite-plugin.js'

export default defineConfig({
    plugins: [
        laravel({ input: ['resources/js/app.js'] }),
        vue(),
        goalCaptcha(),   // ← adds the alias automatically
    ],
})
```

```

import { GoalCaptcha } from '@irabbi360/goal-captcha'
import '@irabbi360/goal-captcha/style'
const token = ref(null)

```

---

Vue Plugin
----------

[](#vue-plugin)

```
import GoalCaptchaPlugin from '@irabbi360/goal-captcha'

createApp(App)
  .use(GoalCaptchaPlugin, {
    generateUrl: '/_goal_captcha/generate',
    verifyUrl:   '/_goal_captcha/verify',
    theme:       'football',
    difficulty:  'medium',
  })
  .mount('#app')
```

---

API Endpoints
-------------

[](#api-endpoints)

MethodURLDescriptionPOST`/_goal_captcha/generate`Returns a CAPTCHA challengePOST`/_goal_captcha/verify`Verifies submission, returns one-time token---

Configuration
-------------

[](#configuration)

```
return [
    'driver'                   => 'cache',    // 'redis' | 'cache'
    'expire'                   => 120,
    'tolerance'                => 12,
    'min_drag_time'            => 400,
    'max_attempts'             => 5,
    'theme'                    => 'football',
    'difficulty'               => 'medium',   // 'easy' | 'medium' | 'hard'
    'enable_behavior_analysis' => true,
];
```

---

Events
------

[](#events)

```
Event::listen(CaptchaVerified::class, fn($e) => logger('solved', ['id' => $e->captcha->captchaId]));
```

EventWhen`CaptchaGenerated`Challenge created`CaptchaVerified`Human confirmed`CaptchaFailed`Verification rejected---

Architecture
------------

[](#architecture)

```
src/
├── GoalCaptchaServiceProvider.php
├── LaravelGoalCaptcha.php
├── Contracts/          CaptchaStoreInterface, MotionAnalyzerInterface
├── DTO/                CaptchaData, VerificationData
├── Events/             Generated, Verified, Failed
├── Exceptions/         Expired, VerificationFailed, TooManyAttempts
├── Facades/            GoalCaptcha
├── Http/               Controllers, Middleware, Requests
├── Services/           Generator, Verifier, MotionAnalyzer, SceneBuilder, TokenManager
└── Support/Stores/     CacheStore, RedisStore

resources/js/
├── components/         GoalCaptcha.vue, GoalCanvas.vue, GoalSlider.vue, SuccessAnimation.vue
├── composables/        useGoalCaptcha.js
├── canvas/             renderer.js, animation.js, physics.js
├── utils/              motionTracker.js
└── index.js            Vue plugin + Blade auto-mount

```

```

```

```

    @csrf

    {{-- CAPTCHA mounts here; on solve it injects a hidden captcha_token input --}}

    Submit

document.addEventListener('DOMContentLoaded', () => {
    const { initMount } = window.GoalCaptcha

    initMount('#goal-captcha', {
        fieldName: 'captcha_token',   // hidden input name injected into the form
    })

    // Enable submit only after CAPTCHA is solved
    document.getElementById('goal-captcha').addEventListener('gc:verified', () => {
        document.getElementById('submit-btn').disabled = false
    })
})

```

```
