¿Cómo obtener la URL completa en PHP sin volverse loco?
\n\nCada desarrollador de PHP se ha enfrentado al menos una vez a la tarea: "¿Cómo obtengo la URL completa de la página actual?". Parecería que no podría ser más sencillo: tomar $_SERVER['HTTP_HOST'], agregar $_SERVER['REQUEST_URI'] y listo. Pero la realidad, como siempre, introduce sus correcciones. ¿HTTP o HTTPS? ¿Y si el puerto no es estándar? ¿Y si el sitio está detrás de un proxy? ¿Y si no solo necesitas obtenerla, sino hacerlo rápido, sin fugas de memoria y con miras al futuro?
La pregunta "Get the full URL in PHP" en Stack Overflow ha acumulado miles de visitas y docenas de respuestas. Esto no es casualidad: el tema parece simple, pero tiene tantas trampas como un charco en primavera. Hoy analizaremos no solo "cómo hacerlo", sino cómo hacerlo correctamente, rápido y de forma confiable. ¡Allá vamos!
\n\n¿Por qué copiar directamente de $_SERVER es malo?
\n\nLos desarrolladores novatos a menudo escriben así:
\n\n$url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];\n\nA primera vista, funciona. Pero veamos los problemas:
\n- \n
- Sin HTTPS. Si el sitio funciona con HTTPS, obtendrá
http://y el navegador se quejará de contenido mixto. \n - Puerto. Si el puerto no es estándar (por ejemplo, 8080), se perderá si no se usa
$_SERVER['SERVER_PORT']. \n - Proxies y balanceadores. Detrás de un proxy inverso (Nginx, Cloudflare),
$_SERVER['HTTP_HOST']puede no ser lo que ve el usuario. \n - Seguridad. El valor de
HTTP_HOSTpuede ser manipulado por un atacante (Host header injection). \n
En resumen, copiar y pegar de la primera respuesta en Stack Overflow no es la mejor opción. Escribamos una función correcta y eficiente.
\n\nFunción de referencia: obtenemos la URL completa correctamente
\n\nAquí hay una función confiable que considera todos los escenarios principales:
\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 // Consideramos encabezados del proxy (si confiamos en él)\n $host = $_SERVER['HTTP_HOST'] ?? '';\n if (empty($host) && !empty($_SERVER['SERVER_NAME'])) {\n $host = $_SERVER['SERVER_NAME'];\n }\n\n // Verificación del puerto\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¿Qué es importante aquí?
\n- \n
- Verificamos
HTTPS— método estándar, funciona en el 99% de los casos. \n - Consideramos
SERVER_PORT— si el sitio está en un puerto no estándar, no lo perdemos. \n - Opción de respaldo con
SERVER_NAME— por siHTTP_HOSTestá vacío. \n - No usamos
$_SERVER['SCRIPT_URI']— no está disponible en todos lados. \n
Optimización del rendimiento: cuando cada milisegundo cuenta
\n\nSi llama a esta función en cada página o en un bucle, vale la pena pensar en la velocidad. Aquí hay algunos consejos:
\n\n1. Almacenamiento en caché del resultado
\nSi la URL no cambia dentro de una misma solicitud (y no cambia), guárdela en caché:
\n\nfunction getFullUrlCached(): string {\n static $url = null;\n if ($url === null) {\n $url = getFullUrl(); // usamos nuestra función anterior\n }\n return $url;\n}\n\nUna variable estática conserva el valor después de la primera llamada — sin cálculos repetidos.
\n\n2. Evite operaciones innecesarias
\nNo use filt