การส่งอาร์กิวเมนต์ไปยังโปรแกรม พารามิเตอร์ฟังก์ชันหลัก (argc, argv)

Htaccess เป็นทางเลือก ไฟล์การกำหนดค่า Apache ซึ่งช่วยให้คุณกำหนดค่าเว็บเซิร์ฟเวอร์สำหรับแต่ละไดเร็กทอรีโดยไม่ส่งผลกระทบต่อไดเร็กทอรีส่วนกลาง การตั้งค่าอาปาเช่- การเปรียบเทียบในท้องถิ่น httpd.conf- โดยทั่วไปแล้วเขาจะรับผิดชอบในการเปลี่ยนเส้นทางและการควบคุมการเข้าถึงไดเรกทอรี

ชื่อขึ้นต้นด้วยจุด เราสามารถพูดได้ว่านี่เป็นไฟล์ที่ไม่มีชื่อและมีนามสกุล htaccess

การตั้งค่า .htaccess ส่งผลต่อไดเร็กทอรีที่มันอยู่และไดเร็กทอรีย่อยทั้งหมด สร้างไฟล์และวางลงในไดเร็กทอรีที่คุณต้องการ ตัวอย่างเช่น ไปที่รูทของโปรเจ็กต์

ตอนนี้คุณต้องกรอกมัน มาดูกันว่า .htaccess ทำอะไรได้บ้าง แต่ก่อนอื่น เรามาศึกษาตัวอย่างการเปลี่ยนเส้นทางแบบง่ายๆ กันก่อน

mod_rewrite และการเปลี่ยนเส้นทาง

ตรวจสอบให้แน่ใจว่าในไฟล์กำหนดค่า Apache ของคุณ httpd.confเปิดใช้งานแล้ว mod_rewrite- นั่นคือบรรทัดที่เกี่ยวข้องไม่มีเครื่องหมายข้อคิดเห็น:

LoadModule โมดูล rewrite_module/mod_rewrite.so

หรือถ้าไม่อยากเปิดเข้าไป โปรแกรมแก้ไขข้อความคุณสามารถใช้คำสั่งในเทอร์มินัล:

Sudo a2enmod เขียนใหม่

mod_rewrite คือ โมดูลอาปาเช่ออกแบบมาเพื่อแปลง URL ลองดูตัวอย่างวิธีการทำงาน สมมติว่าผู้ใช้ป้อนที่อยู่ต่อไปนี้:

การใช้ mod_rewrite คุณสามารถส่งเนื้อหาจาก URL อื่นได้ดังนี้:

http://www.example.com/public/src/view/page.html

ทำไมเราถึงต้องการสิ่งนี้? มันง่ายที่จะเดาว่าจะเขียนอะไร เส้นทางเต็มการเข้าสู่หน้าเพจนั้นยาวและไม่สะดวก ผู้เยี่ยมชมเว็บไซต์ไม่จำเป็นต้องคิดเกี่ยวกับ โครงสร้างภายในเว็บไซต์ - เป็นสิ่งสำคัญสำหรับพวกเขาที่จะไปยังหน้าที่พวกเขาต้องการโดยเร็วที่สุด

ใน แถบที่อยู่ผู้ใช้จะยังคงเห็นสิ่งที่เขาป้อน:

http://www.example.com/page.html

นี่คือตัวอย่างการเปลี่ยนเส้นทางที่ง่ายที่สุด

ตรงไปฝึกครับ

มาวิเคราะห์ไฟล์การกำหนดค่าที่ใช้ในโครงการใดโครงการหนึ่งของเรา วิธีนี้เราจะเข้าใจว่าควรแก้ไขบรรทัดใดหากเกิดปัญหา

Php_value short_open_tag 1 php_value upload_max_filesize 10M php_value post_max_size 10M RewriteEngine บน RewriteBase / RewriteRule ^(แอปพลิเคชัน | โมดูล | ระบบ) - RewriteCond % (REQUEST_FILENAME) !-f RewriteCond % (REQUEST_FILENAME) !-d RewriteRule .* index.php/$0

  • php_valueการตั้งค่าสตริงและ ค่าตัวเลข
  • php_flagตั้งค่าบูลีน (ใช่/ไม่ใช่)

ไวยากรณ์คำสั่งทั่วไป

php_value/php_flag directive_name php แฟล็ก/ค่า

คำสั่ง short_open_tagอนุญาตให้ใช้ไวยากรณ์สั้น ๆ ในการจัดรูปแบบโค้ด PHP:

Php_value short_open_tag 1

upload_max_ขนาดไฟล์กำหนด ขนาดสูงสุดไฟล์ที่ดาวน์โหลด

Php_value upload_max_filesize 10M

post_max_sizeกำหนดขนาดสูงสุดของข้อมูลที่อนุญาตที่ส่ง วิธีการโพสต์.

Php_value post_max_size 10M

เขียนใหม่Engine

เปิด/ปิดกลไก mod_rewrite.

เขียนโปรแกรมใหม่อีกครั้ง

เขียนกฎใหม่

RewriteRule เพียงแปลงสตริงตามนิพจน์ทั่วไป

ไวยากรณ์:เขียนใหม่กฎ Regular_expression

# ป้อน RewriteRule "index.php" RewriteRule ^index.php main.php [R] # เอาต์พุต: "index.php" -> "main.php"

เราแปลง index.php เป็น main.php และดำเนินการเปลี่ยนเส้นทาง

สำคัญ: RewriteRule มักจะรับสองอาร์กิวเมนต์: อะไรจำเป็นต้องเปลี่ยนและ เพื่ออะไรจำเป็นต้องเปลี่ยน หากเราไม่จำเป็นต้องดำเนินการทดแทน เราสามารถเขียนลงในแบบฟอร์ม:

สัญลักษณ์ "-" หมายถึง "อย่าแปลง"

เขียนใหม่Base

หลังจาก RewriteRules ทั้งหมด RewriteBase จะมีผลใช้บังคับ หากเคียวรีผลลัพธ์หลังจากการแปลงมีความสัมพันธ์และแตกต่างจากเคียวรีดั้งเดิม RewriteBase จะกู้คืนเคียวรีนั้น ทำให้เคียวรีเป็นแบบสัมบูรณ์ RewriteBase จะผนวกตัวเองเข้ากับคำขอทางด้านซ้าย เนื่องจากค่า RewriteBase เป็นเส้นทางจากรากของไซต์ไปยัง .htaccess ในกรณีของเรา .htaccess จะอยู่ที่รูท ดังนั้น:

ไวยากรณ์: RewriteBase URL-path-from-.htaccess-file-to-site-root

ตัวอย่างเช่น:

# .htaccess อยู่ใน /dir/ # พาธจากรูทของไซต์ไปยัง .htaccess /dir/ RewriteBase /dir/ # คำขอ http://example.com/dir/logo.gif # อินพุต RewriteRule คือ "logo.gif" RewriteRule ^ logo.gif$ logo-orange.gif # หลังจาก RewriteRule: "logo.gif" -> "logo-orange.gif" # หลังจาก RewriteBase: "logo-orange.gif" -> "/dir/logo-orange. กิ๊ฟ"

การแสดงออกปกติ

นิพจน์ทั่วไปที่คุณอาจพบใน .htaccess

เครื่องหมาย ความหมาย ตัวอย่าง
. ใครก็ได้เครื่องหมาย c.t คือ แมว เปล ตัด ฯลฯ
+ หนึ่งหรือมากกว่านั้น เหมือนกันตัวอักษร a+ คือ a, aa, aaa ฯลฯ
* ศูนย์หรือหลายอย่าง เหมือนกันตัวอักษร a* ทำงานเหมือนกับ a+ แต่ในกรณีของ a* เงื่อนไขก็จะเป็นไปตามนั้นด้วย สตริงว่าง
? จับคู่หรือไม่ก็ได้ colou?r จะเหมาะกับทั้งสีและสี
^ สัญลักษณ์จากที่ เริ่มต้นเส้น ^a จับคู่สตริงที่ขึ้นต้นด้วย a
$ สัญลักษณ์นั้น สิ้นสุดเส้น a$ จับคู่สตริงที่ลงท้ายด้วย .
() ค้นหาและจดจำการแข่งขัน กลุ่มตัวอักษร

ยังสามารถใช้สำหรับ ย้อนกลับอ้างอิง(ดูตัวอย่าง)

(ab)+ จะสนองอาบับ

ตัวอย่างการอ้างอิงด้านหลัง:

เขียนกฎใหม่ ^/ (+) /(.*) $ /home?page= $1 &รหัส= $2

/album/123 → /home?page= อัลบั้ม&รหัส= 123

หนึ่งในอักขระที่เป็นไปได้ ct เหมาะสำหรับการตัด เปล หรือแมว.

การแสดงออกปกติมากขึ้น

ธง

ไวยากรณ์: เขียนใหม่กฎ Regular_expression [flag1,flag2,flag3]

ธง คำอธิบาย
[ฟ] ต้องห้าม- ส่งคืนข้อผิดพลาด 403 ถูกห้าม
[ล] ล่าสุด- หยุดกระบวนการเปลี่ยนแปลง ณ จุดนี้ และไม่ใช้กฎการเปลี่ยนแปลงอีกต่อไป
สตริงแบบสอบถามผนวก- ธงนี้บ่งบอกถึงกลไกการแปลง เพื่อเพิ่มไม่ใช่แทนที่,สืบค้นสตริงจาก URL ไปยังที่มีอยู่ในสตริงการทดแทน
ผ่าน- หยุดกระบวนการแปลงและส่งข้อมูลที่ได้รับ ลิงค์ใหม่ต่อไปตามห่วงโซ่
[ร] เปลี่ยนเส้นทาง- หยุดกระบวนการแปลงและส่งคืนผลลัพธ์ไปยังเบราว์เซอร์ไคลเอนต์เพื่อเปลี่ยนเส้นทางไปยังหน้าใหม่
[ส] ข้าม- คิดถึง กฎถัดไปหากกฎปัจจุบันใช้งานได้ คุณสามารถระบุจำนวนกฎที่จะละเว้นได้

มันเกิดขึ้นว่าข้อมูลถูกถ่ายโอนไปยังโปรแกรมจากบรรทัดคำสั่งเมื่อมีการเรียก ข้อมูลดังกล่าวเรียกว่าอาร์กิวเมนต์บรรทัดคำสั่ง มีลักษณะดังนี้:

./a.out test.txt ls -lt /home/ปีเตอร์/

ที่นี่โปรแกรม a.out ถูกเรียก (จาก ไดเรกทอรีปัจจุบัน) และ ls (จากไดเร็กทอรีเดียวกันที่ระบุในตัวแปรสภาพแวดล้อม PATH) โปรแกรมแรกจากบรรทัดคำสั่งได้รับหนึ่งคำ - test.txt ส่วนที่สอง - สอง: -lt และ /home/peter/

หากโปรแกรมเขียนด้วยภาษา C เมื่อเปิดใช้งาน การควบคุมจะถูกโอนไปยังฟังก์ชัน main() ทันที ดังนั้นจึงเป็นฟังก์ชันที่ได้รับอาร์กิวเมนต์บรรทัดคำสั่งที่กำหนดให้กับตัวแปรพารามิเตอร์

ก่อนหน้านี้ เราได้กำหนดฟังก์ชัน main() ไว้เหมือนกับว่ามันไม่มีพารามิเตอร์และไม่ส่งคืนอะไรเลย ในความเป็นจริง ในภาษา C ฟังก์ชันใดๆ ตามค่าเริ่มต้น (หากไม่มีการกำหนดอย่างอื่น) จะส่งกลับจำนวนเต็ม คุณสามารถมั่นใจได้ในเรื่องนี้ หากคุณเขียนโค้ดด้วยวิธีนี้:

main() ( printf (“สวัสดีครับ. \n"- กลับ 0 ;

-

จากนั้นจะไม่มีคำเตือนหรือข้อผิดพลาดเกิดขึ้นระหว่างการคอมไพล์ สิ่งเดียวกันนี้จะเกิดขึ้นถ้าคุณเขียน int main() นี่เป็นการพิสูจน์ว่าฟังก์ชันโดยค่าเริ่มต้นจะส่งกลับจำนวนเต็มและไม่ใช่ค่าใดเลย (เป็นโมฆะ) แม้ว่าฟังก์ชันที่ส่งคืนจะเป็น "แทนที่" เสมอ เช่น voidmain() หรือ float main()

  1. เมื่อเรียกใช้โปรแกรมจากบรรทัดคำสั่ง ข้อมูลคู่ต่อไปนี้จะถูกส่งเข้าไปเสมอ:จำนวนเต็ม
  2. ระบุจำนวนคำ (องค์ประกอบคั่นด้วยช่องว่าง) บนบรรทัดคำสั่งเมื่อถูกเรียกตัวชี้ไปยังอาร์เรย์ของสตริง โดยที่แต่ละบรรทัดอยู่แยกคำ

จากบรรทัดคำสั่ง

โปรดทราบว่าชื่อโปรแกรมก็นับด้วยเช่นกัน ตัวอย่างเช่น หากการโทรมีลักษณะดังนี้:

อาร์กิวเมนต์แรกของโปรแกรมมีค่า 4 และอาร์เรย์ของสตริงถูกกำหนดเป็น ("./a.out", "12", "theme", "2")

โปรดสังเกตคำศัพท์ มีเพียงสองอาร์กิวเมนต์ของโปรแกรมเท่านั้น (ตัวเลขและอาร์เรย์) แต่มีอาร์กิวเมนต์บรรทัดคำสั่งได้มากเท่าที่คุณต้องการ อาร์กิวเมนต์บรรทัดคำสั่งจะถูก "แปลง" เป็นอาร์กิวเมนต์ของโปรแกรม (เป็นอาร์กิวเมนต์ของฟังก์ชัน main())
ข้อมูลนี้ (หมายเลขและตัวชี้) จะถูกส่งผ่านไปยังโปรแกรม แม้ว่าจะเรียกตามชื่อโดยไม่ส่งผ่านอะไรก็ตาม: ./a.out ในกรณีนี้ อาร์กิวเมนต์แรกมีค่า 1 และอาร์กิวเมนต์ที่สองชี้ไปที่อาร์เรย์ที่ประกอบด้วยเพียงบรรทัดเดียว ("./a.out")

เพียงเพราะว่าข้อมูลถูกส่งเข้าสู่โปรแกรมไม่ได้หมายความว่าฟังก์ชัน main() จะต้องยอมรับข้อมูลนั้น หากฟังก์ชัน main() ถูกกำหนดโดยไม่มีพารามิเตอร์ ก็ไม่สามารถเข้าถึงอาร์กิวเมนต์บรรทัดคำสั่งได้ แม้ว่าจะไม่มีสิ่งใดขัดขวางไม่ให้คุณส่งสัญญาณก็ตาม จะไม่มีข้อผิดพลาด

ในการเข้าถึงข้อมูลที่ส่งไปยังโปรแกรมจะต้องกำหนดให้กับตัวแปร เนื่องจากอาร์กิวเมนต์จะถูกส่งไปยัง main() ทันที ส่วนหัวจึงควรมีลักษณะดังนี้:
หลัก (int n, ถ่าน * arr)

ตัวแปรตัวแรก (n) มีจำนวนคำ และตัวแปรตัวที่สองประกอบด้วยตัวชี้ไปยังอาร์เรย์ของสตริง บ่อยครั้งที่พารามิเตอร์ตัวที่สองเขียนเป็น **arr อย่างไรก็ตาม มันก็เป็นสิ่งเดียวกัน โปรดจำไว้ว่าอาร์เรย์ของสตริงนั้นมีตัวชี้ไปยังสตริงเป็นองค์ประกอบ และเราจะส่งพอยน์เตอร์ไปยังองค์ประกอบแรกของอาร์เรย์ไปยังฟังก์ชัน ปรากฎว่าเรากำลังส่งพอยน์เตอร์ไปยังพอยน์เตอร์เช่น **เอ่อ..

ออกกำลังกาย
เขียนโปรแกรมดังนี้:

#รวม int main(int argc, char ** argv) ( int i; printf ("%d) \n", argc) ;< argc; i++ ) puts (argv[ i] ) ; }

สำหรับ (i= 0 ; i จะแสดงจำนวนคำบนบรรทัดคำสั่งเมื่อมีการเรียกและแต่ละคำด้วยบรรทัดใหม่

- เรียกมันว่าไม่มีอาร์กิวเมนต์บรรทัดคำสั่งและมีอาร์กิวเมนต์

ในโปรแกรมเราใช้ตัวแปรพารามิเตอร์ argc และ argv เป็นเรื่องปกติที่จะใช้ชื่อเหล่านี้ แต่จริงๆ แล้วมันสามารถเป็นอะไรก็ได้ เป็นการดีกว่าที่จะยึดติดกับมาตรฐานนี้เพื่อให้โปรแกรมของคุณเข้าใจได้ง่ายขึ้นไม่เพียง แต่สำหรับคุณเท่านั้น แต่ยังรวมไปถึงโปรแกรมเมอร์คนอื่น ๆ ด้วย

ความสำคัญในทางปฏิบัติของการถ่ายโอนข้อมูลไปยังโปรแกรม

หากคุณมีประสบการณ์เกี่ยวกับบรรทัดคำสั่ง GNU/Linux คุณจะรู้ว่าคำสั่งส่วนใหญ่มีสวิตช์และอาร์กิวเมนต์ ตัวอย่างเช่น เมื่อดูเนื้อหาของไดเร็กทอรี การคัดลอก การย้าย ออบเจ็กต์ระบบไฟล์ที่ดำเนินการคำสั่งจะถูกระบุเป็นอาร์กิวเมนต์ คุณสมบัติของการใช้งานถูกกำหนดโดยใช้คีย์ เช่น ในทีม

cp คือชื่อคำสั่ง -r คือสวิตช์ และ ../les_1 และ ../les_101 เป็นอาร์กิวเมนต์ของคำสั่ง

โดยทั่วไปแล้ว ส่วนใหญ่แล้ว ที่อยู่ไฟล์และ "ตัวดัดแปลง" (ซึ่งเป็นคีย์) ของกระบวนการเรียกใช้งานโปรแกรมจะถูกโอนไปยังโปรแกรมเมื่อมีการเปิดใช้งาน

มาเขียนโปรแกรมที่เปิดขึ้นมากันดีกว่า ระบุโดยผู้ใช้บนบรรทัดคำสั่งไฟล์ที่จะเขียนหรือเพิ่มและเขียน (เพิ่ม) มีข้อมูลเดียวกันกับที่ผู้ใช้ป้อนจากแป้นพิมพ์ระหว่างการทำงานของโปรแกรม:

#รวม #รวม หลัก (int argc, char ** argv) ( int i, ch; FILE * f[ 5 ] ; if (argc< 3 || argc >7) (ใส่ ( "จำนวนพารามิเตอร์ไม่ถูกต้อง"- กลับ 1 ; ) if (strcmp (argv[ 1 ] , "-w" ) != 0 && strcmp (argv[ 1 ] , "-a" ) != 0 ) ( ใส่ ("พารามิเตอร์แรกสามารถเป็นได้ทั้ง -w หรือ -a"< argc- 2 ; i++ ) { f[ i] = fopen (argv[ i+ 2 ] , argv[ 1 ] + 1 ) ; if (f[ i] == NULL) { printf (- กลับ 2 ;) สำหรับ (i= 0 ; i< argc- 2 ; i++ ) putc (ch, f[ i] ) ; for (i= 0 ; i < argc- 2 ; i++ ) fclose (f[ i] ) ; return 0 ; }

"ไฟล์ %s ไม่สามารถเปิดได้\n "

  1. , argv[ i+ 2 ] ) ;
  2. กลับ 3 ;
  3. ) ) ในขณะที่ ((ch = getchar () ) != EOF) สำหรับ (i= 0 ; i
  4. ใน คำอธิบายสำหรับรหัส:มีการสร้างอาร์เรย์ของตัวชี้ไฟล์ห้าตัว ดังนั้นคุณสามารถเปิดไฟล์ได้ไม่เกินห้าไฟล์ในเวลาเดียวกัน ตัวชี้ไฟล์ของไฟล์แรกจะถูกเก็บไว้ในองค์ประกอบอาร์เรย์ f ตัวที่สอง - ใน f เป็นต้น มีการตรวจสอบจำนวนอาร์กิวเมนต์บรรทัดคำสั่ง ควรมีอย่างน้อยสามอันเพราะ... ไฟล์แรกคือชื่อโปรแกรม ไฟล์ที่สองคือโหมดการเปิดไฟล์ ไฟล์ที่สามคือไฟล์แรกหรือไฟล์เดียวที่จะเขียน เนื่องจากโปรแกรมอนุญาตให้คุณเปิดไฟล์ได้เพียงห้าไฟล์ จำนวนอาร์กิวเมนต์บรรทัดคำสั่งทั้งหมดต้องไม่เกินเจ็ดไฟล์ ดังนั้นหากจำนวนอาร์กิวเมนต์น้อยกว่า 3 หรือมากกว่า 7 แสดงว่าโปรแกรมสิ้นสุดลงเนื่องจาก คำสั่ง return จะทำให้ฟังก์ชันออก แม้ว่าจะมีโค้ดเพิ่มเติมตามมาก็ตาม ค่าที่ส่งคืนจากฟังก์ชันที่ไม่เท่ากับ 0 สามารถตีความได้โดยกระบวนการพาเรนต์เป็นข้อความที่โปรแกรมยุติการทำงานด้วยข้อผิดพลาดตรวจสอบความถูกต้องของอาร์กิวเมนต์บรรทัดคำสั่งที่สอง หากไม่ใช่ทั้ง "-w" หรือ "-a" แสดงว่านิพจน์เงื่อนไขในวินาที if ส่งคืน 1 (จริง) ฟังก์ชัน strcmp() ช่วยให้คุณสามารถเปรียบเทียบสตริงและส่งคืนค่า 0 หากสตริงมีค่าเท่ากัน
  5. นิพจน์ argv+1 ช่วยให้คุณสามารถ "ตัด" สตริงย่อย "w" (หรือ "a") ออกจากสตริง "-w" (หรือ "-a") ได้ เนื่องจาก argv เป็นตัวชี้ไปยังองค์ประกอบแรกของสตริง โดยการเพิ่มหนึ่งตัวชี้ไปที่ตัวชี้ เราจะย้ายมันไปยังองค์ประกอบถัดไปของอาร์เรย์
  6. หากไม่สามารถเปิดไฟล์ได้ ฟังก์ชัน fopen() จะคืนค่า NULL ในกรณีนี้โปรแกรมจะสิ้นสุด
  7. อักขระทุกตัวที่ผู้ใช้ป้อนบนแป้นพิมพ์จะถูกเขียนลงในไฟล์ที่เปิดอยู่ทั้งหมด
  8. ในตอนท้ายไฟล์จะถูกปิด

บทความนี้เกิดจากแนวคิดเรื่องการฝึกอบรมขั้นสูงสำหรับพนักงานของเรา การสนับสนุนด้านเทคนิคทำงานกับ mod_rewrite การปฏิบัติแสดงให้เห็นว่าหลังจากศึกษาหนังสือเรียนภาษารัสเซียจำนวนมากแล้ว ทีมสนับสนุนสามารถแก้ไขปัญหาเทมเพลตได้ดี แต่การรวบรวมกฎที่เป็นอิสระเกิดขึ้นจากการลองผิดลองถูก ปริมาณมากข้อผิดพลาด ปัญหาคือความเข้าใจที่ดีเกี่ยวกับวิธีการทำงานของ mod_rewrite จำเป็นต้องศึกษาเอกสารต้นฉบับภาษาอังกฤษ ตามด้วยคำอธิบายเพิ่มเติมหรือชั่วโมงการทดลองกับ RewriteLog

บทความนี้จะอธิบายวิธีการทำงานของ mod_rewrite การทำความเข้าใจหลักการของการดำเนินการช่วยให้คุณเข้าใจผลกระทบของแต่ละคำสั่งได้อย่างชัดเจนและจินตนาการได้อย่างชัดเจนว่าเกิดอะไรขึ้นในคราวเดียวหรืออย่างอื่นภายใน mod_rewrite เมื่อประมวลผลคำสั่ง

ฉันคิดว่าผู้อ่านคงคุ้นเคยกับ mod_rewrite แล้วและฉันจะไม่อธิบายพื้นฐานของมันซึ่งหาได้ง่ายบนอินเทอร์เน็ต ควรสังเกตว่าบทความนี้ครอบคลุมถึงงานของ mod_rewrite เมื่อใช้คำสั่งในไฟล์ .htaccess ความแตกต่างเมื่อทำงานในบริบท กำหนดใน.

ดังนั้น คุณได้ศึกษา mod_rewrite รวบรวม RewriteRules หลายรายการ และจัดการเพื่อเผชิญกับการเปลี่ยนเส้นทางอย่างไม่มีที่สิ้นสุด กรณีที่กฎด้วยเหตุผลบางประการไม่สอดคล้องกับคำขอของคุณ รวมถึงการดำเนินการที่คาดเดาไม่ได้ของกลุ่มกฎเมื่อกฎที่ตามมาเปลี่ยนแปลงโดยไม่คาดคิด คำขอที่จัดทำขึ้นอย่างระมัดระวังตามกฎก่อนหน้านี้

RewriteRule ทำงานร่วมกับอะไร?

RewriteRule แรกจะถูกส่งผ่านเส้นทางจากตำแหน่ง .htaccess ไปยังไฟล์ที่ร้องขอ บรรทัดนี้ไม่เคยขึ้นต้นด้วย "/" RewriteRules ที่ตามมาจะส่งผลลัพธ์ของการแปลงก่อนหน้านี้

หากต้องการทำความเข้าใจวิธีการทำงานของ RewriteRule อย่างถ่องแท้ คุณต้องกำหนดก่อนว่า RewriteRule ทำงานอย่างไร มาดูกันว่า Apache รับสตริงที่ในตอนแรกส่งผ่านไปยัง RewriteRule ใน .htaccess เพื่อการประมวลผลอย่างไร

เมื่อคุณเริ่มทำงานกับ mod_rewrite เป็นครั้งแรก คุณจะถือว่ามันใช้งานได้กับลิงก์ อย่างไรก็ตาม กรณีนี้จะไม่เกิดขึ้นเมื่อใช้ mod_rewrite ใน .htaccess ที่จริงแล้ว ไม่ใช่ลิงก์ที่ส่งไปยัง RewriteRule แต่เป็นเส้นทางไปยังไฟล์ที่ร้องขอ

เนื่องจากสถาปัตยกรรมภายในของ Apache ทันทีที่ .htaccess เข้ามามีบทบาท mod_rewrite สามารถทำงานได้บนพาธไปยังไฟล์ที่จะประมวลผลเท่านั้น นี่เป็นเพราะความจริงที่ว่าก่อนที่จะถูกส่งไปยัง mod_rewrite คำขออาจได้รับการแก้ไขโดยโมดูลอื่น ๆ (เช่น mod_alias) และเส้นทางสุดท้ายไปยังไฟล์บนไซต์อาจไม่ตรงกับลิงก์ดั้งเดิมอีกต่อไป หาก mod_rewrite ทำงานกับการอ้างอิงดั้งเดิม มันจะหยุดการทำงานของโมดูลที่แก้ไขคำขอก่อนหน้านั้น

ดังนั้น mod_rewrite จะถูกส่งผ่านพาธสัมบูรณ์ไปยังไฟล์ที่ควรประมวลผล Mod_rewrite ยังทราบเส้นทางไปยัง .htaccess ซึ่งเป็นที่ตั้งของกฎ RewriteRule หากต้องการสร้างพาธไปยังไฟล์ให้คล้ายกับลิงก์ที่นักพัฒนาไซต์วางแผนจะใช้ mod_rewrite จะตัดส่วนของไฟล์ .htaccess ออกจากพาธสัมบูรณ์

ดังนั้น เส้นทางนี้ซึ่งเส้นทางไปยัง .htaccess ถูกตัดออกไป และถูกส่งผ่านไปยัง RewriteRule แรก ตัวอย่างเช่น:

คำขอ: http://example.com/templates/silver/images/logo.gif DocumentRoot: /var/www/example.com เส้นทางไปยังไฟล์: /var/www/example.com/templates/silver/images/logo gif .htaccess อยู่ใน: /var/www/example.com/templates/.htaccess

RewriteRule แรกจะได้รับ: silver/images/logo.gif โปรดทราบว่า: “templates/” ก็ถูกตัดออกเช่นกัน RewriteRule ทำงานอย่างไร เส้นทางไปยัง .htaccess ถูกตัดออกพร้อมกับเครื่องหมายทับ มีผลกระทบจากสิ่งนี้: บรรทัดที่เริ่มแรกส่งผ่านไปยังการประมวลผล RewriteRule ไม่เคยขึ้นต้นด้วย "/"

สิ่งสำคัญคือต้องจำไว้ว่า RewriteRule ไม่ได้ทำอะไร จะไม่ประมวลผลชื่อไซต์ อาร์กิวเมนต์ที่ส่งไปยังสคริปต์ และจะไม่ประมวลผลลิงก์ทั้งหมด หาก .htaccess ไม่ได้อยู่ในรากของไซต์ ทั้งหมดนี้ดำเนินการโดย RewriteCond ซึ่งเราจะพูดคุยกันในภายหลัง ดังนั้น:

# จะไม่ทำงาน - กฎเริ่มต้นด้วย / RewriteRule ^/index.php$ /my-index.php # จะไม่ทำงาน - ไม่ได้วิเคราะห์ชื่อไซต์ RewriteRule RewriteRule ^example.com/.* http://www.example .com # จะไม่ทำงาน - อาร์กิวเมนต์ลิงก์ไม่อยู่ใน RewriteRule RewriteRule index.php\?newspage=(+) news.php?page=$1 # จะใช้งานได้ก็ต่อเมื่อ .htaccess อยู่ในตำแหน่งเดียวกับเทมเพลต โฟลเดอร์ # ตัวอย่างเช่น ในรูทของไซต์ นั่นคือ หาก .htaccess อยู่ใน templates/.htaccess กฎ # จะไม่ทำงาน เนื่องจาก mod_rewrite จะตัดเส้นทางไปยัง .htaccess และบรรทัดจะไปสิ้นสุดที่อินพุต RewriteRule # โดยไม่มี "templates/" RewriteRule ^templates/ ทั่วไป/yandex-money.gif$ templates/shared/yad.gif

เราพบว่า RewriteRule ทำงานร่วมกับอะไรได้บ้าง ตอนนี้เรามาดูวิธีการทำงานกัน

RewriteRule ทำงานอย่างไร

RewriteRule เพียงแปลงสตริงตามนิพจน์ทั่วไป เท่านี้ก็เรียบร้อย RewriteRule ทำงานบนสตริง ไม่ใช่ลิงก์หรือเส้นทางไปยังไฟล์

ดังที่เราพบข้างต้น อินพุต RewriteRule จะมีเส้นทางจาก .htaccess ไปยังไฟล์ที่ร้องขอ ตอนนี้สะดวกที่สุดในการสรุปจากพาธและลิงก์ และพิจารณาว่า RewriteRule ทำงานร่วมกับอะไรได้บ้าง สตริงปกติ- สตริงนี้ถูกส่งผ่านจาก RewriteRule ไปยัง RewriteRule ซึ่งได้รับการแก้ไขหากมี RewriteRules ใดทำงาน

ใน มุมมองทั่วไปนอกเหนือจากความซับซ้อนของการใช้แฟล็ก (บางส่วนเราจะดูด้านล่าง) และความซับซ้อนของการเขียนนิพจน์ทั่วไป (ซึ่งเราจะไม่กล่าวถึงมากนักในบทความนี้) RewriteRule ทำงานได้ง่ายมาก เราเข้าแถวแล้ว เปรียบเทียบกับนิพจน์ทั่วไปในอาร์กิวเมนต์แรก หากมีข้อมูลที่ตรงกัน ให้แทนที่ทั้งบรรทัดด้วยค่าของอาร์กิวเมนต์ที่สอง ส่งผ่านสตริงไปยัง RewriteRule ถัดไป นั่นคือทั้งหมดโดยพื้นฐาน เพื่อแสดงให้เห็นอย่างชัดเจนว่า RewriteRule ใช้งานได้กับสตริงโดยเฉพาะ ให้พิจารณาตัวอย่างที่ยอดเยี่ยมต่อไปนี้:

# คำขอ: http://mysite.com/info.html # RewriteRule แรกจะมี "info.html" # แปลงคำขอเป็นสตริงที่กำหนดเอง RewriteRule ^info.html$ "ฉันเห็นเต่าอยู่ในหลุม และมันก็กำลังเต้นร็อกแอนด์โรล และมันก็ยิ้ม โดยรวมแล้วมันเป็นตุ๊กตาที่ตลกมาก" # "info.html" -> "ฉันเห็นเต่า..." # แทนที่บรรทัดนี้ด้วย ลิงค์ภายนอก- RewriteRule เต่า https://example.com/information/index.html # "ฉันเห็นเต่า..." -> "https://example.com/information/index.html" # เปลี่ยนชื่อไซต์! กฎการเขียนซ้ำ ^(.*)example.com(.*)$ $1example.org$2 # "https://example.com/information/index.html" -> "https://example.org/information/index. html" # แทนที่โปรโตคอล! RewriteRule ^https:(.*)$ ftp:$1 # "https://example.org/information/index.html" -> "ftp://example.org/information/index.html" # แทนที่ลิงก์สุดท้าย . กฎการเขียนใหม่ ^(.*)/index.html$ $1/main.php # "ftp://example.org/information/index.html" -> "ftp://example.org/information/main.php"

อย่างที่คุณเห็น RewriteRule ไม่สนใจว่ามันจะทำงานกับอะไร - มันเพียงแปลงสตริงตามอาร์กิวเมนต์ที่กำหนด หากต้องการ คุณสามารถจัดเก็บอาร์เรย์ข้อมูลใด ๆ ไว้ในสตริงได้หากต้องการ เก็บไว้ และ ความรู้ที่ดีคุณยังสามารถเขียนโอเอกซ์บน RewriteRule สำหรับนิพจน์ทั่วไปได้

จำเป็นต้องจดบันทึกที่นี่: แม้ว่า RewriteRule จะใช้งานได้กับสตริงล้วนๆ แต่ยังคงเน้นที่การทำงานกับลิงก์ ดังนั้นมันจะตอบสนองในลักษณะพิเศษกับบรรทัดที่ขึ้นต้นด้วย

https://

หรือแอนะล็อก (จะจำได้ว่าเราต้องการเปลี่ยนเส้นทางภายนอก) และไปที่ "?" (ถือว่าอักขระต่อไปนี้เป็นอาร์กิวเมนต์ที่จะต้องทดแทนคำขอ) อย่างไรก็ตาม เราไม่ได้สนใจเรื่องนี้ในตอนนี้ - สิ่งสำคัญคือต้องเข้าใจว่า RewriteRule ไม่มีเวทย์มนตร์ใดๆ - เพียงแค่ใช้สตริงและเปลี่ยนวิธีที่คุณสั่ง เราจะดูการเปลี่ยนเส้นทางและการโต้แย้งภายนอกในบทความในภายหลัง มีบางอย่างที่จะพูดถึงเช่นกัน

หลังจากการแปลงทั้งหมดเสร็จสิ้นและดำเนินการ RewriteRule สุดท้ายแล้ว RewriteBase จะมีผล

RewriteBase ใช้ทำอะไร?

หากแบบสอบถามผลลัพธ์มีความสัมพันธ์และแตกต่างจากแบบสอบถามต้นฉบับ RewriteBase จะเพิ่มตัวเองทางด้านซ้าย จำเป็นต้องระบุ RewriteBase ใน .htaccess ค่าของมันคือเส้นทางจากรูทของไซต์ไปยัง .htaccess RewriteBase จะถูกดำเนินการหลังจาก RewriteRules ทั้งหมดเท่านั้น ไม่ใช่ระหว่างกัน

เราได้กล่าวไปแล้วข้างต้นว่า mod_rewrite ซึ่งทำงานใน .htaccess มีเส้นทางที่แน่นอนไปยังไฟล์ที่ร้องขอ หากต้องการส่งต่อไปยัง RewriteRule mod_rewrite จะตัดเส้นทางไปยัง .htaccess ออก จากนั้น RewriteRules จะเปลี่ยนคำขอทีละรายการตามลำดับ และตอนนี้ หลังจากแก้ไขคำขอแล้ว Apache จะต้องกู้คืนเส้นทางที่แน่นอนไปยังไฟล์ที่ต้องดำเนินการในท้ายที่สุด RewriteBase จริงๆ แล้วเป็นแฮ็คที่ช่วยกู้คืนเส้นทางดั้งเดิมของไฟล์

RewriteBase จะถูกดำเนินการหลังจากการแปลงทั้งหมด ซึ่งหมายความว่าจะไม่เปลี่ยนคำขอระหว่าง RewriteRules แต่จะมีผลเฉพาะเมื่อ RewriteRules ทั้งหมดเสร็จสมบูรณ์แล้วเท่านั้น

หลังจากการแปลงทั้งหมดแล้ว RewriteBase จะดูว่าเส้นทางผลลัพธ์เป็นแบบสัมพัทธ์หรือแบบสัมบูรณ์ ในบริบทของ Apache นี่หมายถึงเส้นทางสัมพัทธ์หรือสัมบูรณ์ เริ่มต้นจากรากของไซต์: images/logo.gif - สัมพันธ์กัน /images/logo.gif - สัมบูรณ์ (เครื่องหมายทับที่จุดเริ่มต้น) http://example.com/images/logo.gif - สมบูรณ์ที่สุด หากเส้นทางเป็นแบบสัมบูรณ์ RewriteBase จะไม่ทำอะไรเลย และถ้ามันสัมพันธ์กัน RewriteBase จะต่อท้ายตัวเองทางด้านซ้าย ใช้ได้กับการเปลี่ยนเส้นทางทั้งภายในและภายนอก:

# .htaccess อยู่ใน /images/ # มีการระบุ RewriteBase /images/ RewriteBase /images/ # คำขอ http://example.com/images/logo.gif # อินพุต RewriteRule คือ "logo.gif" RewriteRule ^logo.gif $ logo -orange.gif # หลังจาก RewriteRule: "logo.gif" -> "logo-orange.gif" # หลังจาก RewriteBase: "logo-orange.gif" -> "/images/logo-orange.gif" # ขอ http :/ /example.com/images/header.png # อินพุต RewriteRule คือ "header.png" RewriteRule ^header.png$ /templates/rebranding/header.png # หลังจาก RewriteRule: "header.png" -> "/ templates/rebranding /header.png" # After RewriteBase: ไม่มีการเปลี่ยนแปลง ดังนั้นผลลัพธ์สุดท้ายของการเปลี่ยนแปลงจึงเริ่มต้นด้วย "/" # คำขอ http://example.com/images/director.tiff # อินพุต RewriteRule คือ "director.tiff" # เราใช้การเปลี่ยนเส้นทางแบบสัมพันธ์ภายนอก RewriteRule ^director.tiff$ staff/manager/director.tiff # หลังจาก RewriteRule: "director.tiff" -> "staff/manager/director.tiff" # + mod_rewrite จำได้ว่าจะมีการเปลี่ยนเส้นทางภายนอก # หลังจาก RewriteBase: "staff/manager/director.tiff" -> "/images/staff/manager/ Director.tiff" # mod_rewrite จำได้เกี่ยวกับการเปลี่ยนเส้นทางภายนอก: # "/images/staff/manager/director.tiff" -> http://example.com/images/staff/manager/director.tiff

โดยทั่วไป หลังจากคุ้นเคยกับ mod_rewrite แล้ว นิสัยต่อไปนี้จะพัฒนา:

    เพิ่ม “RewriteBase /” ลงในแต่ละ .htaccess

    การเปลี่ยนเส้นทางทั้งหมดจะขึ้นต้นด้วยเครื่องหมายทับ: “RewriteRule news.php /index.php?act=news” สิ่งนี้จะช่วยกำจัดสิ่งประดิษฐ์จาก RewriteBase แต่การทำเช่นนี้เป็นสิ่งที่ผิด ตอนนี้เรารู้แล้วว่า RewriteBase ทำอะไรได้บ้าง เราก็สามารถกำหนดกฎที่ถูกต้องต่อไปนี้ได้:

RewriteBase ต้องตรงกับเส้นทางจากรากของไซต์ไปยัง .htaccess คุณจะต้องเริ่มการเปลี่ยนเส้นทางด้วย "/" เมื่อคุณต้องการระบุเส้นทางที่แน่นอนจากรูทไซต์ไปยังไฟล์

จะเกิดอะไรขึ้นถ้าคุณไม่ระบุ RewriteBase ตามค่าเริ่มต้น Apache ทำให้มันเท่ากัน เส้นทางที่แน่นอนบน ระบบไฟล์ to.htaccess (เช่น /var/www/example.com/templates/) ความไม่ถูกต้องของสมมติฐาน Apache นี้ปรากฏในการเปลี่ยนเส้นทางแบบสัมพันธ์ภายนอก:

# คำขอ http://example.com/index.php # DocumentRoot: /var/www/example.com/ # .htaccess อยู่ที่รากของไซต์และไม่ได้ระบุ RewriteBase # ดังนั้น ตามค่าเริ่มต้น RewriteBase จะเท่ากับเส้นทางสัมบูรณ์ to.htaccess: /var/www/example.com/ # อินพุต RewriteRule คือ "index.php" RewriteRule ^index.php main.php [R] # เอาต์พุต คือ "index.php" " -> "main.php" # mod_rewrite จำได้ว่าจำเป็นต้องมีการเปลี่ยนเส้นทางภายนอก # RewriteRule หมด # mod_rewrite ยังคงดำเนินการ RewriteBase เนื่องจากมีค่าเริ่มต้น # ปรากฎว่า: "main.php" -> "/var/www/example.com/main.php" # ที่นี่ mod_rewrite จำได้ว่ามีการเปลี่ยนเส้นทางภายนอก: # "/var/www/example.com/main php" -> http://example.com/var/www/example.com/main.php # ปรากฏว่าไม่ใช่สิ่งที่พวกเขามีอยู่ในใจเลย

ดังนั้นคำขอจะต้องผ่าน RewriteRules ทั้งหมด หลังจากนั้นหากจำเป็น RewriteBase จะถูกเพิ่มเข้าไป ตอนนี้ Apache ควรให้บริการไฟล์ที่เส้นทางผลลัพธ์ชี้ไปหรือไม่ เลขที่ ตอนนี้คำขอผลลัพธ์จะได้รับการประมวลผลอีกครั้ง.

mod_rewrite ทำงานอย่างไร ธง [L]

mod_rewrite เริ่มประมวลผลคำขอซ้ำแล้วซ้ำอีกจนกว่าจะหยุดการเปลี่ยนแปลง และธง [ล]ไม่สามารถหยุดมันได้

เมื่อสร้างการกำหนดค่า mod_rewrite ที่ซับซ้อนไม่มากก็น้อย สิ่งสำคัญคือต้องเข้าใจสิ่งนั้น การแก้ไขแบบสอบถามไม่ได้สิ้นสุดที่ RewriteRule สุดท้าย- หลังจากที่มันได้ผล กฎข้อสุดท้ายเพิ่ม RewriteRule และ RewriteBase แล้ว mod_rewrite จะดูว่าคำขอมีการเปลี่ยนแปลงหรือไม่ หากคำขอมีการเปลี่ยนแปลง การประมวลผลจะเริ่มต้นอีกครั้งจาก beginning.htaccess

Apache ทำเช่นนี้เนื่องจากในกระบวนการเปลี่ยนแปลงคำขอ คำขออาจถูกเปลี่ยนเส้นทางไปยังไดเร็กทอรีอื่น อาจมี .htaccess ของตัวเองซึ่งไม่เกี่ยวข้องกับการประมวลผลคำขอก่อนหน้านี้ .htaccess ใหม่นี้อาจมีกฎที่ส่งผลต่อการประมวลผลคำขอ ทั้งกฎ mod_rewrite และกฎของโมดูลอื่นๆ เพื่อจัดการกับสถานการณ์นี้อย่างถูกต้อง Apache ต้องรีสตาร์ทลูปการประมวลผลทั้งหมด

เดี๋ยวก่อน แต่มีธงอยู่ [ล]ซึ่งหยุดการประมวลผลคำขอ mod_rewrite!

ไม่เชิง. ธง [ล]หยุดการวนซ้ำปัจจุบันของการประมวลผลคำขอ อย่างไรก็ตาม หากคำขอได้รับการแก้ไขโดย RewriteRules ที่ยังคงจัดการเพื่อประมวลผล Apache จะเริ่มรอบการประมวลผลคำขออีกครั้งจาก RewriteRule แรก

# คำขอ: http://example.com/a.html RewriteBase / RewriteRule ^a.html$ b.html [L] RewriteRule ^b.html$ a.html [L]

ตัวอย่างด้านบนจะส่งผลให้เกิดการเปลี่ยนเส้นทางและ "Internal ข้อผิดพลาดของเซิร์ฟเวอร์"ในที่สุด. ในตัวอย่างนี้ การวนซ้ำไม่สิ้นสุดนั้นชัดเจน แต่ในการกำหนดค่าที่ซับซ้อนมากขึ้น คุณอาจต้องเจาะลึกกฎเพื่อพิจารณาว่าข้อความค้นหาใดที่วนซ้ำไปมา

เพื่อหลีกเลี่ยงสถานการณ์ดังกล่าว ขอแนะนำให้ใช้ธง [L] เมื่อจำเป็นเท่านั้น ความต้องการอาจมีได้สองประเภท: เมื่อใช้การเปลี่ยนเส้นทางภายนอก - หรือ . ในกรณีที่มีการเปลี่ยนเส้นทางภายนอก การประมวลผลคำขอเพิ่มเติมเป็นสิ่งที่ไม่พึงประสงค์ (ดูด้านล่างเกี่ยวกับการตั้งค่าสถานะ [ร]) และเป็นการดีกว่าที่จะหยุดมัน เมื่อมีการวนซ้ำใน .htaccess ที่ไม่สามารถกำจัดได้ และจะต้องหยุดการประมวลผลคำขอโดย mod_rewrite ในกรณีนี้ จะใช้โครงสร้างพิเศษ - ดูส่วนท้ายของบทความเพื่อดูเคล็ดลับในหัวข้อนี้

แต่ตัวอย่างด้านล่างจะไม่วนซ้ำ พยายามระบุสาเหตุและไฟล์ใดที่จะมอบให้กับ Apache ในที่สุด

# คำขอ: http://example.com/a.html # Start.htaccess RewriteBase / RewriteRule ^a.html$ b.html RewriteRule ^b.html$ a.html # End.htaccess

วิธีแก้ไข: จากการดำเนินการ RewriteRules ทั้งหมด คำขอจึงมีการเปลี่ยนแปลงในลักษณะที่ผลลัพธ์สุดท้ายจะเท่ากับผลลัพธ์ดั้งเดิม Apache เห็นสิ่งนี้และไม่ประมวลผลคำขออีกครั้ง ไฟล์ a.html จะถูกส่งกลับ

mod_rewrite ทำงานอย่างไร ธง [R]

    ธง [ร]ไม่หยุดการประมวลผลคำขอ โดยส่งคืนการเปลี่ยนเส้นทางภายนอกทันที แต่จะจดจำความจำเป็นในการเปลี่ยนเส้นทางภายนอก และการประมวลผลคำขอจะดำเนินต่อไปด้วย RewriteRule ต่อไปนี้ ขอแนะนำให้ใช้กับแฟล็กเสมอ [ล].

    ธง [ร]บอก Apache ว่าจำเป็นต้องทำการเปลี่ยนเส้นทางภายนอกแทนที่จะเป็นการเปลี่ยนเส้นทางภายใน อะไรคือความแตกต่างระหว่างการเปลี่ยนเส้นทางภายนอกและการเปลี่ยนเส้นทางภายใน? การเปลี่ยนเส้นทางภายในเพียงเปลี่ยนเส้นทางไปยังไฟล์ที่จะมอบให้กับผู้ใช้ ในขณะที่ผู้ใช้เชื่อว่าเขาได้รับไฟล์ที่เขาร้องขอในตอนแรก ด้วยการเปลี่ยนเส้นทางภายนอก Apache จะส่งคืนสถานะการตอบกลับ 301 หรือ 302 ให้กับผู้ใช้แทนเนื้อหาของไฟล์ และแจ้งให้ผู้ใช้ทราบถึงลิงก์ที่เบราว์เซอร์ควรใช้เพื่อรับไฟล์

ดูเหมือนว่าเมื่อประมวลผลแฟล็ก [ร] Apache ควรหยุดการประมวลผล RewriteRule ทันทีและส่งคืนการเปลี่ยนเส้นทางภายนอกให้กับผู้ใช้ อย่างไรก็ตาม เราจะจำตัวอย่างที่ยอดเยี่ยมจากส่วน How RewriteRule Works กัน ในนั้นเราระบุธงก่อน [ร]ซึ่งบ่งบอกถึงความจำเป็นในการเปลี่ยนเส้นทางภายนอก หลังจากนั้นพวกเขาก็เปลี่ยนลิงก์ต่อไปด้วย RewriteRule ต่อไปนี้

นี่คือวิธีการทำงานของ Apache เมื่อระบุการเปลี่ยนเส้นทางภายนอก เพียง "บันทึก" กับตัวเองว่าหลังจากดำเนินการตามกฎทั้งหมดแล้ว จำเป็นต้องส่งคืนสถานะ 302 (โดยค่าเริ่มต้น) แต่ในขณะเดียวกันก็ดำเนินการ RewriteRules ทั้งหมดต่อไปในรายการต่อไป เราสามารถเปลี่ยนคำขอต่อไปได้ตามต้องการ สิ่งเดียวที่ใช้ไม่ได้คือการเปลี่ยนเส้นทางกลับเป็นการภายใน

อย่างไรก็ตาม ไม่น่าเป็นไปได้ที่คุณจะต้องการเปลี่ยนแปลงในทางใดทางหนึ่งหลังจากส่งการเปลี่ยนเส้นทางภายนอกแล้ว ดังนั้นจึงขอแนะนำเมื่อใช้แฟล็ก [ร]ระบุมันด้วย [ล]:

# BlackJack ได้ย้ายไปใช้ชื่อที่สวยงาม RewriteRule ^bj/(.*) blackjack/$1 # คุณสามารถใช้ลิงก์ภายนอก RewriteRule ^bj/(.*) http://blackjack.example.com/$1 [L]

แทนที่จะใช้ธง [ร]คุณสามารถระบุลิงก์ภายนอกได้ ในกรณีนี้ Apache เองจะเดาได้ว่าจำเป็นต้องทำการเปลี่ยนเส้นทางภายนอก ในที่นี้ เช่นเดียวกับในกรณีของการระบุธงอย่างชัดเจน [ร]ขอแนะนำให้ใช้แฟล็ก [ล]- หากการเปลี่ยนเส้นทางภายนอกนำไปสู่ไซต์เดียวกัน ควรใช้แฟล็กจะดีกว่า [ร]โดยไม่มีข้อบ่งชี้ ลิงค์เต็ม(หรืออีกนัยหนึ่ง ให้ใช้การเปลี่ยนเส้นทางภายนอกแบบสัมพันธ์) ซึ่งจะทำให้กฎเป็นอิสระจากชื่อไซต์ หากการเปลี่ยนเส้นทางภายนอกนำไปสู่ไซต์อื่น การดำเนินการนี้จะไม่สามารถทำได้นอกจากการระบุลิงก์ภายนอกแบบเต็ม

mod_rewrite ทำงานอย่างไร การระบุพารามิเตอร์คำขอและแฟล็ก

การเปลี่ยนพารามิเตอร์แบบสอบถามใน RewriteRule จะไม่เปลี่ยนแถวที่ RewriteRule ถัดไปทำงาน อย่างไรก็ตาม การเปลี่ยนพารามิเตอร์จะเปลี่ยนตัวแปร %(QUERY_STRING) ที่ RewriteCond สามารถทำงานได้

คำศัพท์ที่ใช้: "พารามิเตอร์" - พารามิเตอร์คำขอ "อาร์กิวเมนต์" - อาร์กิวเมนต์ RewriteRule

เมื่อใช้ RewriteRule คุณสามารถเปลี่ยนได้ไม่เพียงแต่เส้นทางไปยังไฟล์ที่จะประมวลผล แต่ยังรวมถึงพารามิเตอร์ด้วย รับคำขอซึ่งจะถูกส่งต่อไปยังเขา ซึ่งมักใช้ในการถ่ายโอนการประมวลผล NC ไปยังสคริปต์ตัวจัดการทั่วไป เช่น RewriteBase /

# คำขอ: http://example.com/news/2010/07/12/grand-opening.html # ข้อมูล: "news/2010/07/12/grand-opening.html" RewriteRule ^news/(.* ) $ index.php?act=news&what=$1 # หลังจากเขียนกฎใหม่: "news/2010/07/12/grand-opening.html" -> "index.php" # %(QUERY_STRING): "" -> "act= news&what =2010/07/12/grand-opening.html"

ทันทีที่ RewriteRule พบเครื่องหมายคำถามในอาร์กิวเมนต์ที่สอง ระบบจะรู้ว่าพารามิเตอร์ในคำขอกำลังได้รับการแก้ไข สิ่งที่เกิดขึ้นคือ RewriteRule แทนที่สตริงที่ทำงานกับส่วนหนึ่งของอาร์กิวเมนต์ที่สองก่อนหน้านี้ เครื่องหมายคำถาม- โปรดทราบว่าพารามิเตอร์คำขอใหม่ไม่ได้จบลงในสตริงที่ RewriteRules ที่ตามมาจะทำงาน ส่วนของอาร์กิวเมนต์ที่สองหลังจากเครื่องหมายคำถามจบลงในตัวแปร %(QUERY_STRING) หากมีการระบุธงไว้ พารามิเตอร์การค้นหาจะถูกเพิ่มที่จุดเริ่มต้นของ %(QUERY_STRING) หากไม่ได้ระบุแฟล็ก %(QUERY_STRING) จะถูกแทนที่ด้วยพารามิเตอร์คิวรีจาก RewriteRule โดยสมบูรณ์ ตัวอย่างเพิ่มเติมสองสามตัวอย่าง:

RewriteBase / # คำขอ: http://example.com/news/2010/?page=2 # ป้อน RewriteRule: "news/2010/" RewriteRule ^news/(.*)$ index.php?act=news&what=$1 # หลังการแปลง: "news/2010/" -> "index.php" # Value %(QUERY_STRING): "page=2" -> "act=news&what=2010/" เป็นไปได้มากว่ากฎข้างต้นทำงานไม่ถูกต้อง เนื่องจาก มันเป็นหน้าอาร์กิวเมนต์หายไป มาแก้ไขปัญหานี้กัน: RewriteBase / # Request: http://example.com/news/2010/?page=2 # Input RewriteRule: "news/2010/" RewriteRule ^news/(.*)$ index.php?act= news&what=$1 # หลังการแปลง: "news/2010/" -> "index.php" # Value %(QUERY_STRING): "page=2" -> "act=news&what=2010/&page=2"

สิ่งสำคัญคือต้องเข้าใจว่าการเปลี่ยนแปลงพารามิเตอร์การสืบค้นจะเปลี่ยน %(QUERY_STRING) ซึ่งสามารถใช้ได้ในภายหลังใน RewriteCond สิ่งนี้จะต้องนำมาพิจารณาเมื่อเขียนกฎต่อมาที่ตรวจสอบข้อโต้แย้ง

แน่นอนว่ามันเปลี่ยนไปเพราะ Apache ส่งคำขอไปประมวลผลใหม่!

ไม่ %(QUERY_STRING) เปลี่ยนแปลงทันที ฉันจะไม่ให้หลักฐาน - มีการเขียนเกี่ยวกับพารามิเตอร์มากกว่าความน่าสนใจในการอ่าน :)

คุณสามารถทำอะไรได้บ้างเพื่อตรวจสอบ RewriteCond ว่าพารามิเตอร์คำขอที่ผู้ใช้ส่งผ่าน ไม่ใช่พารามิเตอร์ที่แก้ไขโดย RewriteRules ดูเคล็ดลับท้ายบทความ

RewriteCond และประสิทธิภาพ

ขั้นแรก มีการตรวจสอบการจับคู่คำขอกับ RewriteRule จากนั้น - เงื่อนไขเพิ่มเติมเขียนใหม่Cond.

ควรพูดสองสามคำเกี่ยวกับลำดับที่ mod_rewrite ดำเนินการคำสั่ง เนื่องจาก .htaccess มาพร้อมกับ RewriteCond ก่อนแล้วจึง RewriteRule ดูเหมือนว่า mod_rewrite จะตรวจสอบเงื่อนไขทั้งหมดก่อน จากนั้นจึงเริ่มดำเนินการ RewriteRule

ในความเป็นจริงทุกอย่างเกิดขึ้นในทางกลับกัน ขั้นแรก mod_rewrite จะตรวจสอบว่าค่าคำขอปัจจุบันตรงกับนิพจน์ทั่วไป RewriteRule หรือไม่ จากนั้นจึงจะตรวจสอบเงื่อนไขทั้งหมดที่แสดงอยู่ใน RewriteCond

ดังนั้น หากคุณมีนิพจน์ทั่วไปสองหน้าใน RewriteRule ของคุณ และเมื่อพิจารณาถึงประสิทธิภาพแล้ว คุณตัดสินใจที่จะจำกัดการดำเนินการของกฎนี้ไว้ที่ RewriteConds เพิ่มเติม คุณควรรู้ว่าจะไม่มีอะไรทำงาน ในกรณีนี้ ควรใช้แฟล็ก RewriteRule [C] หรือ [S] เพื่อข้ามเพิ่มเติม กฎที่ซับซ้อนถ้ามีมากกว่านี้ ตรวจสอบง่ายๆไม่ได้ผล

ตัวแปรและแฟล็ก RewriteCond, แฟล็ก RewriteRule อื่นๆ เป็นต้น

อ่านเอกสาร

เราคุ้นเคยกับหลักการทำงานของ RewriteRule, RewriteBase, flags [ล], [ร]และ และยังวิเคราะห์กลไกการประมวลผลคำขอภายใน mod_rewrite สิ่งต่อไปนี้ยังคงไม่ได้รับผลกระทบ: แฟล็ก RewriteRule อื่นๆ, คำสั่ง RewriteCond และ RewriteMap

โชคดีที่คำสั่งและธงเหล่านี้ไม่ได้เต็มไปด้วยความลึกลับใดๆ และทำงานได้ตรงตามที่อธิบายไว้ในบทช่วยสอนส่วนใหญ่ เพื่อทำความเข้าใจพวกเขาเพียงแค่อ่าน เอกสารอย่างเป็นทางการ- ก่อนอื่น ฉันขอแนะนำให้ศึกษารายการตัวแปรที่สามารถตรวจสอบได้ใน RewriteCond - %(QUERY_STING), %(THE_REQUEST), %(REMOTE_ADDR), %(HTTP_HOST), %(HTTP:header) ฯลฯ)

ความแตกต่างในวิธีการทำงานของ mod_rewrite ในบริบท .htaccess และในบริบท VirtualHost

ในบริบท mod_rewrite ทำงานตรงกันข้ามทุกประการ

ดังที่ฉันได้กล่าวไว้ในตอนต้นของบทความ ทุกอย่างที่อธิบายไว้ข้างต้นเกี่ยวข้องกับการใช้ mod_rewrite ในบริบท .htaccess หากใช้ mod_rewrite ใน มันจะทำงานแตกต่างออกไป: ใน RewriteRule รวมถึงเส้นทางคำขอทั้งหมด เริ่มต้นจากเครื่องหมายทับแรกและลงท้ายด้วยจุดเริ่มต้น รับพารามิเตอร์: "http://example.com/some/news/category/post.html?comments_page=3" → "/news/category/post.html" บรรทัดนี้ขึ้นต้นด้วย / เสมอ อาร์กิวเมนต์ที่สองของ RewriteRule ต้องขึ้นต้นด้วย / มิฉะนั้นจะเป็น "คำขอไม่ถูกต้อง" RewriteBase ไม่สมเหตุสมผล การผ่านกฎจะเกิดขึ้นเพียงครั้งเดียว ธง [ล]เสร็จสิ้นการประมวลผลกฎทั้งหมดที่อธิบายไว้ในนั้นแล้ว โดยไม่ต้องทำซ้ำเพิ่มเติม

การเขียนนิพจน์ทั่วไป

พยายามเขียนนิพจน์ทั่วไปเพื่อให้กำหนดแบบสอบถามที่คุณต้องการแก้ไขได้แคบที่สุด เพื่อให้กฎ RewriteRule ไม่ทำงานโดยไม่ตั้งใจกับแบบสอบถามอื่น ตัวอย่างเช่น:

# เริ่มต้นนิพจน์ทั่วไปทั้งหมดด้วย "^" (จุดเริ่มต้นของบรรทัด) # และลงท้ายด้วย "$" (ท้ายบรรทัด): RewriteRule ^news.php$ index.php # แม้ว่าจะไม่จำเป็น - เพื่อความคล่องตัว และเข้าใจการกำหนดค่าได้ดีขึ้น: RewriteRule ^news/(.*)$ index.php # หากควรรวมเฉพาะตัวเลขไว้ในมาสก์ ให้ระบุให้ชัดเจน # ถ้าตัวเลขบางตัวเป็นค่าคงที่ให้ระบุให้ชัดเจน # หากเครื่องหมายทับไม่ปรากฏในส่วนที่เหลือของคำขอ ให้จำกัดการแสดงเครื่องหมายเหล่านั้น #อย่าลืมหนี"." (จุด). # กฎต่อไปนี้กำหนดเป้าหมายคำขอเช่น http://example.com/news/2009/07/28/b-effect.html RewriteRule ^news/20(2)/(2)/(2)/[^/]+ \.html index.php

อย่างไรก็ตามโอ้ การแสดงออกปกติมีทั้งส่วนในเว็บไซต์ที่มีชื่อเสียงแห่งเดียว

การเปลี่ยนเส้นทางภายนอก

แม้ว่า mod_rewrite จะอนุญาตให้คุณเปลี่ยนแม้แต่การเปลี่ยนเส้นทางภายนอกโดยใช้ RewriteRule ไปจนถึงโปรโตคอล แต่ฉันก็ไม่แนะนำให้ทำเช่นนี้อย่างยิ่ง ในบทความ ตัวอย่างของการเปลี่ยนแปลงการเปลี่ยนเส้นทางภายนอกใช้เพื่อกำจัดแนวคิดเช่น "ลิงก์" และ "ไฟล์" เท่านั้น และแสดงให้เห็นอย่างชัดเจนยิ่งขึ้นว่า RewriteRule ใช้งานได้กับสตริงแบบธรรมดา

ฉันไม่คิดว่านักพัฒนา mod_rewrite ตั้งใจที่จะให้ใครทำเช่นนี้ ดังนั้นสิ่งประดิษฐ์ทุกประเภทจึงเป็นไปได้ อย่าทำแบบนี้ได้โปรด

วิธีหยุดการวนซ้ำไม่สิ้นสุด

บางครั้งตรรกะของการเปลี่ยนเส้นทางบนไซต์ก็เป็นเช่นนั้น การกระทำพิเศษ mod_rewrite ถือว่าสิ่งเหล่านี้เป็นเหมือนการเปลี่ยนเส้นทางแบบวนซ้ำไม่รู้จบ ลองมาตัวอย่างต่อไปนี้

เว็บไซต์นี้มีหน้า /info.html ผู้เชี่ยวชาญด้าน SEO ตัดสินใจเช่นนั้น เครื่องมือค้นหาจะจัดทำดัชนีหน้านี้ให้ดีขึ้นหากเรียกว่า /information.html และขอให้เปลี่ยนเส้นทางภายนอกจาก info.html ไปยัง information.html อย่างไรก็ตาม ด้วยเหตุผลบางประการ นักพัฒนาเว็บไซต์ไม่สามารถเปลี่ยนชื่อ info.html เป็น information.html และทำการเปลี่ยนเส้นทางได้ - เขาต้องการให้ส่งข้อมูลโดยตรงจากไฟล์ info.html เขาเขียนกฎต่อไปนี้: # สร้างการเปลี่ยนเส้นทางภายนอก RewriteRule ^info.html information.html # แต่เมื่อมีการร้องขอ /information.html ยังคงให้ info.html RewriteRule ^information.html info.html

...และกำลังเผชิญกับ. วนซ้ำไม่รู้จบ- ทุกคำขอ /information.html ได้รับการเปลี่ยนเส้นทางภายนอกอีกครั้งไปยัง /information.html

ปัญหานี้สามารถแก้ไขได้อย่างน้อยสองวิธี หนึ่งในนั้นได้รับการอธิบายไว้ในHabréแล้ว - คุณต้องติดตั้ง ตัวแปรสภาพแวดล้อมและขึ้นอยู่กับค่าของมัน หยุดการเปลี่ยนเส้นทาง รหัสจะมีลักษณะดังนี้:

RewriteCond %(ENV:REDIRECT_FINISH) !^$ RewriteRule ^ - [L] RewriteRule ^info.html$ information.html RewriteRule ^information.html$ info.html

โปรดทราบว่า mod_rewrite จะเติม "REDIRECT_" ต่อท้ายชื่อตัวแปร

วิธีที่สองคือตรวจสอบ THE_REQUEST ว่าผู้ใช้ร้องขออะไรกันแน่:

# การเปลี่ยนเส้นทางภายนอกจะเกิดขึ้นเฉพาะในกรณีที่ผู้ใช้ร้องขอ info.html # หาก info.html เป็นผลมาจากการเปลี่ยนเส้นทางภายใน กฎจะไม่เริ่มทำงาน RewriteCond %(THE_REQUEST) "^(GET|POST|HEAD) /info.html HTTP/+$" RewriteRule ^info.html$ information.html RewriteRule ^information.html$ info.html

กำลังวิเคราะห์คำขอของผู้ใช้เดิม - ต่อสู้กับการเปิดเผยลิงก์ Apache

เมื่อประมวลผลคำขอ Apache จะขยายอักขระที่เข้ารหัส URL จากคำขอดั้งเดิม ในบางกรณี สิ่งนี้อาจไม่เป็นที่ต้องการ - นักพัฒนาต้องการตรวจสอบคำขอเดิมของผู้ใช้ที่ยังไม่ได้แก้ไขอย่างแน่ชัด ซึ่งสามารถทำได้โดยการตรวจสอบตัวแปร %(THE_REQUEST) ใน RewriteCond:

RewriteCond %(THE_REQUEST) ^GET[\ ]+/tag/([^/]+)/[\ ]+HTTP.*$ RewriteRule ^(.*)$ index.php?tag=%1 [L]

เมื่อสร้างแอปพลิเคชันคอนโซลในภาษาการเขียนโปรแกรม C++ บรรทัดที่คล้ายกันนี้จะถูกสร้างขึ้นโดยอัตโนมัติ:

Int main(int argc, char* argv) // main() พารามิเตอร์ของฟังก์ชัน

บรรทัดนี้เป็นส่วนหัว ฟังก์ชั่นหลัก main() พารามิเตอร์ argс และ argv ถูกประกาศไว้ในวงเล็บ ดังนั้นหากเปิดโปรแกรมผ่านทาง บรรทัดคำสั่งดังนั้นจึงเป็นไปได้ที่จะถ่ายโอนข้อมูลบางอย่างไปยังโปรแกรมนี้ นี่คือสาเหตุว่าทำไมจึงมีพารามิเตอร์ argc และ argv พารามิเตอร์อาร์จีซีมีประเภท ข้อมูลภายในและมีจำนวนพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชันหลัก ยิ่งไปกว่านั้น argc มีค่าอย่างน้อย 1 เสมอ แม้ว่าเราจะไม่ส่งข้อมูลใดๆ เนื่องจากพารามิเตอร์แรกคือชื่อของฟังก์ชัน พารามิเตอร์ argv คืออาร์เรย์ของตัวชี้ไปยังสตริง เฉพาะข้อมูลเท่านั้นที่สามารถถ่ายโอนผ่านทางบรรทัดคำสั่ง ประเภทสตริง- พอยน์เตอร์และสตริงเป็นหัวข้อใหญ่สองหัวข้อที่มีการสร้างส่วนแยกกัน ดังนั้นจึงเป็นการส่งข้อมูลใด ๆ ผ่านทางพารามิเตอร์ argv มาพัฒนาโปรแกรมที่เราจะเปิดผ่านบรรทัดคำสั่งกันดีกว่า สตริงของ Windowsและให้ข้อมูลบางอย่างแก่เธอ

// argc_argv.cpp: กำหนดจุดเริ่มต้นสำหรับแอปพลิเคชันคอนโซล #รวม "stdafx.h" #รวม ใช้เนมสเปซมาตรฐาน; int main(int argc, char* argv) ( ถ้า (argc ><< argv<

// รหัส รหัส::บล็อก

// รหัส Dev-C++

// argc_argv.cpp: กำหนดจุดเริ่มต้นสำหรับแอปพลิเคชันคอนโซล #รวม ใช้เนมสเปซมาตรฐาน; int main(int argc, char* argv) ( if (argc > 1) // ถ้าเราผ่านอาร์กิวเมนต์ argc จะมากกว่า 1 (ขึ้นอยู่กับจำนวนอาร์กิวเมนต์) ( cout<< argv<

หลังจากที่เราดีบั๊กโปรแกรมแล้ว ให้เปิดบรรทัดคำสั่งของ Windows แล้วลากไฟล์ปฏิบัติการของโปรแกรมของเราไปที่หน้าต่างบรรทัดคำสั่ง เส้นทางแบบเต็มไปยังโปรแกรมจะแสดงในบรรทัดคำสั่ง (แต่คุณสามารถป้อนเส้นทางไปยังโปรแกรมด้วยตนเองได้ ) หลังจากนั้นคุณสามารถคลิกได้ เข้าและโปรแกรมจะเริ่มทำงาน (ดูรูปที่ 1)

รูปที่ 1 - พารามิเตอร์ฟังก์ชันหลัก

เนื่องจากเราเพียงแค่รันโปรแกรมและไม่ส่งผ่านข้อโต้แย้งใดๆ ข้อความ "ไม่ใช่ข้อโต้แย้ง" จึงปรากฏขึ้น รูปที่ 2 แสดงการเปิดตัวโปรแกรมเดียวกันผ่านทางบรรทัดคำสั่ง แต่ส่งผ่านอาร์กิวเมนต์ Open

รูปที่ 2 - พารามิเตอร์ฟังก์ชันหลัก

อาร์กิวเมนต์คือคำว่า เปิด ดังที่เห็นจากรูปคำนี้ปรากฏบนหน้าจอ คุณสามารถส่งพารามิเตอร์ได้หลายตัวพร้อมกัน โดยคั่นด้วยเครื่องหมายจุลภาค หากคุณต้องการส่งพารามิเตอร์ที่ประกอบด้วยคำหลายคำ จะต้องใส่เครื่องหมายคำพูดคู่ จากนั้นคำเหล่านี้จะถือเป็นพารามิเตอร์เดียว ตัวอย่างเช่น รูปภาพแสดงการเปิดตัวโปรแกรม โดยส่งผ่านอาร์กิวเมนต์ที่ประกอบด้วยคำสองคำ - มันใช้งานได้

รูปที่ 3 - พารามิเตอร์ฟังก์ชันหลัก

และถ้าคุณลบเครื่องหมายคำพูดออก แล้วเราจะเห็นแต่คำว่ามัน หากคุณไม่ได้วางแผนที่จะส่งข้อมูลใดๆ เมื่อรันโปรแกรม คุณสามารถลบอาร์กิวเมนต์ในฟังก์ชัน main() ได้ และคุณยังสามารถเปลี่ยนชื่อของอาร์กิวเมนต์เหล่านี้ได้ด้วย บางครั้งอาจพบการแก้ไขพารามิเตอร์ argc และ argv แต่ทั้งหมดนี้ขึ้นอยู่กับประเภทของแอปพลิเคชันที่ถูกสร้างขึ้นหรือสภาพแวดล้อมการพัฒนา