Weave 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

Ip2Proxy Laravel Laravel Package

ip2location/ip2proxy-laravel

Laravel integration for IP2Proxy, letting you detect proxy, VPN, Tor, and other anonymizing connections from visitor IPs using IP2Location IP2Proxy databases. Includes service provider, configuration, and simple query helpers.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up.

composer require ip2location/ip2proxy-laravel
php artisan vendor:publish --provider="IP2Proxy\IP2ProxyServiceProvider"

Publishing gives you config/ip2proxy.php, whose only meaningful key is the path to the binary database. Then:

  1. Get a BIN database. This package is a local database reader, not an API client. Nothing works until you have an .BIN file. Download IP2Proxy LITE (free, PX1–PX11, one file per proxy-type tier) from IP2Location, or use a licensed commercial database. The LITE files are refreshed monthly — treat the download as a deploy artefact, not a repo file.
  2. Place it outside the web root (storage/app/ip2proxy/IP2PROXY-LITE-PX*.BIN) and point the config at an absolute path, ideally via .env:
// config/ip2proxy.php
'database' => env('IP2PROXY_DATABASE', storage_path('app/ip2proxy/ip2proxy.bin')),
  1. Query it. The package exposes a facade; the underlying class is the ip2proxy/ip2proxy-php reader:
use IP2Proxy\IP2Proxy; // or the registered facade alias

$record = IP2Proxy::get($request->ip(), 'ALL'); // array/object of fields

Where to look first. The facade is thin — almost all real behaviour lives in ip2proxy/ip2proxy-php (the vendor library in vendor/ip2location/). When something behaves unexpectedly, read that class, not the Laravel wrapper. The wrapper's surface is: service provider binding, a config file, and a facade root. That's it.

First use case. The one that pays for itself fastest: gate registration, login, password-reset and checkout endpoints on a proxy check, and log the verdict rather than blocking outright for the first two weeks. You want to see your false-positive rate against real traffic before you start rejecting customers. A corporate VPN user who can't log in is a support ticket; a TOR exit that completes a card-testing signup is fraud.

Implementation Patterns

Wrap the facade in your own service — never call it from controllers. A one-class ProxyIntelligence service that takes an IP, returns a small typed DTO (isProxy, proxyType, countryCode, usageType, threat), and swallows library exceptions gives you one place to swap providers, add caching, and fake in tests.

final class ProxyLookup
{
    public function check(?string $ip): ProxyVerdict
    {
        if (! $ip || ! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            return ProxyVerdict::unknown(); // don't even ask the DB
        }
        try {
            $r = IP2Proxy::get($ip, 'ALL');
            return ProxyVerdict::fromRecord($r);
        } catch (\Throwable $e) {
            report($e);
            return ProxyVerdict::unknown(); // fail open
        }
    }
}

Middleware, with a risk tier. Don't apply proxy blocking globally. Use a named middleware on the handful of routes where it matters (auth, register, checkout) and a config-driven action per route group: log, challenge (force 2FA/CAPTCHA), or block. Middleware that 403s everything is the classic day-one mistake.

Cache by IP, not by request. A single page load can hit the check several times (middleware, a validation rule, a Blade partial). Memoize per-request in a container-scoped array, and put a short-TTL cache (Cache::remember("ip2proxy:{$ip}", now()->addHours(6), ...)) in front of it for anything repeated across requests. Proxy status for an IP is stable enough that hours of TTL cost you nothing.

Store the verdict, not just the decision. On user creation, persist the proxy fields you got at signup time (is_proxy, proxy_type, country_code, asn) on the user/order row. Later fraud review can then reason over historical data without re-querying, and it survives a BIN database upgrade changing its answer.

Run batch work in a job, never in a request loop. Backfilling 50k signups or scanning an access log is a console command/chunked job. The BIN reader is fast per lookup, but a web request that loops over thousands of IPs will blow your response time and memory.

Deploy the database, don't commit it. Add a deploy step that downloads the current BIN to storage/app/ip2proxy/ and atomically swaps it (mv into place). Keep the previous file so rollback is a symlink flip. If you commit a 40–100 MB binary to git you will regret it in clone times and diffs forever.

For tests, bind a fake. Swap the container binding or IP2Proxy::shouldReceive() in feature tests. Your CI should never need a real BIN file, and never depend on a specific IP's real-world classification (those change monthly).

Gotchas and Tips

  • The LITE databases are field-limited, and asking for a missing field throws. 'ALL' on a PX1 database will not return threat or provider; the underlying library raises an exception when a requested field isn't present in the BIN. Pick the database tier that matches the fields you actually read, and catch IP2ProxyException around every call. This is the #1 surprise.
  • isProxy return type is a truthiness trap. Depending on version it comes back as 'YES'/'NO' strings, 1/0, or similar. Never do === true. Normalise once, in your wrapper: in_array($value, [true, 1, '1', 'YES'], true).
  • Private, reserved, and malformed IPs. Behind a load balancer $request->ip() may be 10.x, 172.16.x, or 127.0.0.1 — the database has no answer. Validate and short-circuit before the lookup, and make sure TrustProxies is configured or every check runs against your LB's address instead of the customer's.
  • IPv6 needs a separate database. The default LITE files are IPv4-only; you need the -IPV6 variant to answer for v6 clients. If you're dual-stack, you need both or you'll silently get "not a proxy" for half your traffic.
  • Config caching and relative paths. env() works in config/ip2proxy.php only because config is built before caching — but after config:cache the value is frozen. Always use absolute paths (storage_path()/base_path()); a relative path resolves against the current working directory and will work in php artisan serve and break under a queue worker or Octane.
  • Octane / long-running workers. The BIN reader holds the file in memory per process. That's great for throughput (no per-request init), but it means a deployed database swap is invisible until workers restart, and memory usage is multiplied by worker count. Restart workers as part of the deploy after swapping the file.
  • BIN file staleness is your silent failure mode. A six-month-old database quietly misses new VPN providers. Put the refresh on a calendar, log the file's mtime at boot, and alert if it's older than ~60 days.
  • Fail open, always. A missing/corrupt BIN file must not take down login. Catch everything, return "unknown", and alert on the exception rate. Only fail closed if you've deliberately decided a proxy-check outage should halt signups.
  • Measure false positives before enforcing. Corporate VPNs, privacy-conscious developers, and some mobile carriers look like proxies. Ship in log-only mode, compare against your chargeback/fraud outcomes for a few weeks, then enforce. Per-route thresholds beat a global switch.
  • Don't ship raw verdicts to the client. proxyType, asn, and threat are useful to attackers for probing what you detect. Keep them server-side; log them.
  • Extension points are limited by design. The package is a facade over a binary reader — there's no driver interface to implement. If you need a remote API or a second provider, put it behind your ProxyLookup abstraction rather than trying to extend the vendor class.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle