いつ他のものを使用することを検討しますか、またその理由は何ですか。
HTTP_Host
は HTTPリクエストヘッダー から取得され、クライアントが実際にリクエストの「ターゲットホスト」として使用したものです。 SERVER_NAME
はサーバー設定で定義されます。どちらを使用するかは、必要なものによって異なります。ただし、1つはクライアント制御の値であり、したがってビジネスロジックで使用するには信頼できない場合があり、もう1つはより信頼性の高いサーバー制御の値であることを理解する必要があります。ただし、問題のWebサーバーにSERVER_NAME
が正しく構成されていることを確認する必要があります。 Apache HTTPDを例にとると、 そのドキュメント からの抜粋です:
ServerName
が指定されていない場合、サーバーはIPアドレスで逆引きを実行してホスト名を推測しようとします。ServerName
にポートが指定されていない場合、サーバーは着信要求からのポートを使用します。最適な信頼性と予測可能性のために、ServerName
ディレクティブを使用して明示的なホスト名とポートを指定する必要があります。
更新: bobince's answer へのリンクを含む あなたの質問に対するPekkaの回答 をチェックした後、PHPは常にHTTP_Host
の値を返します数年前の自分のPHP 4.x + Apache HTTPD 1.2.xの経験に反するSERVER_NAME
の場合、Windows XPの現在のXAMPP環境からほこりを吹き飛ばしました(Apache HTTPD 2.2.1 with PHP 5.2.8)、開始、両方の値を印刷するPHPページを作成、Javaテストアプリケーションを作成 URLConnection
は、Host
ヘッダーとテストを変更して、これが実際に(誤って)事実であることを教えてくれました。
最初にPHPを疑い、主題に関するいくつかの PHPバグレポート を掘り下げた後、問題の根本は使用されているWebサーバーにあり、間違っていることを知りましたSERVER_NAME
が要求されたときにHTTP Host
ヘッダーを返しました。だから私は Apache HTTPDバグレポート を掘り下げて さまざまなキーワード をテーマに使用し、最終的に 関連バグ を見つけました。この動作は、Apache HTTPD 1.3以降に導入されました。 <VirtualHost>
のUseCanonicalName
のhttpd.conf
エントリで on
ディレクティブをServerName
に設定する必要があります( ドキュメント !の下部にある警告も確認してください)。
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
これは私のために働いた。
要約すると、SERVER_NAME
はより信頼性が高いのですが、サーバー構成ではdependentです!
HTTP_Host
は、クライアントによって送信されたターゲットホストです。ユーザーが自由に操作できます。あなたのサイトにHTTP_Host
の値www.stackoverflow.com
を要求するリクエストを送信しても問題ありません。
SERVER_NAME
はサーバーのVirtualHost
の定義に由来するため、より信頼性が高いと見なされます。ただし、Webサーバーの設定方法に関連する特定の条件下では、外部からも操作できます。こちらを参照してください。 This SO question 両方のバリエーションの。
安全であるためにはどちらにも頼るべきではありません。とは言っても、使用するものは本当にあなたがやりたいことにかかっています。スクリプトが実行されているドメインを特定したい場合は、悪意のあるユーザーからの無効な値が破損しない限り、HTTP_Host
を安全に使用できます。
この答え で述べたように、(開発/イントラネットマシンでよく見られるように)サーバーが80以外のポートで動作している場合、HTTP_Host
にはポートが含まれますが、SERVER_NAME
には含まれません。
$_SERVER['HTTP_Host'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(少なくとも、Apacheのポートベースの仮想ホストで私が気付いたのはそれです)
HTTP_Host
はnotはHTTPSで実行しているときに:443
を含みません(私がテストしていない非標準のポートで実行している場合を除く)。
他の人が指摘したように、この2つはIPv6を使用する場合も異なります。
$_SERVER['HTTP_Host'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
IPv6を使用したい場合は、おそらくHTTP_Host
ではなく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でそれにアクセスして、違いをチェックしてください。
私が知りたいことによります。 SERVER_NAMEはサーバーのホスト名、HTTP_Hostはクライアントが接続した仮想ホストです。
簡単な設定(CentOS 7、Apache 2.4.x、PHP 5.6.20)で、Webサイトは1つだけ(仮想ホスティングを想定していない)と仮定します。
PHPの意味では、$_SERVER['SERVER_NAME']
はhttpd.confのApache設定($_SERVER
を含む**ServerName**
ディレクティブ)に基づくUseCanonicalName On
スーパーグローバルの要素PHPレジスタです設定ファイルなど、何でも。 HTTP_Hostは、HTTPの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']
と一致することを確認します。
今、私はスーパーグローバルスピーチを使って私の例を説明していますが、それは filter_input_array()
に関してINPUT_GET
、INPUT_POST
、およびINPUT_SERVER
に不慣れな人がいるためです。
要するに、all 4つの条件が満たされない限り、私は自分のサーバー上でPOST要求を処理しません。したがって、POSTリクエストに関しては、厳密なHTTP 1.0ブラウザでは、HTTP Host
ヘッダーを提供しなかったこと(以前にテスト済みのプレゼンステスト)がDoomとなります。さらに、httpd.conf内のServerName
に要求されたHost 値と一致する必要があります、および拡張により、$_SERVER
スーパーグローバル内の$_SERVER('SERVER_NAME')
の値。繰り返しになりますが、私はINPUT_SERVER
をPHPフィルター関数と一緒に使用しますが、あなたは私のドリフトに気付くでしょう。
Apacheは標準のリダイレクトでしばしばServerName
を使います(例:http://www.foo.com URLの書き換えを使用していなくても、http://www.foo.com/)。
$_SERVER['SERVER_NAME']
ではなく、$_SERVER['HTTP_Host']
を標準として使用します。この問題に関してはたくさんのことがあります。 $_SERVER['HTTP_Host']
は空になる可能性があるので、上記の私のパブリックメソッドのようなコード規約を作成するための基礎になるべきではありません。しかし、両方が設定されているからといって、それらが等しくなるという保証はありません。テストは確実に知るための最良の方法です(ApacheのバージョンとPHPバージョンを念頭に置いてください)。
「SERVER_NAME
」の意味がより信頼できるものになるまでにはしばらく時間がかかりました。共有サーバーを使用していますが、仮想Hostディレクティブにアクセスできません。そのため、私は.htaccess
でmod_rewriteを使用して、異なるHTTP_Host
を異なるディレクトリにマップします。その場合、意味があるのはHTTP_Host
です。
名前ベースの仮想ホストを使用している場合も状況は似ています。仮想ホスト内のServerName
ディレクティブは、どのホスト名がこの仮想ホストにマップされるかを単純に示しています。要するに、どちらの場合も、要求中にクライアントによって提供されたホスト名(HTTP_Host
)は、サーバー内の名前と一致しなければならず、それ自体がディレクトリにマップされています。マッピングが仮想Hostディレクティブで行われるのかhtaccess mod_rewriteルールで行われるのかは、ここでは二次的です。この場合、HTTP_Host
はSERVER_NAME
と同じになります。 Apacheがそのように設定されていることをうれしく思います。
しかし、状況はIPベースの仮想ホストでは異なります。この場合とこの場合に限り、SERVER_NAME
とHTTP_Host
は異なる可能性があります。これは、クライアントが名前ではなくIPでサーバーを選択するためです。 確かに、これが重要な特別な構成があるかもしれません。
それで、これから始めて、私のコードがこれらの特別な設定で移植された場合に備えて、私はSERVER_NAME
を使います。
BalusCがSERVER_NAMEは信頼できないと言ったように、あなたとサーバーの間にあることができるApache設定、サーバーのサーバー名設定およびファイアウォールで変更することができます。
以下の関数は常にポートなしで実際のホスト(ユーザーが入力したホスト)を返し、それはほとんど信頼できます:
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_Host']);
return $realHost;
}