การจัดการ 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;
}
ฟังก์ชันนี้จะ
- กำหนด header เป็น JSON
- กำหนด HTTP status code
- ส่งข้อมูลกลับในรูปแบบ JSON
- จบการทำงานของสคริปต์
การตรวจสอบไฟล์
ฟังก์ชัน 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;
}
การตรวจสอบประกอบด้วย
- ตรวจสอบว่าการอัพโหลดสำเร็จ
- ตรวจสอบขนาดไฟล์
- ตรวจสอบประเภทไฟล์โดยใช้ MIME type
ขั้นตอนการทำงานหลัก
- ตรวจสอบ HTTP Method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
sendResponse(405, 'Method not allowed');
} - รับและตรวจสอบข้อมูล 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); - สร้างโฟลเดอร์สำหรับเก็บไฟล์
if (!file_exists(UPLOAD_DIR)) {
mkdir(UPLOAD_DIR, 0777, true);
} - ตรวจสอบและย้ายไฟล์
$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());
}
ความปลอดภัย
ระบบมีการป้องกันความปลอดภัยหลายระดับ
- ตรวจสอบ MIME type ของไฟล์
- จำกัดขนาดไฟล์
- สร้างชื่อไฟล์ใหม่เพื่อป้องกันการ overwrite
- Sanitize ข้อมูลที่รับมาจาก form
- ใช้ PDO สำหรับการเชื่อมต่อฐานข้อมูล
การนำไปใช้งาน
ในการนำไปใช้งานจริง ควรพิจารณา
- ปรับแต่งค่า configuration ให้เหมาะกับความต้องการ
- เพิ่มการตรวจสอบสิทธิ์ผู้ใช้
- ปรับแต่งโครงสร้างฐานข้อมูล
- เพิ่มการจัดการ error cases เพิ่มเติม
- เพิ่มการ 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());
}