Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

Handling File Uploads

บทความนี้กล่าวถึงวิธีการจัดการการอัปโหลดไฟล์ใน PHP โดยเน้นที่การใช้ `$_FILES` superglobal เพื่อเข้าถึงข้อมูลไฟล์ การตรวจสอบประเภทไฟล์เพื่อความปลอดภัย (แนะนำให้ใ...

Handling File Uploads

การอัปโหลดไฟล์เป็นฟังก์ชันที่สำคัญอย่างยิ่งในเว็บแอปพลิเคชันจำนวนมาก ไม่ว่าจะเป็นการอัปโหลดรูปโปรไฟล์, เอกสาร, หรือไฟล์ประเภทอื่นๆ การจัดการการอัปโหลดไฟล์อย่างปลอดภัยและมีประสิทธิภาพเป็นสิ่งสำคัญเพื่อให้มั่นใจในความสมบูรณ์ของระบบและความปลอดภัยของผู้ใช้ ในบทนี้ เราจะมาเรียนรู้วิธีการจัดการการอัปโหลดไฟล์ใน PHP ตั้งแต่การเข้าถึงข้อมูลไฟล์ผ่าน $_FILES superglobal การตรวจสอบประเภทไฟล์ ไปจนถึงการย้ายไฟล์ไปยังไดเรกทอรีที่ต้องการ

การใช้ $_FILES Superglobal

เมื่อผู้ใช้ทำการอัปโหลดไฟล์ผ่านฟอร์ม HTML ข้อมูลเกี่ยวกับไฟล์ที่อัปโหลดจะถูกเก็บไว้ใน $_FILES superglobal ซึ่งเป็น associative array ที่มีข้อมูลเกี่ยวกับไฟล์แต่ละไฟล์ที่ถูกอัปโหลด แต่ละไฟล์จะมี index เป็นชื่อของ input field ที่ใช้ในการอัปโหลด และแต่ละ index จะมี array ที่ประกอบด้วยข้อมูลต่อไปนี้:

  • name: ชื่อเดิมของไฟล์บนเครื่องของผู้ใช้
  • type: MIME type ของไฟล์ (เช่น image/jpeg, text/plain)
  • tmp_name: ชื่อ temporary ของไฟล์ที่ถูกเก็บไว้บน server
  • error: รหัสข้อผิดพลาดที่เกี่ยวข้องกับการอัปโหลดไฟล์ (ถ้ามี)
  • size: ขนาดของไฟล์เป็น bytes

ตัวอย่าง HTML form สำหรับการอัปโหลดไฟล์:

<form action="upload.php" method="post" enctype="multipart/form-data">
  <label for="fileToUpload">Select image to upload:</label>
  <input type="file" name="fileToUpload" id="fileToUpload">
  <input type="submit" value="Upload Image" name="submit">
</form>

สำคัญ: enctype="multipart/form-data" เป็นสิ่งจำเป็นใน <form> tag เพื่อให้เบราว์เซอร์ส่งไฟล์ไปยัง server ได้อย่างถูกต้อง

ตัวอย่าง PHP code สำหรับการเข้าถึงข้อมูลไฟล์:

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
  if (isset($_FILES["fileToUpload"])) {
    $fileName = $_FILES["fileToUpload"]["name"];
    $fileType = $_FILES["fileToUpload"]["type"];
    $fileTmpName = $_FILES["fileToUpload"]["tmp_name"];
    $fileError = $_FILES["fileToUpload"]["error"];
    $fileSize = $_FILES["fileToUpload"]["size"];

    echo "File Name: " . $fileName . "<br>";
    echo "File Type: " . $fileType . "<br>";
    echo "File Size: " . $fileSize . " bytes<br>";

    // ... (ตรวจสอบข้อผิดพลาดและดำเนินการอื่นๆ)
  }
}
?>

การตรวจสอบ File Type

การตรวจสอบ file type เป็นขั้นตอนที่สำคัญอย่างยิ่งในการรักษาความปลอดภัยของระบบ เพื่อป้องกันการอัปโหลดไฟล์ที่เป็นอันตราย เช่น ไฟล์ PHP ที่อาจถูกใช้ในการโจมตีระบบ การตรวจสอบ file type สามารถทำได้หลายวิธี:

  • ตรวจสอบ MIME Type: ใช้ $_FILES["fileToUpload"]["type"] เพื่อตรวจสอบ MIME type ของไฟล์ แต่วิธีนี้ไม่น่าเชื่อถือ 100% เนื่องจาก MIME type สามารถถูกปลอมแปลงได้
  • ตรวจสอบ File Extension: ตรวจสอบนามสกุลของไฟล์ (เช่น .jpg, .png, .pdf) แต่วิธีนี้ก็ยังไม่ปลอดภัยเท่าที่ควร เนื่องจากผู้โจมตีสามารถเปลี่ยนนามสกุลของไฟล์ได้
  • ใช้ฟังก์ชัน mime_content_type() หรือ finfo_file(): ฟังก์ชันเหล่านี้จะตรวจสอบเนื้อหาของไฟล์เพื่อระบุ MIME type ที่ถูกต้อง วิธีนี้มีความน่าเชื่อถือมากกว่าสองวิธีแรก
  • Whitelist Allowed File Types: กำหนดรายการ file types ที่อนุญาตให้ทำการอัปโหลดเท่านั้น และปฏิเสธ file types อื่นๆ ทั้งหมด

ตัวอย่างการตรวจสอบ file extension และ MIME type:

<?php
$allowedExtensions = array("jpg", "jpeg", "png", "gif");
$allowedMimeTypes = array("image/jpeg", "image/png", "image/gif");

$fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));

if (!in_array($fileExtension, $allowedExtensions)) {
  echo "Error: Invalid file extension. Only JPG, JPEG, PNG, and GIF are allowed.<br>";
  $uploadOk = 0;
}

if (!in_array($fileType, $allowedMimeTypes)) {
  echo "Error: Invalid MIME type. Only image/jpeg, image/png, and image/gif are allowed.<br>";
  $uploadOk = 0;
}

//ใช้ finfo_file() เพื่อตรวจสอบ MIME type จากเนื้อหาไฟล์
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $fileTmpName);
finfo_close($finfo);

if (!in_array($mimeType, $allowedMimeTypes)) {
    echo "Error: Invalid MIME type (content-based). Only image/jpeg, image/png, and image/gif are allowed.<br>";
    $uploadOk = 0;
}
?>

เหตุผลเชิงออกแบบ: การใช้ whitelist approach (อนุญาตเฉพาะ file types ที่กำหนด) เป็นแนวทางปฏิบัติที่ดีที่สุดในการรักษาความปลอดภัย เนื่องจากจะช่วยลดโอกาสที่ผู้โจมตีจะสามารถอัปโหลดไฟล์ที่เป็นอันตรายได้ การตรวจสอบทั้ง file extension และ MIME type จะช่วยเพิ่มระดับความปลอดภัยมากยิ่งขึ้น

การย้ายไฟล์ไปยัง Directory ที่ต้องการ

เมื่อตรวจสอบ file type และยืนยันว่าไฟล์ปลอดภัยแล้ว ขั้นตอนต่อไปคือการย้ายไฟล์จาก temporary location ($_FILES["fileToUpload"]["tmp_name"]) ไปยัง directory ที่ต้องการบน server การใช้ฟังก์ชัน move_uploaded_file() เป็นวิธีที่แนะนำในการทำเช่นนี้

<?php
$targetDir = "uploads/"; // Directory ที่ต้องการเก็บไฟล์
$targetFile = $targetDir . basename($fileName); // Path ของไฟล์ที่จะถูกเก็บ

if (move_uploaded_file($fileTmpName, $targetFile)) {
  echo "The file " . basename($fileName) . " has been uploaded.<br>";
} else {
  echo "Error: There was an error uploading your file.<br>";
}
?>

ข้อควรระวัง:

  • ตรวจสอบให้แน่ใจว่า directory ที่กำหนด ($targetDir) มีสิทธิ์ในการเขียน (write permission) สำหรับ web server
  • พิจารณาการเปลี่ยนชื่อไฟล์ที่อัปโหลดเพื่อป้องกันการเขียนทับไฟล์ที่มีอยู่แล้ว และเพื่อความปลอดภัย (เช่น การใช้ uniqid() หรือ hash() ในการสร้างชื่อไฟล์ใหม่)
  • ตรวจสอบ $_FILES["fileToUpload"]["error"] เพื่อตรวจสอบว่ามีข้อผิดพลาดเกิดขึ้นระหว่างการอัปโหลดหรือไม่ หากมีข้อผิดพลาด ให้แสดงข้อความที่เหมาะสมให้กับผู้ใช้

เหตุผลเชิงออกแบบ: การใช้ move_uploaded_file() มีความปลอดภัยมากกว่าการใช้ฟังก์ชัน copy() เนื่องจาก move_uploaded_file() จะตรวจสอบว่าไฟล์ถูกอัปโหลดผ่าน HTTP POST upload mechanism จริงหรือไม่ ซึ่งจะช่วยป้องกันการโจมตีประเภทต่างๆ เช่น การโจมตีโดยการปลอมแปลงไฟล์

ตัวอย่างการเปลี่ยนชื่อไฟล์:

<?php
$targetDir = "uploads/";
$newFileName = uniqid() . "_" . $fileName; // สร้างชื่อไฟล์ใหม่ที่ไม่ซ้ำกัน
$targetFile = $targetDir . $newFileName;

if (move_uploaded_file($fileTmpName, $targetFile)) {
  echo "The file " . $newFileName . " has been uploaded.<br>";
} else {
  echo "Error: There was an error uploading your file.<br>";
}
?>

สรุป

การจัดการการอัปโหลดไฟล์ใน PHP ต้องอาศัยความระมัดระวังและความเข้าใจในกลไกการทำงานของ $_FILES superglobal การตรวจสอบ file type อย่างเข้มงวด และการใช้ฟังก์ชัน move_uploaded_file() อย่างถูกต้องเป็นสิ่งสำคัญในการรักษาความปลอดภัยของระบบ การคำนึงถึงสิทธิ์ในการเขียน directory และการเปลี่ยนชื่อไฟล์ที่อัปโหลด ก็เป็นแนวทางปฏิบัติที่ดีที่ควรนำมาพิจารณา การทำความเข้าใจ trade-offs ระหว่างความสะดวกในการใช้งานและความปลอดภัย จะช่วยให้คุณสามารถพัฒนาเว็บแอปพลิเคชันที่มีความปลอดภัยและน่าเชื่อถือได้

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service