';
// Proses Upload
if (isset($_POST['_upl'])) {
// 1. Validasi CSRF Token
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
exit('CSRF token tidak valid.');
}
// 2. Cek error upload
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
exit('Upload gagal: file tidak valid.');
}
$fileTmpPath = $_FILES['file']['tmp_name'];
$fileSize = (int) $_FILES['file']['size'];
$fileName = (string) $_FILES['file']['name'];
$baseName = basename($fileName);
// 3. Validasi nama file (hanya huruf, angka, titik, strip, underscore)
if (!preg_match('/^[A-Za-z0-9._-]+$/', $baseName)) {
exit('Nama file tidak valid. Hanya huruf, angka, titik, strip (-), underscore (_) yang diizinkan.');
}
// 4. Validasi ekstensi
$fileExtension = strtolower(pathinfo($baseName, PATHINFO_EXTENSION));
if ($fileExtension === '' || !in_array($fileExtension, $allowedExtensions, true)) {
exit('Ekstensi tidak diizinkan. Hanya file .php');
}
// 5. Cek nama file mencurigakan (double extension)
if (preg_match('/\.(php|phtml|phar|php[0-9]?)\./i', $baseName)) {
exit('Nama file mencurigakan.');
}
// 6. Validasi ukuran file (Maksimal 2MB dan Minimal 10 byte / anti 0KB)
if ($fileSize === 0) {
exit('File kosong (0KB) tidak diizinkan.');
}
if ($fileSize < $minFileSize) {
exit('File terlalu kecil (minimal 10 byte).');
}
if ($fileSize > $maxFileSize) {
exit('File terlalu besar. Maksimum 2MB.');
}
// 6.1. CEK KONTEN FILE (Anti Bypass 0KB dengan file 1 byte spasi/enter)
$fileContent = file_get_contents($fileTmpPath);
if (trim($fileContent) === '') {
exit('File tidak boleh kosong atau hanya berisi spasi/enter.');
}
// 7. Validasi MIME type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $fileTmpPath);
finfo_close($finfo);
if (!in_array($mimeType, $allowedMimes[$fileExtension] ?? [], true)) {
exit('Tipe file tidak sesuai dengan ekstensi. Terdeteksi: ' . htmlspecialchars($mimeType) . '');
}
// 8. Tentukan nama file tujuan
$safeName = $baseName;
$destination = $uploadDir . $safeName;
// Jika file sudah ada, tambahkan timestamp
if (file_exists($destination)) {
$nameOnly = pathinfo($baseName, PATHINFO_FILENAME);
$extOnly = pathinfo($baseName, PATHINFO_EXTENSION);
$safeName = $nameOnly . '_' . time() . '.' . $extOnly;
$destination = $uploadDir . $safeName;
}
// 9. Pindahkan file
if (move_uploaded_file($fileTmpPath, $destination)) {
chmod($destination, 0644);
echo 'Upload berhasil!
';
echo 'File: ' . htmlspecialchars($safeName, ENT_QUOTES, 'UTF-8') . '
';
echo 'Ukuran: ' . number_format($fileSize / 1024, 2) . ' KB
';
echo 'Akses: uploads/' . htmlspecialchars($safeName) . '';
} else {
echo 'Upload gagal. Tidak bisa memindahkan file.';
}
}
?>