farit-slv/sypex-geo-bundle
Symfony bundle for Sypex Geo that resolves visitor IP addresses to country, region, and city data using the Sypex Geo database. Provides ready-made services and configuration for fast, offline IP geolocation in PHP applications.
SypexGeo is an IP‑geolocation library backed by a binary .dat database (sxgeo.dat / SxGeoCity.dat). FaritSlv/SypexGeoBundle is a Symfony bundle that wires that library into a container service — there is no Laravel auto‑discovery, so treat it as a plain library plus a thin service wrapper.
Minimal path:
composer require faritslv/sypexgeo-bundle (or just sypexgeo/sypexgeo if you only want the SxGeo class)..dat file somewhere outside public/ (e.g. storage/app/geo/SxGeoCity.dat) and point config at it via an env var, not a hardcoded path.GeoLocaleMiddleware or helper that maps the request IP to country.iso / city.name and sets locale + currency for the rest of the request.$this->app->singleton(GeoResolver::class, fn () => new GeoResolver(
storage_path('app/geo/SxGeoCity.dat')
));
Wrap, don't sprinkle. Put the bundle's service behind your own GeoResolver interface (resolve(string $ip): ?GeoLocation). This lets you swap to MaxMind/ip-api later and lets you fake it in tests.
Cache per IP. Lookups are fast but not free. Cache::remember("geo:{$ip}", now()->addDay(), ...) — but normalize first: hash the IP or use it directly as the key, and skip caching for private ranges.
Fallback chain for unresolvable IPs. Local/dev traffic (127.0.0.1, 10.x, 192.168.x) returns nothing. Have an explicit contract: config‑driven default locale, X-Forwarded-For/CF-Connecting-IP header trust behind a proxy (TrustProxies), and a null return rather than a thrown exception.
Batch enrichment. For backfilling geo onto existing users/orders rows, don't call the resolver inside a model accessor. Chunk jobs (->chunkById(1000)) and write the resolved country/city as plain columns — you want to query and index on those later without re-resolving.
Data refresh as a scheduled task. The bundled DB goes stale quarterly. Keep the file out of git, download it in a deploy step or a scheduled command, write to a temp file, then atomically rename() over the live path so in‑flight requests never see a half‑written DB. Bust any long‑lived cache keys on refresh.
Config over code. Path, load mode, and default locale belong in config/geo.php reading from env. The bundle's own config is Symfony YAML — you'll be translating it, so keep it in one place.
SxGeoCity.dat is large (tens to hundreds of MB depending on edition). Loading it fully into memory per PHP‑FPM worker is fine on a big box and terrible on a small one — check the library's load mode (memory vs. file handle) against your worker count. Under Octane this is loaded once; under classic FPM it's once per request lifecycle.php artisan vendor:publish. Either use the underlying SxGeo class directly or register the bundle's service manually. The Symfony‑style services.yaml config won't apply.TrustProxies configured; behind a load balancer the raw REMOTE_ADDR is your balancer.GeoResolver in the container returning a fixed country; never let the real .dat file into CI.How can I help you explore Laravel packages today?