trailing slashes in 301 redirect - apache

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.

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.

.htaccess - remove everything after third slash in path

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]

Apache, rewrite/redirect all to index.php - is not empty REQUESTED_FILENAME

I want to forward everything to index.php except if no file (REQUESTED_FILENAME) was specified or with other words URI is empty or take one /.
I've tried this conditions to rewrite/redirect all to index.php in the .htaccess - file.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.php/$1 [QSA]
If I call http://my.dom/test.php, the content of the test.php is displayed (!-f).
Next try: Check, if requested file not index.php and then redirect to index.php
RewriteCond %{REQUEST_FILENAME} !index.php
RewriteRule ^(.*)$ /index.php/$1 [QSA,R=301]
Ok this works. But i would like no redirect by empty requested file.
Next try: Redirect if requested file is not empty and requested file is not index.php
RewriteCond %{REQUEST_FILENAME} !^$
RewriteCond %{REQUEST_FILENAME} !index.php
RewriteRule ^(.*)$ /index.php/$1 [QSA,R=301]
If I call http://my.dom/test.php it works fine, redirect to index.php/test.php :D.
If I call http://my.dom or http://my.dom/ its also redirect to index.php.
But i would like no redirect by empty requested file.
Update (1)
I've now this in my .htaccess.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ / [QSA,R=301]
#this redirect all files to root
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ /index.php/$1 [QSA,L]
#this rewrite on server side to index.php
This doesn't work. http://my.dom/test.php was redirect to http://my.dom/. But the second rule makes an internal (550) error (every time redirect). I've put a new condition to the first section
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} !^/.*$
RewriteRule ^(.*)$ / [QSA,R=301]
#this redirect all files to root
By this: http://my.dom/test.php does not redirect.
Please tell me where my mistake is. And maybe a few solutions.
Regards
Its because / is not a file, / points to your root directory. You cant match against your root dir using Request filename variable. To exclude your homepage from the rule, just change your regex pattern to (.+) .
Or you can use the following rule
RewriteEngine on
RewriteRule ((?!index\.php).+) /index.php/$1 [L]

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]

.htaccess Rewrite Within Directory - Hide PHP extension and force trailing slash

I'm trying to hide the .php extension from my files as well as force a trailing slash on the resulting URLs.
Example: A request to /about.php would become /about/ and requests to /about would go to /about/.
The following rewrite code worked perfectly when I was in the root of my hostdomain:
RewriteEngine On
RewriteRule ^(.*)/$ /$1.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://edit.mydomain.org/$1/ [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)\.php\ HTTP/ [NC]
RewriteRule .+ http://edit.mydomain.org/%1 [R=301,QSA]
However, I need to move my files into a directory of this host name. Adding a directory name to the rules and having the .htaccess in the directory itself didn't work at all and seems to cause a endless redirect.
I looked around StackOverflow and other websites and tried numerous examples and ended up with many different errors with the most common being:
Everything is an endless redirect.
Everything except the directory home page is a 500 Error.
about.php redirects to /about but there's no redirect to /about/ and /about/ displays a 500 Error.
Everything working, but the home page (of the directory) index.php when accessed without a filename goes into an endless redirect.
Things redirect to edit.mydomain.org/home/username/public_html/mydomain.org/edit/pagename.php which obviously doesn't exist.
Thanks for any help! I really need to keep these files in a directory although the .htaccess could go into the host name root if its needed.
The directory for this would be edit.mydomain.org/dave/
Save this as a .htaccess and put it in the 'dave' directory
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\..+$
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^(.*)$ http://edit.mydomain.org/dave/$1/ [R=301,L]
RewriteRule ^(.*)/$ $1.php [L]
This works for me
RewriteBase /
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html