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

อัปโหลดหลายไฟล์พร้อมกันและบันทึกลงโฟลเดอร์ใน PHP

คู่มือฉบับสมบูรณ์สำหรับการอัปโหลดหลายไฟล์ (Multiple File Upload) ใน PHP พร้อม Validation, Security และ Error Handling

HTML Form (สำคัญ: name ต้องเป็น Array และมี multiple attribute)

<form action="upload.php" method="POST" enctype="multipart/form-data">
    <input type="file" name="upload[]" id="upload" multiple accept="image/*,.pdf">
    <button type="submit">อัปโหลด</button>
</form>

จุดสำคัญ:

  • name="upload[]" - ต้องมี [] เพื่อรับเป็น Array
  • multiple - อนุญาตเลือกหลายไฟล์
  • enctype="multipart/form-data" - จำเป็นสำหรับ File Upload
  • accept - จำกัดประเภทไฟล์ฝั่ง Client (แต่ต้อง Validate ฝั่ง Server อีกครั้ง)

PHP: การจัดการอัปโหลดแบบสมบูรณ์

 $maxSize) {
        $errors[] = "File size exceeds " . ($maxSize / 1024 / 1024) . " MB";
    }
    
    // ตรวจสอบ MIME Type จริง (ไม่ไว้ใจ $_FILES['type'])
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    
    if (!in_array($mimeType, $allowedTypes)) {
        $errors[] = "File type not allowed: $mimeType";
    }
    
    // ตรวจสอบว่าเป็นรูปภาพจริง (สำหรับ Image)
    if (str_starts_with($mimeType, 'image/')) {
        $imgInfo = getimagesize($file['tmp_name']);
        if (!$imgInfo) {
            $errors[] = "Invalid image file";
        }
    }
    
    return $errors;
}

// === Main Upload Logic ===
$results = ['success' => [], 'errors' => []];

if (!empty($_FILES['upload']['name'][0])) {
    $fileCount = count($_FILES['upload']['name']);
    
    // จำกัดจำนวนไฟล์
    if ($fileCount > $maxFiles) {
        $results['errors'][] = "Too many files. Maximum $maxFiles files allowed.";
    } else {
        for ($i = 0; $i < $fileCount; $i++) {
            // ข้ามไฟล์ว่าง (user เลือกไฟล์แล้วลบออก)
            if (empty($_FILES['upload']['name'][$i]) || $_FILES['upload']['error'][$i] === UPLOAD_ERR_NO_FILE) {
                continue;
            }
            
            $file = [
                'name'     => $_FILES['upload']['name'][$i],
                'type'     => $_FILES['upload']['type'][$i],
                'tmp_name' => $_FILES['upload']['tmp_name'][$i],
                'error'    => $_FILES['upload']['error'][$i],
                'size'     => $_FILES['upload']['size'][$i],
            ];
            
            $errors = validateFile($file, $allowedTypes, $maxFileSize);
            
            if (empty($errors)) {
                $newName = generateSafeFilename($file['name']);
                $destPath = $uploadDir . $newName;
                
                if (move_uploaded_file($file['tmp_name'], $destPath)) {
                    $results['success'][] = [
                        'original_name' => $file['name'],
                        'saved_name'    => $newName,
                        'size'          => $file['size'],
                        'path'          => $destPath
                    ];
                } else {
                    $results['errors'][] = "Failed to move: {$file['name']}";
                }
            } else {
                $results['errors'][] = "{$file['name']}: " . implode(', ', $errors);
            }
        }
    }
}

// === Response ===
header('Content-Type: application/json');
echo json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>

JavaScript (AJAX) สำหรับ UX ที่ดีกว่า

// ใช้ FormData สำหรับ AJAX File Upload
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    
    const formData = new FormData(e.target);
    const response = await fetch('upload.php', {
        method: 'POST',
        body: formData
    });
    
    const result = await response.json();
    
    if (result.success.length) {
        console.log('Uploaded:', result.success);
        // แสดง Preview, Progress, etc.
    }
    if (result.errors.length) {
        console.error('Errors:', result.errors);
    }
});

Security Checklist

  • ✅ Validate MIME Type ด้วย finfo (ไม่ไว้ใจ $_FILES['type'])
  • ✅ ตรวจสอบขนาดไฟล์
  • ✅ เปลี่ยนชื่อไฟล์ (ป้องกัน Overwrite, Path Traversal)
  • ✅ จำกัดประเภทและขนาดไฟล์
  • ✅ เก็บไฟล์นอก Document Root (ถ้าเป็นไปได้)
  • ✅ ตั้ง Permission โฟลเดอร์ 0755, ไฟล์ 0644
  • ✅ Scan ไวรัส (ClamAV) สำหรับ Production จริง