What is the difference between $_SERVER['HTTP_HOST']
and $_SERVER['SERVER_NAME']
in PHP?
When would you consider using one over the other and why?
What is the difference between $_SERVER['HTTP_HOST']
and $_SERVER['SERVER_NAME']
in PHP?
When would you consider using one over the other and why?
The HTTP_HOST
is obtained from the HTTP request header and this is what the client actually used as "target host" of the request. The SERVER_NAME
is defined in server config. Which one to use depends on what you need it for. You should now however realize that the one is a client-controlled value which may thus not be reliable for use in business logic and the other is a server-controlled value which is more reliable. You however need to ensure that the webserver in question has the SERVER_NAME
correctly configured. Taking Apache HTTPD as an example, here's an extract from its documentation:
If no
ServerName
is specified, then the server attempts to deduce the hostname by performing a reverse lookup on the IP address. If no port is specified in theServerName
, then the server will use the port from the incoming request. For optimal reliability and predictability, you should specify an explicit hostname and port using theServerName
directive.
Update: after checking the answer of Pekka on your question which contains a link to bobince's answer that PHP would always return HTTP_HOST
's value for SERVER_NAME
, which goes against my own PHP 4.x + Apache HTTPD 1.2.x experiences from a couple of years ago, I blew some dust from my current XAMPP environment on Windows XP (Apache HTTPD 2.2.1 with PHP 5.2.8), started it, created a PHP page which prints the both values, created a Java test application using URLConnection
to modify the Host
header and tests taught me that this is indeed (incorrectly) the case.
After first suspecting PHP and digging in some PHP bug reports regarding the subject, I learned that the root of the problem is in web server used, that it incorrectly returned HTTP Host
header when SERVER_NAME
was requested. So I dug into Apache HTTPD bug reports using various keywords regarding the subject and I finally found a related bug. This behaviour was introduced since around Apache HTTPD 1.3. You need to set UseCanonicalName
directive to on
in the <VirtualHost>
entry of the ServerName
in httpd.conf
(also check the warning at the bottom of the document!).
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
This worked for me.
Summarized, SERVER_NAME
is more reliable, but you're dependent on the server config!
HTTP_HOST
クライアントによって送信されるターゲットホストです。ユーザーが自由に操作できます。HTTP_HOST
の値を要求するリクエストをサイトに送信することは問題ありませんwww.stackoverflow.com
。
SERVER_NAME
サーバーのVirtualHost
定義に基づいているため、より信頼性が高いと見なされます。ただし、Webサーバーのセットアップ方法に関連する特定の条件下で、外部から操作することもできます。両方のバリエーションのセキュリティの側面を扱ったこのSOの質問を参照してください。
安全のためにどちらにも頼るべきではありません。とはいえ、何を使用するかは、実際に何をしたいかによって異なります。スクリプトが実行されているドメインを特定する場合はHTTP_HOST
、悪意のあるユーザーからの無効な値が何も壊さない限り、安全に使用できます。
この回答で述べたように、サーバーが80以外のポートで実行されている場合(開発/イントラネットマシンで一般的である可能性があります)HTTP_HOST
、ポートは含まれていますが、含まれてSERVER_NAME
いません。
$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(少なくとも、Apacheポートベースの仮想ホストで気付いたのはそれです)
HTTPSで実行している場合は含まれHTTP_HOST
ないことに注意してください(私がテストしていない非標準のポートで実行している場合を除く)。:443
他の人が指摘しているように、IPv6を使用する場合も2つは異なります。
$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
HTTP_HOST
IPv6を使用する場合は、おそらくではなくを使用することに注意してくださいSERVER_NAME
。環境変数を入力http://[::1]/
すると、次のようになります。
HTTP_HOST = [::1]
SERVER_NAME = ::1
つまり、たとえばmod_rewriteを実行すると、厄介な結果が生じる可能性があります。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}/
これは、ホスト名なしでサーバーにアクセスする場合にのみ適用されます。
server.phpなどをチェックしたい場合は、次のように呼び出します。
<?php
phpinfo(INFO_VARIABLES);
?>
また
<?php
header("Content-type: text/plain");
print_r($_SERVER);
?>
次に、サイトに有効なすべてのURLを使用してアクセスし、違いを確認します。
Depends what I want to find out. SERVER_NAME is the host name of the server, whilst HTTP_HOST is the virtual host that the client connected to.
SERVER_NAME
「人々がより信頼できる」とはどういう意味かを理解するのに少し時間がかかりました。共有サーバーを使用していますが、仮想ホストディレクティブにアクセスできません。したがって、mod_rewrite inを使用して、さまざまなをさまざまなディレクトリ.htaccess
にマップします。HTTP_HOST
その場合、それHTTP_HOST
は意味があります。
名前ベースの仮想ホストを使用する場合も状況は似ています。ServerName
仮想ホスト内のディレクティブは、どのホスト名がこの仮想ホストにマップされるかを単に示します。つまり、どちらの場合も、要求中にクライアントから提供されたホスト名(HTTP_HOST
)は、それ自体がディレクトリにマップされているサーバー内の名前と一致する必要があります。マッピングが仮想ホストディレクティブで行われるか、htaccess mod_rewriteルールで行われるかは、ここでは二次的なものです。これらの場合、HTTP_HOST
はと同じになりますSERVER_NAME
。Apacheがそのように構成されていることをうれしく思います。
ただし、IPベースの仮想ホストでは状況が異なります。この場合、この場合のみであり、SERVER_NAME
異なるHTTP_HOST
可能性があります。これは、クライアントが名前ではなくIPによってサーバーを選択するためです。 実際、これが重要な特別な構成があるかもしれません。
したがって、これからはSERVER_NAME
、コードがこれらの特別な構成で移植される場合に備えて、を使用します。
セットアップが簡単で(CentOS 7、Apache 2.4.x、PHP 5.6.20)、Webサイトが1つだけ(仮想ホスティングを想定していない)であると仮定します...
PHPの意味では、PHPがhttpd.confのApache構成(ディレクティブを含む)に基づいてスーパーグローバルに$_SERVER['SERVER_NAME']
登録する要素です(含まれている仮想ホスト構成ファイルなどから)。HTTP_HOSTは、HTTPヘッダーから派生します。これをユーザー入力として扱います。使用する前にフィルタリングして検証します。$_SERVER
**ServerName**
UseCanonicalName On
host
$_SERVER['SERVER_NAME']
これは、私が比較の基礎として使用する例です。次のメソッドは、私が名前を付けて作成した具体的な子クラスServerValidator
(の子Validator
)からのものです。ServerValidator
使用する前に、$_SERVERの6つまたは7つの要素をチェックします。
HTTPリクエストがPOSTであるかどうかを判断する際に、このメソッドを使用します。
public function isPOST()
{
return (($this->requestMethod === 'POST') && // Ignore
$this->hasTokenTimeLeft() && // Ignore
$this->hasSameGETandPOSTIdentities() && // Ingore
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}
このメソッドが呼び出されるまでに、関連する$ _SERVER要素(および関連するプロパティセット)のすべてのフィルタリングと検証が行われているはずです。
この線 ...
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')
...$_SERVER['HTTP_HOST']
値(最終的に要求されたhost
HTTPヘッダーから派生)が一致することを確認します$_SERVER['SERVER_NAME']
。
今、私はスーパーグローバルスピークを使用して私の例を説明していますが、それは一部の人々が、、、およびに関してなじみがINPUT_GET
ないINPUT_POST
ためINPUT_SERVER
ですfilter_input_array()
。
つまり、 4つの条件がすべて満たされない限り、サーバーでPOST要求を処理しません。したがって、POST要求に関しては、HTTPhost
ヘッダー(以前にテストされた存在)の提供に失敗すると、厳密なHTTP1.0ブラウザーの運命が決まります。さらに、要求されたホストは、httpd.confのの値と一致する必要があり、拡張により、スーパーグローバルのの値と一致する必要があります。繰り返しになりますが、私はPHPフィルター関数を使用しますが、あなたは私のドリフトを捕らえます。ServerName
$_SERVER('SERVER_NAME')
$_SERVER
INPUT_SERVER
Apacheは、標準のリダイレクトで頻繁に使用ServerName
されることに注意してください(たとえば、URLの末尾にスラッシュを残すなど:例: http://www.example.comがhttp://www.example.com/になります)。 URL書き換えを使用します。
私$_SERVER['SERVER_NAME']
は標準として使用しますが、ではありません$_SERVER['HTTP_HOST']
。この問題については多くのことを行ったり来たりしています。 $_SERVER['HTTP_HOST']
空である可能性があるため、これは上記のパブリックメソッドなどのコード規約を作成するための基礎にはなりません。ただし、両方が設定されているからといって、それらが等しくなることを保証するものではありません。テストは確実に知るための最良の方法です(ApacheバージョンとPHPバージョンを念頭に置いてください)。
balusCが述べたように、SERVER_NAMEは信頼性が低く、apache configで変更できます。サーバーとファイアウォールのサーバー名構成は、ユーザーとサーバーの間にある可能性があります。
次の関数は常にポートのない実際のホスト(ユーザーが入力したホスト)を返し、ほぼ信頼できます。
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
return $realHost;
}
$ _SERVER ['SERVER_NAME']は、Webサーバーの構成に基づいています。 $ _SERVER ['HTTP_HOST']は、クライアントからの要求に基づいています。