123

这是如何RewriteCond在 Apache 上使用 AND,OR for?

rewritecond A [or]
rewritecond B
rewritecond C [or]
rewritecond D
RewriteRule ... something

变成if ( (A or B) and (C or D) ) rewrite_it.

所以看起来“OR”的优先级高于“AND”?有没有办法像 (A or B) and (C or D)语法一样轻松分辨?

4

2 回答 2

132

这是一个有趣的问题,由于文档中没有非常明确地解释它,我将通过查看mod_rewrite 的源代码来回答这个问题;展示了开源的一大好处

在顶部,您将快速发现用于命名这些标志的定义

#define CONDFLAG_NONE               1<<0
#define CONDFLAG_NOCASE             1<<1
#define CONDFLAG_NOTMATCH           1<<2
#define CONDFLAG_ORNEXT             1<<3
#define CONDFLAG_NOVARY             1<<4

并搜索 CONDFLAG_ORNEXT 确认它是基于 [OR] 标志的存在使用的

else if (   strcasecmp(key, "ornext") == 0
         || strcasecmp(key, "OR") == 0    ) {
    cfg->flags |= CONDFLAG_ORNEXT;
}

标志的下一次出现是实际实现,您将在其中找到遍历 RewriteRule 具有的所有 RewriteConditions 的循环,它的基本作用是(剥离,为清楚起见添加注释):

# loop through all Conditions that precede this Rule
for (i = 0; i < rewriteconds->nelts; ++i) {
    rewritecond_entry *c = &conds[i];

    # execute the current Condition, see if it matches
    rc = apply_rewrite_cond(c, ctx);

    # does this Condition have an 'OR' flag?
    if (c->flags & CONDFLAG_ORNEXT) {
        if (!rc) {
            /* One condition is false, but another can be still true. */
            continue;
        }
        else {
            /* skip the rest of the chained OR conditions */
            while (   i < rewriteconds->nelts
                   && c->flags & CONDFLAG_ORNEXT) {
                c = &conds[++i];
            }
        }
    }
    else if (!rc) {
        return 0;
    }
}

您应该能够解释这一点;这意味着 OR 具有更高的优先级,并且您的示例确实导致if ( (A OR B) AND (C OR D) ). 例如,如果您有以下条件:

RewriteCond A [or]
RewriteCond B [or]
RewriteCond C
RewriteCond D

它会被解释为if ( (A OR B OR C) and D ).

于 2015-07-22T19:11:46.607 回答
7

经过多次努力并获得一个通用、灵活和更具可读性的解决方案,在我的情况下,我最终将OR的结果保存到ENV变量中,并对这些变量进行AND

# RESULT_ONE = A OR B
RewriteRule ^ - [E=RESULT_ONE:False]
RewriteCond ...A... [OR]
RewriteCond ...B...
RewriteRule ^ - [E=RESULT_ONE:True]

# RESULT_TWO = C OR D
RewriteRule ^ - [E=RESULT_TWO:False]
RewriteCond ...C... [OR]
RewriteCond ...D...
RewriteRule ^ - [E=RESULT_TWO:True]

# if ( RESULT_ONE AND RESULT_TWO ) then ( RewriteRule ...something... )
RewriteCond %{ENV:RESULT_ONE} =True
RewriteCond %{ENV:RESULT_TWO} =True
RewriteRule ...something...

要求

于 2019-10-13T16:19:12.843 回答