Simulating MVC/CoC folder structure in php with mod_rewrite - php

My project directory structure:
project_root/
|- src/
| |- model/
| |- view/
| |- controller/
| -- ...others
-- resources/
|- css/
|- js/
-- images/
Ok, somewhere in src there is a file responsible for redirecting controllers, views and so on, let us say it is the src/url_mapping.php, it is prepared to solve any kind of url, such as /{controller}/{action}/{id}?{query}, there is no problem here, the big deal is I do not want the user realize this folder structure exists, I want to hide it from them and let the flow as simples as RoR and other based systems.
I want allow only http://host/{css,js,images}/* from resources without allowing http://host/resources/* itself, and http://host/{controller}/{action}/{id}?{query} to the src/url_mapping.php file denying direct access to http://host/src.
For now, the closest I managed is the following .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/resources/$1 !-f
RewriteCond %{DOCUMENT_ROOT}/resources/$1 !-d
RewriteCond %{DOCUMENT_ROOT}/resources/$1 !-l
RewriteRule (?!^resources/|^src/url_mapping.php/)^(.*)$ src/url_mapping.php/$1 [L,PT]
RewriteCond %{DOCUMENT_ROOT}/resources/$1 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/resources/$1 -d [OR]
RewriteCond %{DOCUMENT_ROOT}/resources/$1 -l
RewriteRule (?!^resources/)^(.*)$ /resources/$1 [L,PT]
</IfModule>
In that case my first intention was: If users tries to get /resources or /src folder it will be filtered by src/url_mapping.php as well, although I am trying several combinations with no success over and over again.
I noted mod_rewrite are in loop such a way I can not block resources directory as well as src/url_mapping.php, I am limited to .htaccess file with my hands tied, but if there is another way to do that I will accept the solution.
The last choice is do only one redirect and treating even files in resources by src/url_mapping.php, but it will kill the cache, I am avoiding reinvent the wheel.

Well, I realised apache is not so smart, so an acceptable solution I found was changing the directory tree to hide the non-resources content such a way apache cannot access.
Imagine the DocumentRoot is /home/user/www, so if you browse to http://hostname/somefile will point to /home/user/www/somefile, this way files in /home/user/somedir/somefile is not accessible by apache, but could be accessible by your PHP script if it has ownership/permission over that directory.
So, everything in resources I put on /home/user/www and the src was on /home/user/private_html, only my url_mapping.php stayed on /home/user/www/index.php, this way I can fool the user if I throw 404 Not Found when direct accessing it.
The final tree:
project_root
|- private_html
| |- model
| |- view
| |- controller
| -- ...others
-- public_html
|- css
|- js
|- images
-- index.php
Where my .htaccess file is:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase / # Change it if there are a subdirectory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>
And my index.php is:
<?php
if (!array_key_exists('REDIRECT_URL', $_SERVER) && substr($_SERVER['REQUEST_URI'], 0, strlen($_SERVER['SCRIPT_NAME'])) == $_SERVER['SCRIPT_NAME']) {
header('HTTP/1.0 404 Not Found');
exit;
}
define('VALID_KERNEL', true);
require '../private_html/core/core.php';
$server = new Server();
$server->request(array_key_exists('PATH_INFO', $_SERVER) ? $_SERVER['PATH_INFO'] : '/', $_REQUEST);
?>
This way it permits to access index.php only if it is the DirectoryIndex, I mean, http://hostname/ is allowed but http://hostname/index.php is 404 Not Found because this file should not exist, as well as http://hostname/index.php/anything and http://hostname/index.php?anything, although http://hostname/anything will redirect to http://hostname/index.php/anything but with REDIRECT_URL so it is allowed.

Related

How redirect to a static page in Public dir in a Symfony5 project

I have a simple static website.
On that I build a Symfony project to have an admin panel with easyadmin-bundle and an API to retreive data with ajax on the static page.
The project structure is like this:
bin/
config/
migrations/
public/
css/
js/
index.html
index.php
.htaccess
src/
templates/
Everythings works fine but I can only access to the page when I call :
myfakedomain.com/index.html
The page myfakedomain.com is returning a 404 error
What I would like to have is an automatic redirection from myfakedomain.com/ to myfakedomain.com/index.html
I think this can be done ine the .htaccess file. This is the current content of the .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$
RewriteRule .* - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by Apache
RewriteCond %{HTTP:Authorization} .+
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
RewriteCond %{ENV:REDIRECT_STATUS} =""
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>
This project is deployed on heroku so I create a Procfile
web: vendor/bin/heroku-php-apache2 public/
May it come from that ?
It comes from your .htacess which redirects all requests to index.php.
Option1 - using Apache (I don't like this method because of side effects)
Exclude the existing files from the redirection.
Declare index.html as the default file instead of index.php (when calling .
Tips: apache-pack can help you. It contains an up-to-date default configuration
Option2 - using Symfony (Recommanded way):
move index.html to template/index.html
Create a controller returning a response rendering the template files
# src/Controller/HomeController.php
class HomeController extends AbstractController
{
#[Route(name:'home', '/')]
public function index (): Response
{
return $this->render('index.html');
}
}

Slim Framework .htaccess forward

There are several questions out there to that topic, but not a single one did match my question, because I am using Slim Framework 3.
One of my routes, for example, is /stats
When I make requests to http://localhost/slim-app/public/stats - it works.
But, I want to make requests to http://localhost/slim-app/stats - and that doesn't work. Slim gives me the error
Page Not Found The page you are looking for could not be found. Check
the address bar to ensure your URL is spelled correctly. If all else
fails, you can visit our home page at the link below.
My folder structure looks like that:
/slim-app
.htaccess
/logs
/public
index.php
.htaccess
/src
routes.php etc
/templates
/tests
/vendor
The .htaccess- File inside the slim-app folder looks like that:
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
#RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
The .htaccess- File inside the public- folder like that:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
</IfModule>
What should I change inside the htaccess- files to make it work? Thank you guys!

Emulating Node/Express Routes in .htaccess

I have been trying to emulate how nodejs/express work with their routes. I am forwarding all traffic to index.php to process routes (using AltoRouter).
My file struture is something like this:
-/
--public/
|- assets
|- ...
--routes/
|- route.php
|- ...
--index.php
Take these urls for instance (all should return/redirect 404):
http://testsite.com/routes
http://testsite.com/routes/route.php
http://testsite.com/somefile.php
However only assets should be directly accessible like so (I dont want to include /public/:
http://testsite.com/assets/image.png
http://testsite.com/assets/styles/style.css
This is what I have so far:
# Make sure mod_rewrite is on
<IfModule mod_rewrite.c>
RewriteEngine on
# This should allow us to get our assets and keep them public
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.(gif|jpg|png|jpeg|css|js|swf)$ /public/$1.$2 [L,NC]
# Forward other traffic to index.php
RewriteRule ^.+$ index.php [L]
</IfModule>
One issue i've come accross is going: http://testsite.com/routesproduces:
I Guess my main question is anything that isnt in public shouldnt be accessable (not sure if .htacces is the way to go or not)
You don't have to bury your files above web root if you use the right rules. Private files can easily be made inaccessible.
<IfModule mod_rewrite.c>
RewriteEngine on
# transform assets URLs to correct path, and proceed to next rule
# checking existence in RewriteConds is useless here since public URLs are not 1:1 physical paths
RewriteRule ^assets/.+ public/$0 [NS,DPI]
# send *all* URLs to index.php except those that point to an asset file that exists
RewriteCond $1 !=public/assets/ [OR]
# change the slash in next condition to your sub-directory if not serving from the web root, e.g. %{DOCUMENT_ROOT}/project/root/$0
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteRule ^((?:[^/]+/){2})?.+ index.php [NS,END]
</IfModule>

Deploy Laravel to domain subfolder

Intro
I am struggling to deploy a Laravel project to a domain subfolder... Here's the complete "story":
My teacher has control of the machine at: http://ilp.fe.up.pt/
He created a user for me called mitocondrias so I could use it via ssh like:
ssh mitocondrias#ilp.fe.up.pt
He also set the usual public_html folder to be called html only.
So, to sum up, if I create a simple hello world index.html at /home/mitocondrias/html/ I can successfully see it at http://ilp.fe.up.pt/mitocondrias/
What I did
Now, regarding the Laravel deploy, here is what I did:
I cloned my Laravel project called CoExpr to my user home: /home/mitocondrias/coexpr
I deleted the html folder and created a symlink to /home/mitocondrias/coexpr/public called html with the following command:
mitocondrias#ilp:~$ ln -s ~/coexpr/public/ html
So, here is the final tree structure:
ilp.fe.up.pt/ (the root of my teacher web hosting)
|
|-- mitocondrias/ (my user home, aka /home/mitocondrias)
| |
| |-- coexpr/ (the Laravel project)
| | |
| | |-- [...]
| | |-- public/
| | |-- [...]
| |
| |-- html/ (this is actually not a folder,
| | but a symlink to /home/mitocondrias/coexpr/public/)
I also ran the following commands to set the correct Laravel permissions:
chmod -R 755 coexpr/
chmod -R o+w storage
The problem
After all this, I can successfully see the landing page at: http://ilp.fe.up.pt/mitocondrias/ (the equivalent of localhost:8000 if I were serving the app with php artisan serve)
But when I try to use other routes, like: http://ilp.fe.up.pt/mitocondrias/explorer (the equivalent to localhost:8000/explorer) I get:
404 Not Found
The requested URL /home/mitocondrias/html/index.php was not found on this server.
What did I do wrong..?
Extra info
In case this is relevant, the .htaccess in /home/mitocondrias/coexpr/public/ is as it was generated upon the Laravel project creation with composer - I did not touch it:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
And because of the symlink, this is also the .htaccess at /home/mitocondrias/html/.
End
So, that's it... Aff, this was a long post... Thanks in advance!
This related question provides a debugging hint: Check if the route works with /index.php/, to see if the problem is related to .htaccess.
Loading http://ilp.fe.up.pt/mitocondrias/index.php/explorer works!
So for some reason your .htaccess is not working.
Maybe simply enabling it will fix your problem, as stated in this answer to another related question.

htaccess Challenge: rewrite perfection for secure website structure

I am working on a new project where I want to improve the security by using 2 level folders.
The folder "Core" contains all the folders including the "public" which needs to be the only folder the visitor can access.
A short introduction about my webdir:
webdir
| - .htaccess (core)
| - classes
| - functions
| - public
| - .htaccess (public)
| - css
| - files
| - de
| - en
| - general
| - nl
| - images
| - index.php
| - js
| - swf
| - template
For your information:
My public/index.php file sorts out in which section the files are located via [geturl] and [section]. The request "http://example.com/nl/openfile" points to:
public/index.php
this file reads the $_GET and sees that [geturl] is "openfile" in the [section] "nl"
public/index.php wants to open: "files/nl/openfile.php"
this is how it works and I want it to work!
What I want to achieve with my .htaccess is the following:
The website supports 3 languages: en/de/nl. When no language is set then the nl language should be default.
http://example.com/nl/contact needs to target the file: public/files/nl/contact.php
Currently, when the visitor inputs http://example.com/nl/css (with no trailing slash, the problem doesn't occur when the trailing slash is added) the server translates this to http://example.com/public/css/?section=nl.
This is too much information for the visitor. I don't want users to see where the files are located.
The public folder should not be accessed directly. So when a users inputs http://example.com/public this should be redirected to http://example.com/nl/
My current .htaccess files:
.htaccess (core)
<IfModule mod_rewrite.c>
RewriteEngine on
Options +FollowSymLinks
Options -Indexes
RewriteCond %{HTTP_HOST} ^customer.com$ [NC]
RewriteRule ^(.*)$ http://www.customer.com/$1 [R=301,L]
RewriteRule ^company(.*)$ public/$1?section=company [L]
RewriteCond %{QUERY_STRING} (.*)
RewriteRule !(nl|en|de)/(.*).* /webdir/nl/ [R=301,L] # IF NO LANG ISSET THAN NL REDIRECT
RewriteRule ^error(.*).* public/?getpage=error&%1 [PT,L]
RewriteRule ^(nl|en|de)/(.*).* public/$2?section=$1&%1 [L]
</IfModule>
.htaccess (public)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{QUERY_STRING} (.*)
RewriteRule ^(.*).* index.php?geturl=$1&%1 [PT,L]
</IfModule>
What am I doing wrong and how can I improve the .htaccess files?
Summarized, I want the .htaccess to do the following:
The website supports 3 languages: en/de/nl. When no language is set then the nl language should be default.
http://example.com/nl/contact needs to target the file: public/files/nl/contact.php
Currently, when the visitor inputs http://example.com/nl/css (with no trailing slash, the problem doesn't occur when the trailing slash is added) the server translates this to http://example.com/public/css/?section=nl.
This is too much information for the visitor. I don't want users to see where the files are located.
The public folder should not be accessed directly. So when a users inputs http://example.com/public this should be redirected to http://example.com/nl/
Do you know you can block an entire directory by putting an .htaccess with deny from all inside?
This way you can keep your project structure simpler and more portable.

Categories