<?php
declare(strict_types=1);

session_start();
date_default_timezone_set('America/Sao_Paulo');

$phpseclibBase = __DIR__ . '/phpseclib';
if (!is_dir($phpseclibBase)) {
    http_response_code(500);
    echo 'phpseclib nao encontrado em sftp-nuclea/phpseclib.';
    exit;
}

$currentIncludePath = get_include_path();
$extraPaths = [
    $phpseclibBase,
    $phpseclibBase . '/Net',
    $phpseclibBase . '/Crypt',
    $phpseclibBase . '/Math',
    $phpseclibBase . '/File',
    $phpseclibBase . '/System',
];
set_include_path($currentIncludePath . PATH_SEPARATOR . implode(PATH_SEPARATOR, $extraPaths));

require_once $phpseclibBase . '/bootstrap.php';
require_once $phpseclibBase . '/Net/SFTP.php';
require_once $phpseclibBase . '/Crypt/RSA.php';
require_once __DIR__ . '/spbseguranca.php';

if (!class_exists('Net_SFTP') || !class_exists('Crypt_RSA')) {
    http_response_code(500);
    echo 'Falha ao carregar classes do phpseclib.';
    exit;
}

function h(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}

function normalizeRemotePath(string $path): string
{
    $path = trim($path);
    if ($path === '') {
        return '/';
    }

    if ($path[0] !== '/') {
        $path = '/' . $path;
    }

    $parts = [];
    foreach (explode('/', $path) as $part) {
        if ($part === '' || $part === '.') {
            continue;
        }
        if ($part === '..') {
            array_pop($parts);
            continue;
        }
        $parts[] = $part;
    }

    return '/' . implode('/', $parts);
}

function parentRemotePath(string $path): string
{
    if ($path === '/' || $path === '') {
        return '/';
    }

    $segments = explode('/', trim($path, '/'));
    array_pop($segments);
    if (count($segments) === 0) {
        return '/';
    }

    return '/' . implode('/', $segments);
}

function sftpConnect(array $config): array
{
    $host = (string)($config['host'] ?? '');
    $port = (int)($config['port'] ?? 22);
    $username = (string)($config['username'] ?? '');
    $privateKey = (string)($config['private_key'] ?? '');
    $passphrase = (string)($config['passphrase'] ?? '');

    if ($host === '' || $username === '' || $privateKey === '') {
        throw new RuntimeException('Host, usuario e chave privada sao obrigatorios.');
    }

    if (!is_file($privateKey)) {
        throw new RuntimeException('Chave privada nao encontrada: ' . $privateKey);
    }

    $keyContents = @file_get_contents($privateKey);
    if ($keyContents === false || $keyContents === '') {
        throw new RuntimeException('Nao foi possivel ler a chave privada: ' . $privateKey);
    }

    $rsa = new Crypt_RSA();
    if ($passphrase !== '') {
        $rsa->setPassword($passphrase);
    }
    if (!$rsa->loadKey($keyContents)) {
        throw new RuntimeException('Falha ao carregar chave privada. Verifique formato OpenSSH e passphrase.');
    }

    $socketErrorNo = 0;
    $socketError = '';
    $socket = @fsockopen($host, $port, $socketErrorNo, $socketError, 10);
    if (!is_resource($socket)) {
        throw new RuntimeException(
            'Falha de rede ao conectar em ' . $host . ':' . $port .
            ' (erro ' . $socketErrorNo . ': ' . $socketError . ').'
        );
    }
    fclose($socket);

    $sftp = new Net_SFTP($host, $port, 15);

    if (!$sftp->login($username, $rsa)) {
        $details = [];
        if (method_exists($sftp, 'getLastError')) {
            $lastError = (string)$sftp->getLastError();
            if ($lastError !== '') {
                $details[] = $lastError;
            }
        }
        if (method_exists($sftp, 'getErrors')) {
            $errors = $sftp->getErrors();
            if (is_array($errors) && count($errors) > 0) {
                $details[] = implode(' | ', $errors);
            }
        }
        if (method_exists($sftp, 'getSFTPErrors')) {
            $sftpErrors = $sftp->getSFTPErrors();
            if (is_array($sftpErrors) && count($sftpErrors) > 0) {
                $details[] = implode(' | ', $sftpErrors);
            }
        }
        $suffix = count($details) > 0 ? ' Detalhes: ' . implode(' || ', $details) : '';
        throw new RuntimeException('Falha de autenticacao com chave privada/passphrase.' . $suffix);
    }

    return [null, $sftp];
}

function listRemoteDirectory($sftp, string $path): array
{
    $rawList = $sftp->rawlist($path, false);
    if ($rawList === false) {
        throw new RuntimeException('Nao foi possivel abrir diretorio remoto: ' . $path);
    }

    $items = [];
    foreach ($rawList as $entry => $attrs) {
        if ($entry === '.' || $entry === '..') {
            continue;
        }

        $entryPath = normalizeRemotePath($path . '/' . $entry);
        $type = isset($attrs['type']) ? (int)$attrs['type'] : -1;
        $directoryType = defined('NET_SFTP_TYPE_DIRECTORY') ? NET_SFTP_TYPE_DIRECTORY : 2;
        $isDir = $type === $directoryType;
        $size = $isDir ? null : (isset($attrs['size']) ? (int)$attrs['size'] : null);
        $mtime = isset($attrs['mtime']) ? (int)$attrs['mtime'] : null;

        $items[] = [
            'name' => $entry,
            'path' => $entryPath,
            'is_dir' => $isDir,
            'size' => $size,
            'mtime' => $mtime,
        ];
    }

    usort(
        $items,
        static function (array $a, array $b): int {
            if ($a['is_dir'] !== $b['is_dir']) {
                return $a['is_dir'] ? -1 : 1;
            }
            return strcasecmp($a['name'], $b['name']);
        }
    );

    return $items;
}

function sortItems(array $items, string $sortField, string $sortDirection): array
{
    $allowedFields = ['name', 'size', 'mtime'];
    if (!in_array($sortField, $allowedFields, true)) {
        $sortField = 'name';
    }

    $sortDirection = strtolower($sortDirection) === 'desc' ? 'desc' : 'asc';
    $multiplier = $sortDirection === 'desc' ? -1 : 1;

    usort(
        $items,
        static function (array $a, array $b) use ($sortField, $multiplier): int {
            if ($a['is_dir'] !== $b['is_dir']) {
                return $a['is_dir'] ? -1 : 1;
            }

            if ($sortField === 'name') {
                return strcasecmp($a['name'], $b['name']) * $multiplier;
            }

            $aValue = $a[$sortField] ?? null;
            $bValue = $b[$sortField] ?? null;

            if ($aValue === $bValue) {
                return strcasecmp($a['name'], $b['name']);
            }
            if ($aValue === null) {
                return 1;
            }
            if ($bValue === null) {
                return -1;
            }

            return (($aValue <=> $bValue) * $multiplier);
        }
    );

    return $items;
}

function formatBytes(?int $bytes): string
{
    if ($bytes === null) {
        return '-';
    }

    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $value = (float)$bytes;
    $i = 0;
    while ($value >= 1024 && $i < count($units) - 1) {
        $value /= 1024;
        $i++;
    }
    return number_format($value, $i === 0 ? 0 : 2, ',', '.') . ' ' . $units[$i];
}

function formatDate(?int $timestamp): string
{
    if ($timestamp === null) {
        return '-';
    }
    return date('d/m/Y H:i:s', $timestamp);
}

function isSpbPayload(string $payload): bool
{
    if (strlen($payload) < SpbSeguranca::TAMANHO_CABECALHO) {
        return false;
    }
    $headerSize = unpack('n', substr($payload, 0, 2))[1] ?? 0;
    if ($headerSize !== SpbSeguranca::TAMANHO_CABECALHO) {
        return false;
    }
    $version = ord($payload[2]);
    return $version === SpbSeguranca::VERSAO_2 || $version === SpbSeguranca::VERSAO_3;
}

function decryptSpbToUtf8Xml(string $payload, array $security): string
{
    $privateKeyPath = (string)($security['private_key'] ?? '');
    $privateKeyPass = (string)($security['private_key_password'] ?? '');
    $senderCertPaths = $security['sender_cert_paths'] ?? [];
    if (!is_array($senderCertPaths)) {
        $senderCertPaths = [];
    }
    if (!empty($security['sender_cert'])) {
        array_unshift($senderCertPaths, (string)$security['sender_cert']);
    }
    $senderCertPaths = array_values(array_unique(array_filter($senderCertPaths, 'is_file')));

    if (!is_file($privateKeyPath) || count($senderCertPaths) === 0) {
        throw new RuntimeException('Arquivos de seguranca SPB nao encontrados no caminho configurado.');
    }

    $privateKeyPem = file_get_contents($privateKeyPath);
    if ($privateKeyPem === false) {
        throw new RuntimeException('Nao foi possivel ler os arquivos de seguranca SPB.');
    }

    $privateKey = openssl_pkey_get_private($privateKeyPem, $privateKeyPass);
    if ($privateKey === false) {
        throw new RuntimeException('Falha ao abrir chave privada SPB (senha incorreta?).');
    }

    $issuerSerial = strtoupper(substr($payload, 44, 32));
    usort(
        $senderCertPaths,
        static function (string $a, string $b) use ($issuerSerial): int {
            $aInfo = @openssl_x509_parse((string)@file_get_contents($a));
            $bInfo = @openssl_x509_parse((string)@file_get_contents($b));
            $aSerial = str_pad(strtoupper((string)($aInfo['serialNumberHex'] ?? '')), 32, '0', STR_PAD_LEFT);
            $bSerial = str_pad(strtoupper((string)($bInfo['serialNumberHex'] ?? '')), 32, '0', STR_PAD_LEFT);

            return ($bSerial === $issuerSerial ? 1 : 0) <=> ($aSerial === $issuerSerial ? 1 : 0);
        }
    );

    $xmlOriginal = null;
    $lastError = '';
    $attemptedCerts = [];
    foreach ($senderCertPaths as $senderCertPath) {
        $senderCertPem = file_get_contents($senderCertPath);
        if ($senderCertPem === false) {
            continue;
        }

        $certInfo = @openssl_x509_parse($senderCertPem);
        $certSerial = str_pad(strtoupper((string)($certInfo['serialNumberHex'] ?? '')), 32, '0', STR_PAD_LEFT);
        $attemptedCerts[] = basename($senderCertPath) . ' serial ' . $certSerial;

        try {
            $xmlOriginal = SpbSeguranca::decifrarEVerificar($payload, $privateKey, $senderCertPem);
            break;
        } catch (Throwable $e) {
            $lastError = $e->getMessage();
        }
    }

    if (!is_string($xmlOriginal)) {
        $details = ' Serial emissor do arquivo: ' . $issuerSerial . '. Certificados tentados: ' . implode('; ', $attemptedCerts) . '.';
        throw new RuntimeException(($lastError !== '' ? $lastError : 'Nao foi possivel validar a assinatura SPB.') . $details);
    }

    $xmlUtf8 = function_exists('mb_convert_encoding')
        ? mb_convert_encoding($xmlOriginal, 'UTF-8', 'UTF-16BE')
        : $xmlOriginal;

    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;

    if (@$dom->loadXML($xmlUtf8)) {
        return $dom->saveXML();
    }

    return $xmlUtf8;
}

function firstExistingPath(array $candidates): string
{
    foreach ($candidates as $candidate) {
        if (is_string($candidate) && $candidate !== '' && is_file($candidate)) {
            return $candidate;
        }
    }
    return '';
}

function existingFilesFromDirs(array $dirs, string $pattern): array
{
    $files = [];
    foreach ($dirs as $dir) {
        if (!is_string($dir) || $dir === '' || !is_dir($dir)) {
            continue;
        }

        $matches = glob(rtrim($dir, '/\\') . '/' . $pattern);
        if (is_array($matches)) {
            $files = array_merge($files, $matches);
        }
    }

    return array_values(array_unique(array_filter($files, 'is_file')));
}

$homeDir = (string)($_SERVER['HOME'] ?? getenv('HOME') ?: '');
$externalCertBase = $homeDir !== '' ? rtrim($homeDir, '/\\') . '/certificados/certificados_nuclea' : '';
$localCertBase = __DIR__ . '/certificados_nuclea';
$jobCertBase = __DIR__ . '/../pagamentos/jobs/nuclea/certificados';
$certDirs = [$externalCertBase, $localCertBase, $jobCertBase];

$hardcodedConfig = [
    'host' => 'sftp-prd.nucleaservicos.com.br',
    'port' => 22,
    'username' => 'SLC42403952PRD',
    'private_key' => firstExistingPath([
        $externalCertBase . '/id_rsa4',
        $localCertBase . '/id_rsa4',
        __DIR__ . '/id_rsa4',
    ]),
];
$spbSecurityConfig = [
    'sender_cert_paths' => array_merge([
        $externalCertBase . '/SLC-T011.cer',
        $externalCertBase . '/Certnew.cer',
        $localCertBase . '/SLC-T011.cer',
        $localCertBase . '/Certnew.cer',
        $jobCertBase . '/SLC-T011.cer',
        $jobCertBase . '/Certnew.cer',
    ], existingFilesFromDirs($certDirs, '*.cer')),
    'private_key' => firstExistingPath([
        $externalCertBase . '/Certnew.key',
        $localCertBase . '/Certnew.key',
        $jobCertBase . '/Certnew.key',
    ]),
    'private_key_password' => 'Du25041977@',
];

$message = '';
$messageType = 'info';
$shouldPromptPassphrase = false;

if (isset($_GET['logout'])) {
    unset($_SESSION['sftp_passphrase']);
    header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
    exit;
}

$requestMethod = $_SERVER['REQUEST_METHOD'] ?? 'GET';
if ($requestMethod === 'POST') {
    $action = (string)($_POST['action'] ?? '');
    if ($action === 'set_passphrase') {
        $_SESSION['sftp_passphrase'] = (string)($_POST['passphrase'] ?? '');
        $redirectPath = normalizeRemotePath((string)($_POST['path'] ?? '/'));
        header('Location: ?path=' . rawurlencode($redirectPath));
        exit;
    }
    if ($action === 'clear_passphrase') {
        unset($_SESSION['sftp_passphrase']);
        header('Location: ?path=%2F');
        exit;
    }
    if ($action === 'upload_file') {
        $uploadPath = normalizeRemotePath((string)($_POST['path'] ?? '/'));
        $uploadSort = (string)($_POST['sort'] ?? 'name');
        $uploadDir = (string)($_POST['dir'] ?? 'asc');

        try {
            if (!array_key_exists('sftp_passphrase', $_SESSION)) {
                throw new RuntimeException('Informe a senha/passphrase antes de enviar arquivos.');
            }
            if (!isset($_FILES['upload_file']) || !is_array($_FILES['upload_file'])) {
                throw new RuntimeException('Nenhum arquivo enviado.');
            }

            $file = $_FILES['upload_file'];
            $errorCode = (int)($file['error'] ?? UPLOAD_ERR_NO_FILE);
            if ($errorCode !== UPLOAD_ERR_OK) {
                throw new RuntimeException('Falha no upload local (codigo ' . $errorCode . ').');
            }

            $tmpName = (string)($file['tmp_name'] ?? '');
            $originalName = basename((string)($file['name'] ?? ''));
            if ($originalName === '') {
                throw new RuntimeException('Nome de arquivo invalido.');
            }
            if (!is_uploaded_file($tmpName)) {
                throw new RuntimeException('Upload local invalido.');
            }

            $uploadConfig = $hardcodedConfig;
            $uploadConfig['passphrase'] = (string)$_SESSION['sftp_passphrase'];
            [, $uploadSftp] = sftpConnect($uploadConfig);

            $remoteFilePath = normalizeRemotePath($uploadPath . '/' . $originalName);
            $putResult = $uploadSftp->put($remoteFilePath, $tmpName, NET_SFTP_LOCAL_FILE);
            if ($putResult !== true) {
                throw new RuntimeException('Falha ao enviar arquivo para o SFTP.');
            }

            $_SESSION['sftp_flash_message'] = 'Upload realizado com sucesso: ' . $originalName;
            $_SESSION['sftp_flash_type'] = 'success';
        } catch (Throwable $e) {
            $_SESSION['sftp_flash_message'] = $e->getMessage();
            $_SESSION['sftp_flash_type'] = 'error';
        }

        header(
            'Location: ?path=' . rawurlencode($uploadPath) .
            '&sort=' . rawurlencode($uploadSort) .
            '&dir=' . rawurlencode($uploadDir)
        );
        exit;
    }
}

$path = normalizeRemotePath((string)($_GET['path'] ?? '/'));
$sort = (string)($_GET['sort'] ?? 'name');
$dir = (string)($_GET['dir'] ?? 'asc');
$items = [];
$connected = false;
$hasSessionPassphrase = array_key_exists('sftp_passphrase', $_SESSION);
$config = $hardcodedConfig;
$config['passphrase'] = $hasSessionPassphrase ? (string)$_SESSION['sftp_passphrase'] : '';

if (isset($_SESSION['sftp_flash_message'])) {
    $message = (string)$_SESSION['sftp_flash_message'];
    $messageType = (string)($_SESSION['sftp_flash_type'] ?? 'info');
    unset($_SESSION['sftp_flash_message'], $_SESSION['sftp_flash_type']);
}

if ($hasSessionPassphrase) {
    try {
        [, $sftp] = sftpConnect($config);
        $connected = true;
        if ($message === '') {
            $message = 'Conectado no SFTP com sucesso.';
            $messageType = 'success';
        }

        if (isset($_GET['download'])) {
            $downloadPath = normalizeRemotePath((string)$_GET['download']);

            if (!$sftp->is_file($downloadPath)) {
                throw new RuntimeException('Arquivo remoto nao encontrado para download.');
            }

            $filename = basename($downloadPath);
            $fileSize = $sftp->size($downloadPath);
            $fileContents = $sftp->get($downloadPath);
            if ($fileContents === false) {
                throw new RuntimeException('Nao foi possivel baixar o arquivo remoto.');
            }

            $downloadName = $filename;
            $contentType = 'application/octet-stream';
            if (isSpbPayload($fileContents)) {
                $fileContents = decryptSpbToUtf8Xml($fileContents, $spbSecurityConfig);
                $downloadName .= '_decriptado_utf8.xml';
                $contentType = 'application/xml; charset=UTF-8';
                $fileSize = strlen($fileContents);
            }

            header('Content-Description: File Transfer');
            header('Content-Type: ' . $contentType);
            header('Content-Disposition: attachment; filename="' . rawurlencode($downloadName) . '"');
            if (is_int($fileSize) && $fileSize >= 0) {
                header('Content-Length: ' . (string)$fileSize);
            }
            header('Cache-Control: no-cache, must-revalidate');
            header('Pragma: public');
            echo $fileContents;
            exit;
        }

        $items = listRemoteDirectory($sftp, $path);
        $items = sortItems($items, $sort, $dir);
    } catch (Throwable $e) {
        $connected = false;
        unset($_SESSION['sftp_passphrase']);
        $shouldPromptPassphrase = true;
        $message = $e->getMessage();
        $messageType = 'error';
    }
} else {
    $shouldPromptPassphrase = true;
    $message = 'Digite a senha/passphrase para abrir a conexao SFTP.';
}
?>
<!doctype html>
<html lang="pt-br">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>SFTP Nuclea</title>
    <style>
        :root {
            --bg: #f3f6fb;
            --card: #ffffff;
            --text: #1d2a3b;
            --primary: #0f4c81;
            --border: #dce6f2;
            --success: #0b7a4b;
            --error: #b42318;
        }
        * { box-sizing: border-box; }
        body {
            margin: 0;
            font-family: "Segoe UI", Tahoma, sans-serif;
            color: var(--text);
            background: linear-gradient(160deg, #edf3fb 0%, #f8fbff 100%);
        }
        .container {
            max-width: 1100px;
            margin: 24px auto;
            padding: 0 16px;
        }
        .card {
            background: var(--card);
            border: 1px solid var(--border);
            border-radius: 12px;
            padding: 16px;
            margin-bottom: 16px;
            box-shadow: 0 8px 22px rgba(31, 63, 104, 0.06);
        }
        h1 {
            font-size: 22px;
            margin: 0 0 12px;
            color: var(--primary);
        }
        .grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 12px;
        }
        .field {
            display: flex;
            flex-direction: column;
            gap: 6px;
        }
        .field.full { grid-column: 1 / -1; }
        label { font-weight: 600; font-size: 13px; }
        input {
            width: 100%;
            height: 38px;
            border: 1px solid #c8d7ea;
            border-radius: 8px;
            padding: 0 10px;
            outline: none;
            font-size: 14px;
        }
        input:focus { border-color: #7ea3cd; }
        .actions {
            display: flex;
            gap: 8px;
            margin-top: 12px;
            flex-wrap: wrap;
        }
        .btn {
            border: 0;
            border-radius: 8px;
            padding: 10px 14px;
            cursor: pointer;
            font-weight: 600;
            color: #fff;
            background: var(--primary);
            text-decoration: none;
            display: inline-block;
        }
        .btn.secondary { background: #5f6d7d; }
        .msg {
            border-radius: 8px;
            padding: 10px 12px;
            margin-bottom: 12px;
            font-weight: 600;
            font-size: 14px;
        }
        .msg.success { background: #e8f7ef; color: var(--success); border: 1px solid #bce8d0; }
        .msg.error { background: #fff1f2; color: var(--error); border: 1px solid #fecdd3; }
        .path {
            font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
            font-size: 13px;
            background: #eef5ff;
            border: 1px solid #d7e4f7;
            border-radius: 8px;
            padding: 8px 10px;
            margin-bottom: 10px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            border-bottom: 1px solid var(--border);
            text-align: left;
            padding: 10px 8px;
            font-size: 14px;
        }
        th { font-size: 12px; text-transform: uppercase; color: #5c6f88; }
        .muted { color: #607087; font-size: 13px; }
        @media (max-width: 760px) {
            .grid { grid-template-columns: 1fr; }
            th:nth-child(3), td:nth-child(3) { display: none; }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="card">
        <h1>Conexao SFTP Nuclea</h1>

        <?php if ($message !== ''): ?>
            <div class="msg <?= $messageType === 'success' ? 'success' : 'error' ?>"><?= h($message) ?></div>
        <?php endif; ?>

        <p class="muted">Host: <strong><?= h($config['host']) ?></strong></p>
        <p class="muted">Porta: <strong><?= h((string)$config['port']) ?></strong></p>

        <div class="actions">
            <button class="btn" type="button" onclick="requestPassphrase()">Informar senha</button>
            <form method="post" style="display:inline;">
                <input type="hidden" name="action" value="clear_passphrase">
                <button class="btn secondary" type="submit">Limpar senha</button>
            </form>
            <?php if ($connected): ?>
                <a class="btn secondary" href="?logout=1">Desconectar</a>
            <?php endif; ?>
        </div>

    </div>

    <?php if ($connected): ?>
        <div class="card">
            <div class="path">Diretorio atual: <?= h($path) ?></div>
            <form method="post" enctype="multipart/form-data" style="margin-bottom:10px;">
                <input type="hidden" name="action" value="upload_file">
                <input type="hidden" name="path" value="<?= h($path) ?>">
                <input type="hidden" name="sort" value="<?= h($sort) ?>">
                <input type="hidden" name="dir" value="<?= h($dir) ?>">
                <div class="actions" style="margin-top:0; margin-bottom: 10px;">
                    <input type="file" name="upload_file" required>
                    <button class="btn" type="submit">Enviar arquivo</button>
                </div>
            </form>
            <div class="actions" style="margin-top:0; margin-bottom: 10px;">
                <a class="btn secondary" href="?path=<?= rawurlencode(parentRemotePath($path)) ?>&sort=<?= h($sort) ?>&dir=<?= h($dir) ?>">Subir pasta</a>
                <a class="btn secondary" href="?path=%2F&sort=<?= h($sort) ?>&dir=<?= h($dir) ?>">Ir para /</a>
            </div>
            <table>
                <thead>
                <tr>
                    <?php
                    $nameDir = ($sort === 'name' && strtolower($dir) === 'asc') ? 'desc' : 'asc';
                    $sizeDir = ($sort === 'size' && strtolower($dir) === 'asc') ? 'desc' : 'asc';
                    $mtimeDir = ($sort === 'mtime' && strtolower($dir) === 'asc') ? 'desc' : 'asc';
                    ?>
                    <th><a href="?path=<?= rawurlencode($path) ?>&sort=name&dir=<?= h($nameDir) ?>">Nome</a></th>
                    <th><a href="?path=<?= rawurlencode($path) ?>&sort=size&dir=<?= h($sizeDir) ?>">Tamanho</a></th>
                    <th><a href="?path=<?= rawurlencode($path) ?>&sort=mtime&dir=<?= h($mtimeDir) ?>">Modificado em</a></th>
                    <th>Acao</th>
                </tr>
                </thead>
                <tbody>
                <?php if (count($items) === 0): ?>
                    <tr><td colspan="4">Diretorio vazio.</td></tr>
                <?php else: ?>
                    <?php foreach ($items as $item): ?>
                        <tr>
                            <td>
                                <?php if ($item['is_dir']): ?>
                                    <a href="?path=<?= rawurlencode($item['path']) ?>&sort=<?= h($sort) ?>&dir=<?= h($dir) ?>">[DIR] <?= h($item['name']) ?></a>
                                <?php else: ?>
                                    <?= h($item['name']) ?>
                                <?php endif; ?>
                            </td>
                            <td><?= $item['is_dir'] ? '-' : h(formatBytes($item['size'])) ?></td>
                            <td><?= h(formatDate($item['mtime'])) ?></td>
                            <td>
                                <?php if (!$item['is_dir']): ?>
                                    <a href="?path=<?= rawurlencode($path) ?>&sort=<?= h($sort) ?>&dir=<?= h($dir) ?>&download=<?= rawurlencode($item['path']) ?>">Download</a>
                                <?php else: ?>
                                    -
                                <?php endif; ?>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                <?php endif; ?>
                </tbody>
            </table>
        </div>
    <?php endif; ?>
</div>
<form id="passphrase-form" method="post" style="display:none;">
    <input type="hidden" name="action" value="set_passphrase">
    <input type="hidden" name="path" value="<?= h($path) ?>">
    <input type="hidden" name="passphrase" id="passphrase-value" value="">
</form>
<script>
function requestPassphrase() {
    var value = window.prompt('Digite a senha/passphrase da chave SFTP:', '');
    if (value === null) {
        return;
    }
    document.getElementById('passphrase-value').value = value;
    document.getElementById('passphrase-form').submit();
}
<?php if ($shouldPromptPassphrase): ?>
requestPassphrase();
<?php endif; ?>
</script>
</body>
</html>
