| Server IP : 188.114.97.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_v1801_rollback/ |
Upload File : |
<?php
declare(strict_types=1);
/**
* POLANA V17.1 — pojedynczy ekran konfiguracji SMTP home.pl.
* Nienaruszający pozostałych mechanizmów PHP, rezerwacji i SEO.
*/
require_once dirname(__DIR__) . '/includes/functions.php';
require_admin_role();
header('Cache-Control: private, no-store, max-age=0');
header('Pragma: no-cache');
header('X-Robots-Tag: noindex,nofollow');
const PP_MAIL_DOMAIN = 'mojapolanasmakow.pl';
const PP_MAIL_SENDER = '[email protected]';
const PP_MAIL_RESERVATIONS = '[email protected]';
const PP_MAIL_HOST = 'serwer2200110.home.pl';
function ppm_e(string $v): string { return htmlspecialchars($v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
function ppm_current(string $key, string $preferred, bool $strict = false): string
{
$actual = trim(setting($key, ''));
// Preferujemy zadaną domenę po migracji, bez zgadywania starych loginów.
if ($actual === '' || str_contains(strtolower($actual), '@polanasmakow.pl')) return $preferred;
if ($strict && $actual !== $preferred && str_ends_with(strtolower($actual), '.polanasmakow.pl')) return $preferred;
return $actual;
}
function ppm_mail(string $v, string $field): string
{
$v = trim($v);
if (!filter_var($v, FILTER_VALIDATE_EMAIL) || preg_match('/[\r\n]/', $v)) {
throw new RuntimeException('Nieprawidłowy adres e-mail: ' . $field . '.');
}
return $v;
}
function ppm_has_safe_crypto(): bool
{
if (!function_exists('openssl_encrypt') || !function_exists('openssl_decrypt')) return false;
$key = smtp_secret_key(true);
$path = smtp_secret_file();
if (!is_file($path) || !is_readable($path)) return false;
$saved = @file_get_contents($path);
return is_string($saved) && strlen($saved) >= 32 && hash_equals($key, $saved);
}
function ppm_upsert(PDOStatement $stmt, string $key, string $value): void
{
$stmt->execute([$key, $value]);
}
function ppm_mail_configuration(): array
{
$fresh = !smtp_password_is_set();
// Jeśli konto nie jest jeszcze skonfigurowane, gotowy profil home.pl wygrywa ze starymi wartościami z migracji.
$host = $fresh ? PP_MAIL_HOST : ppm_current('smtp_host', PP_MAIL_HOST);
$port = $fresh ? '465' : ppm_current('smtp_port', '465');
$security = $fresh ? 'ssl' : ppm_current('smtp_security', 'ssl');
$username = $fresh ? PP_MAIL_SENDER : ppm_current('smtp_username', PP_MAIL_SENDER);
$sender = $fresh ? PP_MAIL_SENDER : ppm_current('smtp_from_email', PP_MAIL_SENDER);
$notify = ppm_current('reservation_admin_email', PP_MAIL_RESERVATIONS);
return [
'smtp_enabled' => $fresh ? '1' : setting('smtp_enabled', '0'),
'smtp_host' => $host,
'smtp_port' => $port,
'smtp_security' => $security,
'smtp_username' => $username,
'smtp_from_email' => $sender,
'smtp_from_name' => ppm_current('smtp_from_name', 'Moja Polana Smaków'),
'reservation_admin_email' => $notify,
'reservation_auto_reply_enabled' => setting('reservation_auto_reply_enabled', '1'),
];
}
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
verify_csrf();
$action = (string)($_POST['action'] ?? '');
try {
if ($action === 'save') {
$host = trim((string)($_POST['smtp_host'] ?? ''));
if (!preg_match('/^(?=.{4,253}$)[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$/D', $host)) {
throw new RuntimeException('Sprawdź nazwę serwera pocztowego.');
}
$port = (int)($_POST['smtp_port'] ?? 0);
$security = (string)($_POST['smtp_security'] ?? '');
if (!in_array($port, [465, 587], true) || !in_array($security, ['ssl', 'starttls'], true)
|| ($port === 465 && $security !== 'ssl') || ($port === 587 && $security !== 'starttls')) {
throw new RuntimeException('Wybierz SMTP 465 / SSL-TLS lub 587 / STARTTLS.');
}
$user = ppm_mail((string)($_POST['smtp_username'] ?? ''), 'Login SMTP');
$from = ppm_mail((string)($_POST['smtp_from_email'] ?? ''), 'Nadawca');
$notification = ppm_mail((string)($_POST['reservation_admin_email'] ?? ''), 'Powiadomienia');
if (strcasecmp($user, $from) !== 0) {
throw new RuntimeException('W home.pl login SMTP musi odpowiadać adresowi skrzynki używanemu jako nadawca.');
}
$fromName = trim((string)($_POST['smtp_from_name'] ?? ''));
if ($fromName === '' || strlen($fromName) > 250 || preg_match('/[\r\n]/', $fromName)) {
throw new RuntimeException('Nazwa nadawcy jest pusta lub zbyt długa.');
}
$secret = (string)($_POST['smtp_password'] ?? '');
if ($secret === '' && smtp_password() === '') {
throw new RuntimeException('Wpisz hasło istniejącej skrzynki SMTP.');
}
if ($secret !== '' && strlen($secret) > 512) {
throw new RuntimeException('Hasło SMTP jest zbyt długie.');
}
$isEnabled = (string)($_POST['smtp_enabled'] ?? '0') === '1' ? '1' : '0';
$auto = (string)($_POST['reservation_auto_reply_enabled'] ?? '0') === '1' ? '1' : '0';
if ($secret !== '' && !ppm_has_safe_crypto()) {
throw new RuntimeException('Nie można bezpiecznie zapisać hasła. Sprawdź OpenSSL i prawa zapisu katalogu storage.');
}
$encrypted = '';
if ($secret !== '') {
$encrypted = smtp_encrypt_password($secret);
if (!str_starts_with($encrypted, 'enc:')) {
throw new RuntimeException('Szyfrowanie hasła jest niedostępne. Zapis anulowano.');
}
}
$values = [
'smtp_enabled' => $isEnabled,
'smtp_host' => $host,
'smtp_port' => (string)$port,
'smtp_security' => $security,
'smtp_username' => $user,
'smtp_from_email' => $from,
'smtp_from_name' => $fromName,
'reservation_admin_email' => $notification,
'reservation_auto_reply_enabled' => $auto,
];
if ($encrypted !== '') $values['smtp_password_secret'] = $encrypted;
$db = db();
$db->beginTransaction();
try {
$stmt = $db->prepare('INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)');
foreach ($values as $k => $v) ppm_upsert($stmt, $k, $v);
$db->commit();
} catch (Throwable $e) {
if ($db->inTransaction()) $db->rollBack();
throw $e;
}
try { admin_log('smtp_homepl_v171', 'Zaktualizowano ustawienia poczty home.pl (bez hasła w logach)'); } catch (Throwable $ignored) {}
flash('success', 'Zapisano ustawienia poczty. Hasło pozostaje ukryte. Teraz wyślij wiadomość testową.');
redirect('/admin/polana-poczta.php');
}
if ($action === 'test') {
if (setting('smtp_enabled', '0') !== '1') throw new RuntimeException('Najpierw zapisz konfigurację z włączonym SMTP.');
if (smtp_password() === '') throw new RuntimeException('Brakuje poprawnie zapisanego hasła SMTP.');
$testTo = ppm_mail((string)($_POST['test_email'] ?? ''), 'Adres testowy');
smtp_send_mail(
$testTo,
'Test poczty — Moja Polana Smaków',
reservation_email_html('Test poczty', 'Wysyłka SMTP z panelu Moja Polana Smaków działa.'),
'Wysyłka SMTP z panelu Moja Polana Smaków działa.'
);
flash('success', 'Serwer zaakceptował wiadomość testową do ' . $testTo . '. Sprawdź skrzynkę odbiorczą i SPAM.');
redirect('/admin/polana-poczta.php');
}
throw new RuntimeException('Nieznana operacja.');
} catch (Throwable $e) {
// Nigdy nie logujemy ani nie wyświetlamy hasła użytkownika.
flash('error', 'Nie wykonano operacji: ' . $e->getMessage());
redirect('/admin/polana-poczta.php');
}
}
$cfg = ppm_mail_configuration();
$secretSaved = smtp_password_is_set();
$secretUsable = $secretSaved && smtp_password() !== '';
$ready = ($cfg['smtp_enabled'] === '1' && $secretUsable && trim(setting('smtp_host', '')) !== ''
&& trim(setting('smtp_username', '')) !== '' && trim(setting('smtp_from_email', '')) !== '');
render_admin_header('Poczta i SMTP — Moja Polana Smaków');
?>
<style>
.ppm171{max-width:1080px;margin:0 auto;padding:18px 14px 65px}.ppm171 *{box-sizing:border-box}
.ppm171 h1{font-size:clamp(25px,3.5vw,36px);margin:0 0 8px}.ppm171 h2{font-size:21px;margin:0 0 10px}.ppm171 p{line-height:1.55}
.ppm171 .muted{opacity:.75}.ppm171 .pill{display:inline-block;border-radius:99px;background:#eef5ed;color:#20513c;padding:8px 12px;font-weight:750;margin:8px 0 16px}
.ppm171 .pill.warn{background:#fff1dc;color:#7b450e}.ppm171 .panel{border:1px solid #ccd8d0;border-radius:18px;padding:22px;margin:18px 0;background:#fff;color:#183022}
.ppm171 .cols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:15px}.ppm171 label{display:flex;flex-direction:column;font-weight:650;gap:7px}
.ppm171 input,.ppm171 select{width:100%;min-height:45px;padding:10px 12px;border:1px solid #a7bbae;border-radius:10px;font:inherit;background:var(--input-bg,#fff);color:var(--text-color,#162a20)}
.ppm171 .full{grid-column:1/-1}.ppm171 small{font-size:13px;font-weight:400;opacity:.75}
.ppm171 .note{border-left:4px solid #2a7953;background:#eaf4ee;color:#183b2b;padding:13px 15px;border-radius:9px;margin:13px 0}
.ppm171 .actions{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:18px}
.ppm171 .primary{background:#1b6544;color:#fff;border:0;border-radius:11px;padding:13px 19px;font:inherit;font-weight:750;cursor:pointer;min-height:45px}
.ppm171 .linkbtn{display:inline-flex;text-decoration:none;background:#eff5ef;color:#1c5439;border-radius:11px;padding:12px 15px;font-weight:650;min-height:45px;align-items:center}
.ppm171 .secondary{background:#f0f5ee;color:#1b5f43;border:1px solid #aac2b2;border-radius:11px;padding:12px 16px;font:inherit;font-weight:650;cursor:pointer}
@media(max-width:700px){.ppm171 .cols{grid-template-columns:1fr}.ppm171 .panel{padding:15px}.ppm171 .full{grid-column:auto}}
</style>
<main class="ppm171">
<div class="actions" style="margin:0 0 14px">
<a class="linkbtn" href="/admin/polana-zarzadzanie.php">← Zarządzanie</a>
<a class="linkbtn" href="/admin/reservations.php">Rezerwacje</a>
<a class="linkbtn" href="/admin/reservation-settings.php">Zaawansowane wiadomości</a>
</div>
<h1>📨 Poczta restauracji — home.pl</h1>
<p class="muted">Wszystko do wysyłania powiadomień i potwierdzeń rezerwacji. Parametry serwera wpisane, pozostaje hasło skrzynki.</p>
<span class="pill <?= $ready ? '' : 'warn' ?>"><?= $ready ? '✓ SMTP skonfigurowane — wykonaj test' : '● SMTP wymaga zapisania konfiguracji / hasła' ?></span>
<div class="note"><strong>Nadawca:</strong> <code>[email protected]</code> — musi być utworzoną skrzynką na home.pl.<br>
<strong>Powiadomienia dla obsługi:</strong> <code>[email protected]</code> — to osobny adres odbiorcy; również musi istnieć, aby otrzymywać wiadomości.</div>
<form class="panel" method="post" autocomplete="off">
<?= csrf_field() ?>
<input type="hidden" name="action" value="save">
<h2>1. SMTP — ustawienia serwera</h2>
<div class="cols">
<label>Serwer home.pl
<input name="smtp_host" value="<?=ppm_e($cfg['smtp_host'])?>" required spellcheck="false" autocomplete="off">
</label>
<label>Port i szyfrowanie
<select name="smtp_transport" id="ppm171transport">
<option value="465_ssl" <?=($cfg['smtp_port']==='465'&&$cfg['smtp_security']==='ssl')?'selected':''?>>465 — SSL/TLS (zalecane)</option>
<option value="587_starttls" <?=($cfg['smtp_port']==='587'&&$cfg['smtp_security']==='starttls')?'selected':''?>>587 — STARTTLS</option>
</select>
<input type="hidden" name="smtp_port" id="ppm171port" value="<?=ppm_e($cfg['smtp_port'])?>">
<input type="hidden" name="smtp_security" id="ppm171security" value="<?=ppm_e($cfg['smtp_security'])?>">
</label>
<label>Login skrzynki SMTP
<input name="smtp_username" type="email" value="<?=ppm_e($cfg['smtp_username'])?>" required autocomplete="username" spellcheck="false">
</label>
<label>Hasło skrzynki SMTP
<input name="smtp_password" type="password" autocomplete="new-password" placeholder="<?= $secretSaved ? 'Zapisane — pozostaw puste, jeśli bez zmian' : 'Wpisz hasło do skrzynki no-reply' ?>">
<small><?= $secretSaved ? 'Hasło już zapisane; wpisz nowe tylko, aby je zmienić.' : 'Hasło jest potrzebne przy pierwszym zapisie.' ?></small>
</label>
<label>Nadawca wiadomości (musi odpowiadać loginowi)
<input name="smtp_from_email" type="email" value="<?=ppm_e($cfg['smtp_from_email'])?>" required spellcheck="false">
</label>
<label>Nazwa nadawcy
<input name="smtp_from_name" value="<?=ppm_e($cfg['smtp_from_name'])?>" required maxlength="100">
</label>
</div>
<h2 style="margin-top:25px">2. Rezerwacje i automatyczne odpowiedzi</h2>
<div class="cols">
<label>Gdzie wysyłać informacje o nowych rezerwacjach?
<input name="reservation_admin_email" type="email" value="<?=ppm_e($cfg['reservation_admin_email'])?>" required spellcheck="false">
</label>
<label>Wysyłka SMTP
<select name="smtp_enabled">
<option value="1" <?= $cfg['smtp_enabled']==='1' ? 'selected' : '' ?>>Włączona</option>
<option value="0" <?= $cfg['smtp_enabled']==='0' ? 'selected' : '' ?>>Wyłączona</option>
</select>
</label>
<label>Automatyczna odpowiedź do klienta
<select name="reservation_auto_reply_enabled">
<option value="1" <?= $cfg['reservation_auto_reply_enabled']==='1' ? 'selected' : '' ?>>Włączona</option>
<option value="0" <?= $cfg['reservation_auto_reply_enabled']==='0' ? 'selected' : '' ?>>Wyłączona</option>
</select>
</label>
</div>
<div class="actions"><button class="primary" type="submit">Zapisz konfigurację poczty</button></div>
<small>Hasło jest przechowywane w dotychczasowym mechanizmie SMTP, szyfrowane kluczem z katalogu storage. Nie pojawia się w adresie URL ani logach panelu.</small>
</form>
<form class="panel" method="post">
<?= csrf_field() ?>
<input type="hidden" name="action" value="test">
<h2>3. Sprawdź wysyłkę</h2>
<p class="muted">Najpierw kliknij „Zapisz konfigurację poczty”, potem wyślij test. Mail testowy nie tworzy rezerwacji.</p>
<div class="cols">
<label>Adres, na który wysłać test
<input type="email" name="test_email" value="<?=ppm_e($cfg['reservation_admin_email'])?>" required>
</label>
</div>
<div class="actions"><button type="submit" class="secondary" <?= $ready ? '' : 'disabled' ?>>Wyślij test SMTP</button></div>
<small>Sukces oznacza przyjęcie wiadomości przez serwer SMTP. Dostarczenie do skrzynki trzeba jeszcze sprawdzić.</small>
</form>
<div class="actions">
<a class="linkbtn" href="/admin/polana-poczta-skrot.php">Dodaj przycisk „Poczta” do Ustawień</a>
<a class="linkbtn" href="/admin/polana-v168-ustawienia.php">Pozostałe ustawienia restauracji</a>
</div>
</main>
<script>
(()=>{const select=document.querySelector('#ppm171transport'),port=document.querySelector('#ppm171port'),security=document.querySelector('#ppm171security');
if(!select||!port||!security)return;
const update=()=>{const s=select.value.split('_');port.value=s[0];security.value=s[1]};select.addEventListener('change',update);update();})();
</script>
<?php render_admin_footer(); ?>