Get current domain
Asked Answered
P

9

213

I have my site on the server http://www.example.uk.com.

On this server I have two domains:

  • one.example
  • two.example

I would like to get the current domain using PHP, but if I use $_SERVER['HTTP_HOST'] then it is showing me example.uk.com instead of one.example or two.example.

How can I get the domain, and not the server name?

Proteiform answered 23/5, 2012 at 9:36 Comment(7)
You can only get primary URl. Which one is Primary out of those three ?Willumsen
Exactly how your two domains 'redirects' requests to your server?Langrage
@infgeoax probably a frame...Numismatics
primary is myserver.uk.com. so how can i get current domain name? If i open site with address one.com i would like get one.com instead of myserver.uk.comProteiform
@TonyEvyght that's the point infgeoax and I try to make, you should get the host name you're connecting with in $_SERVER['HTTP_HOST']. If the sites one.com and two.com are "redirecting" using an (i)frame, the page itself still comes from myserver.uk.com, so you won't get the real domain. What is the HTML source for one.com?Numismatics
Also see https://mcmap.net/q/55813/-php-_server-39-http_host-39-vs-_server-39-server_name-39-am-i-understanding-the-manual-pages-correctly/632951Aksum
$_SERVER['SERVER_NAME'].dirname($_SERVER['PHP_SELF']) gives me (for example) "domain.xyz/path/index.php"Insanitary
S
229

Try using this:

$_SERVER['SERVER_NAME']

Or parse:

$_SERVER['REQUEST_URI']

Reference: apache_request_headers()

Solus answered 23/5, 2012 at 9:41 Comment(9)
-1: With this answer alone, I do not know exactly what the different suggestions I am looking at do. Sure, this gives me a point to continue looking from, but by itself this is really not a good answer...Pun
just print_r(apache_request_headers()) and you'll understand all :)Solus
@SarahLewis HTTP_X_ORIGINAL_HOST can be modified by the user, and cannot be trusted. This may not always be a problem, but it's something to be aware of.Killebrew
$_SERVER['SERVER_NAME'] may be spoofed and should not be relied onColon
@Colon Can you share more information on that? How can it be spoofed? As far as I know a visitor cannot change it. Some other script may change it, yes, but that goes with all other environment variables.Proclus
Also, not to forget that $_SERVER['HTTP_*'] variables will be able to be changed (headers). Sorry, pressed enter by accident.Proclus
@Proclus Many of the keys in $_SERVER can be spoofed by sending specific headers in certain configurations. I can't quite remember which header it was or which setting governs overriding this specific key.Colon
Actually, the next answer (https://mcmap.net/q/125828/-get-current-domain) goes into detail I seeColon
@Colon Interesting! Well thank you for giving me the extra info. I guess it all boils down to, if you're using variables from outside sources, do your research into each one first. Take care, have a good day.Proclus
K
103

The only secure way of doing this

The only guaranteed secure method of retrieving the current domain is to store it in a secure location yourself.

Most frameworks take care of storing the domain for you, so you will want to consult the documentation for your particular framework. If you're not using a framework, consider storing the domain in one of the following places:

   Secure methods of storing the domain      Used By
A configuration file   Joomla, Drupal/Symfony
The database   WordPress
An environmental variable Laravel
A service registry   Kubernetes DNS

The following work… but they're not secure

Hackers can make the following variables output whatever domain they want. This can lead to cache poisoning and barely noticeable phishing attacks.

$_SERVER['HTTP_HOST']

This gets the domain from the request headers which are open to manipulation by hackers. Same with:

$_SERVER['SERVER_NAME']

This one can be made better if the Apache setting UseCanonicalName is turned on; in which case $_SERVER['SERVER_NAME'] will no longer be allowed to be populated with arbitrary values and will be secure. This is, however, non-default and not as common of a setup.

In popular systems

Below is how you can get the current domain in the following frameworks/systems:

WordPress

$urlparts = wp_parse_url(home_url());
$domain = $urlparts['host'];

If you're constructing a URL in WordPress, just use home_url or site_url, or any of the other URL functions.

Laravel

request()->getHost()

The request()->getHost function is inherited from Symfony, and has been secure since the 2013 CVE-2013-4752 was patched.

Drupal

The installer does not yet take care of making this secure (issue #2404259). But in Drupal 8 there is documentation you can follow at Trusted Host Settings to secure your Drupal installation after which the following can be used:

\Drupal::request()->getHost();

Other frameworks

Feel free to edit this answer to include how to get the current domain in your favorite framework. When doing so, please include a link to the relevant source code or to anything else that would help me verify that the framework is doing things securely.


Addendum

Exploitation examples:

  1. Cache poisoning can happen if a botnet continuously requests a page using the wrong hosts header. The resulting HTML will then include links to the attackers website where they can phish your users. At first the malicious links will only be sent back to the hacker, but if the hacker does enough requests, the malicious version of the page will end up in your cache where it will be distributed to other users.

  2. A phishing attack can happen if you store links in the database based on the hosts header. For example, let say you store the absolute URL to a user's profiles on a forum. By using the wrong header, a hacker could get anyone who clicks on their profile link to be sent a phishing site.

  3. Password reset poisoning can happen if a hacker uses a malicious hosts header when filling out the password reset form for a different user. That user will then get an email containing a password reset link that leads to a phishing site. Another more complex form of this skips the user having to do anything by getting the email to bounce and resend to one of the hacker's SMTP servers (for example CVE-2017-8295.)

  4. Here are some more malicious examples

Additional Caveats and Notes:

  • When UseCanonicalName is turned off the $_SERVER['SERVER_NAME'] is populated with the same header $_SERVER['HTTP_HOST'] would have used anyway (plus the port). This is Apache's default setup. If you or DevOps turns this on then you're okay -- ish -- but do you really want to rely on a separate team, or yourself three years in the future, to keep what would appear to be a minor configuration at a non-default value? Even though this makes things secure, I would caution against relying on this setup.
  • Red Hat, however, does turn UseCanonicalName on by default [source].
  • If serverAlias is used in the virtual hosts entry, and the aliased domain is requested, $_SERVER['SERVER_NAME'] will not return the current domain, but will return the value of the serverName directive.
  • If the serverName cannot be resolved, the operating system's hostname command is used in its place [source].
  • If the host header is left out, the server will behave as if UseCanonicalName was on [source].
  • Lastly, I just tried exploiting this on my local server, and was unable to spoof the hosts header. I'm not sure if there was an update to Apache that addressed this, or if I was just doing something wrong. Regardless, this header would still be exploitable in environments where virtual hosts are not being used.

A Little Rant:

     This question received hundreds of thousands of views without a single mention of the security problems at hand! It shouldn't be this way, but just because a Stack Overflow answer is popular, that doesn't mean it is secure.



Killebrew answered 11/5, 2018 at 23:56 Comment(3)
You might want to mention the difference between home_url and site_url. wordpress.stackexchange.com/a/50605/13Tarpon
+1 for wordpress users. Good if you need to examinate if installed in subdir, but note that parse_url key: $urlparts['path'] is not set if installed in root directory of domain. Else $urlparts['path'] returns the subdirectory.Datura
I am confused, I checked the Apache documentation you linked and it says UseCanonicalName is set Off by default, while you said it's On by default. Also the PHP documentation recommends to switch it On and to specify ServerName, for security. Perhaps a typo from you or am I not understanding? php.net/manual/en/reserved.variables.server.phpSuccumb
P
93

The best use would be

echo $_SERVER['HTTP_HOST'];

And it can be used like this:

if (strpos($_SERVER['HTTP_HOST'], 'example.com') !== false) {
    echo "Yes this is indeed the example.com domain";
}

This code below is a good way to see all the variables in $_SERVER in a structured HTML output with your keywords highlighted that halts directly after execution. Since I do sometimes forget which one to use myself - I think this can be nifty.

<?php
    // Change example.com to the domain you were looking for..
    $wordToHighlight = "example.com";
    $serverVarHighlighted = str_replace( $wordToHighlight, '<span style=\'background-color:#883399; color: #FFFFFF;\'>'. $wordToHighlight .'</span>',  $_SERVER );
    echo "<pre>";
    print_r($serverVarHighlighted);
    echo "</pre>";
    exit();
?>
Pteryla answered 5/5, 2013 at 15:54 Comment(0)
O
41

Using $_SERVER['HTTP_HOST'] gets me (subdomain.)maindomain.extension. It seems like the easiest solution to me.

If you're actually 'redirecting' through an iFrame, you could add a GET parameter which states the domain.

<iframe src="example.uk.com?domain=one.example"/>

And then you could set a session variable that persists this data throughout your application.

Ostrogoth answered 15/4, 2013 at 10:45 Comment(1)
mostly importantly it includes the port number so that I do not need to concat it afterwards. phpinfo suggested by bsdnoobz helps me to find the right solution though.Maybellmaybelle
R
11

Try $_SERVER['SERVER_NAME'].

Tips: Create a PHP file that calls the function phpinfo() and see the "PHP Variables" section. There are a bunch of useful variables we never think of there.

Reinhard answered 23/5, 2012 at 9:40 Comment(1)
you can always try print_r-ing the $_SERVER and searchEpigene
I
10

To get the domain:

$_SERVER['HTTP_HOST'] 

Domain with protocol:

$protocol = strpos(strtolower($_SERVER['SERVER_PROTOCOL']), 'https') === FALSE ? 'http' : 'https';
$domainLink = $protocol . '://' . $_SERVER['HTTP_HOST'];

Protocol, domain, and queryString total:

$url = $protocol . '://' . $_SERVER['HTTP_HOST'] . '?' . $_SERVER['QUERY_STRING'];

**As the $_SERVER['SERVER_NAME'] is not reliable for multi-domain hosting!

Internationale answered 9/8, 2019 at 8:39 Comment(0)
J
4

Everybody is using the parse_url function, but sometimes a user may pass the argument in different formats.

So as to fix that, I have created a function. Check this out:

function fixDomainName($url='')
{
    $strToLower = strtolower(trim($url));
    $httpPregReplace = preg_replace('/^http:\/\//i', '', $strToLower);
    $httpsPregReplace = preg_replace('/^https:\/\//i', '', $httpPregReplace);
    $wwwPregReplace = preg_replace('/^www\./i', '', $httpsPregReplace);
    $explodeToArray = explode('/', $wwwPregReplace);
    $finalDomainName = trim($explodeToArray[0]);
    return $finalDomainName;
}

Just pass the URL and get the domain.

For example,

echo fixDomainName('https://stackoverflow.com');

will return:

stackoverflow.com

And in some situation:

echo fixDomainName('stackoverflow.com/questions/id/slug');

And it will also return stackoverflow.com.

Jenson answered 15/11, 2018 at 6:34 Comment(2)
poor written, but you're onto something hereDyun
Thanks for the compliment @MartinZvarík Will try to refactor it a bit.Jenson
O
3

I know this might not be entirely on the subject, but in my experience, I find storing the WWW-ness of the current URL in a variable useful.

In addition, please see my comment below, to see what this is getting at.

This is important when determining whether to dispatch Ajax calls with "www", or without:

$.ajax("url" : "www.site.com/script.php", ...

$.ajax("url" : "site.com/script.php", ...

When dispatching an Ajax call the domain name must match that of in the browser's address bar, and otherwise you will have an Uncaught SecurityError in the console.

So I came up with this solution to address the issue:

<?php
    substr($_SERVER['SERVER_NAME'], 0, 3) == "www" ? $WWW = true : $WWW = false;

    if ($WWW) {
        /* We have www.example.com */
    } else {
        /* We have example.com */
    }
?>

Then, based on whether $WWW is true, or false run the proper Ajax call.

I know this might sound trivial, but this is such a common problem that is easy to trip over.

Oidium answered 23/8, 2016 at 17:56 Comment(5)
OP explicitly asked for the domain, and not the SERVER_NAME.Horwath
True, but these days you have to worry about the www issue too.Oidium
Why? In JS you could look in window.location. In PHP you got SERVER_NAME.Horwath
SERVER_NAME returns "www.site.com" even when "site.com" is entered into the address bar. If you are using SERVER_NAME throughout your code, inevitably you will run into the www/no-www security issue, especially when it comes to making Ajax calls. But to answer your question, in advanced PHP programming, sometimes PHP needs to dynamically generate code that makes an HTTP call to the server. If the target URL contains "www" on a page that doesn't, it will generate a security error.Oidium
Ok ok... I read about it and you are right. So your answer might be relevant for someone. Good job :)Horwath
M
1

This quick & dirty works for me.

Whichever way you get the string containing the domain you want to extract, i.e. using a super global -$_SERVER['SERVER_NAME']- or, say, in Drupal: global $base_url, regex is your friend:

global $base_url;
preg_match("/\w+\.\w+$/", $base_url, $matches);
$domain = $matches[0];

The particular regex string I am using in the example will only capture the last two components of the $base_url string, of course, but you can add as many "\w+." as desired. Hope it helps.

Manes answered 2/2, 2023 at 14:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.