Kotchasan PHP Framework

การจัดการ File Upload ด้วย PHP

บทความนี้จะอธิบายวิธีการสร้างระบบจัดการการอัพโหลดไฟล์ด้วย PHP โดยเน้นเรื่องความปลอดภัยและการตรวจสอบข้อมูล

การตั้งค่าเบื้องต้น

ในส่วนแรกของไฟล์ upload.php เราจะกำหนดค่าพื้นฐานที่จำเป็น

define('UPLOAD_DIR', 'uploads/');
define('MAX_FILE_SIZE', 10 * 1024 * 1024); // 10MB
define('ALLOWED_TYPES', [
    'image/jpeg',
    'image/png',
    'image/gif',
    'application/pdf',
    'application/msword'
]);

ค่าเหล่านี้ใช้ควบคุม:

  • โฟลเดอร์ที่จะเก็บไฟล์
  • ขนาดไฟล์สูงสุดที่อนุญาต
  • ประเภทไฟล์ที่อนุญาตให้อัพโหลด

การส่ง Response

เราสร้างฟังก์ชัน sendResponse() สำหรับส่งข้อมูลกลับไปยัง client ในรูปแบบ JSON

function sendResponse($status, $message, $data = []) {
    header('Content-Type: application/json');
    http_response_code($status);
    echo json_encode([
        'status' => $status,
        'message' => $message,
        'data' => $data
    ]);
    exit;
}

ฟังก์ชันนี้จะ

  1. กำหนด header เป็น JSON
  2. กำหนด HTTP status code
  3. ส่งข้อมูลกลับในรูปแบบ JSON
  4. จบการทำงานของสคริปต์

การตรวจสอบไฟล์

ฟังก์ชัน validateFile() ทำหน้าที่ตรวจสอบไฟล์ที่อัพโหลด

function validateFile($file) {
    // ตรวจสอบ upload errors
    if ($file['error'] !== UPLOAD_ERROR_OK) {
        return 'Upload error occurred';
    }

    // ตรวจสอบขนาดไฟล์
    if ($file['size'] > MAX_FILE_SIZE) {
        return 'File size exceeds limit';
    }

    // ตรวจสอบประเภทไฟล์
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);

    if (!in_array($mimeType, ALLOWED_TYPES)) {
        return 'File type not allowed';
    }

    return true;
}

การตรวจสอบประกอบด้วย

  1. ตรวจสอบว่าการอัพโหลดสำเร็จ
  2. ตรวจสอบขนาดไฟล์
  3. ตรวจสอบประเภทไฟล์โดยใช้ MIME type

ขั้นตอนการทำงานหลัก

  1. ตรวจสอบ HTTP Method
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        sendResponse(405, 'Method not allowed');
    }
  2. รับและตรวจสอบข้อมูล Form
    $title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_STRING);
    $description = filter_input(INPUT_POST, 'description', FILTER_SANITIZE_STRING);
    $category = filter_input(INPUT_POST, 'category', FILTER_SANITIZE_STRING);
  3. สร้างโฟลเดอร์สำหรับเก็บไฟล์
    if (!file_exists(UPLOAD_DIR)) {
        mkdir(UPLOAD_DIR, 0777, true);
    }
  4. ตรวจสอบและย้ายไฟล์
    $fileExtension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
    $fileName = uniqid() . '_' . time() . '.' . $fileExtension;
    $uploadPath = UPLOAD_DIR . $fileName;

    move_uploaded_file($_FILES['file']['tmp_name'], $uploadPath);

การจัดการฐานข้อมูล

ในตัวอย่างมีโครงสร้างสำหรับบันทึกข้อมูลลงฐานข้อมูล

try {
    $pdo = new PDO("mysql:host=localhost;dbname=your_database", "username", "password");
    $stmt = $pdo->prepare("INSERT INTO uploads (filename, title, description, category) VALUES (?, ?, ?, ?)");
    $stmt->execute([$fileName, $title, $description, $category]);
} catch (Exception $e) {
    if (file_exists($uploadPath)) {
        unlink($uploadPath);
    }
    sendResponse(500, 'Database error: ' . $e->getMessage());
}

ความปลอดภัย

ระบบมีการป้องกันความปลอดภัยหลายระดับ

  1. ตรวจสอบ MIME type ของไฟล์
  2. จำกัดขนาดไฟล์
  3. สร้างชื่อไฟล์ใหม่เพื่อป้องกันการ overwrite
  4. Sanitize ข้อมูลที่รับมาจาก form
  5. ใช้ PDO สำหรับการเชื่อมต่อฐานข้อมูล

การนำไปใช้งาน

ในการนำไปใช้งานจริง ควรพิจารณา

  1. ปรับแต่งค่า configuration ให้เหมาะกับความต้องการ
  2. เพิ่มการตรวจสอบสิทธิ์ผู้ใช้
  3. ปรับแต่งโครงสร้างฐานข้อมูล
  4. เพิ่มการจัดการ error cases เพิ่มเติม
  5. เพิ่มการ log การทำงาน

ระบบนี้สามารถนำไปต่อยอดเพิ่มเติมได้ เช่น

  • เพิ่มการประมวลผลรูปภาพ
  • เพิ่มระบบ versioning
  • เพิ่มการแชร์ไฟล์
  • เพิ่มการสแกนไวรัส

<?php
/**
 * File Upload Handler
 * Process file uploads with validation and error handling
 */


// Set error reporting
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Configuration
define('UPLOAD_DIR', 'uploads/');
define('MAX_FILE_SIZE', 10 * 1024 * 1024); // 10MB
define('ALLOWED_TYPES', [
    'image/jpeg',
    'image/png',
    'image/gif',
    'application/pdf',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
]);

/**
 * Response helper function
 * @param int $status HTTP status code
 * @param string $message Response message
 * @param array $data Additional data
 */

function sendResponse($status, $message, $data = []) {
    header('Content-Type: application/json');
    http_response_code($status);
    echo json_encode([
        'status' => $status,
        'message' => $message,
        'data' => $data
    ]);
    exit;
}

/**
 * Validate uploaded file
 * @param array $file $_FILES array element
 * @return bool|string True if valid, error message if invalid
 */

function validateFile($file) {
    // Check upload errors
    if ($file['error'] !== UPLOAD_ERROR_OK) {
        return 'Upload error occurred: ' . $file['error'];
    }

    // Check file size
    if ($file['size'] > MAX_FILE_SIZE) {
        return 'File size exceeds limit of ' . (MAX_FILE_SIZE / 1024 / 1024) . 'MB';
    }

    // Check file type
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);

    if (!in_array($mimeType, ALLOWED_TYPES)) {
        return 'File type not allowed';
    }

    return true;
}

// Check if this is a POST request
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    sendResponse(405, 'Method not allowed');
}

// Check if file was uploaded
if (empty($_FILES['file'])) {
    sendResponse(400, 'No file uploaded');
}

// Get form data
$title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_STRING);
$description = filter_input(INPUT_POST, 'description', FILTER_SANITIZE_STRING);
$category = filter_input(INPUT_POST, 'category', FILTER_SANITIZE_STRING);

// Validate required fields
if (empty($title)) {
    sendResponse(400, 'Title is required');
}

// Create upload directory if it doesn't exist
if (!file_exists(UPLOAD_DIR)) {
    if (!mkdir(UPLOAD_DIR, 0777, true)) {
        sendResponse(500, 'Failed to create upload directory');
    }
}

// Validate file
$validation = validateFile($_FILES['file']);
if ($validation !== true) {
    sendResponse(400, $validation);
}

// Generate unique filename
$fileExtension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$fileName = uniqid() . '_' . time() . '.' . $fileExtension;
$uploadPath = UPLOAD_DIR . $fileName;

// Move uploaded file
if (!move_uploaded_file($_FILES['file']['tmp_name'], $uploadPath)) {
    sendResponse(500, 'Failed to save uploaded file');
}

// Optional: Save file information to database
try {
    // Example database connection and query
    /*
    $pdo = new PDO("mysql:host=localhost;dbname=your_database", "username", "password");
    $stmt = $pdo->prepare("INSERT INTO uploads (filename, original_name, title, description, category) VALUES (?, ?, ?, ?, ?)");
    $stmt->execute([$fileName, $_FILES['file']['name'], $title, $description, $category]);
    */


    // Return success response
    sendResponse(200, 'File uploaded successfully', [
        'filename' => $fileName,
        'path' => $uploadPath,
        'title' => $title,
        'category' => $category
    ]);

} catch (Exception $e) {
    // If database error occurs, delete uploaded file
    if (file_exists($uploadPath)) {
        unlink($uploadPath);
    }
    sendResponse(500, 'Database error: ' . $e->getMessage());
}