Consolidating redundant RewriteCond lines in .htaccess - apache

I'm trying to consolidate multiple RewriteCond lines in .htaccess and am struggling with the syntax. Here is my code for the redirect area of my .htaccess file:
RewriteEngine On
# BEGIN page-level mobile redirects
<IfModule mod_rewrite.c>
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC]
RewriteRule ^(index.html)?$ http://m.example.com [L,R=301]
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC]
RewriteRule ^page-1/$ http://m.example.com/p1 [L,R=301]
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC]
RewriteRule ^page-2/$ http://m.example.com/p2 [L,R=301]
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC]
RewriteRule ^page-3/$ http://m.example.com/p3 [L,R=301]
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC]
RewriteRule ^category/page-4/$ http://m.example.com/p4 [L,R=301]
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC]
RewriteRule ^category/page-5/$ http://m.example.com/p5 [L,R=301]
</IfModule>
# END mobile redirects
The above solution works properly but is inefficient because there are so many redundant ReWriteCond lines. My goal is to have a single RewriteCond line apply to all of my RewriteRule lines. Is this possible?
I'd normally use REQUEST_URI to more efficiently accomplish this, but i'm unable to in this instance because we're rewriting requests for multiple similar desktop web sites with varied URL layouts to a single mobile web site folder.

Read up on skip and last flags in the Apache documentation. You can also use the regexps to fold some of the lines:
# BEGIN page-level mobile redirects
<IfModule mod_rewrite.c>
RewriteCond %{HTTP_USER_AGENT} !"android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile"
RewriteRule ^ - [skip=3]
RewriteRule ^(index.html)?$ http://m.example.com [L,R=301]
RewriteRule ^page-([123])/$ http://m.example.com/p$1 [L,R=301]
RewriteRule ^category/page-([45])/$ http://m.example.com/p$1 [L,R=301]
</IfModule>
# END mobile redirects
BTW, It's a misconception to think of this in runtime terms. Yes, each regexp / rule will add 10s of μS, but the real hit in performance terms is the need to open and to read the .htaccess file, any .htaccess file in the first place. Do this sort of thing for clarity and ease of maintainability. So long as you don't shoot yourself in the foot by being "too smart", the less lines of rules, the less chance of hiding some error.

Related

How to configure multiple languages via htaccess and sub domains as a GET method?

I want to design my website to have multiple languages and I need to implement it as subdomains.
For example:
https://www.example.com/
https://fa.example.com/
https://en.example.com/
So as I searched and found there are different options.
I should copy my website in different subdomains and change it's language.
Use Url rewriting via htaccess for changing language.
Please guide me which one is a better option.
And if i want to use the second option how i can write it in htaccess.
Note that in second option I need this kind of rewritings:
For example:
https://en.example.com/
will be :
https://www.example.com/?lang=en
or
https://en.example.com/login/
will be:
https://www.example.com/login/?lang=en
or
https://en.example.com/login/example.php?a=123
will be:
https://www.example.com/login/example.php?a=123&lang=en
and all other urls also will change like this.
PS:
My site is only available on https by this code:
RewriteEngine On
Options +SymLinksIfOwnerMatch
RewriteCond %{SERVER_PORT} 80
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
rewritecond %{http_host} ^example.com [nc]
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
rewriterule ^(.*)$ https://www.example.com/$1 [r=301,nc]
Thanks for your help
Copying whole website in multiple directories is not a good idea as you have to maintain and modify files in multiple locations.
Translating language prefix of domain name as lang parameter should be a preferred option.
You can create a wildcard VirtualDomain and point all the subdomains to same DirectoryRoot. Then you can have following rules in site root .htaccess:
Options +SymLinksIfOwnerMatch
RewriteEngine On
# http => https
RewriteCond %{SERVER_PORT} 80
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
# add www to main domain
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L,NE]
# language subdomains handler
RewriteCond %{QUERY_STRING} !(?:^|&)lang= [NC]
RewriteCond %{HTTP_HOST} ^([a-z]{2})\.
RewriteRule ^ %{REQUEST_URI}?lang=%1 [QSA,L]

too many redirects in htaccess

I want to accomplish the following:
redirect non-www to www for all users
redirect desktop users to www.example.com/homepage
redirect mobile users to www.example.com/m
hide /homepage and /m from url so users will see www.example.com only
Here is my htaccess code. I am having a lot of problems with it, like things not redirecting to /m, and iphone users see "too many redirects", and sometimes desktop users are taken to /m even though they should be taken to /homepage.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^$ /homepage/ [R=301]
</IfModule>
RewriteCond %{HTTP_USER_AGENT} ^.*iPad.*$
RewriteRule ^(.*)$ http://www.example.com/m [R=301]
RewriteCond %{HTTP_USER_AGENT} ^.*iPod.*$
RewriteRule ^(.*)$ http://www.example.com/m [R=301]
RewriteCond %{HTTP_USER_AGENT} ^.*iPhone.*$
RewriteRule ^(.*)$ http://www.example.com/m [R=301]
RewriteCond %{HTTP_USER_AGENT} ^.*iemobile.*$
RewriteRule ^(.*)$ http://www.example.com/m [R=301]
RewriteCond %{HTTP_USER_AGENT} ^.*blackberry.*$
RewriteRule ^(.*)$ http://www.example.com/m [R=301]
RewriteCond %{HTTP_USER_AGENT} ^.*Android.*$
RewriteRule ^(.*)$ http://www.example.com/m [R=301]
This will give you too many redirects because you're only looking at the user agent, not the URI that's being requested, so every time a mobile user agent matches you continually redirect them to www.example.com/m. You can also add all the user agents into a single regex to reduce the number of rules you need to maintain.
You need to add a condition to look at the REQUEST_URI. Something like to the following should do:
RewriteCond %{HTTP_USER_AGENT} ^.*(ip(ad|od|hone)|blackberry|iemobile|android).*$ [NC]
RewriteCond %{REQUEST_URI} !^/m/.*
RewriteRule ^.*$ http://www.example.com/m [R=301,L]

Extra lines in .htaccess file

I want to clean-up my .htaccess file of any unnecessary lines of code. This is what I have on there right now:
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.aicmillworks.com$ [NC]
RewriteRule ^(.*)$ http://www.aicmillworks.com/$1 [L,R=301]
ReWriteRule ^home$ / [R=301,L]
RewriteCond %{THE_REQUEST} \ /([^\?\ .]*)\.(?:\?|\ |$)
RewriteRule ^ /%1 [L,R=301]
RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* – [F,L]
The two lines after "RewriteEngine on" are for redirecting pages with non-www to www. All lines after that, I am not sure what they do or why they are there. Would it be better to remove them or are they important to my website somehow? What do they do?
I'm not entirely sure what the third one does, but the rest of the rules are explained below.
# Redirect: prepend www. if the domain does not start with www.
RewriteCond %{HTTP_HOST} !^www.aicmillworks.com$ [NC]
RewriteRule ^(.*)$ http://www.aicmillworks.com/$1 [L,R=301]
# Redirect: /home to /
ReWriteRule ^home$ / [R=301,L]
# Redirect: strip the file format. So /test.html redirects to /test
# I tried testing this on your site, but it didn't work, so I'm not sure if you have this rule enabled or not.
RewriteCond %{THE_REQUEST} \ /([^\?\ .]*)\.(?:\?|\ |$)
RewriteRule ^ /%1 [L,R=301]
# Block libwww-perl from your website. Usually for blocking bots
RewriteCond %{HTTP_USER_AGENT} libwww-perl.*
RewriteRule .* – [F,L]
As for "Would it be better to remove them or are they important to my website somehow?", they certainly won't hurt your website, so you may as well leave them.

Rule exceptions in mod_rewrite

I have created page that every new user is redirected to upon visit, it sets a cookie that allows access to the rest of my site. I want to add exception to this rule for some sites and their bots:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_REFERER} http://www.site1.com [NC,OR]
RewriteCond %{HTTP_REFERER} http://www.site2.net [NC,OR]
RewriteCond %{HTTP_USER_AGENT} bot1 [NC,OR]
RewriteCond %{HTTP_USER_AGENT} bot2 [NC]
RewriteRule .? - [S=1]
RewriteCond %{HTTP_COOKIE} !yes=1 [NC]
RewriteRule !^(script1.php|script2.php)$ script2.php [L]
</IfModule>
As you can see, if the cookie doesn't exist or !=1 every user is redirected to script2.php.
I wrote some exceptions, but sometimes it works, and sometimes it doesn't.
I've made an error somewhere, but i don't see it.
Can you help me with this? Thank you for you time.
I'd rather use [L] instead of [S=1].
Secondly, I would do a external redirect to script2.php, so it's not cached (incorrectly). So use [R,L] instead of just [L] on your last rule.

How do I use .htaccess RewriteRule to change underscores to dashes

I'm working on a site, and its CMS used to save new page urls using the underscore character as a word seperator.
Despite the fact that Google now treats underscore as a word seperator, the SEO powers that be are demanding the site use dashes instead.
This is very easy to do within the CMS, and I can of course change all existing URLs saved in the MySQL database that serves the CMS.
My problem lies in writing a .htaccess rule that will 301 old style underscore seperated links to the new style hyphenated verstion.
I had success using the answers to this Stack Overflow question on other sites, using:
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
However this CMS site uses a lot of existing rules to produce clean URLs, and I can't get this working in conjunction with the existing rule set.
.htaccess currently looks like this:
Options FollowSymLinks
# RewriteOptions MaxRedirects=50
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\.mydomain\.co\.uk$ [NC]
RewriteRule (.*) http://www.mydomain.co.uk/$1 [R=301,L]
#trailing slash enforcement
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !#
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://www.mydomain.co.uk/$1/ [L,R=301]
RewriteRule ^test/([0-9]+)(/)?$ test_htaccess.php?year=$1 [nc]
RewriteRule ^index(/)?$ index.php
RewriteRule ^department/([^/]*)/([^/]*)/([^/]*)(/)?$ ecom/index.php?action=ecom.details&mode=$1&$2=$3 [nc]
RewriteRule ^department/([^/]*)(/)?$ ecom/index.php?action=ecom.details&mode=$1 [nc]
RewriteRule ^product/([^/]*)/([^/]*)/([^/]*)(/)?$ ecom/index.php?action=ecom.pdetails&mode=$1&$2=$3 [nc]
RewriteRule ^product/([^/]*)(/)?$ ecom/index.php?action=ecom.pdetails&mode=$1 [nc]
RewriteRule ^content/([^/]*)(/)?$ ecom/index.php?action=ecom.cdetails&mode=$1 [nc]
RewriteRule ([^/]*)/action/([^/]*)/([^/]*)/([^/]*)/([^/]*)(/)?$ $1/index.php?action=$2&mode=$3&$4=$5 [nc]
RewriteRule ([^/]*)/action/([^/]*)/([^/]*)(/)?$ $1/index.php?action=$2&mode=$3 [nc]
RewriteRule ([^/]*)/action/([^/]*)(/)?$ $1/index.php?action=$2 [nc]
RewriteRule ^eaction/([^/]*)/([^/]*)/([^/]*)/([^/]*)(/)?$ ecom/index.php?action=$1&mode=$2&$3=$4 [nc]
RewriteRule ^eaction/([^/]*)/([^/]*)(/)?$ ecom/index.php?action=$1&mode=$2 [nc]
RewriteRule ^action/([^/]*)/([^/]*)(/)?$ index.php?action=$1&mode=$2 [nc]
RewriteRule ^sid/([^/]*)(/)?$ index.php?sid=$1 [nc]
## Error Handling ##
#RewriteRule ^error/([^/]*)(/)?$ index.php?action=error&mode=$1 [nc]
# ----------------------------------- Content Section ------------------------------ #
#RewriteRule ^([^/]*)(/)?$ index.php?action=cms&mode=$1 [nc]
RewriteRule ^accessibility(/)?$ index.php?action=cms&mode=accessibility
RewriteRule ^terms(/)?$ index.php?action=cms&mode=conditions
RewriteRule ^privacy(/)?$ index.php?action=cms&mode=privacy
RewriteRule ^memberpoints(/)?$ index.php?action=cms&mode=member_points
RewriteRule ^contactus(/)?$ index.php?action=contactus
RewriteRule ^sitemap(/)?$ index.php?action=sitemap
ErrorDocument 404 /index.php?action=error&mode=content
ExpiresDefault "access plus 3 days"
All page URLS are in one of the 3 following formats:
http://www.mydomain.com/department/some_page_address/
http://www.mydomain.com/product/some_page_address/
http://www.mydomain.com/content/some_page_address/
I'm sure I am missing something obvious, but at this level my regex and mod_rewrite skills clearly aren't up to par.
Any ideas would be greatly appreciated!
Just take the rule you were using already:
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
…and put it before all other rewrite rules, and everything should work.
Also, you used RewriteBase / twice. You can omit it the second time, since it’s already defined.