Force trailing slash - .htaccess

I'm trying to force a trailing slash to my URLs, but I can't make it work the way I want. This is my .htaccess file:
RewriteEngine on
#Force trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !index.php
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ /$1/ [L,R=301]
#Subdomains
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteCond %{HTTP_HOST} ^([^/.]+)\.example\.com$
RewriteCond $1/%1 !^([^/]+)/\1$
RewriteRule ^/([^/]+)? /%1%{REQUEST_URI} [L]
#Point everything to page.php
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteCond $1 !^(.*).(php|css|js|png|jpg|gif|htm|html)$
RewriteRule ^(.*)$ page.php?q=$1 [L,NC]
If I go to "en.example.com/about" I'm redirected to "en.example.com/en/about/", which is an invalid page.
How can I make this work?

The problem here is that the L flag causes a restart of the rewriting process with the rewritten URL (I’ve already told you that, didn’t I?):
Remember, however, that if the RewriteRule generates an internal redirect (which frequently occurs when rewriting in a per-directory context), this will reinject the request and will cause processing to be repeated starting from the first RewriteRule.
Now when /about is requested, the first rule get’s applied and redirects to /about/. The subsequent request of /about/ is then processed, at first the third rule is applied and the URL path is rewritten to /page.php. So far, so good.
But now the internal redirect takes place and the rewriting process is restarted with the new URL path /page.php. This is then fetched by the first rule again and redirected externally to /page.php/.
The second rule shouldn’t be applied at all as the pattern ^/ should never match as the per-directory path prefix is removed before testing the pattern when using mod_rewrite in an .htaccess file:
When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the pattern matching and automatically added after the substitution has been done.
But these rules should work:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .*[^/]$ /$0/ [L,R=301]
RewriteCond %{HTTP_HOST} ^([^/.]+)\.example\.com$ [NC]
RewriteCond %1 !=www [NC]
RewriteCond $0/%1 !^([^/]+)/\1$
RewriteRule ^[^/]* /%1%{REQUEST_URI} [L]
RewriteCond %{HTTP_HOST} !=www.example.com [NC]
RewriteCond $1 !.*\.(php|css|js|png|jpg|gif|htm|html)$
RewriteRule .* page.php?q=$0 [L]

Related

htaccess cannot rewrite to proper URL

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^/articles/([0-9]+)/$ /article-one.html?aid=$1 [L]
from SEO friendly URL eg.
https://example.com/articles/99/aaaa-aabbbb-bb-cccccccc
rewrite to
https://example.com/article-one.html?aid=99
why does it not work?
^/articles/([0-9]+)/$
In a directory context (ie. .htaccess) the URL-path matched by the RewriteRule pattern does not start with a slash. However, this would only match URLs of the form /articles/99/, not /articles/99/aaaa-aabbbb-bb-cccccccc - as stated in your example.
You would need to modify the RewriteRule pattern to something like the following instead:
^articles/([0-9]+)/[\w-]*$
This specifically matches an optional trailing slug of the form aaaa-aabbbb-bb-cccccccc (no trailing slash). If you simply wanted to ignore anything that comes after the numeric path segment then just remove the trailing $ (end-of-string anchor). For example:
^articles/([0-9]+)/

redirect non-www to www with https excluding cdn and other sub domains

Right now I have this code
RewriteEngine On
RewriteBase /
# remove the .html extension
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.html\ HTTP
RewriteRule (.*)\.html$ $1 [R=301]
# remove index and reference the directory
RewriteRule (.*)/index$ $1/ [R=301]
# remove trailing slash if not a directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# forward request to html file, **but don't redirect (bot friendly)**
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.html [L]
#First rewrite any request to the wrong domain to use the correct one (here www.)
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
#Now, rewrite to HTTPS:
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Its working perfectly fine, however it's redirecting our cdn images from cdn.domain.com/img.jpg to www.domain.com/img.jpg how can I prevent that from happening?
You can prevent this by prefixing your rules with a condition testing for cdn. and no substitution
RewriteCond %{HTTP_HOST} ^cdn\.
RewriteRule ^ - [L]
This rule leaves the URL as it is -
- (dash)
A dash indicates that no substitution should be performed
(the existing path is passed through untouched). This is used
when a flag (see below) needs to be applied without changing
the path.
and stops further rewriting L|last
The [L] flag causes mod_rewrite to stop processing the rule set.

htaccess remove trailing slash causes redirect loop

I am amending my htaccess file to achieve non-www to www (this is working) plus removing the trailing slash at the end of the URL, e.g.:
www.domain.bc.ca/club/ ---> www.domain.bc.ca/club
www.domain.bc.ca/club/index.html/ ---> www.domain.bc.ca/club/index.html
The portion of the htaccess file is below - the Force www bit is working; the Remove trailing slash bit is not. Help! Many thanks, Amanda.
# Force www.
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^domain\.bc\.ca$ [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
#
# Remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^(.+)/$ /$1 [R=301,L]
I'm going to go out on a limb and guess that you're trying to access a directory when this happens. In your example, the "club" seems to be a directory and when you redirect /club/ to /club, a module called mod_dir will redirect it back to having the trailing slash again. There's a really good reason for this, because if the trailing slash is missing for a directory, the directory's contents will be displayed instead of the index file. That means if you were able to go to www.domain.com/club (without the trailing slash), you'd see all the contents of the club directory instead of the club/index.html file.
If that's ok with you, then you can turn off mod_dir by adding this to your htaccess file:
DirectorySlash Off
But then you'd need to internally add the slash back in:
DirectorySlash Off
# Force www.
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^domain\.bc\.ca$ [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
#
# Remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^(.+)/$ /$1 [R=301,L]
# Add the slash back
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+[^/])$ /$1/ [L]

Messy HTAccess File Gives Duplicate Homepage

I have the following HTAccess file:
ErrorDocument 404 /index.php?name=404
RewriteEngine on
# Add www. to any link without it
RewriteCond %{HTTP_HOST} ^mydomain\.co.uk$
RewriteRule ^(.*)$ http://www.mydomain.co.uk/$1 [R=301,L]
# Set homepage
DirectoryIndex index.php
# Rewrite content pages
RewriteRule ^sub1/([A-Za-z0-9_-]*)/$ index.php?sub1=1&name=$1
RewriteRule ^sub2/([A-Za-z0-9_-]*)/$ index.php?sub2=1&name=$1
RewriteCond %{REQUEST_URI} !^/404/
RewriteRule ^([A-Za-z0-9_-]*)/$ index.php?name=$1
# Make the pages without .php work
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^/]+)/$ $1.php
# Forces a trailing slash to be added
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ /$1/ [R=301,L]
This has gradually had bits and bobs tacked onto it and I now have a really small change to make, but can't work out how to do it.
The rules are basically there to ensure that all page have www and end in a /.
Most pages are in the form www.mydomain.co.uk/page/ which actually goes to mydomain.co.uk/index.php?name=page. There are two subdomains which pass an extra get param to the index.php.
The problem is that the homepage can be accessed from either www.mydomain.co.uk/ or www.mydomain.co.uk/index/.
How can I modify these rules so that if the user enters www.mydomain.co.uk it redirects to www.mydomain.co.uk/index/?
Try making the modification below to your .htaccess
### Existing Rules
# Add www. to any link without it
RewriteCond %{HTTP_HOST} ^mydomain\.co.uk$
RewriteRule ^(.*)$ http://www.mydomain.co.uk/$1 [R=301,L]
##New Rules
#if request for www.mydomain.co.uk
RewriteCond %{HTTP_HOST} ^www\.mydomain\.co\.uk$
#and it is for the home page, then redirect to index
RewriteRule ^$ http://www.mydomain.co.uk/index/ [L,R=301]
##Other Existing rules go here

Removing query_string from wildcard subdomain rewrite

My goal is to point:
http://xyz.domain.com/abc to http://www.domain.com/dir/file.php?var=xyz
(In other words, anything with http://_____.domain.com/abc would read from http://www.domain.com/dir/file.php?var=_____.)
I used this in my .htaccess file at the root of the website (http://www.domain.com/.htaccess):
RewriteCond %{HTTP_HOST} !^www.domain.com [NC]
RewriteCond %{HTTP_HOST} ^(www.)?([a-z0-9-]+).domain.com [NC]
RewriteRule ^abc/*$ dir/file.php?var=%2 [NC,L]
It worked, but then it automatically redirected to http://xyz.domain.com/abc/?var=xyz when I just wanted http://xyz.domain.com/abc without the query string showing up.
I considered adding a %{QUERY_STRING} line to the above but got stuck when trying to match the two RewriteCond's vars to each other.
Then I found this at http://www.askapache.com/htaccess/modrewrite-tips-tricks.html#Removing_Query_String
RewriteCond %{THE_REQUEST} ^GET\ /.*\;.*\ HTTP/
RewriteCond %{QUERY_STRING} !^$
RewriteRule .* http://www.askapache.com%{REQUEST_URI}? [R=301,L]
...which I'm guessing it's the right code to get rid of something like this on a regular domain? I tried making it suitable for wildcard subdomains by changing it to this:
RewriteCond %{THE_REQUEST} ^GET\ /.*\;.*\ HTTP/
RewriteCond %{QUERY_STRING} !^$
RewriteCond %{HTTP_HOST} !^www.domain.com [NC]
RewriteCond %{HTTP_HOST} ^(www.)?([a-z0-9-]+).domain.com[NC]
RewriteRule .* http://%2.domain.com%{REQUEST_URI}? [R=301,L]
But it doesn't work. SO...can anyone help?
There's a Module called mod_dir that redirects the browser when it thinks you are trying to access a directory but are missing the trailing slash. When I test on my apache it only happens when the directory actually exists, I get redirected with a trailing slash, but the rewrite happens and I see the query string. Try forcing, internally, the trailing slash and when rewriting to dir/file, expressly use a trailing slash:
# Force trailing slash when accessing /abc without one
RewriteRule ^abc$ /abc/ [NC,L]
# these are the same
RewriteCond %{HTTP_HOST} !^www.domain.com [NC]
RewriteCond %{HTTP_HOST} ^(www.)?([a-z0-9-]+).domain.com [NC]
# Match against a trailing slash
RewriteRule ^abc/$ dir/file.php?var=%2 [NC,L]

Resources