Weave Code
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

Location Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require stevebauman/location
    
  2. Publish the config (optional but recommended for customization):

    php artisan vendor:publish --provider="Stevebauman\Location\LocationServiceProvider"
    
  3. Configure your driver in .env (example for MaxMind):

    LOCATION_DRIVER=maxmind
    MAXMIND_LICENSE_KEY=your_license_key_here
    

    Or for ipinfo.io:

    LOCATION_DRIVER=ipinfo
    IPINFO_TOKEN=your_token_here
    
  4. First use case: Retrieve a visitor’s location in a controller or middleware:

    use Stevebauman\Location\Facades\Location;
    
    $position = Location::get();
    $country = $position->country;
    $city = $position->city;
    

Where to Look First

  • Configuration: config/location.php – Driver settings, timeouts, and fallback logic.
  • Facade: Stevebauman\Location\Facades\Location – Primary entry point for all location queries.
  • Position Model: Stevebauman\Location\Position – Contains all location data (country, city, coordinates, etc.).
  • Testing: Location::fake() – Simulate locations for development/testing.

Implementation Patterns

Core Workflows

1. Middleware Integration (Geo-Blocking/Localization)

Use middleware to attach location data to requests globally:

// app/Http/Middleware/AttachGeoData.php
public function handle($request, Closure $next) {
    $request->merge([
        'geo' => Location::get(),
    ]);
    return $next($request);
}

Register in app/Http/Kernel.php:

protected $middleware = [
    \App\Http\Middleware\AttachGeoData::class,
];

Access in controllers/views:

$country = request('geo')->country;

2. Dynamic Content Based on Location

Use the Position object to customize responses:

$position = Location::get();
if ($position->country === 'US') {
    return view('pricing.us');
}
return view('pricing.international');

3. Caching Location Data

Cache responses to reduce API calls or database lookups:

$position = Cache::remember("geo_{$request->ip()}", now()->addHours(1), function () {
    return Location::get();
});

4. Fallback Drivers

Configure fallbacks in config/location.php:

'drivers' => [
    'maxmind' => [
        'fallback' => 'ipinfo',
    ],
    'ipinfo' => [
        'fallback' => 'ip2location',
    ],
],

This ensures graceful degradation if the primary driver fails.

5. Testing with Fake Locations

Simulate locations in tests:

Location::fake([
    'country' => 'DE',
    'city' => 'Berlin',
    'latitude' => 52.5200,
    'longitude' => 13.4050,
]);

$position = Location::get();
$this->assertEquals('DE', $position->country);

Advanced Patterns

Extending the Position Model

Add custom methods via macros (e.g., to check if a user is in the EU):

// app/Providers/AppServiceProvider.php
use Stevebauman\Location\Position;

public function boot() {
    Position::macro('isEu', function () {
        $euCountries = ['DE', 'FR', 'IT', 'ES', 'PT', 'NL', 'BE', 'AT', 'SE', 'DK'];
        return in_array($this->country, $euCountries);
    });
}

Usage:

if (Location::get()->isEu()) {
    // Apply VAT or EU-specific logic
}

Custom Drivers

Create a driver for a proprietary API:

// app/Services/CustomLocationDriver.php
namespace App\Services;

use Stevebauman\Location\Contracts\Driver;

class CustomLocationDriver implements Driver {
    public function get($ip) {
        $response = http_get("https://api.example.com/geo?ip={$ip}");
        return new \Stevebauman\Location\Position($response->data);
    }
}

Register in config/location.php:

'drivers' => [
    'custom' => [
        'class' => \App\Services\CustomLocationDriver::class,
    ],
],

Bulk IP Lookup

For batch processing (e.g., importing user data):

$ips = ['192.168.1.1', '8.8.8.8'];
$positions = Location::getMultiple($ips);

Gotchas and Tips

Pitfalls

  1. MaxMind License Key

    • Gotcha: Forgetting to set MAXMIND_LICENSE_KEY in .env will cause silent failures.
    • Fix: Validate the key exists in bootstrap/app.php or a service provider:
      if (empty(config('location.maxmind.license_key'))) {
          throw new \RuntimeException('MaxMind license key not configured.');
      }
      
  2. IPv6 Support

    • Gotcha: Some drivers (e.g., older ipapi.co) may not handle IPv6 addresses correctly.
    • Fix: Test with IPv6 IPs early. Use ipinfo or ip2location for broader support.
  3. Caching Headaches

    • Gotcha: Aggressive caching can serve stale data if IPs change frequently (e.g., mobile users switching networks).
    • Fix: Use short TTLs (e.g., 5–10 minutes) for dynamic environments:
      Cache::remember("geo_{$ip}", now()->addMinutes(5), fn() => Location::get($ip));
      
  4. Fallback Loops

    • Gotcha: Misconfigured fallbacks can create infinite loops if all drivers fail.
    • Fix: Set a final fallback to null or a static default:
      'drivers' => [
          'maxmind' => [
              'fallback' => 'ipinfo',
          ],
          'ipinfo' => [
              'fallback' => null, // No further fallbacks
          ],
      ],
      
  5. MaxMind Database Updates

    • Gotcha: Auto-updates may fail on shared hosting due to permissions or disk space.
    • Fix: Manually trigger updates or set a custom download path:
      MAXMIND_DOWNLOAD_PATH=/custom/path/maxmind
      
  6. Timezone Ambiguity

    • Gotcha: Some drivers return timezones like America/New_York, while others use offsets (e.g., -05:00).
    • Fix: Normalize timezones in a macro:
      Position::macro('timezone', function () {
          $tz = $this->timezone;
          return \DateTimeZone::createFromIC($tz) ?: $tz;
      });
      

Debugging Tips

  1. Log Driver Responses Enable debug mode in config/location.php:

    'debug' => env('LOCATION_DEBUG', false),
    

    This logs raw responses from drivers (useful for troubleshooting API issues).

  2. Check IP Accuracy Use IPinfo’s tool or MaxMind’s demo to verify your IP’s expected location.

  3. Validate Fallbacks Test fallback behavior by disabling drivers:

    // Temporarily disable MaxMind
    config(['location.drivers.maxmind.enabled' => false]);
    $position = Location::get(); // Should use fallback
    
  4. Handle Missing Data Some drivers may return null for optional fields (e.g., postal_code). Use null-safe operators:

    $postalCode = $position->postal ?? 'N/A';
    

Configuration Quirks

  1. Driver-Specific Settings

    • MaxMind: Requires MAXMIND_LICENSE_KEY and MAXMIND_DATABASE_PATH (defaults to storage/app/maxmind).
    • ipinfo.io: Needs IPINFO_TOKEN and optionally IPINFO_SELECT_FIELDS to reduce payload size.
    • IP2Location: Requires IP2LOCATION_API_KEY and IP2LOCATION_LICENSE_KEY.
  2. Timeouts Configure HTTP timeouts in config/location.php:

    'timeout' => 5.0, // Seconds
    

    Critical for API drivers

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.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony