如何在 Apache 上对 RewriteCond 使用“AND”、“OR”?

Posted

技术标签:

【中文标题】如何在 Apache 上对 RewriteCond 使用“AND”、“OR”?【英文标题】:how to use "AND", "OR" for RewriteCond on Apache? 【发布时间】:2010-10-29 16:10:43 【问题描述】:

这是如何在 Apache 上对RewriteCond 使用 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) 语法?

【问题讨论】:

是的,正确的。 [OR] 的优先级高于(隐式)“AND”。组合条件确实是 ((A or B) and (C or D))。 您可以在ckollars.org/apache-rewrite-htaccess.html#precedence 中找到有用的详细信息。 【参考方案1】:

经过多次努力并获得一个通用、灵活且更具可读性的解决方案,就我而言,我最终将 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...

要求

Apache mod_env 已启用

【讨论】:

【参考方案2】:

这是一个有趣的问题,由于文档中没有非常明确地解释它,我将通过 sourcecode of mod_rewrite 来回答这个问题; 展示了开源的一大优势。

在顶部,您会很快发现defines used to name these flags:

#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 确认使用based on the existence of the [OR] flag:

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

标志的下一个出现是actual implementation,您将在其中找到遍历 RewriteRule 所具有的所有 RewriteConditions 的循环,它的基本作用是(为了清晰起见,已剥离,添加了 cmets):

# 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 )

【讨论】:

在我看来,在给出的示例 .htaccess 上执行源代码会产生 ((A OR B) 和 C) 或 D) [即既不是OP希望的,也不是您最初计算的]。你能帮我找出我的解释错误吗? [更明确地说,反过来呢:如果要实现 ((A OR B) AND (C OR D)),.htaccess 文件中的代码到底应该是什么?] +1 表示“展示开源的巨大好处” :) - @ChuckKollars 逻辑不会产生(((A 或 B)和 C)或 D),而是(A 或 B)和(C 或 D)。在每次通过循环时,它都会检查 CONDFLAG_ORNEXT ,它只会在查看 A 和 C 时设置。当它被设置时,如果当前条件通过,它要么跳过下一个条件,要么继续不关心当前条件失败,因为未来条件可能通过并且 OR 组的最后一个不会设置标志,所以如果全部失败,整个事情都会失败。 不知道该怎么做((A 和 B)或(C 和 D)) - 我最终得到了(A 和(B 或 C)和 D) @WillshawMedia 您可以通过将其拆分为两个单独的规则来执行 ((A 和 B) OR (C 和 D)):RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD

以上是关于如何在 Apache 上对 RewriteCond 使用“AND”、“OR”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Apache Spark 上对整数列表进行排序?

Apache中 RewriteCond 规则参数介绍

Apache中RewriteCond规则参数的详细介绍

Apache中 RewriteCond 规则参数介绍

使用 Apache RewriteRule 和 RewriteCond 将替代内容设置到特定日期 [关闭]

Apache RewriteCond %{REQUEST_FILENAME} 不起作用问题