123 votes

Comment utiliser "AND", "OR" pour RewriteCond sur Apache ?

Est-ce la façon d'utiliser AND, OR pour RewriteCond sur 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 "OR" soit plus prioritaire que "AND" ? Existe-t-il un moyen de s'en rendre compte facilement, comme dans l'exemple de l'application (A or B) and (C or D) syntaxe ?

132voto

Sjon Points 3965

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

Dans la partie supérieure, vous repérerez rapidement la rubrique Définitions utilisées pour nommer ces drapeaux :

#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 du drapeau est le mise en œuvre effective où vous trouverez la boucle qui parcourt toutes les RewriteConditions d'une RewriteRule, et ce qu'elle fait essentiellement est (dépouillé, 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 en mesure d'interpréter cela ; cela signifie que OR a une plus grande priorité, et votre exemple conduit en effet à if ( (A OR B) AND (C OR D) ) . Si vous avez, par exemple, 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 ) .

15voto

Chuck Kollars Points 884

Mes tests suggèrent qu'il n'y a tout simplement pas de préséance (raisonnable ou non:-) au sens où nous l'entendons normalement. Et il ne semble pas y avoir de syntaxe pour spécifier une sorte de préséance supplémentaire. Le fait que la réponse fonctionne est simplement "bonne chance" ; ne l'interprétez pas comme suggérant qu'il y a vraiment une sorte d'opération de préséance en cours alors que ce n'est pas le cas.

Les différentes RewriteCond sont simplement exécutées de manière séquentielle, sans tenir compte de nos attentes habituelles en matière de logique booléenne. L'implémentation de la seule modification possible - le drapeau [OR] - est assez simple d'esprit, et bien que le drapeau étende quelque peu l'éventail de ce qui est possible, il y a encore beaucoup de conditions raisonnables qui ne peuvent pas être spécifiées simplement. L'action réelle de l'indicateur [OR] semble être de l'ordre de "après ce test, si le résultat jusqu'à présent est 'vrai', sauter la prochaine RewriteCond (ou en sauter plusieurs si elles ont aussi un indicateur [OR]).

Pour les combinaisons de conditions plus détaillées qui vous amèneraient typiquement à utiliser la logique booléenne, une façon de les mettre en œuvre est souvent de créer plusieurs ensembles Cond/Règle séparés (avec une duplication inévitable), et une autre façon est d'utiliser un ensemble d'ensembles explicites et de tests de variables d'environnement intermédiaires que vous créez juste dans ce but.

Pour des ensembles de règles similaires (à l'exception de l'apparition des OR) ci-dessus plutôt qu'en dessous), vous devrez peut-être recourir à quelque chose comme l'exemple ci-dessous (l'exemple, bien qu'il soit globalement absurde dans ce cas précis, illustre une technique générale qui peut s'avérer utile) :

RewriteCond a [or]

RewriteCond b

RewriteRule . - [E=FIRSTPART:true]

RewriteCond c [or]

RewriteCond d

RewriteRule . - [E=SECONDPART:true]

RewriteCond  %{ENV:FIRSTPART}  true

RewriteCond  %{ENV:SECONDPART}  true

RewriteRule  ...something

(L'exemple de réécriture avec des OU au niveau supérieur et des ET au niveau inférieur, cité dans une autre réponse, semble être rétrograde et donc non fonctionnel. C'est un très beau calcul ... mais il ne semble pas correspondre au comportement réel de mod_rewrite).

7voto

DrLightman Points 122

Après de nombreux efforts et pour parvenir à une solution générale, flexible et plus lisible, dans mon cas, j'ai fini par sauvegarder le fichier OU ésultats de l ENV et en effectuant l'opération 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 :

7voto

Gumbo Points 279147

Vous devrez probablement le convertir en forme normale disjonctive :

  (A or B) and (C or D)
= (A and (C or D)) or (B and (C or D))
= (A and C) or (A and D) or (B and C) or (B and D)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X