make .htaccess to prevent navigating to directories - apache

I have this .htaccess
DirectorySlash On
RewriteEngine On
RewriteRule /?\.htaccess$ - [F,L]
# Remove trailing slash
RewriteRule ^(.*)/$ /project/$1 [R,L]
# Map every link to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/project/index.php.*$
RewriteRule ^(.*)$ /project/index.php?___MYROUTER=$1 [QSA,END]
but when I'm navigating to one of directories next to my .htaccess file like css folder in browser, with this address:
http://localhost/project/css
then my address will be changes to:
http://localhost/project/css?___MYROUTER=css&___MYROUTER=css&___MYROUTER=css&___MYROUTER=css&___MYROUTER=css&___MYROUTER=css&___MYROUTER=css&___MYROUTER=css&___MYROUTER=css&___MYROUTER=css
and in firefox this is the result:
The page isn’t redirecting properly
Firefox has detected that the server is redirecting the request for
this address in a way that will never complete.
This problem can sometimes be caused by disabling or refusing to accept cookies.
but other addresses those are not pointing to an existing directory, will be ok like:
http://localhost/project/mycontroller
this address is ok and will not be changed to anything else
What is the problem with my .htaccess?
this is my log file

That is because Apache is adding a trailing slash in front of directories after mod_dir module has completed execution.
You can add a trailing slash in front of directories yourself using a separate rule.
DirectorySlash On
RewriteEngine On
RewriteRule /?\.htaccess$ - [F,L]
# Remove trailing slash for non directories
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /project/$1 [R,L]
# add a trailing slash to directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301,NE]
# Map every link to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/project/index\.php [NC]
RewriteRule ^(.*)$ project/index.php?___MYROUTER=$1 [QSA,END]

Related

Remove the subfolder from the url path, given that there is no slash at the end

I have the htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /pages/$1 [L]
it removes /pages/ from the url to the pages
but when i open link without the slash at the end:
site.com/contacts
it is redirected to
site.com/pages/contacts/
Is there a way to fix this?
I've tried different results, most often other options cause a redirect to site.com/index.php ( site.com/pages/index.php)
It is happening because pages/contacts is a directory and Apache mod_dir module is adding a trailing slash after request to a directory.
You can check for directory presence and add a trailing / via a rule before rewrite to pages/:
RewriteEngine On
# add a trailing slash if pages/$1 is a directory
RewriteCond %{DOCUMENT_ROOT}/pages/$1 -d
RewriteRule ^(.*?[^/])$ %{REQUEST_URI}/ [L,R=301,NE]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /pages/$1 [L]
Make sure to use a different browser or remove cache data from your browser to test this rule to avoid old cache.

Why does Apache throw a Forbidden error when using RewriteRule and going to an URL with a trailing slash at its end?

I want to build a search page for my application, and I am using .htaccess to make URLs look better. The search page is located at localhost/search. Furthermore, two optional parameters can be appended at the end of the URL, like this: localhost/search/post/12345. However, when no parameters are appended, only a trailing slash (localhost/search/), Apache throws a Forbidden error. I am not sure why this is happening as there is no folder named search on the server.
To better illustrate my problem, here are the links that work and the ones that don't are as follows:
Working:
localhost/search
localhost/search/post
localhost/search/post/
localhost/search/post/12345
localhost/search/post/12345/
Not working:
localhost/search/
search.php is located in the root directory along with the .htaccess file. So here is the .htaccess file:
RewriteEngine On
# Redirect HTTP traffic to HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
# Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/$ $1 [R=301,L]
# Resolve .php file for extension-less php urls
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^/.]+)$ $1.php [L]
# Search parameters
RewriteRule ^search?/?([0-9a-zA-Z_-]+)?/?([0-9a-zA-Z_-]+)?/?$ search.php?type=$1&data=&2
# 404 error
ErrorDocument 404 /errors/404.php
I figured out the problem, following this helpful answer on StackOverflow. In the .htaccess file, I changed the following lines:
# Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/$ $1 [R=301,L]
to:
# Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ /$1 [L,R=301]

mod_rewrite making a directory available from all directories/subdirectorries

I want to link a directory like:
/resources/IMG/
to all other directories like
/IMG/ would resolve to /resources/IMG/
and also
/foo/IMG/bar/anything.img should resolve to /resources/IMG/bar/anything.img
with .htaccess. I have tested several methods of doing this, which one would be the best working one?
EDIT: SOLUTION
# Add trailing slash to any directory if not done so
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*[^/])$ /$1/ [R=301,L]
# MAP /resources/IMG/ to be avaible as /IMG/ from everywhere
RewriteCond %{REQUEST_URI} !^/resources/IMG/
RewriteRule ^(?:.*/IMG/)(.*)$ /resources/IMG/$1 [L]
The best way of dealing with /IMG (without trailing slash) is to firs map it and then add the slash, but since it is a 301 redirect it will refresh the REQUESTED_URI and the url will be /resources/IMG/ but if you always add a trailing slash it should work fine.
You can use this rule as your very first rule:
DirectorySlash Off
# Add trailing slash to any directory if not done so
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.
RewriteRule ^(.*[^/])$ /$1/ [R=301,L]
RewriteCond %{REQUEST_URI} !^/resources/IMG [NC]
RewriteRule ^(?:.*?/)?(IMG(?:/.*)?)$ /resources/$1 [L,NC]

Redirect to index.php in root

I've written the following code in my htaccess file:
RewriteRule ^(.*)/$ $1
RewriteCond %{REQUEST_URI} !^index.php.*$
RewriteRule ^(.*)$ /index.php?route=$1 [END]
It works perfect for every path, except for directories that exist. For example, if I enter http://localhost/profilepic and such directory actually exists, it redirects to http://localhost/profilepic/?route=profilepic, but I want it to be implicitly converted to http://localhost/index.php?route=profilepic.
Thanks in advance.
The reason this is happening is because of mod_dir and the DirectorySlash directive. Essentially, if it sees a URI without a trailing slash, and it maps to an existing directory, then it'll redirect the request so that it has the trailing slash. Since mod_dir and mod_rewrite are both in different places in URL-file processing pipeline, both mod_dir and mod_rewrite get applied to the same URL. That's why you end up with a redirect and a weird URL with the query string.
If you absolutely must have directories without trailing slashes, then you need to turn of DirectorySlash. The problem with turning it off is that there is an information disclosure security concern that will make it so people can look at the contents of a directory even if you have an index file. That means you have to make up for mod_dir using mod_rewrite.
So get rid of the rule:
RewriteRule ^(.*)/$ $1
and replace it with these rules:
DirectorySlash Off
# redirect direct requests that end with a slash to remove the slash.
RewriteCond %{THE_REQUEST} \ /+[^\?\ ]+/($|\ |\?)
RewriteRule ^(.*)/$ /$1 [L,R]
# internally add the trailing slash for directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*[^/])$ /$1/ [L]
Here is another way you can have your rules without turning off DirectorySlash (considered a security hole):
RewriteEngine On
# remove trailing slash for non-directories
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} \s(.+?)/+[?\s]
RewriteRule ^(.+?)/$ /$1 [R=301,L]
# routing for directories
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+?)/$ /index.php?route=$1 [L]
# routing for non directories
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+?)/?$ /index.php?route=$1 [L]

trailing slashes in 301 redirect

I've tried to look through the multiple mod_rewrite questions, so I apologize if this is a duplicate.
I'm trying set it so that if you go to domain.com/about.php it removes .php and if you go to domain.com/about it simply remains like that.
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /$1.php [L,QSA]
RewriteRule ^(.*)/$ /$1 [L,R=301]
So, right now if you go to domain.com/about it displays the page, but if you go to domain.com/about.php it doesn't remove the extension.
Additionally, I have 301 redirects
redirect 301 /our-clients http://www.domain.com/about-ourclients
That works perfect, but if the user goes to domain.com/our-clients/ with the trailing slash, they are directed to about-ourclients.php
Any advice on how to rewrite my rules?
This should do the job:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
# remove .php ONLY if requested directly
RewriteCond %{THE_REQUEST} (\.php\sHTTP/1)
RewriteRule ^(.+)\.php$ /$1 [R=301,L,QSA]
# remove trailing slash ONLY if it is not an existing folder
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# rewrite to FILENAME.php if such file does exist and is not a folder
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ /$1.php [L,QSA]
It will redirect all direct requests to php files: /something.php will be redirected to /something
Will remove the trailing slash IF requested resource is not directory. So if you requesting /home/ and you do have such folder, then it will NOT be redirected to /home.
Will internally rewrite requests to the same named PHP file IF it does exist. If you are requesting /about and you have /about.php then it will do rewrite; If you have no /about.php then nothing happens (well, at least not on these rules -- if you have more rules then such request can be matched later .. or 404 error page will be shown).
If you are requesting /about, you have /about.php and you also have /about folder, then request will go into folder. If you do not want this to happen ( /about should always be rewritten to /about.php) then you need to remove RewriteCond %{REQUEST_FILENAME} !-d from last block. But since you have exactly the same condition in your current .htaccess then I assume it is desired behaviour.