php if statement relating to the url address - php

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.

Related

Best way to detect if request came from a different domain or a sub domain

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

If URL contains something include .php file else do nothing?

I wish to include Smart PHP Cache layer on top of main script on site. It works great, but Smart Cache also caches some pages which should not be cached (search results, admin area...).
I looked into Smart PHP Cache source code, and I am not sure if there is some way to configure which pages should be excluded from cache, or how to configure it.
So, what I need is some php code which will be inserted at top of main script of site, before Smart PHP Cache code which will first check if page contains for example:
"/search/"
"/admin/"
"/latest/"
"/other-live-pages/live-page.php"
and then, if something from above example is in URL to do nothing, (not to include smart_cache.php and to continue with other normal code, so user could see live results) and otherwise if there is nothing from above to include smart_cache.php.
Or.
If you have better knowledge to make modification inside Smart PHP Cache to be able to exclude some URLs from caching mechanism (or to tell me how to do that, because it looks like there is something in configuration of Smart PHP Cache that can bypass the cache layer but I am not sure how to use it.
Best regards.
Question update:
Thanks for answer. It works nice, I just wish to ask can you please little change code to make this:
If "pos1" (if URL contains "/search"), than nothing, false, like it is now
if "pos2" (if URL contains "/admin"), than nothing, false, like it is now
if "pos3" (if URL contains "/latest") include file "smart_cache_latest.php"
and after that like it is now, include "smart_cache.php" for any other URLs.
So practically only change is for URLs with "/latest", which should be cached too by including "smart_cache_latest.php".
Best regards.
$currenturl = $_SERVER['REQUEST_URI'];
$pos1 = strpos($currenturl, "/search");
$pos2 = strpos($currenturl, "/admin");
$pos3 = strpos($currenturl, "/latest");
if ($pos1 === false && $pos2 === false){
require '/path/to/smart_cache.php';
} elseif($pos3 == true) {
require '/path/to/smart_cache_latest.php';
}

Checking PHP referrer

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();
}

How to detect if file is being accessed or requested?

A I have a PHP file that if the user access it directly he should be redirected to another location, but if my script call it through ajax, it should do nothing special.
For example, if a user access
/site/page.php
he should be redirected to
/index.php?view=page
But if he is on the index.php?view=page the file should load without redirects.
How can I do that?
EDIT: If you want to determine if a script was requested through Javascript or not, you'll have to signal it somehow.
Several toolkits define the header X-Requested-With. In that case, you can check for a Javascript call with:
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
//requested with Javascript
}
You can check the size of the result given by debug_backtrace.
Alternatively (better), you can check $_SERVER['SCRIPT_FILENAME']:
if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) {
//this one was requested; not in include
}
By "it should do nothing special" do you mean it shouldn't redirect?
So the Q is really if user accesses a URL for a PHP file directly, it should redirect, if thru AJAX, process as normal?
(to really clarify, you mean thru a URL and not thru a include statement, right?)
Answer: You can't. Artefacto mentions the HTTP_X_REQUESTED_WITH header - sure, but that can be faked.
Is it really so bad is the user accesses the URL directly?
If the answer is "OMG Yes!" then maybe there is something wrong with how the system is designed.
Redesign it until the answer is "Actually, I suppose it wouldn't really hurt."
If you really don't want someone accessing /site/page.php, you should consider moving /site/page.php outside of your web root. Then make your index.php load it as needed:
<?php
$includes = "/path/to/includes"; // specified in a config file somewhere
if ($_GET["view"] == "page") {
require_once(path_join($includes, "page.php"));
DoStuffInPageDotPHP();
}
else {
DoSomethingElse();
}
?>

How to find out programmatically if a web server instance supports url rewrite

What I want to ask is if there is a way to find out if a web-server instance has URL Rewriting enabled. I need this in order to be able to instantiate the correct type of URL handler.
Theoretically you know in advance if you have it enabled or not and can use something to configure it. I would like, however, to be able to detect this setting automatically at runtime.
The URL rewrite rule would be something very simple like:
^/(.*)$ => /bootstrap.php
This guarantees that the relevant string is present in the REQUEST_URI, but doesn't pollute the _GET array.
Where did my research took me so far:
Apache.
In my opinion Apache has a very quirky approach, since it sets the REDIRECT_SCRIPT_URI header for rewrote URLs, but not for the ones that are not rewrote.
E.g. http://host/ana/are/mere would be re-wrote to index.php so the aforementioned header would be present, but http://host/ wouldn't be re-wrote.
Lighttpd.
Lighttpd with fast-cgi behaves OK, setting the REDIRECT_URI header if URL Rewrite is enabled for the current host. This is reliable.
Cherokee.
Well, for Cherokee there is no method that I found out, as it uses (in my opinion) a more complicated method for obtaining URL rewriting. (I.e., it's called internal redirect – and the fcgi process doesn't know that the request was redirected)
Also I haven't tested other http servers, as nginx, so if someone has some input on this matter I would love to hear it.
Not the most elegant solution, but you could create a directory, insert a .htaccess and a small php file and try to open it with curl/file_get_contents() from your actual code:
.htaccess
RewriteEngine on
RewriteRule ^(.*?)$ index.php?myparam=$1
index.php
<?php
//open with file_get_contents("http://yoursite/directory/test")
if($_GET['myparam']){die("active");}
?>
Although this might be acceptable during an installation, for performance reasons this shouldn't be used for every request on your site! Save the information somewhere (sqlite/textfile).
Update
Apache specific, but apache_get_modules()/phpinfo() in combination with array_search/strpos is maybe helpful to you.
It's already touched upon below, but I believe the following recipe is a rather waterproof solution to this problem:
Set up the redirection
Request a page through its rewritten url
If the request returns the page in question, you have redirection set up correctly, if you get HTTP 404 response, then it's not working.
The idea is basically that this works with just about any redirection method. It has already been mentioned, but bears reiterating, such tricks add quite a bit of overhead and are better performed only once (installation or from the settings panel) and then saved in the settings.
Some implementation details, choices to make and a little on how I came to this solution:
I remembered Drupal did such a check during the installing process, so I looked up how they did it. They had the javascript on the install page do an ajax request (synchronously, to prevent concurrency issues with the database). This requires the user installing the software to have javascript turned on, but I don't think that's an unreasonable requirement.
However, I do think using php to request the page might be a cleaner solution. Alongside not bothering with a javascript requirement, it also needs less data to be sent back and forth and just doesn't require the logic of the action to be spread over multiple files. I don't know if there are other (dis)advantage for either method, but this should get you going and let you explore the alternative choices yourself.
There is another choice to be made: whether to test in a test environment or on the normal site. The thing Drupal does is just have the redirection always turned on (such as in the apache case, have the .htaccess file that does redirects just be part of the Drupal download) but only write the fancy urls if the redirection is turned on in the settings. This has the disadvantage that it takes more work to detect which type of redirection is used, but it's still possible (you can for example add a GET variable showing the redirection engine either on a specific test page or even on every page, or you can redirect to a page that sets $redirectionEngine and then includes the real index). Though I don't have much experience with redirection other than with mod_rewrite on apache, I believe this should work with just about every redirection engine.
The other option here is to use a test environment. Basically the idea is to either create a folder and set up redirection for it, or remove the need for file system write access and instead have a folder (or a folder for each redirection engine). This has some disadvantages: you still need write access to set up the redirection for the main site (though maybe not for all redirection engine, I don't really know how you all set them up properly - but for apache you will need write access if you are going to turn on redirection), it might be easier for a bot to detect what software and what version of it you are using through accessing the tests (unless you remove the test folders after testing) and you need to be able to rewrite for only a part of the site (which makes sense for any redirection engine to be a possibility, but I'm not blindly going to assume this functionality). However, this does come with the advantage of it being easier to find out which rewrite engine is being used or basically any other aspect of the redirection. There might also be other advantages I don't know of, so I just give the options and let you pick your method yourself.
With some options left to the user, I believe this should help you set up the system in the manner that you like.
PHP has server-specific functions for Apache, IIS and NSAPI servers. I only have Apache but as merkuro suggested this works as expected:
<?php
if (in_array('mod_rewrite',#apache_get_modules()))
echo 'mod_rewrite enabled';
else
echo 'mod_rewrite not enabled';
?>
As PHP server-specific functions don't cover all the servers you'd like to test in this probably isn't the best solution.
I'd recommend merkuro's first answer - implementing then testing it in script. I believe it's the only way to get a good result.
Hope that helps!
You can programmatically check for the existence of mod_rewrite if the server is Apache by using the apache_get_modules() function in PHP:
$modules = apache_get_modules();
echo in_array('mod_rewrite', $modules) ? 'mod_rewrite detected' : 'mod_rewrite not detected';
This could be used as the first step, but it is not a full proof method by any means. Just because mod_rewrite is loaded does not mean it is available for your environment. This also doesn't help if you are on a server that is not Apache.
There are not many consistent methods that will work across all platform combinations. But since the result is consistent, you can test for that. Setup a special redirect, and have a script use PHP's cURL or file_get_contents() to check a test URL. If the redirect was successful, you will get the expected content, and you can test easily for this.
This is a basic .htaccess I setup to redirect ajax to ajax.php:
RewriteEngine On
RewriteRule ajax ajax.php [L]
The following PHP script will attempt to get the contents of ajax. The real script name is ajax.php. If the redirect fails, then it will not get the expected contents.
error_reporting(E_ALL | E_STRICT);
$url = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['REQUEST_URI']).'/ajax';
$result = json_decode(#file_get_contents($url));
echo ($result === "foobar") ? 'mod_rewrite test was successful' : 'mod_rewrite test failed';
Lastly, here is the final piece of the script, ajax.php. This returns an the expected response when the redirect is successful:
echo json_encode('foobar');
I have setup a live example of this test, and I have also made available the full sources.
As all the awnser already mention, actually testing it is the only way to be sure it works. But instead of actually redirecting to an actual page and waiting for it to load, I would just check the header.
In my opinion this is quickly enough to be even used at runtime at a regular site. If it realy needs to be high performance, then ofcourse caching it is better.
Just put something like the following in your .htaccess file
RewriteEngine on
RewriteRule ^/redir/My/Super/Special/Hidden/Url/To/Test/$ /redir/longload.php [L,R=307]
And then you can use the following php code to check if mod_rewrite is enabled.
<?php
function HasModRewrite() {
$s = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : "";
$sp = strtolower($_SERVER["SERVER_PROTOCOL"]);
$protocol = substr($sp, 0, strpos($sp, "/")) . $s;
$port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]);
$options['http'] = array(
'method' => "HEAD",
'follow_location' => 0,
'ignore_errors' => 1,
'timeout' => 0.2
);
$context = stream_context_create($options);
$body = file_get_contents($protocol . "://" . $_SERVER['SERVER_NAME'] . $port .'/redir/My/Super/Special/Hidden/Url/To/Test/', NULL, $context);
if (!empty($http_response_header))
{
return substr_count($http_response_header[0], ' 307')>0;
}
return false;
}
$st = microtime();
$x = HasModRewrite();
$t = microtime()-$st;
echo 'Loaded in: '.$t.'<hr>';
var_dump($x);
?>
output:
Loaded in: 0.002657
---------------------
bool(true)

Categories