¿Cuál es la diferencia entre HTTP_HOST y SERVER_NAME en PHP?
-
21-09-2019 - |
Pregunta
Cuando se considere el uso de uno sobre el otro y por qué?
Solución
El HTTP_HOST
se obtiene de la solicitud HTTP de cabecera y esto es lo que el cliente utiliza realmente como "host de destino" de la solicitud. El SERVER_NAME
se define en la configuración del servidor. Cuál utilizar depende de lo que lo necesita. Ahora debería sin embargo se da cuenta de que una es un valor cliente-controlado que por lo tanto no puede ser fiable para su uso en la lógica de negocio y el otro es un valor controlada por el servidor que es más fiable. Sin embargo, tendrá que asegurarse de que el servidor web en cuestión ha configurado correctamente el SERVER_NAME
. Tomando Apache HTTPD como ejemplo, he aquí un extracto de su documentación :
Si no se especifica ningún
ServerName
, a continuación, los intentos de servidor para deducir el nombre de host haciendo una busqueda reversa en la dirección IP. Si no se especifica ningún puerto en elServerName
, entonces el servidor usará el puerto para las peticiones entrantes. Para mayor fiabilidad y previsibilidad óptimo, debe especificar un nombre de host y el puerto explícita usando la directivaServerName
.
Actualizar Pekka en su pregunta que contiene un enlace a respuesta de bobince que PHP siempre devolvería el valor de HTTP_HOST
para SERVER_NAME
, lo que va en contra de mi propio PHP 4.x + Apache HTTPD 1.2.x experiencias de una hace dos años, me sopló un poco de polvo de mi entorno actual XAMPP en Windows XP (Apache HTTPD 2.2.1 con PHP 5.2.8), que se inició, crearon una página PHP que imprime los valores de ambos, crearon una aplicación de prueba Java utilizando < a href = "http://docs.oracle.com/javase/8/docs/api/java/net/URLConnection.html" rel => URLConnection
para modificar el encabezado y pruebas Host
"noreferrer" me enseñaron que esto es de hecho (incorrectamente) el caso.
Después de la primera sospechar PHP y cavar en algunos PHP error informes sobre el tema, he aprendido que la raíz del problema está en el servidor web utilizado, que incorrectamente volvió HTTP Host
cabecera cuando se solicitó SERVER_NAME
. Y cavé en Apache HTTPD informes de errores con respecto al tema y, finalmente, me encontré con un relacionada fallo . Este comportamiento se introdujo desde alrededor de Apache HTTPD 1.3. Es necesario configurar UseCanonicalName
directiva para on
en la entrada de <VirtualHost>
la ServerName
en httpd.conf
(consultar también la advertencia en la parte inferior de el documento !).
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
Esto funcionó para mí.
Resumido, SERVER_NAME
es más fiable, pero eres depende en la configuración del servidor!
Otros consejos
HTTP_HOST
es el host de destino enviado por el cliente. Puede ser manipulado libremente por el usuario. No es ningún problema para enviar una petición a su sitio pidiendo un valor de HTTP_HOST
www.stackoverflow.com
.
SERVER_NAME
proviene de definición VirtualHost
del servidor y por lo tanto se considera más fiable. Puede, sin embargo, también se puede manipular desde el exterior, bajo ciertas condiciones relacionadas con la forma en que su servidor web está configurado: Ver este Esta pregunta SO que se ocupa de los aspectos de seguridad de ambas variaciones.
No se debe confiar a uno y otro para estar seguro. Dicho esto, lo que debe utilizar realmente depende de lo que quiere hacer. Si desea determinar qué dominio se ejecuta un script, usted puede utilizar con seguridad HTTP_HOST
, siempre y cuando los valores no válidos procedentes de un usuario malicioso no puede romper nada.
Como he mencionado en esta respuesta , si se ejecuta el servidor en un puerto que no sea 80 (como podría ser común en un desarrollo / máquina de intranet), entonces HTTP_HOST
contiene el puerto, mientras que SERVER_NAME
no lo hace.
$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(al menos eso es lo que he notado en VirtualHosts basadas en puertos Apache)
Tenga en cuenta que HTTP_HOST
hace no contienen :443
cuando se ejecuta en HTTPS (a no ser que se está ejecutando en un puerto no estándar, que no he probado).
Como otros han señalado, los dos también difieren cuando se utiliza IPv6:
$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
Tenga en cuenta que si desea utilizar IPv6, es probable que desea utilizar en lugar de HTTP_HOST
SERVER_NAME
. Si introduce http://[::1]/
las variables de entorno será el siguiente:
HTTP_HOST = [::1]
SERVER_NAME = ::1
Esto significa que, si lo hace un mod_rewrite por ejemplo, es posible obtener un resultado desagradable. Ejemplo para un redireccionamiento SSL:
# SERVER_NAME will NOT work - Redirection to https://::1/
RewriteRule .* https://%{SERVER_NAME}/
# HTTP_HOST will work - Redirection to https://[::1]/
RewriteRule .* https://%{HTTP_HOST}/
Esto se aplica sólo si accede al servidor sin una hostname.
Si desea comprobar a través de un server.php o lo que sea que quieras llamarlo con lo siguiente:
<?php
phpinfo(INFO_VARIABLES);
?>
o
<?php
header("Content-type: text/plain");
print_r($_SERVER);
?>
A continuación, acceder a ella con todas las URL válidas para su sitio y ver la diferencia.
Depende de lo que yo quiero averiguar. SERVER_NAME es el nombre de host del servidor, mientras HTTP_HOST es la máquina virtual que el cliente conectado.
Me tomó un tiempo para entender lo que la gente entiende por"SERVER_NAME
es más fiable'.Yo uso un servidor compartido y no tiene acceso a las directivas de host virtual.Así, puedo utilizar mod_rewrite en .htaccess
asignar diferentes HTTP_HOST
s a directorios diferentes.En ese caso, es HTTP_HOST
que es significativo.
La situación es similar, si uno utiliza el nombre de los hosts virtuales basados en:el ServerName
la directiva dentro de un host virtual simplemente dice que el nombre de host que se asignará a este host virtual.La conclusión es que, en ambos casos, el nombre de host proporcionado por el cliente en la solicitud (HTTP_HOST
), debe coincidir con un nombre en el servidor, el cual está asignado a un directorio.Si la asignación se realiza con las directivas de host virtual o con htaccess reglas de mod_rewrite es secundaria aquí.En estos casos, HTTP_HOST
será el mismo SERVER_NAME
.Me alegro de que Apache está configurado de esa manera.
Sin embargo, la situación es diferente con base IP de los hosts virtuales.En este caso y sólo en este caso, SERVER_NAME
y HTTP_HOST
puede ser diferente, porque ahora el cliente selecciona el servidor por IP, no por el nombre. De hecho, puede haber configuraciones especiales en las que esto es importante.
Así que, a partir de ahora, voy a utilizar SERVER_NAME
, en caso de que mi código es portado en estas configuraciones especiales.
Si se asume una tiene una configuración simple (CentOS 7, Apache 2.4.x, y PHP 5.6.20) y sólo un sitio web (no asumir el alojamiento virtual) ...
En el sentido de PHP, $_SERVER['SERVER_NAME']
es un elemento de registros PHP en el $_SERVER
superglobal función de la configuración de Apache (Directiva **ServerName**
con UseCanonicalName On
) en httpd.conf (ya sea desde un archivo de configuración de host virtual incluida, lo que sea, etc ... ). HTTP_HOST se deriva de la HTTP host
cabecera. Tratar esto como entrada del usuario. Filtro y validar antes de usar.
Este es un ejemplo de donde uso $_SERVER['SERVER_NAME']
como base para una comparación. El siguiente método es de una clase hija de concreto hice ServerValidator
llamado (el niño de Validator
). ServerValidator
cheques seis o siete elementos en $ _SERVER antes de usarlos.
En la determinación de si la petición HTTP es POST, utilizo este método.
public function isPOST()
{
return (($this->requestMethod === 'POST') && // Ignore
$this->hasTokenTimeLeft() && // Ignore
$this->hasSameGETandPOSTIdentities() && // Ingore
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}
En el momento en que este método se llama, todo el filtrado y validación de elementos $ _SERVER pertinentes se habría producido (y propiedades relevantes conjunto).
La línea ...
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')
... comprueba que el valor $_SERVER['HTTP_HOST']
(en última instancia deriva de la la solicitada host
cabecera HTTP) Partidos $_SERVER['SERVER_NAME']
.
Ahora, estoy usando hablan superglobal para explicar mi ejemplo, pero eso es sólo porque algunas personas no están familiarizados con INPUT_GET
, INPUT_POST
y INPUT_SERVER
en lo que respecta a filter_input_array()
.
La conclusión es que no son capaces de manejar las peticiones POST en mi servidor a menos que todos se cumplen cuatro condiciones. Por lo tanto, en términos de solicitudes POST, el no proporcionar un HTTP host
cabecera (presencia probado para antes) hechizos condenación para estrictos HTTP 1.0 navegadores. Por otra parte, el host solicitado debe coincidir con el valor ServerName
en el httpd.conf , y, por extensión, el valor de $_SERVER('SERVER_NAME')
en el $_SERVER
superglobal. Una vez más, estaría usando INPUT_SERVER
con las funciones de filtro PHP, pero lo que me refiero.
Tenga en cuenta que Apache utiliza con frecuencia ServerName
en redirecciones estándar (tales como salir de la barra al final de un URL: ejemplo, http://www.foo.com a ser de http://www.foo.com/ ), incluso si no está utilizando la reescritura de URL.
Yo uso $_SERVER['SERVER_NAME']
como el estándar, no $_SERVER['HTTP_HOST']
. Hay un montón de ida y vuelta en este tema. $_SERVER['HTTP_HOST']
podría estar vacío, por lo que esta no debe ser la base para la creación de códigos de convenciones tales como mi método público anteriormente. Sin embargo, sólo porque ambos pueden ser conjunto no garantiza que serán iguales. La prueba es la mejor manera de saber con seguridad (teniendo en cuenta la versión de Apache y PHP version).
Como dijo balusC SERVER_NAME no es fiable y se puede cambiar en configuración de Apache, nombre del servidor de configuración del servidor y servidor de seguridad que puede haber entre el usuario y el servidor.
Después de la función siempre devuelve verdadero host (anfitrión de usuario mecanografiado) sin el puerto y es casi segura:
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
return $realHost;
}