จะใช้“ AND”,“ OR” สำหรับ RewriteCond บน Apache ได้อย่างไร?


115

นี่คือวิธีใช้ AND, OR สำหรับRewriteCondบน Apache หรือไม่?

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

if ( (A or B) and (C or D) ) rewrite_itจะกลายเป็น

จึงดูเหมือนว่า "OR" มีความสำคัญสูงกว่า "AND"? มีวิธีบอกง่ายๆเหมือนใน (A or B) and (C or D)วากยสัมพันธ์หรือไม่?


1
ใช่ถูกต้อง. [OR] มีความสำคัญสูงกว่า (โดยนัย) "AND" เงื่อนไขรวมกันแน่นอน ((A หรือ B) และ (C หรือ D))
Doin

2
คุณอาจพบรายละเอียดในckollars.org/apache-rewrite-htaccess.html#precedenceเป็นประโยชน์
Chuck Kollars

คำตอบ:


118

นี่เป็นคำถามที่น่าสนใจและเนื่องจากมันไม่ได้อธิบายมากอย่างชัดเจนในเอกสารที่ผมจะตอบคำถามนี้โดยจะผ่านsourcecode ของ 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 ยืนยันว่ามีการใช้ตามการมีอยู่ของแฟล็ก[OR] :

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 ที่กำหนดจะสร้าง ((A OR B) และ C) หรือ D) [นั่นคือสิ่งที่ OP หวังหรือสิ่งที่คุณคำนวณไว้ในตอนแรก] คุณช่วยหาข้อผิดพลาดในการตีความของฉันได้ไหม [นอกจากนี้เพื่อให้ชัดเจนยิ่งขึ้นสิ่งที่เกี่ยวกับการย้อนกลับ: ถ้ามีใครต้องการใช้งาน ((A OR B) AND (C OR D)) หนึ่งรหัสในไฟล์. htaccess ควรเป็นอย่างไร]
Chuck Kollars

3
+1 สำหรับ 'แสดงให้เห็นถึงประโยชน์ที่ยิ่งใหญ่ของโอเพ่นซอร์ส' :) - @ChuckKollars ตรรกะจะไม่สร้าง (((A หรือ B) และ C) หรือ D) แต่เป็น (A หรือ B) และ (C หรือ D) ในแต่ละรอบแม้ว่าลูปจะตรวจสอบ CONDFLAG_ORNEXT ซึ่งจะตั้งค่าเมื่อดูที่ A และ C เท่านั้นเมื่อตั้งค่าแล้วจะข้ามเงื่อนไขถัดไปหากเงื่อนไขปัจจุบันผ่านไปหรือยังคงไม่สนใจว่าเงื่อนไขปัจจุบันจะล้มเหลวเนื่องจากเงื่อนไขในอนาคตอาจ pass และสุดท้ายของกลุ่ม OR จะไม่มีการตั้งค่าสถานะดังนั้นหากทุกอย่างล้มเหลวสิ่งทั้งหมดล้มเหลว
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 ซีดี
Isaac

3

หลังจากการต่อสู้หลายครั้งและเพื่อให้บรรลุวิธีการแก้ปัญหาทั่วไปที่ยืดหยุ่นและอ่านได้ง่ายขึ้นในกรณีของฉันฉันลงเอยด้วยการบันทึกผลลัพธ์ORเป็นตัวแปรENVและทำANDของตัวแปรเหล่านั้น

# 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.