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

Ip Info Provider Laravel Package

geocoder-php/ip-info-provider

IP-Info provider for the Geocoder PHP library. Looks up IP addresses using the ipinfo.io service and returns structured location data (country, region, city, coordinates, timezone, etc.) via a simple provider adapter.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package via Composer:
    composer require geocoder-php/ip-info-provider
    
  2. Configure the provider in your Laravel app (or standalone PHP app):
    use Geocoder\ProviderManager;
    use Geocoder\Geocoder;
    use Geocoder\Provider\IpInfoProvider;
    
    $provider = new IpInfoProvider('YOUR_IPINFO_TOKEN');
    $providerManager = new ProviderManager();
    $providerManager->addProvider($provider);
    
    $geocoder = new Geocoder($providerManager);
    
  3. First use case: Fetch geolocation for a request IP (e.g., in middleware or a service):
    $ip = request()->ip();
    $result = $geocoder->geocode($ip);
    $location = $result->first()->getCoordinates(); // [lat, lng]
    $city = $result->first()->getCity();
    

Key Files to Review

  • src/Provider/IpInfoProvider.php (core logic)
  • tests/ (for edge cases and examples)
  • ipinfo.io API docs (rate limits, response structure)

Implementation Patterns

Common Workflows

1. Middleware for Request Enrichment

Attach location data to incoming requests:

namespace App\Http\Middleware;

use Closure;
use Geocoder\Geocoder;

class GeocodeRequestMiddleware
{
    protected $geocoder;

    public function __construct(Geocoder $geocoder)
    {
        $this->geocoder = $geocoder;
    }

    public function handle($request, Closure $next)
    {
        $ip = $request->ip();
        $result = $this->geocoder->geocode($ip);

        if ($result->first()) {
            $request->merge([
                'location' => [
                    'city' => $result->first()->getCity(),
                    'country' => $result->first()->getCountry(),
                    'coordinates' => $result->first()->getCoordinates(),
                ]
            ]);
        }

        return $next($request);
    }
}

Register in app/Http/Kernel.php:

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

2. Provider Chaining for Fallbacks

Combine with other providers (e.g., Google Maps) for robustness:

$providerManager = new ProviderManager();
$providerManager->addProvider(new IpInfoProvider('TOKEN'));
$providerManager->addProvider(new \Geocoder\Provider\GoogleMapsProvider('GOOGLE_KEY'));
$geocoder = new Geocoder($providerManager);

IpInfoProvider will be tried first; fall back to Google if needed.

3. Caching Responses

Reduce API calls for static IPs (e.g., in a service):

use Illuminate\Support\Facades\Cache;

public function getLocationForIp(string $ip)
{
    return Cache::remember("ipinfo_{$ip}", now()->addHours(1), function() use ($ip) {
        return $this->geocoder->geocode($ip)->first();
    });
}

4. Extracting Structured Data

Normalize responses for analytics or storage:

$location = $geocoder->geocode($ip)->first();
$data = [
    'city' => $location->getCity(),
    'region' => $location->getRegion(),
    'country' => $location->getCountry(),
    'coordinates' => $location->getCoordinates(),
    'timezone' => $location->getTimezone() ?? null,
    'postal' => $location->getPostalCode() ?? null,
];

Gotchas and Tips

Pitfalls

  1. Rate Limits

    • ipinfo.io has strict rate limits (50k/month free tier).
    • Solution: Cache aggressively (e.g., 1-hour TTL for static IPs) or implement a queue for bulk lookups.
    • Debugging: Check IpInfoProvider::doesSupport() for API errors.
  2. IPv6 Support

    • The provider works with IPv6, but test thoroughly if your app handles both IPv4/IPv6.
    • Tip: Normalize IPs before passing to the provider:
      $ip = filter_var($request->ip(), FILTER_VALIDATE_IP);
      
  3. Missing Fields

    • Not all IPs return city/region (e.g., corporate networks or proxies).
    • Workaround: Use getExtraAttributes() to access raw data:
      $rawData = $location->getExtraAttributes();
      // Fallback: $rawData['city'] ?? $rawData['region'] ?? $rawData['country']
      
  4. Timezone Ambiguity

    • ipinfo.io’s timezone may not match political boundaries (e.g., "America/New_York" vs. "America/Toronto").
    • Tip: Validate against a library like overtrue/laravel-timezone.

Debugging

  • Enable HTTP Client Logging:

    $provider = new IpInfoProvider('TOKEN', new \GuzzleHttp\Client([
        'debug' => true,
    ]));
    

    Check Laravel logs for raw API responses.

  • Validate the IP:

    if (!$geocoder->geocode($ip)->valid()) {
        // Handle invalid IP or API failure
    }
    

Configuration Quirks

  1. Token Storage

    • Avoid hardcoding tokens. Use Laravel’s .env:
      IPINFO_TOKEN=your_token_here
      
    • Inject via constructor or bind in AppServiceProvider:
      $this->app->bind(IpInfoProvider::class, function ($app) {
          return new IpInfoProvider(config('services.ipinfo.token'));
      });
      
  2. Custom HTTP Client

    • Override the default client for retries or middleware:
      $client = new \GuzzleHttp\Client([
          'timeout' => 5,
          'headers' => ['Accept' => 'application/json'],
      ]);
      $provider = new IpInfoProvider('TOKEN', $client);
      

Extension Points

  1. Custom Response Mapping Extend the provider to map ipinfo.io fields to your schema:

    class CustomIpInfoProvider extends IpInfoProvider
    {
        protected function parseResponse($data)
        {
            $data['custom_field'] = $data['company'] ?? null;
            return parent::parseResponse($data);
        }
    }
    
  2. Batch Processing Use the ipinfo.io bulk API for large datasets:

    public function bulkGeocode(array $ips)
    {
        $client = new \GuzzleHttp\Client();
        $response = $client->post('https://ipinfo.io/bulk', [
            'json' => ['tokens' => ['TOKEN'], 'ips' => $ips],
        ]);
        return json_decode($response->getBody(), true);
    }
    
  3. Fallback Logic Implement a custom doesSupport() to skip invalid IPs:

    public function doesSupport($query)
    {
        if (strpos($query, 'private') === 0 || strpos($query, '10.') === 0) {
            return false; // Skip private IPs
        }
        return parent::doesSupport($query);
    }
    
  4. Testing Mock the provider for unit tests:

    $provider = $this->createMock(IpInfoProvider::class);
    $provider->method('geocode')->willReturn([$mockLocation]);
    $providerManager->addProvider($provider);
    
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor