portfolio image

اللغات :  Laravel


كيفية الحصول على موقع المستخدم من عنوان IP في Laravel

تعلم ثلاث طرق للحصول على مدينة، بلد، إحداثيات، والمنطقة الزمنية للزائر عبر عنوان الـ IP في Laravel:

  • الطريقة الأولى باستخدام حزمة جاهزة
  • الطريقة الثانية باستخدام استدعاء HTTP مباشر مع API

لماذا نحتاج إلى تحديد الموقع عبر IP؟

  • تخصيص المحتوى والعملة حسب الدولة.
  • التحليلات الجغرافية وتحديد القيود حسب الموقع.
  • الامتثال (مثل إظهار إشعارات الخصوصية حسب المنطقة).

الطريقة 1: باستخدام الحزمة stevebauman/location

التثبيت

composer require stevebauman/location
php artisan vendor:publish --provider="Stevebauman\Location\LocationServiceProvider"

إنشاء Controller باسم LocationController

php artisan make:controller LocationController

الكود داخل الـ Controller

// app/Http/Controllers/LocationController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stevebauman\Location\Facades\Location;

class LocationController extends Controller
{
public function approach1(Request $request){
$ip = $request->ip();
// أو
// $ip = $_SERVER['REMOTE_ADDR'];

        // ملاحظة: Location::get($ip) يعمل على السيرفر وليس على localhost
        $location = Location::get($ip);

        return view('location', [
            'geo' => $location ? [
                'ip'          => $ip,
                'country'     => $location->countryName,
                'countryCode' => $location->countryCode,
                'region'      => $location->regionName,
                'city'        => $location->cityName,
                'postal'      => $location->postalCode,
                'lat'         => $location->latitude,
                'lon'         => $location->longitude,
                'timezone'    => $location->timezone,
            ] : null,
            'error'=>$location? null : 'لم نتمكن من تحديد موقعك'
        ]);
    }
}

ملف المسارات

// routes/web.php
use App\Http\Controllers\LocationController;

Route::get('/approach1', [LocationController::class, 'approach1'])->name('approach1');

كود الـ Blade

<div class="max-w-xl mx-auto mt-8 p-6 bg-white dark:bg-gray-800 shadow rounded-xl">
    <h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">
        🌍 موقع IP
    </h2>

    {{-- قسم الخطأ --}}
    @if($error)
        <div class="p-3 mb-4 text-sm text-red-800 rounded bg-red-100 dark:bg-red-200 dark:text-red-900">
            {{ $error }}
        </div>
    @endif

    {{-- قسم البيانات --}}
    @if($geo)
        <ul class="space-y-2 text-gray-700 dark:text-gray-200">
            <li><strong>IP:</strong> {{ $geo['ip'] }}</li>
            <li><strong>الدولة:</strong> {{ $geo['country'] }} ({{ $geo['countryCode'] }})</li>
            <li><strong>المنطقة:</strong> {{ $geo['region'] }}</li>
            <li><strong>المدينة:</strong> {{ $geo['city'] }}</li>
            <li><strong>الرمز البريدي:</strong> {{ $geo['postal'] }}</li>
            <li><strong>المنطقة الزمنية:</strong> {{ $geo['timezone'] }}</li>
            <li><strong>خط الطول/العرض:</strong> {{ $geo['lat'] }}, {{ $geo['lon'] }}</li>
        </ul>
    @endif
</div>

الطريقة 2: باستخدام استدعاء HTTP + API (مثل ipapi أو IPinfo أو ip-api)

إنشاء Controller

php artisan make:controller LocationController

الكود داخل الـ Controller

// app/Http/Controllers/LocationController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;

class LocationController extends Controller
{
public function approach2(Request $request){
$ip = $request->ip();

        try {
            $res = Http::get("http://ip-api.com/json/{$ip}");

            if (!$res->ok() || $res->json('status') == 'fail') {
                return view('location', [
                    'geo'   => null,
                    'error' => 'لم نتمكن من تحديد موقعك',
                ]);
            }

            return view('location', [
                'geo' => [
                    'ip'          => $ip,
                    'country'     => $res->json('country'),
                    'countryCode' => $res->json('countryCode'),
                    'region'      => $res->json('region'),
                    'city'        => $res->json('city'),
                    'postal'      => $res->json('zip'),
                    'lat'         => $res->json('lat'),
                    'lon'         => $res->json('lon'),
                    'timezone'    => $res->json('timezone'),
                    'org'         => $res->json('org'),
                ],
                'error'=>null
            ]);
        } catch (ConnectionException $exception) {
            return view('location', [
                'geo'   => null,
                'error' => 'خطأ غير متوقع: ' . $exception->getMessage(),
            ]);
        }
    }
}

ملف المسارات

// routes/web.php
use App\Http\Controllers\LocationController;

Route::get('/approach2', [LocationController::class, 'approach2'])->name('approach2');

كود الـ Blade

<div class="max-w-xl mx-auto mt-8 p-6 bg-white dark:bg-gray-800 shadow rounded-xl">
    <h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">
        🌍 موقع IP
    </h2>

    {{-- قسم الخطأ --}}
    @if($error)
        <div class="p-3 mb-4 text-sm text-red-800 rounded bg-red-100 dark:bg-red-200 dark:text-red-900">
            {{ $error }}
        </div>
    @endif

    {{-- قسم البيانات --}}
    @if($geo)
        <ul class="space-y-2 text-gray-700 dark:text-gray-200">
            <li><strong>IP:</strong> {{ $geo['ip'] }}</li>
            <li><strong>الدولة:</strong> {{ $geo['country'] }} ({{ $geo['countryCode'] }})</li>
            <li><strong>المنطقة:</strong> {{ $geo['region'] }}</li>
            <li><strong>المدينة:</strong> {{ $geo['city'] }}</li>
            <li><strong>الرمز البريدي:</strong> {{ $geo['postal'] }}</li>
            <li><strong>المنطقة الزمنية:</strong> {{ $geo['timezone'] }}</li>
            @if(isset($geo['org']))
                <li><strong>المؤسسة:</strong> {{ $geo['org'] }}</li>
            @endif
        </ul>
    @endif
</div>

جدول مقارنة

المعيارالحزمة (stevebauman/location)استدعاء API يدوي
سرعة الإعدادسريع جدًاسريع
الدقةحسب المزودعالية (الخطط المدفوعة)
القيودحسب المزودحسب سياسة المزود
الخصوصيةحسب المزودحسب المزود
التكلفةمجاني (قد يتم احتساب من المزود)مجاني → مدفوع
الصيانةمنخفضةمتوسطة–منخفضة

برمجة سعيدة 🚀