# stevebauman/location Location is a Laravel package that retrieves a visitor's geographic location from their IP address using various geolocation services. It supports both online API services (ip-api.com, ipinfo.io, ipdata.co, etc.) and local database lookups (MaxMind GeoLite2), providing flexibility between real-time accuracy and offline reliability. The package features a clean facade-based API, automatic driver fallback chains for reliability, built-in testing utilities, and comprehensive location data including country, region, city, coordinates, timezone, and currency information. It integrates seamlessly with Laravel's service container and configuration system, making it easy to swap between providers or configure API tokens. ## Location Facade - Get Location by IP The primary entry point for retrieving location data. The `Location::get()` method accepts an optional IP address parameter and returns a `Position` object containing location details, or `false` if the location cannot be determined. When no IP is provided, it automatically uses the current request's IP address. ```php use Stevebauman\Location\Facades\Location; // Get location from current request IP if ($position = Location::get()) { echo $position->countryName; // "United States" echo $position->countryCode; // "US" echo $position->regionName; // "California" echo $position->regionCode; // "CA" echo $position->cityName; // "Mountain View" echo $position->zipCode; // "94043" echo $position->latitude; // "37.4056" echo $position->longitude; // "-122.0775" echo $position->timezone; // "America/Los_Angeles" echo $position->currencyCode; // "USD" echo $position->driver; // "Stevebauman\Location\Drivers\IpApi" echo $position->ip; // "66.102.0.0" } else { echo "Could not determine location"; } // Get location for a specific IP address $position = Location::get('8.8.8.8'); // Convert position to array $data = $position->toArray(); // [ // 'ip' => '8.8.8.8', // 'driver' => 'Stevebauman\Location\Drivers\IpApi', // 'countryName' => 'United States', // 'countryCode' => 'US', // 'regionCode' => 'CA', // 'regionName' => 'California', // 'cityName' => 'Mountain View', // 'zipCode' => '94043', // 'latitude' => '37.4056', // 'longitude' => '-122.0775', // 'timezone' => 'America/Los_Angeles', // 'currencyCode' => 'USD', // ... // ] ``` ## Position Class - Create and Inspect Location Objects The `Position` class is a data transfer object containing all location attributes. Use `Position::make()` to create instances with custom attributes, and `isEmpty()` to check if the position contains meaningful location data. ```php use Stevebauman\Location\Position; // Create a position with specific attributes $position = Position::make([ 'countryName' => 'Canada', 'countryCode' => 'CA', 'regionName' => 'Ontario', 'regionCode' => 'ON', 'cityName' => 'Toronto', 'zipCode' => 'M5V 1J2', 'latitude' => '43.6532', 'longitude' => '-79.3832', 'timezone' => 'America/Toronto', 'currencyCode' => 'CAD', ]); echo $position->countryName; // "Canada" echo $position->cityName; // "Toronto" // Check if position has location data (excludes ip and driver fields) if ($position->isEmpty()) { echo "No location data available"; } // Convert to array for JSON responses or storage $array = $position->toArray(); ``` ## Location::fake() - Testing Utilities The `Location::fake()` method allows you to mock location responses in tests. You can specify exact IP addresses, use wildcards for pattern matching, or return the same position for all requests. When no matches are found, `Location::get()` returns `false`. ```php use Stevebauman\Location\Position; use Stevebauman\Location\Facades\Location; // Fake a specific IP address Location::fake([ '127.0.0.1' => Position::make([ 'countryName' => 'United States', 'countryCode' => 'US', 'cityName' => 'New York', 'regionName' => 'New York', ]), ]); $position = Location::get('127.0.0.1'); echo $position->countryName; // "United States" echo $position->cityName; // "New York" // Use wildcard to match any IP Location::fake([ '*' => Position::make([ 'countryName' => 'Test Country', 'countryCode' => 'TC', ]), ]); $position = Location::get('192.168.1.1'); // Returns Test Country position // Match multiple IP patterns with wildcards Location::fake([ '192.168.*.*' => Position::make([ 'countryName' => 'United States', 'countryCode' => 'US', ]), '10.0.*.*' => Position::make([ 'countryName' => 'Canada', 'countryCode' => 'CA', ]), ]); $usPosition = Location::get('192.168.1.100'); // US $caPosition = Location::get('10.0.0.50'); // Canada // Empty fake returns false for all requests Location::fake(); $result = Location::get('8.8.8.8'); // false ``` ## Configuration - Driver Setup and Fallbacks Configure the primary driver and fallback chain in `config/location.php`. The package automatically tries fallback drivers if the primary fails (e.g., rate limiting, API errors). Each driver can have its own API token configuration. ```php // config/location.php return [ // Primary driver 'driver' => Stevebauman\Location\Drivers\IpApi::class, // Fallback chain (called in order if primary fails) 'fallbacks' => [ Stevebauman\Location\Drivers\Ip2locationio::class, Stevebauman\Location\Drivers\IpInfo::class, Stevebauman\Location\Drivers\GeoPlugin::class, Stevebauman\Location\Drivers\MaxMind::class, ], // HTTP client options for API drivers 'http' => [ 'timeout' => 3, 'connect_timeout' => 3, ], // Local testing configuration (uses US-based Google IP by default) 'testing' => [ 'ip' => '66.102.0.0', 'enabled' => env('LOCATION_TESTING', true), ], // Driver-specific API tokens 'ip_api' => [ 'token' => env('IP_API_TOKEN'), ], 'ipinfo' => [ 'token' => env('IPINFO_TOKEN'), ], 'ipdata' => [ 'token' => env('IPDATA_TOKEN'), ], 'ip2locationio' => [ 'token' => env('IP2LOCATIONIO_TOKEN'), ], 'kloudend' => [ 'token' => env('KLOUDEND_TOKEN'), ], // MaxMind configuration for local database or web service 'maxmind' => [ 'license_key' => env('MAXMIND_LICENSE_KEY'), 'web' => [ 'enabled' => false, 'user_id' => env('MAXMIND_USER_ID'), 'locales' => ['en'], 'options' => ['host' => 'geoip.maxmind.com'], ], 'local' => [ 'type' => 'city', // 'city' or 'country' 'path' => database_path('maxmind/GeoLite2-City.mmdb'), 'url' => sprintf( 'https://download.maxmind.com/app/geoip_download_by_token?edition_id=GeoLite2-City&license_key=%s&suffix=tar.gz', env('MAXMIND_LICENSE_KEY') ), ], ], ]; ``` ## MaxMind Local Database - Offline Geolocation The MaxMind driver supports local database lookups using the GeoLite2 `.mmdb` file. Use the `location:update` artisan command to download and update the database file. This is recommended as a fallback for reliability when online services are unavailable. ```bash # Set your MaxMind license key in .env MAXMIND_LICENSE_KEY=your_license_key_here # Download/update the MaxMind database php artisan location:update # Output: # Updating driver [Stevebauman\Location\Drivers\MaxMind]... # Successfully updated driver [Stevebauman\Location\Drivers\MaxMind]. # All configured drivers have been updated. ``` ```php // Using MaxMind as primary driver in config/location.php 'driver' => Stevebauman\Location\Drivers\MaxMind::class, // Or configure MaxMind web service instead of local database 'maxmind' => [ 'license_key' => env('MAXMIND_LICENSE_KEY'), 'web' => [ 'enabled' => true, 'user_id' => env('MAXMIND_USER_ID'), 'locales' => ['en'], 'options' => ['host' => 'geoip.maxmind.com'], ], ], ``` ## Custom Driver - Extend with Your Own Provider Create custom drivers by extending the `Driver` or `HttpDriver` abstract classes. The `HttpDriver` simplifies HTTP-based providers by only requiring `url()` and `hydrate()` method implementations. ```php namespace App\Location\Drivers; use Illuminate\Support\Fluent; use Illuminate\Support\Facades\Http; use Stevebauman\Location\Position; use Stevebauman\Location\Request; use Stevebauman\Location\Drivers\HttpDriver; class MyCustomDriver extends HttpDriver { /** * Build the URL for the geolocation API request. */ public function url(string $ip): string { $token = config('location.my_driver.token'); return "https://my-geo-api.com/lookup?ip={$ip}&key={$token}"; } /** * Map the API response to the Position object. */ protected function hydrate(Position $position, Fluent $location): Position { $position->countryName = $location->country; $position->countryCode = $location->country_iso; $position->regionName = $location->state; $position->regionCode = $location->state_code; $position->cityName = $location->city; $position->zipCode = $location->postal; $position->latitude = (string) $location->lat; $position->longitude = (string) $location->lng; $position->timezone = $location->tz; return $position; } } // Register in config/location.php 'driver' => App\Location\Drivers\MyCustomDriver::class, 'my_driver' => [ 'token' => env('MY_DRIVER_TOKEN'), ], ``` ## Available Drivers Reference The package includes drivers for major geolocation providers, each returning standardized `Position` objects regardless of the underlying API format. ```php // Available driver classes Stevebauman\Location\Drivers\IpApi::class // ip-api.com (default, free tier) Stevebauman\Location\Drivers\IpApiPro::class // pro.ip-api.com (paid) Stevebauman\Location\Drivers\IpData::class // ipdata.co Stevebauman\Location\Drivers\IpInfo::class // ipinfo.io Stevebauman\Location\Drivers\IpInfoLite::class // ipinfo.io/lite Stevebauman\Location\Drivers\Kloudend::class // ipapi.co Stevebauman\Location\Drivers\GeoPlugin::class // geoplugin.com Stevebauman\Location\Drivers\MaxMind::class // MaxMind (local or web) Stevebauman\Location\Drivers\Cloudflare::class // Cloudflare IP Geolocation Stevebauman\Location\Drivers\Ip2locationio::class // ip2location.io // Example: Using IpInfo as primary with MaxMind fallback // config/location.php 'driver' => Stevebauman\Location\Drivers\IpInfo::class, 'fallbacks' => [ Stevebauman\Location\Drivers\MaxMind::class, ], 'ipinfo' => [ 'token' => env('IPINFO_TOKEN'), ], ``` The Location package is ideal for applications requiring geographic personalization, such as displaying localized content, currency conversion, shipping calculations, or compliance with regional regulations. It's commonly used in e-commerce platforms to auto-detect customer regions, in content delivery systems to serve location-appropriate media, and in analytics dashboards to track visitor demographics. Integration is straightforward: install via Composer, publish the configuration, set any required API tokens in your `.env` file, and call `Location::get()` wherever you need location data. For production environments, configure MaxMind as a fallback driver with a local database to ensure location services remain available even when external APIs are unreachable or rate-limited.