如何在Apache上使用RewriteCond的"AND","OR"?

nop*_*ole 110 mod-rewrite apache-config

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

rewritecond A [or]
rewritecond B
rewritecond C [or]
rewritecond D
RewriteRule ... something
Run Code Online (Sandbox Code Playgroud)

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

所以看起来"OR"的优先级高于"AND"?有没有办法轻松讲述,比如 (A or B) and (C or D)语法?

Sjo*_*jon 110

这是一个有趣的问题,因为在文档中没有非常明确地解释,我将通过浏览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
Run Code Online (Sandbox Code Playgroud)

并且搜索CONDFLAG_ORNEXT确认它是根据[OR]标志的存在使用:

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

下一次出现的标志是实际的实现,你可以在其中找到经过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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

RewriteCond A [or]
RewriteCond B [or]
RewriteCond C
RewriteCond D
Run Code Online (Sandbox Code Playgroud)

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

  • +1表示"证明开源的巨大好处":) - @ChuckKollars逻辑不会产生(((A或B)和C)或D)但(A或B)和(C或D).在每次通过循环时,它会检查CONDFLAG_ORNEXT,这只会在查看A和C时设置.当设置它时,如果当前条件通过,它会跳过下一个条件,或者它继续不关心当前条件是否因为未来条件而失败传递和最后一个OR组将没有设置标志,所以如果所有失败整个事件失败. (3认同)
  • @WillshawMedia您可以通过将其分成两个单独的规则来执行((A和B)OR(C和D)):RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD (2认同)

DrL*_*man 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...
Run Code Online (Sandbox Code Playgroud)

要求