Cara Upload File di Slim Framework

Upload file adalah fitur yang harus ada di setiap aplikasi web.

Lalu bagaimana cara kita membuat fitur upload untuk RESTful API atau webservice?

Itulah yang akan kita pelajari pada tutorial ini.

Kenapa harus upload ke webservice?

Karena kita akan bisa upload file dari mana saja, dari aplikasi android, web, desktop, bot, dan sebagainya.

Konsep Upload File di Slim Framework

File yang di-upload ke aplikasi Slim dapat kita tangkap dengan fungsi atau method getUploadedFiles().

Fungsi ini akan menghasilkan sebuah array yang berisi objek dari data file yang di-upload.

Contoh:

Array
(
    [photo] => Slim\Http\UploadedFile Object
        (
            [file] => /tmp/php0yzLB3
            [name:protected] => install-slim.png
            [type:protected] => image/png
            [size:protected] => 90765
            [error:protected] => 0
            [sapi:protected] => 1
            [stream:protected] => 
            [moved:protected] => 
        )

)

Pada aplikasi client, pastikan membuat form-nya denga atribut enctype="multipart/form-data".

Karena kalau tidak ada itu, maka fungsi getUploadedFiles() akan menghasilkan sebuah array kosong.

Penjelasan lebih lengkap tentang fungsi ini dapat dibaca pada dokumentasi Slim.

Sekarang mari kita lanjutkan project yang sebelumnya…

Membuat Upload pada RESTful API

Pada project sebelumnya, kita memiliki kolom gambar untuk cover buku. Sekarang kita ingin mengisinya dengan gambar yang diupload oleh client.

Secara garis besar, cara kerjanya seperti ini:

  1. Upload File;
  2. Ambil nama File lalu simpan ke database;
  3. Balas dengan URL file.

Sederhana sekali.

Baiklah, sekarang mari kita buka file src/settings.php kemudian tambahkan pengaturan seperti ini.

'upload_directory' => __DIR__ . '/../public/uploads', // upload directory

Pengaturan ini untuk mententukan lokasi file yang akan kita upload.

pengaturan untuk upload file

Setelah itu, buat sebuah direktori baru di dalam public bernama uploads.

Membuat direktori untuk upload file

Berikutnya kita akan membuat rute upload-nya.

Silahkan buka file src/routes.php, kemudian tambahkan kode berikut di paling atas:

use Slim\Http\UploadedFile;

Kode tersebut berfungsi untuk mengimpor fungsi getUploadedFiles().

Impor fungsi upload

Selanjutnya, silahkan buat rute untuk upload file:

$app->post('/books/cover/{id}', function(Request $request, Response $response, $args) {
    
    $uploadedFiles = $request->getUploadedFiles();
    
    // handle single input with single file upload
    $uploadedFile = $uploadedFiles['cover'];
    if ($uploadedFile->getError() === UPLOAD_ERR_OK) {
        
        $extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
        
        // ubah nama file dengan id buku
        $filename = sprintf('%s.%0.8s', $args["id"], $extension);
        
        $directory = $this->get('settings')['upload_directory'];
        $uploadedFile->moveTo($directory . DIRECTORY_SEPARATOR . $filename);

        // simpan nama file ke database
        $sql = "UPDATE books SET cover=:cover WHERE book_id=:id";
        $stmt = $this->db->prepare($sql);
        $params = [
            ":id" => $args["id"],
            ":cover" => $filename
        ];
        
        if($stmt->execute($params)){
            // ambil base url dan gabungkan dengan file name untuk membentuk URL file
            $url = $request->getUri()->getBaseUrl()."/uploads/".$filename;
            return $response->withJson(["status" => "success", "data" => $url], 200);
        }
        
        return $response->withJson(["status" => "failed", "data" => "0"], 200);
    }
});

Rute tersebut akan kita akses melalui /books/cover/id dengan metode POST.

Pertama-tama kita akan menangkap data yang di-upload dengan fungsi ini.

$uploadedFiles = $request->getUploadedFiles();
    
// handle single input with single file upload
$uploadedFile = $uploadedFiles['cover'];

Berikutnya kita melakukan pengecekan, apakah uploadnya berhasil atau tidak.

if ($uploadedFile->getError() === UPLOAD_ERR_OK){
    //...
}

Oya, file yang diupload akan disimpan sementara di direktori tmp.

Setelah itu, kita buat dulu nama file. Karena kita ingin menyimpan nama filenya dengan id dari buku.

// ambil ekstensi file yang di-upload
$extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);

// ubah nama file dengan id buku
$filename = sprintf('%s.%0.8s', $args["id"], $extension);

Setelah itu, kita pindahkan file yang sudah di-upload ke direktori tujuan dengan fungsi ini.

$directory = $this->get('settings')['upload_directory'];
$uploadedFile->moveTo($directory . DIRECTORY_SEPARATOR . $filename);

Variabel $directory akan berisi alamat path (lokasi tujuan upload), sesuai dengan isi pada file src/settings.php yang sudah kita tentukan.

Terakhir, kita menyimpan nama file ke database dan membalas request.

// simpan nama file ke database
$sql = "UPDATE books SET cover=:cover WHERE book_id=:id";
$stmt = $this->db->prepare($sql);
$params = [
    ":id" => $args["id"],
    ":cover" => $filename
];

if($stmt->execute($params)){
    // ambil base url dan gabungkan dengan file name untuk membentuk URL file
    $url = $request->getUri()->getBaseUrl()."/uploads/".$filename;
    return $response->withJson(["status" => "success", "data" => $url], 200);
}

return $response->withJson(["status" => "failed", "data" => "0"], 200);

Kenapa kita tidak menyimpan full URL?

Karena bisa jadi nanti URL-nya berubah, maka kita harus lakukan update lagi.

Percobaan Upload File

Silahkan buka Postman untuk melakukan pengujian.

Pada Header, silahkan masukkan key seperti ini:

Header untuk upload file

Setelah itu, masuk ke bagian Body dan isi key-nya seperti ini:

Body untuk upload file

Sekarang kita bisa mulai upload dengan mengklik tombol Send.

upload file

Sukses! 🎉

Periksa hasilnya, silahkan buka URL tersebut.

upload file

Akhir Kata…

Itulah cara upload file di Slim Framework yang bisa diterapkan dalam aplikasimu.

Oya, contoh upload yang di atas, bisa menerima segala jenis file.

Sebenarnya ini kurang bagus, karena kita hanya butuh file gambar saja.

Lalu bagaimana caranya agar menerima file gambar saja?

Kita bisa melakukan filter atau pengecekan dengan atribut type.

Lebih detailnya, silahkan dipikirkan sendiri 😄.

Selamat berpikir…