ใช้ Header HTTP เพื่อบังคับให้ Browser ดาวน์โหลดไฟล์แทนที่จะเปิดใน Browser (เช่น PDF, Image, Text)
ฟังก์ชัน Force Download มาตรฐาน
/**
* บังคับดาวน์โหลดไฟล์
*
* @param string $filePath Full path ไปยังไฟล์บน Server
* @param string $fileName ชื่อไฟล์ที่จะให้ User ดาวน์โหลด (ถ้าไม่ระบุ ใช้ชื่อเดิม)
* @param string $mimeType MIME Type (ถ้าไม่ระบุ จะ detect อัตโนมัติ)
*/
function forceDownload($filePath, $fileName = null, $mimeType = null) {
// 1. ตรวจสอบไฟล์
if (!file_exists($filePath) || !is_readable($filePath)) {
http_response_code(404);
die("File not found or not readable");
}
// 2. กำหนดชื่อไฟล์
$fileName = $fileName ?? basename($filePath);
// 3. กำหนด MIME Type
if (!$mimeType) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo);
}
// 4. ส่ง Headers (ต้องส่งก่อน Output ใดๆ)
header('Content-Type: ' . $mimeType);
header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"');
header('Content-Length: ' . filesize($filePath));
header('Cache-Control: private, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// 5. ส่งเนื้อหาไฟล์
readfile($filePath);
exit;
}
// === การใช้งาน ===
// forceDownload('/var/www/files/report.pdf', 'monthly-report.pdf');
// forceDownload('/var/www/files/image.png');
ตัวอย่าง: ดาวน์โหลด CSV
วิธี .htaccess (บังคับดาวน์โหลดทุกไฟล์ในโฟลเดอร์)
# .htaccess ในโฟลเดอร์ที่ต้องการบังคับดาวน์โหลด
# ทุกไฟล์จะถูกดาวน์โหลดแทนที่จะเปิดใน Browser
ForceType application/octet-stream
Header set Content-Disposition "attachment"
# หรือเฉพาะนามสกุลบางอย่าง
ForceType application/octet-stream
Header set Content-Disposition "attachment"
⚠️ ข้อควรระวังสำคัญ
- Header ต้องส่งก่อน Output ใดๆ (รวมถึง Whitespace, BOM, Echo) -> ใช้
ob_start()ตอนต้น Script หรือตรวจสอบว่าไม่มี Output ก่อน - Path Traversal: ตรวจสอบ
$filePathอย่างเคร่งครัด ห้ามรับ Path จาก User โดยตรง - Memory:
readfile()สตรีมไฟล์ทีละชิ้น ไม่โหลดทั้งไฟล์เข้ RAM เหมาะกับไฟล์ใหญ่ - Large Files (>2GB): ใช้
freadloop แทน readfile บนระบบ 32-bit
Secure Download Pattern (แนะนำสำหรับ Production)