[php] What is the difference between HTTP_HOST and SERVER_NAME in PHP?

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?

This question is related to php apache server-variables

The answer is


As I mentioned in this answer, if the server runs on a port other than 80 (as might be common on a development/intranet machine) then HTTP_HOST contains the port, while SERVER_NAME does not.

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

(At least that's what I've noticed in Apache port-based virtualhosts)

Note that HTTP_HOST does not contain :443 when running on HTTPS (unless you're running on a non-standard port, which I haven't tested).

As others have noted, the two also differ when using IPv6:

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

Assuming one has a simple setup (CentOS 7, Apache 2.4.x, and PHP 5.6.20) and only one website (not assuming virtual hosting) ...

In the PHP sense, $_SERVER['SERVER_NAME'] is an element PHP registers in the $_SERVER superglobal based on your Apache configuration (**ServerName** directive with UseCanonicalName On ) in httpd.conf (be it from an included virtual host configuration file, whatever, etc ...). HTTP_HOST is derived from the HTTP host header. Treat this as user input. Filter and validate before using.

Here is an example of where I use $_SERVER['SERVER_NAME'] as the basis for a comparison. The following method is from a concrete child class I made named ServerValidator (child of Validator). ServerValidator checks six or seven elements in $_SERVER before using them.

In determining if the HTTP request is POST, I use this method.

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

By the time this method is called, all filtering and validating of relevant $_SERVER elements would have occurred (and relevant properties set).

The line ...

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

... checks that the $_SERVER['HTTP_HOST'] value (ultimately derived from the requested host HTTP header) matches $_SERVER['SERVER_NAME'].

Now, I am using superglobal speak to explain my example, but that is just because some people are unfamiliar with INPUT_GET, INPUT_POST, and INPUT_SERVER in regards to filter_input_array().

The bottom line is, I do not handle POST requests on my server unless all four conditions are met. Hence, in terms of POST requests, failure to provide an HTTP host header (presence tested for earlier) spells doom for strict HTTP 1.0 browsers. Moreover, the requested host must match the value for ServerName in the httpd.conf, and, by extention, the value for $_SERVER('SERVER_NAME') in the $_SERVER superglobal. Again, I would be using INPUT_SERVER with the PHP filter functions, but you catch my drift.

Keep in mind that Apache frequently uses ServerName in standard redirects (such as leaving the trailing slash off a URL: Example, http://www.example.com becoming http://www.example.com/), even if you are not using URL rewriting.

I use $_SERVER['SERVER_NAME'] as the standard, not $_SERVER['HTTP_HOST']. There is a lot of back and forth on this issue. $_SERVER['HTTP_HOST'] could be empty, so this should not be the basis for creating code conventions such as my public method above. But, just because both may be set does not guarantee they will be equal. Testing is the best way to know for sure (bearing in mind Apache version and PHP version).


$_SERVER['SERVER_NAME'] is based on your web servers configuration. $_SERVER['HTTP_HOST'] is based on the request from the client.


If you want to check through a server.php or whatever, you want to call it with the following:

<?php
    phpinfo(INFO_VARIABLES);
?>

or

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

    print_r($_SERVER);
?>

Then access it with all the valid URLs for your site and check out the difference.


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.


It took me a while to understand what people meant by 'SERVER_NAME is more reliable'. I use a shared server and does not have access to virtual host directives. So, I use mod_rewrite in .htaccess to map different HTTP_HOSTs to different directories. In that case, it is HTTP_HOST that is meaningful.

The situation is similar if one uses name-based virtual hosts: the ServerName directive within a virtual host simply says which hostname will be mapped to this virtual host. The bottom line is that, in both cases, the hostname provided by the client during the request (HTTP_HOST), must be matched with a name within the server, which is itself mapped to a directory. Whether the mapping is done with virtual host directives or with htaccess mod_rewrite rules is secondary here. In these cases, HTTP_HOST will be the same as SERVER_NAME. I am glad that Apache is configured that way.

However, the situation is different with IP-based virtual hosts. In this case and only in this case, SERVER_NAME and HTTP_HOST can be different, because now the client selects the server by the IP, not by the name. Indeed, there might be special configurations where this is important.

So, starting from now, I will use SERVER_NAME, just in case my code is ported in these special configurations.


HTTP_HOST is the target host sent by the client. It can be manipulated freely by the user. It's no problem to send a request to your site asking for a HTTP_HOST value of www.stackoverflow.com.

SERVER_NAME comes from the server's VirtualHost definition and is therefore considered more reliable. It can, however, also be manipulated from outside under certain conditions related to how your web server is set up: See this This SO question that deals with the security aspects of both variations.

You shouldn't rely on either to be safe. That said, what to use really depends on what you want to do. If you want to determine which domain your script is running on, you can safely use HTTP_HOST as long as invalid values coming from a malicious user can't break anything.


As balusC said SERVER_NAME is not reliable and can be changed in apache config , server name config of server and firewall that can be between you and server.

Following function always return real host (user typed host) without port and it's almost reliable:

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

Please note that if you want to use IPv6, you probably want to use HTTP_HOST rather than SERVER_NAME . If you enter http://[::1]/ the environment variables will be the following:

HTTP_HOST = [::1]
SERVER_NAME = ::1

This means, that if you do a mod_rewrite for example, you might get a nasty result. Example for a SSL redirect:

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

This applies ONLY if you access the server without an hostname.