كيف تحصل على URL الكامل في PHP دون أن تصاب بالجنون؟
\n\nكل مطور PHP واجه مرة واحدة على الأقل مهمة: "كيف أحصل على URL الكامل للصفحة الحالية؟". قد يبدو الأمر بسيطًا — خذ $_SERVER['HTTP_HOST']، أضف $_SERVER['REQUEST_URI'] — وانتهى الأمر. لكن الواقع، كالعادة، يفرض تعديلاته. HTTP أم HTTPS؟ وماذا لو كان المنفذ غير قياسي؟ وماذا لو كان الموقع خادم وكيل؟ وماذا لو لم يكن المطلوب مجرد الحصول عليه، بل القيام بذلك بسرعة، دون تسرب للذاكرة، وباحتياطي للمستقبل؟
سؤال "Get the full URL in PHP" على Stack Overflow حصد آلاف المشاهدات وعشرات الإجابات. هذا ليس من قبيل الصدفة: الموضوع يبدو بسيطًا، لكن المخاطر الخفية فيه كثيرة. اليوم سنشرح ليس فقط "كيف تفعل"، بل كيف تفعل ذلك بشكل صحيح وسريع وموثوق. هيا بنا!
\n\nلماذا النسخ البسيط من $_SERVER هو أمر سيء؟
\n\nغالبًا ما يكتب المطورون المبتدئون بهذا الشكل:
\n\n$url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];\n\nللوهلة الأولى — يعمل. لكن دعنا نلقي نظرة على المشاكل:
\n- \n
- لا يوجد HTTPS. إذا كان الموقع يعمل عبر HTTPS، ستحصل على
http://— وسيبدأ المتصفح في الشكوى من المحتوى المختلط. \n - المنفذ. إذا كان المنفذ غير قياسي (مثل 8080)، فسيتم فقدانه إذا لم تستخدم
$_SERVER['SERVER_PORT']. \n - الخوادم الوكيلة وموازنات التحميل. خلف الوكيل العكسي (Nginx, Cloudflare)، قد لا يكون
$_SERVER['HTTP_HOST']هو ما يراه المستخدم. \n - الأمان. يمكن للمهاجم تزوير قيمة
HTTP_HOST(حقن رأس المضيف). \n
باختصار، النسخ واللصق من أول إجابة على Stack Overflow ليس الخيار الأفضل. دعنا نكتب دالة صحيحة وعالية الأداء.
\n\nالدالة المثالية: الحصول على URL الكامل بشكل صحيح
\n\nإليك دالة موثوقة تراعي جميع السيناريوهات الأساسية:
\n\nfunction getFullUrl(): string {\n $protocol = 'http';\n if (\n (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')\n || (int)$_SERVER['SERVER_PORT'] === 443\n ) {\n $protocol = 'https';\n }\n\n // مراعاة الرؤوس من الوكيل (إذا كنا نثق به)\n $host = $_SERVER['HTTP_HOST'] ?? '';\n if (empty($host) && !empty($_SERVER['SERVER_NAME'])) {\n $host = $_SERVER['SERVER_NAME'];\n }\n\n // التحقق من المنفذ\n $port = (int)$_SERVER['SERVER_PORT'];\n $portSuffix = '';\n if (\n ($protocol === 'http' && $port !== 80)\n || ($protocol === 'https' && $port !== 443)\n ) {\n $portSuffix = ':' . $port;\n }\n\n $uri = $_SERVER['REQUEST_URI'] ?? '/';\n\n return $protocol . '://' . $host . $portSuffix . $uri;\n}\n\nما المهم هنا؟
\n- \n
- نتحقق من
HTTPS— الطريقة القياسية، تعمل في 99% من الحالات. \n - نأخذ في الاعتبار
SERVER_PORT— إذا كان الموقع على منفذ غير قياسي، لا نفقده. \n - خيار احتياطي عبر
SERVER_NAME— في حال كانHTTP_HOSTفارغًا. \n - لا نستخدم
$_SERVER['SCRIPT_URI']— فهو غير موجود في كل مكان. \n
تحسين الأداء: عندما تكون كل ميلي ثانية مهمة
\n\nإذا كنت تستدعي هذه الدالة في كل صفحة أو في حلقة، يجب التفكير في السرعة. إليك بعض الحيل:
\n\n1. تخزين النتيجة مؤقتًا
\nإذا كان URL لا يتغير ضمن طلب واحد (وهو لا يتغير)، قم بتخزينه مؤقتًا:
\n\nfunction getFullUrlCached(): string {\n static $url = null;\n if ($url === null) {\n $url = getFullUrl(); // نستخدم الدالة أعلاه\n }\n return $url;\n}\n\nالمتغير الثابت يحتفظ بالقيمة بعد الاستدعاء الأول — لا حسابات متكررة.
\n\n2. تجنب العمليات الزائدة
\nلا تستخدم filt