Sunday 15 July 2012

URL Rewriting using mod_rewrite



การนำ mod_rewrite มาช่วยในการแปลง URL นอกจากจะทำให้ได้ URL ที่ดูสวยงามแล้ว ยังช่วยให้ Application ของเราปลอดภัยจากการที่ URL โดนเปลี่ยนแปลง และยังช่วยในเรื่องของ SEO ได้ด้วย mod_rewrite จะทำหน้าที่แปลง URL ที่ User Request ให้เห็น URL ตามที่เรากำหนด มักจะใช้ในการแปลง URL ในรูปแบบที่่ซับซ้อนให้มีรูปแบบที่ง่ายขึ้น ยกตัวอย่างเช่น สมมุติว่า URL จริงเป็นดังต่อไปนี้

http://www.mysite.com/complicated/and/way/too/long/url/here

เราสามารถเปลี่ยนให้เป็นรูปแบบที่ง่ายขึ้น ดังนี้

http://www.mysite.com/shortcut

ซึ่งใน htppd.conf (หรือใน .htaccess) เราจะ config mod_rewrite ดังต่อไปนี้

<IfModule mod_rewrite.c>
RewriteEngine on    
RewriteRule ^/shortcut$ /complicated/and/way/too/long/url/here    
</IfModule>

สำหรับวิธีการกำหนด RewriteRule จะเป็นไปตาม Syntax ดังต่อไปนี้

RewriteRule Pattern Substitution [Flag(s)]

ในส่วนของ Pattern นั้น เราจะใช้ในการกำหนดรูปแบบของ URL ที่เราต้องการเปลี่ยนแปลง โดยใช้ Regular Expression ในส่วนของ Substitution เราจะใช้ในการแทนค่า URL (ซึ่งเมื่อผ่านการแทนค่าเรียบร้อยแล้ว ก็จะคือ URL จริงที่ Apache จะนำไปใช้นั่นเอง) ส่วน Flags มีไว้สำหรับกำหนด Options พิเศษอื่นๆ เดี๋ยวเราจะลองมาดูตัวอย่างที่ซับซ้อนขึ้นมาอีกหน่อย

RewriteRule /products/([0-9]+) /siteengine/products.php?id=$1

ให้สังเกตุว่า ในส่วนของ Substitution เรามีการใช้งาน $1 ซึ่งมีความหมายว่า ให้แทนที่โดยใช้ค่าจาก Sub Pattern ชุดที่ 1 (Pattern ที่อยู่ในวงเล็บ เราจะเรียกว่า Sub Pattern) ในกรณีที่มี Sub Pattern มากกว่า 1 ชุด การแทนที่ เราจะใช้ $1 ,$2, $3 ไปเรื่อยๆ ตามลำดับ จาก Rule ในตัวอย่างข้างต้น จะทำให้ URL สามารถเรียกใช้งาน URL ในรูปแบบดังต่อไปนี้

http://www.mysite.com/products/26

ซึ่งเมื่อผ่าน Rewrite Engine ก็จะถูก rewrite ให้เป็น URL ดังต่อไปนี้

http://www.mysite.com/siteengine/products.php?id=26

สำหรับ URL ที่ไม่ตรงตาม Pattern ที่กำหนดไว้ใน RewriteRule จะไม่สามารถเรียกใช้งาน Script ของเราได้ ซึ่ง Apache จะส่งค่า HTTP Status กลับคืนเป็น 404 Not Found แทน ซึ่งจะทำให้เรามั่นใจได้ว่า URL ที่ Request มาถึง Script ของเราได้ จะต้องเป็น URL ที่ถูกต้องตามรูปแบบที่เรากำหนดไว้เท่านั้น

เราสามารถกำหนด RewriteRule ได้มากกว่า 1 Rule ดังต่อไปนี้

 RewriteRule ^/products$ /content.php    
 RewriteRule ^/products/([0-9]+)$ /content.php?id=$1 

ซึ่งในกรณีที่มี RewriteRule มากกว่าหนึ่ง RewriteEngine จะทำการตรวจสอบ Pattern ในแบบ Top Down (บนลงล่าง) และในกรณีที่เจอ Pattern ที่ตรงกับ URL ที่ Request ก็จะหยุดทันที ดังนั้นเราควรกำหนด URL ที่เป็น Generic (บางครั้งเรียกว่า Catch All URL) เอาไว้สุดท้าย

สำหรับ Parameter ตัวสุดท้ายที่ชื่อว่า Flag มีไว้สำหรับส่ง Response Header ในกรณีที่ URL ที่ Request ตรงกับ Pattern ที่กำหนด อย่างเช่น

'forbidden' หรือ 'f' เอาไว้สำหรับส่ง 403 Forbidden
'gone' หรือ 'g' เอาไว้สำหรับส่ง 410 Gone

นอกจากนั้น เรายังใช้ Flag ในการสั่ง Redirection และกำหนด MIME-Type ได้อีกด้วย สำหรับการใช้ Flag ในการกำหนด Option กรณีอื่นๆ อย่างเช่น

'nocase' หรือ 'NC' ใช้สำหรับกำหนดให้ Pattern เป็นแบบ Case Insensitive

สำหรับส่วนต่อไป เราจะมาดูวิธีการใช้งาน Rewrite Condition กันนะครับ สำหรับ Syntax การใช้งาน Rewrite Condition จะเป็นดังต่อไปนี้

RewriteCond Something_to_test Condition


ก่อนอื่นต้องเข้าใจกระบวนการทำงานของ Rewrite Engine กันก่อน ดังนี้ mod_rewrite จะเริ่มจากการตรวจสอบ URL ก่อน ว่าตรงกับ Pattern ที่กำหนดไว้ใน RewriteRule หรือเปล่า ซึ่งถ้าหากตรง ก็จะตรวจสอบต่อไปว่า มี RewriteCondition กำหนดไว้สำหรับ Rule ดังกล่าวหรือเปล่า ซึ่งถ้ามีก็จะทำการทดสอบ Condition ตามเงื่อนไขที่กำหนด ซึ่งถ้าทดสอบเงื่อนไขแล้วคืนค่ากลับมาเป็น True ก็จะทำกระบวนการ Substitution ตามที่กำหนดไว้ใน RewriteRule สำหรับในกรณีที่ทดสอบเงื่อนไขแล้วคืนค่ากลับมาเป็น False ก็จะทำการทดสอบเงื่อนไขต่อไป (ถ้ามี)

ด้วยความสามารถในการทดสอบ Condition ดังกล่าว ทำให้เราสามารถ Customize URL Rewriting ตามตัวแปร HTTP Variable ใดๆก็ตามที่เราได้รับจาก Apache สำหรับตัวอย่างของ HTTP Variable ที่สามารถใช้งานได้ มีดังต่อไปนี้ (นำมาแสดงเป็นตัวอย่างเพียงแค่บางส่วน)

HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_HOST, HTTP_ACCEPT, REMOTE_ADDR, REMOTE_HOST, REQUEST_METHOD, SERVER_NAME, SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL ...

ต่อไปลองมาดูตัวอย่างการใช้งาน RewriteCondition คู่กับ RewriteRule ดังต่อไปนี้ครับ

 RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*      
 RewriteRule ^/$ /homepage.max.html [L]      
 RewriteCond %{HTTP_USER_AGENT} ^Lynx.*      
 RewriteRule ^/$ /homepage.min.html [L]      
 RewriteRule ^/$ /homepage.std.html [L] 

เมื่อ User ทำการ Request มาที่ http://www.mysite.com/ จะเกิดการทำงานดังต่อไปนี้

User ที่ใช้ Mozilla Browser จะถูกพาไปที่ homepage.max.html
User ที่ใช้ Lynx (Text Based Browser) จะถูกพาไปที่ homepage.min.html
User ที่ใช้ Browser อื่นๆ จะถูกพาไปที่ homepage.std.html

เราสามารถนำ mod_rewrite มาประยุกต์ใช้ในการป้องกันการเรียกใช้งาน image จาก Web ภายนอก ได้ โดยกำหนด config ดังนี้

RewriteCond %{HTTP_REFERER} !^$     
RewriteCond %{HTTP_REFERER} !^http://localhost/.*$ [OR,NC]     
RewriteCond %{HTTP_REFERER} !^http://mysite.com/.*$ [OR,NC]     
RewriteCond %{HTTP_REFERER} !^http://www.mysite.com/.*$ [OR,NC]     
RewriteRule .*\.(gif|GIF|jpg|JPG)$ http://mysite/images/bad.gif [L,R]  


สำหรับผู้ที่สนใจ สามารถศึกษาเพิ่มเติมจาก Official Document ของ Apache ได้ที่นี่ครับ http://httpd.apache.org/docs/current/mod/mod_rewrite.html ส่วน Guide Line ในการใช้งานในรูปแบบต่างๆ สามารถดูได้ที่นี่ครับ http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

แหล่งที่มา:
  1. http://www.sitepoint.com/guide-url-rewriting/ 
  2. http://httpd.apache.org/docs/current/mod/mod_rewrite.html

No comments:

Post a Comment