如何在Apache的RewriteCond中使用“ AND”,“ OR”?


115

这是RewriteCond在Apache上使用AND和OR的方法吗?

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)语法中那样容易分辨的方法 ?


1
是,对的。[OR]的优先级高于(隐式)“ AND”的优先级。组合条件的确是((A或B)和(C或D))。
杜安

Answers:


118

这是一个有趣的问题,因为在文档中没有明确解释,我将通过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 )


1
在我看来,在给定的示例.htaccess上执行源代码会产生((A或B)和C)或D)[即OP希望的或您最初计算的都没有]。您能帮我找到我的解释错误吗?[也要讲得更清楚一些,相反:如果要实现((A OR B)AND(C OR D)),那么.htaccess文件中的一个代码到底应该是什么?]
Chuck Kollars

3
为“展示开源的巨大好处” +1 :)-@ChuckKollars逻辑不会产生(((A或B)和C)或D),而是(A或B)以及(C或D)。每次通过循环时,它都会检查CONDFLAG_ORNEXT,该条件仅在查看A和C时才设置。设置时,它要么跳过当前条件下的下一个条件,要么继续关注当前条件失败,因为将来的条件可能会失败通过,并且OR组的最后一个将没有设置标志,因此,如果全部失败,则整个操作都会失败。
tempcke

1
无法理解如何做((A和B)或(C和D))-我最终遇到了(A和(B或C)和D)
皮特

@WillshawMedia您可以通过将其分成两个单独的规则来执行(((A和B)或(C和D)):RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD
Isaac

3

经过许多努力并寻求一个通用的,灵活的和更具可读性的解决方案,在我的情况下,我最终将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...

要求

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.