مقدمة: لماذا لم يعد "مجرد REMOTE_ADDR" كافياً
كل مطور PHP تساءل مرة واحدة على الأقل: "كيف أحصل على عنوان IP للعميل؟". على Stack Overflow، يجمع هذا الموضوع مئات الآلاف من المشاهدات، وتحت الإجابة الأساسية عشرات التعليقات التوضيحية. المشكلة هي أنه في عام 2025، لم يعد $_SERVER['REMOTE_ADDR'] البسيط كافياً.
المواقع الحديثة تعيش خلف CDN (Cloudflare، Akamai)، وموازنات الأحمال، وخوادم البروكسي. المستخدمون يتصلون عبر VPN أو Tor. والمهاجمون تعلموا تزوير الرؤوس. إذا كنت تريد معرفة عنوان IP الحقيقي للزائر - وفي نفس الوقت لا تفتح الباب للهجمات - يجب عليك تطبيق الممارسات المثبتة.
في هذه المقالة، سأعرض كيف يعمل تحديد IP في PHP، وسأحلل المخاطر الخفية، وسأقدم كوداً جاهزاً يمكنك استخدامه بثقة في عام 2025.
كيف "يرى" PHP عنوان IP؟
عندما يرسل المتصفح طلباً إلى الخادم، يقوم PHP تلقائياً بملء المصفوفة الشاملة $_SERVER. المفتاح المسؤول عن عنوان IP "المحاور" هو REMOTE_ADDR. في عالم مثالي (بدون بروكسي)، هذا هو عنوان IP للعميل:
<?php$ip = $_SERVER['REMOTE_ADDR']; // 192.168.1.5?>لكن في الواقع، غالباً ما يوجد خلف الخادم nginx أو HAProxy أو Cloudflare. في هذه الحالة، يظهر REMOTE_ADDR عنوان IP للبروكسي، وليس المستخدم. يتم نقل العنوان الحقيقي في رؤوس HTTP:
HTTP_X_FORWARDED_FOR— الرأس القياسي للبروكسي؛HTTP_X_REAL_IP— يستخدمه nginx؛HTTP_CF_CONNECTING_IP— خاص بـ Cloudflare؛HTTP_CLIENT_IP— نادر، لكنه موجود.
المشكلة: أي من هذه الرؤوس يمكن تزويره. إذا وثقت بـ $_SERVER['HTTP_X_FORWARDED_FOR'] دون تحقق، يمكن للمهاجم بسهولة وضع عنوان IP مزيف.
REMOTE_ADDR مقابل X-Forwarded-For: متى نستخدم أيهما؟
إليك القاعدة الأساسية التي ستنقذك من الصداع:
- إذا كان الموقع مباشرة على الخادم بدون بروكسي — استخدم فقط
REMOTE_ADDR. - إذا كان الموقع خلف بروكسي موثوق (CDN، موازن أحمال) — خذ IP من الرأس، ولكن فقط بعد التحقق من أن الطلب جاء من البروكسي الخاص بك.
في عام 2025، المعيار الفعلي هو X-Forwarded-For. داخله قد يكون سلسلة من عناوين IP: client, proxy1, proxy2. العنوان الأول هو عنوان العميل، والأخير هو عنوان آخر بروكسي.
لماذا لا يمكن الوثوق بـ X-Forwarded-For بشكل أعمى؟
تخيل: مهاجم يرسل طلباً برأس X-Forwarded-For: 127.0.0.1. إذا كان كودك يقرأ ببساطة $_SERVER['HTTP_X_FORWARDED_FOR']، ستحصل على 127.0.0.1 (المضيف المحلي). السجلات، التحليلات، تحديد الموقع الجغرافي - كل شيء سيتعطل. والأسوأ من ذلك، يمكن للمهاجم وضع عنوان IP لمستخدم آخر لانتحال شخصيته.
الحل: ثق برأس X-Forwarded-For فقط إذا كان REMOTE_ADDR يساوي عنوان IP للبروكسي الموثوق لديك. ليس بأي طريقة أخرى.
أفضل ممارسة لعام 2025: دالة عالمية للحصول على IP
لقد جمعت منطقاً مثبتاً يأخذ في الاعتبار جميع الحقائق الحديثة. الدالة:
- تتحقق مما إذا كان الطلب يأتي عبر بروكسيات موثوقة (تحدد قائمتهم).
- إذا كان الأمر كذلك - تستخرج أول IP من
X-Forwarded-For. - إذا لم يكن كذلك - تعيد
REMOTE_ADDR. - تقوم بتصفية العناوين الخاصة والمحجوزة (اختياري).
<?php/** * يحصل على عنوان IP الحقيقي للعميل. * * @param array $trustedProxies قائمة عناوين IP للبروكسيات الموثوقة * @return string عنوان IP أو '0.0.0.0' إذا تعذر تحديده */function getClientIP(array $trustedProxies = []): string { $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';