Quelle est la différence entre le nom D'hôte HTTP et le nom de serveur en PHP?

Quand vous pensez à utiliser l'un sur l'autre et pourquoi?

485
demandé sur slick 2010-02-19 18:29:54

9 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. À utiliser dépend de ce que vous en avez besoin pour. Vous devez maintenant vous rendre compte que l'un est une valeur contrôlée par le client qui peut donc ne pas être fiable pour une utilisation dans la logique des affaires et l'autre est une valeur contrôlée par le serveur qui est plus fiable. Vous devez cependant vous assurer que le serveur en question a correctement configuré le SERVER_NAME . En prenant Apache HTTPD comme exemple, voici un extrait de sa documentation :

si aucun ServerName n'est spécifié, alors le serveur tente 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 le port de la requête entrante. Pour une fiabilité optimale et prévisibilité, vous devez spécifier un nom d'hôte et un port explicites en utilisant la directive ServerName .


mise à jour : après avoir coché la réponse de Pekka sur votre question qui contient un lien vers réponse de bobince que PHP retournerait toujours HTTP_HOST valeur de l ' SERVER_NAME , ce qui va à l'encontre de mon propre PHP 4.x + Apache HTTPD 1.2.x expériences il y a quelques années, j'ai soufflé de la poussière de mon environnement XAMPP actuel sur Windows XP (Apache HTTPD 2.2.1 avec PHP 5.2.8), Je l'ai démarré, j'ai créé une page PHP qui imprime les deux valeurs, j'ai créé une application de test Java en utilisant URLConnection pour modifier l'en-tête Host et les tests m'ont appris que c'est effectivement (incorrectement) le cas.

après avoir d'abord suspecté PHP et avoir creusé dans certains rapports de bogues PHP en ce qui concerne le sujet, j'ai appris que la racine du problème se trouve dans le serveur web utilisé, QU'il a retourné incorrectement L'en-tête HTTP Host lorsque SERVER_NAME a été demandé. J'ai donc creusé dans Apache HTTPD bug reports en utilisant divers mots clés concernant le sujet et j'ai finalement trouvé un bug lié . Ce comportement a été introduit depuis la version 1.3 D'Apache HTTPD. Vous devez définir UseCanonicalName la directive on dans le <VirtualHost> entrée de l ServerName dans httpd.conf (vérifiez également l'avertissement en bas de le document !).

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

ça a marché pour moi.

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

730
répondu BalusC 2017-05-23 11:33:26

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

SERVER_NAME provient de la définition VirtualHost du serveur et est donc considéré comme plus fiable. Il peut aussi être manipulé de l'extérieur sous certaines conditions liées à la configuration de votre serveur web: voir ce Ainsi, la question qui traite des aspects de sécurité des deux variantes.

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

60
répondu Pekka 웃 2017-05-23 11:47:36

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

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

(du moins c'est ce que j'ai remarqué dans Apache port-based virtualhosts)

Note que HTTP_HOST ne pas contenir :443 lors de l'exécution sur HTTPS (sauf si vous êtes tournant sur 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
répondu Simon East 2017-05-23 12:26:42

veuillez 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}/

ceci S'applique uniquement si vous accédez au serveur sans nom d'hôte.

25
répondu Daniel Marschall 2015-08-11 00:23:01

si vous voulez vérifier via un serveur.php ou ce que vous voulez l'appeler avec ce qui suit:

<?php

phpinfo(INFO_VARIABLES);

?>

ou

<?php

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

print_r($_SERVER);

?>

puis y accéder avec toutes les urls valides pour votre site et vérifier la différence.

5
répondu stevewh 2011-09-03 10:17:15

ça dépend de ce que je veux découvrir. 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
répondu Rowland Shaw 2010-02-19 15:31:32

il m'a fallu un certain temps pour comprendre ce que les gens entendaient par SERVER_NAME est plus fiable". J'utilise un serveur partagé et n'ai pas accès aux directives virtual host. Ainsi, j'utilise mod_rewrite dans .htaccess pour mapper des HTTP_HOST différents à des répertoires différents. Dans ce cas, c'est HTTP_HOST qui est significatif.

la situation est similaire si l'on utilise des serveurs virtuels basés sur le nom: la directive ServerName dans un hôte virtuel dit simplement quel nom d'hôte sera associé à cet hôte virtuel. Le résultat est que, dans les deux cas, le nom d'hôte fourni par le client pendant la requête ( HTTP_HOST ), doit être apparié avec un nom dans le serveur, qui est lui-même associé à un répertoire. Que la mise en correspondance soit faite avec les directives Virtual host ou avec les règles htaccess mod_rewrite est secondaire ici. 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 serveurs virtuels basés sur IP. Dans ce cas et seulement dans ce cas, SERVER_NAME et HTTP_HOST peuvent être différents, 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 , j'utiliserai SERVER_NAME , juste au cas où mon code serait porté dans ces configurations spéciales.

2
répondu Dominic108 2015-08-11 00:31:18

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

au sens de PHP, $_SERVER['SERVER_NAME'] est un élément PHP enregistré 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 En-tête HTTP host . Traitez ceci comme une entrée de l'utilisateur. Filtrer et valider avant utilisation.

voici un exemple où j'utilise $_SERVER['SERVER_NAME'] comme base de comparaison. La méthode suivante est celle d'un enfant en béton de classe I nommé 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, tous les filtres et validations des éléments $_SERVER pertinents se seraient produits (et l'ensemble des propriétés pertinentes).

la ligne ...

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

... vérifie que la valeur $_SERVER['HTTP_HOST'] (dérivée de l'en-tête HTTP host demandé) correspond à $_SERVER['SERVER_NAME'] .

maintenant, j'utilise le langage superglobal pour expliquer mon exemple, mais c'est juste parce que certains les gens ne sont pas familiers avec INPUT_GET , INPUT_POST , et INPUT_SERVER en ce qui concerne filter_input_array() .

en bref, je ne traite pas les requêtes postales sur mon serveur à moins que toutes quatre conditions soient remplies. Par conséquent, en termes de requêtes POST, défaut de fournir un en-tête HTTP host (présence testée pour plus tôt) sorts doom for strict HTTP 1.0 navigateur. 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 filtre PHP, mais vous voyez ce que je veux dire.

gardez à l'esprit Qu'Apache utilise fréquemment ServerName dans redirections standard (tel que comme laissant le slash arrière hors D'une URL: exemple, http://www.foo.com devenant http://www.foo.com / ), même si vous n'utilisez pas la réécriture D'URL.

j'utilise $_SERVER['SERVER_NAME'] comme la norme, et non pas $_SERVER['HTTP_HOST'] . Il y a beaucoup d'allers et retours sur cette question. $_SERVER['HTTP_HOST'] pourrait être vide, donc cela ne devrait pas être la base pour créer des conventions de code comme mon public la méthode ci-dessus. Mais, juste parce que les deux peuvent être définies ne garantit pas qu'ils seront égaux. Tester est la meilleure façon d'en être sûr (en gardant à l'esprit la version Apache et la version PHP).

2
répondu Anthony Rutledge 2017-03-09 15:41:10

comme balusC dit que SERVER_NAME n'est pas fiable et peut être modifié dans apache config , server name config du serveur et firewall qui peut être entre vous et le serveur.

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

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
0
répondu MSS 2016-05-20 13:21:26