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]
Related
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.
On my website, I only use 3 slashes in my URL path:
https://example.com/this/isatest/
Right now I use .htaccess which makes it possible (as a side effect) to add as many stuff on the URL as you like:
https://example.com/this/isatest/hipperdihopperdus/pizza/bacon/with/cheese
I'd like to automatically remove everything after "isatest" while keeping the trailing slash using .htaccess.
This is what my .htaccess currently looks like:
Options -Indexes
Options +FollowSymLinks
RewriteEngine on
# 301 Redirect all requests that don't contain a dot or trailing slash to
# include a trailing slash
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !\.
RewriteRule ^(.*) %{REQUEST_URI}/ [R=301,L]
RewriteCond %{THE_REQUEST} /index\.html [NC]
RewriteRule ^index\.html$ /? [R=301,L,NC]
RewriteRule ^listen/$ /console/ [NC,L]
# Rewrites urls in the form of /parent/child/
# but only rewrites if the requested URL is not a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [L,QSA]
How can I achieve this?
As your first rule, after the RewriteEngine directive, you can do something like the following:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
This checks if there is anything else (the dot) after two path segments and a slash, and redirects to removed "anything else".
Note that this is a 302 (temporary) redirect. Only change this to a 301 (permanent) redirect - if that is the intention - once you have confirmed that it works OK. This is to avoid the browser caching erroneous redirects whilst testing.
UPDATE: It may be more efficient to simply avoid redirecting files that end in a recognised file extension. Or perhaps exclude known directory location(s) of your static resources. For example:
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|png|gif)$ [NC]
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
OR,
RewriteCond %{REQUEST_URI} !^/static-resources/
RewriteRule ^([^/]+/[^/]+/). /$1 [R=302,L]
You can add this rule just below RewriteEngine On line:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+/[^/]+/).+$ /$1 [R=301,L,NE]
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]
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]
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.