Question

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

Était-ce utile?

La solution

Le HTTP_HOST est obtenu à partir de l'en-tête demande HTTP et c'est ce que le client en fait utilisé comme « hôte cible » de la demande. Le SERVER_NAME est défini dans la configuration du serveur. Lequel à utiliser dépend de ce que vous avez besoin pour. Vous devriez maintenant cependant réaliser que l'une est une valeur client contrôlée qui ne peut donc être fiable pour une utilisation dans la logique métier et l'autre est une valeur contrôlée serveur qui est plus fiable. Vous devez toutefois veiller à ce que le serveur Web en question a le SERVER_NAME correctement configuré. Prendre Apache httpd comme un exemple, voici un extrait de sa documentation :

  

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


Mise à 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 renverrait toujours la valeur de HTTP_HOST pour SERVER_NAME, qui va à l'encontre de ma propre expérience 1.2.x PHP 4.x + Apache d'un il y a quelques années, j'ai fait sauter la poussière de mon environnement actuel XAMPP sous Windows XP (Apache httpd 2.2.1 avec PHP 5.2.8), a commencé, a créé une page PHP qui affiche les deux valeurs, a créé une application de test Java en utilisant < a href = "http://docs.oracle.com/javase/8/docs/api/java/net/URLConnection.html" rel = "noreferrer"> URLConnection pour modifier l'en-tête et des tests Host m'a appris que c'est en effet (à tort) le cas.

Après la première soupçonnant PHP et creuser dans certains en ce qui concerne le sujet, j'ai appris que la racine du problème est dans le serveur Web utilisé, que incorrectement retourné en-tête HTTP Host lorsque SERVER_NAME a été demandé. Alors je creusais dans rapports de bogue Apache en utilisant href="http://www.google.com/search?q=php+servername+site%3Abz.apache.org+httpd" différents mots-clés en ce qui concerne le sujet et j'ai finalement trouvé un bug lié . Ce comportement a été introduit depuis environ Apache 1.3. Vous devez définir directive UseCanonicalName on dans l'entrée de <VirtualHost> le ServerName dans httpd.conf (vérifiez également l'avertissement en bas de le document !).

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

Cela a fonctionné pour moi.

succincts, SERVER_NAME est plus fiable, mais vous êtes dépend sur la configuration du serveur!

Autres conseils

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

SERVER_NAME vient de la définition de VirtualHost du serveur et est donc considérée comme plus fiable. Il peut cependant être manipulé aussi de l'extérieur dans certaines conditions liées à la façon dont votre serveur Web est configuré: Voir cette Cette question SO qui traite des aspects de sécurité des deux variations.

Vous ne devriez pas compter sur soit pour être sûr. Cela dit, ce qu'il faut utiliser dépend vraiment de ce que vous voulez faire. Si vous voulez déterminer quel domaine votre script est en cours d'exécution, vous pouvez utiliser en toute sécurité HTTP_HOST aussi longtemps que les valeurs non valides provenant d'un utilisateur malveillant ne peut rien casser.

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

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

(au moins ce que je l'ai remarqué dans virtualhosts basée sur le port Apache)

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

Comme d'autres l'ont noté, les deux diffèrent également lorsque vous utilisez IPv6:

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

S'il vous plaît noter que si vous souhaitez 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 résultat méchant. 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 est valable uniquement si vous accédez au serveur sans nom d'hôte.

si vous voulez vérifier par un server.php ou ce que vous voulez appeler avec les éléments suivants:

<?php

phpinfo(INFO_VARIABLES);

?>

ou

<?php

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

print_r($_SERVER);

?>

Accédez ensuite avec toutes les urls valides pour votre site et de vérifier la différence.

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

Il m'a fallu un certain temps pour comprendre ce que les gens entendaient par «SERVER_NAME est plus fiable. J'utiliser un serveur partagé et n'a pas accès aux directives de l'hôte virtuel. Donc, j'utilise mod_rewrite .htaccess pour cartographier différentes HTTP_HOSTs à différents répertoires. Dans ce cas, il est HTTP_HOST qui est significatif.

La situation est similaire si l'on utilise des hôtes virtuels basés sur le nom: la directive ServerName dans un hôte virtuel indique simplement le nom d'hôte sera mis en correspondance avec cet hôte virtuel. L'essentiel est que, dans les deux cas, le nom d'hôte fourni par le client lors de la demande (HTTP_HOST), doit être associé à un nom dans le serveur, qui lui-même est mis en correspondance dans un répertoire. Que ce soit la mise en correspondance se fait avec les directives de l'hôte virtuel ou des règles htaccess mod_rewrite est secondaire ici. Dans ces cas, HTTP_HOST sera le même que SERVER_NAME. Je suis heureux que Apache est configuré de cette façon.

Toutefois, la situation est différente avec des 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, et non par le nom. En effet, il pourrait y avoir des configurations particulières où cela est important.

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

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

Dans le sens de PHP, $_SERVER['SERVER_NAME'] est un registre PHP élément dans la superglobale $_SERVER en fonction de votre configuration Apache (directive **ServerName** 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é de l'en-tête HTTP host. Traiter cela comme entrée utilisateur. Filtrer et valider avant de l'utiliser.

Voici un exemple de l'endroit où j'utilise $_SERVER['SERVER_NAME'] comme base pour une comparaison. La méthode suivante est d'une classe d'enfants en béton que j'ai fait le nom ServerValidator (enfant de Validator). ServerValidator vérifie six ou sept éléments de $ _SERVER avant de les utiliser.

Pour déterminer si la requête HTTP POST est, 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 pertinents _SERVER $ aurait eu lieu (et les propriétés pertinentes set).

La ligne ...

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

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

Maintenant, je me sers de parler superglobale 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() .

La ligne de fond est, je ne gère pas les requêtes POST sur mon serveur, sauf si tous quatre conditions sont remplies. Par conséquent, en termes de requêtes POST, le défaut de fournir un en-tête de host HTTP (présence testée précédemment) sorts Doom pour strictes HTTP 1.0 navigateurs . En outre, l'hôte demandé doit correspondre à la valeur ServerName httpd.conf , et, par extention, la valeur $_SERVER('SERVER_NAME') dans le $_SERVER superglobale. Encore une fois, je serais en utilisant INPUT_SERVER avec les fonctions de filtrage PHP, mais vous attraper ma dérive.

Gardez à l'esprit que Apache utilise fréquemment ServerName dans réoriente standard (comme laisser le slash hors 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 la norme, et non $_SERVER['HTTP_HOST']. Il y a beaucoup d'allers-retours sur cette question. $_SERVER['HTTP_HOST'] pourrait être vide, donc cela ne devrait pas servir de base à la création de conventions de code tel que ma méthode publique ci-dessus. Mais, juste parce que les deux peuvent être réglés ne garantit pas qu'ils seront égaux. Le test est la meilleure façon de savoir à coup sûr (en gardant à l'esprit la version Apache et PHP version).

Comme balusC dit SERVER_NAME n'est pas fiable et peut être modifié dans la configuration apache, config nom du serveur de serveur et pare-feu qui peut être entre vous et le serveur.

Après la fonction retourne toujours l'hôte réel (hôte tapé par l'utilisateur) sans port et il est presque fiable:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top