Wie verwende ich "AND", "OR" für RewriteCond unter Apache?

114

Ist dies die Verwendung von AND, OR für RewriteCondApache?

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

wird if ( (A or B) and (C or D) ) rewrite_it.

Es scheint also, dass "ODER" eine höhere Priorität hat als "UND"? Gibt es eine Möglichkeit, dies leicht zu erkennen, wie in der (A or B) and (C or D)Syntax?

Unpolarität
quelle
1
Ja richtig. [ODER] hat eine höhere Priorität als das (implizite) "UND". Die kombinierte Bedingung ist tatsächlich ((A oder B) und (C oder D)).
Doin
2
Die Details finden Sie unter ckollars.org/apache-rewrite-htaccess.html#precedence hilfreich.
Chuck Kollars

Antworten:

117

Dies ist eine interessante Frage, und da sie in der Dokumentation nicht sehr explizit erklärt wird, beantworte ich sie, indem ich den Quellcode von mod_rewrite durchführe . Demonstration eines großen Vorteils von Open Source .

Im oberen Bereich finden Sie schnell die Definitionen, mit denen diese Flags benannt werden :

#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

Wenn Sie nach CONDFLAG_ORNEXT suchen, wird bestätigt, dass es basierend auf dem Vorhandensein des [OR] -Flag verwendet wird :

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

Das nächste Vorkommen des Flags ist die eigentliche Implementierung, in der Sie die Schleife finden, die alle RewriteConditions durchläuft, die eine RewriteRule hat, und im Grunde genommen (entfernt, Kommentare zur Klarheit hinzugefügt):

# 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;
    }
}

Sie sollten dies interpretieren können; Dies bedeutet, dass der OP eine höhere Priorität hat und Ihr Beispiel tatsächlich dazu führt if ( (A OR B) AND (C OR D) ). Wenn Sie zum Beispiel folgende Bedingungen hätten:

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

es würde interpretiert werden als if ( (A OR B OR C) and D ).

Sjon
quelle
1
Es scheint mir, dass die Ausführung des Quellcodes in dem angegebenen Beispiel .htaccess ((A ODER B) und C) oder D) erzeugt [dh weder was das OP hofft noch was Sie ursprünglich berechnet haben]. Können Sie mir helfen, meinen Interpretationsfehler zu finden? [Um genauer zu sein, was ist mit dem Gegenteil: Wenn man ((A ODER B) UND (C ODER D)) implementieren möchte, was genau sollte man in der .htaccess-Datei codieren?]
Chuck Kollars
3
+1 für 'Demonstration eines großen Vorteils von Open Source' :) - @ChuckKollars würde die Logik nicht (((A oder B) und C) oder D), sondern (A oder B) und (C oder D) erzeugen. Bei jedem Durchlauf durch die Schleife wird CONDFLAG_ORNEXT überprüft, der nur bei Betrachtung von A und C festgelegt wird. Wenn er festgelegt ist, überspringt er entweder die nächste Bedingung, wenn die aktuelle Bedingung erfüllt ist, oder es ist weiterhin egal, dass die aktuelle Bedingung fehlgeschlagen ist, weil zukünftige Bedingungen möglicherweise auftreten pass und der letzte der OR-Gruppe hat das Flag nicht gesetzt. Wenn also alle fehlschlagen, schlägt das Ganze fehl.
Tempcke
1
Ich kann mir nicht vorstellen, wie es geht ((A und B) ODER (C und D)) - Ich bin mit (A und (B oder C) und D)
Pete
@WillshawMedia Sie können ((A und B) ODER (C und D)) tun, indem Sie es in zwei separate Regeln aufteilen: RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD
Isaac
3

Nach vielen Kämpfen und um eine allgemeine, flexible und besser lesbare Lösung zu finden, habe ich in meinem Fall die Ergebnisse des OP in ENV- Variablen gespeichert und das UND dieser Variablen durchgeführt.

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

Anforderungen :

DrLightman
quelle