403Webshell
Server IP : 188.114.96.3  /  Your IP : 216.73.216.143
Web Server : Apache
System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64
User :  ( 3194769)
PHP Version : 8.5.12
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /polana/admin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /polana/admin/polana-backup-automat.php
<?php
declare(strict_types=1);
require_once dirname(__DIR__) . '/includes/polana_backup_v182.php';
require_admin_role();
header('Cache-Control: private, no-store, max-age=0');
header('X-Robots-Tag: noindex, nofollow');
header('X-Content-Type-Options: nosniff');
$notice = ''; $error = ''; $cfg = [];
try {
    $cfg = pbk_cfg();
    if (isset($_GET['code'], $_GET['state'])) {
        start_session();
        $expected = (string)($_SESSION['pbk_oauth_state'] ?? '');
        $verifier = (string)($_SESSION['pbk_oauth_verifier'] ?? '');
        unset($_SESSION['pbk_oauth_state'], $_SESSION['pbk_oauth_verifier']);
        if ($expected === '' || !hash_equals($expected, (string)$_GET['state']) || strlen($verifier) < 43) throw new RuntimeException('Błędny stan sesji Google OAuth.');
        $secret = pbk_secret_decrypt((string)($cfg['drive_client_secret'] ?? ''));
        [$code, $body] = pbk_http('https://oauth2.googleapis.com/token', 'POST', ['Content-Type: application/x-www-form-urlencoded'], http_build_query([
            'code' => (string)$_GET['code'], 'client_id' => $cfg['drive_client_id'], 'client_secret' => $secret,
            'redirect_uri' => pbk_oauth_redirect_uri(), 'grant_type' => 'authorization_code', 'code_verifier' => $verifier
        ]));
        $response = json_decode($body, true);
        if ($code !== 200 || empty($response['refresh_token'])) throw new RuntimeException('Google nie zwrócił tokenu odświeżania. Sprawdź aplikację OAuth, tryb produkcyjny i zgodę dostępu. HTTP ' . $code);
        $cfg['drive_refresh_token'] = pbk_secret_encrypt((string)$response['refresh_token']);
        $cfg['drive_folder_id'] = '';
        pbk_save_cfg($cfg);
        header('Location: /admin/polana-backup-automat.php?connected=1', true, 303); exit;
    }
    if (isset($_GET['error'])) $error = 'Google odrzucił autoryzację: ' . htmlspecialchars(substr((string)$_GET['error'], 0, 100), ENT_QUOTES);
    if (isset($_GET['connected'])) $notice = 'Konto Google Drive zostało połączone. Włącz przesyłanie na Dysk i zapisz ustawienia.';
    if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
        verify_csrf();
        $action = (string)($_POST['action'] ?? '');
        if ($action === 'save') {
            $email = trim((string)($_POST['email'] ?? ''));
            if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) throw new RuntimeException('Niepoprawny adres e-mail.');
            $mailEnabled = !empty($_POST['email_enabled']);
            if ($mailEnabled && $email === '') throw new RuntimeException('Podaj adres e-mail do wysyłania kopii SQL.');
            $clientId = trim((string)($_POST['drive_client_id'] ?? ''));
            if ($clientId !== '' && (!str_ends_with($clientId, '.apps.googleusercontent.com') || strlen($clientId) > 250)) throw new RuntimeException('Niepoprawny Google OAuth Client ID.');
            if ($clientId !== (string)($cfg['drive_client_id'] ?? '')) { $cfg['drive_refresh_token'] = ''; $cfg['drive_folder_id'] = ''; }
            $secret = trim((string)($_POST['drive_client_secret'] ?? ''));
            if ($secret !== '') $cfg['drive_client_secret'] = pbk_secret_encrypt($secret);
            $cfg['drive_client_id'] = $clientId;
            $cfg['email'] = $email;
            $cfg['email_enabled'] = $mailEnabled;
            $cfg['drive_enabled'] = !empty($_POST['drive_enabled']);
            $cfg['enabled'] = !empty($_POST['enabled']);
            if ($cfg['enabled'] && empty($cfg['key_exported'])) throw new RuntimeException('Najpierw pobierz klucz odzyskiwania i przechowaj go poza serwerem.');
            if ($cfg['drive_enabled'] && empty($cfg['drive_refresh_token'])) throw new RuntimeException('Najpierw połącz konto Google Drive.');
            pbk_save_cfg($cfg);
            $notice = 'Zapisano ustawienia. Automatyczne wykonanie wymaga skonfigurowania zadania CRON na hostingu.';
        } elseif ($action === 'download_key') {
            $key = pbk_key();
            $cfg['key_exported'] = true;
            pbk_save_cfg($cfg);
            if (session_status() === PHP_SESSION_ACTIVE) session_write_close();
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="POLANA-KLUCZ-ODZYSKIWANIA.key"');
            header('Content-Length: 32');
            echo $key; exit;
        } elseif ($action === 'connect') {
            $clientId = trim((string)($cfg['drive_client_id'] ?? ''));
            if ($clientId === '' || empty($cfg['drive_client_secret'])) throw new RuntimeException('Zapisz najpierw Google Client ID i Client Secret.');
            start_session();
            $state = bin2hex(random_bytes(24));
            $verifier = rtrim(strtr(base64_encode(random_bytes(48)), '+/', '-_'), '=');
            $_SESSION['pbk_oauth_state'] = $state;
            $_SESSION['pbk_oauth_verifier'] = $verifier;
            $challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '=');
            $params = http_build_query([
                'client_id' => $clientId, 'redirect_uri' => pbk_oauth_redirect_uri(), 'response_type' => 'code',
                'scope' => 'https://www.googleapis.com/auth/drive.file', 'access_type' => 'offline', 'prompt' => 'consent',
                'state' => $state, 'code_challenge' => $challenge, 'code_challenge_method' => 'S256'
            ]);
            header('Location: https://accounts.google.com/o/oauth2/v2/auth?' . $params, true, 303); exit;
        } elseif ($action === 'test_sql') {
            $result = pbk_run('sql');
            $notice = 'Wykonano próbę SQL: ' . implode('; ', $result) . '. Sprawdź historię oraz dostarczenie e-maila.';
        } elseif ($action === 'test_drive') {
            $token = pbk_drive_access_token($cfg);
            pbk_drive_folder($cfg, $token);
            $notice = 'Połączenie Google Drive działa. Folder kopii jest gotowy.';
        } elseif ($action === 'download_archive') {
            $type = (string)($_POST['type'] ?? '');
            $name = basename((string)($_POST['filename'] ?? ''));
            if (!in_array($type, ['daily', 'weekly'], true) || !preg_match('/^polana-(sql|strona)-\d{4}-\d{2}-\d{2}\.(sql\.gz|tar)\.pbackup$/', $name)) throw new RuntimeException('Nieprawidłowa nazwa archiwum.');
            $path = pbk_private() . '/' . $type . '/' . $name;
            if (!is_file($path)) throw new RuntimeException('Nie znaleziono archiwum.');
            if (session_status() === PHP_SESSION_ACTIVE) session_write_close();
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="' . $name . '"');
            header('Content-Length: ' . filesize($path));
            readfile($path); exit;
        } else throw new RuntimeException('Nieznana operacja.');
        $cfg = pbk_cfg();
    }
} catch (Throwable $e) { $error = $e->getMessage(); }
function pbk_e(mixed $v): string { return htmlspecialchars((string)$v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
$private = ''; $recent = []; $history = [];
try {
    $private = pbk_private();
    foreach (['daily', 'weekly'] as $kind) {
        foreach (glob($private . '/' . $kind . '/*.pbackup') ?: [] as $file) {
            $recent[] = ['file' => $file, 'kind' => $kind, 'size' => filesize($file), 'status' => pbk_status($file)];
        }
    }
    usort($recent, static fn($a, $b) => strcmp($b['file'], $a['file']));
    $lines = is_file($private . '/history.log') ? file($private . '/history.log', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : [];
    foreach (array_reverse(array_slice($lines ?: [], -15)) as $line) { $decoded = json_decode($line, true); if (is_array($decoded)) $history[] = $decoded; }
} catch (Throwable $e) { $error = $error ?: $e->getMessage(); }
render_admin_header('Automatyczne kopie zapasowe — POLANA');
?>
<style>
.pbk{max-width:1150px;margin:18px auto 65px;padding:0 16px;color:#22352b}.pbk *{box-sizing:border-box}.pbk h1{font-size:clamp(23px,3vw,34px)}.pbk h2{font-size:20px}.pbk section{border:1px solid #d8e3d9;background:#fff;border-radius:16px;padding:22px;margin:18px 0}.pbk .cols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.pbk label{display:block;margin:13px 0 5px;font-weight:700}.pbk input[type=email],.pbk input[type=text],.pbk input[type=password]{width:100%;border:1px solid #b8c9bd;border-radius:10px;padding:12px;font:inherit}.pbk button{background:#163c2b;color:#fff;border:0;border-radius:10px;padding:11px 16px;font:inherit;font-weight:700;cursor:pointer;margin:8px 5px 4px 0}.pbk .secondary{background:#e7efe7;color:#163c2b}.pbk .warn{background:#fff3dc;border:1px solid #e4b968;border-radius:10px;padding:13px}.pbk .good{background:#e9f7e8;border:1px solid #92c793;border-radius:10px;padding:13px}.pbk .err{background:#ffe9e7;border:1px solid #e6a49b;border-radius:10px;padding:13px}.pbk small{color:#586a60}.pbk code{overflow-wrap:anywhere}.pbk table{width:100%;border-collapse:collapse}.pbk th,.pbk td{text-align:left;padding:10px;border-bottom:1px solid #e4ece5;font-size:13px}.pbk .scroll{overflow-x:auto}.pbk .pill{padding:4px 9px;background:#eef4ee;border-radius:20px;display:inline-block}@media(max-width:720px){.pbk .cols{grid-template-columns:1fr}.pbk section{padding:15px}}
</style>
<div class="pbk">
<h1>Automatyczne kopie zapasowe</h1>
<p>SQL codziennie • pełne pliki strony co niedzielę • szyfrowanie AES-256-GCM • Google Drive i poczta. Wszystkie archiwa są szyfrowane przed wysyłką.</p>
<?php if ($notice): ?><div class="good"><?=pbk_e($notice)?></div><?php endif; ?>
<?php if ($error): ?><div class="err"><?=pbk_e($error)?></div><?php endif; ?>
<div class="cols">
<section><h2>1. Klucz odzyskiwania</h2><p><b><?=!empty($cfg['key_exported'])?'Klucz został już pobrany':'Pobierz klucz przed uruchomieniem automatu'?></b></p>
<p>Bez tego klucza nie odszyfrujesz kopii. Zapisz go w bezpiecznym miejscu <b>poza hostingiem i Dyskiem z kopiami</b>.</p>
<form method="post"><?=csrf_field()?><input type="hidden" name="action" value="download_key"><button type="submit">Pobierz klucz .key</button></form>
</section>
<section><h2>2. Harmonogram</h2><p><b>Codziennie:</b> pełny SQL, szyfrowany i wysyłany e-mailem. <b>Niedziela:</b> zaszyfrowane archiwum strony na Google Drive.</p>
<p>Przechowywanie lokalne: 14 ostatnich SQL i 4 ostatnie kopie strony. Kopie w Drive nie są automatycznie usuwane.</p>
<small>Automatyzacja wymaga zadania CRON w home.pl; samo włączenie przełącznika nie uruchamia harmonogramu.</small>
</section></div>
<section><h2>3. Ustawienia</h2>
<form method="post"><?=csrf_field()?><input type="hidden" name="action" value="save">
<div class="cols"><div>
<label><input type="checkbox" name="enabled" value="1" <?=!empty($cfg['enabled'])?'checked':''?>> Włącz automatyczne backupy</label>
<label><input type="checkbox" name="email_enabled" value="1" <?=!empty($cfg['email_enabled'])?'checked':''?>> Wysyłaj codzienny SQL na e-mail</label>
<label for="pbkemail">Adres odbiorcy (najlepiej inna skrzynka niż hosting strony)</label>
<input id="pbkemail" type="email" name="email" value="<?=pbk_e($cfg['email']??'')?>" placeholder="[email protected]">
</div><div>
<label><input type="checkbox" name="drive_enabled" value="1" <?=!empty($cfg['drive_enabled'])?'checked':''?>> Wysyłaj kopie na Google Drive</label>
<label for="clientid">Google OAuth Client ID (aplikacja Web)</label>
<input id="clientid" type="text" name="drive_client_id" value="<?=pbk_e($cfg['drive_client_id']??'')?>" placeholder="...apps.googleusercontent.com" autocomplete="off">
<label for="secret">Google OAuth Client Secret (puste = zachowaj)</label>
<input id="secret" type="password" name="drive_client_secret" placeholder="••••••••" autocomplete="new-password">
<small>OAuth callback: <code><?=pbk_e(pbk_oauth_redirect_uri())?></code></small>
</div></div>
<button type="submit">Zapisz ustawienia</button></form>
<div class="cols"><form method="post"><?=csrf_field()?><input type="hidden" name="action" value="connect"><button class="secondary" type="submit">Połącz Google Drive (OAuth)</button></form>
<form method="post"><?=csrf_field()?><input type="hidden" name="action" value="test_drive"><button class="secondary" type="submit">Sprawdź połączenie Drive</button></form></div>
<p>Google Drive: <b><?=!empty($cfg['drive_refresh_token'])?'konto połączone':'konto niepołączone'?></b>. Do integracji wymagany jest osobny zakres uprawnień <code>drive.file</code>; logowanie Google ani sam Kalendarz nie dają automatycznie dostępu do Dysku.</p>
</section>
<section><h2>4. Uruchamianie i test</h2>
<div class="warn">CRON (codziennie około 03:15):<p><code>15 3 * * * /usr/bin/php <?=pbk_e(pbk_root())?>/cron/polana-backup-v182.php</code></p>Ścieżkę interpretera PHP i sposób dodania zadania potwierdź w panelu home.pl. Zadanie musi wykonywać PHP w trybie CLI.</div>
<form method="post" onsubmit="return confirm('Wykonać pełny SQL i wysłać go na e-mail, jeśli wysyłka jest włączona?')"><?=csrf_field()?><input type="hidden" name="action" value="test_sql"><button type="submit">Test: wykonaj SQL teraz</button></form>
<p><small>Dużą kopię całej witryny uruchamiamy przez CRON, żeby nie przekroczyć limitu czasu żądania HTTP.</small></p>
</section>
<section><h2>5. Ostatnie kopie</h2><div class="scroll"><table><thead><tr><th>Archiwum</th><th>Rozmiar</th><th>E-mail</th><th>Drive</th><th>Odzyskanie</th></tr></thead><tbody>
<?php foreach(array_slice($recent,0,30) as $row): ?><tr><td><?=pbk_e(basename($row['file']))?></td><td><?=pbk_e(round($row['size']/1048576,2))?> MB</td><td><?=!empty($row['status']['mail'])?'OK':'—'?></td><td><?=!empty($row['status']['drive'])?'OK':'—'?></td><td><form method="post"><?=csrf_field()?><input type="hidden" name="action" value="download_archive"><input type="hidden" name="type" value="<?=pbk_e($row['kind'])?>"><input type="hidden" name="filename" value="<?=pbk_e(basename($row['file']))?>"><button class="secondary" type="submit">Pobierz</button></form></td></tr><?php endforeach; ?>
<?php if (!$recent): ?><tr><td colspan="5">Brak wykonanych kopii.</td></tr><?php endif; ?></tbody></table></div></section>
<section><h2>6. Historia operacji</h2><div class="scroll"><table><thead><tr><th>Data</th><th>Operacja</th><th>Wynik</th><th>Informacja</th></tr></thead><tbody>
<?php foreach($history as $row): ?><tr><td><?=pbk_e($row['time']??'')?></td><td><?=pbk_e($row['kind']??'')?></td><td><?=pbk_e($row['status']??'')?></td><td><?=pbk_e($row['message']??'')?></td></tr><?php endforeach; ?>
<?php if (!$history): ?><tr><td colspan="4">Brak historii.</td></tr><?php endif; ?></tbody></table></div></section>
</div>
<?php render_admin_footer(); ?>

Youez - 2016 - github.com/yon3zu
LinuXploit