як використовувати "AND", "OR" для RewriteCond на Apache?


115

Це як використовувати AND, АБО для RewriteCondApache?

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

стає if ( (A or B) and (C or D) ) rewrite_it.

Тож здається, що "АБО" є вищим пріоритетом, ніж "І"? Чи є спосіб легко розказати, як у (A or B) and (C or D)синтаксисі?


1
Так, правильно. [АБО] є вищим пріоритетом, ніж (неявна) "І". Комбінований стан справді ((A або B) і (C або D)).
Зробіть

2
Деталі ви можете знайти на ckollars.org/apache-rewrite-htaccess.html#precedence корисними.
Чак Колларз

Відповіді:


118

Це цікаве запитання, і оскільки в документації це не явно пояснено, я відповім на це, переглянувши вихідний код mod_rewrite ; демонструючи велику користь з відкритим кодом .

У верхньому розділі ви швидко помітите визначення, які використовуються для назви цих прапорів :

#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

і пошук CONDFLAG_ORNEXT підтверджує, що він використовується на основі існування прапора [АБО] :

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

Наступним явищем прапора є фактична реалізація, де ви знайдете цикл, який проходить через усі RewriteConditions, які має RewriteRule, і що в основному це робить (знімається, коментарі додаються для наочності):

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

Ви повинні мати можливість інтерпретувати це; це означає, що АБО має вищий пріоритет, і ваш приклад справді призводить до цього if ( (A OR B) AND (C OR D) ). Якщо ви, наприклад, мали б ці Умови:

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

це тлумачиться як if ( (A OR B OR C) and D ).


1
Мені здається, що виконання вихідного коду на наведеному прикладі .htaccess дає ((АБО В) і С) або D) [тобто ні на що сподівається ОП, ні те, що ви спочатку розраховували]. Чи можете ви допомогти мені знайти мою помилку інтерпретації? [Крім того, щоб бути більш explidt, що робити із зворотним: якщо хочеться реалізувати ((АБО B) І (C АБО)), який саме код повинен бути у файлі .htaccess?]
Чак Колларс

3
+1 для "демонстрації великої користі з відкритим кодом" :) - @ChuckKollars логіка створюватиме не (((або B) і C) або D), а (A або B) і (C або D). при кожному пропуску, хоча цикл він перевіряє CONDFLAG_ORNEXT, який буде встановлено лише при перегляді на A і C. Коли він встановлений, він або пропускає наступну умову, якщо поточний стан пройшов, або він продовжує не піклуватися про те, що поточний стан не вдався, оскільки майбутні умови можуть пройдіть, і для останньої групи АБО не буде встановлено прапор, тому якщо всі не вдасться, вся справа вийде з ладу.
tempcke

1
я не можу з головою зробити, як це робити ((A і B) АБО (C і D)) - Я закінчив (A і (B або C) і D)
Піт

@WillshawMedia Ви можете зробити ((A і B) АБО (C і D)), розділивши його на два окремих правила: RewriteCond A RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD
Ісаак

3

Після багатьох боротьби і для того щоб досягти загальне, гнучкого і більш читаного рішення, в моєму випадку , я в кінцевому підсумку економія на або результати сек в ENV змінних і робимо І з цими змінних.

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

Вимоги :

  • Apache mod_env увімкнено
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.