sudo apt install apache2 -y
sudo systemctl enable apache2
sudo systemctl start apache2
sudo apt install mariadb-server mariadb-client -y
sudo systemctl enable mariadb
sudo systemctl start mariadb
<?php
/**
* Simple File Manager - Gerenciador de Arquivos Web
* Similar ao Tiny File Manager mas mais leve
* Único arquivo PHP - basta copiar para o servidor
*/
// ==================== CONFIGURAÇÕES ====================
$use_auth = true; // true = exige login, false = acesso livre
$auth_users = array(
'admin' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // senha: password
'user' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi' // senha: password
);
$readonly_users = array('user'); // usuários que só podem visualizar
$root_path = $_SERVER['DOCUMENT_ROOT']; // pasta raiz a gerenciar
$root_url = ''; // URL relativa
$max_upload_size = 50 * 1024 * 1024; // 50MB
$show_hidden = false; // mostrar arquivos ocultos (começam com .)
$allowed_extensions = array(); // deixe vazio para permitir tudo, ou array('jpg','png','php')
// ==================== SESSÃO E AUTENTICAÇÃO ====================
if (!isset($_SESSION)) {
session_start();
}
function is_logged_in() {
global $use_auth;
if (!$use_auth) return true;
return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
}
function is_readonly() {
global $readonly_users;
if (!is_logged_in()) return true;
if (isset($_SESSION['username']) && in_array($_SESSION['username'], $readonly_users)) {
return true;
}
return false;
}
function login($user, $pass) {
global $auth_users;
if (isset($auth_users[$user]) && password_verify($pass, $auth_users[$user])) {
$_SESSION['logged_in'] = true;
$_SESSION['username'] = $user;
return true;
}
return false;
}
function logout() {
unset($_SESSION['logged_in']);
unset($_SESSION['username']);
session_destroy();
}
// Processar login/logout
if (isset($_GET['logout'])) {
logout();
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
if (isset($_POST['login'])) {
if (login($_POST['username'], $_POST['password'])) {
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
} else {
$login_error = 'Usuário ou senha incorretos!';
}
}
// ==================== FUNÇÕES UTILITÁRIAS ====================
function get_file_icon($ext) {
$icons = array(
'php' => '🐘', 'html' => '🌐', 'htm' => '🌐', 'css' => '🎨', 'js' => '⚡',
'jpg' => '🖼️', 'jpeg' => '🖼️', 'png' => '🖼️', 'gif' => '🖼️', 'svg' => '🖼️',
'pdf' => '📄', 'doc' => '📝', 'docx' => '📝', 'txt' => '📃', 'md' => '📃',
'zip' => '📦', 'rar' => '📦', 'tar' => '📦', 'gz' => '📦',
'mp3' => '🎵', 'mp4' => '🎬', 'avi' => '🎬', 'mkv' => '🎬',
'sql' => '🗄️', 'json' => '📊', 'xml' => '📊', 'csv' => '📊',
'folder' => '📁'
);
return isset($icons[$ext]) ? $icons[$ext] : '📄';
}
function format_size($size) {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$i = 0;
while ($size >= 1024 && $i < count($units) - 1) {
$size /= 1024;
$i++;
}
return round($size, 2) . ' ' . $units[$i];
}
function get_mime_type($file) {
if (function_exists('mime_content_type')) {
return mime_content_type($file);
}
if (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file);
finfo_close($finfo);
return $mime;
}
return 'application/octet-stream';
}
function is_text_file($file) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
$text_exts = array('php','html','htm','css','js','txt','md','json','xml','sql','csv','ini','conf','log','htaccess','sh','py','rb','java','c','cpp','h','go','rs','ts','vue','jsx','tsx','yaml','yml','dockerfile','nginx','apache');
return in_array($ext, $text_exts);
}
function is_image_file($file) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
return in_array($ext, array('jpg','jpeg','png','gif','bmp','svg','webp','ico'));
}
function safe_path($path) {
$path = str_replace('\\', '/', $path);
$path = preg_replace('/\.\.\//', '', $path);
$path = preg_replace('/\.\.\\\\/', '', $path);
return $path;
}
// ==================== PROCESSAMENTO DE AÇÕES ====================
$current_path = isset($_GET['p']) ? safe_path($_GET['p']) : '';
$full_path = $root_path . '/' . $current_path;
$full_path = realpath($full_path) ?: $root_path;
// Verificar se está dentro do root_path
if (strpos($full_path, realpath($root_path)) !== 0) {
$full_path = realpath($root_path);
$current_path = '';
}
$action = isset($_GET['action']) ? $_GET['action'] : '';
$message = '';
$error = '';
// Upload de arquivo
if (isset($_FILES['upload']) && is_logged_in() && !is_readonly()) {
$upload_file = $_FILES['upload'];
if ($upload_file['error'] === UPLOAD_ERR_OK) {
$target = $full_path . '/' . basename($upload_file['name']);
if (move_uploaded_file($upload_file['tmp_name'], $target)) {
$message = 'Arquivo enviado com sucesso!';
} else {
$error = 'Erro ao mover arquivo!';
}
} else {
$error = 'Erro no upload: ' . $upload_file['error'];
}
}
// Criar pasta
if (isset($_POST['new_folder']) && is_logged_in() && !is_readonly()) {
$folder_name = safe_path($_POST['folder_name']);
if ($folder_name && !file_exists($full_path . '/' . $folder_name)) {
if (mkdir($full_path . '/' . $folder_name, 0755, true)) {
$message = 'Pasta criada com sucesso!';
} else {
$error = 'Erro ao criar pasta!';
}
}
}
// Criar arquivo
if (isset($_POST['new_file']) && is_logged_in() && !is_readonly()) {
$file_name = safe_path($_POST['file_name']);
if ($file_name && !file_exists($full_path . '/' . $file_name)) {
if (file_put_contents($full_path . '/' . $file_name, '') !== false) {
$message = 'Arquivo criado com sucesso!';
} else {
$error = 'Erro ao criar arquivo!';
}
}
}
// Deletar
if ($action === 'delete' && isset($_GET['item']) && is_logged_in() && !is_readonly()) {
$item = $full_path . '/' . basename($_GET['item']);
if (is_dir($item)) {
if (rmdir($item)) {
$message = 'Pasta deletada!';
} else {
$error = 'Erro ao deletar pasta (deve estar vazia)!';
}
} else {
if (unlink($item)) {
$message = 'Arquivo deletado!';
} else {
$error = 'Erro ao deletar arquivo!';
}
}
}
// Renomear
if ($action === 'rename' && isset($_POST['old_name'], $_POST['new_name']) && is_logged_in() && !is_readonly()) {
$old = $full_path . '/' . basename($_POST['old_name']);
$new = $full_path . '/' . safe_path($_POST['new_name']);
if (rename($old, $new)) {
$message = 'Renomeado com sucesso!';
} else {
$error = 'Erro ao renomear!';
}
}
// Copiar
if ($action === 'copy' && isset($_POST['source'], $_POST['dest']) && is_logged_in() && !is_readonly()) {
$src = $full_path . '/' . basename($_POST['source']);
$dst = $full_path . '/' . safe_path($_POST['dest']);
if (copy($src, $dst)) {
$message = 'Copiado com sucesso!';
} else {
$error = 'Erro ao copiar!';
}
}
// Mover
if ($action === 'move' && isset($_POST['source'], $_POST['dest']) && is_logged_in() && !is_readonly()) {
$src = $full_path . '/' . basename($_POST['source']);
$dst = $full_path . '/' . safe_path($_POST['dest']);
if (rename($src, $dst)) {
$message = 'Movido com sucesso!';
} else {
$error = 'Erro ao mover!';
}
}
// Salvar edição
if (isset($_POST['save_file']) && isset($_POST['file_path'], $_POST['content']) && is_logged_in() && !is_readonly()) {
$file = safe_path($_POST['file_path']);
$file_full = $root_path . '/' . $file;
if (file_put_contents($file_full, $_POST['content']) !== false) {
$message = 'Arquivo salvo com sucesso!';
} else {
$error = 'Erro ao salvar arquivo!';
}
}
// Download
if ($action === 'download' && isset($_GET['item'])) {
$file = $full_path . '/' . basename($_GET['item']);
if (is_file($file)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
}
// Visualizar
if ($action === 'view' && isset($_GET['item'])) {
$file = $full_path . '/' . basename($_GET['item']);
if (is_file($file)) {
$mime = get_mime_type($file);
header('Content-Type: ' . $mime);
readfile($file);
exit;
}
}
// Editar
$edit_file = null;
$edit_content = '';
if ($action === 'edit' && isset($_GET['item']) && is_logged_in()) {
$file = $full_path . '/' . basename($_GET['item']);
if (is_file($file) && is_text_file($file)) {
$edit_file = $current_path . '/' . basename($_GET['item']);
$edit_content = file_get_contents($file);
}
}
// ==================== LISTAR ARQUIVOS ====================
$items = array();
if (is_dir($full_path)) {
$dh = opendir($full_path);
while (($file = readdir($dh)) !== false) {
if ($file === '.' || $file === '..') continue;
if (!$show_hidden && $file[0] === '.') continue;
$item_path = $full_path . '/' . $file;
$is_dir = is_dir($item_path);
$ext = $is_dir ? 'folder' : strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (!$is_dir && !empty($allowed_extensions) && !in_array($ext, $allowed_extensions)) {
continue;
}
$items[] = array(
'name' => $file,
'is_dir' => $is_dir,
'size' => $is_dir ? '-' : format_size(filesize($item_path)),
'modified' => date('d/m/Y H:i', filemtime($item_path)),
'perms' => substr(sprintf('%o', fileperms($item_path)), -4),
'ext' => $ext,
'icon' => get_file_icon($ext)
);
}
closedir($dh);
// Ordenar: pastas primeiro, depois arquivos
usort($items, function($a, $b) {
if ($a['is_dir'] !== $b['is_dir']) {
return $a['is_dir'] ? -1 : 1;
}
return strcasecmp($a['name'], $b['name']);
});
}
// Breadcrumb
$breadcrumbs = array();
if ($current_path) {
$parts = explode('/', $current_path);
$path_build = '';
foreach ($parts as $part) {
if ($part) {
$path_build .= ($path_build ? '/' : '') . $part;
$breadcrumbs[] = array('name' => $part, 'path' => $path_build);
}
}
}
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple File Manager</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #0f172a;
color: #e2e8f0;
min-height: 100vh;
}
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
/* Header */
.header {
background: #1e293b;
border-bottom: 1px solid #334155;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.header h1 { font-size: 1.5rem; color: #60a5fa; display: flex; align-items: center; gap: 10px; }
.header-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.user-info { color: #94a3b8; font-size: 0.9rem; }
/* Buttons */
.btn {
padding: 8px 16px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.2s;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 6px;
}
.btn-primary { background: #3b82f6; color: white; }
.btn-primary:hover { background: #2563eb; }
.btn-success { background: #10b981; color: white; }
.btn-success:hover { background: #059669; }
.btn-danger { background: #ef4444; color: white; }
.btn-danger:hover { background: #dc2626; }
.btn-warning { background: #f59e0b; color: white; }
.btn-warning:hover { background: #d97706; }
.btn-secondary { background: #475569; color: white; }
.btn-secondary:hover { background: #334155; }
.btn-sm { padding: 5px 10px; font-size: 0.8rem; }
/* Messages */
.alert {
padding: 12px 16px;
border-radius: 6px;
margin: 15px 0;
display: flex;
align-items: center;
gap: 10px;
}
.alert-success { background: #064e3b; color: #6ee7b7; border: 1px solid #059669; }
.alert-error { background: #450a0a; color: #fca5a5; border: 1px solid #dc2626; }
/* Breadcrumb */
.breadcrumb {
background: #1e293b;
padding: 10px 20px;
border-bottom: 1px solid #334155;
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.breadcrumb a { color: #60a5fa; text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb span { color: #64748b; }
/* Toolbar */
.toolbar {
background: #1e293b;
padding: 15px 20px;
border-bottom: 1px solid #334155;
display: flex;
gap: 10px;
flex-wrap: wrap;
align-items: center;
}
.toolbar form { display: flex; gap: 10px; align-items: center; }
.toolbar input[type="text"], .toolbar input[type="file"] {
background: #0f172a;
border: 1px solid #334155;
color: #e2e8f0;
padding: 8px 12px;
border-radius: 6px;
font-size: 0.9rem;
}
.toolbar input[type="text"]:focus {
outline: none;
border-color: #3b82f6;
}
/* File Table */
.file-table {
width: 100%;
border-collapse: collapse;
background: #1e293b;
border-radius: 8px;
overflow: hidden;
margin-top: 0;
}
.file-table th {
background: #0f172a;
padding: 12px 16px;
text-align: left;
font-weight: 600;
color: #94a3b8;
border-bottom: 1px solid #334155;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.file-table td {
padding: 12px 16px;
border-bottom: 1px solid #334155;
font-size: 0.9rem;
}
.file-table tr:hover { background: #252f47; }
.file-table tr:last-child td { border-bottom: none; }
.file-name {
display: flex;
align-items: center;
gap: 10px;
color: #e2e8f0;
text-decoration: none;
}
.file-name:hover { color: #60a5fa; }
.file-icon { font-size: 1.3rem; }
.file-actions {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.file-size { color: #94a3b8; font-family: monospace; }
.file-date { color: #64748b; font-size: 0.85rem; }
.file-perms {
color: #fbbf24;
font-family: monospace;
font-size: 0.8rem;
background: #292524;
padding: 2px 6px;
border-radius: 4px;
}
/* Empty state */
.empty-state {
text-align: center;
padding: 60px 20px;
color: #64748b;
}
.empty-state-icon { font-size: 4rem; margin-bottom: 15px; }
/* Login Form */
.login-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #0f172a;
}
.login-box {
background: #1e293b;
padding: 40px;
border-radius: 12px;
border: 1px solid #334155;
width: 100%;
max-width: 400px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.login-box h2 {
text-align: center;
margin-bottom: 30px;
color: #60a5fa;
font-size: 1.8rem;
}
.login-box .form-group { margin-bottom: 20px; }
.login-box label {
display: block;
margin-bottom: 8px;
color: #94a3b8;
font-size: 0.9rem;
}
.login-box input {
width: 100%;
padding: 12px;
background: #0f172a;
border: 1px solid #334155;
color: #e2e8f0;
border-radius: 6px;
font-size: 1rem;
}
.login-box input:focus {
outline: none;
border-color: #3b82f6;
}
.login-box button {
width: 100%;
padding: 12px;
margin-top: 10px;
}
.login-error {
background: #450a0a;
color: #fca5a5;
padding: 10px;
border-radius: 6px;
margin-bottom: 20px;
text-align: center;
font-size: 0.9rem;
}
/* Editor */
.editor-container {
background: #1e293b;
border-radius: 8px;
overflow: hidden;
margin-top: 15px;
}
.editor-header {
background: #0f172a;
padding: 12px 16px;
border-bottom: 1px solid #334155;
display: flex;
justify-content: space-between;
align-items: center;
}
.editor-header h3 { color: #60a5fa; font-size: 1rem; }
.editor-form { padding: 0; }
.editor-textarea {
width: 100%;
min-height: 500px;
background: #0f172a;
color: #e2e8f0;
border: none;
padding: 16px;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.6;
resize: vertical;
outline: none;
}
.editor-footer {
background: #0f172a;
padding: 12px 16px;
border-top: 1px solid #334155;
display: flex;
justify-content: space-between;
align-items: center;
}
/* Modal */
.modal-overlay {
display: none;
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-overlay.active { display: flex; }
.modal {
background: #1e293b;
border-radius: 12px;
border: 1px solid #334155;
padding: 25px;
width: 90%;
max-width: 500px;
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
.modal h3 { color: #60a5fa; margin-bottom: 20px; }
.modal .form-group { margin-bottom: 15px; }
.modal label { display: block; margin-bottom: 8px; color: #94a3b8; }
.modal input {
width: 100%;
padding: 10px;
background: #0f172a;
border: 1px solid #334155;
color: #e2e8f0;
border-radius: 6px;
}
.modal-actions {
display: flex;
gap: 10px;
justify-content: flex-end;
margin-top: 20px;
}
/* Responsive */
@media (max-width: 768px) {
.header { flex-direction: column; text-align: center; }
.toolbar { flex-direction: column; align-items: stretch; }
.toolbar form { width: 100%; }
.file-table th:nth-child(3),
.file-table td:nth-child(3),
.file-table th:nth-child(4),
.file-table td:nth-child(4) { display: none; }
.file-actions { flex-direction: column; }
.btn { padding: 6px 10px; font-size: 0.8rem; }
}
/* Scrollbar */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: #0f172a; }
::-webkit-scrollbar-thumb { background: #334155; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #475569; }
</style>
</head>
<body>
<?php if (!is_logged_in() && $use_auth): ?>
<!-- TELA DE LOGIN -->
<div class="login-container">
<div class="login-box">
<h2>📁 Simple File Manager</h2>
<?php if (isset($login_error)): ?>
<div class="login-error"><?php echo htmlspecialchars($login_error); ?></div>
<?php endif; ?>
<form method="POST">
<div class="form-group">
<label>Usuário</label>
<input type="text" name="username" placeholder="admin" required autofocus>
</div>
<div class="form-group">
<label>Senha</label>
<input type="password" name="password" placeholder="password" required>
</div>
<button type="submit" name="login" class="btn btn-primary">Entrar</button>
</form>
<p style="text-align: center; margin-top: 20px; color: #64748b; font-size: 0.85rem;">
Default: admin / password
</p>
</div>
</div>
<?php else: ?>
<!-- INTERFACE PRINCIPAL -->
<div class="header">
<h1>📁 Simple File Manager</h1>
<div class="header-actions">
<?php if (is_logged_in()): ?>
<span class="user-info">👤 <?php echo htmlspecialchars($_SESSION['username']); ?>
<?php if (is_readonly()): ?><span style="color: #f59e0b;">[Somente Leitura]</span><?php endif; ?>
</span>
<a href="?logout=1" class="btn btn-danger btn-sm">🚪 Sair</a>
<?php endif; ?>
</div>
</div>
<div class="breadcrumb">
<a href="?">🏠 Home</a>
<?php foreach ($breadcrumbs as $crumb): ?>
<span>/</span>
<a href="?p=<?php echo urlencode($crumb['path']); ?>"><?php echo htmlspecialchars($crumb['name']); ?></a>
<?php endforeach; ?>
</div>
<?php if ($message): ?>
<div class="container">
<div class="alert alert-success">✅ <?php echo htmlspecialchars($message); ?></div>
</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="container">
<div class="alert alert-error">❌ <?php echo htmlspecialchars($error); ?></div>
</div>
<?php endif; ?>
<?php if (!$edit_file): ?>
<!-- LISTAGEM DE ARQUIVOS -->
<div class="toolbar">
<?php if (is_logged_in() && !is_readonly()): ?>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="upload" required>
<button type="submit" class="btn btn-success btn-sm">📤 Upload</button>
</form>
<button onclick="showModal('folderModal')" class="btn btn-primary btn-sm">📁 Nova Pasta</button>
<button onclick="showModal('fileModal')" class="btn btn-primary btn-sm">📄 Novo Arquivo</button>
<?php endif; ?>
<span style="color: #64748b; margin-left: auto;">
📍 <?php echo htmlspecialchars($current_path ?: 'Root'); ?>
(<?php echo count($items); ?> itens)
</span>
</div>
<div class="container" style="padding-top: 0;">
<?php if (empty($items)): ?>
<div class="empty-state">
<div class="empty-state-icon">📂</div>
<p>Esta pasta está vazia</p>
</div>
<?php else: ?>
<table class="file-table">
<thead>
<tr>
<th>Nome</th>
<th>Tamanho</th>
<th>Modificado</th>
<th>Permissões</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
<?php if ($current_path): ?>
<tr>
<td colspan="5">
<a href="?p=<?php echo urlencode(dirname($current_path) === '.' ? '' : dirname($current_path)); ?>" class="file-name">
<span class="file-icon">⬆️</span> ..
</a>
</td>
</tr>
<?php endif; ?>
<?php foreach ($items as $item): ?>
<tr>
<td>
<?php if ($item['is_dir']): ?>
<a href="?p=<?php echo urlencode(($current_path ? $current_path . '/' : '') . $item['name']); ?>" class="file-name">
<span class="file-icon"><?php echo $item['icon']; ?></span>
<?php echo htmlspecialchars($item['name']); ?>
</a>
<?php else: ?>
<span class="file-name">
<span class="file-icon"><?php echo $item['icon']; ?></span>
<?php echo htmlspecialchars($item['name']); ?>
</span>
<?php endif; ?>
</td>
<td class="file-size"><?php echo $item['size']; ?></td>
<td class="file-date"><?php echo $item['modified']; ?></td>
<td><span class="file-perms"><?php echo $item['perms']; ?></span></td>
<td>
<div class="file-actions">
<?php if (!$item['is_dir']): ?>
<a href="?action=download&p=<?php echo urlencode($current_path); ?>&item=<?php echo urlencode($item['name']); ?>" class="btn btn-secondary btn-sm" title="Download">⬇️</a>
<?php if (is_text_file($full_path . '/' . $item['name'])): ?>
<a href="?action=edit&p=<?php echo urlencode($current_path); ?>&item=<?php echo urlencode($item['name']); ?>" class="btn btn-warning btn-sm" title="Editar">✏️</a>
<?php endif; ?>
<?php if (is_image_file($full_path . '/' . $item['name'])): ?>
<a href="?action=view&p=<?php echo urlencode($current_path); ?>&item=<?php echo urlencode($item['name']); ?>" target="_blank" class="btn btn-secondary btn-sm" title="Visualizar">👁️</a>
<?php endif; ?>
<?php endif; ?>
<?php if (is_logged_in() && !is_readonly()): ?>
<button onclick="renameItem('<?php echo addslashes($item['name']); ?>')" class="btn btn-secondary btn-sm" title="Renomear">📝</button>
<button onclick="copyItem('<?php echo addslashes($item['name']); ?>')" class="btn btn-secondary btn-sm" title="Copiar">📋</button>
<a href="?action=delete&p=<?php echo urlencode($current_path); ?>&item=<?php echo urlencode($item['name']); ?>"
onclick="return confirm('Tem certeza que deseja deletar <?php echo addslashes($item['name']); ?>?')"
class="btn btn-danger btn-sm" title="Deletar">🗑️</a>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<?php else: ?>
<!-- EDITOR DE TEXTO -->
<div class="container">
<div style="margin-bottom: 15px;">
<a href="?p=<?php echo urlencode($current_path); ?>" class="btn btn-secondary btn-sm">⬅️ Voltar</a>
</div>
<div class="editor-container">
<div class="editor-header">
<h3>✏️ Editando: <?php echo htmlspecialchars(basename($edit_file)); ?></h3>
<span style="color: #64748b; font-size: 0.85rem;"><?php echo htmlspecialchars($edit_file); ?></span>
</div>
<form method="POST" class="editor-form">
<input type="hidden" name="file_path" value="<?php echo htmlspecialchars($edit_file); ?>">
<textarea name="content" class="editor-textarea" spellcheck="false"><?php echo htmlspecialchars($edit_content); ?></textarea>
<div class="editor-footer">
<span style="color: #64748b; font-size: 0.85rem;">
<?php echo format_size(strlen($edit_content)); ?> |
<?php echo substr_count($edit_content, "\n") + 1; ?> linhas
</span>
<div>
<?php if (!is_readonly()): ?>
<button type="submit" name="save_file" class="btn btn-success">💾 Salvar</button>
<?php endif; ?>
</div>
</div>
</form>
</div>
</div>
<?php endif; ?>
<!-- MODAIS -->
<div class="modal-overlay" id="folderModal">
<div class="modal">
<h3>📁 Criar Nova Pasta</h3>
<form method="POST">
<div class="form-group">
<label>Nome da Pasta</label>
<input type="text" name="folder_name" placeholder="minha-pasta" required autofocus>
</div>
<div class="modal-actions">
<button type="button" onclick="hideModal('folderModal')" class="btn btn-secondary">Cancelar</button>
<button type="submit" name="new_folder" class="btn btn-primary">Criar</button>
</div>
</form>
</div>
</div>
<div class="modal-overlay" id="fileModal">
<div class="modal">
<h3>📄 Criar Novo Arquivo</h3>
<form method="POST">
<div class="form-group">
<label>Nome do Arquivo</label>
<input type="text" name="file_name" placeholder="arquivo.txt" required autofocus>
</div>
<div class="modal-actions">
<button type="button" onclick="hideModal('fileModal')" class="btn btn-secondary">Cancelar</button>
<button type="submit" name="new_file" class="btn btn-primary">Criar</button>
</div>
</form>
</div>
</div>
<div class="modal-overlay" id="renameModal">
<div class="modal">
<h3>📝 Renomear</h3>
<form method="POST" action="?action=rename&p=<?php echo urlencode($current_path); ?>">
<input type="hidden" name="old_name" id="renameOld">
<div class="form-group">
<label>Novo Nome</label>
<input type="text" name="new_name" id="renameNew" required autofocus>
</div>
<div class="modal-actions">
<button type="button" onclick="hideModal('renameModal')" class="btn btn-secondary">Cancelar</button>
<button type="submit" class="btn btn-primary">Renomear</button>
</div>
</form>
</div>
</div>
<div class="modal-overlay" id="copyModal">
<div class="modal">
<h3>📋 Copiar/Mover</h3>
<form method="POST" action="?action=copy&p=<?php echo urlencode($current_path); ?>">
<input type="hidden" name="source" id="copySource">
<div class="form-group">
<label>Destino (nome ou caminho)</label>
<input type="text" name="dest" id="copyDest" required autofocus>
</div>
<div class="modal-actions">
<button type="button" onclick="hideModal('copyModal')" class="btn btn-secondary">Cancelar</button>
<button type="submit" class="btn btn-primary">Copiar</button>
</div>
</form>
</div>
</div>
<script>
function showModal(id) {
document.getElementById(id).classList.add('active');
}
function hideModal(id) {
document.getElementById(id).classList.remove('active');
}
function renameItem(name) {
document.getElementById('renameOld').value = name;
document.getElementById('renameNew').value = name;
showModal('renameModal');
}
function copyItem(name) {
document.getElementById('copySource').value = name;
document.getElementById('copyDest').value = name;
showModal('copyModal');
}
// Fechar modal ao clicar fora
document.querySelectorAll('.modal-overlay').forEach(function(modal) {
modal.addEventListener('click', function(e) {
if (e.target === this) hideModal(this.id);
});
});
// Atalhos de teclado no editor
document.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 's') {
var saveBtn = document.querySelector('button[name="save_file"]');
if (saveBtn) {
e.preventDefault();
saveBtn.click();
}
}
});
</script>
<?php endif; ?>
</body>
</html>