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-v20-godziny-instalator.php
<?php
declare(strict_types=1);
/** POLANA V20 — authenticated, conservative, reversible installer. */
require_once dirname(__DIR__).'/includes/functions.php';
require_once dirname(__DIR__).'/includes/polana_v20_opening_hours.php';
require_admin_role();
header('Cache-Control: private, no-store');
header('X-Robots-Tag: noindex,nofollow');

function pv20_root(): string { return dirname(__DIR__); }
function pv20_target_paths(): array {
    $r=pv20_root();
    return ['includes/polana_v175_booking.php'=>$r.'/includes/polana_v175_booking.php',
            'admin/polana-godziny-rezerwacji.php'=>$r.'/admin/polana-godziny-rezerwacji.php'];
}
function pv20_once(string $source,string $needle,string $replacement,string $path):string {
    if(substr_count($source,$needle)!==1) throw new RuntimeException('Struktura '.$path.' jest inna od oczekiwanej (' . substr($needle,0,70) . ' / ' . substr_count($source,$needle) . '); nic nie zmieniono.');
    return str_replace($needle,$replacement,$source);
}
function pv20_patch_booking(string $s): string {
    if(str_contains($s,'/* POLANA_V20_OPENING_HOURS */')) return $s;
    if(!str_contains($s,'function pv175_available_slots(') || !str_contains($s,'function pv175_validate_slot('))
        throw new RuntimeException('Brak istniejącej walidacji terminów V17.5.');
    $s=pv20_once($s,"declare(strict_types=1);\n", "declare(strict_types=1);\n/* POLANA_V20_OPENING_HOURS */\nrequire_once __DIR__.'/polana_v20_opening_hours.php';\n", 'booking.php');
    $s=pv20_once($s,'if (!is_array($stored)) return $cfg;','if (!is_array($stored)) $stored = [];','booking.php');
    $p=strpos($s,'function pv175_config(): array {');
    $q=strpos($s,'function pv175_enabled(): bool', $p===false?0:$p);
    if($p===false||$q===false) throw new RuntimeException('Nie rozpoznano konfiguracji V17.5.');
    $part=substr($s,$p,$q-$p);
    $part=pv20_once($part,'    return $cfg;', '    return pv20_apply_opening_hours($cfg);', 'booking.php/config');
    $s=substr($s,0,$p).$part.substr($s,$q);
    $s=pv20_once($s,"function pv175_enabled(): bool { return setting('polana_v175_booking_enabled', '0') === '1'; }", "function pv175_enabled(): bool { return pv20_source_present() || setting('polana_v175_booking_enabled', '0') === '1'; }", 'booking.php/enabled');
    $s=pv20_once($s,"    \$cfg = pv175_config();\n    \$window = pv175_day_window(\$date, \$cfg);", "    \$cfg = pv175_config();\n    if (!empty(\$cfg['_opening_hours_error'])) return ['slots'=>[], 'message'=>'Trwa aktualizacja godzin otwarcia. Skontaktuj się z restauracją lub wybierz termin później.'];\n    \$window = pv175_day_window(\$date, \$cfg);", 'booking.php/slots');
    return $s;
}
function pv20_patch_admin(string $s): string {
    if(str_contains($s,'<!-- POLANA_V20_ADMIN_SYNC -->'))return $s;
    if(!str_contains($s,'pv175_valid_window')||!str_contains($s,'pv175_config()')) throw new RuntimeException('Panel godzin ma inną strukturę.');
    $s=pv20_once($s,"        \$cfg['duration']=(int)(\$_POST['duration']??90);", "        // The website's opening_hours is canonical; preserve it on form submit.\n        if (pv20_source_present()) {\n            \$canonical=pv20_opening_status();\n            if (\$canonical['errors']) throw new RuntimeException('Popraw godziny w Ustawieniach: '.implode(' ',\$canonical['errors']));\n            \$cfg['days']=\$canonical['days'];\n            \$openDays=count(array_filter(\$cfg['days'],'pv175_valid_window'));\n        }\n        \$cfg['duration']=(int)(\$_POST['duration']??90);", 'panel/zapis');
    $s=pv20_once($s,"        \$enabled=!empty(\$_POST['enabled']);", "        \$enabled=pv20_source_present() ? true : !empty(\$_POST['enabled']);", 'panel/aktywacja');
    $s=pv20_once($s, "        if (\$enabled && \$openDays===0 && !array_filter(\$cfg['exceptions'],'pv175_valid_window'))", "        if (\$enabled && !pv20_source_present() && \$openDays===0 && !array_filter(\$cfg['exceptions'],'pv175_valid_window'))", 'panel/zamkniete');
    $s=pv20_once($s,"\$cfg=pv175_config();\n\$enabled=pv175_enabled();", "\$cfg=pv175_config();\n\$enabled=pv175_enabled();\n\$pv20Auto=pv20_source_present();\n\$pv20Status=pv20_opening_status();", 'panel/zrodlo');
    $s=pv20_once($s,"    <p>Godziny ustawiasz osobno na każdy dzień. Niezaznaczony dzień oznacza brak rezerwacji online.</p>", "    <!-- POLANA_V20_ADMIN_SYNC -->\n    <?php if (\$pv20Auto): ?>\n      <div style=\"padding:15px 17px;margin:12px 0 18px;border:1px solid #b2c6a3;background:#f1f6ec;border-radius:12px\"><strong>Automatycznie z godzin otwarcia</strong><p style=\"margin:7px 0\">Godziny pobieramy z <a href=\"/admin/settings.php\">Ustawienia → Godziny otwarcia</a>. Poniżej wyświetla się aktualny plan tylko do podglądu. Zmiany godzin wprowadza się w ustawieniach strony, bez ponownego instalowania. Wyjątki i czas stolika można nadal zmieniać tutaj.</p>\n      <?php if (!empty(\$pv20Status['errors'])): ?><strong style=\"color:#9f2929\">Popraw format godzin w Ustawieniach:</strong><ul><?php foreach (\$pv20Status['errors'] as \$err): ?><li><?= e(\$err) ?></li><?php endforeach; ?></ul><?php endif; ?></div>\n    <?php else: ?>\n      <p>Godziny ustawiasz osobno na każdy dzień. Niezaznaczony dzień oznacza brak rezerwacji online.</p>\n    <?php endif; ?>", 'panel/opis');
    $s=pv20_once($s,'    <div class="pv175-days">', '    <?php if ($pv20Auto): ?><fieldset disabled style="border:0;padding:0;margin:0;min-width:0"><legend style="font-size:13px;color:#637063;margin-bottom:10px">Godziny odczytane z ustawień strony</legend><?php endif; ?>' . "\n" . '    <div class="pv175-days">', 'panel/pola');
    $s=pv20_once($s,"    </div>\n    <div class=\"pv175-grid\" style=\"margin:22px 0\">", "    </div>\n    <?php if (\$pv20Auto): ?></fieldset><?php endif; ?>\n    <div class=\"pv175-grid\" style=\"margin:22px 0\">", 'panel/fieldset');
    $marker='<label class="pv175-on" style="margin:20px 0">';
    $s=pv20_once($s,$marker, '<?php if (!$pv20Auto): ?>' . "\n    " .$marker, 'panel/blokada');
    $needle="    <button class=\"pv175-btn\" type=\"submit\">Zapisz godziny i ustawienia</button>";
    $replacement='    <?php else: ?><div class="pv175-on" style="margin:20px 0"><strong>Blokada godzin aktywna automatycznie</strong> — terminy spoza harmonogramu są odrzucane także po ręcznym wysłaniu formularza.</div><?php endif; ?>' . "\n" . $needle;
    $s=pv20_once($s,$needle,$replacement,'panel/status');
    return $s;
}
function pv20_changes():array {
    $changes=[];
    foreach(pv20_target_paths() as $rel=>$path) {
        if(!is_file($path)||!is_readable($path)||!is_writable($path)) throw new RuntimeException('Brak dostępu zapisu do '.$rel);
        $old=@file_get_contents($path);
        if(!is_string($old)) throw new RuntimeException('Błąd odczytu '.$rel);
        $lf=str_replace("\r\n","\n",$old);
        $new=$rel==='includes/polana_v175_booking.php'?pv20_patch_booking($lf):pv20_patch_admin($lf);
        if(str_contains($old,"\r\n")) $new=str_replace("\n","\r\n",$new);
        if($new!==$old)$changes[$rel]=['path'=>$path,'before'=>$old,'after'=>$new];
    }
    return $changes;
}
function pv20_backup_base():string {return dirname(pv20_root()).'/.polana_v20_private_backups';}
function pv20_write_atomic(string $path,string $data):void {
    $tmp=$path.'.pv20_'.bin2hex(random_bytes(6)).'.tmp';
    if(@file_put_contents($tmp,$data,LOCK_EX)!==strlen($data)) { @unlink($tmp);throw new RuntimeException('Błąd zapisu '.basename($path)); }
    $mode=@fileperms($path); if($mode!==false)@chmod($tmp,$mode&0777);
    if(!@rename($tmp,$path)) { @unlink($tmp);throw new RuntimeException('Błąd podmiany '.basename($path)); }
    if(function_exists('opcache_invalidate'))@opcache_invalidate($path,true);
}
function pv20_install():string {
    $s=pv20_opening_status();
    if(!$s['active'])throw new RuntimeException('W Ustawieniach strony brakuje godzin otwarcia. Uzupełnij je przed instalacją.');
    if($s['errors'])throw new RuntimeException('Nie można zainstalować: '.implode(' ',$s['errors']));
    $changes=pv20_changes();
    if(!$changes) return 'Synchronizacja V20 jest już zainstalowana.';
    $base=pv20_backup_base();
    if(!is_dir($base)&&!@mkdir($base,0700,true))throw new RuntimeException('Nie można utworzyć katalogu kopii poza WWW.');
    @chmod($base,0700);
    @file_put_contents($base.'/.htaccess',"Require all denied\nDeny from all\n");
    @file_put_contents($base.'/index.html','');
    $lock=@fopen($base.'/.install.lock','c');
    if(!$lock||!@flock($lock,LOCK_EX|LOCK_NB))throw new RuntimeException('Trwa inna instalacja.');
    $dir=$base.'/'.date('Ymd_His').'_'.bin2hex(random_bytes(4));
    if(!@mkdir($dir,0700))throw new RuntimeException('Nie można utworzyć katalogu kopii.');
    $manifest=['version'=>'20','created_at'=>date(DATE_ATOM),'rolled_back'=>false,'files'=>[]];
    foreach($changes as $rel=>$item) {
        $file=str_replace('/','__',$rel).'.bak';
        if(@file_put_contents($dir.'/'.$file,$item['before'],LOCK_EX)!==strlen($item['before']))throw new RuntimeException('Nie zapisano kopii '.$rel);
        $manifest['files'][$rel]=['backup'=>$file,'before_sha256'=>hash('sha256',$item['before']),'after_sha256'=>hash('sha256',$item['after'])];
    }
    $manifestFile=$dir.'/manifest.json';
    if(@file_put_contents($manifestFile,json_encode($manifest,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR),LOCK_EX)===false)throw new RuntimeException('Brak manifestu kopii.');
    $written=[];
    try {
        foreach($changes as $rel=>$item){pv20_write_atomic($item['path'],$item['after']);$written[]=$rel;}
    }catch(Throwable $ex) {
        foreach(array_reverse($written) as $rel){ try{pv20_write_atomic($changes[$rel]['path'],$changes[$rel]['before']);}catch(Throwable $err){error_log('POLANA V20 AUTO ROLLBACK: '.$err->getMessage());}}
        $manifest['rolled_back']=true;
        @file_put_contents($manifestFile,json_encode($manifest,JSON_PRETTY_PRINT),LOCK_EX);
        throw $ex;
    }finally{ @flock($lock,LOCK_UN);@fclose($lock); }
    return 'Zainstalowano V20. Godziny pobierane są z Ustawień; nie zmieniono bazy rezerwacji, SMTP ani Google Calendar. Kopia: '.basename($dir).'.';
}
function pv20_rollback():string {
    $manifests=glob(pv20_backup_base().'/*/manifest.json')?:[];
    rsort($manifests,SORT_STRING);
    foreach($manifests as $mf){
        $m=json_decode((string)@file_get_contents($mf),true);
        if(!is_array($m)||($m['version']??'')!=='20'||!empty($m['rolled_back']))continue;
        $restore=[];$paths=pv20_target_paths();
        foreach($m['files'] as $rel=>$info){
            if(!isset($paths[$rel]))throw new RuntimeException('Nieznany plik w kopii.');
            $current=@file_get_contents($paths[$rel]);
            if(!is_string($current)||!hash_equals((string)$info['after_sha256'],hash('sha256',$current)))throw new RuntimeException('Od instalacji zmienił się '.$rel.' — zatrzymano rollback, aby nie utracić nowszych zmian.');
            $previous=@file_get_contents(dirname($mf).'/'.basename((string)$info['backup']));
            if(!is_string($previous)||!hash_equals((string)$info['before_sha256'],hash('sha256',$previous)))throw new RuntimeException('Uszkodzona kopia '.$rel);
            $restore[$rel]=$previous;
        }
        foreach($restore as $rel=>$data)pv20_write_atomic($paths[$rel],$data);
        $m['rolled_back']=true;
        @file_put_contents($mf,json_encode($m,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR),LOCK_EX);
        return 'Przywrócono poprzednie pliki. Dane rezerwacji i ustawienia pozostały nietknięte.';
    }
    throw new RuntimeException('Brak aktywnej kopii V20 do przywrócenia.');
}

if(($_SERVER['REQUEST_METHOD']??'')==='POST'){
    verify_csrf();
    try{
        $action=(string)($_POST['action']??'');
        if($action==='install')$msg=pv20_install();
        elseif($action==='rollback' && ($_POST['confirm_rollback']??'')==='1')$msg=pv20_rollback();
        else throw new RuntimeException('Nieprawidłowa operacja.');
        flash('success',$msg);
    }catch(Throwable $e){flash('error',$e->getMessage());}
    redirect('/admin/polana-v20-godziny-instalator.php');
}
$plan=pv20_opening_status();
try {$changes=pv20_changes();$installStatus=$changes?'Możliwa instalacja — '.count($changes).' pliki do zmiany':'Zainstalowana';}
catch(Throwable $e){$installStatus='Wymaga uwagi: '.$e->getMessage();}
$canInstall=$plan['active'] && empty($plan['errors']) && !str_starts_with($installStatus,'Wymaga uwagi');
$dayLabels=['Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota','Niedziela'];
render_admin_header('Polana V20 — godziny rezerwacji');
?>
<div style="max-width:900px;margin:28px auto;padding:0 14px">
 <div class="form-card" style="padding:25px;border-radius:16px;margin-bottom:20px">
  <h1>Polana Smaków · Godziny rezerwacji V20</h1>
  <p>Synchronizacja z godzinami wpisanymi w <a href="/admin/settings.php">Ustawieniach strony</a>. Po zmianie godzin rezerwacje aktualizują się automatycznie, bez instalowania ponownie. Zachowujemy Google Calendar, pocztę i istniejące rezerwacje.</p>
  <p><strong>Stan:</strong> <?= e($installStatus) ?></p>
  <?php if (!$plan['active']): ?><p style="color:#a83228">Brak godzin w głównych Ustawieniach strony. Wpisz je przed instalacją.</p><?php endif; ?>
  <?php if ($plan['errors']): ?><div style="background:#fff3ed;padding:14px;border-radius:10px"><strong>Nie można odczytać godzin:</strong><ul><?php foreach($plan['errors'] as $err): ?><li><?= e($err) ?></li><?php endforeach; ?></ul><p>Zalecany format: <code>Pon: nieczynne</code>, <code>Wt–Czw: 15:00–21:00</code>, <code>Pt–Sob: 13:00–22:00</code>, <code>Nd: 13:00–20:00</code>.</p></div><?php endif; ?>
  <h2>Podgląd godzin otwarcia</h2>
  <div style="display:grid;gap:7px;margin:14px 0 20px">
   <?php foreach($dayLabels as $idx=>$day):$window=$plan['days'][(string)($idx+1)]??null; ?>
   <div style="padding:9px 13px;background:#f4f5f0;border-radius:8px;display:flex;justify-content:space-between"><strong><?=e($day)?></strong><span><?=is_array($window)?e($window['open'].'–'.$window['close']):'Nieczynne / brak godzin'?></span></div>
   <?php endforeach; ?>
  </div>
  <form method="post"><?=csrf_field()?><input type="hidden" name="action" value="install"><button class="btn btn-primary" type="submit" <?= $canInstall?'':'disabled' ?>>Zainstaluj synchronizację z kopią i rollbackiem</button></form>
  <p style="font-size:13px;margin-top:12px">Uwaga: ostatni termin zależy od czasu zajęcia stolika (domyślnie 90 minut), który można zmienić w ustawieniach rezerwacji.</p>
 </div>
 <div class="form-card" style="padding:24px;border-radius:16px;margin-bottom:20px">
  <h2>Przywróć poprzednią wersję</h2><p>Rollback przywraca tylko pliki zmienione podczas instalacji i jest blokowany, jeśli pliki edytowano później.</p>
  <form method="post"><?=csrf_field()?><input type="hidden" name="action" value="rollback"><label style="display:block;margin:12px 0"><input type="checkbox" name="confirm_rollback" value="1" required> Potwierdzam cofnięcie V20</label><button class="btn" type="submit">Przywróć poprzednie pliki</button></form>
  <p><a href="/admin/polana-godziny-rezerwacji.php">Wyjątki, dni świąteczne i czas stolika</a> · <a href="/rezerwacja" target="_blank" rel="noopener">Sprawdź formularz rezerwacji</a></p>
 </div>
</div>
<?php render_admin_footer(); ?>

Youez - 2016 - github.com/yon3zu
LinuXploit