| 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 : |
<?php
declare(strict_types=1);
/** POLANA V17.3 one-package installer: V17.2 mail/newsletter, then Google Calendar status hook. */
require_once dirname(__DIR__) . '/includes/polana_v173_v172_install_lib.php';
require_once dirname(__DIR__) . '/includes/polana_gcal.php';
require_admin_role();
header('Cache-Control: private, no-store, max-age=0');
header('X-Robots-Tag: noindex,nofollow');
function p173_h($v):string{return htmlspecialchars((string)$v,ENT_QUOTES|ENT_SUBSTITUTE,'UTF-8');}
function p173_root():string{return dirname(__DIR__);}
function p173_backup():string{return dirname(p173_root()).'/.polana_v173_backups';}
function p173_targets():array{return ['includes/reservations.php'=>p173_root().'/includes/reservations.php','includes/functions.php'=>p173_root().'/includes/functions.php'];}
function p173_patch(string $relative,string $source):string {
if ($relative==='includes/reservations.php') {
if (str_contains($source,'POLANA_V173_GCAL_STATUS_HOOK'))return $source;
$start=strpos($source,'function reservation_change_status(');
$stop=strpos($source,'function reservation_validate_public_input(');
if ($start===false||$stop===false||$stop<=$start)throw new RuntimeException('Nie znaleziono funkcji zmiany statusu rezerwacji.');
$before=substr($source,0,$start);$body=substr($source,$start,$stop-$start);$after=substr($source,$stop);
$needle=' return $reservation;';
if (substr_count($body,$needle)!==1)throw new RuntimeException('Niejednoznaczne zakończenie reservation_change_status; bez zmian.');
$hook=<<<'HOOK'
/* POLANA_V173_GCAL_STATUS_HOOK: status always saved, calendar failures logged independently */
require_once __DIR__ . '/polana_gcal.php';
pg173_after_change($id, $adminUserId);
return $reservation;
HOOK;
return $before.str_replace($needle,$hook,$body).$after;
}
if ($relative==='includes/functions.php') {
if(str_contains($source,'POLANA_V173_CALENDAR_NAV'))return $source;
$needle='<a href="/admin/polana-komunikacja.php">Poczta i komunikacja</a>';
$replacement=$needle."\n <!-- POLANA_V173_CALENDAR_NAV -->\n <a href=\"/admin/polana-kalendarz.php\">Kalendarz Google</a>";
if(substr_count($source,$needle)!==1)throw new RuntimeException('Nie znaleziono stabilnej nawigacji V17.2 — instalacja kalendarza przerwana.');
return str_replace($needle,$replacement,$source);
}
throw new RuntimeException('Niedozwolony plik: '.$relative);
}
function p173_is_installed():bool {
foreach(p173_targets() as $relative=>$file){
$str=@file_get_contents($file);
if(!is_string($str))return false;
if($relative==='includes/reservations.php'&&!str_contains($str,'POLANA_V173_GCAL_STATUS_HOOK'))return false;
if($relative==='includes/functions.php'&&!str_contains($str,'POLANA_V173_CALENDAR_NAV'))return false;
}
return true;
}
function p173_atomic(string $file,string $content):void {
$temp=$file.'.v173_'.bin2hex(random_bytes(5)).'.tmp';
if(@file_put_contents($temp,$content,LOCK_EX)!==strlen($content)){@unlink($temp);throw new RuntimeException('Brak zapisu: '.basename($file));}
$mode=@fileperms($file);if($mode!==false)@chmod($temp,$mode&0777);
if(!@rename($temp,$file)){@unlink($temp);throw new RuntimeException('Brak podmiany: '.basename($file));}
}
function p173_preflight():void {
foreach(['admin/polana-newsletter.php','admin/polana-komunikacja.php','admin/polana-poczta.php','admin/polana-kalendarz.php',
'includes/polana_v172_newsletter.php','includes/polana_gcal.php'] as $relative){
if(!is_file(p173_root().'/'.$relative))throw new RuntimeException('Brakuje '.$relative.'. Wgraj wszystkie pliki z ZIP.');
}
if(!function_exists('openssl_encrypt')||!function_exists('curl_init'))throw new RuntimeException('PHP wymaga rozszerzeń OpenSSL i cURL.');
// Test future V17.2 + V17.3 patches without writing to existing PHP files.
foreach(p173_targets() as $relative=>$path){
if(!is_file($path)||!is_readable($path)||!is_writable($path))throw new RuntimeException('Brak praw do '.$relative);
$current=(string)file_get_contents($path);
$sim=pi172_patch($relative,str_replace("\r\n","\n",$current));
p173_patch($relative,$sim);
}
pg173_init_private();
$dir=p173_backup();if(!is_dir($dir)&&!@mkdir($dir,0700,true))throw new RuntimeException('Nie można utworzyć prywatnego katalogu backupu.');
if(!is_writable($dir))throw new RuntimeException('Backup poza WWW jest niedostępny.');
}
function p173_install():string {
if(p173_is_installed())return 'Google Kalendarz V17.3 jest już zainstalowany. Nie nadpisano zmian.';
p173_preflight();
// V17.2 runs only if missing. Its installer creates its own private backup and refuses unknown code.
$v172=pi172_install();
$changes=[];
foreach(p173_targets() as $relative=>$path){
$before=@file_get_contents($path);if(!is_string($before))throw new RuntimeException('Brak odczytu '.$relative);
$normalized=str_replace("\r\n","\n",$before);
$patched=p173_patch($relative,$normalized);
$after=str_contains($before,"\r\n")?str_replace("\n","\r\n",$patched):$patched;
if($before!==$after)$changes[$relative]=['file'=>$path,'before'=>$before,'after'=>$after];
}
pg173_ensure_schema();
if(!$changes)return 'Kalendarz zainstalowany wcześniej. '.$v172;
$dir=p173_backup().'/'.date('Ymd_His').'_'.bin2hex(random_bytes(4));
if(!@mkdir($dir,0700))throw new RuntimeException('Brak katalogu do kopii plików.');
$manifest=['version'=>'17.3','files'=>[]];
foreach($changes as $relative=>$change){
$backup='backup-'.count($manifest['files']).'.php.bak';
if(@file_put_contents($dir.'/'.$backup,$change['before'],LOCK_EX)!==strlen($change['before']))throw new RuntimeException('Brak backupu: '.$relative);
@chmod($dir.'/'.$backup,0600);
$manifest['files'][$relative]=['backup'=>$backup,'before_sha'=>hash('sha256',$change['before']),'after_sha'=>hash('sha256',$change['after'])];
}
$json=json_encode($manifest,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR);
if(@file_put_contents($dir.'/manifest.json',$json,LOCK_EX)!==strlen($json))throw new RuntimeException('Nie zapisano manifestu backupu.');
@chmod($dir.'/manifest.json',0600);
$done=[];
try {
foreach($changes as $relative=>$c){
if(@file_get_contents($c['file'])!==$c['before'])throw new RuntimeException('Plik zmienił się w trakcie instalacji: '.$relative);
p173_atomic($c['file'],$c['after']);$done[]=$c;
}
}catch(Throwable $e){foreach(array_reverse($done) as $c){if(@file_get_contents($c['file'])===$c['after']){try{p173_atomic($c['file'],$c['before']);}catch(Throwable $ignored){}}}throw $e;}
try {admin_log('polana_v173_install','Dodano hook Google Kalendarza V17.3 do potwierdzania rezerwacji');}catch(Throwable $ignored){}
return 'Zainstalowano kalendarz + centrum komunikacji. '.$v172.' Połącz konto Google w panelu kalendarza.';
}
function p173_rollback():string {
$list=glob(p173_backup().'/*/manifest.json')?:[];rsort($list);
$manifestPath=$list[0]??null;if(!$manifestPath)throw new RuntimeException('Brak backupu V17.3.');
$m=json_decode((string)file_get_contents($manifestPath),true);
if(!is_array($m)||($m['version']??'')!=='17.3')throw new RuntimeException('Błędny manifest backupu.');
$restore=[];$targets=p173_targets();
foreach(($m['files']??[]) as $relative=>$item){
if(!isset($targets[$relative]))throw new RuntimeException('Nieznany plik kopii.');
$backup=@file_get_contents(dirname($manifestPath).'/'.basename((string)$item['backup']));
$current=@file_get_contents($targets[$relative]);
if(!is_string($backup)||!is_string($current)||hash('sha256',$backup)!==$item['before_sha']||hash('sha256',$current)!==$item['after_sha'])throw new RuntimeException($relative.' został później zmieniony. Rollback zatrzymany.');
$restore[]=[$targets[$relative],$backup];
}
foreach($restore as [$file,$body])p173_atomic($file,$body);
@rename($manifestPath,$manifestPath.'.restored');
return 'Przywrócono integrację V17.3 w PHP. V17.2, ustawienia poczty, newsletter i wydarzenia istniejące w Google pozostają bez zmian.';
}
if(($_SERVER['REQUEST_METHOD']??'GET')==='POST'){
verify_csrf();
try{
$action=(string)($_POST['action']??'');
if($action==='install')$result=p173_install();
elseif($action==='rollback'&&!empty($_POST['confirm_rollback']))$result=p173_rollback();
else throw new RuntimeException('Nieprawidłowe działanie.');
flash('success',$result);
}catch(Throwable $e){flash('error','Nie udało się zainstalować: '.$e->getMessage());}
redirect('/admin/polana-v173-instalator.php');
}
render_admin_header('Instalator Polana V17.3');
?>
<style>.pi173{max-width:1000px;margin:12px auto 70px;padding:16px}.pi173 .card{background:#fff;border:1px solid #d6e5d9;padding:22px;border-radius:14px;margin:15px 0}.pi173 .btn{display:inline-block;padding:12px 16px;min-height:44px;border:0;border-radius:10px;background:#1b6142;color:#fff;cursor:pointer;text-decoration:none;font:inherit;font-weight:bold;margin:4px}.pi173 .btn.alt{background:#e6f1e9;color:#23543a}.pi173 li{margin:8px 0;line-height:1.5}</style>
<div class="pi173">
<h1>POLANA V17.3 — wszystko w jednej paczce</h1>
<p>Rezerwacje, automatyczne potwierdzenia, newsletter z double opt-in i Google Kalendarz dla pracowników. Instalator zachowuje istniejącą bazę, pliki i sekrety SMTP.</p>
<div class="card"><h2>1. Instalacja bezpieczna</h2><p>Sprawdź, czy wgrałeś pliki z katalogu <code>DO_WGRANIA/</code> oraz plik <code>admin/polana-poczta.php</code>, jeśli jeszcze go nie masz. Instalator aktywuje V17.2 tylko w razie potrzeby, a następnie integrację Google V17.3. Nie zmienia Cloudflare ani SEO.</p>
<p><strong>Stan integracji Google:</strong> <?=p173_is_installed()?'Zainstalowana':'Wymaga instalacji'?></p>
<form method="post"><?=csrf_field()?><input type="hidden" name="action" value="install"><button class="btn" type="submit">Zainstaluj wszystko z backupem</button></form></div>
<div class="card"><h2>2. Panele — wszystkie od razu</h2>
<a class="btn" href="/admin/polana-komunikacja.php">Poczta i komunikacja</a><a class="btn" href="/admin/polana-poczta.php">SMTP + test</a><a class="btn" href="/admin/polana-newsletter.php">Newsletter</a><a class="btn" href="/admin/polana-kalendarz.php">Google Kalendarz</a><a class="btn alt" href="/admin/reservations.php">Rezerwacje</a>
<p>Połącz Google w panelu Kalendarza. W ustawieniach Google Cloud włącz <b>Google Calendar API</b> i wpisz adres przekierowania wskazany w panelu.</p></div>
<div class="card"><h2>3. Jak działa potwierdzenie?</h2><ol><li>Gość wysyła prośbę. Obsługa otrzymuje e-mail na <code>[email protected]</code>, gość automatyczne „otrzymaliśmy prośbę”.</li><li>Obsługa klika <b>Potwierdź</b>. Gość otrzymuje e-mail z potwierdzeniem, a Google Kalendarz otrzymuje wydarzenie.</li><li>Anulowanie lub odrzucenie usuwa powiązane wydarzenie. Bez połączenia Google rezerwacja nadal się zapisuje.</li><li>Udostępnij prywatny kalendarz w Google pracownikom — zobaczą go na telefonach.</li></ol></div>
<div class="card"><h2>4. Rollback V17.3</h2><p>Przywraca tylko dwa zmienione pliki integracji kalendarza, nie cofa V17.2, zgód newslettera ani istniejących wydarzeń Google.</p><form method="post" onsubmit="return confirm('Wycofać kod integracji kalendarza? Wydarzenia Google pozostaną.');"><?=csrf_field()?><input type="hidden" name="action" value="rollback"><label><input type="checkbox" name="confirm_rollback" value="1" required> Potwierdzam cofnięcie V17.3</label><button class="btn alt" type="submit">Cofnij integrację kalendarza</button></form></div>
</div>
<?php render_admin_footer(); ?>