htaccess - Simple rewrite rule not triggering - apache

I'm trying to match a simple rule to rewrite a url but it's just not matching. I want to redirect
https://example.com/web/thanks/
to
https://example.com/thanks.php
Here's what I've tried
RewriteEngine On
RewriteBase /
RewriteRule ^thanks/$ https://example.com/thanks.php [R=302,L]
RewriteEngine On
RewriteRule ^thanks/$ https://example.com/thanks.php [R=302,L]
RewriteEngine On
RewriteBase /
RewriteRule ^/(.*)/thanks/$ https://example.com/thanks.php [R=302,L]
RewriteEngine On
RewriteBase /
RewriteRule ^web/thanks/$ https://example.com/thanks.php [R=302,L]
and many more tiny variations but none of them are triggering. I tried using this online tool and it returns "This rule was not met". What am I doing wrong?

To rewrite, just use your last rule
RewriteRule ^web/thanks/?$ /thanks.php [L]
with the following changes
no RewriteBase, this is only relevant for some relative URLs
optional trailing slash /?, if you want both /web/thanks or /web/thanks/ to work
no domain name, because this might trigger a redirect instead of a rewrite, see RewriteRule
Absolute URL
If an absolute URL is specified, mod_rewrite checks to see whether the hostname matches the current host. If it does, the scheme and hostname are stripped out and the resulting path is treated as a URL-path. Otherwise, an external redirect is performed for the given URL. To force an external redirect back to the current host, see the [R] flag below.
no R|redirect flag, because this triggers a redirect instead of a rewrite
The pattern ^.*thanks/$ or ^(.*)thanks/$ also works, but it matches any URL ending in thanks/, like /hellothanks/, /areyousurethanks/, /some/path/thanks/, ...

Related

htaccess redirect outcome not as expected

I hope someone can help me with the following problem.
I have a multiple language site with the language as a folder like
example.com/se/post
I want to get the language separated by domain like example.se.
So far no problem with a DNS alias and WPML plugin.
The problem I have is that I want to redirect example.com/se/post to example.se/post. I try to use this rule in the .HTACCESS file but it changes the URL to example.se/se with the /se that I do not need. I'm not very familiar with the rewrite engine in .HTACCESS file.
<IfModule mod_headers.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www\.)?nofairytales\.nl$ [NC]
RewriteCond %{REQUEST_URI} ^/sv(/.*)?$ [NC]
RewriteRule ^(.*)$ http://www.nofairytales.se%{REQUEST_URI} [L,R=301]
</IfModule>
RewriteCond %{HTTP_HOST} ^(www\.)?nofairytales\.nl$ [NC]
RewriteCond %{REQUEST_URI} ^/sv(/.*)?$ [NC]
RewriteRule ^(.*)$ http://www.example.se%{REQUEST_URI} [L,R=301]
This is close... you are capturing the URL-path (/post part) in the preceding condition but not using it in the substitution string. Instead, you are using REQUEST_URI which contains the full root-relative URL-path.
You are also matching sv in the URL-path, but redirecting to se in the TLD. The following should resolve the issue (with minimal changes):
RewriteCond %{REQUEST_URI} ^/se(/.*)?$ [NC]
RewriteRule ^(.*)$ http://www.example.se%1 [L,R=301]
Where %1 is a backreference to the captured subpattern in the preceding condition (the /post part).
However, You don't need the second (or even the first) condition(s), as it can be all done in the RewriteRule directive. There wouldn't seem to be a need to check the requested hostname, since if the language subdirectory is in the URL-path then it would seem you should redirect anyway to remove it.
For example, the following should be sufficient to redirect a single language code:
# Language "se"
RewriteRule ^se(?:/(.*))?$ https://www.example.se/$1 [R=301,L]
The non-capturing group that contains the slash delimiter ensures that we always have a trailing slash on the target URL (after the hostname). The first rule above requires the user-agent to "correct" the redirect response when the slash after the hostname is omitted (which it does).
For multiple languages you can modify the same rule with regex alternation. For example:
# All supported languages
RewriteRule ^(se|uk|us|au|id)(?:/(.*))?$ https://www.example.$1/$2 [R=301,L]
This assumes all language codes map to a TLD using the same code. If not then you can implement a "mapping" (lang code -> TLD) in the rule itself or use a RewriteMap if you have access to the server config. This could also provide a "default" TLD.
You could be more generic and allow any two-character language code in the regex. eg. ^([a-z]{2})(?:/(.*))?$. And simply pass this through to the TLD. However, a request for an unknown language (eg. /xx/post) - which might have resulted from an error on your site - will now result in either a malformed redirect (since the domain won't resolve) or worse, a redirect to a competitor lying in wait. And this might go undetected unless you run an analysis of your redirects. So, being more restrictive with the regex/rule may be advisable.

htaccess redirect to exclude certain pages

My htaccess file currently redirects everything and has this
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.domain.co.uk/$1 [R,L]
I need to exclude two urls that begin with "send"
I changed the last line to
RewriteRule !^send(.*) https://www.domain.co.uk/$1 [R,L]
It excluded the send urls but any url in a subfolder is redirected to the root index page.
RewriteRule !^send(.*) https://www.domain.co.uk/$1 [R,L]
Negated patterns don't capture anything (by definition), but trying to capture everything after send when send is not present in the URL, doesn't make much sense.
You can do something like the following and use the REQUEST_URI server variable in the substitution instead of the backreference:
RewriteRule !^send https://www.domain.co.uk%{REQUEST_URI} [R,L]
Note that the REQUEST_URI server variable already contains the slash prefix.

No trailing slash causes 404, how to fix using htaccess?

The URLs are:
(Doesn't work) http://example.com/seller/samsung
(Works) http://example.com/seller/samsung/
The .htaccess rule I have for these types of URLs looks like:
RewriteRule ^seller/[^/]+/(.*)$ ./$1
What can I do to make both of these URLs to go to the same page?
You could just force a trailing slash to appear on the end of your URLs. You can do that by using the following in your .htaccess:
RewriteCond %{REQUEST_URI} !(/$|\.)
RewriteRule (.*) %{REQUEST_URI}/ [R=301,L]
Just make sure you clear your cache before you test this.
EDIT:
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
What does the above do? So the condition grabs your directory, so for example /samsung and will check if it has a / on the end. If it does not, it will grab the directory at the end of URL (once again /samsung and add a / on to it. It will do this using a 301 redirect and would leave you with /samsung/.
As for the L flag (taken from official 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. This corresponds to the last command in Perl, or
the break command in C. Use this flag to indicate that the current
rule should be applied immediately without considering further rules.

Opencart 301 Redirects

Having a problem with redirect in a .htaccess file on an Opencart store.
It seems that any URL with /index.php?_route_= isn't getting redirected.
For example, this works:
redirect /old-url-here http://example.com/new-url?
This doesn't:
redirect /index.php?_route_=some-url.asp http://example.com
Any idea or suggestions as to what might get this to work?
You can't match against the query string using mod_alias' Redirect directive. You'll need to use mod_rewrite, and if you use mod_rewrite, you're probably going to want to stop using mod_alias altogether.
Try:
RewriteEngine On
RewriteCond %{QUERY_STRING} route=some-url\.asp
RewriteRule ^index\.php$ http://example.com/
Another thing is - apart from Jon's answer - that URLs like index.php?_route_=some-keyword are used/created only internally and only in case you have the SEO turned on. In this case, you click on a link with URL like http://yourstore.com/some-keyword and this URL is rewritten into index.php?_route_=some-keyword.
Therefore you shouldn't be creating URLs like that on your own nor try to redirect from them. If you need to redirect, catch the first SEO URL to redirect it.
We do not know where did you put your changes into the .htaccess file, but if you take a close look at this rewrite rule
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]
not only you'll find out it is the last rule there, but it also has this L switch which is telling Apache server that if this rule is matched, do a URL rewrite(, attach the query string [QSA] and) stop matching other rules [L] - this is the Last one.
If you need to redirect only a specific URL, do it the same way as redirect for sitemap.xml is done (for example) and place it before the last rewrite rule:
RewriteEngine On
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
# ...
# your new rule here - while the URL in the link is http://yourstore.com/some-url.asp
RewriteRule ^some-url.aspx$ index.php?route=some-folder/some-controller [L]
# ...
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]

Using a .htaccess to RewriteRule and Redirect 301 at the same time?

I have a couple of specific URLs that I want to display differently on my website. For example I want "/contact.php" to become "/contact". So I added this to my .htaccess:
RewriteRule ^contact$ contact.php
And to avoid having 2 different URLS pointing to the same page, I also want to do a 301 redirect between the old URL and the new one:
Redirect 301 /contact.php http://www.example.com/contact
Each of the line above works well separately. But if I add them both in my htaccess, I have a redirect loop. How can I fix that?
In the end, if I either type "/contact" or "/contact.php", I want to see the contact page with the url "/contact".
Edit: I also tried things like that, and it doesn't work:
RewriteRule ^/contact\.php$ http://www.example.com/contact [R=301,L]
RewriteRule ^/contact$ /contact.php [L]
Yes it will indeed cause redirection loop since mod_rewrite rules are applied in a loop. Here value of REQUEST_URI changes to contact.php after first rule and to contact by your second rule.
To avoid this looping you need to use %{THE_REQUEST} in your external redirect rule as THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of some other rewrite rules. Example value of this variable is GET /index.php?id=123 HTTP/1.1.
Use this:
RewriteEngine On
# external redirect from /contact.php to /contact
RewriteCond %{THE_REQUEST} \s/+(contact)\.php\[\s?] [NC]
RewriteRule ^ /%1? [R=302,L]
# internal forward from /contact to /contact.php
RewriteRule ^(contact)/?$ $1.php [L,NC]
Change 302 to 301 once you make sure it is working fine for you.