Question Quelle est la différence entre HTTP_HOST et SERVER_NAME en PHP?


Quand envisageriez-vous d'utiliser l'un sur l'autre et pourquoi?


481
2018-02-19 15:29


origine


Réponses:


le HTTP_HOST est obtenu à partir du En-tête de requête HTTP et c'est ce que le client a réellement utilisé comme "hôte cible" de la requête. le SERVER_NAME est défini dans la configuration du serveur. Lequel utiliser dépend de ce dont vous avez besoin. Cependant, vous devez maintenant réaliser que l’une est une valeur contrôlée par le client qui peut donc ne pas être fiable pour une utilisation dans la logique métier et l’autre est une valeur contrôlée par le serveur qui est plus fiable. Vous devez cependant vous assurer que le serveur Web en question a le SERVER_NAME correctement configuré. En prenant Apache HTTPD comme exemple, voici un extrait de sa documentation:

Sinon ServerName est spécifié, le serveur tente alors de déduire le nom d'hôte en effectuant une recherche inversée sur l'adresse IP. Si aucun port n'est spécifié dans le ServerName, le serveur utilisera alors le port de la requête entrante. Pour une fiabilité et une prévisibilité optimales, vous devez spécifier un nom d'hôte et un port explicites en utilisant ServerName directif.


Mettre à jour: après vérification la réponse de Pekka sur votre question qui contient un lien vers la réponse de bobince que PHP reviendrait toujours HTTP_HOSTla valeur pour SERVER_NAME, qui va à l'encontre de mes propres expériences PHP 4.x + Apache HTTPD 1.2.x d'il y a quelques années, j'ai fait exploser mon environnement XAMPP actuel sous Windows XP (Apache HTTPD 2.2.1 avec PHP 5.2.8), démarré il, a créé une page PHP qui imprime les deux valeurs, créé une application de test Java en utilisant URLConnection modifier le Host En-tête et tests m'ont appris que c'est effectivement (à tort) le cas.

Après avoir d'abord soupçonné PHP et creusé dans certains Rapports de bogue PHP en ce qui concerne le sujet, j'ai appris que la racine du problème est dans le serveur Web utilisé, qu'il renvoie de manière incorrecte HTTP Host en-tête quand SERVER_NAME a été demandé Alors j'ai creusé dans Rapports de bogues Apache HTTPD en utilisant divers mots-clés en ce qui concerne le sujet et j'ai finalement trouvé un bug lié. Ce comportement a été introduit depuis Apache HTTPD 1.3. Vous devez définir UseCanonicalName directive à on dans le <VirtualHost> entrée du ServerName dans httpd.conf (Vérifiez également l'avertissement au bas de le document!).

<VirtualHost *>
    ServerName example.com
    UseCanonicalName on
</VirtualHost> 

Cela a fonctionné pour moi.

Résumé, SERVER_NAME est plus fiable, mais vous êtes dépendant sur la configuration du serveur!


722
2018-02-19 15:32



HTTP_HOST est l'hôte cible envoyé par le client. Il peut être manipulé librement par l'utilisateur. Il n’ya aucun problème à envoyer une demande à votre site pour demander un HTTP_HOST valeur de www.stackoverflow.com.

SERVER_NAME vient du serveur VirtualHost définition et est donc considéré comme plus fiable. Il peut cependant également être manipulé de l'extérieur sous certaines conditions liées à la configuration de votre serveur Web: Cette question SO qui traite des aspects de sécurité des deux variantes.

Vous ne devriez pas compter sur l'un ou l'autre pour être en sécurité. Cela dit, ce qu'il faut vraiment utiliser dépend de ce que vous voulez faire. Si vous souhaitez déterminer le domaine sur lequel votre script s'exécute, vous pouvez utiliser en toute sécurité HTTP_HOST tant que des valeurs invalides provenant d'un utilisateur malveillant ne peuvent rien casser.


60
2018-02-19 15:35



Comme je l'ai mentionné dans cette réponse, si le serveur fonctionne sur un port autre que 80 (comme cela peut être commun sur une machine de développement / intranet) alors HTTP_HOST contient le port, tandis que SERVER_NAME ne fait pas.

$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'

(Au moins c'est ce que j'ai remarqué dans les virtualhosts basés sur le port Apache)

Notez que HTTP_HOST Est-ce que ne pas contenir :443 lors de l'exécution sur HTTPS (sauf si vous utilisez un port non standard, que je n'ai pas testé).

Comme d'autres l'ont noté, les deux diffèrent également en utilisant IPv6:

$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'

45
2017-08-20 00:22



S'il vous plaît noter que si vous voulez utiliser IPv6, vous voulez probablement utiliser HTTP_HOST plutôt que SERVER_NAME . Si vous entrez http://[::1]/ les variables d'environnement seront les suivantes:

HTTP_HOST = [::1]
SERVER_NAME = ::1

Cela signifie que si vous faites un mod_rewrite par exemple, vous pourriez obtenir un mauvais résultat. Exemple pour une redirection 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}/

Cela s'applique UNIQUEMENT si vous accédez au serveur sans nom d'hôte.


25
2018-02-27 01:24



si vous voulez vérifier à travers un server.php ou quoi que vous voulez l'appeler avec ce qui suit:

<?php

phpinfo(INFO_VARIABLES);

?>

ou

<?php

header("Content-type: text/plain");

print_r($_SERVER);

?>

Ensuite, accédez-y avec toutes les URL valides pour votre site et consultez la différence.


5
2018-05-24 07:58



Ça dépend de ce que je veux savoir. SERVER_NAME est le nom d'hôte du serveur, tandis que HTTP_HOST est l'hôte virtuel auquel le client s'est connecté.


4
2018-02-19 15:31



Il m'a fallu du temps pour comprendre ce que les gens entendaient par 'SERVER_NAME est plus fiable ». J'utilise un serveur partagé et je n'ai pas accès aux directives de l'hôte virtuel. Donc, j'utilise mod_rewrite dans .htaccess  pour mapper différents HTTP_HOSTs vers différents répertoires. Dans ce cas, il est HTTP_HOST c'est significatif.

La situation est similaire si l’on utilise des hôtes virtuels basés sur des noms: le ServerName La directive au sein d'un hôte virtuel indique simplement quel nom d'hôte sera mappé à cet hôte virtuel. L'essentiel est que, dans les deux cas, le nom d'hôte fourni par le client lors de la requête (HTTP_HOST), doit être associé à un nom dans le serveur, lui-même mappé sur un répertoire. Que le mappage soit effectué avec des directives d'hôte virtuel ou avec des règles mod_rewrite htaccess est ici secondaire. Dans ces cas, HTTP_HOST sera le même que SERVER_NAME. Je suis content qu'Apache soit configuré de cette façon.

Cependant, la situation est différente avec les hôtes virtuels basés sur IP. Dans ce cas et seulement dans ce cas, SERVER_NAME et HTTP_HOST peut être différent, parce que maintenant le client sélectionne le serveur par l'IP, pas par le nom.  En effet, il pourrait y avoir des configurations spéciales où cela est important.

Donc, à partir de maintenant, je vais utiliser SERVER_NAME, juste au cas où mon code est porté dans ces configurations spéciales.


2
2018-02-16 21:08



En supposant que l'on dispose d'une configuration simple (CentOS 7, Apache 2.4.x et PHP 5.6.20) et d'un seul site web (ne supposant pas l'hébergement virtuel) ...

Dans le sens PHP, $_SERVER['SERVER_NAME']est un élément PHP enregistre dans le $_SERVER superglobal basé sur votre configuration Apache (**ServerName** directive avec UseCanonicalName On ) dans httpd.conf (que ce soit à partir d'un fichier de configuration d'hôte virtuel inclus, peu importe, etc ...). HTTP_HOST est dérivé du HTTP host entête. Traitez cela comme une entrée de l'utilisateur. Filtrer et valider avant utilisation.

Voici un exemple d'où j'utilise $_SERVER['SERVER_NAME'] comme base pour une comparaison. La méthode suivante provient d'une classe enfant concrète que j'ai nommée ServerValidator (enfant de Validator). ServerValidator vérifie six ou sept éléments dans $ _SERVER avant de les utiliser.

Pour déterminer si la requête HTTP est POST, j'utilise cette méthode.

public function isPOST()
{
    return (($this->requestMethod === 'POST')    &&  // Ignore
            $this->hasTokenTimeLeft()            &&  // Ignore
            $this->hasSameGETandPOSTIdentities() &&  // Ingore
            ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}

Au moment où cette méthode est appelée, tout le filtrage et la validation des éléments $ _SERVER pertinents se seraient produits (et les propriétés correspondantes).

La ligne ...

($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')

... vérifie que le $_SERVER['HTTP_HOST'] valeur (finalement dérivé de la demande host En-tête HTTP) correspond $_SERVER['SERVER_NAME'].

Maintenant, j'utilise superglobal pour expliquer mon exemple, mais c'est juste parce que certaines personnes ne connaissent pas INPUT_GET, INPUT_POST, et INPUT_SERVER en ce qui concerne filter_input_array().

L'essentiel est, je ne gère pas les demandes POST sur mon serveur à moins tout quatre conditions sont remplies. Par conséquent, en termes de requêtes POST, l'impossibilité de fournir un HTTP host En-tête (présence testée précédemment) condamner pour strict HTTP 1.0 navigateurs. De plus, l'hôte demandé doit correspondre à la valeur pour ServerName dans le httpd.conf, et, par extension, la valeur de $_SERVER('SERVER_NAME') dans le $_SERVER superglobale. Encore une fois, j'utiliserais INPUT_SERVER avec les fonctions de filtrage PHP, mais vous attrapez ma dérive.

Gardez à l'esprit qu'Apache utilise fréquemment ServerName dans redirections standard (comme laisser la barre oblique à la fin d'une URL: Exemple, http://www.foo.com devenir http://www.foo.com/), même si vous n'utilisez pas la réécriture d'URL.

j'utilise $_SERVER['SERVER_NAME'] comme norme, pas $_SERVER['HTTP_HOST']. Il y a beaucoup de va-et-vient sur cette question. $_SERVER['HTTP_HOST'] peut être vide, donc cela ne devrait pas être la base pour créer des conventions de code comme ma méthode publique ci-dessus. Mais, juste parce que les deux peuvent être fixés ne garantit pas qu'ils seront égaux. Le test est le meilleur moyen de savoir avec certitude (en gardant à l'esprit la version Apache et la version PHP).


2
2018-03-09 05:20



Comme balusC a déclaré SERVER_NAME n'est pas fiable et peut être changé dans la configuration d'Apache, le nom de serveur config du serveur et le pare-feu qui peut être entre vous et le serveur.

La fonction suivante renvoie toujours l'hôte réel (hôte tapé par l'utilisateur) sans port et c'est presque fiable:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}

0
2018-05-20 13:21