Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> PHP

บังคับดาวน์โหลดไฟล์ใน PHP (Force File Download)

ใช้ 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): ใช้ fread loop แทน readfile บนระบบ 32-bit

Secure Download Pattern (แนะนำสำหรับ Production)