comment utiliser «AND», «OR» pour RewriteCond sur Apache?

115

Est-ce comment utiliser AND, OR RewriteCondsur Apache?

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

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

Il semble donc que "OU" soit une priorité plus élevée que "ET"? Existe-t-il un moyen de le dire facilement, comme dans la (A or B) and (C or D)syntaxe?

nonopolarité
la source
1
Oui correct. [OR] a une priorité plus élevée que le "AND" (implicite). La condition combinée est en effet ((A ou B) et (C ou D)).
Fait
2
Vous pouvez trouver les détails dans ckollars.org/apache-rewrite-htaccess.html#precedence utiles.
Chuck Kollars

Réponses:

118

C'est une question intéressante et comme elle n'est pas expliquée très explicitement dans la documentation, je vais y répondre en passant par le code source de mod_rewrite ; démontrant un grand avantage de l' open-source .

Dans la section supérieure, vous repérerez rapidement les définitions utilisées pour nommer ces indicateurs :

#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

et la recherche de CONDFLAG_ORNEXT confirme qu'il est utilisé sur la base de l'existence de l'indicateur [OR] :

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

La prochaine occurrence de l'indicateur est l' implémentation réelle où vous trouverez la boucle qui traverse toutes les RewriteConditions d'une RewriteRule, et ce qu'elle fait essentiellement est (supprimée, commentaires ajoutés pour plus de clarté):

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

Vous devriez être capable d'interpréter cela; cela signifie que OR a une priorité plus élevée, et votre exemple mène effectivement à if ( (A OR B) AND (C OR D) ). Si vous souhaitez, par exemple, avoir ces conditions:

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

il serait interprété comme if ( (A OR B OR C) and D ).

Sjon
la source
1
Il me semble que l'exécution du code source sur l'exemple .htaccess donné produit ((A OR B) et C) ou D) [c'est-à-dire ni ce que l'OP espère ni ce que vous avez initialement calculé]. Pouvez-vous m'aider à trouver mon erreur d'interprétation? [Aussi pour être plus explicite, qu'en est-il de l'inverse: si l'on veut implémenter ((A OR B) AND (C OR D)), que doit-on exactement coder dans le fichier .htaccess?]
Chuck Kollars
3
+1 pour «démontrer un grand avantage de l'open-source» :) - @ChuckKollars la logique ne produirait pas (((A ou B) et C) ou D) mais (A ou B) et (C ou D). à chaque passage dans la boucle, il vérifie CONDFLAG_ORNEXT qui ne serait défini que lors de l'examen de A et C. Lorsqu'il est défini, il saute la condition suivante si la condition actuelle est passée ou il continue de ne pas se soucier que la condition actuelle a échoué car les conditions futures peuvent passer et le dernier du groupe OR n'aura pas le drapeau défini donc si tout échoue, tout échoue.
tempcke
1
Je ne peux pas comprendre comment faire ((A et B) OU (C et D)) - J'ai fini avec (A et (B ou C) et D)
Pete
@WillshawMedia Vous pouvez faire ((A et B) OU (C et D)) en le divisant en deux règles distinctes: RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD
Isaac
3

Après de nombreuses difficultés et pour parvenir à une solution générale, flexible et plus lisible, dans mon cas, j'ai fini par enregistrer les résultats des OR dans des variables ENV et faire les ET de ces variables.

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

Exigences :

DrLightman
la source