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 real location by IP in Laravel. Provides a simple facade/service, multiple driver support, caching options, and easy integration with requests, middleware, and geolocation providers for country, city, lat/long, and more.

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 preferred driver in config/location.php (e.g., driver: 'maxmind').
    • For MaxMind, add your license key:
      'maxmind' => [
          'license_key' => env('MAXMIND_LICENSE_KEY'),
          'database_path' => storage_path('app/GeoLite2-Country.mmdb'),
      ],
      
    • For IPAPI (free tier):
      'ipapi' => [
          'token' => env('IPAPI_TOKEN'),
      ],
      
  4. First usage: Retrieve a user’s location via the facade:
    use Stevebauman\Location\Facades\Location;
    
    $position = Location::get(); // Returns a `Position` object
    
    • Access properties:
      $country = $position->countryCode; // e.g., 'US'
      $city = $position->city; // e.g., 'San Francisco'
      $timezone = $position->timezone; // e.g., 'America/Los_Angeles'
      

First Use Case: Geo-Restricted Middleware

Create middleware to block access by country:

php artisan make:middleware BlockCountry
// app/Http/Middleware/BlockCountry.php
public function handle(Request $request, Closure $next)
{
    $position = Location::get();
    if (in_array($position->countryCode, ['RU', 'CN'])) {
        abort(403, 'Access denied for your region.');
    }
    return $next($request);
}

Register in app/Http/Kernel.php:

protected $routeMiddleware = [
    'block.country' => \App\Http\Middleware\BlockCountry::class,
];

Use in routes:

Route::middleware(['block.country'])->group(function () {
    // Protected routes
});

Implementation Patterns

Core Workflows

1. Provider Chaining (Fallback Logic)

Configure multiple drivers in config/location.php with a fallback chain:

'drivers' => [
    'maxmind',
    'ipapi',
    'ip2location',
],

The package will attempt drivers in order until one succeeds. Log failures for monitoring:

Location::get(); // Auto-falls back if a driver fails

2. Caching for Performance

Leverage Laravel’s cache to reduce API calls:

// Cache for 1 hour
$position = Location::get()->remember(3600);

Or configure globally in config/location.php:

'cache_ttl' => 3600, // Default cache duration in seconds

3. Dynamic Provider Selection

Switch providers based on runtime conditions (e.g., environment):

$driver = app()->environment('production') ? 'ipapi' : 'maxmind';
Location::setDriver($driver);
$position = Location::get();

4. Middleware for Localization

Auto-set locale/currency in middleware:

// app/Http/Middleware/SetLocale.php
public function handle(Request $request, Closure $next)
{
    $position = Location::get();
    app()->setLocale($position->countryCode === 'FR' ? 'fr' : 'en');
    return $next($request);
}

5. Custom Position Creation

Create Position objects manually for testing or edge cases:

use Stevebauman\Location\Position;

$position = Position::make([
    'countryCode' => 'DE',
    'city' => 'Berlin',
    'timezone' => 'Europe/Berlin',
]);

Integration Tips

With Laravel Scout

Index users by location for geo-search:

// app/Models/User.php
public function toSearchableArray()
{
    return [
        'name' => $this->name,
        'location' => Location::get()->countryCode,
    ];
}

Query in Tinker:

User::search('John')->where('location', 'US')->get();

With Laravel Nova

Add a custom field to display location data:

// app/Nova/Fields/CountryField.php
public static function resolve($value, $resource, $attribute = null)
{
    return Location::get()->countryCode ?? 'Unknown';
}

With API Resources

Expose location data in APIs:

// app/Http/Resources/UserResource.php
public function toArray($request)
{
    return [
        'name' => $this->name,
        'location' => [
            'country' => Location::get()->countryCode,
            'city' => Location::get()->city,
        ],
    ];
}

With Queues

Process location-based tasks asynchronously:

// Dispatch a job
SendGeoWelcomeEmail::dispatch($user->email, Location::get());

// Job
public function handle()
{
    $position = Location::get();
    Mail::to($this->email)->send(new WelcomeEmail($position));
}

Gotchas and Tips

Pitfalls

1. Driver-Specific Quirks

  • MaxMind:
    • Database updates: Local MaxMind databases (e.g., GeoLite2-Country.mmdb) require manual updates. Use the update command:
      php artisan location:update
      
    • Windows path issues: Ensure database_path in config/location.php uses forward slashes or raw strings (e.g., r'C:\path\to\file.mmdb').
    • Permission errors: Store .tar files in a writable directory (configurable via maxmind.tmp_path).
  • IPAPI:
    • Rate limits: Free tier allows 1,000 requests/month. Monitor usage and implement caching aggressively.
    • Empty tokens: Validate IPAPI_TOKEN in .env; the driver throws exceptions if invalid.
  • IP2Location.io:
    • API key vs. username/password: Ensure credentials are correctly formatted in config/location.php.

2. Caching Caveats

  • Stale data: Long cache TTLs (e.g., cache_ttl: 86400) may serve outdated location data. Balance performance and accuracy.
  • IP changes: Dynamic IPs (e.g., mobile users) may return stale cached results. Shorten TTL for high-volatility use cases.
  • Testing: Clear cache between tests to avoid flaky results:
    Location::clearCache();
    

3. Testing Challenges

  • Fake data: Use Location::fake() to mock responses, but ensure test coverage for fallback logic:
    Location::fake([
        'countryCode' => 'US',
        'city' => 'New York',
    ]);
    
  • Driver-specific fakes: Some drivers (e.g., MaxMind) may require custom fake implementations for edge cases.

4. Middleware Order

  • Performance impact: Place geo-middleware early in the stack to fail fast, but avoid redundant calls (e.g., don’t call Location::get() in multiple middleware).
  • Dependency injection: Pass the Position object to downstream middleware to avoid repeated API calls:
    // First middleware
    $position = Location::get();
    return $next($request)->with('geo', $position);
    
    // Second middleware
    $position = $request->geo;
    

Debugging Tips

1. Log Driver Failures

Enable debug logging in config/location.php:

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

Check logs for driver-specific errors (e.g., API timeouts, invalid responses).

2. Validate Responses

Inspect raw responses from drivers for malformed data:

$position = Location::get(['debug' => true]);
// Check Laravel logs for raw response

3. Common Errors and Fixes

Error Cause Solution
Class 'GeoIp2\Database\Reader' not found Missing MaxMind PHP extension Install via pecl install geoip or use the Web Service driver.
cURL error 28: Connection timed out API timeout Increase timeout in driver config (e.g., ipapi.timeout: 10).
Invalid license key MaxMind key expired Regenerate key at MaxMind.
Too many requests IPAPI rate limit exceeded Upgrade plan or implement caching.
File not found MaxMind database missing Run php artisan location:update.

Extension Points

1. Custom Drivers

Extend the AbstractDriver class to integrate with proprietary services:

// app/Services/CustomLocationDriver.php
use Stevebauman\Location
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport