stevebauman/location
Retrieve a user’s geolocation from their IP in Laravel. Provides a simple Location facade to get city, region, country, coordinates, timezone and more, with multiple driver support (e.g., IP2Location, IP-API, MaxMind) plus caching and testing helpers.
composer require stevebauman/location
php artisan vendor:publish --provider="Stevebauman\Location\LocationServiceProvider"
.env (example for MaxMind):
LOCATION_DRIVER=maxmind
MAXMIND_LICENSE_KEY=your_license_key_here
use Stevebauman\Location\Facades\Location;
$position = Location::get();
$country = $position->country;
$city = $position->city;
config/location.php – Driver settings, timeouts, and fallback logic.Stevebauman\Location\Facades\Location – Primary entry point for all operations.Stevebauman\Location\Position – Represents location data (e.g., country, latitude, timezone).Location::fake() – Simulate locations for tests or development.Attach location data to every request via middleware:
// app/Http/Middleware/AttachGeoData.php
public function handle($request, Closure $next) {
$request->merge([
'geo' => Location::get()->toArray(),
]);
return $next($request);
}
Register in app/Http/Kernel.php:
protected $middleware = [
// ...
\App\Http\Middleware\AttachGeoData::class,
];
Use the facade in Blade templates or controllers:
// app/Http/Controllers/PageController.php
public function show() {
$position = Location::get();
return view('welcome', [
'currency' => $position->currencyCode,
'language' => $position->countryCode === 'US' ? 'en' : 'es',
]);
}
Configure fallbacks in config/location.php:
'drivers' => [
'maxmind' => [
'enabled' => true,
'fallback' => 'ipinfo',
],
'ipinfo' => [
'enabled' => true,
'fallback' => false,
],
],
Leverage Laravel’s cache to reduce API calls:
$position = Location::get(); // Uses cache by default (TTL: 1 hour)
$position = Location::get(['cache' => false]); // Bypass cache
Simulate locations in tests:
Location::fake([
'country' => 'DE',
'city' => 'Berlin',
'latitude' => 52.5200,
]);
$position = Location::get(); // Returns fake data
Block access based on location:
// app/Http/Middleware/GeoBlock.php
public function handle($request, Closure $next) {
$position = Location::get();
if ($position->countryCode === 'RU') {
abort(403, 'Access denied from your region.');
}
return $next($request);
}
Add methods to the Position model via macros:
// app/Providers/AppServiceProvider.php
use Stevebauman\Location\Position;
public function boot() {
Position::macro('isEu', function () {
$euCountries = ['AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', /* ... */];
return in_array($this->countryCode, $euCountries);
});
}
// Usage:
$position = Location::get();
if ($position->isEu()) {
// Apply EU-specific logic
}
Create a driver for a proprietary API:
// app/Providers/LocationServiceProvider.php
use Stevebauman\Location\Contracts\Driver;
class CustomDriver implements Driver {
public function get($ip = null) {
$response = Http::get('https://api.your-service.com/geo', [
'ip' => $ip ?? request()->ip(),
]);
return new Position($response->json());
}
}
// Register in config/location.php:
'drivers' => [
'custom' => [
'class' => \App\Providers\CustomDriver::class,
],
],
For batch processing (e.g., analytics), fetch multiple IPs:
$ips = ['192.168.1.1', '8.8.8.8'];
$positions = Location::get($ips); // Returns collection of Position objects
MaxMind Database Updates
MAXMIND_AUTO_UPDATE=false in .env and manually update:
php artisan location:update
storage/app/maxmind directory is writable and has enough space (~5MB per database).IPv6 Support
ipapi.co) may not support IPv6.ipinfo or maxmind if needed.Fallback Logic Failures
driver1 falls back to driver2, which falls back to driver1) cause infinite loops.fallback: false for the last driver in the chain:
'drivers' => [
'maxmind' => ['fallback' => 'ipinfo'],
'ipinfo' => ['fallback' => false],
],
Timezone Inconsistencies
timezone field from the Position object and validate it:
$position = Location::get();
if (!in_array($position->timezone, DateTimeZone::listIdentifiers())) {
$position->timezone = 'UTC'; // Fallback
}
Rate Limiting on API Drivers
Location::get(['cache' => true, 'cache_ttl' => 3600]); // Cache for 1 hour
Windows Path Issues
storage/app/maxmind is configured correctly in config/location.php:
'maxmind' => [
'path' => storage_path('app/maxmind'),
],
Check Driver Responses Enable debug mode to log raw responses:
Location::setDebug(true);
$position = Location::get(); // Logs driver responses to Laravel logs
Validate IP Addresses Ensure the IP passed to the driver is valid:
use Stevebauman\Location\Support\IpAddress;
$ip = IpAddress::make('2001:0db8:85a3::8a2e:0370:7334');
$position = Location::get($ip);
Test Fallbacks Manually Disable primary drivers to test fallbacks:
Location::extend('maxmind', function () {
throw new \RuntimeException('Simulate maxmind failure');
});
$position = Location::get(); // Should use fallback
Handle Missing Data
Some drivers may return null for optional fields (e.g., postalCode). Normalize data:
$postal = $position->postalCode ?? 'N/A';
MaxMind License Key
MAXMIND_LICENSE_KEY in .env or config/location.php.Driver-Specific Settings
IPIINFO_TOKEN in .env).IP2LOCATION_DATABASE_PATH).How can I help you explore Laravel packages today?