come usare "AND", "OR" per RewriteCond su Apache?


115

È così che si usa AND, OR RewriteCondsu Apache?

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

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

Quindi sembra che "OR" sia una precedenza maggiore di "AND"? C'è un modo per dirlo facilmente, come nella (A or B) and (C or D)sintassi?


1
Si corretto. [OR] ha una precedenza maggiore di "AND" (implicito). La condizione combinata è infatti ((A o B) e (C o D)).
Doin

2
Potresti trovare utili i dettagli in ckollars.org/apache-rewrite-htaccess.html#precedence .
Chuck Kollars

Risposte:


118

Questa è una domanda interessante e poiché non è spiegata in modo molto esplicito nella documentazione risponderò a questa domanda passando attraverso il codice sorgente di mod_rewrite ; dimostrando un grande vantaggio dell'open source .

Nella sezione superiore individuerai rapidamente le definizioni utilizzate per denominare questi 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

e la ricerca di CONDFLAG_ORNEXT conferma che viene utilizzato in base all'esistenza del flag [OR] :

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

La prossima occorrenza del flag è l' implementazione effettiva in cui troverai il ciclo che attraversa tutte le RewriteConditions di una RewriteRule, e ciò che fondamentalmente fa è (spogliato, commenti aggiunti per chiarezza):

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

Dovresti essere in grado di interpretarlo; significa che OR ha una precedenza più alta e il tuo esempio porta davvero a if ( (A OR B) AND (C OR D) ). Se, ad esempio, avessi queste condizioni:

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

sarebbe interpretato come if ( (A OR B OR C) and D ).


1
Mi sembra che l'esecuzione del codice sorgente sull'esempio .htaccess fornito produca ((A OR B) e C) o D) [cioè né ciò che l'OP spera né ciò che hai calcolato inizialmente]. Potete aiutarmi a trovare il mio errore di interpretazione? [Anche per essere più esplorati, che dire del contrario: se si vuole implementare ((A OR B) AND (C OR D)), cosa si dovrebbe esattamente codificare nel file .htaccess?]
Chuck Kollars

3
+1 per "dimostrare un grande vantaggio dell'open source" :) - @ChuckKollars la logica non produrrebbe (((A o B) e C) o D) ma (A o B) e (C o D). ad ogni passaggio attraverso il ciclo controlla CONDFLAG_ORNEXT che sarebbe impostato solo guardando A e C.Quando è impostato salta la condizione successiva se la condizione corrente è passata o continua a non preoccuparsi che la condizione corrente non sia riuscita perché le condizioni future potrebbero pass e l'ultimo del gruppo OR non avrà il flag impostato quindi se tutto fallisce l'intera cosa fallisce.
tempcke

1
non riesco a capire come fare ((A e B) OR (C e D)) - Ho finito con (A e (B o C) e D)
Pete

@WillshawMedia Puoi fare ((A e B) OR (C e D)) suddividendolo in due regole separate: RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD
Isaac

3

Dopo molte lotte e per ottenere una soluzione generale, flessibile e più leggibile, nel mio caso ho finito per salvare i risultati dell'OR in variabili ENV e fare gli AND di quelle variabili.

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

Requisiti :

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.