Tutorial Codeigniter: Upload File

Pada tutorial sebelumnya, kita sudah menyelesaikan fitur CRUD. Ini merupakan fitur utama yang harus ada di dalam aplikasi.

Tetapi, masih ada yang kurang…

Apa itu?

Gambar untuk produk.

Gambar produk tidak bisa ditampilkan

Gambar produk belum ada. Sehingga akan ditampilkan broken image.

Gambar untuk produk, kita akan diisi dengan nilai default.jpg. Jika tidak ada gambar yang di-upload.

Kalau kita lihat alamat path yang dipakai, gambar ini akan berlokasi di /upload/product/default.jpg.

Sedangkan kita belum punya folder dan file default.jpg.

Bagaimana cara mengatasinya?

Sederhana…

Kita tinggal buat folder baru di dalam project dengan nama upload, lalu di dalamnya berisi folder lagi bernama product.

Membuat folder upload

…dan di sanalah kita akan menaruh file default.jpg.

Gambar default.jpg akan menjadi gambar placeholder apabila tidak ada gambar yang di-upload.

Sebagai contoh, saya akan mengisinya dengan gambar “No Image” yang saya buat dengan GIMP.

Membuat gambar di GIMP

Jika kamu ingin menggunakan gambar ini.

Silahkan download: 🖼 default.jpg

Setelah itu, silahkan taruh gambar tersebut pada folder upload/product/

Maka hasilnya:

List produk dengan image

Bagus!

Tapi masalahanya:

Tidak semua produk akan menggunakan gambar default.jpg.

Karena itu, kita harus membuatkan fitur upload, agar admin bisa menentukan gambar yang ia sukai.

Bagaimana caranya?

Mari kita bahas…

Membuat Fitur Upload pada Codeigniter

Sebelum kita membuat fitur upload, kita perlu pahami dulu bagaimana konsep kerjanya.

Upload file memiliki alur proeses seperti ini:

  1. User mengirim file melalui form;
  2. File di-upload ke server dan disimpan dalam folder tmp dulu;
  3. Kita pindahkan file yang ada di direktori tmp ke dalam direktori upload/product/ yang sudah kita buat;
  4. Selesai.

Terdengar sederhana…

Tapi mari kita lihat dalam prekteknya.

Silahkan buka model Product_model.php, kemudian tambahakan method _uploadImage() tepat di bawah method delete().

Berikut ini isi kode method _uploadImage():

private function _uploadImage()
{
    $config['upload_path']          = './upload/product/';
    $config['allowed_types']        = 'gif|jpg|png';
    $config['file_name']            = $this->product_id;
    $config['overwrite']			= true;
    $config['max_size']             = 1024; // 1MB
    // $config['max_width']            = 1024;
    // $config['max_height']           = 768;

    $this->load->library('upload', $config);

    if ($this->upload->do_upload('image')) {
        return $this->upload->data("file_name");
    }
    
    return "default.jpg";
}

Sehingga akan menjadi seperti ini:

Method untuk upload file

Apa yang dilakuakn oleh method ini?

Sederhana…

  1. Kita membuat konfigurasi untuk upload file seperti:
    • upload_path untuk menentukan alamat lokasi file akan terupload
    • file_name untuk menentukan nama file. Oya, nama file akan kita ambil dari ID produk. Karena itu, kita mengisinya dengan $this->product_id.
    • overwrite untuk menindih file yang sudah ter-upload saat di-upload file baru (edit data).
    • allowed_types untuk membatasi tipe file yang boleh di-upload.
    • max_size untuk menentukan batasan ukuran file.
    • max_wdith dan max_height sengaja saya komentari agar tidak diaktifkan. Ini fungsinya untuk membatasi ukuran lebar dan tinggi image. Apabila image yang di-upload melebihi dari ukuran yang ditetapkan, maka upload akan gagal.
  2. Kita me-load library upload dengan konfigurasi yang sudah ditentukan.

    $this->load->library('upload', $config);
    
  3. Kita akan mengembalikan nama file yang sudah di-upload. Apabila upload gagal, maka kembalikan saja default.jpg.

Mengapa method ini diberikan modifier private?

Bukankah nanti kita akan memanggilnya dari Controller?

Oh tidak-tidak…

Kita tidak akan memanggil method ini dari Controller. Karena itu, kita memberikan modifier priavate.

Method ini nanti akan dipanggil dari class Product_model (class itu sendiri), pada method save() dan update().

Nah, sekarang tugas kita adalah mengubah method save() dan update().

Menggunakan Method _uploadImage()

Coba tebak?

Di mana kita akan memanggil method ini?

Yap! Method ini akan kita gunakan untuk mengisi properti $this->image.

Silahkan ubah method save() dan update() menjadi seperti ini:

Mengubah method save() dan update()

Khusus untuk method update(), kita membuat pengecekan seperti ini:

if (!empty($_FILES["image"]["name"])) {
    $this->image = $this->_uploadImage();
} else {
    $this->image = $post["old_image"];
}

Artinya, jika ada file yang di-upload saat mengedit data, maka upload file-nya.

Tapi kalau tidak ada, cukup gunakan nama file yang sudah ada (old_image).

Nilai old_image kita dapatkan dari form, karena pada edit_form.php kita sudah membuat field ini dengan tipe hidden.

old image pada form

Percobaan Upload File

Sebelum mencoba melakukan upload, kita harus ubah dulu hak akses dari direktori upload.

Jika kamu menggunakan Windows, kamu tidak perlu melakukan ini.

Tapi, bagi kamu yang menggunakan Linux, ini harus dilakukan agar aplikasi dapat membuat file baru di dalam direktori upload.

Silahkan ketik perintah berikut:

sudo chmod 777 /var/www/html/tokobuah/upload/ -R

Atau pada terminal di VS Code, ketik seperti ini:

sudo chmod 777 upload/ -R

Kita akan diminta password, silahkan isi dengan password yang kamu gunakan di komputermu.

Mengubah hak akses direktori

Setelah itu, silahkan coba tambahkan produk baru dan jangan lupa sertakan gambarnya.

Menambahkan data baru

Setelah itu, klik Save dan buka halaman list products.

Maka hasilnya:

Hasil upload data di list product

Jika kita mengecek pada direktori project, maka akan ada file baru di sana.

Hasil upload data di dalam direktori project

Selamat, kita sudah berhasil membuat fitur upload 👏👏👏…

…Tapi masih ada yang kurang.

Apa itu?

Ketika kita menghapus data, filenya akan tetap ada di dalam aplikasi. Karena belum ada fungsi untuk menghapus file.

Mari kita perbaiki…

Menghapus File yang di-upload

Kita membutuhkan sebuah method khusus untuk menghapus file yang telah di-upload.

Silahkan tambahkan method berikut pada class Product_model, tepat di bawah method _uploadImage().

private function _deleteImage($id)
{
    $product = $this->getById($id);
    if ($product->image != "default.jpg") {
	    $filename = explode(".", $product->image)[0];
		return array_map('unlink', glob(FCPATH."upload/product/$filename.*"));
    }
}

Sehingga akan menjadi seperti ini:

Method untuk menghapus file

Terakhir, panggil method _deleteImage() pada method delete().

Method untuk menghapus data dan file

Oke, sekarang kita sudah bisa menghapus data dan juga file yang terupload.

Mari kita coba…

Menghapus data dan file pada aplikasi

Yep! berhasil 🎉

Mungkin kamu akan bertanya,

Mengapa ada dua file yang terhapus?

Jadi gini…

Coba perhatikan method-nya, khususnya kode yang ada di dalam if.

if ($product->image != "default.jpg") {
    $filename = explode(".", $product->image)[0];
	return array_map('unlink', glob(FCPATH."upload/product/$filename.*"));
}

Di sana kita mengambil nama file dengan fungsi exlode(). Lalu kita cari file berdasarkan nama tersbut dengan fungsi glob().

Setelah file-file ditemukan, lalu kita gunakan fungsi array_map() untuk mengeksekusi fungsi unlink() pada tiap file yang ditemukan.

Tanda bitang (*) setelah $filename artinya semua ektensi dipilih.

$filename.*

(pengguna Linux pasti paham 😉)

Ini nanti akan menghapus semua file dengan nama yang sama dan apapun ekstensinya.

Mengapa demikian?

Karena pada fungsi upload yang kita buat, di sana kita membolehkan untuk upload file dengan ekstensi jpg, gif, dan png.

Ketika data diedit dan gambar yang di-upload berekstensi berbeda dengan yang sudah ada di server…

…maka ia akan membuat file baru.

Misalnya di server sudah ada 123.jpg, lalu di-upload lagi—misal file .png— maka nanti akan dibuat lagi 123.png.

Mengapa bisa begitu? Bukankah kita sudah memberikan konfigurasi overwrite = true?

overwrite pada konfigurasi upload, hanya akan menindih file dengan nama dan ekstensi yang sama.

Misal:

Di server sudah ada 123.jpg. Ketika kita upload file lagi dengan ekstensi yang sama, maka 123.jpg akan ditindih dengan file yang baru.

Apa Selanjutnya?

Kita sudah berhasil membuat fitur upload. Tentu ini masih belum sempurna.

Karena…

Masih ada fitur yang perlu dibuat, seperti:

  • Crop image sebelum di-upload;
  • Upload Banyak gambar;
  • Upload via Ajax;
  • dll.

Selanjutnya silahkan dikembangkan sendiri.

Selamat mencoba.

Oya, source code tutorial ini dapat anda lihat & download di Github.

[🎁 Download Source Code]