cách sử dụng “AND”, “OR” cho RewriteCond trên Apache?


115

Đây có phải là cách sử dụng AND, OR cho RewriteCondtrên Apache không?

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

trở thành if ( (A or B) and (C or D) ) rewrite_it.

Vì vậy, có vẻ như "OR" được ưu tiên cao hơn "AND"? Có cách nào để dễ dàng nhận biết, như trong (A or B) and (C or D)cú pháp không?


1
Vâng chính xác. [OR] có mức độ ưu tiên cao hơn "AND" (ngầm định). Điều kiện kết hợp thực sự là ((A hoặc B) và (C hoặc D)).
Doin

2
Bạn có thể thấy các thông tin chi tiết trong ckollars.org/apache-rewrite-htaccess.html#precedence hữu ích.
Chuck Kollars

Câu trả lời:


118

Đây là một câu hỏi thú vị và vì nó không được giải thích rõ ràng trong tài liệu nên tôi sẽ trả lời điều này bằng cách xem qua mã nguồn của mod_rewrite ; thể hiện lợi ích lớn của mã nguồn mở .

Trong phần trên cùng, bạn sẽ nhanh chóng phát hiện ra các định nghĩa được sử dụng để đặt tên cho các cờ này :

#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

và tìm kiếm CONDFLAG_ORNEXT xác nhận rằng nó được sử dụng dựa trên sự tồn tại của cờ [OR] :

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

Lần xuất hiện tiếp theo của cờ là quá trình triển khai thực tế , nơi bạn sẽ tìm thấy vòng lặp đi qua tất cả các Điều kiện của RewriteRule mà RewriteRule có và về cơ bản nó làm được gì (bị loại bỏ, nhận xét được thêm vào để làm rõ):

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

Bạn sẽ có thể giải thích điều này; nó có nghĩa là OR có mức độ ưu tiên cao hơn và ví dụ của bạn thực sự dẫn đến if ( (A OR B) AND (C OR D) ). Ví dụ: nếu bạn sẽ có các Điều kiện sau:

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

nó sẽ được hiểu là if ( (A OR B OR C) and D ).


1
Đối với tôi, dường như việc thực thi mã nguồn trên ví dụ .htaccess đã cho tạo ra ((A OR B) và C) hoặc D) [tức là không phải những gì OP hy vọng cũng như những gì bạn tính toán ban đầu]. Bạn có thể giúp tôi tìm ra lỗi diễn giải của tôi không? [Cũng để giải thích rõ hơn, còn điều ngược lại: nếu người ta muốn triển khai ((A HOẶC B) VÀ (C HOẶC D)), chính xác thì một mã trong tệp .htaccess là gì?]
Chuck Kollars

3
+1 vì 'thể hiện lợi ích lớn của mã nguồn mở' :) - @ChuckKollars logic sẽ không tạo ra (((A hoặc B) và C) hoặc D) mà là (A hoặc B) và (C hoặc D). trên mỗi lần vượt qua mặc dù vòng lặp nó kiểm tra CONDFLAG_ORNEXT sẽ chỉ được đặt khi nhìn vào A và C. Khi nó được đặt, nó sẽ bỏ qua điều kiện tiếp theo nếu điều kiện hiện tại được thông qua hoặc nó tiếp tục mà không quan tâm rằng điều kiện hiện tại không thành công vì các điều kiện trong tương lai có thể vượt qua và cuối cùng của nhóm HOẶC sẽ không có cờ được thiết lập, vì vậy nếu tất cả không thành công thì toàn bộ sẽ không thành công.
tempcke

1
Tôi không thể hiểu được cách làm ((A và B) HOẶC (C và D)) - Tôi đã kết thúc với (A và (B hoặc C) và D)
Pete

@WillshawMedia Bạn có thể làm ((A và B) OR (C và D)) bằng cách tách nó thành hai quy tắc riêng biệt: RewriteCond Một RewriteCond B RewriteRule AB RewriteCond C RewriteCond D RewriteRule CD
Isaac

3

Sau nhiều lần đấu tranh và tìm ra giải pháp tổng quát, linh hoạt và dễ đọc hơn, trong trường hợp của tôi, tôi đã lưu kết quả OR vào các biến ENV và thực hiện AND của các biến đó.

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

Yêu cầu :

  • Apache mod_env đã được bật
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.