Kotchasan Framework Documentation

Kotchasan Framework Documentation

การจัดการไฟล์และรูปภาพ

TH 05 Feb 2026 06:23

การจัดการไฟล์และรูปภาพ

Kotchasan Framework มีคลาสสำหรับการจัดการไฟล์และรูปภาพที่ครอบคลุมทุกความต้องการ ตั้งแต่การอัปโหลด การจัดการ การประมวลผลรูปภาพ จนถึงการจัดเก็บอย่างปลอดภัย

สารบัญ

  1. File Class - การจัดการไฟล์และไดเรกทอรี
  2. UploadedFile Class - การจัดการไฟล์อัปโหลด
  3. Files Collection - คอลเลกชันไฟล์
  4. Image Class - การประมวลผลรูปภาพ
  5. การใช้งานในระบบจริง
  6. Best Practices

File Class - การจัดการไฟล์และไดเรกทอรี

การจัดการไดเรกทอรี

use Kotchasan\File;

// สร้างไดเรกทอรีอย่างปลอดภัย
$uploadDir = '/var/www/uploads/documents/';
if (File::makeDirectory($uploadDir, 0755)) {
    echo "ไดเรกทอรีพร้อมใช้งาน";
} else {
    echo "ไม่สามารถสร้างไดเรกทอรีได้";
}

// สร้างโครงสร้างไดเรกทอรีที่ซับซ้อน
$userUploadDir = '/var/www/uploads/users/' . $userId . '/documents/';
$imageUploadDir = '/var/www/uploads/users/' . $userId . '/images/';
$tempDir = '/var/www/temp/' . session_id() . '/';

$directories = [$userUploadDir, $imageUploadDir, $tempDir];
foreach ($directories as $dir) {
    if (!File::makeDirectory($dir, 0755)) {
        throw new Exception("ไม่สามารถสร้างไดเรกทอรี: {$dir}");
    }
}

// คัดลอกไดเรกทอรีทั้งหมด
$sourceTemplate = '/var/www/templates/user_template/';
$userCustomDir = '/var/www/uploads/users/' . $userId . '/custom/';

File::copyDirectory($sourceTemplate, $userCustomDir);
echo "คัดลอกไฟล์ template สำเร็จ";

การจัดการไฟล์

// ค้นหาไฟล์ในระบบ
$documentFiles = [];
File::listFiles('/var/www/uploads/documents/', $documentFiles, ['pdf', 'doc', 'docx']);

echo "พบเอกสาร " . count($documentFiles) . " ไฟล์:\n";
foreach ($documentFiles as $file) {
    echo "- " . basename($file) . " (" . File::ext($file) . ")\n";
}

// ค้นหาไฟล์รูปภาพ
$imageFiles = [];
File::listFiles('/var/www/uploads/images/', $imageFiles, ['jpg', 'jpeg', 'png', 'gif', 'webp']);

// สร้างรายการไฟล์พร้อมข้อมูลเพิ่มเติม
$fileList = [];
foreach ($imageFiles as $file) {
    $fileInfo = [
        'path' => $file,
        'name' => basename($file),
        'extension' => File::ext($file),
        'size' => filesize($file),
        'modified' => filemtime($file)
    ];
    $fileList[] = $fileInfo;
}

// เรียงลำดับตามวันที่แก้ไข
usort($fileList, function($a, $b) {
    return $b['modified'] - $a['modified'];
});

การทำความสะอาดไฟล์

// ลบไฟล์ temp ที่เก่า
$tempDir = '/var/www/temp/';
$tempFiles = [];
File::listFiles($tempDir, $tempFiles);

$cutoffTime = time() - (24  60  60); // 24 ชั่วโมงที่แล้ว

foreach ($tempFiles as $file) {
    if (filemtime($file) < $cutoffTime) {
        unlink($file);
        echo "ลบไฟล์ temp: " . basename($file) . "\n";
    }
}

// ลบไดเรกทอรีที่ว่าง
$userDirs = glob('/var/www/uploads/users/*', GLOB_ONLYDIR);
foreach ($userDirs as $dir) {
    $files = [];
    File::listFiles($dir . '/', $files);

    if (empty($files)) {
        File::removeDirectory($dir . '/', true);
        echo "ลบไดเรกทอรีว่าง: " . basename($dir) . "\n";
    }
}

// ทำความสะอาดไฟล์ cache
$cacheDir = '/var/www/cache/';
File::removeDirectory($cacheDir, false); // ลบเฉพาะไฟล์ใน dir
echo "ทำความสะอาด cache เสร็จสิ้น";
*/

UploadedFile Class - การจัดการไฟล์อัปโหลด

การตรวจสอบไฟล์อัปโหลด

use Kotchasan\Http\UploadedFile;

// สมมติว่าได้ UploadedFile จาก Request
$uploadedFile = $request->getUploadedFiles()['document'] ?? null;

if ($uploadedFile && $uploadedFile->hasUploadFile()) {
    // ตรวจสอบข้อผิดพลาด
    if ($uploadedFile->hasError()) {
        $error = $uploadedFile->getErrorMessage();
        throw new Exception("เกิดข้อผิดพลาดในการอัปโหลด: {$error}");
    }

    // ตรวจสอบขนาดไฟล์
$maxSize = 5; // 1024  1024; // 5MB
    if ($uploadedFile->getSize() > $maxSize) {
        throw new Exception("ไฟล์มีขนาดใหญ่เกินไป (สูงสุด 5MB)");
    }

    // ตรวจสอบประเภทไฟล์
    $allowedTypes = ['pdf', 'doc', 'docx', 'txt'];
    if (!$uploadedFile->validFileExt($allowedTypes)) {
        throw new Exception("ประเภทไฟล์ไม่ได้รับอนุญาต (อนุญาตเฉพาะ: " . implode(', ', $allowedTypes) . ")");
    }

    echo "ไฟล์ผ่านการตรวจสอบเบื้องต้น";
} else {
    throw new Exception("ไม่พบไฟล์ที่อัปโหลด");
}

การจัดเก็บไฟล์อัปโหลด

use Kotchasan\Database;

// สร้างชื่อไฟล์ที่ปลอดภัย
$originalName = $uploadedFile->getClientFilename();
$cleanName = $uploadedFile->getCleanFilename('_');
$extension = strtolower(pathinfo($cleanName, PATHINFO_EXTENSION));

// สร้างชื่อไฟล์ไม่ซ้ำ
$uniqueName = date('Y-m-d_H-i-s') . '_' . uniqid() . '.' . $extension;

// กำหนดโฟลเดอร์จัดเก็บตามประเภท
$uploadPath = match($extension) {
    'pdf', 'doc', 'docx' => '/var/www/uploads/documents/',
    'jpg', 'jpeg', 'png', 'gif', 'webp' => '/var/www/uploads/images/',
    'mp4', 'avi', 'mov' => '/var/www/uploads/videos/',
    default => '/var/www/uploads/others/'
};

// สร้างโครงสร้างไดเรกทอรีตามวันที่
$dateDir = $uploadPath . date('Y/m/');
if (!File::makeDirectory($dateDir, 0755)) {
    throw new Exception("ไม่สามารถสร้างไดเรกทอรีจัดเก็บได้");
}

$targetPath = $dateDir . $uniqueName;

try {
    // ย้ายไฟล์ไปยังตำแหน่งปลายทาง
    $uploadedFile->moveTo($targetPath);

    // บันทึกข้อมูลไฟล์ลงฐานข้อมูล
    $fileData = [
        'original_name' => $originalName,
        'stored_name' => $uniqueName,
        'file_path' => $targetPath,
        'file_size' => $uploadedFile->getSize(),
        'mime_type' => $uploadedFile->getClientMediaType(),
        'extension' => $extension,
        'uploaded_at' => date('Y-m-d H:i:s'),
        'user_id' => $_SESSION['user_id'] ?? null
    ];

    Kotchasan\Database::create()
        ->insert('uploaded_files')
        ->values($fileData)
        ->execute();

    echo "อัปโหลดไฟล์สำเร็จ: {$uniqueName}";

} catch (Exception $e) {
    throw new Exception("ไม่สามารถจัดเก็บไฟล์ได้: " . $e->getMessage());
}

การสำรองและคัดลอกไฟล์

// สำรองไฟล์สำคัญ
$backupDir = '/var/www/backups/' . date('Y-m-d') . '/';
File::makeDirectory($backupDir, 0755);

try {
    // คัดลอกแทนการย้าย (เก็บไฟล์ต้นฉบับ)
    $backupPath = $backupDir . $uniqueName;
    $uploadedFile->copyTo($backupPath);

    // จากนั้นจึงย้ายไปยังตำแหน่งหลัก
    $uploadedFile->moveTo($targetPath);

    echo "จัดเก็บไฟล์พร้อมสำรองสำเร็จ";

} catch (Exception $e) {
    throw new Exception("เกิดข้อผิดพลาดในการจัดเก็บ: " . $e->getMessage());
}

Files Collection - คอลเลกชันไฟล์

การจัดการไฟล์หลายไฟล์

use Kotchasan\Files;

// สร้าง Files collection
$files = new Files();

// เพิ่มไฟล์จาก $_FILES
if (isset($_FILES['documents'])) {
    if (is_array($_FILES['documents']['name'])) {
        // Multiple files
        for ($i = 0; $i < count($_FILES['documents']['name']); $i++) {
            $files->add(
                'document_' . $i,
                $_FILES['documents']['tmp_name'][$i],
                $_FILES['documents']['name'][$i],
                $_FILES['documents']['type'][$i],
                $_FILES['documents']['size'][$i],
                $_FILES['documents']['error'][$i]
            );
        }
    } else {
        // Single file
        $files->add(
            'document',
            $_FILES['documents']['tmp_name'],
            $_FILES['documents']['name'],
            $_FILES['documents']['type'],
            $_FILES['documents']['size'],
            $_FILES['documents']['error']
        );
    }
}

// ประมวลผลไฟล์ทั้งหมด
$uploadResults = [];
$uploadErrors = [];

foreach ($files as $key => $uploadedFile) {
    try {
        // ตรวจสอบไฟล์
        if (!$uploadedFile->hasUploadFile()) {
            continue; // ข้ามไฟล์ที่ไม่มี
        }

        if ($uploadedFile->hasError()) {
            $uploadErrors[] = $key . ': ' . $uploadedFile->getErrorMessage();
            continue;
        }

        // ตรวจสอบประเภทไฟล์
        $allowedExts = ['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png'];
        if (!$uploadedFile->validFileExt($allowedExts)) {
            $uploadErrors[] = $key . ': ประเภทไฟล์ไม่ได้รับอนุญาต';
            continue;
        }

        // อัปโหลดไฟล์
        $result = $this->processFileUpload($uploadedFile);
        $uploadResults[] = $result;

    } catch (Exception $e) {
        $uploadErrors[] = $key . ': ' . $e->getMessage();
    }
}

// แสดงผลลัพธ์
if (!empty($uploadResults)) {
    echo "อัปโหลดสำเร็จ " . count($uploadResults) . " ไฟล์\n";
}

if (!empty($uploadErrors)) {
    echo "เกิดข้อผิดพลาด:\n";
    foreach ($uploadErrors as $error) {
        echo "- {$error}\n";
    }
}

Image Class - การประมวลผลรูปภาพ

การปรับขนาดรูปภาพ

use Kotchasan\Image;

// ตั้งค่าคุณภาพรูปภาพ
$quality = 8; // 5; // สำหรับ JPEG และ WebP

// ปรับขนาดรูปภาพอัตโนมัติ (รักษาสัดส่วน)
$sourceImage = '/var/www/uploads/original/photo.jpg';
$thumbnailDir = '/var/www/uploads/thumbnails/';

// สร้าง thumbnail ขนาดต่างๆ
$thumbnailSizes = [
    'small' => 150,
    'medium' => 300,
    'large' => 600
];

foreach ($thumbnailSizes as $size => $width) {
    $targetFile = $thumbnailDir . $size . '_photo.jpg';

    if (Image::resize($sourceImage, $thumbnailDir, $size . '_photo.jpg', $width)) {
        echo "สร้าง thumbnail {$size} ({$width}px) สำเร็จ\n";
    }
}

// ปรับขนาดพร้อมกำหนดความสูง
$profileDir = '/var/www/uploads/profiles/';
$profileImage = $profileDir . 'profile.jpg';

// สร้างรูปโปรไฟล์ขนาด 200x200 (crop กลาง)
if (Image::crop($sourceImage, $profileImage, 200, 200, '', false)) {
    echo "สร้างรูปโปรไฟล์สำเร็จ\n";
}

// สร้างรูป banner แบบ fit (ไม่ crop)
$bannerImage = $profileDir . 'banner.jpg';
if (Image::crop($sourceImage, $bannerImage, 800, 200, '', true)) {
    echo "สร้างรูป banner สำเร็จ\n";
}

การเพิ่ม Watermark

// ตั้งค่า font สำหรับ watermark
Image::$fontPath = '/var/www/fonts/arial.ttf';

// เพิ่ม watermark ลงในรูปภาพ
$watermarkText = '© 2024 My Website';

// ปรับขนาดพร้อม watermark
$watermarkedFile = '/var/www/uploads/watermarked/photo_wm.jpg';
if (Image::resize($sourceImage, '/var/www/uploads/watermarked/', 'photo_wm.jpg', 800, $watermarkText)) {
    echo "เพิ่ม watermark สำเร็จ\n";
}

// Crop พร้อม watermark
$thumbnailWm = '/var/www/uploads/thumbnails/thumb_wm.jpg';
if (Image::crop($sourceImage, $thumbnailWm, 300, 300, $watermarkText, false)) {
    echo "สร้าง thumbnail พร้อม watermark สำเร็จ\n";
}

การประมวลผลรูปภาพขั้นสูง

// โหลดรูปภาพจาก Base64
$base64Data = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD...';
$allowedFormats = ['jpg', 'jpeg', 'png', 'gif', 'webp'];

$imageInfo = Image::loadImageFromBase64($base64Data, $allowedFormats);
if ($imageInfo !== false) {
    $imageResource = $imageInfo['resource'];
    $mimeType = $imageInfo['mime'];
    $extension = $imageInfo['extension'];

    // ประมวลผลรูปภาพ
    $processedImage = Image::processImageResource($imageResource, 400, 300, 'Sample Watermark', true);

    // บันทึกรูปภาพ
    $outputFile = '/var/www/uploads/processed/image.' . $extension;
    if (Image::saveImageResource($processedImage, $outputFile)) {
        echo "ประมวลผลรูปภาพจาก Base64 สำเร็จ\n";
    }

    // ทำลาย resource
    imagedestroy($processedImage);
    imagedestroy($imageResource);
}

// ประมวลผลรูปภาพแบบ batch
$sourceDir = '/var/www/uploads/originals/';
$outputDir = '/var/www/uploads/processed/';

$imageFiles = [];
File::listFiles($sourceDir, $imageFiles, ['jpg', 'jpeg', 'png']);

foreach ($imageFiles as $imagePath) {
    $filename = basename($imagePath);
    $outputPath = $outputDir . $filename;

    try {
        // โหลดรูปภาพ
        $imageResource = Image::loadImageResource($imagePath);

        // ปรับขนาดเป็น 800px (รักษาสัดส่วน)
        $processedImage = Image::processImageResource($imageResource, 800, 0, '© My Company', false);

        // บันทึก
        Image::saveImageResource($processedImage, $outputPath);

        // ทำลาย resource
        imagedestroy($processedImage);
        imagedestroy($imageResource);

        echo "ประมวลผล {$filename} สำเร็จ\n";

    } catch (Exception $e) {
        echo "ไม่สามารถประมวลผล {$filename}: " . $e->getMessage() . "\n";
    }
}

การใช้งานในระบบจริง

ระบบอัปโหลดไฟล์สมบูรณ์

use Kotchasan\Database;

class FileUploadManager
{
    private $uploadConfig = [
        'documents' => [
            'path' => '/var/www/uploads/documents/',
            'allowed_exts' => ['pdf', 'doc', 'docx', 'txt'],
            'max_size' => 10  1024  1024, // 10MB
            'watermark' => false
        ],
        'images' => [
            'path' => '/var/www/uploads/images/',
            'allowed_exts' => ['jpg', 'jpeg', 'png', 'gif', 'webp'],
            'max_size' => 5  1024  1024, // 5MB
            'watermark' => true,
            'thumbnails' => [150, 300, 600]
        ],
        'videos' => [
            'path' => '/var/www/uploads/videos/',
            'allowed_exts' => ['mp4', 'avi', 'mov'],
            'max_size' => 100  1024  1024, // 100MB
            'watermark' => false
        ]
    ];

    public function handleUpload($uploadedFile, $category, $userId)
    {
        if (!isset($this->uploadConfig[$category])) {
            throw new Exception("ประเภทไฟล์ไม่ได้รับอนุญาต: {$category}");
        }

        $config = $this->uploadConfig[$category];

        // ตรวจสอบไฟล์
        $this->validateFile($uploadedFile, $config);

        // เตรียมเส้นทางจัดเก็บ
        $storagePath = $this->prepareStoragePath($config['path'], $userId);

        // สร้างชื่อไฟล์
        $fileName = $this->generateFileName($uploadedFile);
        $fullPath = $storagePath . $fileName;

        // อัปโหลดไฟล์
        $uploadedFile->moveTo($fullPath);

        // ประมวลผลเพิ่มเติม
        $result = $this->postProcessFile($fullPath, $config, $uploadedFile);

        // บันทึกลงฐานข้อมูล
        return $this->saveFileRecord($result, $category, $userId);
    }

    private function validateFile($uploadedFile, $config)
    {
        if (!$uploadedFile->hasUploadFile()) {
            throw new Exception("ไม่พบไฟล์ที่อัปโหลด");
        }

        if ($uploadedFile->hasError()) {
            throw new Exception("เกิดข้อผิดพลาด: " . $uploadedFile->getErrorMessage());
        }

        if ($uploadedFile->getSize() > $config['max_size']) {
            $maxSizeMB = $config['max_size'] / (1024 * 1024);
            throw new Exception("ไฟล์มีขนาดใหญ่เกินไป (สูงสุด {$maxSizeMB}MB)");
        }

        if (!$uploadedFile->validFileExt($config['allowed_exts'])) {
            throw new Exception("ประเภทไฟล์ไม่ได้รับอนุญาต");
        }
    }

    private function prepareStoragePath($basePath, $userId)
    {
        $datePath = date('Y/m/d/');
        $userPath = $basePath . $userId . '/' . $datePath;

        if (!File::makeDirectory($userPath, 0755)) {
            throw new Exception("ไม่สามารถสร้างไดเรกทอรีจัดเก็บได้");
        }

        return $userPath;
    }

    private function generateFileName($uploadedFile)
    {
        $originalName = $uploadedFile->getClientFilename();
        $cleanName = $uploadedFile->getCleanFilename('_');
        $extension = strtolower(pathinfo($cleanName, PATHINFO_EXTENSION));

        return date('Y-m-d_H-i-s') . '_' . uniqid() . '.' . $extension;
    }

    private function postProcessFile($filePath, $config, $uploadedFile)
    {
        $result = [
            'original_path' => $filePath,
            'file_size' => filesize($filePath)
        ];

        // ประมวลผลรูปภาพ
        if (in_array(File::ext($filePath), ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
            $result = array_merge($result, $this->processImage($filePath, $config));
        }

        return $result;
    }

    private function processImage($imagePath, $config)
    {
        $result = ['thumbnails' => []];
        $baseDir = dirname($imagePath) . '/';
        $baseName = pathinfo($imagePath, PATHINFO_FILENAME);
        $extension = pathinfo($imagePath, PATHINFO_EXTENSION);

        // สร้าง thumbnails
        if (isset($config['thumbnails'])) {
            foreach ($config['thumbnails'] as $size) {
                $thumbName = $baseName . '_thumb_' . $size . '.' . $extension;
                $thumbPath = $baseDir . 'thumbnails/' . $thumbName;

                File::makeDirectory(dirname($thumbPath) . '/', 0755);

                $watermark = $config['watermark'] ? '© My Website' : '';

                if (Image::resize($imagePath, dirname($thumbPath) . '/', $thumbName, $size, $watermark)) {
                    $result['thumbnails'][$size] = $thumbPath;
                }
            }
        }

        return $result;
    }

    private function saveFileRecord($fileData, $category, $userId)
    {
        $record = [
            'user_id' => $userId,
            'category' => $category,
            'original_path' => $fileData['original_path'],
            'file_size' => $fileData['file_size'],
            'thumbnails' => isset($fileData['thumbnails']) ? json_encode($fileData['thumbnails']) : null,
            'uploaded_at' => date('Y-m-d H:i:s')
        ];

        $fileId = Kotchasan\Database::create()
            ->insert('uploaded_files')
            ->values($record)
            ->execute();

        return array_merge($record, ['id' => $fileId]);
    }
}
class GalleryManager
{
    public function createGallery($images, $albumId)
    {
        $galleryPath = '/var/www/uploads/gallery/' . $albumId . '/';
        File::makeDirectory($galleryPath, 0755);

        $processedImages = [];

        foreach ($images as $uploadedImage) {
            try {
                $result = $this->processGalleryImage($uploadedImage, $galleryPath);
                $processedImages[] = $result;

            } catch (Exception $e) {
                // Log error และข้ามรูปที่มีปัญหา
                error_log("Gallery processing error: " . $e->getMessage());
            }
        }

        return $processedImages;
    }

    private function processGalleryImage($uploadedImage, $galleryPath)
    {
        // สร้างชื่อไฟล์
        $fileName = uniqid() . '.jpg';
        $originalPath = $galleryPath . 'originals/' . $fileName;

        // สร้างไดเรกทอรีย่อย
        File::makeDirectory(dirname($originalPath) . '/', 0755);
        File::makeDirectory($galleryPath . 'thumbnails/', 0755);
        File::makeDirectory($galleryPath . 'display/', 0755);

        // บันทึกไฟล์ต้นฉบับ
        $uploadedImage->moveTo($originalPath);

        // สร้างรูปสำหรับแสดงผล (1200px max)
        $displayPath = $galleryPath . 'display/' . $fileName;
        Image::resize($originalPath, dirname($displayPath) . '/', basename($displayPath), 1200, '© Gallery 2024');

        // สร้าง thumbnail (300px)
        $thumbnailPath = $galleryPath . 'thumbnails/' . $fileName;
        Image::crop($originalPath, $thumbnailPath, 300, 300, '', false);

        return [
            'filename' => $fileName,
            'original_path' => $originalPath,
            'display_path' => $displayPath,
            'thumbnail_path' => $thumbnailPath,
            'file_size' => filesize($originalPath)
        ];
    }

$outputSize = 120; // 0)
    {
        $galleryPath = '/var/www/uploads/gallery/' . $albumId . '/';
        $thumbnailDir = $galleryPath . 'thumbnails/';

        $thumbnails = [];
        File::listFiles($thumbnailDir, $thumbnails, ['jpg', 'jpeg', 'png']);

        if (count($thumbnails) < 4) {
            throw new Exception("ต้องมีรูปภาพอย่างน้อย 4 รูป");
        }

        // สร้าง mosaic 2x2
        $tileSize = $outputSize / 2;
        $mosaic = imagecreatetruecolor($outputSize, $outputSize);

        $positions = [
            [0, 0], [$tileSize, 0],
            [0, $tileSize], [$tileSize, $tileSize]
        ];

        for ($i = 0; $i < 4 && $i < count($thumbnails); $i++) {
            $thumbnail = Image::loadImageResource($thumbnails[$i]);
            $resized = Image::processImageResource($thumbnail, $tileSize, $tileSize, '', false);

            imagecopy($mosaic, $resized, $positions[$i][0], $positions[$i][1], 0, 0, $tileSize, $tileSize);

            imagedestroy($resized);
            imagedestroy($thumbnail);
        }

        $mosaicPath = $galleryPath . 'mosaic.jpg';
        Image::saveImageResource($mosaic, $mosaicPath);
        imagedestroy($mosaic);

        return $mosaicPath;
    }
}

Best Practices

1. ความปลอดภัยของไฟล์

// ✅ ดี - ตรวจสอบประเภทไฟล์อย่างเข้มงวด
function validateFileSecurely($uploadedFile) {
    // ตรวจสอบ extension
    $allowedExts = ['jpg', 'jpeg', 'png', 'pdf'];
    if (!$uploadedFile->validFileExt($allowedExts)) {
        throw new Exception("ประเภทไฟล์ไม่ได้รับอนุญาต");
    }

    // ตรวจสอบ MIME type
    $allowedMimes = ['image/jpeg', 'image/png', 'application/pdf'];
    if (!in_array($uploadedFile->getClientMediaType(), $allowedMimes)) {
        throw new Exception("MIME type ไม่ได้รับอนุญาต");
    }

    // ตรวจสอบเนื้อหาไฟล์จริง
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $realMime = $finfo->file($uploadedFile->getTempFileName());
    if (!in_array($realMime, $allowedMimes)) {
        throw new Exception("เนื้อหาไฟล์ไม่ตรงกับประเภทที่ประกาศ");
    }
}

// ✅ ดี - สร้างชื่อไฟล์ที่ปลอดภัย
function generateSecureFileName($uploadedFile) {
    $extension = strtolower(pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION));
    return hash('sha256', uniqid() . time() . $uploadedFile->getClientFilename()) . '.' . $extension;
}

2. การจัดการข้อผิดพลาด

// ✅ ดี - จัดการ exception อย่างเหมาะสม
class FileHandler
{
    public function handleUpload($uploadedFile)
    {
        try {
            $this->validateFile($uploadedFile);
            $path = $this->saveFile($uploadedFile);
            $this->logSuccess($path);
            return $path;

        } catch (InvalidArgumentException $e) {
            $this->logError("Validation error", $e);
            throw new Exception("ไฟล์ไม่ถูกต้อง: " . $e->getMessage());

        } catch (RuntimeException $e) {
            $this->logError("Runtime error", $e);
            throw new Exception("ไม่สามารถจัดเก็บไฟล์ได้");

        } catch (Exception $e) {
            $this->logError("Unexpected error", $e);
            throw new Exception("เกิดข้อผิดพลาดไม่คาดคิด");
        }
    }

    private function logError($type, $exception)
    {
        error_log("File upload {$type}: " . $exception->getMessage());
    }

    private function logSuccess($path)
    {
        error_log("File uploaded successfully: " . $path);
    }
}

3. การเพิ่มประสิทธิภาพ

// ✅ ดี - ใช้ memory อย่างมีประสิทธิภาพ
class OptimizedImageProcessor
{
    public function processBatchImages($imagePaths, $outputDir)
    {
        foreach ($imagePaths as $imagePath) {
            $this->processImageMemoryEfficient($imagePath, $outputDir);
        }
    }

    private function processImageMemoryEfficient($imagePath, $outputDir)
    {
        try {
            // โหลดรูปภาพ
            $imageResource = Image::loadImageResource($imagePath);

            // ประมวลผล
            $processed = Image::processImageResource($imageResource, 800, 0, '', false);

            // บันทึก
            $outputPath = $outputDir . basename($imagePath);
            Image::saveImageResource($processed, $outputPath);

        } finally {
            // ทำลาย resource เสมอ
            if (isset($processed) && is_resource($processed)) {
                imagedestroy($processed);
            }
            if (isset($imageResource) && is_resource($imageResource)) {
                imagedestroy($imageResource);
            }
        }
    }
}

// ✅ ดี - Lazy loading สำหรับรายการไฟล์ขนาดใหญ่
class FileListManager
{
$limit = 5; // 0)
    {
        $allFiles = [];
        File::listFiles($directory, $allFiles);

        $totalFiles = count($allFiles);
        $offset = ($page - 1) * $limit;
        $pagedFiles = array_slice($allFiles, $offset, $limit);

        return [
            'files' => $pagedFiles,
            'pagination' => [
                'current_page' => $page,
                'total_pages' => ceil($totalFiles / $limit),
                'total_files' => $totalFiles
            ]
        ];
    }
}

4. การทำความสะอาดและบำรุงรักษา

// ✅ ดี - ระบบทำความสะอาดอัตโนมัติ
class FileMaintenance
{
    public function cleanupExpiredFiles()
    {
        $tempDir = '/var/www/uploads/temp/';
        $expiredTime = time() - (24  60  60); // 24 ชั่วโมง

        $tempFiles = [];
        File::listFiles($tempDir, $tempFiles);

        $deletedCount = 0;
        foreach ($tempFiles as $file) {
            if (filemtime($file) < $expiredTime) {
                if (unlink($file)) {
                    $deletedCount++;
                }
            }
        }

        return $deletedCount;
    }

    public function optimizeImageDirectory($directory)
    {
        $imageFiles = [];
        File::listFiles($directory, $imageFiles, ['jpg', 'jpeg', 'png']);

        $optimizedCount = 0;
        foreach ($imageFiles as $imagePath) {
            $originalSize = filesize($imagePath);

            // ลด quality ถ้าไฟล์ใหญ่เกินไป
            if ($originalSize > 1024 * 1024) { // > 1MB
$quality = 7; // 0;

                $backupPath = $imagePath . '.backup';
                rename($imagePath, $backupPath);

                if (Image::resize($backupPath, dirname($imagePath) . '/', basename($imagePath), 0, '')) {
                    $newSize = filesize($imagePath);
                    if ($newSize < $originalSize) {
                        unlink($backupPath);
                        $optimizedCount++;
                    } else {
                        rename($backupPath, $imagePath);
                    }
                }
            }
        }

        return $optimizedCount;
    }
}

การจัดการไฟล์และรูปภาพใน Kotchasan Framework ให้ความยืดหยุ่นและความปลอดภัยสูง ควรใช้งานอย่างระมัดระวังและติดตาม best practices เพื่อประสิทธิภาพและความปลอดภัยสูงสุด