NexaForm menyediakan sistem yang komprehensif untuk menangani upload file dengan aman dan efisien. Dengan menggunakan NexaForm dan NexaFile helper, Anda dapat dengan mudah mengimplementasikan fitur upload file dalam aplikasi Anda, termasuk validasi, enkripsi nama file, pembuatan thumbnail, dan banyak lagi.
Untuk mengaktifkan upload file dalam form, Anda perlu mengatur konfigurasi upload dengan method setUpload()
:
$form = $this->createForm();
// Konfigurasi form dengan field file
$form->fields([
'title' => 'Title|5|Judul minimal 5 karakter',
'description' => 'Textarea|10|Deskripsi minimal 10 karakter',
'image' => 'File|jpg,png,gif|Gambar harus berupa JPG/PNG/GIF maksimal 2MB',
'document' => 'FileOptional|pdf,doc,docx|Dokumen maksimal 5MB'
])
->setUpload([
// Konfigurasi utama
'maxSize' => '5MB', // Ukuran maksimum file (dapat menggunakan format seperti '2MB', '1GB')
'allowedTypes' => ['jpg', 'png', 'gif', 'pdf', 'doc', 'docx'], // MIME types yang diizinkan
'allowedExtensions' => ['jpg', 'png', 'gif', 'pdf', 'doc', 'docx'], // Ekstensi file yang diizinkan
// Konfigurasi thumbnail (opsional)
'thumbnail' => ['300x200', '150x100'], // Ukuran thumbnail yang akan dibuat
'thumbnailCropMode' => 'fit' // Mode cropping: 'fit' (pertahankan rasio) atau 'crop' (isi kanvas)
]);
YYYY/MM/
) di dalam direktori upload dasar. Nama file juga secara otomatis dienkripsi untuk keamanan.
NexaForm menyediakan beberapa aturan validasi khusus untuk file:
file
- Field harus berupa file yang diuploadfileoptional
- Field boleh kosong atau berupa file yang diuploadimage
- Field harus berupa file gambar (jpg, jpeg, png, gif)mimes:ext1,ext2,...
- Field harus berupa file dengan ekstensi tertentumax:size
- Ukuran file tidak boleh melebihi size (dalam KB atau dengan notasi seperti 2M, 1G)dimensions:min_width=100,min_height=100,max_width=1000,max_height=1000
- Dimensi gambar harus sesuai
$form->fields([
// File gambar wajib, max 2MB, dimensi minimal 300x200
'profile_image' => 'File|jpg,png,gif|Dimensi gambar minimal 300x200',
// File PDF opsional, max 5MB
'resume' => 'FileOptional|pdf|File resume maksimal 5MB',
// File gambar atau dokumen, max 10MB
'attachment' => 'File|jpg,jpeg,png,pdf,doc,docx|File attachment maksimal 10MB'
]);
Saat form disubmit, NexaForm akan otomatis memproses upload file jika konfigurasi upload telah diatur:
public function uploadFile(): void
{
$form = $this->createForm();
// Konfigurasi form dengan field file
$form->fields([
'title' => 'Title|5|Judul minimal 5 karakter',
'image' => 'File|jpg,png,gif|Gambar maksimal 2MB'
])
->setUpload([
'maxSize' => '2MB',
'allowedTypes' => ['jpg', 'png', 'gif'],
'allowedExtensions' => ['jpg', 'png', 'gif'],
'thumbnail' => ['300x200', '150x100'],
'thumbnailCropMode' => 'fit'
]);
if ($this->isPost()) {
// Proses form
$result = $form->process();
if ($result['success']) {
// Form valid dan file berhasil diupload
$data = $result['data'];
// $data['image'] berisi path file yang diupload
$imagePath = $data['image'];
// Informasi file yang diupload
$fileInfo = $result['files']['image'];
// Simpan data ke database
$this->useModels('Article', 'save', [
'title' => $data['title'],
'image_path' => $imagePath,
'image_name' => $fileInfo['orig_name'] ?? $fileInfo['path'],
'image_type' => $fileInfo['type'],
'image_size' => $fileInfo['size']
]);
$this->setFlash('success', 'File berhasil diupload');
$this->redirect('/articles');
return;
}
}
// Render form dengan data validasi
$this->assignVars($form->Response());
$this->render('articles/upload');
}
Setelah file berhasil diupload, informasi file tersedia dalam array $result['files']
:
// Struktur $result['files'] untuk field 'image'
[
'image' => [
'path' => '2023/05/encrypted_filename.jpg', // Path file relatif
'size' => '1.00 MB', // Ukuran file dalam format yang mudah dibaca
'type' => 'image/jpeg', // MIME type
'uploaded_at' => '2023-05-20 15:30:45', // Waktu upload
'thumbnails' => [ // Informasi thumbnail jika dikonfigurasi
'300x200' => '2023/05/300x200/encrypted_filename.jpg',
'150x100' => '2023/05/150x100/encrypted_filename.jpg'
]
]
]
Dalam data yang divalidasi ($result['data']
), field file akan berisi path file yang diupload:
// Struktur $result['data'] untuk form dengan field file
[
'title' => 'My Article',
'image' => 'uploads/images/encrypted_filename.jpg' // Path file relatif
]
Untuk mengupload multiple file, Anda dapat menggunakan array notation dalam nama field:
// HTML Form
<form method="post" enctype="multipart/form-data">
<input type="text" name="title">
<input type="file" name="images[]" multiple>
<button type="submit">Upload</button>
</form>
// Controller
public function uploadMultipleFiles(): void
{
$form = $this->createForm();
// Konfigurasi form dengan field file multiple
$form->fields([
'title' => 'Title|5|Judul minimal 5 karakter',
'images' => 'File|jpg,png,gif|Gambar maksimal 2MB' // Validasi untuk setiap file
])
->setUpload([
'maxSize' => '2MB',
'allowedTypes' => ['jpg', 'png', 'gif'],
'allowedExtensions' => ['jpg', 'png', 'gif'],
'thumbnail' => ['300x200', '150x100']
]);
if ($this->isPost()) {
// Proses form
$result = $form->process();
if ($result['success']) {
// Form valid dan file berhasil diupload
$data = $result['data'];
$title = $data['title'];
// Informasi file yang diupload
$files = $result['files']['images'];
// Simpan data ke database
foreach ($files as $file) {
$this->useModels('Gallery', 'save', [
'title' => $title,
'image_path' => $file['path'],
'image_name' => $file['orig_name'],
'image_type' => $file['file_type'],
'image_size' => $file['file_size']
]);
}
$this->setFlash('success', count($files) . ' file berhasil diupload');
$this->redirect('/gallery');
return;
}
}
// Render form
$this->assignVars($form->Response());
$this->render('gallery/upload');
}
NexaForm menyediakan method deleteFile()
untuk menghapus file yang sudah diupload:
public function deleteImage(): void
{
$form = $this->createForm();
// Mendapatkan ID gambar dari parameter
$imageId = $this->getParam('id');
// Mendapatkan data gambar dari database
$image = $this->useModels('Gallery', 'getById', [$imageId]);
if (!$image) {
$this->setFlash('error', 'Gambar tidak ditemukan');
$this->redirect('/gallery');
return;
}
// Hapus file dari penyimpanan
$form->deleteFile($image['image_path']);
// Cek hasil penghapusan
$deleteResult = $form->getDeleteResult();
if ($deleteResult && $deleteResult['main_file']) {
// Hapus data dari database
$this->useModels('Gallery', 'delete', [$imageId]);
$this->setFlash('success', 'Gambar berhasil dihapus');
} else 'Gagal menghapus file'; $this->setFlash('error', $error);
$this->redirect('/gallery');
}
Method deleteFile()
dapat menerima string path file atau array informasi file:
// Hapus file dengan path
$form->deleteFile('uploads/images/file.jpg');
// Hapus file dengan array informasi file
$form->deleteFile([
'path' => 'uploads/images/file.jpg',
'thumb_path' => 'uploads/images/file_thumb.jpg'
]);
// Mendapatkan hasil penghapusan
$deleteResult = $form->getDeleteResult();
// [
// 'main_file' => true, // Apakah file utama berhasil dihapus
// 'thumb_file' => true, // Apakah thumbnail berhasil dihapus
// 'errors' => [] // Array error jika ada
// ]
// Mendapatkan error penghapusan
$deleteError = $form->getDeleteError();
Untuk menampilkan file yang diupload dalam template, Anda dapat menggunakan informasi file yang disimpan:
public function viewGallery(): void
{
// Mendapatkan semua gambar dari database
$images = $this->useModels('Gallery', 'getAll');
// Assign data ke template
$this->assignVar('images', $images);
// Render template
$this->render('gallery/view');
}
Di template, Anda dapat menampilkan gambar seperti ini:
<div class="gallery">
{{#each images}}
<div class="gallery-item">
<h3>{{title}}</h3>
<img src="/{{image_path}}" alt="{{title}}">
<p>Original: {{image_name}}</p>
<p>Size: {{image_size}} KB</p>
<a href="/gallery/delete/{{id}}" class="btn btn-danger">Delete</a>
</div>
{{/each}}
</div>
Untuk menampilkan preview file yang dipilih sebelum diupload, Anda dapat menggunakan JavaScript:
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="image">Image</label>
<input type="file" name="image" id="image" class="form-control-file" onchange="previewImage(this)">
<div id="image-preview" class="mt-2"></div>
{{{image_info}}}
{{#if errors_image}}
<div class="error-message">{{errors_image}}</div>
{{/if}}
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>
<script>
function previewImage(input) {
const preview = document.getElementById('image-preview');
preview.innerHTML = '';
if (input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
const img = document.createElement('img');
img.src = e.target.result;
img.style.maxWidth = '300px';
img.style.maxHeight = '200px';
img.className = 'img-thumbnail';
preview.appendChild(img);
}
reader.readAsDataURL(input.files[0]);
}
}
</script>
Berikut adalah beberapa praktik terbaik dalam menangani upload file:
encrypt_name
untuk mencegah overwrite file dan meningkatkan keamanancreate_thumb
untuk gambar yang akan ditampilkan di halaman web