vpndetector/laravel-vpn-detector 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

vpndetector/laravel-vpn-detector

Composer 安装命令:

composer require vpndetector/laravel-vpn-detector

包简介

VPN, proxy and Tor detection middleware for Laravel, powered by the IP2Proxy database.

README 文档

README

Block VPN, proxy, and Tor traffic in your Laravel application — powered by the IP2Proxy PX2 database.

PHP Laravel License

What it does

Laravel VPN Detector looks up every incoming request's IP address against a local copy of the IP2Proxy database and can:

  • Block requests from VPN, public proxy, web proxy, or Tor nodes via a drop-in middleware
  • Force a logout when an authenticated user switches to a Tor exit node mid-session
  • Keep the database fresh automatically with a built-in Artisan command and scheduler integration

All lookups are done in-process against your own database — no external API calls at runtime, no latency overhead.

How it works

Incoming request
       │
       ▼
 getClientIp()          Resolves the real IP:
                        CF-Connecting-IP → X-Forwarded-For → request()->ip()
       │
       ▼
 checkProxyType()       SELECT from ip2proxy_px2_ipv4/ipv6
                        WHERE INET_ATON(?) BETWEEN ip_from AND ip_to
       │
       ▼
 proxy_type?            VPN | TOR | PUB | WEB → blocked
                        null or other           → allowed

Requirements

Dependency Version
PHP ^8.3
Laravel ^12.0
MySQL / MariaDB Any version supporting INET_ATON / INET6_ATON
IP2Proxy account Free tier works (PX2 database)

Installation

1. Install via Composer

composer require vpndetector/laravel-vpn-detector

2. Publish config and migrations

# Publish the config file to config/vpn-detector.php
php artisan vendor:publish --tag=vpn-detector-config

# Publish the migrations
php artisan vendor:publish --tag=vpn-detector-migrations

# Run the migrations (creates ip2proxy_px2_ipv4 and ip2proxy_px2_ipv6 tables)
php artisan migrate

3. Set your IP2Proxy token

Add your download token to .env (get it at ip2location.com):

VPN_DETECTOR_IP2PROXY_TOKEN=your-token-here

4. Import the database

php artisan vpn-detector:update-database

This downloads the PX2 CSV files from IP2Proxy (~300 MB each), extracts them, and bulk-imports them into the two database tables. Expect it to take 2–5 minutes on first run.

Architecture

The package is built around three layers:

VpnDetectionServiceInterface
        │
        ├── VpnDetectionService          (base: direct DB lookup)
        │
        └── CachedVpnDetectionService    (decorator: wraps base with a cache layer)
                │
                └── delegates to VpnDetectionService on cache miss

IpLookupResult DTO is returned by checkProxyType() instead of raw stdClass, giving you typed, expressive access to the result:

$result = app(VpnDetectionServiceInterface::class)->checkProxyType('1.2.3.4');

$result->isBlocked();       // true for VPN | TOR | PUB | WEB
$result->isVpn();
$result->isTor();
$result->isPublicProxy();
$result->isWebProxy();
$result->isClean();         // true when proxy_type === '-'
$result->toArray();         // ['ip', 'proxy_type', 'country_code', 'country_name', 'blocked']

The VpnDetector Facade provides a clean static interface:

use VpnDetector\Facades\VpnDetector;

VpnDetector::isUsingProxy();
VpnDetector::checkProxyType('1.2.3.4');
VpnDetector::getClientIp();

Configuration

After publishing, config/vpn-detector.php exposes:

return [
    // IP2Proxy download token (required for database updates)
    'ip2proxy_token' => env('VPN_DETECTOR_IP2PROXY_TOKEN'),

    // HTTP status returned by BlockVpnMiddleware (default: 403)
    'block_status_code' => env('VPN_DETECTOR_BLOCK_STATUS', 403),

    // Cache lookup results (strongly recommended in production)
    'cache' => [
        'enabled' => env('VPN_DETECTOR_CACHE_ENABLED', true),
        'store'   => env('VPN_DETECTOR_CACHE_STORE', null), // null = Laravel default
        'ttl'     => env('VPN_DETECTOR_CACHE_TTL', 3600),   // seconds
    ],

    // Scheduler settings for automatic database refresh
    'schedule' => [
        'frequency'           => env('VPN_DETECTOR_SCHEDULE_FREQUENCY', 'daily'),
        'daily_at'            => env('VPN_DETECTOR_SCHEDULE_AT', '02:00'),
        'timezone'            => env('VPN_DETECTOR_SCHEDULE_TIMEZONE', null),
        'environments'        => ['production', 'staging'],
        'without_overlapping' => true,
        'run_in_background'   => true,
    ],
];

Full list of .env keys: see .env.example.

Usage

Middleware — block VPN/proxy users

Register BlockVpnMiddleware on any route or group:

use VpnDetector\Http\Middleware\BlockVpnMiddleware;

// Single route
Route::get('/checkout', CheckoutController::class)
    ->middleware(BlockVpnMiddleware::class);

// Route group
Route::middleware(BlockVpnMiddleware::class)->group(function () {
    Route::get('/dashboard', DashboardController::class);
    Route::get('/account', AccountController::class);
});

Blocked requests receive a 403 Access via VPN or proxy is not permitted. response.

Action — force-logout Tor users

Use CheckVpnBlocked in your own middleware or controller when you want finer control (e.g. only log out authenticated Tor users):

use VpnDetector\Action\CheckVpnBlocked;

class EnsureNotTor
{
    public function handle(Request $request, Closure $next)
    {
        if (app(CheckVpnBlocked::class)->handle()) {
            return redirect()->route('login')->withErrors('Session terminated for security reasons.');
        }

        return $next($request);
    }
}

The IP is cached in the session so the database is only queried once per unique IP per session.

Service — direct injection

Inject VpnDetectionService (or its interface) anywhere:

use VpnDetector\Contracts\VpnDetectionServiceInterface;

class SecurityController extends Controller
{
    public function __construct(private VpnDetectionServiceInterface $vpn) {}

    public function status(): JsonResponse
    {
        $ip    = $this->vpn->getClientIp();
        $entry = $this->vpn->checkProxyType($ip);

        return response()->json([
            'ip'         => $ip,
            'proxy_type' => $entry?->proxy_type,
            'country'    => $entry?->country_name,
            'blocked'    => $this->vpn->isUsingProxy(),
        ]);
    }
}

Scheduler — keep the database fresh

Add SchedulesVpnDetector to your console kernel to automatically refresh the IP2Proxy data:

use VpnDetector\Traits\SchedulesVpnDetector;

class Kernel extends ConsoleKernel
{
    use SchedulesVpnDetector;

    protected function schedule(Schedule $schedule): void
    {
        // Uses frequency from config/vpn-detector.php (default: daily at 02:00)
        $this->scheduleVpnDetector($schedule);

        // Or use the production preset (daily at 02:00, background, no overlap)
        $this->scheduleVpnDetectorForProduction($schedule);

        // Or pass a custom cron expression
        $this->scheduleVpnDetector($schedule, '0 3 * * 0'); // every Sunday at 03:00
    }
}

Database tables

The package creates two tables populated from the IP2Proxy PX2 dataset:

Column Type Description
ip_from decimal(39,0) Start of IP range (integer representation)
ip_to decimal(39,0) End of IP range
proxy_type varchar(3) VPN, TOR, PUB, WEB, -
country_code char(2) ISO 3166-1 alpha-2
country_name varchar(64) Full country name

Both ip_from and ip_to form a composite primary key, allowing efficient range lookups via INET_ATON / INET6_ATON.

Note: IP2Proxy recommends using the IPv6 table for both IPv4 and IPv6 queries, but coverage is incomplete in practice. This package queries both tables, routing by address family.

Benchmark

The package ships with a self-contained benchmark command. It generates 6 000 000 synthetic rows (3M IPv4 + 3M IPv6) into a temporary SQLite file, then measures lookup latency — no real IP2Proxy database or API token required.

# From the package directory (no host app needed)
php bin/benchmark

# Via Composer script
composer benchmark

# Inside a Laravel app (after installing the package)
php artisan vpn-detector:benchmark

# Options (same for all three entry points)
php bin/benchmark --rows=6000000 --iterations=2000
php bin/benchmark --rows=500000          # quick smoke test
php bin/benchmark --no-cache             # skip the cache scenario
php bin/benchmark --keep-db              # keep SQLite file for inspection

Example output (AMD Ryzen 7, SQLite — MySQL with proper indexes will be significantly faster):

  Laravel VPN Detector -- Benchmark
  ==================================
  Dataset     : 6,000,000 rows  (3,000,000 IPv4 + 3,000,000 IPv6)
  Iterations  : 1,000 per scenario
  Cache       : enabled (scenario 2)

  Generating 3000000 ipv4 rows...  3,000,000 rows in `ip2proxy_px2_ipv4`.
  Generating 3000000 ipv6 rows...  3,000,000 rows in `ip2proxy_px2_ipv6`.

  Test pool  : 6000 IPs (3000 IPv4 + 3000 IPv6)

  -- Scenario 1: Direct DB lookup (no cache) --

 1000/1000 [============================] 100%

+--------------+---------------+
| Metric       | Value         |
+--------------+---------------+
| Iterations   | 1,000         |
| DB hits      | 1,000         |
| DB misses    | 0             |
| Total time   | 58,526.344 ms |
| Average      | 58.526 ms     |
| Min          | 180.6 us      |
| P50 (median) | 57.965 ms     |
| P95          | 110.748 ms    |
| P99          | 114.839 ms    |
| Max          | 136.482 ms    |
+--------------+---------------+

  -- Scenario 2: Warm cache (array store) --

 1000/1000 [============================] 100%

+--------------+----------+
| Metric       | Value    |
+--------------+----------+
| Iterations   | 1,000    |
| DB hits      | 1,000    |
| DB misses    | 0        |
| Total time   | 2.854 ms |
| Average      | 2.9 us   |
| Min          | 2.3 us   |
| P50 (median) | 2.4 us   |
| P95          | 2.7 us   |
| P99          | 2.9 us   |
| Max          | 390.1 us |
+--------------+----------+

  Cache speedup: 20,507.5x faster (avg)
  Benchmark complete.

These numbers use SQLite as the backend. Production MySQL/MariaDB with a real IP2Proxy dataset and proper indexes will have lower raw lookup latency; the cache speedup ratio (~20 000x) holds regardless of the database engine.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-23

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固