🐘
index_copy2.php
Back
📝 Php ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
<?php // Force login + disable caching session_start(); require_once __DIR__ . '/../core/db_config.php'; // Anti-cache headers header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); header('Cache-Control: post-check=0, pre-check=0', false); header('Pragma: no-cache'); header('Expires: 0'); // Redirect if not logged in if (empty($_SESSION['username'])) { $redirect = urlencode($_SERVER['REQUEST_URI'] ?? '/'); header("Location: /core/auth/login.php?redirect={$redirect}"); exit; } // Cache-busting helper function asset($path) { $isAbsolute = strlen($path) && $path[0] === '/'; $abs = $isAbsolute ? rtrim($_SERVER['DOCUMENT_ROOT'], '/') . $path : __DIR__ . '/' . $path; $v = is_file($abs) ? filemtime($abs) : time(); return $path . '?v=' . $v; } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>App Index</title> <!-- Shared overlay CSS --> <link rel="stylesheet" href="<?= asset('/core/css/overlay.css') ?>"> <style> html, body { height: 100%; margin: 0; overscroll-behavior-y: contain; } body { background: #0b0f14; color: #e6edf3; font-family: system-ui, -apple-system, Segoe UI, Roboto, Inter, "Helvetica Neue", Arial; } .body-lock { overflow: hidden !important; touch-action: none; } .topbar { position: sticky; top: 0; z-index: 5; background: linear-gradient(180deg, rgba(11,15,20,.95), rgba(11,15,20,.85)); border-bottom: 1px solid #1e2633; backdrop-filter: blur(6px); } .topbar-inner { max-width: 1000px; margin: 0 auto; padding: .75rem; display: flex; align-items: center; gap: .75rem; } #buttonRow { flex: 1 1 auto; min-width: 0; display: flex; gap: .75rem; align-items: center; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; -webkit-overflow-scrolling: touch; } #menuContainer { flex: 0 0 auto; margin-left: .25rem; position: relative; } .chip { flex: 0 0 auto; border: 1px solid #2a3648; background: #1a2332; color: #e6edf3; padding: .55rem .9rem; border-radius: 999px; font-weight: 600; cursor: pointer; transition: background .15s ease; } .chip:hover { background: #263244; } .container { max-width: 1000px; margin: 1.25rem auto; padding: 0 .75rem; } .lead { color: #9aa4b2; } .menu-trigger { width: 38px; text-align: center; } .menu-list { display: none; position: absolute; right: 0; top: calc(100% + 6px); background: #1a2332; border: 1px solid #2a3648; border-radius: 10px; min-width: 180px; padding: .25rem 0; z-index: 9999; box-shadow: 0 10px 30px rgba(0,0,0,.3); } .menu-list.open { display: block; } .menu-item { display: block; width: 100%; text-align: left; background: none; border: none; color: #e6edf3; padding: .6rem 1rem; cursor: pointer; font: inherit; } .menu-item:hover { background: #263244; } /* SFTP Form */ form.sftp-form { margin-top: 2rem; background: #1a2332; border: 1px solid #2a3648; border-radius: 12px; padding: 1.5rem; max-width: 460px; } form.sftp-form label { display: block; margin-top: 0.75rem; font-weight: 600; } form.sftp-form input[type="text"], form.sftp-form input[type="password"], form.sftp-form input[type="number"] { width: 100%; padding: 0.6rem; margin-top: 0.3rem; border-radius: 6px; border: 1px solid #2a3648; background: #0f1725; color: #e6edf3; } .pw-wrap { position: relative; display: flex; width: 100%; } .pw-toggle { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); background: transparent; border: none; color: #9aa4b2; cursor: pointer; padding: 6px; border-radius: 6px; } form.sftp-form button[type="submit"] { margin-top: 1rem; padding: 0.6rem 1.2rem; border: none; border-radius: 8px; background: linear-gradient(135deg,#3b82f6,#9333ea); color: white; font-weight: 600; cursor: pointer; } .msg { margin-top: 1rem; font-weight: 600; } </style> </head> <body> <?php include __DIR__ . '/../core/auth/header.php'; ?> <header class="topbar" aria-label="Top navigation"> <div class="topbar-inner"> <div id="buttonRow" role="tablist" aria-label="App sections"></div> <div id="menuContainer" aria-label="More actions"></div> </div> </header> <main class="container"> <h1>DevBrewing SFTP Connection</h1> <p class="lead">Connect securely to the DevBrewing file server and manage your remote files.</p> <!-- 🔹 SFTP Connect Form --> <form id="sftpForm" class="sftp-form" autocomplete="off"> <label for="sftp_ip">Server</label> <input type="text" id="sftp_ip" value="files.devbrewing.com" required> <label for="sftp_user">Username</label> <input type="text" id="sftp_user" value="<?= htmlspecialchars($_SESSION['username'] ?? '') ?>" required> <label for="sftp_pass">Password</label> <div class="pw-wrap"> <input type="password" id="sftp_pass" required> <button type="button" class="pw-toggle" id="togglePw">👁️</button> </div> <label for="sftp_port">Port</label> <input type="number" id="sftp_port" value="22" required> <button type="submit">Connect</button> </form> <div id="sftpMsg" class="msg"></div> </main> <script> window.AppItems = [ ]; window.AppMenu = []; </script> <script src="<?= asset('/core/js/overlay.js') ?>" defer></script> <script src="<?= asset('menu.js') ?>" defer></script> <script src="<?= asset('filemanager.js') ?>" defer></script> <script defer> document.addEventListener('DOMContentLoaded', () => { const form = document.getElementById('sftpForm'); const msg = document.getElementById('sftpMsg'); const toggle = document.getElementById('togglePw'); const pass = document.getElementById('sftp_pass'); // 👁️ toggle password visibility toggle.addEventListener('click', () => { pass.type = pass.type === 'password' ? 'text' : 'password'; toggle.textContent = pass.type === 'password' ? '👁️' : '🙈'; }); // 🔄 handle form submission via fetch form.addEventListener('submit', async (e) => { e.preventDefault(); msg.textContent = 'Connecting...'; msg.style.color = '#9aa4b2'; const payload = { action: 'connect', host: document.getElementById('sftp_ip').value.trim(), username: document.getElementById('sftp_user').value.trim(), password: document.getElementById('sftp_pass').value.trim(), port: parseInt(document.getElementById('sftp_port').value, 10) }; try { const res = await fetch('SFTPconnector.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await res.json(); if (data.success) { msg.innerHTML = data.message; msg.style.color = '#10b981'; // Optional: open overlay if (window.AppOverlay) { AppOverlay.open([ { title: 'SFTP Connection', html: `<p>${data.message}</p>` } ]); } } else { msg.innerHTML = data.message || 'Connection failed'; msg.style.color = '#ef4444'; } } catch (err) { msg.textContent = 'Network error: ' + err.message; msg.style.color = '#ef4444'; } }); }); </script> <!-- 🔹 Render chips + menu (same logic as before) --> <script defer> document.addEventListener('DOMContentLoaded', () => { const row = document.getElementById('buttonRow'); row.innerHTML = ''; (window.AppItems || []).forEach((item, i) => { const btn = document.createElement('button'); btn.className = 'chip'; btn.textContent = item.title || `Item ${i+1}`; btn.onclick = () => window.AppOverlay && AppOverlay.open(window.AppItems, i, btn); row.appendChild(btn); }); const menuContainer = document.getElementById('menuContainer'); menuContainer.innerHTML = ''; const menuItems = window.AppMenu || []; if (menuItems.length > 0) { const trigger = document.createElement('button'); trigger.className = 'chip menu-trigger'; trigger.textContent = '⋮'; menuContainer.appendChild(trigger); const dropdown = document.createElement('div'); dropdown.className = 'menu-list'; menuContainer.appendChild(dropdown); menuItems.forEach((m, idx) => { const item = document.createElement('button'); item.className = 'menu-item'; item.textContent = m.label || `Action ${idx+1}`; item.onclick = () => { dropdown.classList.remove('open'); m.action && m.action(); }; dropdown.appendChild(item); }); trigger.addEventListener('click', (e)=>{ e.stopPropagation(); dropdown.classList.toggle('open'); }); document.addEventListener('click', (e)=>{ if (!menuContainer.contains(e.target)) dropdown.classList.remove('open'); }); } }); </script> </body> </html>