PHPackages                             mchev/banhammer - 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. mchev/banhammer

ActiveLibrary[Security](/categories/security)

mchev/banhammer
===============

Banhammer for Laravel allows you to ban any Model by key and by IP.

v2.4.3(4mo ago)36693.4k↓19%282MITPHPPHP ^8.0CI passing

Since Feb 11Pushed 4mo ago2 watchersCompare

[ Source](https://github.com/mchev/banhammer)[ Packagist](https://packagist.org/packages/mchev/banhammer)[ Docs](https://github.com/mchev/banhammer)[ GitHub Sponsors](https://github.com/mchev)[ RSS](/packages/mchev-banhammer/feed)WikiDiscussions 2.x Synced 1mo ago

READMEChangelog (10)Dependencies (2)Versions (23)Used By (2)

Banhammer 🔨
===========

[](#banhammer-)

> A simple and powerful ban package for Laravel - ban models, IPs, and countries with ease.

[![Latest Version on Packagist](https://camo.githubusercontent.com/e49924bb79b059f66bed6b63185e15a61b4ac8c2cd675c21cb60fb6fc7210774/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d636865762f62616e68616d6d65722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mchev/banhammer)[![GitHub Tests Action Status](https://github.com/laravel/pint/workflows/tests/badge.svg)](https://github.com/mchev/banhammer/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/d97d2e2b4341906fb3f8c7676a6497735a633cdb1b689bb1822ca10eb92a13c8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d636865762f62616e68616d6d65722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mchev/banhammer)[![Package for laravel](https://camo.githubusercontent.com/236bdc6baa59bc38274092110f30505ea78b0df6d88e2eec7b15da73b6141427/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5061636b616765253230666f722532304c61726176656c2d677265792e7376673f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/mchev/banhammer)

Banhammer allows you to ban any Eloquent model, IP addresses, and even entire countries. Bans can be permanent or temporary with automatic expiration.

---

📋 Table of Contents
-------------------

[](#-table-of-contents)

- [Quick Start](#-quick-start)
- [Features](#-features)
- [Installation](#-installation)
- [Usage Guide](#-usage-guide)
    - [Banning Models](#banning-models)
    - [Banning IPs](#banning-ips)
    - [Country Blocking](#country-blocking)
    - [Middleware](#middleware)
    - [Scheduler](#scheduler)
    - [Events](#events)
- [Advanced Topics](#-advanced-topics)
    - [Metas](#metas)
    - [UUIDs](#uuids)
    - [Upgrading](#upgrading-to-20-from-1x)
- [Development](#-development)

---

🚀 Quick Start
-------------

[](#-quick-start)

```
composer require mchev/banhammer
php artisan vendor:publish --provider="Mchev\Banhammer\BanhammerServiceProvider" --tag="migrations"
php artisan migrate
```

Add the trait to your model:

```
use Mchev\Banhammer\Traits\Bannable;

class User extends Model
{
    use Bannable;
}
```

Ban a user:

```
$user->ban();
```

---

✨ Features
----------

[](#-features)

- ✅ Ban any Eloquent model (User, Team, etc.)
- ✅ Ban IP addresses (single or multiple)
- ✅ Block entire countries
- ✅ Temporary or permanent bans
- ✅ Automatic expiration handling
- ✅ Middleware protection
- ✅ Event system
- ✅ Metadata support
- ✅ Laravel 9, 10, 11 &amp; 12 compatible

---

📦 Installation
--------------

[](#-installation)

### Requirements

[](#requirements)

- PHP 8.0+
- Laravel 9, 10, 11 or 12

### Setup

[](#setup)

1. **Install the package:**

    ```
    composer require mchev/banhammer
    ```
2. **Publish and run migrations:**

    ```
    php artisan vendor:publish --provider="Mchev\Banhammer\BanhammerServiceProvider" --tag="migrations"
    php artisan migrate
    ```
3. **Publish config (optional):**

    ```
    php artisan vendor:publish --provider="Mchev\Banhammer\BanhammerServiceProvider" --tag="config"
    ```

    > 💡 The config file allows you to customize table name, model, fallback URLs, and more.

---

📖 Usage Guide
-------------

[](#-usage-guide)

### Banning Models

[](#banning-models)

#### Make a Model Bannable

[](#make-a-model-bannable)

Add the `Bannable` trait to any model:

```
use Mchev\Banhammer\Traits\Bannable;

class User extends Model
{
    use Bannable;
}
```

> 💡 You can add the trait to multiple models (User, Team, Group, etc.)

#### Basic Operations

[](#basic-operations)

ActionCode**Ban a user**`$user->ban()`**Ban with expiration**`$user->banUntil('2 days')`**Check if banned**`$user->isBanned()`**Check if not banned**`$user->isNotBanned()`**Unban**`$user->unban()`#### Advanced Ban Options

[](#advanced-ban-options)

```
$user->ban([
    'comment' => "You've been evil",
    'ip' => "8.8.8.8",
    'expired_at' => Carbon::now()->addDays(7),
    'created_by_type' => 'App\Models\Admin',
    'created_by_id' => auth()->id(),
    'metas' => [
        'route' => request()->route()->getName(),
        'user_agent' => request()->header('user-agent')
    ]
]);
```

> ⚠️ Without `expired_at`, the ban is permanent.

#### Query Scopes

[](#query-scopes)

```
// Get banned users
$bannedUsers = User::banned()->get();

// Get non-banned users
$activeUsers = User::notBanned()->get();

// Alternative syntax
$activeUsers = User::banned(false)->get();
```

#### List Bans

[](#list-bans)

```
// All bans for a model
$bans = $user->bans()->get();

// Only expired bans
$expired = $user->bans()->expired()->get();

// Active bans
$active = $user->bans()->notExpired()->get();
```

---

### Banning IPs

[](#banning-ips)

#### Basic Operations

[](#basic-operations-1)

```
use Mchev\Banhammer\IP;

// Ban single IP
IP::ban("8.8.8.8");

// Ban multiple IPs
IP::ban(["8.8.8.8", "4.4.4.4", "1.1.1.1"]);

// Ban with expiration
IP::ban("8.8.8.8", [], now()->addMinutes(10));

// Ban with metadata
IP::ban("8.8.8.8", [
    'reason' => 'spam',
    'severity' => 'high'
]);
```

#### Unban IPs

[](#unban-ips)

```
// Unban single IP
IP::unban("8.8.8.8");

// Unban multiple IPs
IP::unban(["8.8.8.8", "4.4.4.4"]);
```

#### Check &amp; List Banned IPs

[](#check--list-banned-ips)

```
// Check if IP is banned
IP::isBanned("8.8.8.8"); // bool

// Get all banned IPs
$ips = IP::banned()->get(); // Collection
$ips = IP::banned()->pluck('ip')->toArray(); // Array
```

---

### Country Blocking

[](#country-blocking)

Block access from specific countries automatically.

#### Configuration

[](#configuration)

1. **Enable country blocking** in `config/ban.php`:

    ```
    'block_by_country' => true,
    ```
2. **Specify blocked countries**:

    ```
    'blocked_countries' => ['FR', 'ES', 'US'],
    ```

That's it! The middleware will automatically block requests from these countries.

> ⚠️ **Rate Limit Notice:** The free version of ip-api.com has a limit of 45 requests/minute. Exceeding this will result in 429 errors until the limit resets.

> 💡 **Want to improve this?** If you have suggestions for better geolocation services or want to contribute improvements, please [open an issue](https://github.com/mchev/banhammer/issues) or submit a [pull request](https://github.com/mchev/banhammer/pulls).

---

### Middleware

[](#middleware)

Protect your routes with ban middleware:

#### Available Middleware

[](#available-middleware)

MiddlewareDescription`auth.banned`Blocks banned users`ip.banned`Blocks banned IPs`logout.banned`Logs out and blocks banned users/IPs#### Usage

[](#usage)

```
// Single route
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth.banned');

// Route group
Route::middleware(['auth.banned'])->group(function () {
    Route::get('/profile', [ProfileController::class, 'index']);
    Route::get('/settings', [SettingsController::class, 'index']);
});

// Block IPs on all routes
// Add to app/Http/Kernel.php:
protected $middleware = [
    // ...
    \Mchev\Banhammer\Middleware\IPBanned::class,
];
```

> 💡 **Tip:** `logout.banned` includes the functionality of both `auth.banned` and `ip.banned`, so you don't need to use them together.

---

### Scheduler

[](#scheduler)

Banhammer automatically deletes expired bans using Laravel's scheduler.

#### Setup

[](#setup-1)

> ⚠️ **Important:** You must have a cron job running Laravel's scheduler:
>
> ```
> * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
> ```
>
>
>
> See: [Laravel Scheduler Docs](https://laravel.com/docs/scheduling#running-the-scheduler)

#### Configuration

[](#configuration-1)

By default, the `banhammer:unban` command runs **every minute**. You can customize this:

**Disable automatic scheduler:**

```
// config/ban.php
'scheduler_enabled' => false,
```

Or via environment:

```
BANHAMMER_SCHEDULER_ENABLED=false
```

**Change frequency:**

```
// config/ban.php
'scheduler_periodicity' => 'everyFiveMinutes', // or 'hourly', 'daily', etc.
```

Or via environment:

```
BANHAMMER_SCHEDULER_PERIODICITY=everyFiveMinutes
```

**Available frequencies:** `everyMinute`, `everyFiveMinutes`, `everyTenMinutes`, `everyFifteenMinutes`, `everyThirtyMinutes`, `hourly`, `daily`, `twiceDaily`, etc.

---

### Events

[](#events)

Listen to ban/unban events:

```
use Mchev\Banhammer\Events\ModelWasBanned;
use Mchev\Banhammer\Events\ModelWasUnbanned;

Event::listen(ModelWasBanned::class, function ($event) {
    // User was banned
    Log::info("User {$event->ban->bannable->id} was banned");
});

Event::listen(ModelWasUnbanned::class, function ($event) {
    // User was unbanned
    Log::info("User {$event->ban->bannable->id} was unbanned");
});
```

---

🔧 Advanced Topics
-----------------

[](#-advanced-topics)

### Metas

[](#metas)

Store additional data with bans:

```
// Set meta
$ban->setMeta('username', 'Jane');
$ban->setMeta('reason', 'spam');

// Get meta
$ban->getMeta('username'); // 'Jane'

// Check if meta exists
$ban->hasMeta('username'); // true

// Remove meta
$ban->forgetMeta('username');
```

#### Filter by Meta

[](#filter-by-meta)

```
// Find bans with specific meta
IP::banned()->whereMeta('username', 'Jane')->get();
$user->bans()->whereMeta('reason', 'spam')->get();
User::whereBansMeta('username', 'Jane')->get();
```

#### Ban with Metas

[](#ban-with-metas)

```
// When banning
$user->ban([
    'metas' => [
        'route' => request()->route()->getName(),
        'user_agent' => request()->header('user-agent')
    ]
]);

IP::ban("8.8.8.8", [
    'reason' => 'spam',
    'severity' => 'high'
]);
```

---

### UUIDs

[](#uuids)

To use UUIDs instead of auto-incrementing IDs:

1. **Publish migrations:**

    ```
    php artisan vendor:publish --provider="Mchev\Banhammer\BanhammerServiceProvider" --tag="migrations"
    ```
2. **Edit the migration:**

    ```
    - $table->id();
    + $table->uuid('id');
    ```
3. **Create a custom Ban model:**

    ```
    namespace App\Models;

    use Illuminate\Database\Eloquent\Concerns\HasUuids;
    use Mchev\Banhammer\Models\Ban as BanhammerBan;

    class Ban extends BanhammerBan
    {
        use HasUuids;
    }
    ```
4. **Update config:**

    ```
    // config/ban.php
    'model' => \App\Models\Ban::class,
    ```

---

### Upgrading To 2.0 from 1.x

[](#upgrading-to-20-from-1x)

1. **Update composer.json:**

    ```
    "require": {
        "mchev/banhammer": "^2.0"
    }
    ```
2. **Update the package:**

    ```
    composer update mchev/banhammer
    ```
3. **Update configuration:**

    ```
    # Backup your current config
    cp config/ban.php config/ban.php.backup

    # Republish config
    php artisan vendor:publish --provider="Mchev\Banhammer\BanhammerServiceProvider" --tag="config" --force

    # Review and merge any custom settings
    ```

---

🛠️ Development
--------------

[](#️-development)

### Commands

[](#commands)

```
# Manually delete expired bans
php artisan banhammer:unban

# Permanently delete all expired bans
php artisan banhammer:clear
```

### Programmatic Usage

[](#programmatic-usage)

```
use Mchev\Banhammer\Banhammer;

// Delete expired bans
Banhammer::unbanExpired();

// Permanently delete expired bans
Banhammer::clear();
```

### Testing

[](#testing)

```
composer test
```

---

🤝 Contributing
--------------

[](#-contributing)

We welcome contributions! Please:

- Open issues for bug reports or feature requests
- Submit pull requests (mark as "ready for review")
- Ensure all tests pass
- Follow Laravel coding standards

> 💡 Pull requests in "draft" state will be closed after a few days of inactivity.

---

🙏 Credits
---------

[](#-credits)

Inspired by [laravel-ban](https://github.com/cybercog/laravel-ban) from [cybercog](https://github.com/cybercog).

---

📄 License
---------

[](#-license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

56

—

FairBetter than 98% of packages

Maintenance75

Regular maintenance activity

Popularity52

Moderate usage in the ecosystem

Community23

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 93.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~53 days

Recently: every ~73 days

Total

21

Last Release

134d ago

Major Versions

v1.x-dev → v2.0.02024-01-07

### Community

Maintainers

![](https://www.gravatar.com/avatar/1a4fc05da542c49e0d7d3aa2bd8c077c80c502ad2beeee5da4d5ed398e5de296?d=identicon)[mchev](/maintainers/mchev)

---

Top Contributors

[![mchev](https://avatars.githubusercontent.com/u/5514329?v=4)](https://github.com/mchev "mchev (149 commits)")[![KieranLProctor](https://avatars.githubusercontent.com/u/25559341?v=4)](https://github.com/KieranLProctor "KieranLProctor (4 commits)")[![mepsd](https://avatars.githubusercontent.com/u/45997529?v=4)](https://github.com/mepsd "mepsd (3 commits)")[![onlime](https://avatars.githubusercontent.com/u/2759561?v=4)](https://github.com/onlime "onlime (2 commits)")[![dannydinges](https://avatars.githubusercontent.com/u/1787211?v=4)](https://github.com/dannydinges "dannydinges (1 commits)")[![YazeedAlsaif](https://avatars.githubusercontent.com/u/3579831?v=4)](https://github.com/YazeedAlsaif "YazeedAlsaif (1 commits)")

---

Tags

accessautorizationbanblockcountriesiplaravelmiddlewarepackagephprestrictsecuritytraituserlaravelIPcountrybanbannablemchevbans-for-laravel

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mchev-banhammer/health.svg)

```
[![Health](https://phpackages.com/badges/mchev-banhammer/health.svg)](https://phpackages.com/packages/mchev-banhammer)
```

###  Alternatives

[hibit-dev/geodetect

Automatically detect user's geo data based on their IP address

2319.5k](/packages/hibit-dev-geodetect)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
