torann/geoip
GeoIP for Laravel resolves visitor location and currency from IP addresses via configurable services. Integrates with Laravel, supports multiple drivers/providers, and lets you publish config to choose and tune your lookup service.
Installation:
composer require torann/geoip
php artisan vendor:publish --provider="Torann\GeoIP\GeoIPServiceProvider"
This publishes the config file (config/geoip.php) and creates a default service binding.
Configure a Provider:
Edit config/geoip.php to set your preferred provider (e.g., ipdata.co or maxmind). Example for ipdata.co:
'providers' => [
'ipdata' => [
'enabled' => true,
'api_key' => env('IPDATA_API_KEY'),
],
],
First Use Case: Resolve geolocation data in a controller or middleware:
use Torann\GeoIP\Facades\GeoIP;
$location = GeoIP::getLocation();
$country = $location->countryCode; // e.g., 'US'
$currency = $location->currency; // e.g., 'USD'
Middleware Integration (Optional):
Add GeoIPMiddleware to app/Http/Kernel.php to resolve geolocation for every request:
protected $middleware = [
\Torann\GeoIP\Middleware\GeoIPMiddleware::class,
];
Access the location via $request->geoip.
Request-Level Geolocation:
Use GeoIPMiddleware to attach geolocation data to every request:
// In a controller
public function show(Request $request) {
$country = $request->geoip->countryCode;
// Use $country for dynamic content, routing, or analytics
}
Service Layer Integration:
Inject the GeoIP facade or service into services for reusable logic:
class PricingService {
protected $geoIP;
public function __construct(\Torann\GeoIP\Facades\GeoIP $geoIP) {
$this->geoIP = $geoIP;
}
public function getLocalizedPrice() {
$currency = $this->geoIP->getLocation()->currency;
// Fetch price based on $currency
}
}
Caching Strategies: Leverage Laravel’s cache for high-traffic applications:
// Cache for 1 hour
$location = GeoIP::getLocation()->remember(3600);
Or configure provider-specific caching in config/geoip.php:
'providers' => [
'ipdata' => [
'cache' => true,
'cache_ttl' => 3600,
],
],
Event-Driven Extensions: Listen for geolocation resolution events to trigger side effects:
// In EventServiceProvider
protected $listen = [
'geoip.resolved' => [
\App\Listeners\LogGeoIP::class,
\App\Listeners\UpdateAnalytics::class,
],
];
Dynamic Provider Switching: Change providers at runtime via config or environment variables:
// config/geoip.php
'default_provider' => env('GEOIP_PROVIDER', 'ipdata'),
Geotargeted Routing: Redirect users based on location in middleware:
public function handle(Request $request, Closure $next) {
if ($request->geoip->countryCode === 'GB') {
return redirect()->route('uk.home');
}
return $next($request);
}
Localization: Set locale or currency dynamically:
app()->setLocale($request->geoip->language);
app()->setLocaleResolver(new GeoIPLocaleResolver($request->geoip));
Fraud Detection: Block high-risk regions or VPNs:
$riskyCountries = ['RU', 'CN', 'IR'];
if (in_array($request->geoip->countryCode, $riskyCountries)) {
abort(403, 'Access denied from your region.');
}
A/B Testing: Segment users by region for experiments:
$experiment = Experiment::where('regions', 'like', '%'.$request->geoip->countryCode.'%')->first();
Environment Variables:
Store API keys in .env and reference them in config/geoip.php:
IPDATA_API_KEY=your_api_key_here
MAXMIND_LICENSE_KEY=your_license_key
Testing:
Mock geolocation data in tests using the GeoIP facade:
GeoIP::shouldReceive('getLocation')->andReturn(new \Torann\GeoIP\Location(['countryCode' => 'US']));
Provider-Specific Features: Enable provider-specific features (e.g., MaxMind’s ISP data):
$location = GeoIP::getLocation(['include' => ['isp', 'domain']]);
Fallback Providers:
Configure fallback providers in config/geoip.php:
'providers' => [
'ipdata' => ['enabled' => true],
'ipapi' => ['enabled' => true, 'fallback' => true],
],
Missing Configuration: After upgrading to v3.0+, ensure you publish the config file:
php artisan vendor:publish --provider="Torann\GeoIP\GeoIPServiceProvider"
Failure to do so will result in a BindingResolutionException.
API Key Limits: Free tiers of providers (e.g., ipdata.co) have request limits. Monitor usage and upgrade if needed.
IPv6 Support: Some providers may not fully support IPv6. Test with IPv6 addresses if your audience includes them.
Caching Invalidation:
Cached geolocation data may become stale if the IP is reassigned. Adjust cache_ttl based on your use case.
Middleware Order:
Place GeoIPMiddleware early in the middleware stack to ensure geolocation data is available for subsequent middleware.
Provider Deprecation: Providers like MaxMind may deprecate free services. Monitor the package for updates and switch providers proactively.
Log Provider Responses:
Enable debug mode in config/geoip.php:
'debug' => true,
This logs raw API responses to storage/logs/geoip.log.
Check IP Resolution: Verify the IP being resolved matches the request:
$ip = $request->ip();
$location = GeoIP::forIp($ip)->getLocation();
Provider-Specific Errors: Handle provider-specific exceptions:
try {
$location = GeoIP::getLocation();
} catch (\Torann\GeoIP\Exceptions\ProviderException $e) {
// Fallback logic or retry with another provider
}
Cache Issues: Clear the cache if geolocation data appears stale:
php artisan cache:clear
Use Facades Sparingly: Prefer dependency injection for better testability:
// Instead of:
$location = GeoIP::getLocation();
// Do:
public function __construct(\Torann\GeoIP\Facades\GeoIP $geoIP) {
$this->geoIP = $geoIP;
}
Leverage Laravel’s Cache Tags: Tag cached geolocation data for bulk invalidation:
$location = GeoIP::getLocation()->rememberForever('geoip:'.$request->ip());
Cache::tags(['geoip'])->flush(); // Invalidate all geoip-tagged cache
Batch Processing: For CLI jobs or batch processing, disable caching:
$location = GeoIP::getLocation(['cache' => false]);
Custom Location Attributes:
Extend the Location model to add custom attributes:
namespace App\Extensions;
use Torann\GeoIP\Location as BaseLocation;
class Location extends BaseLocation {
public function getRegionName() {
return $this->region ?? $this->countryName;
}
}
Then bind your custom class in a service provider:
GeoIP::macro('getLocation', function () {
return new \App\Extensions\Location(GeoIP::resolve());
});
Performance Optimization: For high-traffic sites, use a local MaxMind database instead of API calls:
'providers' => [
'maxmind' => [
'enabled' => true,
'database' => storage_path('app/GeoLite2-Country.mmdb'),
],
],
Compliance Notes:
How can I help you explore Laravel packages today?