So, I need to check the referrer to a page using php, and if it is *.example.com, or *.anothersite.com, execute code, but if not, redirect elsewhere.
How would I go about checking if the HTTP_REFERER is equal to those values, with a wildcard character?
Thanks!
EDIT: The url will contain more than one domain, so the regex needs to match the FIRST occurance found.
Should do it:
$allowed_host = 'example.com';
$host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
if(substr($host, 0 - strlen($allowed_host)) == $allowed_host) {
// some code
} else {
// redirection
}
Other answers' checks' are good but are not strictly bound to your website. So for example referer with value http://attacker.com/www.example.com/ will pass almost all the checks. And it is very easy to make such site and just send a cross-domain request.
There is a reliable and secure method to check if referer is really your domain. Of course referer can be spoofed, but a victim of an attacker site will send correct referer.
The trick is in ^ special character. Here is the magic regex:
^https?://(([a-z0-9-]+)\.)*example\.com/
^ - ensures that we are at the start
https? - protocol - http or https
(([a-z0-9-]+)\.)* - matches subdomains, also of higher levels, if any
example\.com - matches main domain
/ - ensures start of path so domain name cannot continue
$ref = $_SERVER['HTTP_REFERER'];
if (strpos($ref, 'example.com') !== FALSE) {
redirect to wherever example.com people should go
}
if (strpos($ref, 'example.org') !== FALSE) {
redirect to wherever example.org people should go
}
Of course, this only works if the referer is "nice". For instance, coming from google you could possibly have "example.org" in the search term somewhere, in which case strpos would see it, and redirect, even though you came from google.
preg_match('/(.+?)\.example\.(com|org)/',$_SERVER['HTTP_REFERER'])
This will only match an address that has a subdomain, and it also will not continue looking for anything beyond subdomain.example.com or .org. i.e. subdomain.example.com/some-other-stuff. Do you need to also match either of these?
Correction - this will match www.example.com but will not match example.com.
Try this:
if (preg_match('/\.example\.(com|org)/', $_SERVER['HTTP_REFERER']))
{
// execute your code
}
else
{
header("Location: http://example.com/redirectpage.htm");
exit();
}
Related
I'm writing a PHP application where the user can enter a URL and some operations take place afterwards (further details not relevant to this question).
Requirement: If the user enters example.com, it should be converted to http://www.example.com.
The http:// part is straight-forward but am struggling with the rules that determine whether www. is prepended. Since the URL could be anything that might work in a web browser, it could be localhost or 192.168.0.1 for example. For these, clearly www. shouldn't be prepended.
So the exclusion list from above is: "If the host is localhost or looks like a v4 IP address, don't prepend". But expect there will be other cases that need to covered - could anyone advise - or suggest an alternative way of approaching this?
You can validate the user input to IP and decide whether to concatenate the "www" or not.
The user input can be "127.0.0.1", "127.0.0.1:8080","http://127.0.0.1:8080' or "http://exaple.com:8080".
$input = ("127.0.0.1:8080");
[$host,$port] = explode(":",trim($input,"http://"));
if(!empty($port)){
}
if (filter_var($host, FILTER_VALIDATE_IP)) {
header("location:http://$host:$port");
} else {
header("location:www.$host:$port");
}
In PHP I have this URL which is valid:
http://example.net/dir/valid+page/
But some people replace + with space, ie. they try to access this URL instead:
http://example.net/dir/valid page/
Here, I think, space is replaced with %20 in the URL in browser.
My question is: how to detect if there is a space in this URL (or, probably better, in the part after /dir/) and if so, 301-redirect user to the version with the + instead?
I have this part of code, but the first line is missing:
if(??space_in_/valid page/_url??)
{
header('HTTP 1.1 301 Moved Permanently');
header("http://example.net/dir/valid+page/");
exit;
}
Get the path of the URL, and use preg_match to check if there is a space in the path.
$url = 'http://example.net/dir/valid page/';
if (preg_match ('/ /', parse_url ($url, PHP_URL_PATH))) {
header ('HTTP 1.1 301 Moved Permanently');
header ('Location: http://example.net/dir/valid+page/');
exit;
}
These are two different URLs you're talking about. http://example.net/dir/valid+page/ will give you your page, and http://example.net/dir/valid page/ will give you a 404 error. Putting code in the page won't help, because it never sees the invalid requests.
If you really feel you want to address this particular typo, you need to do so in your web server configuration. For Apache, you would add this:
Redirect permanent /dir/valid%20page/ http://example.net/dir/valid+page/
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 can't seem to work out why the below sends ALL traffic to the page-not-found page, even if referred by Paypal. Any ideas?
$refererUrl = $_SERVER['HTTP_REFERER'];
$Exploded = explode("/",$refererUrl);
$urlToCheck = $Exploded[3];
$findURL = strpos($urlToCheck,'paypal.com');
if($findURL === false){
header('location:/page-not-found');
} else {
/* Do something if page referred to by Paypal */
}
You are checking if 'paypal.com' is present in $Exploded[3]. Why do you expect that part of the referer url to be the hostname? Array indexes start at 0, so counting from left to right would give you the following, indicating that 2 would be the correct index.
$Exploded = explode('http://www.google.com/?q=foobar', '/');
// $Exploded now contains:
0: http:
1:
2: www.google.com
3: ?q=foobar
However, it would be more safe to use some utility that will parse arbitrary URLs and read the hostname from the interpreted url. You could do something like this (untested):
$referer = parse_url($_SERVER['HTTP_REFERER']);
if($referer['host'] != 'paypal.com')
header('location:/page-not-found');
else
/* Do something if page referred to by Paypal */
parse_url doc: http://php.net/manual/en/function.parse-url.php
Are you sure that HTTP_REFERER is set? If you have a look at the documentation it says
The address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.
Is it correct?
$urlToCheck = $Exploded[3];
If your reffer looks like http://www.example.com/....
the by exploding by "/" you will never got domain in 3rd index. It should be 2.
Try using
$urlToCheck = $Exploded[2];
Say my URL address is www.example.com
I want to have an if statement in my script such that the test condition is true if the url is www.example.com and false if it is anything else e.g. www.example.com/test or www.example.com?var=3&function=7.
How do I achieve this? And will it add much overhead to the loading of the webpage? As I will have this if statement on the front page of the website.
Thank you
It will add an insignificant amount of load time, as it's just parsing some header information.
$_SERVER['HTTP_HOST'] // The host (e.g. www.example.com)
$_SERVER['REQUEST_URI'] // The URI (e.g. /something.php or /something.php?this=true)
And to implement:
if ($_SERVER['HTTP_HOST'] != "www.domain.com") // Do something
Testing to see if you have any extra parameters can be done like this:
if(count($_GET) > 0) { /* parameters exist */ }
However, to test if the browser is pointing to /example, you will have to employ some URL rewriting, as it not pointing to your php file.
If you have the mod_rewrite on:
if($_SERVER['SCRIPT_URI'] == 'http://www.example.com' && !$_SERVER['QUERY_STRING'])
There should be no noticeable impact on performance.