htaccess combine/reduce rewrite conditions into one (or at least fewer) - apache

I have a course booking component that is unfortunately providing three different URLs to the same page, depending on whether you go in via a menu link, breadcrumb or link within the component.
As such, I've been adding a new rewrite condition to an htaccess file, per course, as follows:
RewriteCond %{REQUEST_URI} ^/citb/smsts/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/smsts/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/smsts/book-now/1$ [NC]
RewriteRule .* /citb/smsts/book-now/1-smsts [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/citb/smsts-refresher/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/smsts-refresher/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/smsts-refresher/book-now/2$ [NC]
RewriteRule .* /citb/smsts-refresher/book-now/2-smsts-refresher [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/citb/sssts/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/sssts/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/sssts/book-now/3$ [NC]
RewriteRule .* /citb/sssts/book-now/3-sssts [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/citb/sssts-refresher/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/sssts-refresher/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/sssts-refresher/book-now/4$ [NC]
RewriteRule .* /citb/sssts-refresher/book-now/4-sssts-refresher [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/citb/health-and-safety-awareness/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/health-and-safety-awareness/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/citb/health-and-safety-awareness/book-now/7$ [NC]
RewriteRule .* /citb/health-and-safety-awareness/book-now/7-health-and-safety-awareness [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/iosh/managing-safely/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/iosh/managing-safely/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/iosh/managing-safely/book-now/8$ [NC]
RewriteRule .* /iosh/managing-safely/book-now/8-iosh-managing-safely [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/iosh/working-safely/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/iosh/working-safely/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/iosh/working-safely/book-now/9$ [NC]
RewriteRule .* /iosh/working-safely/book-now/9-iosh-working-safely [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/first-aid/3-day-first-aid-at-work/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/first-aid/3-day-first-aid-at-work/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/first-aid/3-day-first-aid-at-work/book-now/5$ [NC]
RewriteRule .* /first-aid/3-day-first-aid-at-work/book-now/5-3-day-first-aid-at-work [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/first-aid/1-day-first-aid-at-work/book-now$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/first-aid/1-day-first-aid-at-work/book-now/$ [NC,OR]
RewriteCond %{REQUEST_URI} ^/first-aid/1-day-first-aid-at-work/book-now/6$ [NC]
RewriteRule .* /first-aid/1-day-first-aid-at-work/book-now/6-1-day-first-aid-at-work [R=301,NC,L]
This is obviously not a desirable approach to keep repeating every time there's a new course to be added (and yes I know the best solution would actually be to hack the component around so that it's not doing this) so I was wondering if there was a way of making this more generic, either with the one rewrite condition or maybe one per category or however it could be best generalised?
Each desired/destination URL will follow the following format:
/[category]/[course]/book-now/[id]-[alias]
Where, from the first example above:
category = citb
course = smsts
id = 1
alias = smsts
Many thanks in advance!

Actually, i don't think (or i don't know how) you could reduce all your redirections (you can't actually guess the missing number in your 2 first conditions).
But you could actually handle all your 3rd conditions with :
RewriteEngine On
RewriteRule ^([^/]*)/([^/]*)/book-now/([0-9]+)$ /$1/$2/book-now/$3-$2 [R=301,NC,L]
And combine your 2 first conditions by using (/?) at the end.
That would make :
RewriteEngine On
RewriteRule ^([^/]*)/([^/]*)/book-now/([0-9]+)$ /$1/$2/book-now/$3-$2 [R=301,NC,L]
RewriteCond %{REQUEST_URI} ^/citb/smsts/book-now(/?)$ [NC]
RewriteRule .* /citb/smsts/book-now/1-smsts [R=301,NC,L]
...
PS : You wrote :
Each desired/destination URL will follow the following format:
/[category]/[course]/book-now/[id]-[alias]
Where, from the first example above:
category = citb
course = smsts
id = 1
alias = smsts
But actually, for your /iosh/working-safely/book-now/9 url, your format is :
alias = [category]-[course]
Since it becomes
/iosh/working-safely/book-now/9-iosh-working-safely
Not sure if it's a mistake in your htaccess, seems important to notice.
Hope it helps !

Related

Mod_rewrite combine default path with www. and https redirect

I'm trying to reduce the number of redirects on our website. I already managed to combine some of our redirect code (forcing www. and https://), but I also need to add a default path (/en/) in case there is none.
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.example.com%{REQUEST_URI} [R=301,L]
The other bit of code I want to implement is this:
RewriteRule "^/$" /en/
So if there's no path or arguments given, it needs to redirect to /en/. (Now I do this in PHP, meaning almost every person typing "example.com" gets two redirects, where one should really be enough)
My goal is to combine these rules into one single redirect. Is that possible?
Finally, I also have an internal rewrite rule, which is likely irrelevant for the question above, but I'll add it for completeness:
RewriteRule "(^|/)\." - [F]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$/? index.php?rewrite=$1 [QSA]
You can use (in this order):
RewriteRule ^$ /en/
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.example.com/$1 [R=301,L]
If this is a language test, you can also test the values (ex with: en, fr or de) and change the first line in
RewriteRule !^(en|fr|de)/ /en/ [NC]
Should work:
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{REQUEST_URI} ^/$
RewriteRule (.*) https://www.example.com/en%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.example.com%{REQUEST_URI} [R=301,L]

htaccess rewrite condition redirect to root domain

I am just simply trying to redirect several pages to the root domain and unsure why its failing, nothing happens.
RewriteEngine On
RewriteCond %{QUERY_STRING} /category/uncategorized/
RewriteCond %{QUERY_STRING} /2014/12/
RewriteCond %{QUERY_STRING} attachment_id=19
RewriteCond %{QUERY_STRING} attachment_id=18
RewriteCond %{QUERY_STRING} attachment_id=5
RewriteCond %{QUERY_STRING} attachment_id=20
RewriteCond %{QUERY_STRING} attachment_id=72
RewriteCond %{QUERY_STRING} attachment_id=6
RewriteCond %{QUERY_STRING} attachment_id=10
RewriteCond %{QUERY_STRING} attachment_id=15
RewriteCond %{QUERY_STRING} attachment_id=14
RewriteCond %{QUERY_STRING} attachment_id=16
RewriteCond %{QUERY_STRING} attachment_id=17
RewriteCond %{QUERY_STRING} attachment_id=99
RewriteCond %{QUERY_STRING} attachment_id=44
RewriteRule http://domain.com? [L,R=301]
The WP rewrites are in this same .htaccess but no change if I remove them.
Something like the below should work. Make sure it's in the .htaccess in your DocumentRoot
RewriteEngine On
RewriteRule category/uncategorized/? http://domain.com? [L,R=301]
RewriteRule 2014/12/? http://domain.com? [L,R=301]
RewriteCond %{QUERY_STRING} attachment_id=([56]|1[4-9]|20|44|72|99)
RewriteRule ^ http://domain.com? [L,R=301]
Edit: #arco444's answer will work for you (and is indeed a better answer), but it is essential that you try and understand exactly what is happening if you want to use it.
Option 1
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/category/uncategorized/ [OR]
RewriteCond %{REQUEST_URI} ^/2014/12/ [OR]
RewriteCond %{QUERY_STRING} attachment_id=19 [OR]
RewriteCond %{QUERY_STRING} attachment_id=18 [OR]
RewriteCond %{QUERY_STRING} attachment_id=5 [OR]
RewriteCond %{QUERY_STRING} attachment_id=20 [OR]
RewriteCond %{QUERY_STRING} attachment_id=72 [OR]
RewriteCond %{QUERY_STRING} attachment_id=6 [OR]
RewriteCond %{QUERY_STRING} attachment_id=10 [OR]
RewriteCond %{QUERY_STRING} attachment_id=15 [OR]
RewriteCond %{QUERY_STRING} attachment_id=14 [OR]
RewriteCond %{QUERY_STRING} attachment_id=16 [OR]
RewriteCond %{QUERY_STRING} attachment_id=17 [OR]
RewriteCond %{QUERY_STRING} attachment_id=99 [OR]
RewriteCond %{QUERY_STRING} attachment_id=44
RewriteRule ^ http://domain.com? [L,R=301]
The main thing here is the [OR] flag. In your original code, you were basically saying that all conditions had to be met. Remember that the last condition should not have the [OR].
Secondly, you were using QUERY_STRING to check for category/..., but that has nothing to do with the query string, which appear after the ?. So, I have change that to %{REQUEST_URI}.
Also, your RewriteRule did not have a URI to match against. I have added a ^ before the domain name to say that it should match everything (that is, provided the conditions have been met).
Option 2
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/category/uncategorized/ [OR]
RewriteCond %{REQUEST_URI} ^/2014/12/ [OR]
RewriteCond %{QUERY_STRING} attachment_id=(5|6|10|14|15|16|17|18|19|20|44|72|99)
RewriteRule ^ http://domain.com? [L,R=301]
Here, I have simplified the query string check. We now use one condition to check for different attachment IDs.
You could probably simplify this even further, but the purpose of my answer is to let you know where you went wrong, and where things can be simplified a little.

mod_rewrite multiple domains rewrite domain name

I have a bunch of domains that might be coming in with or without a www. With some of these domains I want to redirect them if they are mobile to m.domain.com. If I do 1 domain, it works. For example:
RewriteCond %{HTTP_ACCEPT} text/vnd.wap.wml [NC,OR]
RewriteCond %{HTTP_USER_AGENT} !(ipad|joojoo|tablet) [NC]
RewriteCond %{HTTP_USER_AGENT} \bagent1|agent2|agent3\b[NC]
RewriteCond %{HTTP_HOST} ^domain1\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.domain1\.com$
RewriteRule .* "http\:\/\/m\.domain1.com/" [R,L]
But when I try to capture the domain name and use it in the rule, it doesn't seem to work, for example:
RewriteCond %{HTTP_ACCEPT} text/vnd.wap.wml [NC,OR]
RewriteCond %{HTTP_USER_AGENT} !(ipad|joojoo|tablet) [NC]
RewriteCond %{HTTP_USER_AGENT} \bagent1|agent2|agent3\b[NC]
RewriteCond %{HTTP_HOST} ^(domain1\.com)$ [OR]
RewriteCond %{HTTP_HOST} ^www\.(domain1\.com)$ [OR]
RewriteCond %{HTTP_HOST} ^(domain2\.com)$ [OR]
RewriteCond %{HTTP_HOST} ^www\.(domain2\.com)$
RewriteRule .* "http\:\/\/m\.$1/" [R,L]
$1 is not getting set with the domain name. Any idea what I'm doing wrong?
TIA
There are two things wrong with
RewriteRule .* "http\:\/\/m\.$1/" [R,L]
One, you don't need to escape characters (like / here) in the substitution URL path because it isn't treated as a pattern but just text. Use of $ and % back references is allowed but no escaping is required as such.
Second, to capture the host sub-group you need %1 instead of $1 because the sub-group comes from RewriteCond instead of RewriteRule. So, you can change your .htaccess to
RewriteCond %{HTTP_ACCEPT} text/vnd.wap.wml [NC,OR]
RewriteCond %{HTTP_USER_AGENT} !(ipad|joojoo|tablet) [NC]
RewriteCond %{HTTP_USER_AGENT} \b(agent1|agent2|agent3)\b[NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?((?:domain1|domain2)\.com)$ [NC]
RewriteRule ^ http://m.%1/ [R=301,L]
The %{HTTP_HOST} condition matches for any domain name that starts with www\. but makes it optional (?: ... )?. Followed by either domain1|domain2 followed by .com.

Apache .hatccess rewrites not working for legacy URLS

I'm trying to rewrite some legacy Joomla URLs on a site that's now using ExpressionEngine as its CMS but they're not working.
The ExpressionEngine URL rewrites, i.e. removing index.php from the URL work fine though.
This is what I've got:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
# This is the one that's not working
RewriteRule /index.php?option=com_chronocontact&Itemid=54 /contact/ [R=301,L]
# Force www
RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
RewriteCond %{HTTP_HOST} (.+)$ [NC]
RewriteRule ^(.*)$ http://www.%1/$1 [R=301,L]
# Redirect index.php Requests
RewriteCond %{THE_REQUEST} ^[^/]*/index\.php [NC]
RewriteCond %{THE_REQUEST} ^GET
RewriteRule ^index\.php(.+) $1 [R=301,L]
# Standard ExpressionEngine Rewrite
RewriteCond %{REQUEST_URI} ^/
RewriteCond %{QUERY_STRING} ^(gclid=.*)
RewriteRule ^(.+) /index.php?/ [L,PT]
RewriteCond $1 !\.(css|js|gif|jpe?g|png) [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(assets|css|images|tinymce|js|min|cms|themes|index\.php|admin\.php|favicon\.ico|index\.php|path\.php|php\.ini) [NC]
RewriteRule ^(.+) /index.php?/ [L]
</IfModule>
Can anyone spot what I'm doing wrong?
The first thing is the stray RewriteCond %{HTTPS} !=on that you have at the top. It looks like it belongs to the rule under it, as in:
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
RewriteCond %{HTTP_HOST} (.+)$ [NC]
RewriteRule ^(.*)$ http://www.%1/$1 [R=301,L]
As far as the rule that you have commented that doesn't work, the ? is a reserved character for regular expressions, and your pattern actually says that the second p in /index.php is "optional". Additionally, you can't match against the query string in a rewrite rule, you need to use a rewrite condition and match against the %{QUERY_STRING} variable:
RewriteCond %{QUERY_STRING} ^option=com_chronocontact&Itemid=54$
RewriteRule ^(index.php)?$ /contact/? [R=301,L]
is probably more along the lines of what you're looking for.

combine flags with wildcards using RewriteCond?

I try to understand some basic rewrite stuff, so what I fount is something like:
RewriteCond %{HTTP_HOST} ^example.(.+)$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
and:
RewriteCond %{HTTP_HOST} ^(www2.example.de|example.de)$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
But if I combine it like
RewriteCond %{HTTP_HOST} ^(www2.example|example).(.+)$ [NC]
I get an internal server error because of too many redirects.
So how can I combine with or whithout www and with different domain endings:
RewriteCond %{HTTP_HOST} ^example.com$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www.example.name$ [NC,OR]
RewriteCond %{HTTP_HOST} ^example.name$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www.example.de$ [NC,OR]
RewriteCond %{HTTP_HOST} ^example.de$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
I think it should be quite simple but I just don't get it...
The five coditions could be combined in a single one, like this:
RewriteCond %{HTTP_HOST} ^example\.com$ [NC,OR]
RewriteCond %{HTTP_HOST} (?:www\.)?example\.(name|de) [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]