How can I create the following logic: (A and B) or (C and D) with RewriteCond?
The documentation wasn't very clear here, so I'm hoping some experts might shine some light.
I looked at the following post: how to use "AND", "OR" for RewriteCond on Apache? This one made it somewhat clear for the given examples, but I'm still a little stuck.
Take the following example. If I need (A and B) or (C and D), would this be correct? Or is it A and (B or C) and D?
RewriteCond A
RewriteCond B [OR]
RewriteCond C
RewriteCond D
Is the following (A and B and C) or D, or is it A and B and (C or D)?
RewriteCond A
RewriteCond B
RewriteCond C [OR]
RewriteCond D
Is the only way to solve it by splitting them up into multiple RewriteRules?
CodePudding user response:
NB: All the code examples are semi-pseudo-code, unless otherwise stated.
It's an interesting question, however, how you actually implement something like this is really dependent on exactly what you are trying to achieve. There are several methods/techniques to get the job done.
You can't implement this logic literally as you have it in your example, ie. with 4 conditions: A, B, C and D. And using OR
and (implied) AND flags. This is because conditions are processed in order top to bottom, OR
has precedence over an implied AND and there is no syntax to group conditions together (other than splitting into separate rules).
RewriteCond A RewriteCond B [OR] RewriteCond C RewriteCond D
This is equivalent to A and (B or C) and D
. Processing stops early if conditions are not met. So in this example if A
fails then no further processing occurs.
RewriteCond A RewriteCond B RewriteCond C [OR] RewriteCond D
And this is equivalent to A and B and (C or D)
.
How can I create the following logic: (A and B) or (C and D) with RewriteCond?
In a general sense, there are various methods to achieve this logic, depending on the intended action. On Apache 2.4 you can embed an Apache expression in the RewriteCond
directive, so you can more literally do something like:
RewriteCond expr "A && B" [OR]
RewriteCond expr "C && D"
(Although this could even be combined into a single condition.)
Or, use an Apache <If>
expression directly. For example:
<If "(A && B) || (C && D)">
RewriteRule ^ something
</If>
On earlier versions of Apache you can make use of environment variables (to store the results of intermediary expressions) and/or skip rules depending on the outcome of earlier conditions.
For example:
# If "A and B" then env var is set and the next rule is skipped
RewriteCond A
RewriteCond B
RewriteRule ^ - [E:A_AND_B:1,S=1]
# If "C and D" then env var is set
RewriteCond C
RewriteCond D
RewriteRule ^ - [E:C_AND_D:1]
RewriteCond A_AND_B [OR]
RewriteCond C_AND_D
RewriteRule <do-this>
Although you don't need two env vars in the above - one will do:
# If "A and B" then env var is set and the next rule is skipped
RewriteCond A
RewriteCond B
RewriteRule ^ - [E:SUCCESS:1,S=1]
# If "C and D" then env var is set
RewriteCond C
RewriteCond D
RewriteRule ^ - [E:SUCCESS:1]
# If neither "A and B" or "C and D" is set then SUCCESS is also not set
RewriteCond SUCCESS
RewriteRule <do-this>
Or, skip and chain rules together (no env var required):
# If "A and B" then skip the next rule that checks "C and D"
RewriteCond A
RewriteCond B
RewriteRule ^ - [S=1]
# If "C and D" then chain to the next rule
RewriteCond C
RewriteCond D
RewriteRule ^ - [C]
# (A and B) or (C and D) - Otherwise this rule is skipped
RewriteRule <do-this>
However, depending on what you are doing you can also be creative with regex and "link" conditions together using backreferences to earlier conditions. For example, see my answer to the following question: Apache mod_rewrite/mod_redirect: convert URL with query parameters into an SEO-friendly URL. some query parameters are ignored