Using .htcaccess to redirect to www. AND add trailing forward slash - apache

I have searched around for a while and had a go at tweaking this file myself and I'm almost there but there is one case which I can't figure out...
How to get both a www. AND a forward slash at the same time
If I type in spectrl.com, it redirects to www.spectrl.com CORRECT - Adds www.
If I type in www.spectrl.com/ebaycalculator it redirects to www.spectrl.com/ebaycalculator/ CORRECT - Adds /
But if I type in spectrl.com/ebaycalculator I get a 404 error when it should go to www.spectrl.com/ebaycalculator/
Here's my .htcaccess file, kept at the root:
RewriteBase /
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://spectrl.com/$1/ [L,R=301]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Thanks

#Kavi
Try this:
RewriteEngine On
RewriteCond "%{HTTP_HOST}" "^(?:www\.)?(.*)" [NC]
RewriteCond "%{REQUEST_URI}" "!/$"
RewriteRule "(.*)" "http://www.%1%/$1/" [R=301,L]
RewriteCond "%{HTTP_HOST}" "!^www\." [NC]
RewriteRule "(.*)" "http://www.%1/$1" [R=301,L]
The first RewriteCond captures the hostname (without any leading www.) in the reference %1. That condition will always succeed.
The second RewriteCond checks for the trailing slash; if not found, the next RewriteRule will be triggered.
That first RewriteRule uses the captured www.-less host name to construct a redirect that includes www. and the training /.
The second stanza will be triggered if the request falls through because it does have a trailing /. It checks for a leading www., and does the same sort of redirect (only without appending a slash, since there's already one there) as the first stanza.
At least, that's how is should work; I haven't tested it. :-)

After removing and re-uploading .htaccess and then clearing the cache, everything seems to be working as intended using my original code in the question.
Hope this will be helpful for someone else.

Related

Apache Redirect // to no //

An email went out with the wrong link (https://www.digitalmarketer.com/digital-marketing/content-marketing-strategy//) and we need to redirect the // to (https://www.digitalmarketer.com/digital-marketing/content-marketing-strategy/) but no matter what I try, the redirect isn't working.
They also want it to be redirected to always have https:///www at the beginning and to never have index.html at the end, so already in the .htaccess file I have:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteRule ^content\-marketing\-strategy/index\.html$ /digital-marketing/content-marketing-strategy/? [L,R=301]
I've tried adding a new RewriteRule, but this won't work:
RewriteRule ^content\-marketing\-strategy//$ /digital-marketing/content-marketing-strategy/? [L,R=301]
I'm very new to Apache and redirects so any help is much appreciated! Thank you!
Edit: Of note, this is in an .htaccess file inside of the digital-marketing folder (https://www.digitalmarketer.com/digital-marketing/.htaccess) which was done so all the above rules would only apply to the digital-marketing folder.
You can use insert rule at the end of your other rules to strip multiple // into /:
RewriteCond %{THE_REQUEST} //
RewriteRule ^.*$ /digital-marketing/$0 [R=301,L,NE]
Apache automatically strips down multiple // into one inside the pattern for RewriteRule thus captured value $0 will have all // converted into /
You can write a wildcard expression to remove trailing slashes. The below will match any HTTP or HTTPS URL that trails in a forward slash, and remove all trailing forward slashes from that URL:
RewriteRule ^(.*)/+$ $1 [R=301,L]
And more using 301 redirects, see more here: Best Practice: 301 Redirect HTTP to HTTPS (Standard Domain)
Good luck!
I see nothing in the way that the rule is written that would make it not rewrite. However you have multiple rules with the L flag that might stop processing on the rewrite at an earlier point than you are looking for. From the documentation
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed.
(https://httpd.apache.org/docs/current/rewrite/flags.html).
You can try this page out http://htaccess.mwl.be/ to test all your rules together. You might have to rewrite them a bit to work with that page, it's not aware of the level your .htaccess file is at so you will have to rewrite all your rules to trigger from the root for example: RewriteRule ^digital\-marketing/content\-marketing\-strategy//$ /digital-marketing/content-marketing-strategy/? [L,R=301]

htaccess issue with non-www redirect and trailing slash

I currently redirect all traffic to the www. version of my site. However, upon checking redirected links in a specific folder, I've noticed something that may / may not be an issue.
Basically, if I do a header check on www.example.com/example/examplepage/ it shows 200 OK.
If I check www.example.com/example/examplepage (without trailing /) it shows 301 redirect to the above as it should.
BUT, if I check example.com/example/examplepage/ (without www), it redirects to www.example.com/example/examplepage.php ... which then redirects to www.example.com/example/examplepage/ (the correct page).
I hope this makes sense?
a) is this OK?
b) am I missing something in my .htaccess?
RewriteOptions inherit
RewriteEngine On
RewriteCond %{THE_REQUEST} ^.*/index.htm
RewriteRule ^(.*)index.htm$ http://www.example.com/$1 [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
RewriteCond %{THE_REQUEST} \.php
RewriteRule ^tips/([^.]+)\.php$ http://www.example.com/example/$1/ [R=301,L]
RewriteRule ^tips/([^.]+[^./])$ http://www.example.com/example/$1/ [R=301,L]
RewriteRule ^(tips/[^.]+)/$ /$1.php [L]
Please note: the above PHP rule was created to "hide" .php extensions on a specific folder (didn't want them hidden anywhere else).
I managed to work it out (well, ok - got lucky guessing), but either way, it seems to work now. I've adapted the above rule order to show the following:
RewriteEngine On
RewriteCond %{THE_REQUEST} \.php
RewriteRule ^tips/([^.]+)\.php$ http://www.example.com/tips/$1/ [R=301,L]
RewriteRule ^tips/([^.]+[^./])$ http://www.example.com/tips/$1/ [R=301,L]
RewriteCond %{THE_REQUEST} ^.*/index.htm
RewriteRule ^(.*)index.htm$ http://www.example.com/$1 [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
RewriteRule ^(tips/[^.]+)/$ /$1.php [L]
This now results in:
http://example.com/tips/examplepage.php (and www version)
http://example.com/tips/examplepage - without trailing slash (and www version)
All finally redirecting to www.example.com/tips/examplepage/ (with trailing slash)
It also ensures www.example.com/examplepage.php (not within the "tips" folder) keeps it's extension.
It also re-writes index.htm to / (using both www and non-www).
I've tried to add as much detail here as possible in the hope it prevents someone else wasting an entire weekend pulling their hair out, going gray etc...

.htaccess - rewrite with https and trailing / in one step has unintended conseqences

I added an ssl certificate to my website recently using cloudflare. I added some lines to my .htaccess to use https by default. Looking at google page speed insights, I notice that when visiting a sub-directory of my website using http, three redirects were occurring. For example the following redirect chain would occur when visiting http://markfisher.photo/galleries.
http://markfisher.photo/galleries
https:://markfisher.photo/galleries (Sorry, not enough rep for >2 links. Double colon is to break link)
http:://markfisher.photo/galleries/
https:://markfisher.photo/galleries/
I fixed this (i.e. combining the https and trailing slash in one step) by modifying the relevant lines in .htaccess to
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_HOST} ^markfisher.photo$ [OR]
RewriteCond %{HTTP_HOST} ^www.markfisher.photo$
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}\/ [L,R]
The only change from before was adding / towards the end of the bottom line. This works as intended for subdirectories of my website, but when visiting the root directory with http http:://markfisher.photo, it gets redirected to https:://markfisher.photo//. This works fine but looks ugly. I can't work out how to stop the double trailing slashes from occuring. I'm guessing it has something to do with a global .htaccess file used by my host but I don't know what that file(s) might contain so I'm struggling to work it out.
Also if anyone could tell my how to get www in there as will without any additional redirects that would be great.
The following worked. I separated into 2 cases - one where the trailing slash was absent and needed to be rewritten in, and on where it was present and so an extra slash was unwanted.
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_HOST} ^markfisher.photo$ [OR]
RewriteCond %{HTTP_HOST} ^www.markfisher.photo$
RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} !^/.*/$
RewriteRule ^ https://www.markfisher.photo%{REQUEST_URI}\/ [R=301]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTP_HOST} ^markfisher.photo$ [OR]
RewriteCond %{HTTP_HOST} ^www.markfisher.photo$
RewriteCond %{REQUEST_URI} ^.*/$
RewriteRule ^ https://www.markfisher.photo%{REQUEST_URI} [R=301]

How to avoid chain redirections using mod_rewrite?

Basicly i'm working on my site to be SEO-friendly. I wanted to achieve following:
Rewrite urls to pretty ones
Remove multiple slashes (eg. example.com/////something/// to example.com/something/
Redirect www version to a non-www version.
Hide index.php file from all urls
Redirect from old (/?id=something/ to new urls /something/)
I came up with this .htaccess code:
RewriteCond %{THE_REQUEST} //
RewriteRule .* $0 [R=301]
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^id=([a-z0-9\/-]+)
RewriteRule ^(.*)$ http://example.com/%1? [R=301]
RewriteRule ^index.php(.*)$ /$1 [R=301]
RewriteRule ^([a-z0-9\/-]+)$ /?id=$1 [L]
...and though it's working it has a side effect: chain redirects, eg. example.com/?id=something////// -> example.com/something////// -> example.com/something/
So is there a way to rewrite or modify this code so it'll be redirecting just once to the preferred version of the url?
Trying to interpret what you want, let's look at the rules in your question:
.1 Can't understand the purpose of this:
RewriteCond %{THE_REQUEST} //
RewriteRule .* $0 [R=301]
.2 This rule-set in your question removes www and converts the query string ?id=val to /val, but only when the incoming URI has www AND there is a query string as both conditions must be met:
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^id=([a-z0-9\/-]+)
RewriteRule ^(.*)$ http://example.com/%1? [R=301]
.3 This rule
RewriteRule ^index.php(.*)$ /$1 [R=301]
Hides index.php, but only when it is in the root directory. Example:
http://www.example.com/index.php?id=val
Does not work when it is in a subdirectory. Example:
http://www.example.com/folder/index.php?id=val
.4 Can't understand the purpose of this:
RewriteRule ^([a-z0-9\/-]+)$ /?id=$1 [L]
I suggest this instead:
RewriteEngine On
RewriteBase /
#Redirects all www to non-www
RewriteCond %{HTTP_HOST} www\.example\.com$ [NC]
RewriteRule ^(.*)/?$ http://example.com/$1 [R=301,L]
#Hides "index.php" keeping the query if present
RewriteRule ^(.*)/index\.php$ $1/ [R=301,QSA,L]
#Converts query string `?id=val` to `/val`
RewriteCond %{QUERY_STRING} id=([^/]+)
RewriteRule .* /%1? [R=301,L]
Remember spiders will "adapt" to the correct new structure after a few months, and the problem may ultimately be a whole lot less severe than what it looks like initially. You can leave all the .htaccess code in place, knowing it always be there to correct any "old" references yet will in fact hardly ever actually be used.
I've never found an easy way to avoid multiple round trips back to the client when "fixing up" a URL to be in some sort of canonical form. mod_rewrite seems to be more focussed on the "local" redirect case where the client has no idea that the content it got back came out of a file structure that doesn't perfectly match that implied by the URL.
It is possible to save up all the URL mods locally, then provoke only one round trip to the client that delivers all the URL corrections all at once by setting everything in newly created "environment" variables then at the end asking basically "has anything changed?" However doing so is notably verbose and rather awkward and quite error-prone and has never become a "recommended technique".

htaccess - rewritecond issue

I have an htacess file for apache that isn't working properly.
I have a default cactch-all that grabs all requests however it's still catching the matched URL above it (ajax/*). I thought that condition to match urls not containing ajax would stop it but it isn't.
RewriteRule ^ajax/(.*)$ process_lite.php [QSA,L]
RewriteRule ^resources/(.*)$ resources/$1 [L]
RewriteCond %{REQUEST_URI} !\.(css|jpg|js|gif|png)$
RewriteCond %{REQUEST_URI} !^ajax
RewriteRule ^(.*)$ process.php [QSA,L]
Can someone help me out?
It's probably because the first rule matches /ajax/ requests and rewrites it to /process_lite.php, thus the RewriteCond %{REQUEST_URI} !^ajax doesn't match since the URI is now process_lite.php. The regular expression you use won't match anything anyways because REQUEST_URI variable will start with a leading slash. You can try changing the condition to:
RewriteCond %{REQUEST_URI} !^/process_lite.php
Additionally, the "resources" rule doesn't seem to do anything except end rewriting, you could change it to this if that's the goal:
RewriteRule ^resources/ - [L]