jak używać „AND”, „OR” dla RewriteCond na Apache?


115

Czy to jest jak używać AND, OR dla RewriteCond na Apache?

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

staje się if ( (A or B) and (C or D) ) rewrite_it .

Więc wygląda na to, że „OR” ma wyższy priorytet niż „AND”? Czy jest sposób, aby łatwo to stwierdzić, jak w (A or B) and (C or D)składni?


1
Tak, poprawnie. [OR] ma wyższy priorytet niż (niejawne) „AND”. Warunek łączony to rzeczywiście ((A lub B) i (C lub D)).
Doin

2
Pomocne mogą być szczegółowe informacje na stronie ckollars.org/apache-rewrite-htaccess.html#precedence .
Chuck Kollars

Odpowiedzi:


118

Jest to interesujące pytanie, a ponieważ nie zostało to wyjaśnione w dokumentacji, odpowiem na nie, przechodząc przez kod źródłowy mod_rewrite ; demonstrując dużą korzyść z open-source .

W górnej sekcji szybko zauważysz definicje używane do nazwania tych flag :

#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

a wyszukanie CONDFLAG_ORNEXT potwierdza, że ​​jest ono używane na podstawie istnienia flagi [OR] :

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

Następnym wystąpieniem flagi jest rzeczywista implementacja, w której znajdziesz pętlę, która przechodzi przez wszystkie RewriteConditions, które ma RewriteRule, i to, co w zasadzie robi (pozbawione, komentarze dodane dla przejrzystości):

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

Powinieneś być w stanie to zinterpretować; oznacza to, że OR ma wyższy priorytet, a twój przykład rzeczywiście do tego prowadzi if ( (A OR B) AND (C OR D) ). Jeśli chciałbyś, na przykład, mieć te Warunki:

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

zostanie zinterpretowany jako if ( (A OR B OR C) and D ).


1
Wydaje mi się, że wykonanie kodu źródłowego na podanym przykładzie .htaccess daje ((A LUB B) i C) lub D) [tj. Ani to, na co liczy OP, ani to, co początkowo obliczyłeś]. Czy możesz mi pomóc znaleźć błąd w interpretacji? [Żeby być bardziej zrozumiałym, co z odwrotnością: jeśli ktoś chce zaimplementować ((A OR B) AND (C OR D)), co dokładnie powinien kodować w pliku .htaccess?]
Chuck Kollars

3
+1 za „wykazanie dużej korzyści z open-source” :) - @ChuckKollars logika nie wyprodukowałaby (((A lub B) i C) lub D), ale (A lub B) i (C lub D). przy każdym przejściu przez pętlę sprawdza CONDFLAG_ORNEXT, który byłby ustawiony tylko podczas patrzenia na A i C. Gdy jest ustawiony, albo pomija następny warunek, jeśli bieżący warunek został spełniony, albo kontynuuje, nie dbając o to, że bieżący warunek zawiódł, ponieważ przyszłe warunki mogą pass, a ostatni z grupy OR nie będzie miał ustawionej flagi, więc jeśli wszystkie zawiodą, cała rzecz się nie powiedzie.
tempcke

1
nie mogę pojąć, jak to zrobić ((A i B) LUB (C i D)) - Skończyłem z (A i (B lub C) i D)
Pete

@WillshawMedia Możesz to zrobić ((A i B) LUB (C i D)), dzieląc to na dwie osobne reguły: RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD
Isaac

3

Po wielu zmaganiach i uzyskaniu ogólnego, elastycznego i bardziej czytelnego rozwiązania, w moim przypadku zapisałem wyniki OR w zmiennych ENV i wykonałem operacje AND tych zmiennych.

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

Wymagania :

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.