wake-up-neo.com

Was ist der Unterschied zwischen HTTP_Host und SERVER_NAME in PHP?

Wann würden Sie in Betracht ziehen, eine über die andere zu ziehen, und warum?

517
Emanuil Rusev

Der HTTP_Host wird aus dem HTTP-Anforderungsheader erhalten, und dies ist das, was der Client tatsächlich als "Zielhost" der Anforderung verwendet. Der SERVER_NAME wird in der Serverkonfiguration definiert. Welches verwendet wird, hängt davon ab, wofür Sie es benötigen. Sie sollten sich jetzt jedoch darüber im Klaren sein, dass es sich bei dem einen Wert um einen clientgesteuerten Wert handelt, der für die Verwendung in der Geschäftslogik möglicherweise nicht zuverlässig ist, und bei dem anderen Wert handelt es sich um einen servergesteuerten Wert, der zuverlässiger ist. Sie müssen jedoch sicherstellen, dass der betreffende Webserver den SERVER_NAME korrekt konfiguriert hat. Am Beispiel von Apache HTTPD sehen Sie hier einen Auszug aus dessen Dokumentation :

Wenn ServerName nicht angegeben ist, versucht der Server, den Hostnamen durch eine umgekehrte Suche der IP-Adresse abzuleiten. Wenn in ServerName kein Port angegeben ist, verwendet der Server den Port aus der eingehenden Anforderung. Um eine optimale Zuverlässigkeit und Vorhersagbarkeit zu erzielen, sollten Sie einen expliziten Hostnamen und Port mithilfe der Anweisung ServerName angeben.


Update : nach Überprüfung die Antwort von Pekka auf Ihre Frage , die einen Link zu Bobinces Antwort enthält dass PHP immer den Wert von HTTP_Host für SERVER_NAME zurückgibt, was gegen meine eigenen Erfahrungen mit PHP 4.x + Apache HTTPD 1.2.x vor einigen Jahren verstößt Ich habe etwas Staub aus meiner aktuellen XAMPP-Umgebung unter Windows XP (Apache HTTPD 2.2.1 mit PHP 5.2.8) ausgeblasen, es gestartet und eine PHP - Seite erstellt, die die beiden erstellten Werte druckt Eine Testanwendung Java, die URLConnection verwendet, um den Header Host zu ändern, und Tests haben mir gezeigt, dass dies tatsächlich (fälschlicherweise) der Fall ist.

Nachdem ich zuerst PHP vermutet und einige PHP-Fehlerberichte in Bezug auf das Thema recherchiert hatte, erfuhr ich, dass die Wurzel des Problems im verwendeten Webserver liegt und dass der HTTP-Header Host fälschlicherweise zurückgegeben wurde, wenn SERVER_NAME wurde angefordert. Also habe ich mich in Apache HTTPD-Fehlerberichte mit verschiedenen Schlüsselwörtern über das Thema vertieft und schließlich einen verwandten Fehler gefunden. Dieses Verhalten wurde seit Apache HTTPD 1.3 eingeführt. Sie müssen die Direktive UseCanonicalName auf on im Eintrag <VirtualHost> des Eintrags ServerName in httpd.conf setzen (überprüfen Sie auch die Warnung unten in dem Dokument !).

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

Das hat bei mir funktioniert.

Zusammengefasst ist SERVER_NAME zuverlässiger, aber Sie sind abhängig von der Serverkonfiguration!

763
BalusC

HTTP_Host ist der vom Client gesendete Zielhost. Es kann vom Benutzer frei manipuliert werden. Es ist kein Problem, eine Anfrage an Ihre Site zu senden, in der ein HTTP_Host -Wert von www.stackoverflow.com angefordert wird.

SERVER_NAME stammt aus der VirtualHost -Definition des Servers und wird daher als zuverlässiger angesehen. Es kann jedoch auch von außen manipuliert werden, unter bestimmten Bedingungen in Bezug auf die Einrichtung Ihres Webservers: Siehe diese Diese SO Frage , die sich mit den Sicherheitsaspekten beider Varianten befasst.

Sie sollten sich auch nicht darauf verlassen, dass Sie in Sicherheit sind. Das heißt, was zu verwenden ist, hängt wirklich davon ab, was Sie tun möchten. Wenn Sie feststellen möchten, auf welcher Domäne Ihr Skript ausgeführt wird, können Sie HTTP_Host ohne Bedenken verwenden, solange ungültige Werte eines böswilligen Benutzers nichts beschädigen können.

64
Pekka 웃

Wie in diese Antwort erwähnt, enthält HTTP_Host den Port, wenn der Server an einem anderen Port als 80 ausgeführt wird (wie es auf einem Entwicklungs-/Intranet-Computer üblich ist), während SERVER_NAME nicht.

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

(Zumindest ist mir das bei portbasierten Apache-Virtualhosts aufgefallen.)

Beachten Sie, dass HTTP_Host nicht :443 enthält, wenn Sie auf HTTPS ausgeführt werden (es sei denn, Sie verwenden einen nicht standardmäßigen Port, den ich nicht getestet habe) ).

Wie andere angemerkt haben, unterscheiden sich die beiden auch bei der Verwendung von IPv6:

$_SERVER['HTTP_Host'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
51
Simon East

Beachten Sie, dass Sie, wenn Sie IPv6 verwenden möchten, wahrscheinlich HTTP_Host anstelle von SERVER_NAME verwenden möchten. Wenn Sie http://[::1]/ eingeben, lauten die Umgebungsvariablen wie folgt:

HTTP_Host = [::1]
SERVER_NAME = ::1

Dies bedeutet, dass Sie, wenn Sie beispielsweise ein mod_rewrite ausführen, möglicherweise ein unangenehmes Ergebnis erzielen. Beispiel für eine SSL-Umleitung:

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

Dies gilt NUR, wenn Sie ohne Hostnamen auf den Server zugreifen.

26

wenn du eine server.php durchsehen willst oder wie auch immer du es nennen willst mit:

<?php

phpinfo(INFO_VARIABLES);

?>

oder

<?php

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

print_r($_SERVER);

?>

Greifen Sie dann mit allen gültigen URLs auf Ihre Website zu und überprüfen Sie den Unterschied.

6
stevewh

Kommt darauf an, was ich herausfinden will. SERVER_NAME ist der Hostname des Servers, während HTTP_Host der virtuelle Host ist, mit dem der Client verbunden ist.

5
Rowland Shaw

Vorausgesetzt, man hat ein einfaches Setup (CentOS 7, Apache 2.4.x und PHP 5.6.20) und nur eine Website (kein virtuelles Hosting vorausgesetzt) ​​...

Im PHP Sinne ist _$_SERVER['SERVER_NAME']_ ein Element, das PHP im _$_SERVER_ Superglobal registriert, basierend auf Ihrer Apache-Konfiguration (_**ServerName**_ Direktive mit _UseCanonicalName On_) in httpd.conf (sei es aus einer enthaltenen Konfigurationsdatei für virtuelle Hosts, was auch immer, etc ...). HTTP_Host ​​wird aus dem HTTP-Header Host abgeleitet. Behandle dies als Benutzereingabe. Vor der Verwendung filtern und validieren.

Hier ist ein Beispiel, wo ich _$_SERVER['SERVER_NAME']_ als Grundlage für einen Vergleich verwende. Die folgende Methode stammt aus einer konkreten untergeordneten Klasse mit dem Namen ServerValidator (untergeordnetes Element von Validator). ServerValidator überprüft sechs oder sieben Elemente in $ _SERVER, bevor sie verwendet werden.

Um festzustellen, ob es sich bei der HTTP-Anforderung um POST handelt, verwende ich diese Methode.

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

Zum Zeitpunkt des Aufrufs dieser Methode wäre das gesamte Filtern und Validieren der relevanten $ _SERVER-Elemente erfolgt (und die relevanten Eigenschaften festgelegt).

Die Linie ...

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

... prüft, ob der Wert _$_SERVER['HTTP_Host']_ (letztendlich abgeleitet aus dem angeforderten HTTP-Header Host) mit _$_SERVER['SERVER_NAME']_ übereinstimmt.

Jetzt benutze ich superglobal speak, um mein Beispiel zu erklären, aber das liegt nur daran, dass einige Leute mit _INPUT_GET_, _INPUT_POST_ und _INPUT_SERVER_ in Bezug auf filter_input_array() nicht vertraut sind =.

Die Quintessenz ist, dass ich POST Anfragen auf meinem Server nur bearbeite, wenn all vier Bedingungen erfüllt sind. In Bezug auf POST Anfragen bedeutet dies, dass das Fehlen eines HTTP-Headers Host (Vorhandensein wurde auf frühere Versionen getestet) die folgenden Zaubersprüche bedeutet: Doom für strict HTTP 1. Browser. Darüber hinaus muss der angeforderte Host mit dem Wert für ServerName in httpd.conf übereinstimmen. Der Wert für $_SERVER('SERVER_NAME') im _$_SERVER_ Superglobal. Auch hier würde ich _INPUT_SERVER_ mit den Filterfunktionen PHP verwenden, aber Sie erfassen meine Abweichung.

Denken Sie daran, dass Apache häufig ServerName in standard redirects verwendet (z. B. den abschließenden Schrägstrich von einer URL lassen: Beispiel, http: // www.foo.com wird http://www.foo.com/), auch wenn Sie es sind Verwenden Sie keine URL-Umschreibung.

Ich verwende _$_SERVER['SERVER_NAME']_ als Standard, nicht _$_SERVER['HTTP_Host']_. Es gibt viel Hin und Her zu diesem Thema. _$_SERVER['HTTP_Host']_ kann leer sein, daher sollte dies nicht die Grundlage für die Erstellung von Codekonventionen sein, wie z. B. meine oben angegebene öffentliche Methode. Aber nur weil beide gesetzt werden können, ist dies keine Garantie dafür, dass sie gleich sind. Testen ist der beste Weg, um sicherzugehen (unter Berücksichtigung der Apache-Version und der PHP-Version).

2

Ich habe eine Weile gebraucht, um zu verstehen, was die Leute mit "SERVER_NAME is moreiable" gemeint haben. Ich verwende einen gemeinsam genutzten Server und habe keinen Zugriff auf Anweisungen für virtuelle Hosts. Also benutze ich mod_rewrite in .htaccess, um verschiedene HTTP_Hosts verschiedenen Verzeichnissen zuzuordnen. In diesem Fall ist HTTP_Host sinnvoll.

Ähnlich verhält es sich, wenn man namensbasierte virtuelle Hosts verwendet: Die Anweisung ServerName innerhalb eines virtuellen Hosts gibt lediglich an, welcher Hostname diesem virtuellen Host zugeordnet wird. Die Quintessenz ist, dass in beiden Fällen der vom Client während der Anforderung angegebene Hostname (HTTP_Host) mit einem Namen auf dem Server übereinstimmen muss, der selbst einem Verzeichnis zugeordnet ist. Ob das Mapping mit virtuellen Host-Direktiven oder mit htaccess mod_rewrite-Regeln durchgeführt wird, ist hier zweitrangig. In diesen Fällen ist HTTP_Host dasselbe wie SERVER_NAME. Ich bin froh, dass Apache so konfiguriert ist.

Bei IP-basierten virtuellen Hosts ist die Situation jedoch anders. In diesem Fall und nur in diesem Fall können SERVER_NAME und HTTP_Host unterschiedlich sein, da der Client nun den Server durch das auswählt IP, nicht nach dem Namen. In der Tat kann es spezielle Konfigurationen geben, bei denen dies wichtig ist.

Daher werde ich ab sofort SERVER_NAME verwenden, nur für den Fall, dass mein Code in diesen speziellen Konfigurationen portiert ist.

2
Dominic108

Wie balusC sagte, ist SERVER_NAME nicht zuverlässig und kann in der Apache-Konfiguration, der Servernamenskonfiguration des Servers und der Firewall, die sich zwischen Ihnen und dem Server befinden können, geändert werden.

Die folgende Funktion gibt immer einen echten Host (vom Benutzer eingegebener Host) ohne Port zurück und ist fast zuverlässig:

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