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?
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 leServerName
, 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 directiveServerName
.
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!
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.
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'
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.
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.
ç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é.
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.
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).
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;
}