I've already checked the issue disable access to included files , but I am wondering if that's the best solution.
Context: I'm building a bootstrap class for my PHP Framework, and realized that there are multiple solutions to this security issue.
After researching and reading posts like the one I mentioned at first and others related to htaccess, I think that there are basically three types of solutions:
1 - Checking a constant (like in the post I linked)
if(!defined('THIS_IS_NOT_A_DIRECT_ACCESS')) {
header('HTTP/1.1 404 Not Found');
include('./../error/404.php');
die;
}
Or
require('../error/include_file.php');
//
if(!defined('THIS_IS_NOT_A_DIRECT_ACCESS'))
{
header('HTTP/1.1 404 Not Found');
include('404.php');
die;
}
2 - Redirecting all calls to the Bootstrap and making a clever filtering.
//Something like
// if $urlRequested it's a file
// Go to Error
// else if $urlRequested it's not a controller
// Go to Error
// else
// Execute Controller Logic.
3 - Setting htaccess.
# Redirecting calls for non-directories, files or links
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA]
# Redirecting the rest of the calls to the error page.
RewriteRule ^(.+)$ index.php?url=error/404 [QSA]
Personally I think the solution 3 is the most interesting, but I am pretty new in the Htaccess control so I wonder if this is a safe solution.
For the purists and minimalists, the Question in here would be:
Are these (the three examples) nice direct access control systems for Apache-PHP applications? Else, which would be the safest approach? And the simplest?
This is a debatable topic but .htaccess rules applies to all the document on that particular directory. While applying 1 or 2 you may have to include that portion on every file.
Looking at all the options listed here IMO better would be to just place these files above the public_html folder or whatever is your DOCUMENT_ROOT folder and include with ../ paths. Then it would be available to your PHP scripts but for the web requests would get a default 404/ file not found error.
Related
I'm currently converting an old website to use Symfony 4 and the site uses the LiveZilla live chat app.
LiveZilla lives in a subfolder of the site, and is accessed directly using URLs under somesite.com/livezilla. I can't currently access it of course, because I haven't configured a route for this folder. So Symfony decides that this will be a 404.
LiveZilla is essentially a completely separate app living in its own folder here. It isn't dependent on the website hosting it. Is there a way to tell Symfony to ignore certain paths so that code like this can be executed without interference?
I have a sneaking feeling that I need to adjust the way I am looking at this as I can't find anything obvious in the Symfony docs about this, and the framework is pretty well thought out. The best I have come up with so far is hacking public/.htaccess, but it feels wrong somehow...
Your .htaccess file should allow requests directly to existing files, but not directories. See this rule:
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
This means you should be able to access somesite.com/livezilla/index.php but a request to somesite.com/livezilla will redirect to the symfony front controller. So try changing your links to point to actual files within the sub-directory.
There is also nothing wrong with editing the .htaccess file to suit your needs. You just need a condition that checks if the request is to the sub-directory and if so use the same RewriteRule ^ - [L] as above to allow that request to continue.
The following should work if placed after the above rule (reference):
RewriteCond %{REQUEST_URI} ^/livezilla/
RewriteRule ^ - [L]
Or this may be better, place this rule immediately after the line RewriteEngine On(reference)
RewriteRule ^(livezilla) - [L]
The [L] flag means the rule will be the last one used for the request.
My question is very fundamental: The basic idea of a CMS is that there aren't real content files but in the simplest scenario one single file index.php, which:
reads the URL like domain.com/fruit/pineapple(.php) or
domain.com?cat=fruit&sort=pineapple,
fills itself with the pineapple-content from a datasource,
will be send back then to the client with the alias of the request URL.
About 1) How does the server know that index.php is in charge for every request? Is it only htaccess? Wordpress:
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Is this everything? Every nonexisting file is interpreted as an existing article of the content? So I have to check inside index.php that a forgotten image pineapple.png is sorted out?
About 2) How does the server rewrite the name index.php into /fruit/pineapple(.php) or ?cat=fruit&sort=pineapple ? This can't be a 301-rewrite, the server has to rebaptize index.php into the requested URL.
Question 1: Yes, RewriteEngine takes care of routing every call to index.php.
Edit: Actually, not every call, the lines with !-f !-d test if the call refers to an existing resource. It only routes to index.php if they don't exist. This allows for the server to send existing files (such as images and other included files, like js and css files) without help from index.php.
So, if I request domain.com/fruit/pineapple.jpg, and that image exists, I will get it. if it doesn´t exist, index.php gets called and it may generate a nice looking 404 page.
Question 2: No, this is not taken care by APACHE, it is taken care by index.php itself, by inspecting $_SERVER['REQUEST_URI'], and mathing its contents against a set of predefined routes.
This is called URL Routing. Each CMS has its own way of doing this, and there are also some libraries for PHP (or any other server-side language you prefer).
You can take a look at a longer explanation about How to Implement URL Routing in PHP
I am using Yii2 framework for my PHP development. In my view files, If I want to call any of the functions, I just use Class/Function name
Eg : www.example.com/SiteController[class name]/index[function name]
And it is calling the function.
I like to know, How to do the same in a pure php script ?.
I searched in many places and I could get the suggestions for special_autoload_register();. But I could not understand the exact practical application.
Guidance is expected and Thanks is advance.
Its easy :).
It's all based on apache module mod_rewrite. This module allows you to modify path behavior in .htaccess file.
Using this .htaccess file
RewriteEngine On
# The following rule tells Apache that if the requested filename
# exists, simply serve it.
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
# The following rewrites all other queries to index.php. The
# condition ensures that if you are using Apache aliases to do
# mass virtual hosting, the base path will be prepended to
# allow proper resolution of the index.php file; it will work
# in non-aliased environments as well, providing a safe, one-size
# fits all solution.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::$
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
you will get following behavior:
If requested file exists (/styles/style.css - styles, javascripts, images, etc) serve it (dont change anything on current behavior)
If requested file doesn't exist, go to index.php.
If you are redirected to index.php, you can find full requested url in $_SERVER['REDIRECT_URL'] or $_SERVER['REQUEST_URI']. There you can take it, parse and based on requested uri, behave.
Please take this as explanation post, not a guide on how to get this going. Mostly it requires some apache configuration because mod_rewrite is mostly disabled by default.
If you want to get things going, I would recommend this post.
To fully answer your question, you can for example explode request uri by "/" sign, save first part into $firstPart and second into $secondPart and then have
$controllerName = $firstPart."Controller";
$controller = new $controllerName;
$actionName = $secondPart."Action"
$response = $controller->$actionName();
So if you call /help/me, helpController->meAction() will be called.
I hope I helped :)
To do this, Yii 2 (and other PHP frameworks) have routers. The router in Yii 2 is the UrlManager class.
I would not advice you write a router from scratch for a solution you want to deploy. There are routing packages in PHP which you could easily use in your solution. I like Klein. It's a pure router in PHP.
However, if for academic purposes, you want to know how routing works in PHP, get to understand the $_SERVER reserved variable. It has all the details of the HTTP request coming to your script. You can then use the details from this to call the specific function you want to call.
I have an index.php file which I would like to serve different content based on the url structure.
For example. If the url is mysite.com/index.php/folder1 I run a certain query and display the results and if the url is mysite.com/index.php/folder2, run a different query.
The solution also has to work for mysite.com/folder1 etc (ie index.php omitted).
And it would be ideal if the same approach could be extended to mysite/com/folder1/category1 etc. Note, GET variables aren't desired here.
What you need is a routing component that links url's to classes/functions in your code that do stuff. This component execute certain class/function depending on your request.
In this question, different strategies are discussed, although there are some already existing frameworks missing that are interesting:
Symfony Routing Component
SlimPHP
You could use any of those to do exactly what I mention earlier. For example, using the Symfony Routing Component, you could have your routes (potential urls) in a config file like:
# routes.yml
route1:
path: /foo
defaults: { _controller: 'MyController::fooAction' }
route2:
path: /foo/bar
defaults: { _controller: 'MyController::foobarAction' }
So when the requested uri matches with "/foo", the method fooAction from the class MyController is executed.
If you are not sure about how to implement this in your existing codebase, I'd strongly recommend you to read a series of posts about how to use different Symfony components in your code, written by Fabien Potencier. There is a specific post about the routing part.
As for the need to remove "index.php/" from your url, you need to rewrite it. If you are using Apache, you need to add the rewrite rules in your virtual host configuration file, or just create an .htaccess file in your document root. There are hundreds of questions in StackOverflow about this (like this one), and plenty of documentation in the official documentation page.
Add following RewriteRule in your .htaccess file and put .htaccess file into your webroot
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Above rule redirects all requests to index.php if there is not file/directory exists on the system.
For example, without above rule if http://example.com/test returns 404 error, then with above redirect rule, this will resolved to index.php. Now, within index.php you can parse the URL and do processing according to your requirements.
The best way is probably to assign variables in the browser. e.g.
index.php?folder=1 AND index.php?folder=2
In php then you use:
$folder = $GET_['folder']
if($folder == 1)
{
//show site 1
}
else if ($folder == 2)
{
//show site 2
}
else
{
//error code
}
there are other ways including .htaccess but for someone who does not want to go into that, i found this was the best way
Ok, I am starting to wonder if this is even possible. I have been pouring over htaccess tutorials and examples and I just can't seem to get it working right.
I have a script that creates dynamic images running in a directory on a friends website. I have access to / but the actual directory I am using is in /mydir/. In order to display the images they are output to png via PHP. I have the following RewriteRule setup to take the filename requested and run a PHP script. Each filename represents a separate file with a serialized object used in the display.php script
RewriteRule ^(.*)\.jpg$ display.php?file=$1
That part is working fine, however if someone requests a file that doesn't exist it just throws PHP errors because the script gets called but there is no object for it to use.
What I am trying to do now, and utterly failing at, is to have it check if the file exists in ./Cache/ directory then run the script as usual and if not then the server can just throw a standard 404.
I have tried things like
RewriteCond %{REQUEST_URI} ^(.*)\.jpg$
RewriteCond %{DOCUMENT ROOT}/img/Cache/%1.jpg -f
and other combinations of REQUEST_URI, REQUEST_URL, SCRIPT_FILENAME, SCRIPT_NAME, etc. I can't seem to come up with the proper variable and regex expression to handle this so I am turning to you guys for help. The biggest problem is not knowing what is actually in each of those variables so I can see where I am going wrong. I would kill for some kind of var_dump(),
Use this rule:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/mydir/img/Cache/$1.jpg -f
RewriteRule ^(.*)\.jpg$ display.php?file=$1 [L]
This needs to be placed into .htaccess file in /mydir/img folder
If you move this folder somewhere else or rename parent folder, you will need update it as well in RewriteCond line.
If you wish you can try this approach, which is more flexible (no need to specify parent folder names) but I cannot guarantee that this will work on your setup (but it DOES work on my PC):
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} ^(.*)/([^/]+)\.jpg$
RewriteCond %1/Cache/%2.jpg -f
RewriteRule ^(.*)\.jpg display.php?file=$1 [L]
Here the current physical folder is determined automatically from requested URL. But if you have symbolic links or some other settings, it may produce incorrect results. Plus .. it has 1 more Condition .. which makes it a bit slower (1 extra regex to check).
I would use the PHP file to check it:
use file_exists in your PHP and if it does not exist, use header("HTTP/1.0 404 Not Found"); or header('Location to a 404 image