PHP $_Server['Http_Host'] Vs. $_Server['Server_Name'], Am I Understanding the Man Pages Correctly

PHP $_SERVER['HTTP_HOST'] vs. $_SERVER['SERVER_NAME'], am I understanding the man pages correctly?

That’s probably everyone’s first thought. But it’s a little bit more difficult. See Chris Shiflett’s article SERVER_NAME Versus HTTP_HOST.

It seems that there is no silver bullet. Only when you force Apache to use the canonical name you will always get the right server name with SERVER_NAME.

So you either go with that or you check the host name against a white list:

$allowed_hosts = array('foo.example.com', 'bar.example.com');
if (!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], $allowed_hosts)) {
header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
exit;
}

PHP: $_SERVER variables: $_SERVER['HTTP_HOST'] vs $_SERVER['SERVER_NAME']

$_SERVER['SERVER_NAME'] gives the value of the server name as defined in host configuration (i.e for Apache the Apache .conf file).

$_SERVER['HTTP_HOST'] gives you the domain name through which the current request is being fulfilled and is more directly related to the request.

HTTP_HOST is typically more useful in most applications in that it relates directly to the request, whereas SERVER_NAME could return whatever value is in the conf file and doesn't tell you anything about the request at all.

I will give you an example of how HTTP_HOST might differ from SERVER_NAME. Say you have an host defined in Apache with ServerName of example.com and an IP address of 1.2.3.4.

Let's look at two incoming request URLs and show the difference between these variables:

http://www.example.com
HTTP_HOST = www.example.com
SERVER_NAME = example.com

http://1.2.3.4
HTTP_HOST = 1.2.3.4
SERVER_NAME = example.com

So again, HTTP_HOST is tied more to the request, whereas SERVER_NAME is determined by server configuration.

What is the difference between HTTP_HOST and SERVER_NAME in PHP?

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 the ServerName, 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 the ServerName 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!

$_SERVER['HTTP_HOST'] = an ip that's not my server

HTTP_HOST is provided by the client, in the Host: part of the HTTP request. It can be changed arbitrarily, though I can't see why one would want to. See the manual page.

Use $_SERVER['SERVER_NAME'] instead. This is defined by the server itself.

Can $_SERVER['SERVER_NAME'] be forged/faked?

Actually $_SERVER['SERVER_NAME'] can be affected by what the client browser sends over... See http://shiflett.org/blog/2006/mar/server-name-versus-http-host for a through investigation on the issue.

Why does if condition not working? $_SERVER['SERVER_NAME'] . $_SERVER['REQUREST_URI']

Just a guess, but the string comparison is case sensitive so if the url has incorrect case, it will evaluate to false. If you are hosting on IIS, this can be a problem since IIS is case insensitive. You might want to try :

$host = strtolower($_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']);
if($host=="www.thesofacompany.ca/index.php?route=information/contact"){
echo "A";
}
if($host=="www.thesofacompany.ca/index.php?route=information/information&information_id=4") //This if statement isn't working..
{
echo "B";
}

This will just make sure you have a lowercase string to compare against.



Related Topics



Leave a reply



Submit