ขึ้นหัวข้อมาน่ากลัวเลย แต่จริง ๆ แล้วคำว่า ขังเดี่ยว PHP มันไม่เกินจริงเลย เพราะการ set open_basedir ไว้เป็นวิธีแยก site ของ PHP ให้แยกออกจากเว็บอื่น ๆ ที่อยู่บน server เดียวกัน เพื่อความปลอดภัย (Security) สำหรับเซิร์ฟเวอร์ที่รันหลายเว็บไซต์ (Multi-site) เพราะหน้าที่ของมันคือการ จำกัดขอบเขต ให้ PHP ของเว็บไซต์หนึ่ง ไม่สามารถเข้าไปอ่านหรือแก้ไขไฟล์ของอีกเว็บไซต์หนึ่งได้
ทำไมต้องใช้ open_basedir ในระบบ Multi-site
ถ้าคุณไม่ตั้งค่านี้ และมีเว็บไซต์หนึ่งในเซิร์ฟเวอร์ถูกแฮก (เช่น โดนฝัง Shell script) แฮกเกอร์จะสามารถใช้คำสั่ง PHP สแกนหาไฟล์ wp-config.php หรือไฟล์รหัสผ่านของเว็บไซต์อื่นๆ ในพาธเดียวกันได้ทันที
ตัวอย่างโครงสร้างไฟล์:
- Site A: /var/www/site_a/public_html
- Site B: /var/www/site_b/public_html
การตั้ง open_basedir จะทำให้ Site A มองเห็นแค่ไฟล์ในโฟลเดอร์ของตัวเองเท่านั้น ไม่สามารถแก้ไขหรือแม้แต่อ่านไฟล์นอกจากที่ใส่ไว้ใน open_basedir ได้
วิธีการตั้งค่า
- การตั้งค่า
open_basedir สำหรับหลายเว็บไซต์ ไม่ควร ทำในไฟล์ php.ini หลัก (Global) เพราะจะทำให้ทุกเว็บติดเงื่อนไขเดียวกันหมด เราควรแยกตั้งค่าตามราย Site ดังนี้ครับ การขังเดี่ยวของเราจะไม่ได้ผล เท่าที่ควร เหมือนเอาคนป่วยมาอยู่ในห้องเดียวกันกับคนอื่นในแผนก ไม่นานก็จะกลายเป็นป่วยเหมือนกันยกตี้
- กรณีใช้ Apache (.htaccess หรือ VirtualHost)
คุณสามารถกำหนดผ่านไฟล์ .htaccess (ถ้า Server ยอมให้ Override) หรือในไฟล์ VirtualHost:
<VirtualHost *:80>
…
ServerName site_a.com
php_admin_value open_basedir “/var/www/site_a:/tmp“
…
</VirtualHost>
- กรณีใช้ Nginx กับ PHP-FPM (แนะนำมันดีกว่า Apache จริง ๆ)
วิธีที่ง่ายที่สุดคือการตั้งค่าใน Config ของแต่ละเว็บไซต์
; ในไฟล์คอนฟิกของ Site A
php_admin_value[open_basedir] = "/var/www/site_a:/tmp"
; ในไฟล์คอนฟิกของ Site B
php_admin_value[open_basedir] = "/var/www/site_b:/tmp"
Tip: ควรใส่ /tmp ไว้ด้วยเพื่อให้ PHP ยังสามารถเขียนไฟล์ชั่วคราว (เช่น การ Upload รูป) ได้ปกติ
ข้อควรระวังและ Best Practices
| ข้อควรระวัง | รายละเอียด |
|---|
| Path Separator | ใน Linux ใช้เครื่องหมาย : เพื่อแยกหลาย Path (เช่น /home/user:/tmp) |
| Symlinks | ถ้าคุณมีการใช้ Symbolic Link ข้ามโฟลเดอร์ open_basedir อาจจะบล็อกการทำงานได้ ต้องระบุ Path จริงลงไปด้วย |
| PHP Functions | ฟังก์ชันอย่าง include, file_get_contents, fopen จะถูกจำกัดทั้งหมดภายใต้กฎนี้ |
| Session & Uploads | อย่าลืมเช็คว่า session.save_path และ upload_tmp_dir อยู่ในขอบเขตที่อนุญาตหรือไม่ |
วิธีการทดสอบว่าใช้งานได้จริงหรือไม่
สร้างไฟล์ test.php ใน Site A แล้วลองสั่งให้อ่านไฟล์ของ Site B
<?php
// ลองอ่านไฟล์ข้าม Site
echo file_get_contents('/var/www/site_b/public_html/index.php');
?>
ถ้าตั้งค่าสำเร็จ: จะเกิด Error ว่า “open_basedir restriction in effect”
ถ้าอ่านได้: แสดงว่าการตั้งค่าของคุณยังผิดอยู่ อาจจะลอง restart server ดูก่อน
ตัวอย่าง phpMyAdmin
fastcgi_param PHP_VALUE "open_basedir=/var/www/phpmyadmin/:/tmp/:/var/lib/php/sessions/";
ส่วนที่ php ใน site นี้ทำงานได้
- /tmp/
- /var/lib/php/sessions/
- /var/www/phpmyadmin/
ตัวอย่าง WordPress
fastcgi_param PHP_VALUE "open_basedir=/tmp/:/var/www/plusmagi.com/pitt/";
ส่วนที่ php ใน site นี้ทำงานได้
- /tmp/
- /var/www/plusmagi.com/pitt/