Remove trailing slash with htaccess with existing rules - .htaccess

I wish to remove a trailing slash when one is given using htaccess. What would be the best way to do it that will work with my existing rules as below:
# make sure www. is always there
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# if requested url does not exist pass it as path info to index.php
RewriteRule ^$ index.php?/ [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?/$1 [QSA,L]
A sample URL would be something like:
https://www.example.com/this-test/
I of course want the ending slash removed.
I've tried this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ /$1 [R,L]
But that does not work with the existing rules that are there. It ends up redirecting to the index.php pages due to the other rules.

Have it this way:
Options -MultiViews
DirectoryIndex index.php
RewriteEngine On
# add www and turn on https in same rule
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} !on
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]
# Unless directory, remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^(.+)/+$
RewriteRule ^ %1 [R=301,NE,L]
# if requested url does not exist pass it as path info to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php?/$0 [QSA,L]
Make sure to test it after completely clearing browser cache.

Related

How to let htaccess distinguish between files and ids

Options +FollowSymLinks
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d # not an existing dir
RewriteCond %{REQUEST_FILENAME} !-f # not an existing file
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}\.php -f # and page.php exists
# redirect to the physical page
RewriteRule ^(.*)$ $1.php [L]
# otherwise, redirect to serve.php
RewriteRule ^ /serve.php [L]
RewriteRule ^(\w+)$ ./serve.php?id=$1
So in the first part of the code I just turn http into https. My aim is that I can use urls without an .php but in my old code I had the problem that if I did so, it was used as an id for my serve.php page. So if use https://example.com/contact it was like https://example.com/serve.php?id=contact but I want it to work as https://example.com/contact.php but on the other side I want that ids that arent directions or file should still work as ids. My old code was...
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(\w+)$ ./serve.php?id=$1
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
You can use these rules in your site root .htaccess:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
# skip rules below this for files and directories
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# rewrite to the physical php page
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
# otherwise, redirect to serve.php
RewriteRule ^/?$ serve.php [L]
RewriteRule ^(\w+)/?$ serve.php?id=$1 [L,QSA]

htaccess no-trailing-slash policy: non existing urls (404) should not redirect

If I open a non existing url on my site like www.domain.de/abcde/ (with trailing slash) the url redirects to www.domain.de/abcde (without trailing slash) and opens the 404 site after.
But the 404 site should come directly when the url does not exist (without redirecting for the non-trailing-slash policy).
What do I need to add to my htaccess? Thank you!
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]
------
starkeens suggestion does only work on a clean htaccess, but I got some more code. It does not work together with the other lines. All the code:
RewriteEngine on
RewriteBase /
# redirect urls without www. to url with www.
RewriteCond %{HTTP_HOST} ^domain\.de$
RewriteRule ^(.*)$ http://www.domain.de/$1 [L,R=301]
# hide the suffix of urls
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.+)\.html\ HTTP/
RewriteRule (.*).html$ /$1 [R=301,L]
# start redirect everything to the subfolder
RewriteCond %{HTTP_HOST} ^(www\.)?domain\.de [NC]
# except these folders:
RewriteCond %{REQUEST_URI} !^/downloads [NC]
RewriteCond %{REQUEST_URI} !^/cms [NC]
RewriteCond %{REQUEST_URI} !^/vorschau [NC]
RewriteCond %{REQUEST_URI} !^/domain/.*$
RewriteRule ^(.*)$ /subfolder/$1
# end redirect everything to the subfolder
# no-trailing-slash policy
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]
Any new suggestions? :)
TRY :
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ - [R=404,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]
Finally i got a solution that seems to work.. maybe anyone got the same issue and needs the code. Comments for optimization are welcome!
# trailing Slashes
# to enforce a no-trailing-slash policy with subfolder
# is the request for a non-existent file?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# if so, skip the next RewriteRule
RewriteRule .? - [S=1]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]
Now only existing files get the redirect of my no-trailing-slash policy. Non existing files aren't redirected and occur a 404 page directly, as wished.

Redirect non-www to www. equivalent but allow one REQUEST_URI regex match?

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{REQUEST_URI} !^.+?games/.+?\.jpg$ [NC] #if does not match then proceed with redirect...
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
RewriteRule ^.+?games/(.+?)\.jpg$ index.php?g=$1 [L] #will only get to this point if not starting with www.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
Above code does not work, what am I doing wrong?
Problem is your use of REQUEST_URI variable that changes to /index.php due to your last rule and when mod_rewrite runs again your first rule happily adds www in the URL.
You should use THE_REQUEST variable, THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of some rewrite rules.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{THE_REQUEST} !games/.+?\.jpg [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
RewriteRule ^.+?games/(.+?)\.jpg$ index.php?g=$1 [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]

strange htaccess query parameters

I have searched some on this site but couldn't find a right answer to my question.
I am trying to force a www redirect and forcing an endslash on each url.
I have the following lines in my htaccess:
# enable rewriting
RewriteEngine on
# if not a file or folder, use index.php
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L]
# force www
RewriteCond %{HTTP_HOST} !^www
RewriteRule .? http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# force endslash
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule (.*) %{REQUEST_URI}/ [L,R=301]
My www redirect is working fine, it will go like:
http://example.com
to
http://www.example.com
But now the strange part is, my end slash line is adding the url parameter which I don't want.
So this will go like:
http://www.example.com/path/without/endlash
to
http://www.example.com/index.php/?url=path/without/endslash
Why is it that my defined url parameter is used in this case, and how can I prevent this.
Thanks in advance
EDIT:
thanks to icrew
Only added no-file/no-dir before the endlash entry because otherwise it would redirect my assets.
Final code:
RewriteCond %{HTTP_HOST} !^www
RewriteRule .? http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/index.php
RewriteRule (.*) %{REQUEST_URI}/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
This part of .htaccess
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L]
is responsible for http://www.example.com/index.php/?url=path/without/endslash redirection. So basicly if you do not want url parameter in query string remove those three lines.
Edit: I figure out what you wanted. Bellow is correct code
# enable rewriting
RewriteEngine on
# force www
RewriteCond %{HTTP_HOST} !^www
RewriteRule .? http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# force endslash
RewriteCond %{REQUEST_URI} !(.*)/$
#next row prevent redirection if final rewriting is done
RewriteCond %{REQUEST_URI} !=/index.php
RewriteRule (.*) %{REQUEST_URI}/ [L,R=301]
# if not a file or folder, use index.php
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
#QSA because I suppose you dont want to discard the existing query string. Remove QSA if you want to discard
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]

https in htaccess and order of rules (using Expression Engine)

I'm building a site in expression engine that part of needs to be https. The site is also using a new domain name (new one www.example-new.com the old one www.example.old.com).
I want to do the following things:
remove the index.php
force www
force https for any url starting www.example.old.com/extranet
redirect https URLs that are not www.example.old.com/extranet (e.g. www.example.old.com/news to http
I have the following code so far that works for the first two requirements:
<IfModule mod_rewrite.c>
RewriteEngine On
# Force www
RewriteCond %{HTTP_HOST} ^example-new.com$ [NC]
RewriteRule ^(.*)$ http://www.example-new.com/$1 [R=301,L]
# Removes index.php
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
AddType x-httpd-php53 .php
I seem to be going round in circles, so I've two questions that will help me write the other rewrites (although feel free to share suggestions...):
1) Should the code for requirements 3 and 4 be positioned before "removes index.php" code?
2) Does the position have any bearing on the redirects that will be coming from the old site e.g. www.example-old.com/some-link-here.asp will be redirected to www.example-new.com/some-new-link-here
Thanks,
Gregor
1) Remove 'index.php' from ExpressionEngine URLs
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
2) Add 'www' to all URIs
RewriteCond %{HTTP_HOST} !^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
3) Force https:// for any URI starting with /extranet
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/extranet(.*)$ [NC]
RewriteRule . https://%{HTTP_HOST}%{REQUEST_URI}$1 [R=301,L]
4) Redirect https:// URIs that are not /extranet
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/extranet(.*)$ [NC]
RewriteRule . http://%{HTTP_HOST}%{REQUEST_URI}$1 [R=301,L]
Putting it all together, here's your complete set of RewriteRules:
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/extranet(.*)$ [NC]
RewriteRule . https://%{HTTP_HOST}%{REQUEST_URI}$1 [R=301,L]
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/extranet(.*)$ [NC]
RewriteRule . http://%{HTTP_HOST}%{REQUEST_URI}$1 [R=301,L]
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
1) Should the code for requirements 3 and 4 be positioned before "removes index.php" code?
The rules are processed in the order that you write them. I expect that you want the site to redirect first then do the remove index, so yes, it should go before
2) Does the position have any bearing on the redirects that will be coming from the old site e.g. www.example-old.com/some-link-here.asp will be redirected to www.example-new.com/some-new-link-here
If you are using the same directory for both sites, then you would need to prefix all rules for one site with a RewriteCond that limits the domain. Otherwise, order of the rules (old vs new site) is important.
Your redirects from the old site should also incorporate rules in the new e.g. ensure that you are going to http/s as necessary to avoid extra redirects.
Below is the code to force http/s
#if not secure
RewriteCond %{HTTPS} off
#and starts with /extranet
RewriteCond %{REQUEST_URI} ^/extranet [NC]
#redirect to secure
RewriteRule . https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
#if secure
RewriteCond %{HTTPS} on
#and does not start with /extranet
RewriteCond %{REQUEST_URI} !^/extranet [NC]
#redirect to http
RewriteRule . http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# force www on hostname, but keep same protocol (http/https)
RewriteCond %{HTTP_HOST} !^www\.(.+)
RewriteCond %{HTTPS}s ^(on(s)|offs)
RewriteRule ^ http%2://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
If it helps... I just did this yesterday for an ecommerce site... Here's my .htaccess file
# Remove WWW from URL
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]
# Add a trailing slash to paths without an extension
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteCond %{REQUEST_METHOD} !=POST
RewriteRule ^(.*)$ $1/ [L,R=301]
#remove index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1
#Force HTTPS on checkout/account pages
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} (checkout|account)
RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
#remove HTTPS on all other pages
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(img|_|images|checkout|account)
RewriteRule ^(.*)$ http://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

Resources