I am coding on a social site in CakePHP say example.com, here in the users profiles are located at example.com/profiles/user1. Now I need to provide the functionality to the users to use their custom domains for profiles. For example user1.com should render content from example.com/profiles/user1
Please suggest me the best solution for my problem. I am working on Shared Hosting - Linux Server.
For this functionality, you need to point user1.com to example.com/profiles/user1
For this I can think of two methods:
1. Name server Method:
you can change name servers of user1.com to your example.com name servers like:
ns1.example.com
ns2.example.com
NOTE: This may take 3-4 hours to work
2. URL Forwarding Method:
You can also use URL forwarding to point user1.com to example.com .
This will give you basic idea of forwarding http://support.godaddy.com/help/article/422/forwarding-or-masking-your-domain-name
Assuming that you both have a wildcard record in DNS and that the webserver is configured to serve your Cake project from those hostnames (how to do these things will depend upon your hosting provider), then (with thanks to Subdomaining with Cake), you simply need to place the following in app/config/bootstrap.php:
$subdomain = substr( env('HTTP_HOST'), 0, strpos(env('HTTP_HOST'), '.') );
if( strlen($subdomain)>0 && $subdomain != 'www' ) {
$_GET['url'] = 'user/' . $subdomain . '/' . (isset($_GET['url']) ? $_GET['url'] : '');
}
Related
Lets say for example my website address is: www.example.com
I let my users each have a website at user1.example.com, user2.example.com - I have achieved this through wildcard sub domains etc.
How can I let my users have these sites (which I host) at specialpage.theirsite.com? They would add a cname record for specialpage pointing to userpages.example.com - How would I handle hosting these pages once they have been pointed? Preferably in PHP!
The best solution is to use CloudFlare wildcard DNS entries to point all unset subdomains to the A record for userpages.example.com and then use a php script in the directory for userpages.example.com to check if the subdomain has been setup.
<?php
$subdomain = array_shift((explode(".",$_SERVER['HTTP_HOST'])));
if ($subdomain IN DATABASE) echo DATABASEOUTPUT;
else echo 'Domain: "' . $subdomain . '.example.com"';
?>
I'm building an application that uses sub domains and custom domain names that sit in the database for users, so if a request comes from another domain I'll check from the database if that custom url is indeed there or when the request comes from a subdomain, I'll check if that's there. If it is I do my stuff.
Consider this a simple example of I'm looking for:
if(is_user_request())
{
$url = get_url();
// assuming that get_url() magically decides whether to output ..
// a custom domain (http://domain.tld)
// or a subdomain's first part (eg. "this".domain.tld)
}
else
{
// otherwise it's not a sub domain nor a custom domain,
// so we're dealing with our own main site.
}
Now before you go ahead assuming that because I have 0 rep, I'm here asking for "teh codes". I have a completely working way of doing this, which is the following:
// hosts
$hosts = explode('.', $_SERVER['HTTP_HOST']);
// if there is a subdomain and that's under our $sitename
if(!empty($hosts[1]) AND $hosts[1] === Config::get('domain_mid_name'))
{
$url = $hosts[0];
$url_custom = false;
}
// if there is no subdomain, but the domain is our $sitename
elseif(!empty($hosts[0]) AND $hosts[0] === Config::get('domain_mid_name') AND !empty($hosts[1]) AND $hosts[1] !== Config::get('domain_mid_name'))
{
$url = false;
$url_custom = false;
}
// otherwise it's most likely that the request
// came from a entirely different domain name.
// which means it's probably $custom_site
else
{
$url = false;
$url_custom = implode('.', $hosts);
}
if($url)
{
return $url;
}
if($url_custom)
{
return $url_custom;
}
However, I'm sure there are better way of doing this. Because first of all, HTTP_HOST does not include 'http://', so I need to add that manually and I'm pretty sure this entire if, else thing is just an overkill. So, people smarter than me, enlighten me, please.
Oh and, no .. I do not have pre-defined sub-domains. I have a simple wildcard *.domain.tld set up, so all sub-domains go to the main script. I'm just saying this because from my search for a solution I found numerous answers that suggested to manually create a sub-domain, which is not even remotely related to what I'm asking, so let's skip that subject.
$_SERVER['HTTP_HOST'] is the correct way to do it unless you want to pass different parameters from your web server into PHP.
As for the protocol, be aware the request protocol should be determined by $_SERVER['HTTPS'] rather than assuming it's http.
For extracting the subdomain you could look at using array_shift and then running
$subdomain = array_shift(explode('.', $_SERVER['HTTP_HOST']));
But generally what you have is how it should be done.
As already said, $_SERVER['HTTP_HOST'] is the way to go.
But there are errors in your code. You're assuming that host names sent consist of 2 or 3 components but you can't be sure of that. You should at least check count($hosts) too.
If by example you use domain.tld for your own site then you're better off with first checking if domain.tld is sent (you return your page, fast); then see if substr($_SERVER['HTTP_HOST']...,-11)==='.domain.tld' and if so, return the subsite (works with any level of subdomain, still fast); else error-recovery, since a completely foreign domain has been routed to you. The key thing to note is that domain matching from the hierarchy's top means matching the hostname strings right-aligned:
.domain.tld | subsite-pattern
sub12.domain.tld | MATCH
sub12.dumain.tld | NO MATCH
sub12domain.tld | NO MATCH
I have my site on the server http://www.myserver.uk.com.
On this server I have two domains:
one.com and two.com
I would like to get the current domain using PHP, but if I use $_SERVER['HTTP_HOST'] then it is showing me
myserver.uk.com
instead of:
one.com or two.com
How can I get the domain, and not the server name?
Try using this:
$_SERVER['SERVER_NAME']
Or parse:
$_SERVER['REQUEST_URI']
Reference: apache_request_headers()
The best use would be
echo $_SERVER['HTTP_HOST'];
And it can be used like this:
if (strpos($_SERVER['HTTP_HOST'], 'banana.com') !== false) {
echo "Yes this is indeed the banana.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 banana.com to the domain you were looking for..
$wordToHighlight = "banana.com";
$serverVarHighlighted = str_replace( $wordToHighlight, '<span style=\'background-color:#883399; color: #FFFFFF;\'>'. $wordToHighlight .'</span>', $_SERVER );
echo "<pre>";
print_r($serverVarHighlighted);
echo "</pre>";
exit();
?>
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 off; 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 = 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 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:
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.
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.
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.)
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 usecanonical 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 usecanonical
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.
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="myserver.uk.com?domain=one.com"/>
And then you could set a session variable that persists this data throughout your application.
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.
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!
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.
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.
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.
I am on shared hosting and on a add on domain.
I need to create subdomain for each user of my website like if the username is jeff then he should have a url jeff.mydomain.com.
How can I create it programmatically using PHP?
There's two parts to this. Firstly you'll need to setup a wildcard dns entry.
Once you've got that setup you should have all your requests pointed back to a single domain. From there you can then use php to figure out which domain you're currently on:
$domain = $_SERVER['HTTP_HOST'];
$base = 'mydomain.com';
$user = substr($domain, 0, -(strlen($base)+1));// the user part of the domain
if(!empty($user)) {
$user = sanatiseUser($user);
require_once $user.'.php';
}
You need to set apache to listen for all domains coming into a specific IP.
You then need to setup a wildcard DNS entry to point *.domain.com to that IP.
Then inside your app, use $_SERVER['HTTP_HOST'] to determine which user to load.
What's the most reliable, generic way to construct a self-referential URL? In other words, I want to generate the http://www.site.com[:port] portion of the URL that the user's browser is hitting. I'm using PHP running under Apache.
A few complications:
Relying on $_SERVER["HTTP_HOST"] is dangerous, because that seems to come straight from the HTTP Host header, which someone can forge.
There may or may not be virtual hosts.
There may be a port specified using Apache's Port directive, but that might not be the port that the user specified, if it's behind a load-balancer or proxy.
The port may not actually be part of the URL. For example, 80 and 443 are usually omitted.
PHP's $_SERVER["HTTPS"] doesn't always give a reliable value, especially if you're behind a load-balancer or proxy.
Apache has a UseCanonicalName directive, which affects the values of the SERVER_NAME and SERVER_PORT environment variables. We can assume this is turned on, if that helps.
I would suggest that the only way to be sure and to be secure is to define a constant for the url in some kind of config file for the site. You could generate the constant with $_SERVER['HTTP_HOST'] as a default and replace with a hard coded definition on deployments where security really matters.
define('SITE_URL', $_SERVER['HTTP_HOST']);
and replace as needed:
define('SITE_URL', 'http://foo.bar.com:8080/');
As I recall, you want to do something like this:
$protocol = 'http';
if ( (!empty($_SERVER['HTTPS'])) || ($_SERVER['HTTPS'] == 'off') ) {
$protocol = 'https';
if ($_SERVER['SERVER_PORT'] != 443)
$port = $_SERVER['SERVER_PORT'];
} else if ($_SERVER['SERVER_PORT'] != 80) {
$port = $_SERVER['SERVER_PORT'];
}
// Server name is going to be whatever the virtual host name is set to in your configuration
$address = $protocol . '://' . $_SERVER['SERVER_NAME'];
if (!empty($port))
$address .= ':' . $port
$address .= $_SERVER['REQUEST_URI'];
// Optional, if you want the query string intact
if (!empty($_SERVER['QUERY_STRING']))
$address .= '?' . $_SERVER['QUERY_STRING'];
I haven't tested this code, because I don't have PHP handy at the moment.
The most reliable way is to provide it yourself.
The site should be coded to be hostname neutral, but to know about a special configuration file. This file doesn't get put into source control for the codebase because it belongs to the webserver's configuration. The file is used to set things like the hostname and other webserver-specific parameters. You can accomodate load balancers, changing ports, etc, because you're saying if an HTTP request hits that code, then it can assume however much you will let it assume.
This trick also helps development, incidentally. :-)
$_SERVER["HTTP_HOST"] is probably the best way, after some validation of course.
Yes, the user specifies it and so it cannot be trusted, but you can easily detect when the user is playing games with it.
One idea for validating that $_SERVER['HTTP_HOST'] is valid could be to validate it by DNS. I've used this method in one or two cases without serious consequences to speed and I believe this method fails silently if provided a IP address.
http://www.php.net/manual/en/function.gethostbyname.php
Peusudo code might be:
define('SITEHOME', in_array(gethostbyname($_SERVER['HTTP_HOST']), array(... valid IP's)))
? $_SERVER['HTTP_HOST']
: 'default_hostname';
why {if you wish the user to continue using http:///host:port/ that they are on do you wish to generate full urls}
whan you can use relative urls instead of either
say on page http://xxx:yy/zzz/fff/
you culd use either
../graphics/whatever.jpg
{to go back one directory from current and get http://xxx:yy/zzz/graphics/whatever.jpg
or
/zzz/graphics/whatever.jpg
{to goto site root and work up the directories as specified}
these both avoid mentioning the host:port part and inherit it from the one currently in use