Upload file adalah salah satu fitur inti dalam banyak aplikasi web modern. Dari e-commerce yang memungkinkan upload foto produk, sistem rekrutmen yang menerima CV dalam bentuk PDF, hingga media sosial yang mendukung unggahan foto dan video, semuanya membutuhkan mekanisme upload file yang aman dan andal. PHP, dengan fungsi bawaannya, sudah menyediakan infrastruktur dasar untuk menangani file upload. Namun, agar tidak menjadi celah keamanan, kita wajib menambahkan validasi dan praktik terbaik dalam implementasinya.
Dasar-Dasar Upload File di PHP
Saat pengguna memilih file dan menekan tombol upload, browser akan mengirimkan file tersebut ke server. Di PHP, file yang diterima otomatis ditempatkan pada direktori sementara. Informasi lengkap file seperti nama, ukuran, tipe, dan lokasi sementara tersimpan di dalam variabel superglobal $_FILES.
Setelah file sampai ke server, developer menggunakan fungsi move_uploaded_file() untuk memindahkan file dari folder sementara ke folder tujuan. Jika langkah ini dilewati, file akan hilang karena folder sementara dihapus secara otomatis setelah eksekusi script selesai.
Membuat Form HTML untuk Upload
Langkah pertama adalah membuat form di sisi frontend. Atribut enctype="multipart/form-data" sangat penting agar file bisa dikirim. Contoh:
<form action="upload.php" method="post" enctype="multipart/form-data">
<label>Pilih file:</label>
<input type="file" name="myfile" required>
<button type="submit" name="submit">Upload</button>
</form>
Tanpa multipart/form-data, file tidak akan terkirim dengan benar. Input bertipe file memungkinkan pengguna memilih file dari perangkat mereka.
Script PHP Sederhana
Script paling dasar untuk menangani upload di server tampak seperti ini:
<?php
if (isset($_POST['submit'])) {
$fileName = $_FILES['myfile']['name'];
$fileTmp = $_FILES['myfile']['tmp_name'];
move_uploaded_file($fileTmp, "uploads/" . $fileName);
echo "File berhasil diupload!";
}
?>
Script tersebut memang berfungsi, tetapi belum aman. Misalnya, jika seseorang mengupload file malware.php, lalu mencoba mengaksesnya di browser, server bisa dieksploitasi. Di sinilah validasi file menjadi sangat penting.
Mengapa Validasi File Penting?
Ada dua alasan utama kenapa validasi wajib dilakukan:
- Keamanan: Mencegah file berbahaya seperti script PHP atau executable disimpan di server.
- Kualitas Data: Memastikan file sesuai kebutuhan aplikasi, misalnya hanya menerima gambar untuk foto profil atau PDF untuk dokumen.
Tanpa validasi, sistem terbuka bagi serangan arbitrary file upload yang dapat membahayakan server dan data pengguna.
Validasi MIME Type
Validasi pertama adalah tipe file (MIME type). Cara paling aman adalah dengan fungsi mime_content_type().
$fileTmp = $_FILES['myfile']['tmp_name'];
$fileType = mime_content_type($fileTmp);
$allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
if (!in_array($fileType, $allowedTypes)) {
die("Tipe file tidak diizinkan.");
}
Dengan cara ini, file teks atau script yang menyamar sebagai gambar akan ditolak.
Validasi Ekstensi
Selain MIME type, kita juga harus memeriksa ekstensi file:
$fileName = $_FILES['myfile']['name'];
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$allowedExt = ['jpg', 'jpeg', 'png', 'pdf'];
if (!in_array($fileExt, $allowedExt)) {
die("Ekstensi file tidak valid.");
}
Mengecek ekstensi mencegah pengguna mengupload file dengan ekstensi yang tidak diizinkan.
Membatasi Ukuran File
Ukuran file yang terlalu besar bisa menghabiskan storage atau bandwidth server. Batas maksimal bisa ditentukan, misalnya 2MB:
$fileSize = $_FILES['myfile']['size'];
$maxSize = 2 * 1024 * 1024; // 2MB
if ($fileSize > $maxSize) {
die("Ukuran file terlalu besar. Maksimal 2MB.");
}
Selain validasi di script, pastikan juga mengatur upload_max_filesize dan post_max_size di file php.ini.
Menangani Error Upload
PHP menyediakan kode error untuk setiap upload melalui $_FILES['myfile']['error']:
0: Tidak ada error.1: File melebihiupload_max_filesize.4: Tidak ada file yang diupload.
Contoh pengecekan:
if ($_FILES['myfile']['error'] !== UPLOAD_ERR_OK) {
die("Terjadi error saat upload file.");
}
Hal ini membantu memberikan feedback yang lebih jelas kepada pengguna.
Menyimpan File dengan Nama Unik
Menggunakan nama file asli berisiko menimpa file yang sudah ada. Solusinya, gunakan nama unik:
$newName = uniqid("file_", true) . "." . $fileExt;
move_uploaded_file($fileTmp, "uploads/" . $newName);
Dengan cara ini, file foto.jpg yang diupload banyak pengguna tidak akan saling menimpa.
Studi Kasus: Upload Gambar Profil dengan Validasi
Misalkan aplikasi hanya menerima gambar JPG/PNG dengan ukuran maksimal 1MB. Contoh implementasi:
<?php
if (isset($_POST['submit'])) {
$fileName = $_FILES['myfile']['name'];
$fileTmp = $_FILES['myfile']['tmp_name'];
$fileSize = $_FILES['myfile']['size'];
$fileError = $_FILES['myfile']['error'];
if ($fileError !== UPLOAD_ERR_OK) {
die("Upload gagal. Kode error: " . $fileError);
}
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$allowedExt = ['jpg', 'jpeg', 'png'];
if (!in_array($fileExt, $allowedExt)) {
die("Ekstensi file tidak valid.");
}
if ($fileSize > 1024 * 1024) {
die("Ukuran file terlalu besar. Maksimal 1MB.");
}
$fileType = mime_content_type($fileTmp);
$allowedTypes = ['image/jpeg', 'image/png'];
if (!in_array($fileType, $allowedTypes)) {
die("Tipe file tidak valid.");
}
$newName = uniqid("profile_", true) . "." . $fileExt;
$uploadDir = "uploads/";
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
if (move_uploaded_file($fileTmp, $uploadDir . $newName)) {
echo "Upload berhasil! Disimpan sebagai: " . $newName;
} else {
echo "Gagal menyimpan file.";
}
}
?>
Kode ini sudah cukup aman untuk digunakan dalam proyek nyata.
Upload Multiple Files
Selain single upload, PHP juga mendukung upload beberapa file sekaligus dengan atribut multiple di input form:
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="myfiles[]" multiple>
<button type="submit" name="submit">Upload</button>
</form>
Script PHP untuk menanganinya:
<?php
if (isset($_POST['submit'])) {
foreach ($_FILES['myfiles']['tmp_name'] as $key => $tmpName) {
$fileName = $_FILES['myfiles']['name'][$key];
$fileSize = $_FILES['myfiles']['size'][$key];
$fileError = $_FILES['myfiles']['error'][$key];
if ($fileError === UPLOAD_ERR_OK) {
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$newName = uniqid("multi_", true) . "." . $fileExt;
move_uploaded_file($tmpName, "uploads/" . $newName);
echo "File $fileName berhasil diupload sebagai $newName<br>";
}
}
}
?>
Dengan cara ini, pengguna bisa mengupload banyak file sekaligus dalam satu kali submit.
Tips Keamanan Lanjutan
- Gunakan
getimagesize()untuk memastikan file benar-benar gambar. Fungsi ini membaca dimensi gambar dan akan gagal jika file bukan gambar.if (getimagesize($fileTmp) === false) { die("File bukan gambar valid."); } - Batasi akses folder upload. Misalnya dengan menambahkan file
.htaccessagar file.phptidak bisa dieksekusi. - Gunakan random hash pada nama file untuk mengurangi risiko konflik.
- Scan file dengan antivirus eksternal jika server digunakan pada skala besar.
- Hindari menyimpan file di root domain, simpan di folder khusus di luar
public_htmllalu akses melalui script.
Praktik Terbaik
- Simpan metadata file (nama asli, ukuran, path, uploader) di database.
- Terapkan validasi ganda: sisi client (JavaScript) dan sisi server (PHP).
- Berikan feedback jelas kepada pengguna ketika upload gagal.
- Hindari menampilkan path asli file di server.
